diff --git a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py index b1e00c65ef..9b84929adb 100644 --- a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py +++ b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py @@ -7,8 +7,9 @@ from glue.core.message import EditSubsetMessage, SubsetUpdateMessage from glue.core.edit_subset_mode import (AndMode, AndNotMode, OrMode, ReplaceMode, XorMode) +from glue.core.exceptions import IncompatibleAttribute from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI -from glue.core.subset import RoiSubsetState, RangeSubsetState, CompositeSubsetState +from glue.core.subset import SubsetState, RoiSubsetState, RangeSubsetState, CompositeSubsetState from glue.icons import icon_path from glue_jupyter.widgets.subset_mode_vuetify import SelectionModeMenu from glue_jupyter.common.toolbar_vuetify import read_icon @@ -32,6 +33,44 @@ } +class MultiMaskSubsetState(SubsetState): + """ + A subset state that can include a different mask for different datasets. + Adopted from https://github.com/glue-viz/glue/pull/2415 + + Parameters + ---------- + masks : dict + A dictionary mapping data UUIDs to boolean arrays with the same + dimensions as the data arrays. + """ + + def __init__(self, masks=None): + super(MultiMaskSubsetState, self).__init__() + self._masks = masks + + def to_mask(self, data, view=None): + if data.uuid in self._masks: + mask = self._masks[data.uuid] + if view is not None: + mask = mask[view] + return mask + else: + raise IncompatibleAttribute() + + def copy(self): + return MultiMaskSubsetState(masks=self._masks) + + def __gluestate__(self, context): + serialized = {key: context.do(value) for key, value in self._masks.items()} + return {'masks': serialized} + + @classmethod + def __setgluestate__(cls, rec, context): + masks = {key: context.object(value) for key, value in rec['masks'].items()} + return cls(masks=masks) + + @tray_registry('g-subset-plugin', label="Subset Tools") class SubsetPlugin(PluginTemplateMixin, DatasetSelectMixin): template_file = __file__, "subset_plugin.vue" @@ -51,6 +90,7 @@ class SubsetPlugin(PluginTemplateMixin, DatasetSelectMixin): multiselect = Bool(False).tag(sync=True) is_centerable = Bool(False).tag(sync=True) can_simplify = Bool(False).tag(sync=True) + can_freeze = Bool(False).tag(sync=True) icon_replace = Unicode(read_icon(os.path.join(icon_path("glue_replace", icon_format="svg")), 'svg+xml')).tag(sync=True) # noqa icon_or = Unicode(read_icon(os.path.join(icon_path("glue_or", icon_format="svg")), 'svg+xml')).tag(sync=True) # noqa @@ -258,6 +298,16 @@ def _get_subset_definition(self, *args): self._unpack_get_subsets_for_ui() + def vue_freeze_subset(self, *args): + sgs = {sg.label: sg for sg in self.app.data_collection.subset_groups} + sg = sgs.get(self.subset_selected) + + masks = {} + for data in self.app.data_collection: + masks[data.uuid] = sg.subset_state.to_mask(data) + + sg.subset_state = MultiMaskSubsetState(masks) + def vue_simplify_subset(self, *args): if self.multiselect: self.hub.broadcast(SnackbarMessage("Cannot simplify spectral subset " diff --git a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.vue b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.vue index 14060d4135..36284ed71f 100644 --- a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.vue +++ b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.vue @@ -113,10 +113,13 @@ - - Simplify - - Update - + + Freeze + + + Simplify + + Update +