From 1c27d24eb9980d7611365282ca16bc0e3ea6e8de Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Wed, 7 Sep 2022 09:34:21 -0400 Subject: [PATCH 1/4] user API for slice plugin --- jdaviz/configs/cubeviz/plugins/slice/slice.py | 47 ++++++++++++++----- .../configs/cubeviz/plugins/slice/slice.vue | 7 ++- .../cubeviz/plugins/slice/tests/test_slice.py | 16 +++---- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.py b/jdaviz/configs/cubeviz/plugins/slice/slice.py index 9a016129e8..ed53b7d495 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.py @@ -9,14 +9,33 @@ from jdaviz.core.events import AddDataMessage, SliceToolStateMessage, SliceSelectSliceMessage from jdaviz.core.registries import tray_registry from jdaviz.core.template_mixin import PluginTemplateMixin +from jdaviz.core.user_api import PluginUserApi __all__ = ['Slice'] @tray_registry('cubeviz-slice', label="Slice") class Slice(PluginTemplateMixin): + """ + See the :ref:`Slice Plugin Documentation ` for more details. + + Only the following attributes and methods are available through the + :ref:`public plugin API `: + + * :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.show` + * :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.open_in_tray` + * ``slice`` + Current slice number. + * ``wavelength`` + Wavelength of the current slice. If setting, will update automatically to the nearest + slice. + * ``setting_show_indicator`` + Whether to show indicator in spectral viewer when slice tool is inactive. + * ``setting_show_wavelength`` + Whether to show slice wavelength in label to right of indicator. + """ template_file = __file__, "slice.vue" - slider = Any(0).tag(sync=True) + slice = Any(0).tag(sync=True) wavelength = Any(-1).tag(sync=True) wavelength_unit = Any("").tag(sync=True) min_value = Float(0).tag(sync=True) @@ -51,6 +70,11 @@ def __init__(self, *args, **kwargs): self.session.hub.subscribe(self, AddDataMessage, handler=self._on_data_added) + @property + def user_api(self): + return PluginUserApi(self, expose=('slice', 'wavelength', + 'setting_show_indicator', 'setting_show_wavelength')) + def _watch_viewer(self, viewer, watch=True): if isinstance(viewer, BqplotImageView): if watch and viewer not in self._watched_viewers: @@ -96,13 +120,13 @@ def _update_data(self, x_all): if self.wavelength == -1: if len(x_all): # initialize at middle of cube - self.slider = int(len(x_all)/2) + self.slice = int(len(x_all)/2) else: - # leave in the pre-init state and don't update the wavelength/slider + # leave in the pre-init state and don't update the wavelength/slice return # force wavelength to update from the current slider value - self._on_slider_updated({'new': self.slider}) + self._on_slider_updated({'new': self.slice}) def _viewer_slices_changed(self, value): # the slices attribute on the viewer state was changed, @@ -110,37 +134,38 @@ def _viewer_slices_changed(self, value): # the slider observer (_on_slider_updated) and sync across # any other applicable viewers if len(value) == 3: - self.slider = float(value[-1]) + self.slice = float(value[-1]) def _on_select_slice_message(self, msg): # NOTE: by setting the slice index, the observer (_on_slider_updated) # will sync across all viewers and update the wavelength with warnings.catch_warnings(): warnings.simplefilter('ignore', category=UnitsWarning) - self.slider = msg.slice + self.slice = msg.slice - def vue_change_wavelength(self, event): + @observe('wavelength') + def _on_wavelength_updated(self, event): # convert to float (JS handles stripping any invalid characters) try: - value = float(event) + value = float(event.get('new')) except ValueError: # do not accept changes, we'll revert via the slider # since this @change event doesn't have access to # the old value, and self.wavelength already updated # via the v-model - self._on_slider_updated({'new': self.slider}) + self._on_slider_updated({'new': self.slice}) return # NOTE: by setting the index, this should recursively update the # wavelength to the nearest applicable value in _on_slider_updated - self.slider = int(np.argmin(abs(value - self._x_all))) + self.slice = int(np.argmin(abs(value - self._x_all))) @observe('setting_show_indicator', 'setting_show_wavelength') def _on_setting_changed(self, event): msg = SliceToolStateMessage({event['name']: event['new']}, sender=self) self.session.hub.broadcast(msg) - @observe('slider') + @observe('slice') def _on_slider_updated(self, event): value = int(event.get('new', int(len(self._x_all)/2))) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.vue b/jdaviz/configs/cubeviz/plugins/slice/slice.vue index 7735dbefe6..89223bd639 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.vue +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.vue @@ -34,7 +34,7 @@ @@ -79,7 +78,7 @@ module.exports = { created() { this.throttledSetValue = _.throttle( - (v) => { this.slider = v; }, + (v) => { this.slice = v; }, this.wait); }, } diff --git a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py index 195f3f9713..99427db1d0 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py @@ -13,9 +13,9 @@ def test_slice(cubeviz_helper, spectrum1d_cube): app.add_data_to_viewer("flux-viewer", "test") # sample cube only has 2 slices with wavelengths [4.62280007e-07 4.62360028e-07] m - assert sl.slider == 1 + assert sl.slice == 1 cubeviz_helper.select_slice(0) - assert sl.slider == 0 + assert sl.slice == 0 with pytest.raises( TypeError, @@ -28,17 +28,17 @@ def test_slice(cubeviz_helper, spectrum1d_cube): cubeviz_helper.select_slice(-5) cubeviz_helper.select_wavelength(4.62360028e-07) - assert sl.slider == 1 + assert sl.slice == 1 # from the widget this logic is duplicated (to avoid sending logic through messages) - sl.vue_change_wavelength('4.62e-07') - assert sl.slider == 0 + sl._on_wavelength_updated({'new': '4.62e-07'}) + assert sl.slice == 0 assert np.allclose(sl.wavelength, 4.62280007e-07) # make sure that passing an invalid value from the UI would revert to the previous value # JS strips invalid characters, but doesn't ensure its float-compatible - sl.vue_change_wavelength('1.2.3') - assert sl.slider == 0 + sl._on_wavelength_updated({'new': '1.2.3'}) + assert sl.slice == 0 # there is only one watched viewer, since the uncertainty/mask viewers are empty assert len(sl._watched_viewers) == 1 @@ -60,7 +60,7 @@ def test_slice(cubeviz_helper, spectrum1d_cube): new_len = len(sv.native_marks[0].x) assert new_len == 2*orig_len cubeviz_helper.select_wavelength(4.62360028e-07) - assert sl.slider == 1 + assert sl.slice == 1 @pytest.mark.filterwarnings('ignore:No observer defined on WCS') From 44b53d268eabd02bde7fbc8d20419b410658eb90 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 15 Sep 2022 11:17:08 -0400 Subject: [PATCH 2/4] remove setting_ prefix from traitlets --- jdaviz/configs/cubeviz/plugins/slice/slice.py | 12 ++++++------ jdaviz/configs/cubeviz/plugins/slice/slice.vue | 4 ++-- .../cubeviz/plugins/slice/tests/test_slice.py | 8 ++++---- jdaviz/core/marks.py | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.py b/jdaviz/configs/cubeviz/plugins/slice/slice.py index ed53b7d495..49ec4bf8c4 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.py @@ -29,9 +29,9 @@ class Slice(PluginTemplateMixin): * ``wavelength`` Wavelength of the current slice. If setting, will update automatically to the nearest slice. - * ``setting_show_indicator`` + * ``show_indicator`` Whether to show indicator in spectral viewer when slice tool is inactive. - * ``setting_show_wavelength`` + * ``show_wavelength`` Whether to show slice wavelength in label to right of indicator. """ template_file = __file__, "slice.vue" @@ -42,8 +42,8 @@ class Slice(PluginTemplateMixin): max_value = Float(100).tag(sync=True) wait = Int(200).tag(sync=True) - setting_show_indicator = Bool(True).tag(sync=True) - setting_show_wavelength = Bool(True).tag(sync=True) + show_indicator = Bool(True).tag(sync=True) + show_wavelength = Bool(True).tag(sync=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -73,7 +73,7 @@ def __init__(self, *args, **kwargs): @property def user_api(self): return PluginUserApi(self, expose=('slice', 'wavelength', - 'setting_show_indicator', 'setting_show_wavelength')) + 'show_indicator', 'show_wavelength')) def _watch_viewer(self, viewer, watch=True): if isinstance(viewer, BqplotImageView): @@ -160,7 +160,7 @@ def _on_wavelength_updated(self, event): # wavelength to the nearest applicable value in _on_slider_updated self.slice = int(np.argmin(abs(value - self._x_all))) - @observe('setting_show_indicator', 'setting_show_wavelength') + @observe('show_indicator', 'show_wavelength') def _on_setting_changed(self, event): msg = SliceToolStateMessage({event['name']: event['new']}, sender=self) self.session.hub.broadcast(msg) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.vue b/jdaviz/configs/cubeviz/plugins/slice/slice.vue index 89223bd639..7824378d1f 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.vue +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.vue @@ -15,7 +15,7 @@ @@ -23,7 +23,7 @@ diff --git a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py index 99427db1d0..f946a246a2 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py @@ -73,13 +73,13 @@ def test_indicator_settings(cubeviz_helper, spectrum1d_cube): sv = app.get_viewer('spectrum-viewer') indicator = sv.slice_indicator - assert sl.setting_show_indicator is True + assert sl.show_indicator is True assert indicator._show_if_inactive is True - assert sl.setting_show_wavelength is True + assert sl.show_wavelength is True assert indicator.label.visible is True - sl.setting_show_indicator = False + sl.show_indicator = False assert indicator._show_if_inactive is False - sl.setting_show_wavelength = False + sl.show_wavelength = False assert indicator.label.visible is False diff --git a/jdaviz/core/marks.py b/jdaviz/core/marks.py index bae9166d2b..85677e5c04 100644 --- a/jdaviz/core/marks.py +++ b/jdaviz/core/marks.py @@ -277,9 +277,9 @@ def _on_change_state(self, msg): for k, v in changes.items(): if k == 'active': self._active = v - elif k == 'setting_show_indicator': + elif k == 'show_indicator': self._show_if_inactive = v - elif k == 'setting_show_wavelength': + elif k == 'show_wavelength': self._show_wavelength = v self._update_colors_opacities() From 0950fd5a6ba967dba719df3e907328e795bc595e Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 15 Sep 2022 11:19:22 -0400 Subject: [PATCH 3/4] clarify description on wavelength traitlet --- jdaviz/configs/cubeviz/plugins/slice/slice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.py b/jdaviz/configs/cubeviz/plugins/slice/slice.py index 49ec4bf8c4..a7f2c72076 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.py @@ -27,8 +27,8 @@ class Slice(PluginTemplateMixin): * ``slice`` Current slice number. * ``wavelength`` - Wavelength of the current slice. If setting, will update automatically to the nearest - slice. + Wavelength of the current slice. When setting this directly, it will update automatically to + the wavelength corresponding to the nearest slice. * ``show_indicator`` Whether to show indicator in spectral viewer when slice tool is inactive. * ``show_wavelength`` From 4c224498984532766dd7d0da88702cf4e7f704ad Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 15 Sep 2022 11:25:02 -0400 Subject: [PATCH 4/4] update changelog entry --- CHANGES.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index ad8c812541..83f3b9f7d9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,7 +10,8 @@ New Features in Jy [#1564] - User-friendly API access to plugins, with exposed functionality for: line analysis, gaussian - smooth, moment maps, compass, collapse, and metadata. [#1401, #1642, #1643, #1636, #1641, #1634] + smooth, moment maps, compass, collapse, metadata, and slice. + [#1401, #1642, #1643, #1636, #1641, #1634, #1635] Cubeviz ^^^^^^^