From ad3412f44e9117b33cb304e6edc6a1fcc5f1b5b8 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 13:15:28 -0400 Subject: [PATCH 01/16] Update main doc page --- docs/contains.rst | 3 ++- docs/contributing.rst | 46 ++++++++++++++++++++++++++++++++ docs/development.rst | 24 ----------------- docs/getting_started.rst | 2 +- docs/index.rst | 57 ++++++++++++++++++++-------------------- docs/references.txt | 3 +-- 6 files changed, 79 insertions(+), 56 deletions(-) create mode 100644 docs/contributing.rst delete mode 100644 docs/development.rst diff --git a/docs/contains.rst b/docs/contains.rst index c3aff534..a7082e08 100644 --- a/docs/contains.rst +++ b/docs/contains.rst @@ -8,7 +8,8 @@ Checking for points inside regions ================================== -Let's continue with sky and pixel regions defined in the :ref:`gs` section: +Let's continue with sky and pixel regions defined in the +:ref:`getting_started` section: .. code-block:: python diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 00000000..e3bef9f9 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,46 @@ +Reporting Issues and Contributing +================================= + +Reporting Issues +---------------- + +If you have found a bug in Regions please report it by +creating a new issue on the `Regions GitHub issue tracker +`_. That requires creating a +`free Github account `_ if you do not have one. + +Please include an example that demonstrates the issue that will allow +the developers to reproduce and fix the problem. You may also be asked +to provide information about your operating system and a full Python +stack trace. The developers will walk you through obtaining a stack +trace if it is necessary. + + +Contributing +------------ + +Like the `Astropy`_ project, Regions is made both by and for its users. +We accept contributions at all levels, spanning the gamut from fixing a +typo in the documentation to developing a major new feature. We welcome +contributors who will abide by the `Python Software Foundation Code of +Conduct `_. + +Regions follows the same workflow and coding guidelines as `Astropy`_. +The following pages will help you get started with contributing fixes, +code, or documentation (no git or GitHub experience necessary): + +* `How to make a code contribution `_ + +* `Coding Guidelines `_ + +* `Developer Documentation `_ + + +Getting Help +------------ + +Besides GitHub, you can `get help`_ from the community in a number of +ways. There is also a slack channel for Regions hosted under the main +Astropy slack. + +.. _get help: https://www.astropy.org/help.html diff --git a/docs/development.rst b/docs/development.rst deleted file mode 100644 index 9aa8e887..00000000 --- a/docs/development.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. include:: references.txt - -Development -=========== - -If you have a feature request or would like to contribute to ``regions``, -please go here: https://github.com/astropy/regions/ - -Notes ------ - -Minutes for the discussions on regions: - -* `Python in astronomy 2015 `__ -* `Python in astronomy 2016 `__ - - -Dependencies ------------- - -Should we use these packages or start building functionality from scratch? - -* spherical_geometry https://github.com/spacetelescope/spherical_geometry -* Shapely https://pypi.org/project/Shapely diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 64e4a763..bb888db3 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -1,6 +1,6 @@ .. include:: references.txt -.. _gs: +.. _getting_started: Getting started =============== diff --git a/docs/index.rst b/docs/index.rst index 3e3de93a..d136579d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,30 +7,39 @@ Feedback and contributions are welcome! -############################# -Astropy Regions Documentation -############################# +############### +Astropy Regions +############### -This is an in-development `affiliated package`_ of `Astropy`_ for region handling. +**Regions** is an in-development `coordinated package`_ of `Astropy`_ +for region handling. -To get an overview of available features, see :ref:`gs`. +To get an overview of available features, see :ref:`getting_started`. -The goal is to merge the functionality from `pyregion`_ and `photutils`_ apertures -and then after some time propose this package for inclusion in the Astropy core. +The eventual goal is to merge this package into the Astropy core +package. -* Code : `Github repository`_ -* Docs : `Region documentation`_ +* Code : `GitHub repository`_ * Contributors : https://github.com/astropy/regions/graphs/contributors -* Releases: https://pypi.org/project/regions -User Documentation -================== + +Getting Started +=============== .. toctree:: :maxdepth: 1 installation getting_started + changelog + + +User Documentation +================== + +.. toctree:: + :maxdepth: 1 + shapes contains compound @@ -38,24 +47,16 @@ User Documentation plotting region_io shapely - changelog - -+----------------------------------------+----------------------------------------+ -| ds9 | regions + matplotlib | -+========================================+========================================+ -| .. image:: _static/region_ds9.png | .. plot:: plot_reg.py | -| :width: 300px | :width: 300px | -| :target: _static/region_ds9.png | | -+----------------------------------------+----------------------------------------+ - -Advanced -======== + api -.. toctree:: - :maxdepth: 1 ++----------------------------------------+------------------------------------+ +| ds9 | regions + matplotlib | ++========================================+====================================+ +| .. image:: _static/region_ds9.png | .. plot:: plot_reg.py | +| :width: 300px | :width: 300px | +| :target: _static/region_ds9.png | | ++----------------------------------------+------------------------------------+ - api - development Reporting Issues ================ diff --git a/docs/references.txt b/docs/references.txt index 691009b5..0c95e289 100644 --- a/docs/references.txt +++ b/docs/references.txt @@ -5,5 +5,4 @@ .. _shapely: https://shapely.readthedocs.io/en/latest/ .. _Github repository: https://github.com/astropy/regions .. _Region documentation: https://astropy-regions.readthedocs.io/en/latest/ -.. _affiliated package: https://www.astropy.org/affiliated/index.html -.. _get help: https://www.astropy.org/help.html +.. _coordinated package: https://www.astropy.org/affiliated/index.html#coordinated-packages From a4f6688bb5f5b18d1f1865caae6db0148d4a0b41 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 13:20:52 -0400 Subject: [PATCH 02/16] Add new contributing page --- docs/index.rst | 54 +-------------------------------------------- docs/references.txt | 2 +- 2 files changed, 2 insertions(+), 54 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index d136579d..60725307 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -31,6 +31,7 @@ Getting Started installation getting_started + contributing changelog @@ -56,56 +57,3 @@ User Documentation | :width: 300px | :width: 300px | | :target: _static/region_ds9.png | | +----------------------------------------+------------------------------------+ - - -Reporting Issues -================ - -If you have found a bug in Regions please report it by creating a -new issue on the `Regions GitHub issue tracker -`_. - -Please include an example that demonstrates the issue that will allow -the developers to reproduce and fix the problem. You may also be asked to -provide information about your operating system and a full Python -stack trace. The developers will walk you through obtaining a stack -trace if it is necessary. - -Astropy Regions uses a package of utilities called `astropy-helpers -`_ during building and -installation. If you have any build or installation issue mentioning -the ``astropy_helpers`` or ``ah_bootstrap`` modules please send a -report to the `astropy-helpers issue tracker -`_. If you are -unsure, then it's fine to report to the main Regions issue tracker. - - -Contributing -============ - -Like the `Astropy`_ project, Regions is made both by and for its -users. We accept contributions at all levels, spanning the gamut from -fixing a typo in the documentation to developing a major new feature. -We welcome contributors who will abide by the `Python Software -Foundation Code of Conduct -`_. -If you have a feature request or would like to contribute to ``regions``, -please go here: https://github.com/astropy/regions/ - -Regions follows the same workflow and coding guidelines as -`Astropy`_. The following pages will help you get started with -contributing fixes, code, or documentation (no git or GitHub -experience necessary): - -* `How to make a code contribution `_ - -* `Coding Guidelines `_ - -* `Developer Documentation `_ - - -Get Help -======== - -Besides github, you can `get help`_ from the community in a number of ways. -There is also a slack channel for regions hosted under the main astropy slack. diff --git a/docs/references.txt b/docs/references.txt index 0c95e289..b60d3108 100644 --- a/docs/references.txt +++ b/docs/references.txt @@ -3,6 +3,6 @@ .. _photutils: https://photutils.readthedocs.io/en/latest/aperture.html .. _matplotlib: https://matplotlib.org/ .. _shapely: https://shapely.readthedocs.io/en/latest/ -.. _Github repository: https://github.com/astropy/regions +.. _GitHub repository: https://github.com/astropy/regions .. _Region documentation: https://astropy-regions.readthedocs.io/en/latest/ .. _coordinated package: https://www.astropy.org/affiliated/index.html#coordinated-packages From 0bea34ece4241f95bf22a50a49628905a63e4cb2 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 14:51:08 -0400 Subject: [PATCH 03/16] Move warning message --- docs/index.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 60725307..ee0e4afd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,12 +1,5 @@ .. include:: references.txt -.. warning:: - This ``regions`` package is in a very early stage of development. - It is neither feature complete nor API stable! - That said, please have a look and try to use it for your applications. - Feedback and contributions are welcome! - - ############### Astropy Regions ############### @@ -22,6 +15,12 @@ package. * Code : `GitHub repository`_ * Contributors : https://github.com/astropy/regions/graphs/contributors +.. warning:: + This ``regions`` package is in an early stage of development. It + is neither feature complete nor API stable. That said, please + have a look and try to use it for your applications. Feedback and + contributions are welcome! + Getting Started =============== From 659d6d776b3e1b7bd35ace66ccfdfb95e488a3f2 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 16:34:26 -0400 Subject: [PATCH 04/16] Update install docs --- docs/index.rst | 2 +- docs/install.rst | 145 ++++++++++++++++++++++++++++++++++++++++++ docs/installation.rst | 77 ---------------------- 3 files changed, 146 insertions(+), 78 deletions(-) create mode 100644 docs/install.rst delete mode 100644 docs/installation.rst diff --git a/docs/index.rst b/docs/index.rst index ee0e4afd..e2ae3486 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,7 +28,7 @@ Getting Started .. toctree:: :maxdepth: 1 - installation + install getting_started contributing changelog diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 00000000..0a5f9a39 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,145 @@ +************ +Installation +************ + +Requirements +============ + +Regions has the following strict requirements: + +* `Python `_ 3.6 or later + +* `Numpy `_ 1.16 or later + +* `Astropy`_ 3.2 or later + +Region also optionally depends on other packages for some features: + +* `matplotlib `_ 2.0 or later + +Regions depends on `pytest-astropy +`_ (0.4 or later) and +`pytest-arraydiff `_ (0.3 +or later) to run the test suite. + + +Installing the latest released version +====================================== + +The latest released (stable) version of Regions can be installed either +with `pip`_ or `conda`_. + +Using pip +--------- + +To install Regions with `pip`_, run:: + + pip install regions + +If you want to make sure that none of your existing dependencies get +upgraded, instead you can do:: + + pip install regions --no-deps + +Note that you may need a C compiler (e.g., ``gcc`` or ``clang``) to be +installed for the installation to succeed. + +If you get a ``PermissionError``, this means that you do not have the +required administrative access to install new packages to your Python +installation. In this case you may consider using the ``--user`` +option to install the package into your home directory. You can read +more about how to do this in the `pip documentation +`_. + +Do **not** install Regions or other third-party packages using +``sudo`` unless you are fully aware of the risks. + +Using conda +----------- + +Regions can be installed with `conda`_ if you have installed +`Anaconda `_ or +`Miniconda `_. +To install Regions using the `conda-forge Anaconda channel +`_, run:: + + conda install -c conda-forge regions + + +Installing the latest development version from Source +===================================================== + +Prerequisites +------------- + +You will need `Cython `_ (0.28 or later), a +compiler suite, and the development headers for Python and Numpy in +order to build Regions from the source distribution. On Linux, using the +package manager for your distribution will usually be the easiest route. + +On MacOS X you will need the `XCode`_ command-line tools, which can be +installed using:: + + xcode-select --install + +Follow the onscreen instructions to install the command-line tools +required. Note that you do not need to install the full `XCode`_ +distribution (assuming you are using MacOS X 10.9 or later). + + +Building and installing manually +-------------------------------- + +Regions is being developed on `GitHub`_. The latest development version +of the Regions source code can be retrieved using git:: + + git clone https://github.com/astropy/regions.git + +Then to build and install Regions, run:: + + cd regions + pip install ".[all]" + +If you wish to install the package in "editable" mode, instead include +the "-e" option:: + + pip install -e ".[all]" + + +Building and installing using pip +--------------------------------- + +Alternatively, `pip`_ can be used to retrieve, build, and install the +latest development version from `GitHub`_:: + + pip install git+https://github.com/astropy/regions.git + +Again, if you want to make sure that none of your existing +dependencies get upgraded, instead you can do:: + + pip install git+https://github.com/astropy/regions.git --no-deps + + +Testing an installed Regions +============================ + +The easiest way to test your installed version of Regions is running +correctly is to use the :func:`regions.test` function: + +.. doctest-skip:: + + >>> import regions + >>> regions.test() + +Note that this may not work if you start Python from within the Regions +source distribution directory. + +The tests should run and report any failures, +which you can report to the `Regions issue tracker +`_. + + +.. _pip: https://pip.pypa.io/en/latest/ +.. _conda: https://conda.io/en/latest/ +.. _GitHub: https://github.com/astropy/photutils +.. _Xcode: https://developer.apple.com/xcode/ diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index e47ae0f7..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. include:: references.txt - -.. _install: - -************ -Installation -************ - -The regions package requires the following packages: - -* Python 3.6 or later -* `Numpy `_ 1.16 or later -* `Astropy `__ 3.2 or later - -In addition, the following packages are needed for optional functionality: - -* `Matplotlib `__ 2.0 or later - -Stable version -============== - -Installing the latest stable version is possible either using pip or conda. - -Using pip ---------- - -To install regions with `pip `_ -from `PyPI `_, run:: - - pip install regions --no-deps - -.. note:: - - The ``--no-deps`` flag is optional, but highly recommended if you already - have Numpy installed, since otherwise pip will sometimes try to "help" you - by upgrading your Numpy installation, which may not always be desired. - -Using conda ------------ - -To install regions with `Anaconda `_, simply run:: - - conda install -c conda-forge regions - -Testing installation --------------------- - -To check if there are any issues with your installation, you can run the tests: - -.. code-block:: bash - - python -c 'import regions; regions.test()' - -Development version -=================== - -Install the latest development version from https://github.com/astropy/regions : - -.. code-block:: bash - - git clone https://github.com/astropy/regions - cd regions - python setup.py install - -To run the tests, you will need to make sure the `pytest-arraydiff -`_ package is installed -(version v0.3 or newer). Then, run the tests with: - -.. code-block:: bash - - python setup.py test - -To build the documentation, do: - -.. code-block:: bash - - python setup.py build_docs From f8fb9cd6f253c89224ce1c4b35a9de5932bb55a5 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 17:59:49 -0400 Subject: [PATCH 05/16] Add license page --- docs/index.rst | 1 + docs/license.rst | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 docs/license.rst diff --git a/docs/index.rst b/docs/index.rst index e2ae3486..c9995c55 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -31,6 +31,7 @@ Getting Started install getting_started contributing + license changelog diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 00000000..c1e765ba --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,8 @@ +.. _regions_license: + +License +======= + +Regions is licensed under a 3-clause BSD license: + +.. include:: ../LICENSE.rst From b2f72ec4414fc4b9d9e3dd77b66219a3e6d376a4 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 18:01:22 -0400 Subject: [PATCH 06/16] Update getting started docs --- docs/changelog.rst | 1 - docs/getting_started.rst | 168 +++++++++++++++++++++------------------ docs/shapes.rst | 3 +- regions/core/pixcoord.py | 4 +- 4 files changed, 93 insertions(+), 83 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 7552b062..f34a16c8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,5 @@ .. _changelog: - ************** Full Changelog ************** diff --git a/docs/getting_started.rst b/docs/getting_started.rst index bb888db3..3fc11535 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -2,34 +2,37 @@ .. _getting_started: -Getting started +Getting Started =============== -.. _gs-intro: - Introduction ------------ -The `regions` package provides (or plans to provide) classes to represent: +The Regions package provides classes to represent: -* Regions defined using pixel coordinates (`~regions.CirclePixelRegion`) -* Regions defined using celestial coordinates, but still in an Euclidean geometry (`~regions.CircleSkyRegion`) -* Regions defined on the celestial sphere (no examples yet) +* Regions defined using pixel coordinates (e.g., + `~regions.CirclePixelRegion`) +* Regions defined using celestial coordinates, but still in an Euclidean + geometry (e.g., `~regions.CircleSkyRegion`) -To transform between sky and pixel regions, a world coordinate system -(represented by a `~astropy.wcs.WCS` object) is needed. Some functions for -region-based calculations (e.g. filtering a table of sky or pixel positions) as -well as functions for region serialisation (e.g. to and from ds9/crtf region string -format) are available. +To transform between sky and pixel regions, a `world coordinate system +`_ object (e.g., +`astropy.wcs.WCS`) is needed. -.. _gs-ds: +Regions also provides a unified interface for reading, +writing, parsing, and serializing regions data in different +formats, including `CRTF (CASA Region Text Format) +`_, `DS9 Region Format +`_, and `FITS Region Binary Table +`_. -Dataset -------- +Example Dataset +--------------- -Throughout the documentation, we will be working with the same example dataset -and assume that you have run `~regions.make_example_dataset` to create example -``dataset`` and ``wcs`` objects like this: +Throughout the documentation, we will be working with the same example +dataset and assume that you have run `~regions.make_example_dataset` to +create example ``dataset`` and ``wcs`` objects like this: .. code-block:: python @@ -37,36 +40,38 @@ and assume that you have run `~regions.make_example_dataset` to create example >>> dataset = make_example_dataset(data='simulated') >>> wcs = dataset.wcs -For image examples, we will use the ``wcs`` and ``image`` attributes. For -example positions, we will use the ``source_table`` and ``event_table`` -attributes. +For image examples, we will use the ``wcs`` and ``image`` attributes. +For example positions, we will use the ``source_table`` and +``event_table`` attributes. -In your own analyses, you will usually load image data and WCS objects from file -or compute them with a Python script. We don't do this here, because we wanted -to make this tutorial independent of any example data files, to help you get -started quickly. +In your own analyses, you will usually load image data and WCS objects +from file or compute them with a Python script. We don't do this here, +because we wanted to make this tutorial independent of any example data +files, to help you get started quickly. -Also, this example image was created to illustrate some of the key issues when -working with regions. It represents an all-sky image in Aitoff (``AIT``) -projection, which means that there are pixels at the edge of the image that -don't correspond to positions on the sky. And the pixels are huge, roughly 10 -deg time 10 deg, which means that there are well-visible differences between sky -and pixel regions, caused by the WCS projection. +The example image was created to illustrate some of the key issues +when working with regions. It represents an all-sky image in Aitoff +(``AIT``) projection, which means that there are pixels at the edge of +the image that don't correspond to positions on the sky. And the pixels +are huge, roughly :math:`10 \times 10 \deg`, which means that there are +well-visible differences between sky and pixel regions, caused by the +WCS projection. Before we start diving into coding with regions, here's an image that -illustrates our example counts image, with source positions and a few regions -overplotted: +illustrates our example counts image, with source positions and a few +regions overplotted: .. plot:: plot_example.py :include-source: false -.. _gs-coord: + +.. _getting_started-coord: Coordinates ----------- -This regions package uses :class:`~astropy.coordinates.SkyCoord` objects to -represent sky coordinates. +This regions package uses :class:`~astropy.coordinates.SkyCoord` objects +to represent sky coordinates. .. code-block:: python @@ -76,7 +81,8 @@ represent sky coordinates. -To represent pixel coordinates, :class:`~regions.PixCoord` objects are used. +To represent pixel coordinates, :class:`~regions.PixCoord` objects are +used. .. code-block:: python @@ -88,18 +94,20 @@ To represent pixel coordinates, :class:`~regions.PixCoord` objects are used. 42 >>> pixcoord.y 43 + >>> pixcoord.xy + (42, 43) -`~astropy.coordinates.SkyCoord` is a very powerful and complex class (different -representations, a coordinate transformation tree) that is documented -extensively in the `astropy.coordinates` docs. +`~astropy.coordinates.SkyCoord` is a very powerful and complex class +(different representations, a coordinate transformation tree) that is +documented extensively in the `astropy.coordinates` docs. -In contrast, `~regions.PixCoord` is a small and simple helper class. The pixel -coordinate is always represented as cartesian coordinate data members ``x`` and -``y``. A pixel coordinate doesn't have a frame and is not connected to the -`astropy.coordinates` transformation tree. +In contrast, `~regions.PixCoord` is a small and simple helper class. +The pixel coordinate is always represented as cartesian coordinate data +members ``x`` and ``y``. A pixel coordinate doesn't have a frame and is +not connected to the `astropy.coordinates` transformation tree. -For a given image, represented by a `~astropy.wcs.WCS` object, it's easy to -transform back and forth between sky and pixel coordinates: +A WCS object is used to transform back and forth between sky and pixel +coordinates: .. code-block:: python @@ -111,14 +119,12 @@ transform back and forth between sky and pixel coordinates: -This is an object-oriented thin wrapper around the functionality provided by -`~astropy.wcs.WCS` and `astropy.wcs.utils`. - -It is possible to create `~astropy.coordinates.SkyCoord` and `~regions.PixCoord` -objects that represent arrays of pixel coordinates, and operations like -transforming between sky- and pixel or region containment checks work as -expected (i.e. return arrays of the same shape as the inputs, and perform -operations on array entries independently. +It is also possible to create `~astropy.coordinates.SkyCoord` and +`~regions.PixCoord` objects that represent arrays of pixel coordinates. +With such coordinates, operations like transforming between sky and +pixel or region containment checks work as expected (i.e., they return +arrays of the same shape as the inputs, and perform operations on array +entries independently). .. code-block:: python @@ -128,29 +134,25 @@ operations on array entries independently. PixCoord(x=[0 1], y=[2 3]) # Two-dimensional array pixel coordinates: - >>> pixcoord = PixCoord( - ... x=[[1, 2, 3], [4, 5, 6]], - ... y=[[11, 12, 13], [14, 15, 16]] - ... ) + >>> pixcoord = PixCoord(x=[[1, 2, 3], [4, 5, 6]], + ... y=[[11, 12, 13], [14, 15, 16]]) >>> print(pixcoord) PixCoord(x=[[1 2 3] [4 5 6]], y=[[11 12 13] [14 15 16]]) - To represent angles both on the sky and in an image, -`~astropy.coordinates.Angle` objects or `~astropy.units.Quantity` objects with -angular units can be used. +`~astropy.coordinates.Angle` objects or `~astropy.units.Quantity` +objects with angular units can be used. -.. _gs-sky: Sky regions ----------- -Sky regions are regions that are defined using celestial coordinates. Note that -these are **not** defined as regions on the celestial sphere, but rather are -meant to represent shapes on an image, but simply defined using celestial -coordinates as opposed to pixel coordinates. +Sky regions are regions that are defined using celestial coordinates. +Note that these are **not** defined as regions on the celestial sphere, +but rather are meant to represent shapes on an image, but simply defined +using celestial coordinates as opposed to pixel coordinates. This is how to create a sky region: @@ -163,6 +165,18 @@ This is how to create a sky region: >>> radius = Angle(3, 'deg') >>> region = CircleSkyRegion(center, radius) +Alternatively, one can define the radius using a +`~astropy.units.Quantity` object with angular units: + +.. code-block:: python + + >>> import astropy.units as u + >>> from regions import CircleSkyRegion + + >>> center = SkyCoord(42, 43, unit='deg') + >>> radius = 3.0 * u.deg + >>> region = CircleSkyRegion(center, radius) + You can print the regions to get some info about its properties: .. code-block:: python @@ -173,27 +187,25 @@ You can print the regions to get some info about its properties: (42., 43.)> radius: 3.0 deg -To see a list of all available sky regions, you can go to the API docs or in -IPython print the list using: +To see a list of all available sky regions, you can go to the API docs +or in IPython print the list using: .. code-block:: none In [1]: import regions In [2]: regions.*SkyRegion? -.. _gs-pix: Pixel regions ------------- -In some cases you might instead want to directly represent a region in pixel -coordinates. For those, there's a `~regions.PixCoord` class to represent a -point, and a set of "pixel region" classes. One example is -`~regions.CirclePixelRegion`: +In some cases you might instead want to directly represent a region in +pixel coordinates. For those, there's a `~regions.PixCoord` class to +represent an (x, y) pixel coordinate and a set of "pixel-based region" +classes. One example is `~regions.CirclePixelRegion`: .. code-block:: python - >>> from astropy.coordinates import Angle, SkyCoord >>> from regions import PixCoord, CirclePixelRegion >>> center = PixCoord(x=42, y=43) @@ -209,13 +221,13 @@ You can print the regions to get some info about its properties: center: PixCoord(x=42, y=43) radius: 4.2 -To see a list of all available sky regions, you can go to the API docs or in -IPython print the list using: +To see a list of all available sky regions, you can go to the API docs +or in IPython print the list using: .. code-block:: none In [1]: import regions In [2]: regions.*PixelRegion? -To learn more about :class:`~regions.Region` and it's capabilities in -:ref:`sh` +To learn more about :class:`~regions.Region` objects and their +capabilities see the :ref:`shapes` documentation. diff --git a/docs/shapes.rst b/docs/shapes.rst index 13106ec4..dc8ed4ed 100644 --- a/docs/shapes.rst +++ b/docs/shapes.rst @@ -5,9 +5,8 @@ >>> dataset = make_example_dataset(data='simulated') >>> wcs = dataset.wcs -.. _sh: -.. _sh-shapes: +.. _shapes: Shapes ====== diff --git a/regions/core/pixcoord.py b/regions/core/pixcoord.py index aaf7c5de..af81fce3 100644 --- a/regions/core/pixcoord.py +++ b/regions/core/pixcoord.py @@ -34,8 +34,8 @@ class PixCoord: Examples -------- - Usage examples are provided in the :ref:`gs-coord` section of the - docs. + Usage examples are provided in the :ref:`getting-started-coord` + section of the documentation. """ def __init__(self, x, y): From 7bcc0be8a8242b46d4cd838d7c9477a5d6093283 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Fri, 16 Jul 2021 20:19:11 -0400 Subject: [PATCH 07/16] Update shapes docs --- docs/shapes.rst | 530 +++++++++++++++++++++++++----------------------- 1 file changed, 279 insertions(+), 251 deletions(-) diff --git a/docs/shapes.rst b/docs/shapes.rst index dc8ed4ed..d39a1515 100644 --- a/docs/shapes.rst +++ b/docs/shapes.rst @@ -11,185 +11,231 @@ Shapes ====== -This section shows one example how to construct a region for each shape that's -currently supported. +Regions provides `~regions.Region` objects, defined in pixel or sky +coordinates, representing shapes such as circles, ellipses, rectangles, +polygons, lines, and points. There are also regions defining circular, +elliptical, and rectangular annuli. -* `~regions.CircleSkyRegion` and `~regions.CirclePixelRegion` + +Defining Shapes +--------------- + +This section shows examples of how to construct a region for each shape +that's currently supported. + +Circle +****** + +`~regions.CircleSkyRegion` and `~regions.CirclePixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord >>> from astropy import units as u - >>> from regions import PixCoord, CircleSkyRegion, CirclePixelRegion + >>> from regions import PixCoord + >>> from regions import CircleSkyRegion, CirclePixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> circle_sky = CircleSkyRegion(center=center_sky, radius=3 * u.deg) - >>> circle_pix = CirclePixelRegion(center=PixCoord(x=42, y=43), + >>> region_sky = CircleSkyRegion(center=center_sky, radius=3 * u.deg) + >>> region_pix = CirclePixelRegion(center=PixCoord(x=42, y=43), ... radius=4.2) -* `~regions.CircleAnnulusSkyRegion` and `~regions.CircleAnnulusPixelRegion` + +`~regions.CircleAnnulusSkyRegion` and `~regions.CircleAnnulusPixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord >>> from astropy import units as u - >>> from regions import PixCoord, CircleAnnulusSkyRegion, CircleAnnulusPixelRegion + >>> from regions import PixCoord + >>> from regions import CircleAnnulusSkyRegion, CircleAnnulusPixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> circle_annulus_sky = CircleAnnulusSkyRegion(center=center_sky, - ... inner_radius=3 * u.deg, - ... outer_radius=4 * u.deg) - >>> circle_annulus_pix = CircleAnnulusPixelRegion(center=PixCoord(x=42, y=43), - ... inner_radius=4.2, - ... outer_radius=5.2) + >>> region_sky = CircleAnnulusSkyRegion(center=center_sky, + ... inner_radius=3 * u.deg, + ... outer_radius=4 * u.deg) + >>> region_pix = CircleAnnulusPixelRegion(center=PixCoord(x=42, y=43), + ... inner_radius=4.2, + ... outer_radius=5.2) + -* `~regions.EllipseSkyRegion` and `~regions.EllipsePixelRegion` +Ellipse +******* + +`~regions.EllipseSkyRegion` and `~regions.EllipsePixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord >>> from astropy import units as u - >>> from regions import PixCoord, EllipseSkyRegion, EllipsePixelRegion + >>> from regions import PixCoord + >>> from regions import EllipseSkyRegion, EllipsePixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> ellipse_sky = EllipseSkyRegion(center=center_sky, - ... height=3 * u.deg, width=3 * u.deg, - ... angle=5 * u.deg) - >>> ellipse_pix = EllipsePixelRegion(center=PixCoord(x=42, y=43), - ... height=4.2, width=4.2, - ... angle=5 * u.deg) + >>> region_sky = EllipseSkyRegion(center=center_sky, + ... height=3 * u.deg, width=3 * u.deg, + ... angle=5 * u.deg) + >>> region_pix = EllipsePixelRegion(center=PixCoord(x=42, y=43), + ... height=4.2, width=4.2, + ... angle=5 * u.deg) + -* `~regions.EllipseAnnulusSkyRegion` and `~regions.EllipseAnnulusPixelRegion` +`~regions.EllipseAnnulusSkyRegion` and +`~regions.EllipseAnnulusPixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord >>> from astropy import units as u - >>> from regions import PixCoord, EllipseAnnulusSkyRegion, EllipseAnnulusPixelRegion + >>> from regions import PixCoord + >>> from regions import EllipseAnnulusSkyRegion, EllipseAnnulusPixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> ellipse_annulus_sky = EllipseAnnulusSkyRegion(center=center_sky, - ... inner_width=3 * u.deg, - ... outer_width=4 * u.deg, - ... inner_height=6 * u.deg, - ... outer_height=7 * u.deg, - ... angle=6 * u.deg) - >>> ellipse_annulus_pix = EllipseAnnulusPixelRegion(center=PixCoord(x=42, y=43), - ... inner_width=4.2, - ... outer_width=5.2, - ... inner_height=7.2, - ... outer_height=8.2, - ... angle=6 * u.deg) - -* `~regions.PointSkyRegion` and `~regions.PointPixelRegion` + >>> region_sky = EllipseAnnulusSkyRegion(center=center_sky, + ... inner_width=3 * u.deg, + ... outer_width=4 * u.deg, + ... inner_height=6 * u.deg, + ... outer_height=7 * u.deg, + ... angle=6 * u.deg) + >>> region_pix = EllipseAnnulusPixelRegion(center=PixCoord(x=42, y=43), + ... inner_width=4.2, + ... outer_width=5.2, + ... inner_height=7.2, + ... outer_height=8.2, + ... angle=6 * u.deg) + + +Rectangle +********* + +`~regions.RectangleSkyRegion` and `~regions.RectanglePixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord - >>> from regions import PixCoord, PointSkyRegion, PointPixelRegion + >>> from astropy import units as u + >>> from regions import PixCoord + >>> from regions import RectangleSkyRegion, RectanglePixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> point_sky = PointSkyRegion(center=center_sky) - >>> point_pix = PointPixelRegion(center=PixCoord(x=42, y=43)) + >>> region_sky = RectangleSkyRegion(center=center_sky, + ... width=3 * u.deg, height=4 * u.deg, + ... angle=5 * u.deg) + >>> region_pix = RectanglePixelRegion(center=PixCoord(x=42, y=43), + ... width=3, height=4, + ... angle=5 * u.deg) -* `~regions.TextSkyRegion` and `~regions.TextPixelRegion` + +`~regions.RectangleAnnulusSkyRegion` and +`~regions.RectangleAnnulusPixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord - >>> from regions import PixCoord, TextSkyRegion, TextPixelRegion + >>> from astropy import units as u + >>> from regions import PixCoord, RectangleAnnulusSkyRegion + >>> from regions import RectangleAnnulusPixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> point_sky = TextSkyRegion(center=center_sky, text='Demo Text') - >>> point_pix = TextPixelRegion(center=PixCoord(x=42, y=43), text='Demo Text') + >>> region_sky = RectangleAnnulusSkyRegion(center=center_sky, + ... inner_width=3 * u.deg, + ... outer_width=4 * u.deg, + ... inner_height=6 * u.deg, + ... outer_height=7 * u.deg, + ... angle=15 * u.deg) + >>> region_pix = RectangleAnnulusPixelRegion(center=PixCoord(x=42, y=43), + ... inner_width=4.2, + ... outer_width=5.2, + ... inner_height=7.2, + ... outer_height=8.2, + ... angle=15 * u.deg) + + +Polygon +******* + +.. Polygons are the most versatile region, since any region can be +.. approximated as a polygon. +.. +.. TODO: explain how polygons are implemented and special polygon +.. methods, e.g. how to obtain a polygon approximation for any shape. +.. This is not available yet, for now see `spherical_geometry`_ for +.. spherical polygons and `Shapely`_ for pixel polygons. -* `~regions.LineSkyRegion` and `~regions.LinePixelRegion` +`~regions.PolygonSkyRegion` and `~regions.PolygonPixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord - >>> from regions import PixCoord, LineSkyRegion, LinePixelRegion + >>> from regions import PixCoord, PolygonSkyRegion, PolygonPixelRegion - >>> start_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> end_sky = SkyCoord(52, 53, unit='deg', frame='fk5') - >>> line_sky = LineSkyRegion(start=start_sky, end=end_sky) - >>> line_pix = LinePixelRegion(start=PixCoord(x=42, y=43), end=PixCoord(x=52, y=53)) + >>> vertices = SkyCoord([1, 2, 2], [1, 1, 2], unit='deg', frame='fk5') + >>> region_sky = PolygonSkyRegion(vertices=vertices) + >>> vertices = PixCoord(x=[1, 2, 2], y=[1, 1, 2])) + >>> region_pix = PolygonPixelRegion(vertices=vertices) -* `~regions.RectangleSkyRegion` and `~regions.RectanglePixelRegion` + +Point +***** + +`~regions.PointSkyRegion` and `~regions.PointPixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord - >>> from astropy import units as u - >>> from regions import PixCoord, RectangleSkyRegion, RectanglePixelRegion + >>> from regions import PixCoord, PointSkyRegion, PointPixelRegion >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> rectangle_sky = RectangleSkyRegion(center=center_sky, - ... width=3 * u.deg, height=4 * u.deg, - ... angle=5 * u.deg) - >>> rectangle_pix = RectanglePixelRegion(center=PixCoord(x=42, y=43), - ... width=3, height=4, - ... angle=5 * u.deg) + >>> region_sky = PointSkyRegion(center=center_sky) + >>> region_pix = PointPixelRegion(center=PixCoord(x=42, y=43)) -* `~regions.RectangleAnnulusSkyRegion` and `~regions.RectangleAnnulusPixelRegion` + +Line +**** + +`~regions.LineSkyRegion` and `~regions.LinePixelRegion` .. code-block:: python >>> from astropy.coordinates import SkyCoord - >>> from astropy import units as u - >>> from regions import PixCoord, RectangleAnnulusSkyRegion, RectangleAnnulusPixelRegion + >>> from regions import PixCoord, LineSkyRegion, LinePixelRegion - >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') - >>> rectangle_annulus_sky = RectangleAnnulusSkyRegion(center=center_sky, - ... inner_width=3 * u.deg, - ... outer_width=4 * u.deg, - ... inner_height=6 * u.deg, - ... outer_height=7 * u.deg, - ... angle=15 * u.deg) - >>> rectangle_annulus_pix = RectangleAnnulusPixelRegion(center=PixCoord(x=42, y=43), - ... inner_width=4.2, - ... outer_width=5.2, - ... inner_height=7.2, - ... outer_height=8.2, - ... angle=15 * u.deg) - -* `~regions.PolygonSkyRegion` and `~regions.PolygonPixelRegion` + >>> start_sky = SkyCoord(42, 43, unit='deg', frame='fk5') + >>> end_sky = SkyCoord(52, 53, unit='deg', frame='fk5') + >>> region_sky = LineSkyRegion(start=start_sky, end=end_sky) + >>> region_pix = LinePixelRegion(start=PixCoord(x=42, y=43), + ... end=PixCoord(x=52, y=53)) -.. code-block:: python - >>> from astropy.coordinates import SkyCoord - >>> from regions import PixCoord, PolygonSkyRegion, PolygonPixelRegion +Text +***** - >>> polygon_sky = PolygonSkyRegion(vertices=SkyCoord([1, 2, 2], [1, 1, 2], unit='deg', frame='fk5')) - >>> polygon_pix = PolygonPixelRegion(vertices=PixCoord(x=[1, 2, 2], y=[1, 1, 2])) +The text regions can be used to annotate a text string on an image. -.. .. _sh-poly: -.. -.. Polygons -.. -------- -.. -.. Polygons are the most versatile region, since any region can be approximated -.. as a polygon. -.. -.. TODO: explain how polygons are implemented and special polygon methods, -.. e.g. how to obtain a polygon approximation for any shape. -.. This is not available yet, for now see `spherical_geometry`_ -.. for spherical polygons and `Shapely`_ for pixel polygons. +`~regions.TextSkyRegion` and `~regions.TextPixelRegion` -.. _sh-wcs: +.. code-block:: python + + >>> from astropy.coordinates import SkyCoord + >>> from regions import PixCoord, TextSkyRegion, TextPixelRegion + + >>> center_sky = SkyCoord(42, 43, unit='deg', frame='fk5') + >>> point_sky = TextSkyRegion(center=center_sky, text='Demo Text') + >>> point_pix = TextPixelRegion(center=PixCoord(x=42, y=43), + ... text='Demo Text') -Transformations ---------------- -In the last two sections, we talked about how for every region shape (e.g. -circle), there are two classes, one representing "sky regions" and another -representing "pixel regions" on a given image. +Region Transformations +---------------------- -A key feature of the regions package is that, for a given image, more precisely -a given `~astropy.wcs.WCS` object, it is possible to convert back and forth -between sky and image regions. +For every region shape there are two classes, one representing a "sky +region" and another representing a "pixel region" on a given image. A +key feature of the regions package is that it is possible to convert +back and forth between sky and image regions given a WCS object (e.g., +`astropy.wcs.WCS`). -As an example, let's use this :class:`~regions.CircleSkyRegion`, a sky circle region: +As an example, let's use the :class:`~regions.CircleSkyRegion`, a sky +circle region: .. code-block:: python @@ -200,8 +246,9 @@ As an example, let's use this :class:`~regions.CircleSkyRegion`, a sky circle re >>> radius = Angle(30, 'arcsec') >>> sky_reg = CircleSkyRegion(center, radius) -To convert it to a :class:`~regions.PixelRegion`, call the -:meth:`~regions.SkyRegion.to_pixel` method: +To convert it to a pixel circle region (i.e., +:class:`~regions.CirclePixelRegion`), call the +:meth:`~regions.SkyRegion.to_pixel` method with a WCS object: .. code-block:: python @@ -211,8 +258,9 @@ To convert it to a :class:`~regions.PixelRegion`, call the center: PixCoord(x=55.35205711214607, y=40.0958313892697) radius: 0.010259141135043101 -Also to convert a :class:`~regions.PixelRegion` to a -:class:`~regions.SkyRegion`, call the :meth:`~regions.PixelRegion.to_sky` method: +Also to convert a :class:`~regions.PixelRegion` +to a :class:`~regions.SkyRegion`, call the +:meth:`~regions.PixelRegion.to_sky` method with a WCS object: .. code-block:: python @@ -223,207 +271,189 @@ Also to convert a :class:`~regions.PixelRegion` to a (172.17231545, -38.27972337)> radius: 18.55481729935556 arcsec -.. _sh-meta: - -Meta Data ---------- - -A :class:`~regions.Region` has ``meta`` and ``visual`` attributes which -stores the meta data of the region. Since this package supports various file -formats it is necessary to handle the meta attributes supported by them. -To handle them there are :class:`~regions.RegionMeta` and -:class:`~regions.RegionVisual` for meta and visual attributes respectively. -They are subclasses of the python dictionary (`~dict`). - -The meta attribute provides additional data about regions such as labels, tags, -comments, name, etc. which are used for non-display tasks. -It also stores the spectral dimensions of the region. -These classes, for now, just check whether the key is valid or not. - -The valid keys for :class:`~regions.RegionMeta` class are: - -1. ``label``: - - - CRTF, DS9 (text label for a region) - - - Ex: meta['label'] = 'this is a circle' - -2. ``tag``: - - - DS9 (All regions may have zero or more tags associated with it, - which may be used for grouping and searching.) - - - Ex: meta['tags'] = ['{Group 1}', '{Group 2}']} - -3. ``include``: - - - CRTF, DS9 (Region inclusion) - - - Possible Values: True, False - - - Ex: meta['include'] = True - -4. ``frame``: - - - CRTF (Frequency/Velocity Axis) - - - Possible values: 'REST', 'LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', 'GALACTO', 'LGROUP', 'CMB' - - - Default: image value - - - Ex: meta['frame'] = 'TOPO' - -5. ``range``: - - - CRTF (Frequency/Velocity Range) - - - Possible units: GHz, MHz, kHz, km/s, Hz, channel, chan (=channel) - - - Default: image range - - Format: [min, max] +Metadata +-------- - - Ex: meta['range'] = [-320 * u.m/u.sec, -330 * u.m/u.s] +A :class:`~regions.Region` object has both ``meta`` and +``visual`` attributes that store the metadata of the region. The +:class:`~regions.RegionMeta` and :class:`~regions.RegionVisual` classes +handle the metadata and visual attributes, respectively. Both behave +like Python dictionaries. -6. ``veltype``: +The ``meta`` attribute stores additional metadata about the region such +as labels, tags, comments, name, etc. that are used for non-display +tasks. It can also store the spectral dimensions of the region. The +``visual`` attribute stores visual properties for the region such as +color, font style, font size, line width, line style, etc. - - CRTF (Velocity Calculation) +The valid keys in the :class:`~regions.RegionMeta` object are: - - Possible values: 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA' +* ``label``: - - Default: image value + - CRTF, DS9 (text label for a region) + - Ex: meta['label'] = 'this is a circle' - - Ex: meta['veltype'] = 'RADIO' +* ``tag``: -7. ``restfreq``: + - DS9 (All regions may have zero or more tags associated with it, + which may be used for grouping and searching.) - - CRTF (Rest Frequency) + - Ex: meta['tags'] = ['{Group 1}', '{Group 2}']} - - Possible values: `~astropy.units.Quantity` object +* ``include``: - - Default: image value + - CRTF, DS9 (Region inclusion) + - Possible Values: True, False + - Ex: meta['include'] = True - - Ex: meta['restfreq'] = Quantity("1.42GHz") +* ``frame``: -8. ``corr``: + - CRTF (Frequency/Velocity Axis) + - Possible values: 'REST', 'LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', + 'GALACTO', 'LGROUP', 'CMB' + - Default: image value + - Ex: meta['frame'] = 'TOPO' - - CRTF (Correlational Axis) +* ``range``: - - Possible values: 'I', 'Q', 'U', 'V', 'RR', 'RL', 'LR', 'LL', 'XX', 'XY', - 'YX', 'YY', 'RX', 'RY', 'LX', 'LY', 'XR', 'XL', 'YR', 'YL', 'PP', 'PQ', - 'QP', 'QQ', 'RCircular', 'LCircular', 'Linear', 'Ptotal', 'Plinear', - 'PFtotal', 'PFlinear', 'Pangle' + - CRTF (Frequency/Velocity Range) + - Possible units: GHz, MHz, kHz, km/s, Hz, channel, chan (=channel) + - Default: image range + - Format: [min, max] + - Ex: meta['range'] = [-320 * u.m/u.sec, -330 * u.m/u.s] - - Default: all planes present in image +* ``veltype``: - - Ex: meta['corr'] = ['X', 'Y'] + - CRTF (Velocity Calculation) + - Possible values: 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA' + - Default: image value + - Ex: meta['veltype'] = 'RADIO' -9. ``comment``: +* ``restfreq``: - - DS9, CRTF (Comment on the region) + - CRTF (Rest Frequency) + - Possible values: `~astropy.units.Quantity` object + - Default: image value + - Ex: meta['restfreq'] = Quantity("1.42GHz") - - Ex: meta['comment'] = 'Any comment for the region' +* ``corr``: -11. ``line``: + - CRTF (Correlational Axis) + - Possible values: 'I', 'Q', 'U', 'V', 'RR', 'RL', 'LR', 'LL', + 'XX', 'XY', 'YX', 'YY', 'RX', 'RY', 'LX', 'LY', 'XR', 'XL', 'YR', + 'YL', 'PP', 'PQ', 'QP', 'QQ', 'RCircular', 'LCircular', 'Linear', + 'Ptotal', 'Plinear', 'PFtotal', 'PFlinear', 'Pangle' + - Default: all planes present in image + - Ex: meta['corr'] = ['X', 'Y'] - - DS9 (The line region may be rendered with arrows, one at each end. - To indicate arrows, use the line property. A '1' indicates an arrow, '0' - indicates no arrow.) +* ``comment``: - - Ex: meta['line'] = [1, 1] + - DS9, CRTF (Comment on the region) + - Ex: meta['comment'] = 'Any comment for the region' -12. ``name`` +* ``line``: -13. ``select`` + - DS9 (The line region may be rendered with arrows, one at each end. + To indicate arrows, use the line property. A '1' indicates an arrow, + '0' indicates no arrow.) + - Ex: meta['line'] = [1, 1] -14. ``highlite`` +* ``name`` -15. ``fixed`` +* ``select`` -16. ``edit``: +* ``highlite`` - - DS9 (The Edit property specifies if the user is allowed to edit - the region via the GUI.) +* ``fixed`` - - Ex: meta['edit'] = 1 +* ``edit``: -17. ``move``: + - DS9 (The Edit property specifies if the user is allowed to edit the + region via the GUI.) + - Ex: meta['edit'] = 1 - - DS9 (The Move property specifies if the user is allowed to move - the region via the GUI. ) +* ``move``: - - Ex: meta['move'] = 1 + - DS9 (The Move property specifies if the user is allowed to move the + region via the GUI. ) + - Ex: meta['move'] = 1 -18. ``rotate``: +* ``rotate``: - - DS9 (The Rotate property specifies if the user is allowed to - rotate the region via the GUI. ) + - DS9 (The Rotate property specifies if the user is allowed to rotate + the region via the GUI. ) + - Ex: meta['rotate'] = 1 - - Ex: meta['rotate'] = 1 +* ``delete``: -19. ``delete``: + - DS9 (The Delete property specifies if the user is allowed to delete + the region via the GUI. ) + - Ex: meta['delete'] = 1 - - DS9 (The Delete property specifies if the user is allowed to - delete the region via the GUI. ) +* ``source`` - - Ex: meta['delete'] = 1 +* ``background`` -20. ``source`` -21. ``background`` +The visual attributes are metadata meant to be used to visualize +regions, especially used by plotting libraries such as `Matplotlib`_ . +The valid keys in the `~regions.RegionVisual` class are: -The visual attributes are meta data meant to be used to visualize regions, especially -used by plotting libraries such as `Matplotlib`_ . +* ``color``: CRTF, DS9 (Region, symbol and text color) -The valid keys for `~regions.RegionVisual` class are: + - Possible values: any color recognized by `Matplotlib`_, including + hex values + - Default: color=green + - Ex: visual['color'] = 'blue' -1. ``color``: CRTF, DS9 (Region, symbol and text color) - - Possible values: any color recognized by `Matplotlib`_, including hex values - - Default: color=green - - Ex: visual['color'] = 'blue' +* ``dash``: Render region using dashed lines using current dashlist + value. -2. ``dash``: Render region using dashed lines using current dashlist value. +* ``font``: Name of the font. -3. ``font``: Name of the font. +* ``dashlist``: Sets dashed line parameters. This does not render the + region in dashed lines. -4. ``dashlist``: Sets dashed line parameters. This does not render the region in dashed lines. +* ``symsize``: Size of the symbol. -5. ``symsize``: Size of the symbol +* ``symthick``: Thickness of the symbol. -6. ``symthick``: Thickness of the symbol +* ``fontsize``: Size of the font. -7. ``fontsize``: Size of the font. +* ``fontstyle``: Style of the font. -8. ``fontstyle``: Style of the font. +* ``usetex``: Boolean value whether the label uses TeX. -9. ``usetex``: Boolean value whether the label uses tex. +* ``labelpos``: Position of the label. -10. ``labelpos``: position of the label +* ``labeloff``: Label offset. -11. ``labeloff``: label offset +* ``linewidth``: Width of the line. -12. ``linewidth``: width of the line +* ``linestyle``: Style of the line. -13. ``linestyle``: style of the line +* ``fill``: Boolean value whether the region is filled. -14. ``fill``: Boolean value whether the regions is filled +* ``line``: The line region may be rendered with arrows, one at each + end. To indicate arrows, use the line property. A '1' indicates an + arrow, '0' indicates no arrow. -15. ``line``: The line region may be rendered with arrows, one at each end. - To indicate arrows, use the line property. A '1' indicates an arrow, '0' indicates no arrow. +* ``symbol``/``point``: CRTF, DS9 (Symbol for which a point region is + described) -16. ``symbol``/``point``: CRTF, DS9 (Symbol for which a point region is described) + - Ex: meta['symbol'] = 'point marker' - - Ex: meta['symbol'] = 'point marker' .. _sh-lists: -Lists ------ +Multiple Regions +---------------- -A `~regions.Region` object can only represent one region, not -an array (a.k.a. vector or list) of regions. +A `~regions.Region` object can represent only one region, not an array +(e.g., vector or list) of regions. This is in contrast to the aperture classes in `Photutils `__ like @@ -437,17 +467,15 @@ This is in contrast to the aperture classes in `Photutils >>> apertures = CircularAperture(positions, r=4.2) To represent lists of `~regions.Region` objects, you can store them in -Python lists (or other containers, but lists are the most common). -To create many similar regions or process many regions you can use for loops or -list comprehensions. +Python lists (or other containers, but lists are the most common). To +create many similar regions or process many regions you can use for +loops or list comprehensions. .. code-block:: python >>> from regions import PixCoord, CirclePixelRegion - >>> regions = [ - ... CirclePixelRegion(center=PixCoord(x, y), radius=4.2) - ... for x, y in [(1, 2), (3, 4)] - ... ] + >>> regions = [CirclePixelRegion(center=PixCoord(x, y), radius=4.2) + ... for x, y in [(1, 2), (3, 4)]] >>> for region in regions: ... print(region.center) PixCoord(x=1, y=2) From 77eb5b47640b92ca930df32facd66016881460a9 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 13:04:23 -0400 Subject: [PATCH 08/16] Update contains docs --- docs/contains.rst | 48 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/docs/contains.rst b/docs/contains.rst index a7082e08..415ee521 100644 --- a/docs/contains.rst +++ b/docs/contains.rst @@ -1,17 +1,7 @@ -.. testsetup: - >>> from regions import make_example_dataset - >>> dataset = make_example_dataset(data='simulated') - >>> wcs = dataset.wcs - -.. _gs-contain: - Checking for points inside regions ================================== -Let's continue with sky and pixel regions defined in the -:ref:`getting_started` section: - -.. code-block:: python +Let's start by defining both a sky and pixel region:: >>> from astropy.coordinates import Angle, SkyCoord >>> from regions import CircleSkyRegion, PixCoord, CirclePixelRegion @@ -19,25 +9,28 @@ Let's continue with sky and pixel regions defined in the >>> sky_center = SkyCoord(42, 43, unit='deg') >>> sky_radius = Angle(25, 'deg') >>> sky_region = CircleSkyRegion(sky_center, sky_radius) - >>> pixel_center = PixCoord(x=42, y=43) - >>> pixel_radius = 42 - >>> pixel_region = CirclePixelRegion(pixel_center, pixel_radius) - >>> print(sky_region) Region: CircleSkyRegion center: radius: 25.0 deg + + >>> pixel_center = PixCoord(x=42, y=43) + >>> pixel_radius = 42 + >>> pixel_region = CirclePixelRegion(pixel_center, pixel_radius) >>> print(pixel_region) Region: CirclePixelRegion center: PixCoord(x=42, y=43) radius: 42 +Let's also define a WCS object using our example dataset:: -To test if a given point is inside or outside the regions, the Python ``in`` operator -can be called, which calls the special ``__contains__`` method defined on the region classes: + >>> from regions import make_example_dataset + >>> dataset = make_example_dataset(data='simulated') + >>> wcs = dataset.wcs -.. code-block:: python +To test if a given point is inside or outside the region, the Python +``in`` operator can be called:: >>> from regions import PixCoord >>> PixCoord(55, 40) in pixel_region @@ -45,11 +38,9 @@ can be called, which calls the special ``__contains__`` method defined on the re >>> PixCoord(55, 200) in pixel_region False -The ``in`` operator only works for scalar coordinates, because Python requires -the return value to be a scalar bool, and only works for pixel regions. If you -try to use ``in`` for non-scalar coordinates, you'll get a ``ValueError``: - -.. code-block:: python +The ``in`` operator works only for scalar coordinates and pixel regions. +If you try to use ``in`` for non-scalar coordinates, you'll get a +`ValueError`:: >>> pixcoord = PixCoord([50, 50], [10, 60]) >>> pixcoord in pixel_region @@ -57,19 +48,14 @@ try to use ``in`` for non-scalar coordinates, you'll get a ``ValueError``: ... ValueError: coord must be scalar. coord=PixCoord(x=[50 50], y=[10 60]) -If you have arrays of coordinates, use the `regions.SkyRegion.contains` or -`regions.PixelRegion.contains` methods: - -.. code-block:: python +If you have arrays of coordinates, use the `regions.SkyRegion.contains` +or `regions.PixelRegion.contains` methods:: >>> pixcoords = PixCoord.from_sky(sky_center, wcs) >>> pixel_region.contains(pixcoords) True -Note that `regions.SkyRegion.contains` -requires a WCS to be passed: - -.. code-block:: python +Note that `regions.SkyRegion.contains` requires a WCS to be passed:: >>> skycoord = SkyCoord([50, 50], [10, 60], unit='deg') >>> sky_region.contains(skycoord, wcs) From e6c54b68ada86cefb1cb188ce178ac975acd054f Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 13:29:17 -0400 Subject: [PATCH 09/16] Update docs for combining regions --- docs/compound.rst | 113 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 21 deletions(-) diff --git a/docs/compound.rst b/docs/compound.rst index 154b9921..212a8b93 100644 --- a/docs/compound.rst +++ b/docs/compound.rst @@ -1,32 +1,44 @@ - -.. _gs-compound: - Combining regions ================= -There's a few ways to combine any two `~regions.Region` objects into a compound region, -i.e. a `~regions.CompoundPixelRegion` or `~regions.CompoundSkyRegion` object. +There are a few ways to combine any two `~regions.Region` objects +into a compound region, i.e., a `~regions.CompoundPixelRegion` or +`~regions.CompoundSkyRegion` object. -* The ``&`` operator calls the ``__and__`` method which calls the :meth:`~regions.Region.intersection` method - to create an intersection compound region. -* The ``|`` operator calls the ``__or__`` method which calls the :meth:`~regions.Region.union` method - to create a union compound region. -* The ``^`` operator calls the ``__xor__`` method which calls the :meth:`~regions.Region.symmetric_difference` method - to create a symmetric difference compound region. - -.. code-block:: python +Let's start by defining two sky regions:: >>> from astropy.coordinates import Angle, SkyCoord >>> from regions import CircleSkyRegion + >>> circle1 = CircleSkyRegion( - ... center=SkyCoord(1,2, unit='deg', frame='galactic'), - ... radius=Angle('5 deg') - ... ) + ... center=SkyCoord(1, 2, unit='deg', frame='galactic'), + ... radius=Angle('5 deg')) >>> circle2 = CircleSkyRegion( - ... center=SkyCoord(-4,3, unit='deg', frame='galactic'), - ... radius=Angle('3 deg'), - ... ) - >>> print(circle1 & circle2) + ... center=SkyCoord(-4, 3, unit='deg', frame='galactic'), + ... radius=Angle('3 deg')) + + +Intersection (AND) +------------------ + +To create an intersection compound region, use either the ``&`` operator +or the :meth:`~regions.Region.intersection` method:: + + >>> comp_region = circle1 & circle2 + >>> print(comp_region) + Region: CompoundSkyRegion + region1: Region: CircleSkyRegion + center: + radius: 5.0 deg + region2: Region: CircleSkyRegion + center: + radius: 3.0 deg + operator: + + >>> comp_region = circle1.intersection(circle2) + >>> print(comp_region) Region: CompoundSkyRegion region1: Region: CircleSkyRegion center: radius: 3.0 deg operator: - >>> print(circle1 ^ circle2) + + +Union (OR) +---------- + +To create a union compound region, use either the ``|`` operator or the +:meth:`~regions.Region.union` method:: + + >>> comp_region = circle1 | circle2 + >>> print(comp_region) + Region: CompoundSkyRegion + region1: Region: CircleSkyRegion + center: + radius: 5.0 deg + region2: Region: CircleSkyRegion + center: + radius: 3.0 deg + operator: + + >>> comp_region = circle1.union(circle2) + >>> print(comp_region) + Region: CompoundSkyRegion + region1: Region: CircleSkyRegion + center: + radius: 5.0 deg + region2: Region: CircleSkyRegion + center: + radius: 3.0 deg + operator: + + +Symmetric Difference (XOR) +-------------------------- + +To create a symmetric difference compound region, use either the ``^`` +operator or the :meth:`~regions.Region.symmetric_difference` method:: + + >>> comp_region = circle1 ^ circle2 + >>> print(comp_region) + Region: CompoundSkyRegion + region1: Region: CircleSkyRegion + center: + radius: 5.0 deg + region2: Region: CircleSkyRegion + center: + radius: 3.0 deg + operator: + + >>> comp_region = circle1.symmetric_difference(circle2) + >>> print(comp_region) Region: CompoundSkyRegion region1: Region: CircleSkyRegion center: + +Example Illustrating Compound Regions +------------------------------------- + .. plot:: plot_compound.py :include-source: false From 4702e6736fb055abbf00ab7e708956e07e043735 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 14:16:41 -0400 Subject: [PATCH 10/16] Update region I/O docs --- docs/region_io.rst | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/region_io.rst b/docs/region_io.rst index a15ea6bc..be170829 100644 --- a/docs/region_io.rst +++ b/docs/region_io.rst @@ -7,13 +7,14 @@ The regions package provides a unified interface for reading, writing, parsing, and serializing regions data in different formats. -Getting Started with Regions I/O -================================ +Regions I/O +=========== -The `~regions.Regions` class includes four methods, +The `~regions.Regions` class (which represents a list +of `~regions.Region` objects) includes four methods, :meth:`~regions.Regions.read`, :meth:`~regions.Regions.write`, :meth:`~regions.Regions.parse`, and :meth:`~regions.Regions.serialize`, -that make is possible to read, write, parse, and serialize region files +that make it possible to read, write, parse, and serialize region files or region data. The :class:`~regions.Regions` class has built-in support for various @@ -41,11 +42,8 @@ registered I/O formats as a :class:`~astropy.table.Table`:: fits Yes Yes Yes Yes Yes -Examples --------- - Read -^^^^ +---- To read in a region file, first import the :class:`~regions.Regions` class, then call the :meth:`~regions.Regions.read` method with the name @@ -82,7 +80,7 @@ uncompress them if supported by the Python installation (see Write -^^^^^ +----- Use the :meth:`~regions.Regions.write` method to write regions to a region file. Like the :meth:`~regions.Regions.read` method, the @@ -103,7 +101,7 @@ If the file already exists and you want to overwrite it, then set the Parse -^^^^^ +----- Region data in the form of a string or table may also be parsed into a :class:`~regions.Regions` object by using the @@ -122,7 +120,7 @@ parsed for the ``fits`` format:: Serialize -^^^^^^^^^ +--------- Regions can be serialized to a string or table by using the :meth:`~regions.Regions.serialize` method. The ``format`` keyword must From 5a5803be040095bf9749f40791267dbfe2a8e4e9 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 14:29:31 -0400 Subject: [PATCH 11/16] Update plotting documentation --- docs/plotting.rst | 79 ++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/docs/plotting.rst b/docs/plotting.rst index dfe46123..93189edd 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -1,13 +1,13 @@ -.. _gs-mpl: - -Plotting regions with Matplotlib +Plotting Regions with Matplotlib ================================ -Some `~regions.PixelRegion` objects have an ``as_artist()`` method that returns an -equivalent `matplotlib.patches` object. For example :meth:`regions.CirclePixelRegion.as_artist` -returns a `matplotlib.patches.Circle` object. +Some `~regions.PixelRegion` objects have an ``as_artist()`` +method that returns an equivalent `matplotlib.patches` object. +For example :meth:`regions.CirclePixelRegion.as_artist` returns a +`matplotlib.patches.Circle` object. -To draw a matplotlib patch object, add it to an `matplotlib.axes.Axes` object. +To draw a matplotlib patch object, add it to an `matplotlib.axes.Axes` +object. .. plot:: :include-source: @@ -24,32 +24,18 @@ To draw a matplotlib patch object, add it to an `matplotlib.axes.Axes` object. axes.set_xlim([-0.5, 1]) axes.set_ylim([-0.5, 1]) +The :meth:`regions.PixelRegion.plot` method is a convenience method that +combines these two steps (creating a matplotlib patch artist and adding +it to an axis). If no axis is passed then it calls ``plt.gca()``. -The :meth:`~regions.PixelRegion.plot`, a convenience method just does these two -steps at once (creating a matplotlib patch artist and adding it to an axis), -and calls ``plt.gca()`` if no axis is passed in. - -You can shift the origin of the region very conveniently while plotting by simply -supplying the ``origin`` pixel coordinates to :meth:`~regions.PixelRegion.plot` -and :meth:`~regions.PixelRegion.as_artist`. The ``**kwargs`` argument takes any -keyword argument that the `~matplotlib.patches.Patch` object accepts for those -regions represented as patches, or arguments `~matplotlib.lines.Line2D` accepts +You can shift the origin of the region while plotting by supplying the +``origin`` pixel coordinates to either :meth:`~regions.PixelRegion.plot` +or :meth:`~regions.PixelRegion.as_artist`. The +:meth:`~regions.PixelRegion.plot` method also takes any keyword argument +that the `~matplotlib.patches.Patch` object accepts for those regions +represented as patches, or arguments `~matplotlib.lines.Line2D` accepts for point regions. For example: -.. plot:: - :include-source: - - from regions import BoundingBox - - bbox = BoundingBox(ixmin=-1, ixmax=1, iymin=-2, iymax=2) - # shifting the origin to (1, 1) pixel position - ax = bbox.plot(origin=(1, 1), edgecolor='yellow', facecolor='red', fill=True) - ax.set_xlim([-4, 2]) - ax.set_ylim([-4, 2]) - - -Here's a full example how to plot a `~regions.CirclePixelRegion` on an image. - .. plot:: :include-source: @@ -58,28 +44,29 @@ Here's a full example how to plot a `~regions.CirclePixelRegion` on an image. from regions import PixCoord, CirclePixelRegion fig, ax = plt.subplots() - region = CirclePixelRegion(center=PixCoord(x=3, y=5), radius=3) + region = CirclePixelRegion(center=PixCoord(x=7, y=5), radius=3) data = np.arange(10 * 15).reshape((10, 15)) ax.imshow(data, cmap='gray', interpolation='nearest', origin='lower') - region.plot(ax=ax, color='red') - + region.plot(ax=ax, color='red', lw=2.0) -The `~regions.RectanglePixelRegion` and `~regions.EllipsePixelRegion` docstrings also -contain plot examples. +The documentation for `~regions.RectanglePixelRegion` and +`~regions.EllipsePixelRegion` also shows plotting examples. -`~regions.SkyRegion` objects currently don't have an ``as_artist()`` or ``plot()`` -method. To plot them, convert them to a pixel region first: -.. code-block:: python +Plotting Sky Regions +-------------------- - sky_region = <...> - pixel_region = sky_region.to_pixel(wcs, mode, tolerance) - pixel_region.plot(**kwargs) # plot options passed to matplotlib +Note that `~regions.SkyRegion` objects do not have an ``as_artist()`` or +``plot()`` method. To plot a `~regions.SkyRegion` object, you will need +to convert it to a pixel region (using a WCS object): -We do plan to add extensive documentation on sky region plotting, or to -add methods on sky region to do it directly in the future -(see https://github.com/astropy/regions/issues/76 ), -after the polygon region classes are developed. +.. doctest-skip:: -An example of how to plot sky regions on a sky image is shown above. + >>> from astropy.coordinates import Angle, SkyCoord + >>> from regions import CircleSkyRegion + >>> sky_center = SkyCoord(42, 43, unit='deg') + >>> sky_radius = Angle(25, 'deg') + >>> sky_region = CircleSkyRegion(sky_center, sky_radius) + >>> pixel_region = sky_region.to_pixel(wcs) + >>> pixel_region.plot() From 5861561da8aee48b7bba0ea3268f65d41bc49f1c Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 14:53:27 -0400 Subject: [PATCH 12/16] Update shapely docs --- docs/shapely.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/shapely.rst b/docs/shapely.rst index 64ca8768..f670096d 100644 --- a/docs/shapely.rst +++ b/docs/shapely.rst @@ -1,24 +1,23 @@ -.. _gs-shapely: - -Converting regions to shapely objects +Converting Regions to Shapely Objects ===================================== The `Shapely `__ Python package is a generic package for the manipulation and analysis of -geometric objects in the Cartesian plane. Concerning regions in the -cartesian plane, it is more feature-complete, powerful and optimized -than this ``regions`` package. - -The use of Shapely or other Python regions packages that come from the geospatial domain -in Astronomy is rare. However, if you have a complex pixel region analysis task, -you can consider using Shapely. Either use it directly, by defining Shapely regions -via Python code or one of the serialisation formats they support, or by writing -some Python code to convert ``astropy-regions`` objects to Shapely objects. - -Here we give one example how to do this: convert a circle to a Shapely object -and polygonise it. That's one nice feature of Shapely, it can polygonise all shapes -and do fast polygon-based computations like intersection and union. If you need to -do this, that's a good reason to use Shapely. +geometric objects in the Cartesian plane. For regions in the cartesian +plane, it is more feature-complete, powerful, and optimized than this +package. + +The use of Shapely or other Python regions packages that come from the +geospatial domain in Astronomy is rare. However, if you have a complex +pixel region analysis task, you can consider using Shapely. Either use +it directly, by defining Shapely regions via Python code or one of the +serialization formats they support, or by writing some Python code to +convert `~regions.Region` objects to Shapely objects. + +Here we give an example of converting a circle to a Shapely object +and then polygonize it. One nice feature of Shapely is that it can +polygonize all shapes and perform fast polygon-based computations like +intersection and union. .. plot:: :include-source: @@ -34,10 +33,11 @@ do this, that's a good reason to use Shapely. point = Point(region.center.x, region.center.y) circle = point.buffer(region.radius) - # Actually, this is a polygon approximation of the circle! + # Actually, this is a polygon approximation of the circle print(circle) # Plot the result x, y = circle.exterior.xy ax = plt.subplot(1, 1, 1) + ax.set_aspect('equal') ax.plot(x, y, 'g-') From 9c7450c2735eea774bbe89c1cfdc27193f938a99 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 14:53:48 -0400 Subject: [PATCH 13/16] Add new doc page for region metadata --- docs/compound.rst | 2 +- docs/contains.rst | 2 +- docs/index.rst | 1 + docs/metadata.rst | 183 ++++++++++++++++++++++++++++++++++++++++++++++ docs/shapes.rst | 182 ++------------------------------------------- 5 files changed, 191 insertions(+), 179 deletions(-) create mode 100644 docs/metadata.rst diff --git a/docs/compound.rst b/docs/compound.rst index 212a8b93..1100cb07 100644 --- a/docs/compound.rst +++ b/docs/compound.rst @@ -1,4 +1,4 @@ -Combining regions +Combining Regions ================= There are a few ways to combine any two `~regions.Region` objects diff --git a/docs/contains.rst b/docs/contains.rst index 415ee521..9b50e2e5 100644 --- a/docs/contains.rst +++ b/docs/contains.rst @@ -1,4 +1,4 @@ -Checking for points inside regions +Checking for Points Inside Regions ================================== Let's start by defining both a sky and pixel region:: diff --git a/docs/index.rst b/docs/index.rst index c9995c55..2f88907b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,6 +42,7 @@ User Documentation :maxdepth: 1 shapes + metadata contains compound masks diff --git a/docs/metadata.rst b/docs/metadata.rst new file mode 100644 index 00000000..17921133 --- /dev/null +++ b/docs/metadata.rst @@ -0,0 +1,183 @@ +.. include:: references.txt + +Region Metadata +=============== + +A :class:`~regions.Region` object has both ``meta`` and +``visual`` attributes that store the metadata of the region. The +:class:`~regions.RegionMeta` and :class:`~regions.RegionVisual` classes +handle the general metadata and visual attributes, respectively. Both +behave like Python dictionaries. + + +General Metadata +---------------- + +The :class:`~regions.Region` ``meta`` attribute stores additional +metadata about the region such as labels, tags, comments, name, etc. +that are used for non-display tasks. It can also store the spectral +dimensions of the region. + +The valid keys in the :class:`~regions.RegionMeta` object are: + +* ``label``: + + - CRTF, DS9 (text label for a region) + - Ex: meta['label'] = 'this is a circle' + +* ``tag``: + + - DS9 (All regions may have zero or more tags associated with it, + which may be used for grouping and searching.) + + - Ex: meta['tags'] = ['{Group 1}', '{Group 2}']} + +* ``include``: + + - CRTF, DS9 (Region inclusion) + - Possible Values: True, False + - Ex: meta['include'] = True + +* ``frame``: + + - CRTF (Frequency/Velocity Axis) + - Possible values: 'REST', 'LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', + 'GALACTO', 'LGROUP', 'CMB' + - Default: image value + - Ex: meta['frame'] = 'TOPO' + +* ``range``: + + - CRTF (Frequency/Velocity Range) + - Possible units: GHz, MHz, kHz, km/s, Hz, channel, chan (=channel) + - Default: image range + - Format: [min, max] + - Ex: meta['range'] = [-320 * u.m/u.sec, -330 * u.m/u.s] + +* ``veltype``: + + - CRTF (Velocity Calculation) + - Possible values: 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA' + - Default: image value + - Ex: meta['veltype'] = 'RADIO' + +* ``restfreq``: + + - CRTF (Rest Frequency) + - Possible values: `~astropy.units.Quantity` object + - Default: image value + - Ex: meta['restfreq'] = Quantity("1.42GHz") + +* ``corr``: + + - CRTF (Correlational Axis) + - Possible values: 'I', 'Q', 'U', 'V', 'RR', 'RL', 'LR', 'LL', + 'XX', 'XY', 'YX', 'YY', 'RX', 'RY', 'LX', 'LY', 'XR', 'XL', 'YR', + 'YL', 'PP', 'PQ', 'QP', 'QQ', 'RCircular', 'LCircular', 'Linear', + 'Ptotal', 'Plinear', 'PFtotal', 'PFlinear', 'Pangle' + - Default: all planes present in image + - Ex: meta['corr'] = ['X', 'Y'] + +* ``comment``: + + - DS9, CRTF (Comment on the region) + - Ex: meta['comment'] = 'Any comment for the region' + +* ``line``: + + - DS9 (The line region may be rendered with arrows, one at each end. + To indicate arrows, use the line property. A '1' indicates an arrow, + '0' indicates no arrow.) + - Ex: meta['line'] = [1, 1] + +* ``name`` + +* ``select`` + +* ``highlite`` + +* ``fixed`` + +* ``edit``: + + - DS9 (The Edit property specifies if the user is allowed to edit the + region via the GUI.) + - Ex: meta['edit'] = 1 + +* ``move``: + + - DS9 (The Move property specifies if the user is allowed to move the + region via the GUI. ) + - Ex: meta['move'] = 1 + +* ``rotate``: + + - DS9 (The Rotate property specifies if the user is allowed to rotate + the region via the GUI. ) + - Ex: meta['rotate'] = 1 + +* ``delete``: + + - DS9 (The Delete property specifies if the user is allowed to delete + the region via the GUI. ) + - Ex: meta['delete'] = 1 + +* ``source`` + +* ``background`` + + +Visual Metadata +--------------- + +The :class:`~regions.Region` ``visual`` attribute stores visual +properties for the region such as color, font style, font size, line +width, line style, etc. The visual attributes are metadata meant to be +used to visualize regions, especially used by plotting libraries such as +`Matplotlib`_ . + +The valid keys in the `~regions.RegionVisual` class are: + +* ``color``: CRTF, DS9 (Region, symbol and text color) + + - Possible values: any color recognized by `Matplotlib`_, including + hex values + - Default: color=green + - Ex: visual['color'] = 'blue' + +* ``dash``: Render region using dashed lines using current dashlist + value. + +* ``font``: Name of the font. + +* ``dashlist``: Sets dashed line parameters. This does not render the + region in dashed lines. + +* ``symsize``: Size of the symbol. + +* ``symthick``: Thickness of the symbol. + +* ``fontsize``: Size of the font. + +* ``fontstyle``: Style of the font. + +* ``usetex``: Boolean value whether the label uses TeX. + +* ``labelpos``: Position of the label. + +* ``labeloff``: Label offset. + +* ``linewidth``: Width of the line. + +* ``linestyle``: Style of the line. + +* ``fill``: Boolean value whether the region is filled. + +* ``line``: The line region may be rendered with arrows, one at each + end. To indicate arrows, use the line property. A '1' indicates an + arrow, '0' indicates no arrow. + +* ``symbol``/``point``: CRTF, DS9 (Symbol for which a point region is + described) + + - Ex: meta['symbol'] = 'point marker' diff --git a/docs/shapes.rst b/docs/shapes.rst index d39a1515..799b2645 100644 --- a/docs/shapes.rst +++ b/docs/shapes.rst @@ -8,14 +8,17 @@ .. _shapes: -Shapes -====== +Region Shapes +============= Regions provides `~regions.Region` objects, defined in pixel or sky coordinates, representing shapes such as circles, ellipses, rectangles, polygons, lines, and points. There are also regions defining circular, elliptical, and rectangular annuli. +There is also a `~regions.Regions` class that can hold a list of +`~regions.Region` objects. + Defining Shapes --------------- @@ -272,181 +275,6 @@ to a :class:`~regions.SkyRegion`, call the radius: 18.55481729935556 arcsec -Metadata --------- - -A :class:`~regions.Region` object has both ``meta`` and -``visual`` attributes that store the metadata of the region. The -:class:`~regions.RegionMeta` and :class:`~regions.RegionVisual` classes -handle the metadata and visual attributes, respectively. Both behave -like Python dictionaries. - -The ``meta`` attribute stores additional metadata about the region such -as labels, tags, comments, name, etc. that are used for non-display -tasks. It can also store the spectral dimensions of the region. The -``visual`` attribute stores visual properties for the region such as -color, font style, font size, line width, line style, etc. - -The valid keys in the :class:`~regions.RegionMeta` object are: - -* ``label``: - - - CRTF, DS9 (text label for a region) - - Ex: meta['label'] = 'this is a circle' - -* ``tag``: - - - DS9 (All regions may have zero or more tags associated with it, - which may be used for grouping and searching.) - - - Ex: meta['tags'] = ['{Group 1}', '{Group 2}']} - -* ``include``: - - - CRTF, DS9 (Region inclusion) - - Possible Values: True, False - - Ex: meta['include'] = True - -* ``frame``: - - - CRTF (Frequency/Velocity Axis) - - Possible values: 'REST', 'LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', - 'GALACTO', 'LGROUP', 'CMB' - - Default: image value - - Ex: meta['frame'] = 'TOPO' - -* ``range``: - - - CRTF (Frequency/Velocity Range) - - Possible units: GHz, MHz, kHz, km/s, Hz, channel, chan (=channel) - - Default: image range - - Format: [min, max] - - Ex: meta['range'] = [-320 * u.m/u.sec, -330 * u.m/u.s] - -* ``veltype``: - - - CRTF (Velocity Calculation) - - Possible values: 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA' - - Default: image value - - Ex: meta['veltype'] = 'RADIO' - -* ``restfreq``: - - - CRTF (Rest Frequency) - - Possible values: `~astropy.units.Quantity` object - - Default: image value - - Ex: meta['restfreq'] = Quantity("1.42GHz") - -* ``corr``: - - - CRTF (Correlational Axis) - - Possible values: 'I', 'Q', 'U', 'V', 'RR', 'RL', 'LR', 'LL', - 'XX', 'XY', 'YX', 'YY', 'RX', 'RY', 'LX', 'LY', 'XR', 'XL', 'YR', - 'YL', 'PP', 'PQ', 'QP', 'QQ', 'RCircular', 'LCircular', 'Linear', - 'Ptotal', 'Plinear', 'PFtotal', 'PFlinear', 'Pangle' - - Default: all planes present in image - - Ex: meta['corr'] = ['X', 'Y'] - -* ``comment``: - - - DS9, CRTF (Comment on the region) - - Ex: meta['comment'] = 'Any comment for the region' - -* ``line``: - - - DS9 (The line region may be rendered with arrows, one at each end. - To indicate arrows, use the line property. A '1' indicates an arrow, - '0' indicates no arrow.) - - Ex: meta['line'] = [1, 1] - -* ``name`` - -* ``select`` - -* ``highlite`` - -* ``fixed`` - -* ``edit``: - - - DS9 (The Edit property specifies if the user is allowed to edit the - region via the GUI.) - - Ex: meta['edit'] = 1 - -* ``move``: - - - DS9 (The Move property specifies if the user is allowed to move the - region via the GUI. ) - - Ex: meta['move'] = 1 - -* ``rotate``: - - - DS9 (The Rotate property specifies if the user is allowed to rotate - the region via the GUI. ) - - Ex: meta['rotate'] = 1 - -* ``delete``: - - - DS9 (The Delete property specifies if the user is allowed to delete - the region via the GUI. ) - - Ex: meta['delete'] = 1 - -* ``source`` - -* ``background`` - - - -The visual attributes are metadata meant to be used to visualize -regions, especially used by plotting libraries such as `Matplotlib`_ . - -The valid keys in the `~regions.RegionVisual` class are: - -* ``color``: CRTF, DS9 (Region, symbol and text color) - - - Possible values: any color recognized by `Matplotlib`_, including - hex values - - Default: color=green - - Ex: visual['color'] = 'blue' - -* ``dash``: Render region using dashed lines using current dashlist - value. - -* ``font``: Name of the font. - -* ``dashlist``: Sets dashed line parameters. This does not render the - region in dashed lines. - -* ``symsize``: Size of the symbol. - -* ``symthick``: Thickness of the symbol. - -* ``fontsize``: Size of the font. - -* ``fontstyle``: Style of the font. - -* ``usetex``: Boolean value whether the label uses TeX. - -* ``labelpos``: Position of the label. - -* ``labeloff``: Label offset. - -* ``linewidth``: Width of the line. - -* ``linestyle``: Style of the line. - -* ``fill``: Boolean value whether the region is filled. - -* ``line``: The line region may be rendered with arrows, one at each - end. To indicate arrows, use the line property. A '1' indicates an - arrow, '0' indicates no arrow. - -* ``symbol``/``point``: CRTF, DS9 (Symbol for which a point region is - described) - - - Ex: meta['symbol'] = 'point marker' - - .. _sh-lists: Multiple Regions From 6bed20b260dae577a0be9f3a8407b2c50aacc4e7 Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 16:08:00 -0400 Subject: [PATCH 14/16] Update region shapes docs --- docs/region_io.rst | 4 ++-- docs/shapes.rst | 25 +++++++++++++++++++------ regions/core/pixcoord.py | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/region_io.rst b/docs/region_io.rst index be170829..42cf620e 100644 --- a/docs/region_io.rst +++ b/docs/region_io.rst @@ -1,10 +1,10 @@ -.. _unified-io: +.. _regions_io: Reading/Writing Region Files **************************** The regions package provides a unified interface for reading, writing, -parsing, and serializing regions data in different formats. +parsing, and serializing regions data in different standard formats. Regions I/O diff --git a/docs/shapes.rst b/docs/shapes.rst index 799b2645..24dd6689 100644 --- a/docs/shapes.rst +++ b/docs/shapes.rst @@ -16,9 +16,6 @@ coordinates, representing shapes such as circles, ellipses, rectangles, polygons, lines, and points. There are also regions defining circular, elliptical, and rectangular annuli. -There is also a `~regions.Regions` class that can hold a list of -`~regions.Region` objects. - Defining Shapes --------------- @@ -295,13 +292,14 @@ This is in contrast to the aperture classes in `Photutils >>> apertures = CircularAperture(positions, r=4.2) To represent lists of `~regions.Region` objects, you can store them in -Python lists (or other containers, but lists are the most common). To -create many similar regions or process many regions you can use for -loops or list comprehensions. +Python lists or the `~regions.Regions` class, which effectly acts like a +list of regions. To create many similar regions or process many regions +you can use for loops or list comprehensions. .. code-block:: python >>> from regions import PixCoord, CirclePixelRegion + >>> from regions import Regions >>> regions = [CirclePixelRegion(center=PixCoord(x, y), radius=4.2) ... for x, y in [(1, 2), (3, 4)]] >>> for region in regions: @@ -310,3 +308,18 @@ loops or list comprehensions. PixCoord(x=3, y=4) >>> [region.area for region in regions] [55.41769440932395, 55.41769440932395] + +To create a `~regions.Regions` object, simply pass in a list of +regions:: + + >>> regs = Regions(regions) + >>> print(regs[0]) + Region: CirclePixelRegion + center: PixCoord(x=1, y=2) + radius: 4.2 + >>> [reg.area for reg in regs] + [55.41769440932395, 55.41769440932395] + +The `~regions.Regions` class also provides a :ref:`unified interface for +reading, writing, parsing, and serializing regions data ` in +different standard formats. diff --git a/regions/core/pixcoord.py b/regions/core/pixcoord.py index af81fce3..06fc71cf 100644 --- a/regions/core/pixcoord.py +++ b/regions/core/pixcoord.py @@ -34,7 +34,7 @@ class PixCoord: Examples -------- - Usage examples are provided in the :ref:`getting-started-coord` + Usage examples are provided in the :ref:`getting_started-coord` section of the documentation. """ From 6a9109012c773e685e23381e0cb490596e0bf97e Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 16:40:35 -0400 Subject: [PATCH 15/16] Update region masks docs --- docs/masks.rst | 103 +++++++++++++++++++++++-------------------- regions/core/mask.py | 4 +- 2 files changed, 57 insertions(+), 50 deletions(-) diff --git a/docs/masks.rst b/docs/masks.rst index 4b0d141a..e74dca23 100644 --- a/docs/masks.rst +++ b/docs/masks.rst @@ -1,16 +1,16 @@ -.. _gs-masks: +.. _overlap-masks: -Computing overlap masks +Computing Overlap Masks ======================= Defining a region mask within its bounding box ---------------------------------------------- For aperture photometry, a common operation is to compute, for a given -image and region, a mask or array of pixel indices defining which -pixels (in the whole image or a minimal rectangular bounding box) are -inside and outside the region. +image and region, a mask or array of pixel indices defining which pixels +(in the whole image or a minimal rectangular bounding box) are inside +and outside the region. All :class:`~regions.PixelRegion` objects have a :meth:`~regions.PixelRegion.to_mask` method that returns a @@ -31,27 +31,29 @@ arrays:: [0., 1., 1., 1., 0.]]) The mask data contains floating point that are between 0 (no overlap) -and 1 (overlap). By default, this is determined by looking only at the -central position in each pixel, and:: +and 1 (full overlap). By default, this is determined by looking only at +the central position in each pixel, and:: - >>> reg.to_mask() # doctest: +IGNORE_OUTPUT + >>> reg.to_mask() # doctest: +IGNORE_OUTPUT is equivalent to:: - >>> reg.to_mask(mode='center') # doctest: +IGNORE_OUTPUT + >>> reg.to_mask(mode='center') # doctest: +IGNORE_OUTPUT -but other modes are available: +The other mask modes that are available are: * ``mode='exact'``: the overlap is determined using the exact - geometrical overlap between pixels and the region. This is slower than - using the central position, but allows partial overlap to be treated - correctly. + geometrical overlap between pixels and the region. This is slower + than using the central position, but allows partial overlap to be + treated correctly. The mask data values will be between 0 and 1 for + partial-pixel overlap. * ``mode='subpixels'``: the overlap is determined by sub-sampling the pixel using a grid of sub-pixels. The number of sub-pixels to use in - this mode should be given using the ``subpixels`` argument. + this mode should be given using the ``subpixels`` argument. The mask + data values will be between 0 and 1 for partial-pixel overlap. -Here are what the different modes look like: +Here are what the region masks produced by different modes look like: .. plot:: :include-source: @@ -89,27 +91,27 @@ Here are what the different modes look like: plt.imshow(mask4.data, cmap=plt.cm.viridis, interpolation='nearest', origin='lower') -As we've seen above, the :class:`~regions.RegionMask` objects have a +As we've seen above, the :class:`~regions.RegionMask` object has a ``data`` attribute that contains a Numpy array with the mask values. -However, if you have for example a circular region with a radius of 3 -pixels at a pixel position of (1000, 1000), it would be inefficient to -store a mask that has a size larger than this, so instead we store the -mask using the minimal array that contains the mask, and the -:class:`~regions.RegionMask` objects also include a ``bbox`` attribute -that is a :class:`~regions.BoundingBox` object used to indicate where -the mask should be applied in an image. +However, if you have, for example, a small circluar region with a radius +of 3 pixels at a pixel position of (1000, 1000), it would be inefficient +to store a large mask array that has a size to cover this position +(most of the mask values would be zero). Instead, we store the mask +using the minimal array that contains the region mask along with a +``bbox`` attribute that is a :class:`~regions.BoundingBox` object used +to indicate where the mask should be applied in an image. Defining a region mask within an image -------------------------------------- -:class:`~regions.RegionMask` objects also have a number of methods to -make it easy to use the masks with data. The +:class:`~regions.RegionMask` objects also have a number of +methods to make it easy to use the masks with data. The :meth:`~regions.RegionMask.to_image` method can be used to obtain an -image of the mask in a 2D array of the given shape. This places the -mask in the correct place in the image and deals properly with -boundary effects. For this example, let's place the mask in an image -with shape (50, 50): +image of the mask in a 2D array of the given shape. This places the +mask in the correct place in the image and deals properly with boundary +effects. For this example, let's place the mask in an image with shape +(50, 50): .. plot:: :include-source: @@ -138,37 +140,41 @@ the aperture mask with the input data to create a mask-weighted data cutout. All of these methods properly handle the cases of partial or no overlap of the aperture mask with the data. -These masks can be used as the building blocks for photometry, which -we demonstrate with a simple example. We start off by getting an -example image:: +These masks can be used, for example, as the building blocks for +photometry, which we demonstrate with a simple example. We start off by +getting an example image:: >>> from astropy.io import fits >>> from astropy.utils.data import get_pkg_data_filename - >>> filename = get_pkg_data_filename('photometry/M6707HH.fits') # doctest: +IGNORE_OUTPUT - >>> pf = fits.open(filename) - >>> hdu = pf[0] + >>> filename = get_pkg_data_filename('photometry/M6707HH.fits') # doctest: +IGNORE_OUTPUT + >>> hdulist = fits.open(filename) + >>> hdu = hdulist[0] -We then define the aperture:: +We then define a circular aperture region:: >>> from regions.core import PixCoord >>> from regions.shapes.circle import CirclePixelRegion >>> center = PixCoord(158.5, 1053.5) >>> aperture = CirclePixelRegion(center, 4.) -We convert the aperture to a mask and extract a cutout from the data, -as well as a cutout with the data multiplied by the mask:: +We then convert the aperture to a mask and extract a cutout from the +data, as well as a cutout with the data multiplied by the mask:: >>> mask = aperture.to_mask(mode='exact') >>> data = mask.cutout(hdu.data) >>> weighted_data = mask.multiply(hdu.data) - >>> pf.close() Note that ``weighted_data`` will have zeros where the mask is zero; it therefore should not be used to compute statistics (see :ref:`Masked -Statistics ` below). +Statistics ` below). To get the mask-weighted pixel +values as a 1D array, excluding the pixels where the mask is zero, +use the :meth:`~regions.RegionMask.get_values` method:: -We can take a look at the results to make sure the source overlaps -with the aperture: + >>> weighted_data_1d = mask.get_values(hdu.data) + >>> hdulist.close() + +We can take a look at the results to make sure the source overlaps with +the aperture: .. doctest-skip:: @@ -201,8 +207,8 @@ with the aperture: from regions.shapes.circle import CirclePixelRegion filename = get_pkg_data_filename('photometry/M6707HH.fits') - pf = fits.open(filename) - hdu = pf[0] + hdulist = fits.open(filename) + hdu = hdulist[0] center = PixCoord(158.5, 1053.5) aperture = CirclePixelRegion(center, 4.) mask = aperture.to_mask(mode='exact') @@ -223,6 +229,7 @@ with the aperture: plt.imshow(weighted_data, cmap=plt.cm.viridis, interpolation='nearest', origin='lower', extent=mask.bbox.extent) + hdulist.close() We can also use the `~regions.RegionMask` ``bbox`` attribute to look at the extent of the mask in the image: @@ -239,8 +246,8 @@ at the extent of the mask in the image: from regions.shapes.circle import CirclePixelRegion filename = get_pkg_data_filename('photometry/M6707HH.fits') - pf = fits.open(filename) - hdu = pf[0] + hdulist = fits.open(filename) + hdu = hdulist[0] center = PixCoord(158.5, 1053.5) aperture = CirclePixelRegion(center, 4.) mask = aperture.to_mask(mode='exact') @@ -252,7 +259,7 @@ at the extent of the mask in the image: ax.add_artist(aperture.as_artist(facecolor='none', edgecolor='orange')) ax.set_xlim(120, 180) ax.set_ylim(1000, 1059) - pf.close() + hdulist.close() .. _masked_statistics: @@ -264,5 +271,5 @@ Finally, we can use the mask and data values to compute weighted statistics:: >>> import numpy as np - >>> np.average(data, weights=mask) # doctest: +FLOAT_CMP + >>> np.average(data, weights=mask) # doctest: +FLOAT_CMP 9364.012674888021 diff --git a/regions/core/mask.py b/regions/core/mask.py index 9f59399e..8b96346a 100644 --- a/regions/core/mask.py +++ b/regions/core/mask.py @@ -28,8 +28,8 @@ class RegionMask: Examples -------- - Usage examples are provided in the :ref:`gs-masks` section of the - docs. + Usage examples are provided in the :ref:`overlap-masks` section of + the docs. """ def __init__(self, data, bbox): From 944236d0136e8e47c8649dce82da92b42ce417be Mon Sep 17 00:00:00 2001 From: Larry Bradley Date: Mon, 19 Jul 2021 17:32:31 -0400 Subject: [PATCH 16/16] Fix doctests --- docs/shapes.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/shapes.rst b/docs/shapes.rst index 24dd6689..f179c35b 100644 --- a/docs/shapes.rst +++ b/docs/shapes.rst @@ -171,7 +171,7 @@ Polygon >>> vertices = SkyCoord([1, 2, 2], [1, 1, 2], unit='deg', frame='fk5') >>> region_sky = PolygonSkyRegion(vertices=vertices) - >>> vertices = PixCoord(x=[1, 2, 2], y=[1, 1, 2])) + >>> vertices = PixCoord(x=[1, 2, 2], y=[1, 1, 2]) >>> region_pix = PolygonPixelRegion(vertices=vertices) @@ -272,8 +272,6 @@ to a :class:`~regions.SkyRegion`, call the radius: 18.55481729935556 arcsec -.. _sh-lists: - Multiple Regions ----------------