-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enable coords-info and markers plugin (#22)
* enable coords-info and markers plugin * basic test coverage
- Loading branch information
Showing
8 changed files
with
258 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
from .coords_info.coords_info import * # noqa | ||
from .ephemeris.ephemeris import * # noqa | ||
from .plot_options.plot_options import * # noqa | ||
from .markers.markers import * # noqa | ||
from .plot_options.plot_options import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .coords_info import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import numpy as np | ||
|
||
from glue.core.subset_group import GroupedSubset | ||
from jdaviz.configs.imviz.plugins.coords_info import CoordsInfo | ||
from jdaviz.core.registries import tool_registry | ||
|
||
from lcviz.viewers import TimeScatterView, PhaseScatterView | ||
|
||
|
||
__all__ = ['CoordsInfo'] | ||
|
||
|
||
@tool_registry('lcviz-coords-info') | ||
class CoordsInfo(CoordsInfo): | ||
_supported_viewer_classes = (TimeScatterView, PhaseScatterView) | ||
_viewer_classes_with_marker = (TimeScatterView, PhaseScatterView) | ||
|
||
def update_display(self, viewer, x, y): | ||
self._dict = {} | ||
|
||
if not len(viewer.state.layers): | ||
return | ||
|
||
is_phase = isinstance(viewer, PhaseScatterView) | ||
# TODO: update with display_unit when supported in lcviz | ||
x_unit = '' if is_phase else str(viewer.time_unit) | ||
y_unit = str(viewer.data()[0].flux.unit) | ||
|
||
def _cursor_fallback(): | ||
self._dict['axes_x'] = x | ||
self._dict['axes_x:unit'] = x_unit | ||
self._dict['axes_y'] = y | ||
self._dict['axes_y:unit'] = y_unit | ||
|
||
self._dict['data_label'] = '' | ||
self._dict['time'] = x if not is_phase else np.nan | ||
self._dict['phase'] = x if is_phase else np.nan | ||
self._dict['flux'] = y | ||
self._dict['ephemeris'] = '' | ||
|
||
self.row2_title = '' | ||
self.row2_text = '' | ||
self.row3_title = '' | ||
self.row3_text = '' | ||
self.icon = 'mdi-cursor-default' | ||
self.marks[viewer._reference_id].visible = False | ||
|
||
self.row1a_title = 'Cursor' | ||
self.row1a_text = f'{x:10.5e}, {y:10.5e}' | ||
|
||
# show the locked marker/coords only if either no tool or the default tool is active | ||
if self.dataset.selected == 'none': | ||
_cursor_fallback() | ||
return | ||
|
||
xrange = abs(viewer.state.x_max - viewer.state.x_min) | ||
yrange = abs(viewer.state.y_max - viewer.state.y_min) | ||
|
||
# Snap to the closest data point | ||
closest_distsq = None | ||
closest_x = None | ||
closest_y = None | ||
closest_icon = None | ||
closest_lyr = None | ||
for lyr in viewer.layers: | ||
if isinstance(lyr.layer, GroupedSubset): | ||
continue | ||
if self.dataset.selected == 'auto' and not lyr.visible: | ||
continue | ||
if self.dataset.selected != 'auto' and self.dataset.selected != lyr.layer.label: | ||
continue | ||
|
||
scatter = lyr.scatter | ||
lyr_x, lyr_y = scatter.x, scatter.y | ||
# NOTE: unlike specviz which determines the closest point in x per-layer, | ||
# this determines the closest point in x/y per-layer in pixel-space | ||
# (making it easier to get the snapping point into shallow eclipses, etc) | ||
distsqs = ((lyr_x - x)/xrange)**2 + ((lyr_y - y)/yrange)**2 | ||
cur_i = np.nanargmin(distsqs) | ||
cur_x, cur_y = float(lyr_x[cur_i]), float(lyr_y[cur_i]) | ||
cur_distsq = distsqs[cur_i] | ||
|
||
if (closest_distsq is None) or (cur_distsq < closest_distsq): | ||
closest_distsq = cur_distsq | ||
closest_i = cur_i | ||
closest_x = cur_x | ||
closest_y = cur_y | ||
closest_icon = self.app.state.layer_icons.get(lyr.layer.label, '') | ||
closest_lyr = lyr | ||
self._dict['data_label'] = lyr.layer.label | ||
|
||
if closest_lyr is None: | ||
_cursor_fallback() | ||
return | ||
|
||
self.row2_title = 'Phase' if is_phase else 'Time' | ||
if is_phase: | ||
self.row2_text = f'{closest_x:0.05f}' | ||
component_labels = [comp.label for comp in closest_lyr.layer.components] | ||
time_comp = closest_lyr.layer.components[component_labels.index('World 0')] | ||
times = closest_lyr.layer.get_data(time_comp) | ||
self._dict['time'] = float(times[closest_i]) | ||
self._dict['phase'] = closest_x | ||
self._dict['ephemeris'] = viewer.reference.split(':')[1] | ||
else: | ||
self.row2_text = f'{closest_x:10.5e} {x_unit}' | ||
self._dict['time'] = closest_x | ||
self._dict['phase'] = np.nan | ||
self._dict['ephemeris'] = '' | ||
|
||
self._dict['axes_x'] = closest_x | ||
self._dict['axes_x:unit'] = x_unit | ||
self._dict['index'] = float(closest_i) | ||
|
||
self.row3_title = 'Flux' | ||
self.row3_text = f'{closest_y:10.5e} {y_unit}' | ||
self._dict['axes_y'] = closest_y | ||
self._dict['axes_y:unit'] = y_unit | ||
self._dict['flux'] = closest_y | ||
|
||
self.icon = closest_icon | ||
|
||
self.marks[viewer._reference_id].update_xy([closest_x], [closest_y]) # noqa | ||
self.marks[viewer._reference_id].visible = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .markers import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import numpy as np | ||
|
||
from jdaviz.configs.default.plugins import Markers | ||
from jdaviz.core.registries import tray_registry | ||
|
||
__all__ = ['Markers'] | ||
|
||
|
||
@tray_registry('lcviz-markers', label="Markers") | ||
class Markers(Markers): | ||
_default_table_values = {'time': np.nan, | ||
'phase': np.nan, | ||
'ephemeris': '', | ||
'flux': np.nan} | ||
|
||
def __init__(self, *args, **kwargs): | ||
kwargs['headers'] = ['time', 'phase', 'ephemeris', 'flux', 'viewer'] | ||
super().__init__(*args, **kwargs) | ||
|
||
@property | ||
def coords_info(self): | ||
return self.app.session.application._tools['lcviz-coords-info'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import numpy as np | ||
from numpy.testing import assert_allclose | ||
|
||
from jdaviz.core.marks import MarkersMark | ||
|
||
|
||
def _get_markers_from_viewer(viewer): | ||
return [m for m in viewer.figure.marks if isinstance(m, MarkersMark)][0] | ||
|
||
|
||
def _assert_dict_allclose(dict1, dict2): | ||
assert dict1.keys() == dict2.keys() | ||
for k, v in dict1.items(): | ||
if isinstance(v, float): | ||
assert_allclose(v, dict2.get(k)) | ||
elif isinstance(v, (tuple, list)): | ||
assert_allclose(np.asarray(v), np.asarray(dict2.get(k))) | ||
else: | ||
assert v == dict2.get(k) | ||
|
||
|
||
def test_plugin_markers(helper, light_curve_like_kepler_quarter): | ||
helper.load_data(light_curve_like_kepler_quarter) | ||
tv = helper.app.get_viewer(helper._default_time_viewer_reference_name) | ||
|
||
mp = helper.plugins['Markers'] | ||
label_mouseover = mp._obj.coords_info | ||
mp.open_in_tray() | ||
|
||
# test event in flux-vs-time viewer | ||
label_mouseover._viewer_mouse_event(tv, | ||
{'event': 'mousemove', | ||
'domain': {'x': 0, 'y': 0}}) | ||
|
||
assert label_mouseover.as_text() == ('Cursor 0.00000e+00, 0.00000e+00', | ||
'Time 5.45833e+00 d', | ||
'Flux 9.67587e-01') | ||
|
||
_assert_dict_allclose(label_mouseover.as_dict(), {'data_label': 'Light curve', | ||
'time': 5.4583335, | ||
'phase': np.nan, | ||
'ephemeris': '', | ||
'axes_x': 5.4583335, | ||
'axes_x:unit': 'd', | ||
'index': 262.0, | ||
'axes_y': 0.96758735, | ||
'axes_y:unit': '', | ||
'flux': 0.96758735}) | ||
|
||
mp._obj._on_viewer_key_event(tv, {'event': 'keydown', | ||
'key': 'm'}) | ||
assert len(mp.export_table()) == 1 | ||
assert len(_get_markers_from_viewer(tv).x) == 1 | ||
|
||
ephem = helper.plugins['Ephemeris'] | ||
pv = ephem.create_phase_viewer() | ||
|
||
# test event in flux-vs-phase viewer | ||
label_mouseover._viewer_mouse_event(pv, | ||
{'event': 'mousemove', | ||
'domain': {'x': 0.5, 'y': 0}}) | ||
|
||
assert label_mouseover.as_text() == ('Cursor 5.00000e-01, 0.00000e+00', | ||
'Phase 0.45833', | ||
'Flux 9.67587e-01') | ||
|
||
_assert_dict_allclose(label_mouseover.as_dict(), {'data_label': 'Light curve', | ||
'time': 5.458333374001086, | ||
'phase': 0.4583333730697632, | ||
'ephemeris': 'default', | ||
'axes_x': 0.4583333730697632, | ||
'axes_x:unit': '', | ||
'index': 262.0, | ||
'axes_y': 0.9675873517990112, | ||
'axes_y:unit': '', | ||
'flux': 0.9675873517990112}) | ||
|
||
mp._obj._on_viewer_key_event(pv, {'event': 'keydown', | ||
'key': 'm'}) | ||
assert len(mp.export_table()) == 2 | ||
assert len(_get_markers_from_viewer(tv).x) == 1 | ||
assert len(_get_markers_from_viewer(pv).x) == 1 | ||
|
||
# test event in flux-vs-phase viewer (with cursor only) | ||
label_mouseover.dataset.selected = 'none' | ||
label_mouseover._viewer_mouse_event(pv, | ||
{'event': 'mousemove', | ||
'domain': {'x': 0.6, 'y': 0}}) | ||
|
||
print(label_mouseover.as_text()) | ||
assert label_mouseover.as_text() == ('Cursor 6.00000e-01, 0.00000e+00', | ||
'', | ||
'') | ||
|
||
_assert_dict_allclose(label_mouseover.as_dict(), {'axes_x': 0.6, | ||
'axes_x:unit': '', | ||
'axes_y': 0, | ||
'axes_y:unit': '', | ||
'data_label': '', | ||
'time': np.nan, | ||
'phase': 0.6, | ||
'flux': 0, | ||
'ephemeris': ''}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters