Skip to content

Commit

Permalink
FEAT: Annulus draw tool for Imviz.
Browse files Browse the repository at this point in the history
TODO: Need to fix icon.

TST: Add tests.

[ci skip] [rtd skip]
  • Loading branch information
pllim committed Jun 13, 2023
1 parent 2093786 commit 94f0973
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 43 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Imviz
- Added the ability to load DS9 region files (``.reg``) using the ``IMPORT DATA``
button. However, this only works after loading at least one image into Imviz. [#2201]

- Added support for new ``CircularAnnulusROI`` subset from glue. [#2201]
- Added support for new ``CircularAnnulusROI`` subset from glue, including
a new draw tool. [#2201, #2240]

Mosviz
^^^^^^
Expand Down
27 changes: 3 additions & 24 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
from astropy.nddata import CCDData, NDData
from astropy.io import fits
from astropy import units as u
from astropy.coordinates import Angle
from astropy.time import Time
from regions import PixCoord, CirclePixelRegion, RectanglePixelRegion, EllipsePixelRegion

from echo import CallbackProperty, DictCallbackProperty, ListCallbackProperty
from ipygoldenlayout import GoldenLayout
Expand All @@ -38,8 +36,8 @@
from glue.core.state_objects import State
from glue.core.subset import (Subset, RangeSubsetState, RoiSubsetState,
CompositeSubsetState, InvertState)
from glue.core.roi import CircularROI, EllipticalROI, RectangularROI
from glue_astronomy.spectral_coordinates import SpectralCoordinates
from glue_astronomy.translators.regions import roi_subset_state_to_spatial
from glue_jupyter.app import JupyterApplication
from glue_jupyter.common.toolbar_vuetify import read_icon
from glue_jupyter.state_traitlets_helpers import GlueState
Expand Down Expand Up @@ -987,27 +985,8 @@ def _get_range_subset_bounds(self, subset_state, simplify_spectral=True):
return spec_region

def _get_roi_subset_definition(self, subset_state):
_around_decimals = 6
roi = subset_state.roi
roi_as_region = None
if isinstance(roi, CircularROI):
x, y = roi.get_center()
r = roi.radius
roi_as_region = CirclePixelRegion(PixCoord(x, y), r)

elif isinstance(roi, RectangularROI):
theta = np.around(np.degrees(roi.theta), decimals=_around_decimals)
roi_as_region = RectanglePixelRegion(PixCoord(roi.center()[0], roi.center()[1]),
roi.width(), roi.height(), Angle(theta, "deg"))

elif isinstance(roi, EllipticalROI):
xc = roi.xc
yc = roi.yc
rx = roi.radius_x
ry = roi.radius_y
theta = np.around(np.degrees(roi.theta), decimals=_around_decimals)
roi_as_region = EllipsePixelRegion(PixCoord(xc, yc), rx * 2, ry * 2, Angle(theta, "deg")) # noqa: E501

# TODO: Imviz: Return sky region if link type is WCS.
roi_as_region = roi_subset_state_to_spatial(subset_state)
return [{"name": subset_state.roi.__class__.__name__,
"glue_state": subset_state.__class__.__name__,
"region": roi_as_region,
Expand Down
22 changes: 16 additions & 6 deletions jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from glue.core.message import EditSubsetMessage, SubsetUpdateMessage
from glue.core.edit_subset_mode import (AndMode, AndNotMode, OrMode,
ReplaceMode, XorMode)
from glue.core.roi import CircularROI, EllipticalROI, RectangularROI
from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI
from glue.core.subset import RoiSubsetState, RangeSubsetState, CompositeSubsetState
from glue.icons import icon_path
from glue_jupyter.widgets.subset_mode_vuetify import SelectionModeMenu
Expand Down Expand Up @@ -156,7 +156,7 @@ def _unpack_get_subsets_for_ui(self):
glue_state = spec["glue_state"]
if isinstance(subset_state, RoiSubsetState):
if isinstance(subset_state.roi, CircularROI):
x, y = subset_state.roi.get_center()
x, y = subset_state.roi.center()
r = subset_state.roi.radius
subset_definition = [{"name": "X Center", "att": "xc", "value": x, "orig": x},
{"name": "Y Center", "att": "yc", "value": y, "orig": y},
Expand All @@ -173,8 +173,7 @@ def _unpack_get_subsets_for_ui(self):
{"name": "Angle", "att": "theta", "value": theta, "orig": theta})

elif isinstance(subset_state.roi, EllipticalROI):
xc = subset_state.roi.xc
yc = subset_state.roi.yc
xc, yc = subset_state.roi.center()
rx = subset_state.roi.radius_x
ry = subset_state.roi.radius_y
theta = np.around(np.degrees(subset_state.roi.theta), decimals=_around_decimals)
Expand All @@ -185,6 +184,17 @@ def _unpack_get_subsets_for_ui(self):
{"name": "Y Radius", "att": "radius_y", "value": ry, "orig": ry},
{"name": "Angle", "att": "theta", "value": theta, "orig": theta}]

elif isinstance(subset_state.roi, CircularAnnulusROI):
x, y = subset_state.roi.center()
inner_r = subset_state.roi.inner_radius
outer_r = subset_state.roi.outer_radius
subset_definition = [{"name": "X Center", "att": "xc", "value": x, "orig": x},
{"name": "Y Center", "att": "yc", "value": y, "orig": y},
{"name": "Inner radius", "att": "inner_radius",
"value": inner_r, "orig": inner_r},
{"name": "Outer radius", "att": "outer_radius",
"value": outer_r, "orig": outer_r}]

subset_type = subset_state.roi.__class__.__name__

elif isinstance(subset_state, RangeSubsetState):
Expand Down Expand Up @@ -353,7 +363,7 @@ def get_center(self):

if isinstance(subset_state, RoiSubsetState):
sbst_obj = subset_state.roi
if isinstance(sbst_obj, (CircularROI, EllipticalROI)):
if isinstance(sbst_obj, (CircularROI, CircularAnnulusROI, EllipticalROI)):
cen = sbst_obj.get_center()
elif isinstance(sbst_obj, RectangularROI):
cen = sbst_obj.center()
Expand Down Expand Up @@ -403,7 +413,7 @@ def set_center(self, new_cen, update=False):
if isinstance(subset_state, RoiSubsetState):
x, y = new_cen
sbst_obj = subset_state.roi
if isinstance(sbst_obj, (CircularROI, EllipticalROI)):
if isinstance(sbst_obj, (CircularROI, CircularAnnulusROI, EllipticalROI)):
self._set_value_in_subset_definition(0, "X Center", "value", x)
self._set_value_in_subset_definition(0, "Y Center", "value", y)
elif isinstance(sbst_obj, RectangularROI):
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/configs/imviz/plugins/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ImvizImageView(JdavizViewerMixin, BqplotImageView, AstrowidgetsImageViewer
['jdaviz:homezoom', 'jdaviz:prevzoom'],
['jdaviz:boxzoommatch', 'jdaviz:boxzoom'],
['jdaviz:panzoommatch', 'jdaviz:imagepanzoom'],
['bqplot:circle', 'bqplot:rectangle', 'bqplot:ellipse',
['bqplot:circle', 'bqplot:rectangle', 'bqplot:ellipse', 'bqplot:circannulus',
'jdaviz:singlepixelregion'],
['jdaviz:blinkonce', 'jdaviz:contrastbias'],
['jdaviz:sidebar_plot', 'jdaviz:sidebar_export', 'jdaviz:sidebar_compass']
Expand Down
6 changes: 4 additions & 2 deletions jdaviz/core/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
HomeTool, BqplotPanZoomMode,
BqplotPanZoomXMode, BqplotPanZoomYMode,
BqplotRectangleMode, BqplotCircleMode,
BqplotEllipseMode, BqplotXRangeMode,
BqplotYRangeMode, BqplotSelectionTool,
BqplotEllipseMode, BqplotCircularAnnulusMode,
BqplotXRangeMode, BqplotYRangeMode,
BqplotSelectionTool,
INTERACT_COLOR)
from bqplot.interacts import BrushSelector, BrushIntervalSelector

Expand All @@ -25,6 +26,7 @@
BqplotRectangleMode.icon = os.path.join(ICON_DIR, 'select_xy.svg')
BqplotCircleMode.icon = os.path.join(ICON_DIR, 'select_circle.svg')
BqplotEllipseMode.icon = os.path.join(ICON_DIR, 'select_ellipse.svg')
BqplotCircularAnnulusMode.icon = os.path.join(ICON_DIR, 'select_annulus.svg')
BqplotXRangeMode.icon = os.path.join(ICON_DIR, 'select_x.svg')
BqplotYRangeMode.icon = os.path.join(ICON_DIR, 'select_y.svg')

Expand Down
31 changes: 31 additions & 0 deletions jdaviz/data/icons/select_annulus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 18 additions & 9 deletions jdaviz/tests/test_subsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from astropy import units as u
from astropy.tests.helper import assert_quantity_allclose
from glue.core import Data
from glue.core.roi import CircularROI, EllipticalROI, RectangularROI, XRangeROI
from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI, XRangeROI

from glue.core.edit_subset_mode import AndMode, AndNotMode, OrMode, XorMode
from regions import PixCoord, CirclePixelRegion, RectanglePixelRegion, EllipsePixelRegion
from regions import (PixCoord, CirclePixelRegion, RectanglePixelRegion, EllipsePixelRegion,
CircleAnnulusPixelRegion)

from numpy.testing import assert_allclose
from specutils import SpectralRegion
Expand Down Expand Up @@ -329,7 +330,7 @@ def test_composite_region_from_subset_3d(cubeviz_helper):
'subset_state': reg[-1]['subset_state']}

cubeviz_helper.app.session.edit_subset_mode.mode = OrMode
viewer.apply_roi(EllipticalROI(30, 30, 3, 6))
viewer.apply_roi(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6))
reg = cubeviz_helper.app.get_subsets("Subset 1")
ellipse1 = EllipsePixelRegion(center=PixCoord(x=30, y=30),
width=6, height=12, angle=0.0 * u.deg)
Expand Down Expand Up @@ -381,7 +382,7 @@ def test_composite_region_with_consecutive_and_not_states(cubeviz_helper):
'subset_state': reg[-1]['subset_state']}

cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode
viewer.apply_roi(EllipticalROI(30, 30, 3, 6))
viewer.apply_roi(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6))
reg = cubeviz_helper.app.get_subsets("Subset 1")
ellipse1 = EllipsePixelRegion(center=PixCoord(x=30, y=30),
width=6, height=12, angle=0.0 * u.deg)
Expand Down Expand Up @@ -426,7 +427,7 @@ def test_composite_region_with_imviz(imviz_helper, image_2d_wcs):
arr = np.ones((10, 10))

data_label = 'image-data'
viewer = imviz_helper.app.get_viewer('imviz-0')
viewer = imviz_helper.default_viewer
imviz_helper.load_data(arr, data_label=data_label, show_in_viewer=True)
viewer.apply_roi(CircularROI(xc=5, yc=5, radius=2))
reg = imviz_helper.app.get_subsets("Subset 1")
Expand All @@ -435,25 +436,33 @@ def test_composite_region_with_imviz(imviz_helper, image_2d_wcs):
'subset_state': reg[-1]['subset_state']}

