diff --git a/CHANGES.rst b/CHANGES.rst index daba79a73f..cf107b003a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -30,6 +30,8 @@ Cubeviz - New aperture photometry plugin that can perform aperture photometry on selected cube slice. [#2666] +- Live previews in spectral extraction plugin. [#2733] + Imviz ^^^^^ diff --git a/jdaviz/app.py b/jdaviz/app.py index cc0400d22a..cc4dc0baf6 100644 --- a/jdaviz/app.py +++ b/jdaviz/app.py @@ -126,6 +126,7 @@ def to_unit(self, data, cid, values, original_units, target_units): 'j-plugin-section-header': 'components/plugin_section_header.vue', 'j-number-uncertainty': 'components/number_uncertainty.vue', 'j-plugin-popout': 'components/plugin_popout.vue', + 'plugin-previews-temp-disabled': 'components/plugin_previews_temp_disabled.vue', # noqa 'plugin-table': 'components/plugin_table.vue', 'plugin-dataset-select': 'components/plugin_dataset_select.vue', 'plugin-subset-select': 'components/plugin_subset_select.vue', diff --git a/jdaviz/components/plugin_previews_temp_disabled.vue b/jdaviz/components/plugin_previews_temp_disabled.vue new file mode 100644 index 0000000000..0aed4c84a7 --- /dev/null +++ b/jdaviz/components/plugin_previews_temp_disabled.vue @@ -0,0 +1,25 @@ + + + diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py index 36d1210337..851a9bae37 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py @@ -14,6 +14,7 @@ from jdaviz.core.custom_traitlets import FloatHandleEmpty from jdaviz.core.events import SnackbarMessage, SliceValueUpdatedMessage +from jdaviz.core.marks import SpectralExtractionPreview from jdaviz.core.registries import tray_registry from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetSelectMixin, @@ -21,10 +22,12 @@ ApertureSubsetSelectMixin, ApertureSubsetSelect, AddResultsMixin, - with_spinner) + skip_if_no_updates_since_last_active, + with_spinner, with_temp_disable) from jdaviz.core.user_api import PluginUserApi from jdaviz.core.region_translators import regions2aperture from jdaviz.configs.cubeviz.plugins.parsers import _return_spectrum_with_correct_units +from jdaviz.configs.cubeviz.plugins.viewers import CubevizProfileView __all__ = ['SpectralExtraction'] @@ -59,6 +62,7 @@ class SpectralExtraction(PluginTemplateMixin, ApertureSubsetSelectMixin, """ template_file = __file__, "spectral_extraction.vue" uses_active_status = Bool(True).tag(sync=True) + show_live_preview = Bool(True).tag(sync=True) # feature flag for background cone support dev_bg_support = Bool(False).tag(sync=True) # when enabling: add entries to docstring @@ -458,3 +462,60 @@ def _set_default_results_label(self, event={}): ): label += f' ({self.aperture_selected})' self.results_label_default = label + + @property + def marks(self): + marks = {} + for id, viewer in self.app._viewer_store.items(): + if not isinstance(viewer, CubevizProfileView): + continue + for mark in viewer.figure.marks: + if isinstance(mark, SpectralExtractionPreview): + marks[id] = mark + break + else: + mark = SpectralExtractionPreview(viewer, visible=self.is_active) + viewer.figure.marks = viewer.figure.marks + [mark] + marks[id] = mark + return marks + + def _clear_marks(self): + for mark in self.marks.values(): + if mark.visible: + mark.clear() + mark.visible = False + + @observe('is_active', 'show_live_preview') + def _toggle_marks(self, event={}): + visible = self.show_live_preview and self.is_active + + if not visible: + self._clear_marks() + elif event.get('name', '') in ('is_active', 'show_live_preview'): + # then the marks themselves need to be updated + self._live_update(event) + + @observe('aperture_selected', 'function_selected', + 'wavelength_dependent', 'reference_wavelength', + 'aperture_method_selected', + 'previews_temp_disabled') + @skip_if_no_updates_since_last_active() + @with_temp_disable(timeout=0.3) + def _live_update(self, event={}): + if not self.show_live_preview or not self.is_active: + self._clear_marks() + return + + if event.get('name', '') not in ('is_active', 'show_live_preview'): + # mark visibility hasn't been handled yet + self._toggle_marks() + + try: + sp = self.collapse_to_spectrum(add_data=False) + except Exception: + self._clear_marks() + return + + for mark in self.marks.values(): + mark.update_xy(sp.spectral_axis.value, sp.flux.value) + mark.visible = True diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue index 8698db0b57..75179e3c8e 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue @@ -8,6 +8,26 @@ :popout_button="popout_button" :disabled_msg="disabled_msg"> + + + + + Settings + + + + + + + + + +
Aperture @@ -166,7 +186,11 @@ - + + """ + def decorator(meth): + def wrapper(self, *args, **kwargs): + if getattr(self, disable_traitlet): + return + start = time.time() + ret_ = meth(self, *args, **kwargs) + exec_time = np.round(time.time() - start, 2) + setattr(self, time_traitlet, exec_time) + if exec_time > timeout: + setattr(self, disable_traitlet, True) + return ret_ + return wrapper + return decorator + + class PluginTemplateMixin(TemplateMixin): """ This base class can be inherited by all sidebar/tray plugins to expose common functionality. @@ -319,6 +350,8 @@ class PluginTemplateMixin(TemplateMixin): keep_active = Bool(False).tag(sync=True) # noqa whether the live-preview marks show regardless of active state, inapplicable unless uses_active_status is True is_active = Bool(False).tag(sync=True) # noqa read-only: whether the previews should be shown according to plugin_opened and keep_active spinner = Bool(False).tag(sync=True) # noqa use along-side @with_spinner() and + previews_temp_disabled = Bool(False).tag(sync=True) # noqa use along-side @with_temp_disable() and + previews_last_time = Float(0).tag(sync=True) def __init__(self, **kwargs): self._viewer_callbacks = {}