Skip to content

Commit

Permalink
refactor mouseover coords info display
Browse files Browse the repository at this point in the history
* refactored to bring mouseover logic into the plugin itself
* traitlets for information are now based on their position in the UI rather than their meaning for imviz (which was then "stretched" to apply to other viewers)
  • Loading branch information
kecnry committed Jan 24, 2023
1 parent 8f8106b commit 39ad22d
Show file tree
Hide file tree
Showing 18 changed files with 684 additions and 816 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, tmpdir):
assert mm.results_label_overwrite is True

# Make sure coordinate display works
flux_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
label_mouseover._viewer_mouse_event(flux_viewer, {'event': 'mousemove',
'domain': {'x': 0, 'y': 0}})
assert flux_viewer.state.slices == (0, 0, 1)
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+8.00000e+00 Jy' # Slice 0 has 8 pixels, this is Slice 1 # noqa
assert flux_viewer.label_mouseover.world_ra_deg == '204.9997755346'
assert flux_viewer.label_mouseover.world_dec_deg == '27.0000999998'
# Slice 0 has 8 pixels, this is Slice 1
assert label_mouseover.as_text() == ("Pixel x=00.0 y=00.0 Value +8.00000e+00 Jy",
"World 13h39m59.9461s +27d00m00.3600s (ICRS)",
"204.9997755346 27.0000999998 (deg)") # noqa

# Make sure adding it to viewer does not crash.
cubeviz_helper.app.add_data_to_viewer(
Expand All @@ -62,11 +64,12 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, tmpdir):
assert dc[1].coords is None

# Make sure coordinate display now show moment map info (no WCS)
flux_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+8.00000e+00 Jy' # Slice 0 has 8 pixels, this is Slice 1 # noqa
assert flux_viewer.label_mouseover.world_ra_deg == '204.9997755346'
assert flux_viewer.label_mouseover.world_dec_deg == '27.0000999998'
label_mouseover._viewer_mouse_event(flux_viewer, {'event': 'mousemove',
'domain': {'x': 0, 'y': 0}})
# Slice 0 has 8 pixels, this is Slice 1 # noqa
assert label_mouseover.as_text() == ("Pixel x=00.0 y=00.0 Value +8.00000e+00 Jy",
"World 13h39m59.9461s +27d00m00.3600s (ICRS)",
"204.9997755346 27.0000999998 (deg)") # noqa

assert mm.filename == 'moment0_test_FLUX.fits' # Auto-populated on calculate.
mm.filename = str(tmpdir.join(mm.filename)) # But we want it in tmpdir for testing.
Expand Down Expand Up @@ -96,10 +99,9 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, tmpdir):
assert dc.external_links[3].cids2[0] == dc[-1].pixel_component_ids[0]

# Coordinate display should be unaffected.
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+8.00000e+00 Jy' # Slice 0 has 8 pixels, this is Slice 1 # noqa
assert flux_viewer.label_mouseover.world_ra_deg == '204.9997755346'
assert flux_viewer.label_mouseover.world_dec_deg == '27.0000999998'
assert label_mouseover.as_text() == ("Pixel x=00.0 y=00.0 Value +8.00000e+00 Jy",
"World 13h39m59.9461s +27d00m00.3600s (ICRS)",
"204.9997755346 27.0000999998 (deg)") # noqa


@pytest.mark.filterwarnings('ignore:No observer defined on WCS')
Expand Down
58 changes: 33 additions & 25 deletions jdaviz/configs/cubeviz/plugins/tests/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,19 @@ def test_fits_image_hdu_with_microns(image_cube_hdu_obj_microns, cubeviz_helper)
assert cubeviz_helper.app.data_collection[i].meta[PRIHDR_KEY]['BITPIX'] == 8

flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer')
flux_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+1.00000e+00 1e-17 erg / (Angstrom cm2 s)'
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
label_mouseover._viewer_mouse_event(flux_viewer,
{'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert label_mouseover.as_text() == ('Pixel x=00.0 y=00.0 Value +1.00000e+00 1e-17 erg / (Angstrom cm2 s)', # noqa
'World 13h41m45.5759s +27d00m12.3044s (ICRS)',
'205.4398995981 27.0034178810 (deg)') # noqa

unc_viewer = cubeviz_helper.app.get_viewer('uncert-viewer')
unc_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert unc_viewer.label_mouseover.pixel == 'x=-1.0 y=00.0'
assert unc_viewer.label_mouseover.value == '' # Out of bounds
label_mouseover._viewer_mouse_event(unc_viewer,
{'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert label_mouseover.as_text() == ('Pixel x=-1.0 y=00.0',
'World 13h41m45.5759s +27d00m12.3044s (ICRS)',
'205.4398995981 27.0034178810 (deg)') # noqa


def test_spectrum1d_with_fake_fixed_units(spectrum1d, cubeviz_helper):
Expand Down Expand Up @@ -100,18 +105,19 @@ def test_fits_image_hdu_parse_from_file(tmpdir, image_cube_hdu_obj, cubeviz_help
assert cubeviz_helper.app.data_collection[i].meta[PRIHDR_KEY]['BITPIX'] == 8

flux_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_flux_viewer_reference_name)
flux_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+1.00000e+00 1e-17 erg / (Angstrom cm2 s)'
assert flux_viewer.label_mouseover.world_ra_deg == '205.4433848390'
assert flux_viewer.label_mouseover.world_dec_deg == '26.9996149270'
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
label_mouseover._viewer_mouse_event(flux_viewer,
{'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert label_mouseover.as_text() == ('Pixel x=00.0 y=00.0 Value +1.00000e+00 1e-17 erg / (Angstrom cm2 s)', # noqa
'World 13h41m46.4124s +26d59m58.6137s (ICRS)',
'205.4433848390 26.9996149270 (deg)') # noqa

unc_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_uncert_viewer_reference_name)
unc_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert unc_viewer.label_mouseover.pixel == 'x=-1.0 y=00.0'
assert unc_viewer.label_mouseover.value == '' # Out of bounds
assert unc_viewer.label_mouseover.world_ra_deg == '205.4441642302'
assert unc_viewer.label_mouseover.world_dec_deg == '26.9996148973'
label_mouseover._viewer_mouse_event(unc_viewer,
{'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert label_mouseover.as_text() == ('Pixel x=-1.0 y=00.0',
'World 13h41m46.5994s +26d59m58.6136s (ICRS)',
'205.4441642302 26.9996148973 (deg)') # noqa


@pytest.mark.filterwarnings('ignore')
Expand All @@ -128,17 +134,19 @@ def test_spectrum3d_parse(image_cube_hdu_obj, cubeviz_helper):

# Same as flux viewer data in test_fits_image_hdu_parse_from_file
flux_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_flux_viewer_reference_name)
flux_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert flux_viewer.label_mouseover.pixel == 'x=00.0 y=00.0'
assert flux_viewer.label_mouseover.value == '+1.00000e+00 1e-17 erg / (Angstrom cm2 s)'
assert flux_viewer.label_mouseover.world_ra_deg == '205.4433848390'
assert flux_viewer.label_mouseover.world_dec_deg == '26.9996149270'
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
label_mouseover._viewer_mouse_event(flux_viewer,
{'event': 'mousemove', 'domain': {'x': 0, 'y': 0}})
assert label_mouseover.as_text() == ('Pixel x=00.0 y=00.0 Value +1.00000e+00 1e-17 erg / (Angstrom cm2 s)', # noqa
'World 13h41m46.4124s +26d59m58.6137s (ICRS)',
'205.4433848390 26.9996149270 (deg)') # noqa

# These viewers have no data.

unc_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_uncert_viewer_reference_name)
unc_viewer.on_mouse_or_key_event({'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert unc_viewer.label_mouseover is None
label_mouseover._viewer_mouse_event(unc_viewer,
{'event': 'mousemove', 'domain': {'x': -1, 'y': 0}})
assert label_mouseover.as_text() == ('', '', '')


def test_spectrum3d_no_wcs_parse(cubeviz_helper):
Expand All @@ -163,8 +171,8 @@ def test_spectrum1d_parse(spectrum1d, cubeviz_helper):
assert cubeviz_helper.app.data_collection[0].meta['uncertainty_type'] == 'std'

# Coordinate display is only for spatial image, which is missing here.
flux_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_flux_viewer_reference_name)
assert flux_viewer.label_mouseover is None
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
assert label_mouseover.as_text() == ('', '', '')


def test_numpy_cube(cubeviz_helper):
Expand Down
23 changes: 11 additions & 12 deletions jdaviz/configs/cubeviz/plugins/tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ def test_spectrum_at_spaxel_altkey_true(cubeviz_helper, spectrum1d_cube):
assert len(spectrum_viewer.data()) == 1

# Check coordinate info panel
flux_viewer.on_mouse_or_key_event(
{'event': 'mousemove', 'domain': {'x': 1, 'y': 1}})
assert flux_viewer.label_mouseover.pixel == 'x=01.0 y=01.0'
assert flux_viewer.label_mouseover.value == '+1.30000e+01 Jy'
assert flux_viewer.label_mouseover.world_ra_deg == '204.9997755344'
assert flux_viewer.label_mouseover.world_dec_deg == '27.0001999998'
label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info']
label_mouseover._viewer_mouse_event(flux_viewer,
{'event': 'mousemove', 'domain': {'x': 1, 'y': 1}})
assert label_mouseover.as_text() == ('Pixel x=01.0 y=01.0 Value +1.30000e+01 Jy',
'World 13h39m59.9461s +27d00m00.7200s (ICRS)',
'204.9997755344 27.0001999998 (deg)')

# Click on spaxel location
flux_viewer.toolbar.active_tool.on_mouse_event(
Expand Down Expand Up @@ -83,12 +83,11 @@ def test_spectrum_at_spaxel_altkey_true(cubeviz_helper, spectrum1d_cube):
assert isinstance(reg2, RectanglePixelRegion)

# Make sure coordinate info panel did not change
flux_viewer.on_mouse_or_key_event(
{'event': 'mousemove', 'domain': {'x': 1, 'y': 1}})
assert flux_viewer.label_mouseover.pixel == 'x=01.0 y=01.0'
assert flux_viewer.label_mouseover.value == '+1.30000e+01 Jy'
assert flux_viewer.label_mouseover.world_ra_deg == '204.9997755344'
assert flux_viewer.label_mouseover.world_dec_deg == '27.0001999998'
label_mouseover._viewer_mouse_event(flux_viewer,
{'event': 'mousemove', 'domain': {'x': 1, 'y': 1}})
assert label_mouseover.as_text() == ('Pixel x=01.0 y=01.0 Value +1.30000e+01 Jy',
'World 13h39m59.9461s +27d00m00.7200s (ICRS)',
'204.9997755344 27.0001999998 (deg)')

# Make sure linked pan mode works on all image viewers
t_linkedpan = flux_viewer.toolbar.tools['jdaviz:simplepanzoommatch']
Expand Down
98 changes: 5 additions & 93 deletions jdaviz/configs/cubeviz/plugins/viewers.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import numpy as np
from glue.core import BaseData
from glue.core.subset import RoiSubsetState, RangeSubsetState
from glue_jupyter.bqplot.image import BqplotImageView

from jdaviz.core.registries import viewer_registry
from jdaviz.core.marks import SliceIndicatorMarks, ShadowSpatialSpectral
from jdaviz.configs.default.plugins.viewers import JdavizViewerMixin
from jdaviz.configs.cubeviz.helper import layer_is_cube_image_data
from jdaviz.configs.imviz.helper import data_has_valid_wcs
from jdaviz.configs.default.plugins.viewers import JdavizViewerMixin
from jdaviz.configs.specviz.plugins.viewers import SpecvizProfileView

__all__ = ['CubevizImageView', 'CubevizProfileView']
Expand Down Expand Up @@ -45,102 +43,16 @@ def __init__(self, *args, **kwargs):
self._subscribe_to_layers_update()
self.state.add_callback('reference_data', self._initial_x_axis)

self.label_mouseover = None
self.add_event_callback(self.on_mouse_or_key_event, events=['mousemove', 'mouseenter',
'mouseleave'])

def on_mouse_or_key_event(self, data):

@property
def active_image_layer(self):
# Find visible layers
visible_layers = [layer for layer in self.state.layers
if (layer.visible and layer_is_cube_image_data(layer.layer))]

if len(visible_layers) == 0:
return

if self.label_mouseover is None:
if 'g-coords-info' in self.session.application._tools:
self.label_mouseover = self.session.application._tools['g-coords-info']
else:
return

if data['event'] == 'mousemove':
# Display the current cursor coordinates (both pixel and world) as
# well as data values. For now we use the first dataset in the
# viewer for the data values.

# Extract first dataset from visible layers and use this for coordinates - the choice
# of dataset shouldn't matter if the datasets are linked correctly
active_layer = visible_layers[-1]
image = active_layer.layer
self.label_mouseover.icon = self.jdaviz_app.state.layer_icons.get(active_layer.layer.label) # noqa

# Extract data coordinates - these are pixels in the reference image
x = data['domain']['x']
y = data['domain']['y']

if x is None or y is None: # Out of bounds
self.label_mouseover.pixel = ""
self.label_mouseover.reset_coords_display()
self.label_mouseover.value = ""
return

maxsize = int(np.ceil(np.log10(np.max(image.shape[:2])))) + 3
fmt = 'x={0:0' + str(maxsize) + '.1f} y={1:0' + str(maxsize) + '.1f}'
self.label_mouseover.pixel = (fmt.format(x, y))

# TODO: This assumes data_collection[0] is the main reference
# data for this application. This section will need to be updated
# when that is no longer true.
# Hack to insert WCS for generated 2D and 3D images using FLUX cube WCS.
if 'Plugin' in image.meta:
coo_data = self.jdaviz_app.data_collection[0]
else:
coo_data = image

# Hack around various WCS propagation issues in Cubeviz.
if '_orig_wcs' in coo_data.meta:
coo = coo_data.meta['_orig_wcs'].pixel_to_world(x, y, self.state.slices[-1])[0].icrs
self.label_mouseover.set_coords(coo)
elif data_has_valid_wcs(coo_data):
try:
coo = coo_data.coords.pixel_to_world(x, y, self.state.slices[-1])[-1].icrs
except Exception:
self.label_mouseover.reset_coords_display()
else:
self.label_mouseover.set_coords(coo)
else:
self.label_mouseover.reset_coords_display()

# Extract data values at this position.
# Check if shape is [x, y, z] or [y, x] and show value accordingly.
if image.ndim == 3:
ix_shape = 0
iy_shape = 1
elif image.ndim == 2:
ix_shape = 1
iy_shape = 0
else: # pragma: no cover
raise ValueError(f'Cubeviz does not support ndim={image.ndim}')

if (-0.5 < x < image.shape[ix_shape] - 0.5 and -0.5 < y < image.shape[iy_shape] - 0.5
and hasattr(active_layer, 'attribute')):
attribute = active_layer.attribute
arr = image.get_component(attribute).data
unit = image.get_component(attribute).units
if image.ndim == 3:
value = arr[int(round(x)), int(round(y)), self.state.slices[-1]]
else: # 2
value = arr[int(round(y)), int(round(x))]
self.label_mouseover.value = f'{value:+10.5e} {unit}'
else:
self.label_mouseover.value = ''

elif data['event'] == 'mouseleave' or data['event'] == 'mouseenter':
return None

self.label_mouseover.pixel = ""
self.label_mouseover.reset_coords_display()
self.label_mouseover.value = ""
return visible_layers[-1]

def _initial_x_axis(self, *args):
# Make sure that the x_att is correct on data load
Expand Down
Loading

0 comments on commit 39ad22d

Please sign in to comment.