Skip to content

Commit

Permalink
Merge pull request #557 from astrofrog/coords-in-toolbar
Browse files Browse the repository at this point in the history
Imviz: Move coordinates overlay to toolbar
  • Loading branch information
pllim authored May 6, 2021
2 parents 9f494c3 + 507d96c commit 2dfb487
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 21 deletions.
4 changes: 4 additions & 0 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class ApplicationState(State):
'tray': True,
'tab_headers': True,
},
'dense_toolbar': True,
'context': {
'notebook': {
'max_height': '600px'
Expand Down Expand Up @@ -1195,6 +1196,8 @@ def compose_viewer_area(viewer_area_items):
'widget': "IPY_MODEL_" + tool.model_id
})

self._application_handler._tools[name] = tool

for name in config.get('tray', []):
tray = tray_registry.members.get(name)
tray_item_instance = tray.get('cls')(app=self)
Expand All @@ -1210,6 +1213,7 @@ def _reset_state(self):
""" Resets the application state """
self.state = ApplicationState()
self.state.add_callback('stack_items', self.vue_relayout)
self._application_handler._tools = {}

def get_configuration(self, path=None, section=None):
""" Returns a copy of the application configuration
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/app.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<v-app id="web-app" class="jdaviz">
<v-app-bar color="primary" dark dense flat app absolute clipped-right>
<v-app-bar color="primary" dark :dense="state.settings.dense_toolbar" flat app absolute clipped-right>
<jupyter-widget :widget="item.widget" v-for="item in state.tool_items" :key="item.name"></jupyter-widget>
<v-spacer></v-spacer>
<v-toolbar-items>
Expand Down
2 changes: 2 additions & 0 deletions jdaviz/configs/imviz/imviz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ settings:
toolbar: true
tray: true
tab_headers: true
dense_toolbar: false
context:
notebook:
max_height: 600px
toolbar:
- g-data-tools
- g-subset-tools
- g-image-viewer-creator
- g-coords-info
viewer_area:
- container: col
children:
Expand Down
1 change: 1 addition & 0 deletions jdaviz/configs/imviz/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .viewers import * # noqa
from .image_viewer_creator import * # noqa
from .parsers import * # noqa
from .coords_info import * # noqa
1 change: 1 addition & 0 deletions jdaviz/configs/imviz/plugins/coords_info/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .coords_info import * # noqa
15 changes: 15 additions & 0 deletions jdaviz/configs/imviz/plugins/coords_info/coords_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from traitlets import Unicode

from jdaviz.core.registries import tool_registry
from jdaviz.core.template_mixin import TemplateMixin
from jdaviz.utils import load_template

__all__ = ['CoordsInfo']


@tool_registry('g-coords-info')
class CoordsInfo(TemplateMixin):
template = load_template("coords_info.vue", __file__).tag(sync=True)
pixel = Unicode("").tag(sync=True)
world = Unicode("").tag(sync=True)
value = Unicode("").tag(sync=True)
6 changes: 6 additions & 0 deletions jdaviz/configs/imviz/plugins/coords_info/coords_info.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template>
<div v-if="pixel" style="white-space: nowrap;">
<b v-if="pixel">Pixel </b>{{ pixel }}&nbsp;&nbsp;<b v-if="value">Value </b>{{ value }}<br>
<b v-if="world">World </b>{{ world }}<br>
</div>
</template>
63 changes: 43 additions & 20 deletions jdaviz/configs/imviz/plugins/viewers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import numpy as np

from astropy.wcs.wcsapi import BaseHighLevelWCS

from glue.core import BaseData
from glue_jupyter.bqplot.image import BqplotImageView

from bqplot import Label

from jdaviz.core.registries import viewer_registry

__all__ = ['ImvizImageView']
Expand All @@ -21,54 +21,77 @@ def __init__(self, *args, **kwargs):

super().__init__(*args, **kwargs)

self.label_mouseover = Label(x=[0.05], y=[0.05], text=[''],
default_size=12, colors=['orange'])
self.figure.marks = self.figure.marks + [self.label_mouseover]
self.label_mouseover = None

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

self.state.show_axes = False

def on_mouse_or_key_event(self, data):

if len(self.state.layers) == 0:
# Find visible layers
visible_layers = [layer for layer in self.state.layers if layer.visible]

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
image = visible_layers[0].layer

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

overlay = f'x={x:.1f} y={y:.1f}'
maxsize = int(np.ceil(np.log10(np.max(image.shape)))) + 3

image = self.state.layers[0].layer
fmt = 'x={0:0' + str(maxsize) + '.1f} y={1:0' + str(maxsize) + '.1f}'

if isinstance(image.coords, BaseHighLevelWCS):
self.label_mouseover.pixel = (fmt.format(x, y))

if isinstance(image.coords, BaseHighLevelWCS):
# Convert these to a SkyCoord via WCS - note that for other datasets
# we aren't actually guaranteed to get a SkyCoord out, just for images
# with valid celestial WCS
try:
celestial_coordinates = image.coords.pixel_to_world(x, y).icrs.to_string('hmsdms') # noqa: E501
overlay += f' ICRS={celestial_coordinates}'
celestial_coordinates = (image.coords.pixel_to_world(x, y).icrs
.to_string('hmsdms', precision=4, pad=True))
except Exception:
overlay += ' ICRS=unknown'

# Extract data values at this position
self.label_mouseover.world = ''
else:
self.label_mouseover.world = f'{celestial_coordinates:32s} (ICRS)'
else:
self.label_mouseover.world = ''

# Extract data values at this position.
# TODO: for now we just use the first visible layer but we should think
# of how to display values when multiple datasets are present.
if x > -0.5 and y > -0.5 and x < image.shape[1] - 0.5 and y < image.shape[0] - 0.5:
value = image.get_data(image.main_components[0])[int(round(y)), int(round(x))]
overlay += f' data={value:.2g}'

self.label_mouseover.text = [overlay]
attribute = visible_layers[0].attribute
value = image.get_data(attribute)[int(round(y)), int(round(x))]
unit = image.get_component(attribute).units
self.label_mouseover.value = f'{value:+10.5e} {unit}'
else:
self.label_mouseover.value = ''

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

self.label_mouseover.text = ""
self.label_mouseover.pixel = ""
self.label_mouseover.world = ""
self.label_mouseover.value = ""

if data['event'] == 'keydown' and data['key'] == 'b':

Expand Down

0 comments on commit 2dfb487

Please sign in to comment.