-
Notifications
You must be signed in to change notification settings - Fork 74
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
View spectrum from single spaxel on hover #2647
Changes from 6 commits
07b9799
956cffb
e448c6c
5f9b843
ec03400
cb3b1ed
1d4be47
05bd078
29cd90c
5145cc4
b652e16
34d2c98
bd81c8a
2b2bd3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,12 @@ | |
from glue.config import viewer_tool | ||
from glue_jupyter.bqplot.image import BqplotImageView | ||
from glue.viewers.common.tool import CheckableTool | ||
import numpy as np | ||
|
||
from jdaviz.configs.imviz.plugins.tools import _MatchedZoomMixin | ||
from jdaviz.core.events import SliceToolStateMessage | ||
from jdaviz.core.tools import PanZoom, BoxZoom, SinglePixelRegion | ||
from jdaviz.core.marks import PluginLine | ||
|
||
__all__ = [] | ||
|
||
|
@@ -83,3 +85,59 @@ | |
tool_id = 'jdaviz:spectrumperspaxel' | ||
action_text = 'See spectrum at a single spaxel' | ||
tool_tip = 'Click on the viewer and see the spectrum at that spaxel in the spectrum viewer' | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self._spectrum_viewer = None | ||
self._previous_bounds = None | ||
self._mark = None | ||
self._data = None | ||
|
||
def _reset_spectrum_viewer_bounds(self): | ||
sv_state = self._spectrum_viewer.state | ||
sv_state.x_min = self._previous_bounds[0] | ||
sv_state.x_max = self._previous_bounds[1] | ||
sv_state.y_min = self._previous_bounds[2] | ||
sv_state.y_max = self._previous_bounds[3] | ||
|
||
def activate(self): | ||
self.viewer.add_event_callback(self.on_mouse_move, events=['mousemove', 'mouseleave']) | ||
if self._spectrum_viewer is None: | ||
self._spectrum_viewer = self.viewer.jdaviz_helper.app.get_viewer('spectrum-viewer') | ||
if self._mark is None: | ||
self._mark = PluginLine(self._spectrum_viewer, visible=False) | ||
self._spectrum_viewer.figure.marks = self._spectrum_viewer.figure.marks + [self._mark,] | ||
# Store these so we can revert to previous user-set zoom after preview view | ||
sv_state = self._spectrum_viewer.state | ||
self._previous_bounds = [sv_state.x_min, sv_state.x_max, sv_state.y_min, sv_state.y_max] | ||
super().activate() | ||
|
||
def deactivate(self): | ||
self.viewer.remove_event_callback(self.on_mouse_move) | ||
self._reset_spectrum_viewer_bounds() | ||
super().deactivate() | ||
|
||
def on_mouse_move(self, data): | ||
if data['event'] == 'mouseleave': | ||
self._mark.visible = False | ||
self._reset_spectrum_viewer_bounds() | ||
return | ||
|
||
x = int(np.round(data['domain']['x'])) | ||
y = int(np.round(data['domain']['y'])) | ||
|
||
# Use first visible layer for now | ||
cube_data = [layer.layer for layer in self.viewer.layers if layer.state.visible][0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this use similar logic as #2646 to ensure its pulling from the flux cube? What happens when there are no visible layers (I'm guessing a traceback... we might want to just skip that case gracefully)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed this to return on an empty result, good catch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic in 2646 might be useful, but I don't think it's worth holding this up for that to be merged. We could potentially do that if/when we change the axis handling. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, but the first visible layer now could still be a flat image, or the uncertainty or mask cubes, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a check to at least only use 3D data, avoiding a traceback if something like a collapsed image is displayed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thinking about this more... I think this should listen to the layer selection in mouseover itself, which also might fix the bug with the uncertainty cube failing to display. That or we just ALWAYS pull the flux cube, regardless of the viewer and whether it is an active layer in that viewer or not 🤷 |
||
spectrum = cube_data.get_object(statistic=None) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is it worth caching this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about getting this on activation but was worried about data changing while the tool is active, and since it seems performant I didn't think it was worth the overhead of adding a hub listener or something along those lines. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this might not be performant on large cubes (or anything where |
||
|
||
if x >= spectrum.flux.shape[0] or x < 0 or y >= spectrum.flux.shape[1] or y < 0: | ||
self._mark.visible = False | ||
kecnry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
self._mark.visible = True | ||
kecnry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
y_values = spectrum.flux[x, y, :] | ||
if np.all(np.isnan(y_values)): | ||
self._mark.visible = False | ||
return | ||
self._mark.update_xy(spectrum.spectral_axis.value, y_values) | ||
self._spectrum_viewer.state.y_max = np.nanmax(y_values.value) * 1.2 | ||
self._spectrum_viewer.state.y_min = np.nanmin(y_values.value) * 0.8 | ||
kecnry marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we avoid hardcoding
'spectrum-viewer'
here by using the helper attributes?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still think this might be worth doing to avoid future headache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, grabs the first profile viewer now.