Skip to content

Commit

Permalink
DOC: add section for as_mpl_selector and callback example to "masks"
Browse files Browse the repository at this point in the history
  • Loading branch information
dhomeier committed Jan 28, 2022
1 parent 521a460 commit f993a7b
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
51 changes: 51 additions & 0 deletions docs/masks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,54 @@ statistics::
>>> import numpy as np
>>> np.average(data, weights=mask) # doctest: +FLOAT_CMP
9364.012674888021


.. _interactive-masks:

Interactive Mask Control
------------------------

In the last example we will show how to use a
:ref:`Matplotlib selector<regions-as_mpl_selector>` widget with a custom
``callback`` function for creating a mask and updating it interactively through
the selector.
We first create an :class:`~regions.EllipsePixelRegion` and add an ``as_mpl_selector``
property linked to the Matplotlib axes. This can be moved around to
position it on different sources, and resized just like its Rectangle
counterpart, using the handles of the bounding box.

The user-defined callback function here generates a mask from this region and overlays
it on the image as an alpha filter (keeping the areas outside shaded).
We will use this mask as an aperture as well to calculate integrated
and averaged flux, which is updated live in the text field of the plot as well.

.. plot::
:context:
:include-source:
:align: center

from astropy import units as u
from regions import PixCoord, EllipsePixelRegion

hdulist = fits.open(filename)
hdu = hdulist[0]

plt.clf()
ax = plt.subplot(1, 1, 1)
im = ax.imshow(hdu.data, cmap=plt.cm.viridis, interpolation='nearest', origin='lower')
text = ax.text(122, 1002, '', size='small', color='yellow')
ax.set_xlim(120, 180)
ax.set_ylim(1000, 1059)

def update_sel(region):
mask = region.to_mask(mode='subpixels', subpixels=10)
im.set_alpha((mask.to_image(hdu.data.shape) + 1) / 2)
total = mask.multiply(hdu.data).sum()
mean = np.average(hdu.data, weights=mask.to_image(hdu.data.shape))
text.set_text(f'Total: {total:g}\nMean: {mean:g}')

ellipse = EllipsePixelRegion(center=PixCoord(x=126, y=1031), width=8, height=4,
angle=-0*u.deg, visual={'color': 'yellow'})
selector = ellipse.as_mpl_selector(ax, callback=update_sel, use_data_coordinates=True)

hdulist.close()
44 changes: 44 additions & 0 deletions docs/shapes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,50 @@ to a :class:`~regions.SkyRegion`, call the
radius: 18.55481729935556 arcsec
.. _regions-as_mpl_selector:

Selectors for Regions
---------------------

Several geometric regions (at this time, :class:`~regions.RectanglePixelRegion`,
:class:`~regions.EllipsePixelRegion` and :class:`~regions.PolygonPixelRegion`)
provide a method :meth:`~regions.RectanglePixelRegion.as_mpl_selector` to
create an interactive editable matplotlib widget that will be
connected to its parent region.

.. doctest-skip::

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> from regions import PixCoord, RectanglePixelRegion

>>> x, y = np.mgrid[-15:16, -10:21]
>>> z = np.exp(-(x / 4)**2 - (y / 6)**2)
>>> ax = plt.subplot()
>>> img = ax.imshow(z)

>>> rectangle = RectanglePixelRegion(center=PixCoord(x=12, y=15), width=12, height=10)
>>> selector = rectangle.as_mpl_selector(ax)

The ``selector`` creates and establcihes a link to a ``matplotlib`` ``Selector``
widget that allows manually positioning the ``rectangle`` region at the
central point, and scaling it by dragging its corner points.
Several modifier keys as specified by the ``state_modifier_keys`` parameter to
:class:`matplotlib.widgets.RectangleSelector` provide further control of the
manipulation of this widget, with the following operations available:

- "move": Move the existing shape from anywhere, default: "space".
- "clear": Clear the current shape, default: "escape".
- "square": Make the shape square, default: "shift".
- "center": Change the shape around its center, default: "ctrl".
- "rotate": Rotate the shape around its center, default: "r" (toggles, requires Matplotlib 3.6+).

Via the optional ``callback`` parameter this method can be passed a
custom function that will be called on every update of the region,
i.e. after every move or resize of the selector.
For an example of its usage see :ref:`Interactive Mask Control<interactive-masks>`.


Multiple Regions
----------------

Expand Down

0 comments on commit f993a7b

Please sign in to comment.