imviz_helper.app.session.edit_subset_mode.mode = AndNotMode
viewer.apply_roi(RectangularROI(2, 4, 2, 4))
viewer.apply_roi(RectangularROI(xmin=2, xmax=4, ymin=2, ymax=4))
reg = imviz_helper.app.get_subsets("Subset 1")
rectangle1 = RectanglePixelRegion(center=PixCoord(x=3, y=3),
width=2, height=2, angle=0.0 * u.deg)
assert reg[-1] == {'name': 'RectangularROI', 'glue_state': 'AndNotState', 'region': rectangle1,
'subset_state': reg[-1]['subset_state']}

imviz_helper.app.session.edit_subset_mode.mode = AndNotMode
viewer.apply_roi(EllipticalROI(3, 3, 3, 6))
viewer.apply_roi(EllipticalROI(xc=3, yc=3, radius_x=3, radius_y=6))
reg = imviz_helper.app.get_subsets("Subset 1")
ellipse1 = EllipsePixelRegion(center=PixCoord(x=3, y=3),
width=6, height=12, angle=0.0 * u.deg)
assert reg[-1] == {'name': 'EllipticalROI', 'glue_state': 'AndNotState', 'region': ellipse1,
'subset_state': reg[-1]['subset_state']}

imviz_helper.app.session.edit_subset_mode.mode = OrMode
viewer.apply_roi(CircularAnnulusROI(xc=5, yc=5, inner_radius=2.5, outer_radius=5))
reg = imviz_helper.app.get_subsets("Subset 1")
ann1 = CircleAnnulusPixelRegion(center=PixCoord(x=5, y=5), inner_radius=2.5, outer_radius=5)
assert reg[-1] == {'name': 'CircularAnnulusROI', 'glue_state': 'OrState', 'region': ann1,
'subset_state': reg[-1]['subset_state']}

subset_plugin = imviz_helper.app.get_tray_item_from_name('g-subset-plugin')
assert subset_plugin.subset_selected == "Subset 1"
assert subset_plugin.subset_types == ['CircularROI', 'RectangularROI', 'EllipticalROI']
assert subset_plugin.glue_state_types == ['AndState', 'AndNotState', 'AndNotState']
assert subset_plugin.subset_types == ['CircularROI', 'RectangularROI', 'EllipticalROI',
'CircularAnnulusROI']
assert subset_plugin.glue_state_types == ['AndState', 'AndNotState', 'AndNotState', 'OrState']


def test_with_invalid_subset_name(cubeviz_helper):
Expand Down

0 comments on commit 94f0973

Please sign in to comment.