-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
162 additions
and
61 deletions.
There are no files selected for viewing
122 changes: 102 additions & 20 deletions
122
jdaviz/configs/imviz/plugins/subset_control/subset_control.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,102 @@ | ||
from jdaviz.core.registries import tray_registry | ||
from jdaviz.core.template_mixin import TemplateMixin | ||
from jdaviz.utils import load_template | ||
|
||
__all__ = ['SubsetControl'] | ||
|
||
|
||
@tray_registry('imviz-subset-control', label="Subset Control") | ||
class SubsetControl(TemplateMixin): | ||
template = load_template("subset_control.vue", __file__).tag(sync=True) | ||
|
||
# TODO: | ||
# 1. Let user select which subset to operate on. | ||
# 2. Hide angle field when it does not make sense (e.g., circle) | ||
# 3. Grab new values from user inputs | ||
# 4. Apply new values to Subset | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
from glue.core.roi import CircularROI, EllipticalROI, RectangularROI | ||
from glue.core.subset import Subset | ||
from glue.core.message import SubsetUpdateMessage, SubsetDeleteMessage | ||
from traitlets import Float, List | ||
|
||
from jdaviz.core.events import SnackbarMessage | ||
from jdaviz.core.registries import tray_registry | ||
from jdaviz.core.template_mixin import TemplateMixin | ||
from jdaviz.utils import load_template | ||
|
||
__all__ = ['SubsetControl'] | ||
|
||
|
||
@tray_registry('imviz-subset-control', label="Subset Control") | ||
class SubsetControl(TemplateMixin): | ||
template = load_template("subset_control.vue", __file__).tag(sync=True) | ||
|
||
subset_items = List([]).tag(sync=True) | ||
new_subset_angle = Float(default=0).tag(sync=True) | ||
new_subset_x = Float().tag(sync=True) | ||
new_subset_y = Float().tag(sync=True) | ||
|
||
# TODO: | ||
# 1. Let user select which subset to operate on. | ||
# 2. Hide angle field when it does not make sense (e.g., circle) | ||
# 3. Grab new values from user inputs | ||
# 4. Apply new values to Subset | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self._selected_subset_label = '' | ||
self._all_subsets = {} | ||
|
||
# NOTE: Subscribing to SubsetCreateMessage breaks Subset interactive creation. | ||
self.hub.subscribe(self, SubsetUpdateMessage, | ||
handler=lambda x: self._on_viewer_subset_changed()) | ||
self.hub.subscribe(self, SubsetDeleteMessage, | ||
handler=lambda x: self._on_viewer_subset_changed()) | ||
|
||
def get_subset_rois(self): | ||
"""Get a list of all current Subset ROI objects.""" | ||
# Even though Subset is global, still need to access it from viewer. | ||
viewer = self.app.get_viewer('viewer-1') | ||
rois = {} | ||
for layer_state in viewer.state.layers: | ||
if hasattr(layer_state, 'layer') and isinstance(layer_state.layer, Subset): | ||
rois[layer_state.layer.label] = layer_state.layer.subset_state.roi | ||
return rois | ||
|
||
def _on_viewer_subset_changed(self): | ||
"""Callback method for when a subset is updated or deleted.""" | ||
self._all_subsets = self.get_subset_rois() | ||
self.subset_items = sorted(self._all_subsets.keys()) | ||
|
||
def _has_subset_angle(self): | ||
cur_roi = self._all_subsets[self._selected_subset_label] | ||
has_angle = False | ||
if isinstance(cur_roi, (EllipticalROI, RectangularROI)): | ||
has_angle = True | ||
return has_angle | ||
|
||
# TODO: How to make v-show="has_subset_angle" work? | ||
def vue_has_subset_angle(self): | ||
return self._has_subset_angle() | ||
|
||
def vue_subset_selected(self, event): | ||
self._selected_subset_label = event | ||
cur_roi = self._all_subsets[self._selected_subset_label] | ||
|
||
# https://github.com/glue-viz/glue/issues/2207 | ||
if isinstance(cur_roi, (CircularROI, EllipticalROI)): | ||
# NOTE: vuejs complains about float32 if float is not cast explicitly. | ||
self.new_subset_x = float(cur_roi.xc) | ||
self.new_subset_y = float(cur_roi.yc) | ||
else: | ||
cur_pos = cur_roi.center() | ||
self.new_subset_x = cur_pos[0] | ||
self.new_subset_y = cur_pos[1] | ||
|
||
if self._has_subset_angle(): | ||
# TODO: Need upstream fix to access angle property. | ||
self.new_subset_angle = 42 | ||
else: | ||
# TODO: Do not need this if we can hide the field! | ||
self.new_subset_angle = 0 | ||
|
||
def vue_update_subset(self, event): | ||
# TODO: Does not work! How to actually move it? | ||
# TODO: Using echo.delay_callback breaks the call too. | ||
cur_roi = self._all_subsets[self._selected_subset_label] | ||
try: | ||
cur_roi.move_to(self.new_subset_x, self.new_subset_y) | ||
except Exception as e: | ||
self.hub.broadcast(SnackbarMessage( | ||
f"{repr(e)}", color='error', sender=self)) | ||
|
||
if self._has_subset_angle(): | ||
# TODO: Need upstream fix to access angle property. | ||
pass | ||
|
||
# TODO: Debugging only. Remove me. | ||
self.hub.broadcast(SnackbarMessage(f"{event}", color='info', sender=self)) |
101 changes: 60 additions & 41 deletions
101
jdaviz/configs/imviz/plugins/subset_control/subset_control.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,60 @@ | ||
<template> | ||
<v-card flat tile> | ||
<v-container> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_angle" | ||
label="New Angle" | ||
v-model="new_subset_angle" | ||
hint="New angle for subset." | ||
persistent-hint | ||
disabled="True" | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_x" | ||
label="New X" | ||
v-model="new_subset_x" | ||
hint="New X for subset." | ||
persistent-hint | ||
disabled="True" | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_y" | ||
label="New Y" | ||
v-model="new_subset_y" | ||
hint="New Y for subset." | ||
persistent-hint | ||
disabled="True" | ||
</v-col> | ||
</v-row> | ||
</v-container> | ||
</v-card> | ||
</template> | ||
<template><v-card flat tile> | ||
<v-card-text> | ||
<v-container> | ||
<v-row> | ||
<v-col> | ||
<v-select | ||
:items="subset_items" | ||
@change="subset_selected" | ||
label="Subset" | ||
hint="Select the Subset to be modified." | ||
persistent-hint | ||
></v-select> | ||
</v-col> | ||
</v-row> | ||
</v-container> | ||
</v-card-text> | ||
<v-divider></v-divider> | ||
|
||
<v-card-text> | ||
<v-container> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_angle" | ||
label="New Angle" | ||
v-model="new_subset_angle" | ||
v-show="has_subset_angle" | ||
hint="New angle in degrees for subset." | ||
persistent-hint | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_x" | ||
label="New X" | ||
v-model="new_subset_x" | ||
hint="New 0-indexed X for subset center." | ||
persistent-hint | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
<v-row> | ||
<v-col> | ||
<v-text-field | ||
ref="new_subset_y" | ||
label="New Y" | ||
v-model="new_subset_y" | ||
hint="New 0-indexed Y for subset center." | ||
persistent-hint | ||
></v-text-field> | ||
</v-col> | ||
</v-row> | ||
<v-row justify="end"> | ||
<v-btn color="primary" text @click="update_subset">Apply</v-btn> | ||
</v-row> | ||
</v-container> | ||
</v-card-text> | ||
</v-card></template> |