Skip to content

Commit

Permalink
new get subset method
Browse files Browse the repository at this point in the history
  • Loading branch information
cshanahan1 committed Dec 6, 2024
1 parent 1a7d932 commit 9f6a2ef
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 42 deletions.
14 changes: 9 additions & 5 deletions jdaviz/configs/cubeviz/plugins/tests/test_regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def test_regions_pixel(self):
[my_reg], return_bad_regions=True)
assert len(bad_regions) == 0
self.verify_region_loaded('Subset 1', count=1)
assert len(self.cubeviz.get_interactive_regions()) == 1
assert len(self.cubeviz.plugins['Subset Tools']._obj.get_subsets_as_regions()) == 1

def test_regions_sky_has_wcs(self):
sky = SkyCoord(205.4397, 27.0035, unit='deg')
Expand All @@ -63,10 +63,14 @@ def test_spatial_spectral_mix(self):
4.896 * unit))
self.cubeviz.app.session.edit_subset_mode.edit_subset = None

# Get interactive spatial regions only.
spatial_subsets = self.cubeviz.get_interactive_regions()
assert list(spatial_subsets.keys()) == ['Subset 1'], spatial_subsets
assert isinstance(spatial_subsets['Subset 1'], EllipsePixelRegion)
# Get spatial regions only.
st = self.cubeviz.plugins['Subset Tools']._obj
spatial_subsets_as_regions = st.get_subsets_as_regions(region_type='spatial')
assert list(spatial_subsets_as_regions.keys()) == ['Subset 1'], spatial_subsets_as_regions
assert isinstance(spatial_subsets_as_regions['Subset 1'], EllipsePixelRegion)
# ensure agreement between app.get_subsets and subset_tools.get_subsets_as_regions
ss = self.cubeviz.app.get_subsets()
assert ss['Subset 1'][0]['region'] == spatial_subsets_as_regions['Subset 1']

# NOTE: This does not test that spectrum from Subset is actually scientifically accurate.
# Get spectral regions only.
Expand Down
109 changes: 104 additions & 5 deletions jdaviz/configs/default/plugins/subset_tools/subset_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
ReplaceMode, XorMode, NewMode)
from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI
from glue.core.subset import (RoiSubsetState, RangeSubsetState, CompositeSubsetState,
MaskSubsetState)
MaskSubsetState, Subset)
from glue.icons import icon_path
from glue_jupyter.widgets.subset_mode_vuetify import SelectionModeMenu
from glue_jupyter.common.toolbar_vuetify import read_icon
Expand Down Expand Up @@ -165,12 +165,111 @@ def __init__(self, *args, **kwargs):

@property
def user_api(self):
expose = ['subset', 'combination_mode',
'recenter_dataset', 'recenter',
'get_center', 'set_center',
'import_region']
expose = ['subset', 'combination_mode', 'recenter_dataset', 'recente',
'get_center', 'set_center', 'import_region', 'get_subsets_as_regions']
return PluginUserApi(self, expose)

def get_subsets_as_regions(self, region_type=None, list_of_subset_labels=None,
use_display_units=False):
"""
Return spatial and/or spectral subsets of ``region_type`` (spatial or
spectral, default both) as ``regions`` or ``SpectralRegions`` objects,
respectivley.
Parameters
----------
region_type : str or None, optional
Specifies the type of subsets to retrieve. Options are:
- ``spatial``: Retrieve only spatial subsets.
- ``spectral``: Retrieve only spectral subsets.
- ``None`` (default): Retrieve both spatial and spectral subsets,
determined by the current configuration.
list_of_subset_labels : list of str or None, optional
If specified, only subsets matching these labels will be included.
If not specified, all subsets matching the `region_type` will be
returned.
use_display_units : bool, optional
(For spectral subsets) If False (default), subsets are returned in
the native data unit. If True, subsets are returned in the spectral
axis display unit set in the Unit Conversion plugin.
Returns
-------
regions : dict
A dictionary mapping subset labels to their respective ``regions``
objects (for spatial regions) or ``SpectralRegions`` objects
(for spectral regions).
"""

if region_type is not None:
region_type = region_type.lower()
if region_type not in ['spectral', 'spatial']:
raise ValueError("`region_type` must be 'spectral' or 'spatial'.")
if ((self.config == 'imviz' and region_type == 'spectral') or
(self.config == 'specviz' and region_type == 'spatial')):
raise ValueError(f"No {region_type} subests in {self.config}.")
region_type = [region_type]

else: # determine which subset types should be returned by config, if type not specified
if self.config == 'imviz':
region_type = ['spatial']
elif self.config == 'specviz':
region_type = ['spectral']
else:
region_type = ['spatial', 'spectral']

regions = {}

if 'spatial' in region_type:
from glue_astronomy.translators.regions import roi_subset_state_to_region

failed_regs = set()
to_sky = self.app._align_by == 'wcs'

# Subset is global, so we just use default viewer.
for lyr in self.app._jdaviz_helper.default_viewer._obj.layers:
if (not hasattr(lyr, 'layer') or not isinstance(lyr.layer, Subset)
or lyr.layer.ndim not in (2, 3)):
continue

subset_data = lyr.layer
subset_label = subset_data.label

# TODO: Remove this when Jdaviz support round-tripping, see
# https://github.com/spacetelescope/jdaviz/pull/721
if not subset_label.startswith('Subset'):
continue
try:
if self.app.config == "imviz" and to_sky:
region = roi_subset_state_to_region(subset_data.subset_state,
to_sky=to_sky)
else:
region = subset_data.data.get_selection_definition(
subset_id=subset_label, format='astropy-regions')
except (NotImplementedError, ValueError):
failed_regs.add(subset_label)
else:
regions[subset_label] = region

