From c92ea66e77b195419d56eef189f5e38f6ea4e844 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Mon, 19 Feb 2024 09:00:36 -0500 Subject: [PATCH] WIP: support upstream refactor * removes need for context-aware as the plugin is now always relevant with synced time indicators * renames "Slice" plugin to "Time Selector" --- docs/plugins.rst | 19 +++-- lcviz/helper.py | 2 +- lcviz/plugins/__init__.py | 2 +- lcviz/plugins/slice/__init__.py | 1 - lcviz/plugins/slice/slice.py | 87 -------------------- lcviz/plugins/time_selector/__init__.py | 1 + lcviz/plugins/time_selector/time_selector.py | 32 +++++++ lcviz/tools.py | 13 --- lcviz/viewers.py | 21 ++++- 9 files changed, 64 insertions(+), 114 deletions(-) delete mode 100644 lcviz/plugins/slice/__init__.py delete mode 100644 lcviz/plugins/slice/slice.py create mode 100644 lcviz/plugins/time_selector/__init__.py create mode 100644 lcviz/plugins/time_selector/time_selector.py diff --git a/docs/plugins.rst b/docs/plugins.rst index c52661c9..2d848c47 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -179,18 +179,19 @@ visible when the plugin is opened. Jdaviz documentation on the Markers plugin. -.. _slice: +.. _time-indicator: -Slice -===== +Time Selector +============== -The slice plugin allows defining the time at which all image cubes are displayed. +The time selector plugin allows defining the time indicated in all light curve viewers +(time and phase viewers) as well as the time at which all image cubes are displayed. .. admonition:: User API Example :class: dropdown - See the :class:`~lcviz.plugins.slice.slice.Slice` user API documentation for more details. + See the :class:`~lcviz.plugins.time_selector.time_selector.TimeSelector` user API documentation for more details. .. code-block:: python @@ -201,14 +202,14 @@ The slice plugin allows defining the time at which all image cubes are displayed lcviz.load_data(lc) lcviz.show() - sl = lcviz.plugins['Slice'] - sl.open_in_tray() + ts = lcviz.plugins['Time Selector'] + ts.open_in_tray() .. seealso:: - :ref:`Jdaviz Markers ` - Jdaviz documentation on the Markers plugin. + :ref:`Jdaviz Slice Plugin ` + Jdaviz documentation on the Slice plugin. diff --git a/lcviz/helper.py b/lcviz/helper.py index 596922cf..bbd6ecab 100644 --- a/lcviz/helper.py +++ b/lcviz/helper.py @@ -74,7 +74,7 @@ class LCviz(ConfigHelper): 'toolbar': ['g-data-tools', 'g-subset-tools', 'lcviz-coords-info'], 'tray': ['lcviz-metadata-viewer', 'flux-column', 'lcviz-plot-options', 'lcviz-subset-plugin', - 'lcviz-markers', 'lcviz-slice', + 'lcviz-markers', 'time-selector', 'flatten', 'frequency-analysis', 'ephemeris', 'binning', 'lcviz-export-plot'], 'viewer_area': [{'container': 'col', diff --git a/lcviz/plugins/__init__.py b/lcviz/plugins/__init__.py index 332b2641..fe4c9879 100644 --- a/lcviz/plugins/__init__.py +++ b/lcviz/plugins/__init__.py @@ -6,7 +6,7 @@ from .flux_column.flux_column import * # noqa from .frequency_analysis.frequency_analysis import * # noqa from .markers.markers import * # noqa -from .slice.slice import * # noqa +from .time_selector.time_selector import * # noqa from .metadata_viewer.metadata_viewer import * # noqa from .plot_options.plot_options import * # noqa from .subset_plugin.subset_plugin import * # noqa diff --git a/lcviz/plugins/slice/__init__.py b/lcviz/plugins/slice/__init__.py deleted file mode 100644 index 9bd7645f..00000000 --- a/lcviz/plugins/slice/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .slice import * # noqa diff --git a/lcviz/plugins/slice/slice.py b/lcviz/plugins/slice/slice.py deleted file mode 100644 index f8c5e377..00000000 --- a/lcviz/plugins/slice/slice.py +++ /dev/null @@ -1,87 +0,0 @@ -from glue_jupyter.bqplot.scatter import BqplotScatterView -from glue.core.message import (DataCollectionAddMessage, - DataCollectionDeleteMessage) - - -from jdaviz.configs.cubeviz.plugins import Slice -from jdaviz.core.registries import tray_registry - -from lcviz.viewers import CubeView - -__all__ = ['Slice'] - - -@tray_registry('lcviz-slice', label="Slice") -class Slice(Slice): - _cube_viewer_cls = CubeView - _cube_viewer_default_label = 'image' - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.docs_link = f"https://lcviz.readthedocs.io/en/{self.vdocs}/plugins.html#slice" - self.docs_description = "Select time to show in the image viewer. The slice can also be changed interactively in any time viewer by activating the slice tool." # noqa - self.value_label = 'Time' - self.value_unit = 'd' - - for id, viewer in self.app._viewer_store.items(): - if isinstance(viewer, BqplotScatterView) or len(viewer.data()): - self._watch_viewer(viewer, True) - - for msg in (DataCollectionAddMessage, DataCollectionDeleteMessage): - self.session.hub.subscribe(self, msg, handler=self._update_relevant) - self._update_relevant() - - @property - def slice_component_label(self): - # label of the component in the cubes corresponding to the slice axis - # calling data_collection_item.get_component(slice_component_label) on any - # input cube-data must work - return 'dt' - - @property - def slice_index(self): - # index in viewer.slices corresponding to the slice axis - return 0 - - @property - def slice_axis(self): - # global display unit "axis" corresponding to the slice axis - return 'time' - - def _update_relevant(self, *args): - # whether the plugin is currently relevant and should appear in the tray - # TODO: if adding a button in the slice plugin to create an image viewer, then this - # should be changed to check for cube data in the data-collection instead - for data in self.app.data_collection: - if data.ndim == 3: - self.irrelevant_msg = '' - return - self.irrelevant_msg = 'Slice plugin is only relevant when cube-like data (e.g., TPF data) is loaded in the app' # noqa - - @property - def user_api(self): - api = super().user_api - # can be removed after deprecated upstream attributes for wavelength/wavelength_value - # are removed in the lowest supported version of jdaviz - api._expose = [e for e in api._expose if e not in ('wavelength', 'wavelength_value', 'show_wavelength')] # noqa - return api - - def _watch_viewer(self, viewer, watch=True): - super()._watch_viewer(viewer, watch=watch) - # image viewer watching handled upstream - if isinstance(viewer, BqplotScatterView): - if self._x_all is None and len(viewer.data()): - # cache values (wavelengths/freqs) so that value <> slice conversion can efficient - self._update_data(viewer.data()[0].time) - - if viewer not in self._indicator_viewers: - self._indicator_viewers.append(viewer) - # if the units (or data) change, we need to update internally -# need to subscribe to add_data instead of reference_data.... -# viewer.state.add_callback("reference_data", -# self._update_reference_data) - - def _update_reference_data(self, reference_data): - if reference_data is None: - return # pragma: no cover - self._update_data(reference_data.get_object().time) diff --git a/lcviz/plugins/time_selector/__init__.py b/lcviz/plugins/time_selector/__init__.py new file mode 100644 index 00000000..0983e6d5 --- /dev/null +++ b/lcviz/plugins/time_selector/__init__.py @@ -0,0 +1 @@ +from .time_selector import * # noqa diff --git a/lcviz/plugins/time_selector/time_selector.py b/lcviz/plugins/time_selector/time_selector.py new file mode 100644 index 00000000..c184d68f --- /dev/null +++ b/lcviz/plugins/time_selector/time_selector.py @@ -0,0 +1,32 @@ +from jdaviz.configs.cubeviz.plugins import Slice +from jdaviz.core.registries import tray_registry + +from lcviz.viewers import CubeView + +__all__ = ['TimeSelector'] + + +@tray_registry('time-selector', label="Time Selector") +class TimeSelector(Slice): + _cube_viewer_cls = CubeView + _cube_viewer_default_label = 'image' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.docs_link = f"https://lcviz.readthedocs.io/en/{self.vdocs}/plugins.html#time-selector" + self.docs_description = "Select time to sync across all viewers (as an indicator in all time/phase viewers or to select the active slice in any image/cube viewers). The slice can also be changed interactively in any time viewer by activating the slice tool." # noqa + self.value_label = 'Time' + self.value_unit = 'd' + + @property + def slice_axis(self): + # global display unit "axis" corresponding to the slice axis + return 'time' + + @property + def user_api(self): + api = super().user_api + # can be removed after deprecated upstream attributes for wavelength/wavelength_value + # are removed in the lowest supported version of jdaviz + api._expose = [e for e in api._expose if e not in ('wavelength', 'wavelength_value', 'show_wavelength')] # noqa + return api diff --git a/lcviz/tools.py b/lcviz/tools.py index 30b905f0..badb5aa2 100644 --- a/lcviz/tools.py +++ b/lcviz/tools.py @@ -4,9 +4,6 @@ from glue.viewers.common.tool import Tool from jdaviz.core.tools import SidebarShortcutPlotOptions, SidebarShortcutExportPlot -from jdaviz.configs.cubeviz.plugins.tools import SelectSlice - -from lcviz.viewers import CubeView ICON_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), 'data', 'icons')) @@ -18,16 +15,6 @@ __all__ = ['ViewerClone'] -def _slice_is_visible(self): - if getattr(self.viewer, 'jdaviz_helper', None) is None: - return False - return len([viewer for viewer in self.viewer.jdaviz_helper.viewers.values() - if isinstance(viewer._obj, CubeView)]) > 0 - - -SelectSlice.is_visible = _slice_is_visible - - @viewer_tool class ViewerClone(Tool): icon = os.path.join(ICON_DIR, 'viewer_clone') diff --git a/lcviz/viewers.py b/lcviz/viewers.py index c2fdb50a..109f5287 100644 --- a/lcviz/viewers.py +++ b/lcviz/viewers.py @@ -12,7 +12,8 @@ from jdaviz.core.events import NewViewerMessage from jdaviz.core.registries import viewer_registry -from jdaviz.configs.cubeviz.plugins.viewers import CubevizImageView, WithSliceIndicator +from jdaviz.configs.cubeviz.plugins.viewers import (CubevizImageView, + WithSliceIndicator, WithSliceSelection) from jdaviz.configs.default.plugins.viewers import JdavizViewerMixin from jdaviz.configs.specviz.plugins.viewers import SpecvizProfileView @@ -275,9 +276,13 @@ def times_to_phases(self, times): return ephem.times_to_phases(times, ephem_component=self.ephemeris_component) + def _set_slice_indicator_value(self, value): + # NOTE: on first call, this will initialize the indicator itself + self.slice_indicator.value = self.times_to_phases(value) + @viewer_registry("lcviz-cube-viewer", label="cube") -class CubeView(CloneViewerMixin, CubevizImageView): +class CubeView(CloneViewerMixin, CubevizImageView, WithSliceSelection): # categories: zoom resets, zoom, pan, subset, select tools, shortcuts tools_nested = [ ['jdaviz:homezoom', 'jdaviz:prevzoom'], @@ -307,6 +312,18 @@ def __init__(self, *args, **kwargs): # * _default_flux_viewer_reference_name # * _default_uncert_viewer_reference_name + @property + def slice_component_label(self): + # label of the component in the cubes corresponding to the slice axis + # calling data_collection_item.get_component(slice_component_label) on any + # input cube-data must work + return 'dt' + + @property + def slice_index(self): + # index in viewer.slices corresponding to the slice axis + return 0 + def _initial_x_axis(self, *args): # Make sure that the x_att/y_att is correct on data load # called via a callback set upstream in CubevizImageView when reference_data is changed