Skip to content
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

refactor mouseover coords info display #1976

Merged
merged 4 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/imviz/displayimages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ If your *reference data* has GWCS with a bounding box, any coordinates transform
outside that bounding box is less reliable. This still applies even when you are
looking at some other data that is not the reference data if they are linked by WCS
because all transformations in glue go through the reference data. Such a situation
is indicated by "(est.)" and the affected coordinates becoming gray.
is indicated by the affected coordinates becoming gray.

If your data of interest also has a GWCS with a bounding box, only
the mouseover data where it overlaps with the reference data's
Expand Down
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,11 @@ 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'
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 +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
60 changes: 35 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,21 @@ 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()[0] == 'Pixel x=-1.0 y=00.0' # Out of bounds
# FIXME: remaining lines are unvalidated,
# see https://github.com/spacetelescope/jdaviz/issues/1991
# '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 +107,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', # Out of bounds
'World 13h41m46.5994s +26d59m58.6136s (ICRS)',
'205.4441642302 26.9996148973 (deg)') # noqa


@pytest.mark.filterwarnings('ignore')
Expand All @@ -128,17 +136,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 +173,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
99 changes: 6 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,17 @@ 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):
kecnry marked this conversation as resolved.
Show resolved Hide resolved
"""Active image layer in the viewer, if available."""
# 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