if len(failed_regs) > 0:
self.app.hub.broadcast(SnackbarMessage(
f"Regions skipped: {', '.join(sorted(failed_regs))}",
color="warning", timeout=8000, sender=self.app))

if 'spectral' in region_type:
spec_regions = self.app.get_subsets(spectral_only=True,
use_display_units=use_display_units)
if spec_regions:
regions.update(spec_regions)

# filter by list_of_subset_labels
if list_of_subset_labels is not None:
regions = {key: regions[key] for key in list_of_subset_labels}

return regions

def _on_link_update(self, *args):
"""When linking is changed pixels<>wcs, change display units of the
subset plugin from pixel (for pixel linking) to sky (for WCS linking).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np
from astropy.nddata import NDData
import astropy.units as u
from regions import CirclePixelRegion, PixCoord
from specutils import SpectralRegion
from glue.core.roi import EllipticalROI, CircularROI, CircularAnnulusROI, RectangularROI
from glue.core.edit_subset_mode import ReplaceMode, OrMode
Expand Down Expand Up @@ -226,3 +227,28 @@ def test_import_spectral_regions_file(cubeviz_helper, spectrum1d_cube, tmp_path)

with pytest.raises(ValueError, match='\'test\' not one of'):
plg.combination_mode = 'test'


def test_get_subsets_as_regions(cubeviz_helper, spectrum1d_cube):

cubeviz_helper.load_data(spectrum1d_cube)
plg = cubeviz_helper.plugins['Subset Tools']

# load one spectral region, which will become 'Subset 1'
plg.import_region(SpectralRegion(1* u.um, 2 * u.um))

# load one spatial region, which will become 'Subset 2'
spatial_reg = CirclePixelRegion(center=PixCoord(x=2, y=2), radius=2)
plg.import_region(spatial_reg)

# call get_subsets_as_regions, which by default for cubeviz will return both
# spatial and spectral regoins
all_regions = plg.get_subsets_as_regions()
# assert len(all_regions) == 2

# now specify region type
spatial_regions = plg.get_subsets_as_regions(region_type='spatial')
assert len(spatial_regions) == 1

spectral_regions = plg.get_subsets_as_regions(region_type='spectral')
assert len(spectral_regions) == 1
12 changes: 11 additions & 1 deletion jdaviz/configs/imviz/tests/test_linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,17 @@ def test_wcslink_affine_with_extras(self):

# Ensure subsets are still there.
all_labels = [layer.layer.label for layer in self.viewer.state.layers]
assert sorted(self.imviz.get_interactive_regions()) == ['Subset 1', 'Subset 2']
# Retrieved subsets as sky regions from Subset plugin, and ensure they
# match what was loaded and that they are in sky coordinates.
subset_as_regions = self.imviz.plugins['Subset Tools']._obj.get_subsets_as_regions()
assert sorted(subset_as_regions) == ['Subset 1', 'Subset 2']
assert_allclose(subset_as_regions['Subset 1'].center.ra.deg, 337.519449)
assert_allclose(subset_as_regions['Subset 2'].center.ra.deg, 337.518498)
# ensure agreement between app.get_subsets and subset_tools.get_subsets_as_regions
ss = self.imviz.app.get_subsets(include_sky_region=True)
assert ss['Subset 1'][0]['sky_region'] == subset_as_regions['Subset 1']
assert ss['Subset 2'][0]['sky_region'] == subset_as_regions['Subset 2']

assert 'MaskedSubset 1' in all_labels
assert 'MaskedSubset 2' in all_labels

Expand Down
11 changes: 9 additions & 2 deletions jdaviz/configs/imviz/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from astropy.wcs import WCS
from gwcs import WCS as GWCS
from numpy.testing import assert_allclose, assert_array_equal
from regions import CirclePixelRegion, RectanglePixelRegion
from regions import CirclePixelRegion, PixCoord, RectanglePixelRegion
from skimage.io import imsave
from stdatamodels import asdf_in_fits

Expand Down Expand Up @@ -259,10 +259,17 @@ def test_parse_jwst_nircam_level2(self, imviz_helper):
imviz_helper._apply_interactive_region('bqplot:rectangle',
(982, 1088),
(1008, 1077)) # Background
subsets = imviz_helper.get_interactive_regions()
subsets = imviz_helper.plugins['Subset Tools']._obj.get_subsets_as_regions()
assert list(subsets.keys()) == ['Subset 1', 'Subset 2'], subsets
# check that retrieved subsets-as-regions from subset plugin match what was loaded.
assert isinstance(subsets['Subset 1'], CirclePixelRegion)
assert subsets['Subset 1'].center == PixCoord(970.95, 1116.05)
assert isinstance(subsets['Subset 2'], RectanglePixelRegion)
assert subsets['Subset 2'].center == PixCoord(995.0, 1082.5)
# ensure agreement between app.get_subsets and subset_tools.get_subsets_as_regions
ss = imviz_helper.app.get_subsets()
assert ss['Subset 1'][0]['region'] == subsets['Subset 1']
assert ss['Subset 2'][0]['region'] == subsets['Subset 2']

# Test simple aperture photometry plugin.
phot_plugin = imviz_helper.app.get_tray_item_from_name('imviz-aper-phot-simple')
Expand Down
Loading

0 comments on commit 9f6a2ef

Please sign in to comment.