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

Data Dropdown Component #1313

Merged
merged 24 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
789f2cb
create viewer-data-select component with delete support
kecnry May 11, 2022
dcd8714
hide button entirely for mosviz (except spectrum-viewer)
kecnry May 12, 2022
cf64ca5
use snake_case instead of having to handle camelCase vs kebab-case
kecnry May 12, 2022
cdad1ca
filter data entries by shape, plugin, config, viewer
kecnry May 12, 2022
c75f322
fix indentation
kecnry May 12, 2022
92f488c
mosviz: filter data entires in spectrum-viewer by active row
kecnry May 12, 2022
a3db032
hide delete button in mosviz
kecnry May 12, 2022
ed1f9fd
changes entry
kecnry May 12, 2022
7176c41
plugins: store row where plugin output was created
kecnry May 12, 2022
77b2db0
show gaussian smooth entries in both image and spectrum-viewers
kecnry May 12, 2022
e09cb76
mosviz: per-row plugin outputs
kecnry May 13, 2022
c63baf1
data dropdowns: ability to toggle between replace and multi-select
kecnry May 13, 2022
d2cf752
simpler data-type-detection
kecnry May 13, 2022
4100fde
mosviz: support showing items from other rows
kecnry May 14, 2022
16d960f
minor styling updates
kecnry May 16, 2022
80ceb56
test coverage
kecnry May 16, 2022
53c04d5
fix dark-mode support
kecnry May 16, 2022
ec6166f
rename test data names to avoid confusion
kecnry May 17, 2022
3fb74c3
only show delete button for plugin products
kecnry May 17, 2022
f60d51d
fix test from rebase
kecnry May 17, 2022
44a9ed3
simplify WCS access from metadata
kecnry May 19, 2022
6eca4b1
fix data-filtering for NIRISS
kecnry May 20, 2022
ceacc18
fix data menu support for imviz generated viewers
kecnry May 23, 2022
95259a1
Apply suggestions from code review
kecnry May 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ New Features

