From 910d1773cfe39220e53cfbe7eaff25595f8e4643 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 10:08:54 -0500 Subject: [PATCH 01/16] allow manual_options to be filter * manual options can be either strings or dictionaries * filters passed to SelectPluginComponent will act on manual items, classes that subclass SelectPluginComponent may choose to ALWAYS include all manual items, ignoring filters --- .../default/plugins/data_menu/data_menu.py | 2 +- .../imviz/plugins/footprints/footprints.py | 13 +- jdaviz/core/template_mixin.py | 130 ++++++++++-------- 3 files changed, 82 insertions(+), 63 deletions(-) diff --git a/jdaviz/configs/default/plugins/data_menu/data_menu.py b/jdaviz/configs/default/plugins/data_menu/data_menu.py index 8a0fab6e22..d1a2abcb5f 100644 --- a/jdaviz/configs/default/plugins/data_menu/data_menu.py +++ b/jdaviz/configs/default/plugins/data_menu/data_menu.py @@ -247,7 +247,7 @@ def _layers_changed(self, event={}): if event.get('name') == 'layer_items': # changing the layers in the viewer needs to trigger an update to dataset_items # through the set filters - self.dataset._on_data_changed() + self.dataset._update_items() self.loaded_n_data = len([lyr for lyr in self.layer.choices if lyr not in subset_labels]) return diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 862b58b9c9..2ac14dae5d 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -126,17 +126,20 @@ def __init__(self, *args, **kwargs): on_remove=self._on_overlay_remove) if self.has_pysiaf: - preset_options = list(_available_instruments.keys()) + preset_options = list(preset_regions._instruments.keys()) + preset_options = [{'label': region, + 'instrument': instrument, + 'observatory': 'JWST', + 'icon': 'mdi-hexagon-outline'} + for region, instrument in _available_instruments.items()] else: preset_options = ['None'] - if not self.app.state.settings.get('server_is_remote', False): - preset_options.append('From File...') - self.preset = FileImportSelectPluginComponent(self, items='preset_items', selected='preset_selected', - manual_options=preset_options) + manual_options=preset_options, + server_is_remote=self.app.state.settings.get('server_is_remote', False)) # noqa # set the custom file parser for importing catalogs self.preset._file_parser = self._file_parser diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index 3779d97383..15aca75f3d 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -790,7 +790,7 @@ def __init__(self, *args, **kwargs): manual_options = [default_text] + manual_options self._manual_options = manual_options - self.items = [{"label": opt} if isinstance(opt, str) else opt for opt in manual_options] + self.items = [self._to_item(opt) for opt in manual_options] # set default values for traitlets if default_text is not None: self.selected = default_text @@ -807,6 +807,12 @@ def __init__(self, *args, **kwargs): if default_mode != 'empty' and self.selected == '': self._apply_default_selection() + @staticmethod + def _to_item(item): + if isinstance(item, dict): + return item + return {'label': item} + def __repr__(self): if hasattr(self, 'multiselect'): return f"" # noqa @@ -906,6 +912,15 @@ def remove_filter(self, *filters): self.filters = [f for f in self.filters if (f not in filters and getattr(f, '__name__', '') not in filters)] + @observe('filters') + def _update_items(self, msg={}): + all_items = [self._to_item(opt) for opt in self.manual_options] + self.items = [item for item in all_items if self._is_valid_item(item)] + + try: + self._apply_default_selection() + except: pass + @property def viewer_dicts(self): all_viewer_dicts = super().viewer_dicts @@ -1091,7 +1106,8 @@ class FileImportSelectPluginComponent(SelectPluginComponent): def __init__(self, plugin, **kwargs): self._cached_obj = {} - if "From File..." not in kwargs['manual_options']: + if (not kwargs.get('server_is_remote', False) + and "From File..." not in kwargs['manual_options']): kwargs['manual_options'] += ['From File...'] if not isinstance(plugin, HasFileImportSelect): # pragma: no cover @@ -1493,19 +1509,19 @@ def __init__(self, plugin, items, selected, viewer, self.hub.subscribe(self, AddDataMessage, handler=self._on_data_added) self.hub.subscribe(self, RemoveDataMessage, - handler=lambda _: self._update_layer_items()) + handler=lambda _: self._update_items()) self.hub.subscribe(self, SubsetCreateMessage, handler=lambda _: self._on_subset_created()) self.hub.subscribe(self, SubsetUpdateMessage, handler=lambda _: self._update_layer_items()) self.hub.subscribe(self, SubsetDeleteMessage, - handler=lambda _: self._update_layer_items()) + handler=lambda _: self._update_items()) self.sort_by = sort_by - self.app.state.add_callback('layer_icons', self._update_layer_items) + self.app.state.add_callback('layer_icons', self._update_items) self.add_observe(viewer, self._on_viewer_selected_changed) - self.add_observe(selected, self._update_layer_items) - self._update_layer_items() + self.add_observe(selected, self._update_items) + self._update_items() self.update_wcs_only_filter(only_wcs_layers) # TODO: all of these add_filter commands should be refactored to pass filters directly @@ -1632,7 +1648,7 @@ def _on_viewer_selected_changed(self, msg=None): new = [new] if new != old: self._clear_cache() - self._update_layer_items() + self._update_items() added_viewers = list(set(new) - set(old)) removed_viewers = list(set(old) - set(new)) for old_viewer in removed_viewers: @@ -1640,38 +1656,38 @@ def _on_viewer_selected_changed(self, msg=None): if old_viewer is None: continue # NOTE: color_mode callback must be conflicting with something else, so instead - # we call _update_layer_items in the PlotOptionsSyncState for color_mode - # old_viewer.state.remove_callback('color_mode', self._update_layer_items) + # we call _update_items in the PlotOptionsSyncState for color_mode + # old_viewer.state.remove_callback('color_mode', self._update_items) for layer in old_viewer.state.layers: if is_wcs_only(layer.layer): continue - layer.remove_callback('color', self._update_layer_items) - layer.remove_callback('zorder', self._update_layer_items) + layer.remove_callback('color', self._update_items) + layer.remove_callback('zorder', self._update_items) if hasattr(layer, 'cmap'): - layer.remove_callback('cmap', self._update_layer_items) + layer.remove_callback('cmap', self._update_items) if hasattr(layer, 'bitmap_visible'): - layer.remove_callback('bitmap_visible', self._update_layer_items) + layer.remove_callback('bitmap_visible', self._update_items) elif hasattr(layer, 'visible'): - layer.remove_callback('visible', self._update_layer_items) + layer.remove_callback('visible', self._update_items) for new_viewer in added_viewers: new_viewer = self._get_viewer(new_viewer) if new_viewer is None: continue # NOTE: color_mode callback must be conflicting with something else, so instead - # we call _update_layer_items in the PlotOptionsSyncState for color_mode - # new_viewer.state.add_callback('color_mode', self._update_layer_items) + # we call _update_items in the PlotOptionsSyncState for color_mode + # new_viewer.state.add_callback('color_mode', self._update_items) for layer in new_viewer.state.layers: if is_wcs_only(layer.layer): continue - layer.add_callback('color', self._update_layer_items) - layer.add_callback('zorder', self._update_layer_items) + layer.add_callback('color', self._update_items) + layer.add_callback('zorder', self._update_items) if hasattr(layer, 'cmap'): - layer.add_callback('cmap', self._update_layer_items) + layer.add_callback('cmap', self._update_items) if hasattr(layer, 'bitmap_visible'): - layer.add_callback('bitmap_visible', self._update_layer_items) + layer.add_callback('bitmap_visible', self._update_items) if hasattr(layer, 'visible'): - layer.add_callback('visible', self._update_layer_items) + layer.add_callback('visible', self._update_items) def _on_subset_created(self, msg=None): new_subset_label = self.app.data_collection.subset_groups[-1].label @@ -1679,10 +1695,10 @@ def _on_subset_created(self, msg=None): for current_viewer in viewer: for layer in self._get_viewer(current_viewer).state.layers: if layer.layer.label == new_subset_label and is_not_wcs_only(layer.layer): - layer.add_callback('color', self._update_layer_items) - layer.add_callback('visible', self._update_layer_items) + layer.add_callback('color', self._update_items) + layer.add_callback('visible', self._update_items) # TODO: Add ability to add new item to self.items instead of recompiling - self._update_layer_items({'source': 'subset_added'}) + self._update_items({'source': 'subset_added'}) def _on_data_added(self, msg=None): if msg is None or not hasattr(msg, 'data') or msg.data is None: @@ -1700,18 +1716,18 @@ def _on_data_added(self, msg=None): # _on_layers_changed whenever the color changes # TODO: find out if this conflicts with another color change event # and is causing the lag in the color picker - layer.add_callback('color', self._update_layer_items) + layer.add_callback('color', self._update_items) if hasattr(layer, 'cmap'): - layer.add_callback('cmap', self._update_layer_items) + layer.add_callback('cmap', self._update_items) if hasattr(layer, 'bitmap_visible'): - layer.add_callback('bitmap_visible', self._update_layer_items) + layer.add_callback('bitmap_visible', self._update_items) if hasattr(layer, 'visible'): - layer.add_callback('visible', self._update_layer_items) + layer.add_callback('visible', self._update_items) - self._update_layer_items({'source': 'data_added'}) + self._update_items({'source': 'data_added'}) @observe('filters', 'sort_by') - def _update_layer_items(self, msg={}): + def _update_items(self, msg={}): # NOTE: _on_layers_changed is passed without a msg object during init # TODO: if the message is a SubsetUpdateMessage, only act on those that require # an update @@ -2716,12 +2732,12 @@ def __init__(self, plugin, items, selected, multiselect=multiselect, filters=filters, default_text=default_text, manual_options=manual_options, default_mode=default_mode) - self.hub.subscribe(self, PluginTableAddedMessage, handler=self._on_tables_changed) - self.hub.subscribe(self, PluginTableModifiedMessage, handler=self._on_tables_changed) - self._on_tables_changed() + self.hub.subscribe(self, PluginTableAddedMessage, handler=self._update_items) + self.hub.subscribe(self, PluginTableModifiedMessage, handler=self._update_items) + self._update_items() @observe('filters') - def _on_tables_changed(self, *args): + def _update_items(self, *args): manual_items = [{'label': label} for label in self.manual_options] self.items = manual_items + [{'label': k} for k, v in self.plugin.app._plugin_tables.items() if self._is_valid_item(v._obj)] @@ -2829,12 +2845,12 @@ def __init__(self, plugin, items, selected, multiselect=multiselect, filters=filters, default_text=default_text, manual_options=manual_options, default_mode=default_mode) - self.hub.subscribe(self, PluginPlotAddedMessage, handler=self._on_plots_changed) - self.hub.subscribe(self, PluginPlotModifiedMessage, handler=self._on_plots_changed) - self._on_plots_changed() + self.hub.subscribe(self, PluginPlotAddedMessage, handler=self._update_items) + self.hub.subscribe(self, PluginPlotModifiedMessage, handler=self._update_items) + self._update_items() @observe('filters') - def _on_plots_changed(self, *args): + def _update_items(self, *args): manual_items = [{'label': label} for label in self.manual_options] self.items = manual_items + [{'label': k} for k, v in self.plugin.app._plugin_plots.items() if self._is_valid_item(v._obj)] @@ -3251,12 +3267,12 @@ def __init__(self, plugin, items, selected, default_text=default_text, manual_options=manual_options, default_mode=default_mode) - self.hub.subscribe(self, ViewerAddedMessage, handler=self._on_viewers_changed) - self.hub.subscribe(self, ViewerRemovedMessage, handler=self._on_viewers_changed) - self.hub.subscribe(self, ViewerRenamedMessage, handler=self._on_viewers_changed) + self.hub.subscribe(self, ViewerAddedMessage, handler=self._update_items) + self.hub.subscribe(self, ViewerRemovedMessage, handler=self._update_items) + self.hub.subscribe(self, ViewerRenamedMessage, handler=self._update_items) # initialize viewer_items from original viewers - self._on_viewers_changed() + self._update_items() @property def ids(self): @@ -3328,8 +3344,8 @@ def add_filter(self, *filters): super().add_filter(*filters) if 'reference_has_wcs' in filters: # reference data can change whenever data is added OR removed from a viewer - self.hub.subscribe(self, AddDataMessage, handler=self._on_viewers_changed) - self.hub.subscribe(self, RemoveDataMessage, handler=self._on_viewers_changed) + self.hub.subscribe(self, AddDataMessage, handler=self._update_items) + self.hub.subscribe(self, RemoveDataMessage, handler=self._update_items) def _is_valid_item(self, viewer): def is_spectrum_viewer(viewer): @@ -3350,8 +3366,8 @@ def reference_has_wcs(viewer): return super()._is_valid_item(viewer, locals()) @observe('filters') - def _on_viewers_changed(self, msg=None): - # NOTE: _on_viewers_changed is passed without a msg object during init + def _update_items(self, msg=None): + # NOTE: _update_items is passed without a msg object during init # list of dictionaries with id, ref, ref_or_id was_empty = len(self.items) == 0 manual_items = [{'label': label} for label in self.manual_options] @@ -3477,16 +3493,16 @@ def __init__(self, plugin, items, selected, # override this for how to access on-the-fly spectral extraction of a cube self._spectral_extraction_function = 'sum' # Add/Remove Data are triggered when checked/unchecked from viewers - self.hub.subscribe(self, AddDataMessage, handler=self._on_data_changed) - self.hub.subscribe(self, RemoveDataMessage, handler=self._on_data_changed) - self.hub.subscribe(self, DataCollectionAddMessage, handler=self._on_data_changed) - self.hub.subscribe(self, DataCollectionDeleteMessage, handler=self._on_data_changed) + self.hub.subscribe(self, AddDataMessage, handler=self._update_items) + self.hub.subscribe(self, RemoveDataMessage, handler=self._update_items) + self.hub.subscribe(self, DataCollectionAddMessage, handler=self._update_items) + self.hub.subscribe(self, DataCollectionDeleteMessage, handler=self._update_items) self.hub.subscribe(self, GlobalDisplayUnitChanged, handler=self._on_global_display_unit_changed) - self.app.state.add_callback('layer_icons', lambda _: self._on_data_changed()) + self.app.state.add_callback('layer_icons', lambda _: self._update_items()) # initialize items from original viewers - self._on_data_changed() + self._update_items() @property def default_data_cls(self): @@ -3639,7 +3655,7 @@ def not_child_layer(data): return self.app._get_assoc_data_parent(data.label) is None def same_mosviz_row(data): - # NOTE: requires calling _on_data_changed on a change to row + # NOTE: requires calling _update_items on a change to row # currently handled by mosviz helper _row_click_message_handler meta = getattr(data, 'meta', None) if meta is None: @@ -3656,8 +3672,8 @@ def same_mosviz_row(data): return super()._is_valid_item(data, locals()) @observe('filters') - def _on_data_changed(self, msg=None): - # NOTE: _on_data_changed is passed without a msg object during init + def _update_items(self, msg=None): + # NOTE: _update_items is passed without a msg object during init # future improvement: don't recreate the entire list when msg is passed def _dc_to_dict(data): d = {'label': data.label, @@ -4488,7 +4504,7 @@ def _on_glue_value_changed(self, value): viewer.data_menu.layer._update_layer_items() # callbacks from the viewer state also do not trigger an update to the # layer items (tabs), so we'll force those to update from here as well. - self.plugin.layer._update_layer_items() + self.plugin.layer._update_items() if self._processing_change_to_glue: return From c128a4d2655af44a6d2f1d4c42a126dea7720718 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 10:10:13 -0500 Subject: [PATCH 02/16] FileImportSelect icon support --- .../components/plugin_file_import_select.vue | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/jdaviz/components/plugin_file_import_select.vue b/jdaviz/components/plugin_file_import_select.vue index d037d025c0..5d9ca360c4 100644 --- a/jdaviz/components/plugin_file_import_select.vue +++ b/jdaviz/components/plugin_file_import_select.vue @@ -4,7 +4,9 @@ - diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 5dcee36ee6..c03a81f967 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -121,7 +121,7 @@ def __init__(self, *args, **kwargs): on_remove=self._on_overlay_remove) if self.has_pysiaf: - obs_icons = {'JWST': 'mdi-hexagon-outline', 'Roman': 'mdi-telescope'} + obs_icons = {'JWST': 'JWST', 'Roman': 'Roman'} preset_options = list(preset_regions._instruments.keys()) preset_options = [{'label': display_name, 'siaf_name': siaf_name, diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.vue b/jdaviz/configs/imviz/plugins/footprints/footprints.vue index 746bf96770..d73f59eca6 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.vue +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.vue @@ -106,7 +106,8 @@ style="padding-left: 8px; padding-right: 6px;" @click="() => {preset_only_roman = false; preset_only_jwst = !preset_only_jwst}" > - mdi-hexagon-outline + JWST + JWST @@ -120,8 +121,9 @@ style="padding-left: 8px; padding-right: 6px;" @click="() => {preset_only_jwst = false; preset_only_roman = !preset_only_roman}" > - mdi-telescope - + Roman + Roman + diff --git a/jdaviz/main_styles.vue b/jdaviz/main_styles.vue index 4512758dfc..5612f8c45b 100644 --- a/jdaviz/main_styles.vue +++ b/jdaviz/main_styles.vue @@ -320,4 +320,15 @@ span.api-hint-header { color: #C6F0FD !important; } +.telescope-badge { + font-size: 11px; + font-variant: small-caps; + border: 1px solid black; + border-radius: 2px; + background-color: gray; + color: white; + padding: 2px; + vertical-align: text-top; +} + From cc4042ffee8ffa2eae4ef54f19c61798b332ebb8 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Wed, 27 Nov 2024 15:41:18 -0500 Subject: [PATCH 06/16] use select component instead of boolean toggles * and expose to user API --- .../imviz/plugins/footprints/footprints.py | 41 +++++++++---------- .../imviz/plugins/footprints/footprints.vue | 12 +++--- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index c03a81f967..18e4f6b5aa 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -10,7 +10,7 @@ from jdaviz.core.region_translators import regions2roi from jdaviz.core.registries import tray_registry from jdaviz.core.template_mixin import (PluginTemplateMixin, ViewerSelectMixin, - EditableSelectPluginComponent, + EditableSelectPluginComponent, SelectPluginComponent, FileImportSelectPluginComponent, HasFileImportSelect) from jdaviz.core.user_api import PluginUserApi @@ -47,6 +47,8 @@ class Footprints(PluginTemplateMixin, ViewerSelectMixin, HasFileImportSelect): color of the currently selected overlay * ``fill_opacity`` opacity of the filled region of the currently selected overlay + * ``preset_obs`` (:class:`~jdaviz.core.template_mixin.SelectPluginComponent`): + selected observatories to filter ``preset`` choices. * ``preset`` (:class:`~jdaviz.core.template_mixin.SelectPluginComponent`): selected overlay preset * :meth:`import_region` @@ -85,8 +87,8 @@ class Footprints(PluginTemplateMixin, ViewerSelectMixin, HasFileImportSelect): # PRESET OVERLAYS AND OPTIONS has_pysiaf = Bool(preset_regions._has_pysiaf).tag(sync=True) - preset_only_jwst = Bool(False).tag(sync=True) - preset_only_roman = Bool(False).tag(sync=True) + preset_obs_items = List().tag(sync=True) + preset_obs_selected = Unicode().tag(sync=True) preset_items = List().tag(sync=True) preset_selected = Unicode().tag(sync=True) @@ -129,8 +131,15 @@ def __init__(self, *args, **kwargs): 'icon': obs_icons.get(observatory, None)} for observatory, instruments in preset_regions._instruments.items() for display_name, siaf_name in instruments.items()] + preset_obs_options = ['Any'] + list(preset_regions._instruments.keys()) else: preset_options = ['None'] + preset_obs_options = [] + + self.preset_obs = SelectPluginComponent(self, + items='preset_obs_items', + selected='preset_obs_selected', + manual_options=preset_obs_options) self.preset = FileImportSelectPluginComponent(self, items='preset_items', @@ -153,7 +162,7 @@ def user_api(self): return PluginUserApi(self, expose=('overlay', 'rename_overlay', 'add_overlay', 'remove_overlay', 'viewer', 'visible', 'color', 'fill_opacity', - 'preset', 'import_region', + 'preset_obs', 'preset', 'import_region', 'center_on_viewer', 'ra', 'dec', 'pa', 'v2_offset', 'v3_offset', 'overlay_regions')) @@ -498,30 +507,20 @@ def overlay_regions(self): regs = [] return regs - @observe('preset_only_jwst', 'preset_only_roman') + @observe('preset_obs_selected') def _update_preset_filters(self, event={}): - if event.get('new', True): - # toggle the others off and then recall - if event.get('name') == 'preset_only_jwst' and self.preset_only_roman: - self.preset_only_roman = False - return - elif event.get('name') == 'preset_only_roman' and self.preset_only_jwst: - self.preset_only_jwst = False - return - def only_jwst(item): return item['label'] == 'From File...' or item.get('observatory') == 'JWST' def only_roman(item): return item['label'] == 'From File...' or item.get('observatory') == 'Roman' - filters = [] - if self.preset_only_jwst: - filters.append(only_jwst) - if self.preset_only_roman: - filters.append(only_roman) - self.preset.filters = filters - self._preset_args_changed() + if self.preset_obs_selected == 'JWST': + self.preset.filters = [only_jwst] + elif self.preset_obs_selected == 'Roman': + self.preset.filters = [only_roman] + else: + self.preset.filters = [] @observe('preset_selected', 'from_file', 'ra', 'dec', 'pa', 'v2_offset', 'v3_offset') def _preset_args_changed(self, msg={}, overlay_selected=None): diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.vue b/jdaviz/configs/imviz/plugins/footprints/footprints.vue index d73f59eca6..bb1c255bd0 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.vue +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.vue @@ -101,12 +101,12 @@ :elevation=0 x-small dense - :color="preset_only_jwst ? 'turquoise' : 'transparent'" + :color="preset_obs_selected === 'JWST' ? 'turquoise' : 'transparent'" dark style="padding-left: 8px; padding-right: 6px;" - @click="() => {preset_only_roman = false; preset_only_jwst = !preset_only_jwst}" + @click="() => {if (preset_obs_selected === 'JWST') {preset_obs_selected = 'Any'} else {preset_obs_selected = 'JWST'}}" > - JWST + JWST JWST @@ -116,12 +116,12 @@ :elevation=0 x-small dense - :color="preset_only_roman ? 'turquoise' : 'transparent'" + :color="preset_obs_selected === 'Roman' ? 'turquoise' : 'transparent'" dark style="padding-left: 8px; padding-right: 6px;" - @click="() => {preset_only_jwst = false; preset_only_roman = !preset_only_roman}" + @click="() => {if (preset_obs_selected === 'Roman') {preset_obs_selected = 'Any'} else {preset_obs_selected = 'Roman'}}" > - Roman + Roman Roman From 9a56a51ef5eac85a9a0dab6ef09b39221747daf4 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 10:15:00 -0500 Subject: [PATCH 07/16] update on rebase --- jdaviz/core/template_mixin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index 15aca75f3d..87431f55a9 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -1513,7 +1513,7 @@ def __init__(self, plugin, items, selected, viewer, self.hub.subscribe(self, SubsetCreateMessage, handler=lambda _: self._on_subset_created()) self.hub.subscribe(self, SubsetUpdateMessage, - handler=lambda _: self._update_layer_items()) + handler=lambda _: self._update_items()) self.hub.subscribe(self, SubsetDeleteMessage, handler=lambda _: self._update_items()) @@ -4501,7 +4501,7 @@ def _on_glue_value_changed(self, value): # currently in subscribed states will be ignored. for viewer in self.subscribed_viewers: viewer._update_layer_icons() - viewer.data_menu.layer._update_layer_items() + viewer.data_menu.layer._update_items() # callbacks from the viewer state also do not trigger an update to the # layer items (tabs), so we'll force those to update from here as well. self.plugin.layer._update_items() From b91b7a4ff679021b08f08d6b69218de8f84abcb2 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 10:25:58 -0500 Subject: [PATCH 08/16] revert to use icon in dropdown --- jdaviz/components/plugin_file_import_select.vue | 4 ++-- jdaviz/configs/imviz/plugins/footprints/footprints.py | 2 +- .../configs/imviz/plugins/footprints/footprints.vue | 8 +++----- jdaviz/main_styles.vue | 11 ----------- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/jdaviz/components/plugin_file_import_select.vue b/jdaviz/components/plugin_file_import_select.vue index e74775761e..5d9ca360c4 100644 --- a/jdaviz/components/plugin_file_import_select.vue +++ b/jdaviz/components/plugin_file_import_select.vue @@ -20,14 +20,14 @@ {{'\'' + selected + '\''}} - {{ item.icon }} + {{ item.icon }} {{ selected }} diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 18e4f6b5aa..e850a40ed7 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -123,7 +123,7 @@ def __init__(self, *args, **kwargs): on_remove=self._on_overlay_remove) if self.has_pysiaf: - obs_icons = {'JWST': 'JWST', 'Roman': 'Roman'} + obs_icons = {'JWST': 'mdi-hexagon-outline', 'Roman': 'mdi-telescope'} preset_options = list(preset_regions._instruments.keys()) preset_options = [{'label': display_name, 'siaf_name': siaf_name, diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.vue b/jdaviz/configs/imviz/plugins/footprints/footprints.vue index bb1c255bd0..26878500fc 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.vue +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.vue @@ -106,8 +106,7 @@ style="padding-left: 8px; padding-right: 6px;" @click="() => {if (preset_obs_selected === 'JWST') {preset_obs_selected = 'Any'} else {preset_obs_selected = 'JWST'}}" > - JWST - JWST + mdi-hexagon-outline @@ -121,9 +120,8 @@ style="padding-left: 8px; padding-right: 6px;" @click="() => {if (preset_obs_selected === 'Roman') {preset_obs_selected = 'Any'} else {preset_obs_selected = 'Roman'}}" > - Roman - Roman - + mdi-telescope + diff --git a/jdaviz/main_styles.vue b/jdaviz/main_styles.vue index 5612f8c45b..4512758dfc 100644 --- a/jdaviz/main_styles.vue +++ b/jdaviz/main_styles.vue @@ -320,15 +320,4 @@ span.api-hint-header { color: #C6F0FD !important; } -.telescope-badge { - font-size: 11px; - font-variant: small-caps; - border: 1px solid black; - border-radius: 2px; - background-color: gray; - color: white; - padding: 2px; - vertical-align: text-top; -} - From d1077ca2510ab061a12fd5e41c23b7efbb74111c Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 11:14:49 -0500 Subject: [PATCH 09/16] use custom icons Co-authored-by: Jennifer Kotler --- .../components/plugin_file_import_select.vue | 6 ++- .../imviz/plugins/footprints/footprints.py | 10 +++-- .../imviz/plugins/footprints/footprints.vue | 45 +++++++------------ jdaviz/data/icons/jwst.svg | 40 +++++++++++++++++ jdaviz/data/icons/jwst_solid.svg | 11 +++++ jdaviz/data/icons/roman.svg | 31 +++++++++++++ jdaviz/data/icons/roman_solid.svg | 11 +++++ 7 files changed, 121 insertions(+), 33 deletions(-) create mode 100644 jdaviz/data/icons/jwst.svg create mode 100644 jdaviz/data/icons/jwst_solid.svg create mode 100644 jdaviz/data/icons/roman.svg create mode 100644 jdaviz/data/icons/roman_solid.svg diff --git a/jdaviz/components/plugin_file_import_select.vue b/jdaviz/components/plugin_file_import_select.vue index 5d9ca360c4..941bc476e6 100644 --- a/jdaviz/components/plugin_file_import_select.vue +++ b/jdaviz/components/plugin_file_import_select.vue @@ -20,14 +20,16 @@ {{'\'' + selected + '\''}} - {{ item.icon }} + {{ item.icon }} + {{ selected }} diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index e850a40ed7..9145f58e1d 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -1,8 +1,10 @@ from traitlets import Bool, List, Unicode, observe import numpy as np +import os import regions from glue.core.message import DataCollectionAddMessage, DataCollectionDeleteMessage +from glue_jupyter.common.toolbar_vuetify import read_icon from jdaviz.core.custom_traitlets import FloatHandleEmpty from jdaviz.core.events import LinkUpdatedMessage, ChangeRefDataMessage @@ -12,6 +14,7 @@ from jdaviz.core.template_mixin import (PluginTemplateMixin, ViewerSelectMixin, EditableSelectPluginComponent, SelectPluginComponent, FileImportSelectPluginComponent, HasFileImportSelect) +from jdaviz.core.tools import ICON_DIR from jdaviz.core.user_api import PluginUserApi from jdaviz.configs.imviz.plugins.footprints import preset_regions @@ -123,15 +126,16 @@ def __init__(self, *args, **kwargs): on_remove=self._on_overlay_remove) if self.has_pysiaf: - obs_icons = {'JWST': 'mdi-hexagon-outline', 'Roman': 'mdi-telescope'} - preset_options = list(preset_regions._instruments.keys()) + obs_icons = {'JWST': read_icon(os.path.join(ICON_DIR, 'JWST_solid.svg'), 'svg+xml'), + 'Roman': read_icon(os.path.join(ICON_DIR, 'Roman_solid.svg'), 'svg+xml')} preset_options = [{'label': display_name, 'siaf_name': siaf_name, 'observatory': observatory, 'icon': obs_icons.get(observatory, None)} for observatory, instruments in preset_regions._instruments.items() for display_name, siaf_name in instruments.items()] - preset_obs_options = ['Any'] + list(preset_regions._instruments.keys()) + preset_obs_options = ['Any'] + [{'label': obs, 'icon': obs_icons.get(obs)} + for obs in preset_regions._instruments.keys()] else: preset_options = ['None'] preset_obs_options = [] diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.vue b/jdaviz/configs/imviz/plugins/footprints/footprints.vue index 26878500fc..e6c869d625 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.vue +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.vue @@ -95,34 +95,23 @@ - - - mdi-hexagon-outline - - - - - mdi-telescope - - +
+ + + + {{ preset_obs_item.label }} + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jdaviz/data/icons/jwst_solid.svg b/jdaviz/data/icons/jwst_solid.svg new file mode 100644 index 0000000000..36d5ce20e4 --- /dev/null +++ b/jdaviz/data/icons/jwst_solid.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/jdaviz/data/icons/roman.svg b/jdaviz/data/icons/roman.svg new file mode 100644 index 0000000000..1ff0e60d69 --- /dev/null +++ b/jdaviz/data/icons/roman.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jdaviz/data/icons/roman_solid.svg b/jdaviz/data/icons/roman_solid.svg new file mode 100644 index 0000000000..d0a78297cc --- /dev/null +++ b/jdaviz/data/icons/roman_solid.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file From 64d7e4cf54a0848a9bdcb336158f5030a38ff9d3 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 11:22:46 -0500 Subject: [PATCH 10/16] codestyle --- jdaviz/configs/imviz/plugins/footprints/footprints.py | 2 +- jdaviz/core/template_mixin.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 9145f58e1d..9498538831 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -517,7 +517,7 @@ def only_jwst(item): return item['label'] == 'From File...' or item.get('observatory') == 'JWST' def only_roman(item): - return item['label'] == 'From File...' or item.get('observatory') == 'Roman' + return item['label'] == 'From File...' or item.get('observatory') == 'Roman' if self.preset_obs_selected == 'JWST': self.preset.filters = [only_jwst] diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index 87431f55a9..3d09098c62 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -919,7 +919,8 @@ def _update_items(self, msg={}): try: self._apply_default_selection() - except: pass + except ValueError: + pass @property def viewer_dicts(self): From 056271c700ff83bfcf9430054820307c22777800 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Tue, 10 Dec 2024 11:29:26 -0500 Subject: [PATCH 11/16] add to existing changelog entry --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index fb46739f5d..4f65e455cd 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,7 +16,7 @@ Imviz - Orientation plugin API now exposes create_north_up_east_left and create_north_up_east_right methods. [#3308] -- Add Roman WFI and CGI footprints to the Footprints plugin. [#3322] +- Add Roman WFI and CGI footprints to the Footprints plugin. [#3322, #3345] - Catalog Search plugin now exposes a maximum sources limit for all catalogs and resolves an edge case when loading a catalog from a file that only contains one source. [#3337] From 504f25c6310fb9ae9e6717e7144548f1b265e83d Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Fri, 13 Dec 2024 13:31:51 -0500 Subject: [PATCH 12/16] fix test failures --- .../default/plugins/data_quality/data_quality.py | 2 +- .../default/plugins/subset_tools/subset_tools.py | 14 +++++++------- .../plugins/subset_tools/subset_tools.vue | 2 +- .../imviz/plugins/footprints/footprints.py | 7 ++++++- jdaviz/configs/mosviz/helper.py | 2 +- jdaviz/core/template_mixin.py | 16 ++++++++++++++-- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/jdaviz/configs/default/plugins/data_quality/data_quality.py b/jdaviz/configs/default/plugins/data_quality/data_quality.py index e432e7b133..10ad8619f6 100644 --- a/jdaviz/configs/default/plugins/data_quality/data_quality.py +++ b/jdaviz/configs/default/plugins/data_quality/data_quality.py @@ -142,7 +142,7 @@ def update_dq_layer(self, *args): return self.dq_layer.filter_is_child_of = self.science_layer_selected - self.dq_layer._update_layer_items() + self.dq_layer._update_items() # listen for changes on the image opacity, and update the # data quality layer opacity on changes to the science layer opacity diff --git a/jdaviz/configs/default/plugins/subset_tools/subset_tools.py b/jdaviz/configs/default/plugins/subset_tools/subset_tools.py index 930eb5444f..4e9dc5290a 100644 --- a/jdaviz/configs/default/plugins/subset_tools/subset_tools.py +++ b/jdaviz/configs/default/plugins/subset_tools/subset_tools.py @@ -116,8 +116,8 @@ class SubsetTools(PluginTemplateMixin): icon_radialtocheck = Unicode(read_icon(os.path.join(ICON_DIR, 'radialtocheck.svg'), 'svg+xml')).tag(sync=True) # noqa icon_checktoradial = Unicode(read_icon(os.path.join(ICON_DIR, 'checktoradial.svg'), 'svg+xml')).tag(sync=True) # noqa - combination_items = List([]).tag(sync=True) - combination_selected = Any().tag(sync=True) + combination_mode_items = List([]).tag(sync=True) + combination_mode_selected = Any().tag(sync=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -160,8 +160,8 @@ def __init__(self, *args, **kwargs): multiselect=None) self.combination_mode = SelectPluginComponent(self, - items='combination_items', - selected='combination_selected', + items='combination_mode_items', + selected='combination_mode_selected', manual_options=COMBO_OPTIONS) @property @@ -1125,11 +1125,11 @@ def _load_regions(self, regions, combination_mode=None, max_num_regions=None, if return_bad_regions: return bad_regions - @observe('combination_selected') - def _combination_selected_updated(self, change): + @observe('combination_mode_selected') + def _combination_mode_selected_updated(self, change): self.app.session.edit_subset_mode.mode = SUBSET_MODES_PRETTY[change['new']] def _update_combination_mode(self): if self.app.session.edit_subset_mode.mode in SUBSET_TO_PRETTY.keys(): - self.combination_mode.selected = SUBSET_TO_PRETTY[ + self.combination_mode_selected = SUBSET_TO_PRETTY[ self.app.session.edit_subset_mode.mode] diff --git a/jdaviz/configs/default/plugins/subset_tools/subset_tools.vue b/jdaviz/configs/default/plugins/subset_tools/subset_tools.vue index 7055a0b45a..d6c16dd72d 100644 --- a/jdaviz/configs/default/plugins/subset_tools/subset_tools.vue +++ b/jdaviz/configs/default/plugins/subset_tools/subset_tools.vue @@ -52,7 +52,7 @@ - plg.combination_mode = '{{ combination_selected }}' + plg.combination_mode = '{{ combination_mode_selected }}' diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 9498538831..fa1f302733 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -143,7 +143,8 @@ def __init__(self, *args, **kwargs): self.preset_obs = SelectPluginComponent(self, items='preset_obs_items', selected='preset_obs_selected', - manual_options=preset_obs_options) + manual_options=preset_obs_options, + apply_filter_to_manual_options=True) self.preset = FileImportSelectPluginComponent(self, items='preset_items', @@ -513,6 +514,10 @@ def overlay_regions(self): @observe('preset_obs_selected') def _update_preset_filters(self, event={}): + if not hasattr(self, 'preset'): + # during plugin init + return + def only_jwst(item): return item['label'] == 'From File...' or item.get('observatory') == 'JWST' diff --git a/jdaviz/configs/mosviz/helper.py b/jdaviz/configs/mosviz/helper.py index 2ded2d0624..bd3cf23e1e 100644 --- a/jdaviz/configs/mosviz/helper.py +++ b/jdaviz/configs/mosviz/helper.py @@ -163,7 +163,7 @@ def _row_click_message_handler(self, msg): # update data filters in each viewer's data_menu for viewer in self.viewers.values(): if data_menu := getattr(viewer._obj, '_data_menu', None): - data_menu.dataset._on_data_changed() + data_menu.dataset._update_items() def _handle_image_zoom(self, msg): mos_data = self.app.data_collection['MOS Table'] diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index 3d09098c62..eb440ab863 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -779,6 +779,7 @@ def __init__(self, *args, **kwargs): # we'll pop from kwargs now to avoid passing to the super.__init__, but need to # wait for everything else to be set before setting to the traitlet filters = kwargs.pop('filters', [])[:] # [:] needed to force copy from kwarg default + self._apply_filters_to_manual_options = kwargs.pop('apply_filters_to_manual_options', False) super().__init__(*args, **kwargs) self._selected_previous = None @@ -914,8 +915,19 @@ def remove_filter(self, *filters): @observe('filters') def _update_items(self, msg={}): - all_items = [self._to_item(opt) for opt in self.manual_options] - self.items = [item for item in all_items if self._is_valid_item(item)] + if self._apply_filters_to_manual_options: + all_items = self.items + [self._to_item(opt) + for opt in self.manual_options + if self._to_item(opt) not in self.items] + self.items = [item for item in all_items if self._is_valid_item(item)] + else: + filtered_items = [item + for item in self.items + if self._is_valid_item(item)] + manual_options = [self._to_item(opt) + for opt in self.manual_options + if self._to_item(opt) not in filtered_items] + self.items = filtered_items + manual_options try: self._apply_default_selection() From bfdeb50eff3d9bc50ef1f031705a35aaa9ad277d Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Wed, 18 Dec 2024 14:31:29 -0500 Subject: [PATCH 13/16] handle exception in export plugin --- .../configs/default/plugins/export/export.py | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/jdaviz/configs/default/plugins/export/export.py b/jdaviz/configs/default/plugins/export/export.py index c7cbeb8b75..9360d075f6 100644 --- a/jdaviz/configs/default/plugins/export/export.py +++ b/jdaviz/configs/default/plugins/export/export.py @@ -290,7 +290,12 @@ def _is_filename_changed(self, event): def _update_subset_format_disabled(self): new_items = [] if self.subset.selected is not None: - subset = self.app.get_subsets(self.subset.selected) + try: + subset = self.app.get_subsets(self.subset.selected) + except Exception: + # subset invalid message will already be set, + # no need to set valid/invalid formats. + return if self.app._is_subset_spectral(subset[0]): good_formats = ["ecsv"] else: @@ -333,16 +338,20 @@ def _set_subset_not_supported_msg(self, msg=None): disable Export button until these are supported. """ - if self.subset.selected is not None: - subset = self.app.get_subsets(self.subset.selected) - if self.subset.selected == '': - self.subset_invalid_msg = '' - elif self.app._is_subset_spectral(subset[0]): - self.subset_invalid_msg = '' - elif len(subset) > 1: - self.subset_invalid_msg = 'Export for composite subsets not yet supported.' + if self.subset.selected not in [None, '']: + try: + subset = self.app.get_subsets(self.subset.selected) + except Exception as e: + self.subset_invalid_msg = f"Export for subset not supported: {e}" else: - self.subset_invalid_msg = '' + if self.subset.selected == '': + self.subset_invalid_msg = '' + elif self.app._is_subset_spectral(subset[0]): + self.subset_invalid_msg = '' + elif len(subset) > 1: + self.subset_invalid_msg = 'Export for composite subsets not yet supported.' + else: + self.subset_invalid_msg = '' else: # no subset selected (can be '' instead of None if previous selection made) self.subset_invalid_msg = '' From 5c4184970f30335a3590897af9709145c6178fa1 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Wed, 18 Dec 2024 14:41:16 -0500 Subject: [PATCH 14/16] codestyle --- jdaviz/configs/imviz/plugins/footprints/footprints.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index fa1f302733..316c20b8f1 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -516,7 +516,7 @@ def overlay_regions(self): def _update_preset_filters(self, event={}): if not hasattr(self, 'preset'): # during plugin init - return + return def only_jwst(item): return item['label'] == 'From File...' or item.get('observatory') == 'JWST' From f915bf5f11e94ea05e6ec357bec16873dcfc5523 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Wed, 18 Dec 2024 15:01:05 -0500 Subject: [PATCH 15/16] correct ordering of options * manual options always last * actually assign to correct select --- .../configs/imviz/plugins/footprints/footprints.py | 4 ++-- jdaviz/core/template_mixin.py | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index 316c20b8f1..bfbfc1be93 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -143,13 +143,13 @@ def __init__(self, *args, **kwargs): self.preset_obs = SelectPluginComponent(self, items='preset_obs_items', selected='preset_obs_selected', - manual_options=preset_obs_options, - apply_filter_to_manual_options=True) + manual_options=preset_obs_options) self.preset = FileImportSelectPluginComponent(self, items='preset_items', selected='preset_selected', manual_options=preset_options, + apply_filters_to_manual_options=True, server_is_remote=self.app.state.settings.get('server_is_remote', False)) # noqa # set the custom file parser for importing catalogs diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index eb440ab863..7dd3f5a364 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -915,18 +915,14 @@ def remove_filter(self, *filters): @observe('filters') def _update_items(self, msg={}): + manual_options = [self._to_item(opt) for opt in self.manual_options] + non_manual_options = [item for item in self.items if item not in manual_options] if self._apply_filters_to_manual_options: - all_items = self.items + [self._to_item(opt) - for opt in self.manual_options - if self._to_item(opt) not in self.items] - self.items = [item for item in all_items if self._is_valid_item(item)] + self.items = [item for item in non_manual_options + manual_options + if self._is_valid_item(item)] else: - filtered_items = [item - for item in self.items + filtered_items = [item for item in non_manual_options if self._is_valid_item(item)] - manual_options = [self._to_item(opt) - for opt in self.manual_options - if self._to_item(opt) not in filtered_items] self.items = filtered_items + manual_options try: From 53dcc7d8d71061eec61e695062d2790b842ff508 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 19 Dec 2024 11:36:42 -0500 Subject: [PATCH 16/16] fix case of referenced image filename --- jdaviz/configs/imviz/plugins/footprints/footprints.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/footprints/footprints.py b/jdaviz/configs/imviz/plugins/footprints/footprints.py index bfbfc1be93..4ba333b604 100644 --- a/jdaviz/configs/imviz/plugins/footprints/footprints.py +++ b/jdaviz/configs/imviz/plugins/footprints/footprints.py @@ -126,8 +126,8 @@ def __init__(self, *args, **kwargs): on_remove=self._on_overlay_remove) if self.has_pysiaf: - obs_icons = {'JWST': read_icon(os.path.join(ICON_DIR, 'JWST_solid.svg'), 'svg+xml'), - 'Roman': read_icon(os.path.join(ICON_DIR, 'Roman_solid.svg'), 'svg+xml')} + obs_icons = {'JWST': read_icon(os.path.join(ICON_DIR, 'jwst_solid.svg'), 'svg+xml'), + 'Roman': read_icon(os.path.join(ICON_DIR, 'roman_solid.svg'), 'svg+xml')} preset_options = [{'label': display_name, 'siaf_name': siaf_name, 'observatory': observatory,