-
Notifications
You must be signed in to change notification settings - Fork 76
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 10 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 |
---|---|---|
|
@@ -3,11 +3,15 @@ | |
|
||
from glue.config import viewer_tool | ||
from glue_jupyter.bqplot.image import BqplotImageView | ||
from glue_jupyter.bqplot.image.layer_artist import BqplotImageSubsetLayerArtist | ||
from glue.viewers.common.tool import CheckableTool | ||
import numpy as np | ||
from specutils import Spectrum1D | ||
|
||
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 +87,86 @@ class SpectrumPerSpaxel(SinglePixelRegion): | |
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 the selected layer from coords_info as long as it's 3D | ||
coords_info_dataset = self.viewer.session.application._tools['g-coords-info'].dataset.selected | ||
if coords_info_dataset == 'auto': | ||
cube_data = self.viewer.active_image_layer.layer | ||
elif coords_info_dataset == 'none': | ||
cube_data = self.viewer.layers[0].layer | ||
else: | ||
for layer in self.viewer.layers: | ||
if layer.layer.label == coords_info_dataset and layer.visible: | ||
if isinstance(layer, BqplotImageSubsetLayerArtist): | ||
# cannot expose info for spatial subset layers | ||
continue | ||
cube_data = layer.layer | ||
break | ||
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. can this rely on 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. That also then might let you mouseover the uncertainty viewer but access the mouseover from the flux cube (if selected manually in the mouseover cycler) which would be super cool! 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 was just copying the logic from 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. hmmm true, I think most people don't even use the cycler though, so probably won't run into this except for advanced use-cases. Might be worth some user-testing or just see if anyone complains about confusion. |
||
else: | ||
return | ||
|
||
if cube_data.ndim != 3: | ||
cube_data = [layer.layer for layer in self.viewer.layers if layer.state.visible | ||
and layer.layer.ndim == 3] | ||
if len(cube_data) == 0: | ||
return | ||
cube_data = cube_data[0] | ||
|
||
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 |
||
# Note: change this when Spectrum1D.with_spectral_axis is fixed. | ||
if spectrum.spectral_axis.unit != self._spectrum_viewer.state.x_display_unit: | ||
new_spectral_axis = spectrum.spectral_axis.to(self._spectrum_viewer.state.x_display_unit) | ||
spectrum = Spectrum1D(spectrum.flux, new_spectral_axis) | ||
|
||
if x >= spectrum.flux.shape[0] or x < 0 or y >= spectrum.flux.shape[1] or y < 0: | ||
self._reset_spectrum_viewer_bounds() | ||
self._mark.visible = False | ||
else: | ||
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._mark.visible = True | ||
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.