- Line list plugin now supports exact-text filtering on line names. [#1298]
- Added a Subset Tools plugin for viewing information about defined subsets. [#1292]
- Data menus in the viewers are filtered to applicable entries only and support removing data from
kecnry marked this conversation as resolved.
Show resolved Hide resolved
the app. [#1313]

- Offscreen indication for spectral lines and slice indicator. [#1312]

Expand Down
113 changes: 63 additions & 50 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from glue.core.state_objects import State
from glue.core.subset import Subset, RangeSubsetState, RoiSubsetState
from glue_jupyter.app import JupyterApplication
from glue_jupyter.common.toolbar_vuetify import read_icon
from glue_jupyter.state_traitlets_helpers import GlueState
from glue_jupyter.bqplot.profile import BqplotProfileView
from ipyvuetify import VuetifyTemplate
Expand All @@ -37,6 +38,7 @@
ViewerAddedMessage, ViewerRemovedMessage)
from jdaviz.core.registries import (tool_registry, tray_registry, viewer_registry,
data_parser_registry)
from jdaviz.core.tools import ICON_DIR
from jdaviz.utils import SnackbarQueue

__all__ = ['Application']
Expand All @@ -54,57 +56,29 @@
# some glue-core versions
glue_settings.DATA_ALPHA = 1

ipyvue.register_component_from_file(None, 'j-tooltip',
os.path.join(os.path.dirname(__file__),
'components/tooltip.vue'))
custom_components = {'j-tooltip': 'components/tooltip.vue',
'j-external-link': 'components/external_link.vue',
'j-docs-link': 'components/docs_link.vue',
'j-viewer-data-select': 'components/viewer_data_select.vue',
'j-viewer-data-select-item': 'components/viewer_data_select_item.vue',
'j-tray-plugin': 'components/tray_plugin.vue',
'j-play-pause-widget': 'components/play_pause_widget.vue',
'j-plugin-section-header': 'components/plugin_section_header.vue',
'j-number-uncertainty': 'components/number_uncertainty.vue',
'plugin-dataset-select': 'components/plugin_dataset_select.vue',
'plugin-subset-select': 'components/plugin_subset_select.vue',
'plugin-viewer-select': 'components/plugin_viewer_select.vue',
'plugin-add-results': 'components/plugin_add_results.vue',
'plugin-auto-label': 'components/plugin_auto_label.vue'}

ipyvue.register_component_from_file(None, 'j-external-link',
os.path.join(os.path.dirname(__file__),
'components/external_link.vue'))

ipyvue.register_component_from_file(None, 'j-docs-link',
os.path.join(os.path.dirname(__file__),
'components/docs_link.vue'))

ipyvue.register_component_from_file(None, 'j-tray-plugin',
os.path.join(os.path.dirname(__file__),
'components/tray_plugin.vue'))

ipyvue.register_component_from_file(None, 'j-plugin-section-header',
os.path.join(os.path.dirname(__file__),
'components/plugin_section_header.vue'))

ipyvue.register_component_from_file(None, 'j-number-uncertainty',
os.path.join(os.path.dirname(__file__),
'components/number_uncertainty.vue'))

ipyvue.register_component_from_file(None, 'plugin-dataset-select',
os.path.join(os.path.dirname(__file__),
'components/plugin_dataset_select.vue'))

ipyvue.register_component_from_file(None, 'plugin-subset-select',
os.path.join(os.path.dirname(__file__),
'components/plugin_subset_select.vue'))

ipyvue.register_component_from_file(None, 'plugin-viewer-select',
os.path.join(os.path.dirname(__file__),
'components/plugin_viewer_select.vue'))

ipyvue.register_component_from_file(None, 'plugin-add-results',
os.path.join(os.path.dirname(__file__),
'components/plugin_add_results.vue'))

ipyvue.register_component_from_file(None, 'plugin-auto-label',
os.path.join(os.path.dirname(__file__),
'components/plugin_auto_label.vue'))

# Register pure vue component. This allows us to do recursive component instantiation only in the
# vue component file
ipyvue.register_component_from_file('g-viewer-tab', "container.vue", __file__)
for name, path in custom_components.items():
ipyvue.register_component_from_file(None, name,
os.path.join(os.path.dirname(__file__), path))

ipyvue.register_component_from_file(None, 'j-play-pause-widget',
os.path.join(os.path.dirname(__file__),
'components/play_pause_widget.vue'))
ipyvue.register_component_from_file('g-viewer-tab', "container.vue", __file__)


class ApplicationState(State):
Expand Down Expand Up @@ -151,6 +125,11 @@ class ApplicationState(State):
}
}, docstring="Top-level application settings.")

icons = DictCallbackProperty({
'radialtocheck': read_icon(os.path.join(ICON_DIR, 'radialtocheck.svg'), 'svg+xml'),
'checktoradial': read_icon(os.path.join(ICON_DIR, 'checktoradial.svg'), 'svg+xml')
}, docstring="Custom application icons")

data_items = ListCallbackProperty(
docstring="List of data items parsed from the Glue data collection.")

