Skip to content

Commit

Permalink
Subsets tools API hints (#3325)
Browse files Browse the repository at this point in the history
* expose user API for recenter_data and recenter
* subset tools API hints
* update tests
  • Loading branch information
kecnry authored Dec 5, 2024
1 parent 300e5f3 commit 1a7d932
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 34 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ API Changes
-----------
- Removed API access to plugins that have passed the deprecation period: Links Control, Canvas Rotation, Export Plot. [#3270]

- Subset Tools plugin now exposes the ``subset``, ``combination_mode``, ``get_center``, and ``set_center`` in the user API. [#3293, #3304]
- Subset Tools plugin now exposes the ``subset``, ``combination_mode``, ``recenter_dataset``,
``recenter``, ``get_center``, and ``set_center`` in the user API. [#3293, #3304, #3325]

- Metadata plugin: ``metadata_plugin.metadata`` API has been deprecated; use
``metadata_plugin.meta`` instead, which will return a Python dictionary instead of
Expand Down
30 changes: 25 additions & 5 deletions jdaviz/configs/default/plugins/subset_tools/subset_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from jdaviz.core.region_translators import regions2roi, aperture2regions
from jdaviz.core.events import SnackbarMessage, GlobalDisplayUnitChanged, LinkUpdatedMessage
from jdaviz.core.registries import tray_registry
from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetSelectMixin,
from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetSelect,
SubsetSelect, SelectPluginComponent)
from jdaviz.core.tools import ICON_DIR
from jdaviz.core.user_api import PluginUserApi
Expand Down Expand Up @@ -63,7 +63,7 @@


@tray_registry('g-subset-tools', label="Subset Tools")
class SubsetTools(PluginTemplateMixin, DatasetSelectMixin):
class SubsetTools(PluginTemplateMixin):
"""
See the :ref:`Subset Tools <imviz-subset-plugin>` for more details.
Expand All @@ -77,6 +77,9 @@ class SubsetTools(PluginTemplateMixin, DatasetSelectMixin):
Manages subset selection and creation
* ``combination_mode`` (:class:`~jdaviz.core.template_mixin.SelectPluginComponent`):
Allows selection of combination modes for subsets
* ``recenter_dataset`` (:class:`~jdaviz.core.template_mixin.DatasetSelect`):
Data used for recentering.
* :meth:`recenter`
* :meth:`get_center`
* :meth:`set_center`
* :meth:`import_region`
Expand All @@ -93,6 +96,9 @@ class SubsetTools(PluginTemplateMixin, DatasetSelectMixin):
glue_state_types = List([]).tag(sync=True)
has_subset_details = Bool(False).tag(sync=True)

recenter_dataset_items = List().tag(sync=True)
recenter_dataset_selected = Unicode().tag(sync=True)

subplugins_opened = Any().tag(sync=True)

multiselect = Bool(False).tag(sync=True) # multiselect only for subset
Expand Down Expand Up @@ -148,14 +154,21 @@ def __init__(self, *args, **kwargs):
align_by = getattr(self.app, '_align_by', None)
self.display_sky_coordinates = (align_by == 'wcs' and not self.multiselect)

self.recenter_dataset = DatasetSelect(self, 'recenter_dataset_items',
'recenter_dataset_selected',
multiselect=None)

self.combination_mode = SelectPluginComponent(self,
items='combination_items',
selected='combination_selected',
manual_options=COMBO_OPTIONS)

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

def _on_link_update(self, *args):
Expand Down Expand Up @@ -556,7 +569,11 @@ def _check_input(self):

return status, reason

def vue_recenter_subset(self, *args):
def recenter(self):
"""
Recenter the selected subset on the centroid of the region of the current subset
in the selected data layer.
"""
# Composite region cannot be centered. This only works for Imviz.
if not self.is_centerable or self.config != 'imviz': # no-op
raise NotImplementedError(
Expand All @@ -570,7 +587,7 @@ def _do_recentering(subset, subset_state):
try:
reg = _get_region_from_spatial_subset(self, subset_state)
aperture = regions2aperture(reg)
data = self.dataset.selected_dc_item
data = self.recenter_dataset.selected_dc_item
comp = data.get_component(data.main_components[0])
comp_data = comp.data
phot_aperstats = ApertureStats(comp_data, aperture, wcs=data.coords)
Expand Down Expand Up @@ -613,6 +630,9 @@ def _do_recentering(subset, subset_state):
f"composite subset {sub}",
color='error', sender=self))

def vue_recenter_subset(self, *args):
self.recenter()

def _get_subset_state(self, subset_name=None):
if self.multiselect and not subset_name:
raise ValueError("Please include subset_name in when in multiselect mode")
Expand Down
51 changes: 48 additions & 3 deletions jdaviz/configs/default/plugins/subset_tools/subset_tools.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
<template>
<j-tray-plugin
:config="config"
plugin_key="Subset Tools"
:api_hints_enabled.sync="api_hints_enabled"
:description="docs_description"
:link="docs_link || 'https://jdaviz.readthedocs.io/en/'+vdocs+'/'+config+'/plugins.html#subset-tools'"
:popout_button="popout_button"
:scroll_to.sync="scroll_to">

<v-row v-if="api_hints_enabled && config === 'imviz'">
<span class="api-hint">
plg.subset.multiselect = {{ boolToString(multiselect) }}
</span>
</v-row>
<v-row v-if="config === 'imviz'">
<div style="width: calc(100% - 32px)">
</div>
Expand All @@ -29,6 +37,8 @@
:multiselect="multiselect"
:show_if_single_entry="true"
label="Subset"
api_hint="plg.subset ="
:api_hints_enabled="api_hints_enabled"
hint="Select subset to edit."
/>
</v-col>
Expand All @@ -40,6 +50,12 @@
</v-col>
</v-row>

<v-row v-if="api_hints_enabled" style="margin-top: -32px">
<span class="api-hint">
plg.combination_mode = '{{ combination_selected }}'
</span>
</v-row>

<!-- Sub-plugin for recentering of spatial subset (Imviz only) -->
<v-row v-if="config=='imviz' && is_centerable">
<v-expansion-panels accordion v-model="subplugins_opened">
Expand All @@ -49,14 +65,29 @@
</v-expansion-panel-header>
<v-expansion-panel-content class="plugin-expansion-panel-content">
<plugin-dataset-select
:items="dataset_items"
:selected.sync="dataset_selected"
:items="recenter_dataset_items"
:selected.sync="recenter_dataset_selected"
:show_if_single_entry="true"
label="Data"
api_hint="plg.recenter_dataset ="
:api_hints_enabled="api_hints_enabled"
hint="Select the data for centroiding."
/>
<v-row justify="end" no-gutters>
<v-btn color="primary" text @click="recenter_subset">Recenter</v-btn>
<j-tooltip tooltipcontent="Recenter subset to centroid of selected data">
<v-btn
color="primary"
text
@click="recenter_subset"
:class="api_hints_enabled ? 'api-hint' : null"
>
{{ api_hints_enabled ?
'plg.recenter()'
:
'Recenter'
}}
</v-btn>
</j-tooltip>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
Expand Down Expand Up @@ -146,3 +177,17 @@
</v-row>
</j-tray-plugin>
</template>

<script>
module.exports = {
methods: {
boolToString(b) {
if (b) {
return 'True'
} else {
return 'False'
}
},
}
}
</script>
38 changes: 19 additions & 19 deletions jdaviz/configs/imviz/tests/test_subset_centroid.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@
class TestImvizSpatialSubsetCentroidPixelLinked(BaseImviz_WCS_GWCS):
def test_centroiding_pixel(self):
reg = CirclePixelRegion(PixCoord(2, 2), 3)
plg = self.imviz.plugins['Subset Tools']._obj
plg = self.imviz.plugins['Subset Tools']
plg.import_region(reg)

plg.subset_selected = 'Subset 1'
plg.subset = 'Subset 1'

# Since they are linked by pixels, the bright corner pixel aligns
# and nothing should change.
for data_label in ('fits_wcs[DATA]', 'gwcs[DATA]'):
plg.dataset_selected = data_label
plg.recenter_dataset = data_label
plg.set_center((2, 2), update=True) # Move the Subset back first.
plg.vue_recenter_subset()
plg.recenter()

# Calculate and move to centroid.
for key in ("X Center (pixels)", "Y Center (pixels)"):
assert plg._get_value_from_subset_definition(0, key, "value") == -1
assert plg._get_value_from_subset_definition(0, key, "orig") == -1
assert plg._obj._get_value_from_subset_definition(0, key, "value") == -1
assert plg._obj._get_value_from_subset_definition(0, key, "orig") == -1

# Radius will not be touched.
for key in ("value", "orig"):
assert plg._get_value_from_subset_definition(0, "Radius (pixels)", key) == 3
assert plg._obj._get_value_from_subset_definition(0, "Radius (pixels)", key) == 3

assert plg.get_center() == (-1, -1)

Expand All @@ -40,34 +40,34 @@ def test_centroiding_wcs(self):
self.imviz.link_data(align_by='wcs')

reg = CirclePixelRegion(PixCoord(2, 2), 3).to_sky(self.wcs_1)
plg = self.imviz.plugins['Subset Tools']._obj
plg = self.imviz.plugins['Subset Tools']
plg.import_region(reg)

plg.subset_selected = 'Subset 1'
plg.dataset_selected = 'fits_wcs[DATA]'
plg.vue_recenter_subset()
plg.subset = 'Subset 1'
plg.recenter_dataset = 'fits_wcs[DATA]'
plg.recenter()

# Pixel value is now w.r.t. fake WCS layer, not the selected data.
for key in ("value", "orig"):
# subset definition is now in sky coordinates. get RA and Dec and convert back to pixel
# to compare with expected recentered position.
ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key) * u.deg
dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key) * u.deg
ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key) * u.deg
dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key) * u.deg
x, y = SkyCoord(ra, dec).to_pixel(self.wcs_1)
assert_allclose((x, y), -1)

# GWCS does not extrapolate and this Subset is out of bounds,
# so will get NaNs and enter the exception handling logic.
plg.dataset_selected = 'gwcs[DATA]'
plg.recenter_dataset = 'gwcs[DATA]'
plg.set_center((2.6836, 1.6332), update=True) # Move the Subset back first.
plg.vue_recenter_subset()
plg.recenter()
subsets = self.imviz.app.get_subsets(include_sky_region=True)
subsets_sky = subsets['Subset 1'][0]['sky_region']
subsets_pix = subsets['Subset 1'][0]['region']
assert_allclose((subsets_pix.center.x, subsets_pix.center.y), (2.6836, 1.6332))
for key in ("value", "orig"):
ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key)
dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key)
ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key)
dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key)

# make sure what is in subset_definitions matches what is returned by get_subsets
assert_allclose((ra, dec), (subsets_sky.center.ra.deg, subsets_sky.center.dec.deg))
Expand All @@ -77,8 +77,8 @@ def test_centroiding_wcs(self):
# vue_update_subset is called.
plg.set_center((2, 2), update=False)
for key in ("value", "orig"):
ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key)
dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key)
ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key)
dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key)
# here 'ra' and 'dec' should remain unchanged from when they were defined, since
# vue_update_subset hasn't run
assert_allclose((ra, dec), (subsets_sky.center.ra.deg, subsets_sky.center.dec.deg))
12 changes: 6 additions & 6 deletions jdaviz/tests/test_subsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def test_region_from_subset_2d(cubeviz_helper):
assert_allclose(reg.height, 6.6)
assert_allclose(reg.angle.value, 0)

assert subset_plugin._obj.subset_selected == "Subset 1"
assert subset_plugin.subset == "Subset 1"
assert subset_plugin._obj.subset_types == ["EllipticalROI"]
assert subset_plugin._obj.is_centerable
for key in ("orig", "value"):
Expand All @@ -52,7 +52,7 @@ def test_region_from_subset_2d(cubeviz_helper):

# Recenter GUI should not be exposed, but API call would raise exception.
with pytest.raises(NotImplementedError, match='Cannot recenter'):
subset_plugin._obj.vue_recenter_subset()
subset_plugin.recenter()


def test_region_from_subset_3d(cubeviz_helper):
Expand Down Expand Up @@ -430,12 +430,12 @@ def test_recenter_linked_by_wcs(imviz_helper):
RectanglePixelRegion(center=PixCoord(x=229, y=152), width=17, height=7).to_sky(w))

subset_plugin = imviz_helper.plugins['Subset Tools']
subset_plugin._obj.subset_selected = "Subset 1"
subset_plugin._obj.dataset_selected = "gauss100_fits_wcs_block_reduced[PRIMARY,1]"
subset_plugin.subset = "Subset 1"
subset_plugin.recenter_dataset = "gauss100_fits_wcs_block_reduced[PRIMARY,1]"

# Do it a few times to converge.
for _ in range(5):
subset_plugin._obj.vue_recenter_subset()
subset_plugin.recenter()

# If handled correctly, it won't change much.
# But if not, it move down by 7 pix or so (229.05, 145.92) and fails the test.
Expand All @@ -453,7 +453,7 @@ def test_recenter_linked_by_wcs(imviz_helper):

# Do it a few times to converge.
for _ in range(5):
subset_plugin._obj.vue_recenter_subset()
subset_plugin._obj.recenter()

xy = imviz_helper.default_viewer._obj._get_real_xy(
imviz_helper.app.data_collection[0], *subset_plugin.get_center("Subset 2"))[:2]
Expand Down

0 comments on commit 1a7d932

Please sign in to comment.