Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

footprints: filter by observatory #3345

Merged
merged 16 commits into from
Dec 20, 2024
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
29 changes: 21 additions & 8 deletions jdaviz/components/plugin_file_import_select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,36 @@
<v-select
:menu-props="{ left: true }"
attach
:items="items.map(i => i.label)"
:items="items"
item-text="label"
item-value="label"
v-model="selected"
@change="$emit('update:selected', $event)"
:label="api_hints_enabled && api_hint ? api_hint : label"
:class="api_hints_enabled && api_hint ? 'api-hint' : null"
:hint="hint"
persistent-hint
>
<template v-slot:selection="{ item }">
<span :class="api_hints_enabled ? 'api-hint' : null">
{{ api_hints_enabled ?
'\'' + item + '\''
:
item
}}
<template v-slot:selection="{ item, index }">
<div class="single-line" style="width: 100%">
<span v-if="api_hints_enabled" class="api-hint" :style="index > 0 ? 'display: none' : null">
{{'\'' + selected + '\''}}
</span>
<span v-else>
<v-icon v-if="item.icon && item.icon.length < 50" small>{{ item.icon }}</v-icon>
<img v-else-if="item.icon" :src="item.icon" width="16" class="invert-if-dark" style="opacity: 1.0; margin-bottom: -2px"/>
{{ selected }}
</span>
</div>
</template>
<template v-slot:item="{ item }">
<span style="margin-top: 8px; margin-bottom: 0px">
<v-icon v-if="item.icon && item.icon.length < 50" small>{{ item.icon }}</v-icon>
<img v-else-if="item.icon" :src="item.icon" width="16" class="invert-if-dark" style="opacity: 1.0; margin-bottom: -2px"/>
{{ item.label }}
</span>
</template>

</v-select>
<v-chip v-if="selected === 'From File...'"
close
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/configs/default/plugins/data_menu/data_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 19 additions & 10 deletions jdaviz/configs/default/plugins/export/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines -293 to +298
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is needed here because adding support for filtering the select dropdowns meant that this line was getting triggered and raising an exception. Without this PR, this traceback could still be triggered by going to the export plugin on an invalid subset (e.g., AND logic but not overlapping), but now it was being triggered in the test when importing the subset instead of when accessing it.

if self.app._is_subset_spectral(subset[0]):
good_formats = ["ecsv"]
else:
Expand Down Expand Up @@ -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 = ''

Expand Down
14 changes: 7 additions & 7 deletions jdaviz/configs/default/plugins/subset_tools/subset_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

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

Expand Down
63 changes: 48 additions & 15 deletions jdaviz/configs/imviz/plugins/footprints/footprints.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
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
from jdaviz.core.marks import FootprintOverlay
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.tools import ICON_DIR
from jdaviz.core.user_api import PluginUserApi

from jdaviz.configs.imviz.plugins.footprints import preset_regions
Expand All @@ -20,13 +23,6 @@
__all__ = ['Footprints']


_available_instruments = {
display_name: {'label': display_name, 'siaf_name': siaf_name, 'observatory': observatory}
for observatory, instruments in preset_regions._instruments.items()
for display_name, siaf_name in instruments.items()
}


@tray_registry('imviz-footprints', label="Footprints")
class Footprints(PluginTemplateMixin, ViewerSelectMixin, HasFileImportSelect):
"""
Expand Down Expand Up @@ -54,6 +50,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`
Expand Down Expand Up @@ -92,6 +90,8 @@ class Footprints(PluginTemplateMixin, ViewerSelectMixin, HasFileImportSelect):

# PRESET OVERLAYS AND OPTIONS
has_pysiaf = Bool(preset_regions._has_pysiaf).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)

Expand Down Expand Up @@ -126,17 +126,31 @@ def __init__(self, *args, **kwargs):
on_remove=self._on_overlay_remove)

if self.has_pysiaf:
preset_options = list(_available_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'] + [{'label': obs, 'icon': obs_icons.get(obs)}
for obs in preset_regions._instruments.keys()]
else:
preset_options = ['None']
preset_obs_options = []

if not self.app.state.settings.get('server_is_remote', False):
preset_options.append('From File...')
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',
selected='preset_selected',
manual_options=preset_options)
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
self.preset._file_parser = self._file_parser
Expand All @@ -153,7 +167,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'))
Expand Down Expand Up @@ -489,15 +503,34 @@ def overlay_regions(self):
regs = [regs]
overlay['regions'] = regs
regs = overlay.get('regions', [])
elif self.has_pysiaf and self.preset_selected in _available_instruments.keys():
elif self.has_pysiaf:
regs = preset_regions.instrument_footprint(
_available_instruments[self.preset_selected]['observatory'],
self.preset.selected_item['observatory'],
self.preset_selected, **callable_kwargs
)
else: # pragma: no cover
regs = []
return regs

@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'

def only_roman(item):
return item['label'] == 'From File...' or item.get('observatory') == 'Roman'

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):
if self._ignore_traitlet_change:
Expand Down
20 changes: 20 additions & 0 deletions jdaviz/configs/imviz/plugins/footprints/footprints.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@
To use JWST or Roman footprints, install pysiaf and restart jdaviz.
</v-alert>

<v-row justify="end" class="row-no-outside-padding" style="margin-bottom: -6px !important">
<div v-for="preset_obs_item in preset_obs_items">
<j-tooltip v-if="preset_obs_item.label !== 'Any'" :tooltipcontent="'Show only '+preset_obs_item.label+' footprints in preset list'">
<v-btn
tile
:elevation=0
x-small
dense
:color="preset_obs_selected === preset_obs_item.label ? 'turquoise' : 'transparent'"
:dark="preset_obs_selected === preset_obs_item.label"
style="padding-left: 8px; padding-right: 6px;"
@click="() => {if (preset_obs_selected === preset_obs_item.label) {preset_obs_selected = 'Any'} else {preset_obs_selected = preset_obs_item.label}}"
>
<img :src="preset_obs_item.icon" width="16" class="invert-if-dark" style="margin-right: 2px"/>
{{ preset_obs_item.label }}
</v-btn>
</j-tooltip>
</div>
</v-row>

<plugin-file-import-select
:items="preset_items"
:selected.sync="preset_selected"
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/configs/mosviz/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
Loading
Loading