Expand Down Expand Up @@ -1124,18 +1103,26 @@ def vue_data_item_selected(self, event):
"""
viewer_id, item_id, checked = event['id'], event['item_id'], event['checked']
viewer_item = self._viewer_item_by_id(viewer_id)
replace = event.get('replace', False)

if viewer_item is None:
raise ValueError(f'viewer {viewer_id} not found')

if checked:
if replace:
selected_items = [item_id]
elif checked:
selected_items = [*viewer_item['selected_data_items'], item_id]
else:
selected_items = list(filter(
lambda id: id != item_id, viewer_item['selected_data_items']))

self._update_selected_data_items(viewer_id, selected_items)

def vue_data_item_remove(self, event):
"""
"""
kecnry marked this conversation as resolved.
Show resolved Hide resolved
self.data_collection.remove(self.data_collection[event['item_name']])
kecnry marked this conversation as resolved.
Show resolved Hide resolved

def vue_close_snackbar_message(self, event):
"""
Callback to close a message in the snackbar when the "close"
Expand Down Expand Up @@ -1225,7 +1212,7 @@ def _on_data_added(self, msg):
the new data.
"""
self._link_new_data()
data_item = self._create_data_item(msg.data.label)
data_item = self._create_data_item(msg.data)
self.state.data_items.append(data_item)

def _on_data_deleted(self, msg):
Expand All @@ -1244,11 +1231,37 @@ def _on_data_deleted(self, msg):
self.state.data_items.remove(data_item)

@staticmethod
def _create_data_item(label):
def _create_data_item(data):
ndims = len(data.shape)
wcsaxes = data.meta.get('WCSAXES', None)
if wcsaxes is None:
# then we'll need to determine type another way, we want to avoid
# this when we can though since its not as cheap
component_ids = [str(c) for c in data.component_ids()]
if data.label == 'MOS Table':
typ = 'table'
elif ndims == 1:
typ = '1d spectrum'
elif ndims == 2 and wcsaxes is not None:
if wcsaxes == 3:
typ = '2d spectrum'
elif wcsaxes == 2:
typ = 'image'
else:
typ = 'unknown'
elif ndims == 2 and wcsaxes is None:
typ = '2d spectrum' if 'Wavelength' in component_ids else 'image'
elif ndims == 3:
typ = 'cube'
else:
typ = 'unknown'
return {
'id': str(uuid.uuid4()),
'name': label,
'name': data.label,
'locked': False,
'ndims': len(data.shape),
kecnry marked this conversation as resolved.
Show resolved Hide resolved
'type': typ,
'meta': {k: v for k, v in data.meta.items() if k in ['Plugin', 'mosviz_row']},
kecnry marked this conversation as resolved.
Show resolved Hide resolved
'children': []}

@staticmethod
Expand Down
7 changes: 6 additions & 1 deletion jdaviz/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@
v-for="(stack, index) in state.stack_items"
:stack="stack"
:key="stack.viewers.map(v => v.id).join('-')"
:data-items="state.data_items"
:data_items="state.data_items"
:app_settings="state.settings"
:icons="state.icons"
@resize="relayout"
:closefn="destroy_viewer_item"
@data-item-selected="data_item_selected($event)"
@data-item-remove="data_item_remove($event)"
@call-viewer-method="call_viewer_method($event)"
></g-viewer-tab>
</gl-row>
Expand Down Expand Up @@ -134,6 +137,7 @@ export default {
secondary: "#007DA4",
accent: "#C75109",
turquoise: "#007BA1",
lightblue: "#E3F2FD", // matches highlighted row in MOS table
spinner: "#163C4C",
error: '#FF5252',
info: '#2196F3',
Expand All @@ -147,6 +151,7 @@ export default {
secondary: "#007DA4",
accent: "#C75109",
turquoise: "#007BA1",
lightblue: "#E3F2FD",
spinner: "#ACE1FF",
error: '#FF5252',
info: '#2196F3',
Expand Down
5 changes: 5 additions & 0 deletions jdaviz/components/tooltip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ const tooltips = {
'viewer-toolbar-figure-save': 'Save figure',
'viewer-toolbar-menu': 'Adjust display: contrast, bias, stretch',
'viewer-toolbar-more': 'More options...',
'viewer-data-select-enabled': 'Allow multiple entries (click to enable replace)',
'viewer-data-radio-enabled': 'Replace current entry (click to enable multi-select)',
'viewer-data-select': 'Toggle whether data entry is loaded in the viewer',
'viewer-data-radio': 'Change viewer to this data entry',
'viewer-data-delete': 'Remove data entry across entire app',

'table-prev': 'Select previous row in table',
'table-next': 'Select next row in table',
Expand Down
Loading