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

Add stretch bounds tool to plot option histogram viewer #2513

Merged
merged 10 commits into from
Oct 20, 2023
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ New Features
- Plots in plugins now include basic zoom/pan tools for Plot Options,
Imviz Line Profiles, and Imviz's aperture photometry. [#2498]

- Histogram plot in Plot Options now includes tool to set stretch vmin and vmax. [#2513]

Cubeviz
^^^^^^^

Expand Down
6 changes: 6 additions & 0 deletions jdaviz/configs/default/plugins/plot_options/plot_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from glue_jupyter.bqplot.image.state import BqplotImageLayerState
from glue_jupyter.common.toolbar_vuetify import read_icon

from jdaviz.components.toolbar_nested import NestedJupyterToolbar
from jdaviz.core.registries import tray_registry
from jdaviz.core.template_mixin import (PluginTemplateMixin, ViewerSelect, LayerSelect,
PlotOptionsSyncState, Plot,
Expand Down Expand Up @@ -403,6 +404,11 @@ def state_attr_for_line_visible(state):
state_filter=is_image)

self.stretch_histogram = Plot(self, viewer_type='histogram')
# Add the stretch bounds tool to the default Plot viewer.
self.stretch_histogram.tools_nested.append(["jdaviz:stretch_bounds"])
self.stretch_histogram.toolbar = NestedJupyterToolbar(self.stretch_histogram.viewer,
self.stretch_histogram.tools_nested,
[])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might eventually want to generalize this as a method (or have the init take options for the tools), but this is probably ok for now if this is the only case we're modifying?

rosteen marked this conversation as resolved.
Show resolved Hide resolved
# NOTE: this is a current workaround so the histogram viewer doesn't crash when replacing
# data. Note also that passing x=[0] fails on SOME machines, so we'll pass [0, 1] instead
self.stretch_histogram._add_data('ref', x=[0, 1])
Expand Down
2 changes: 2 additions & 0 deletions jdaviz/core/template_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3280,7 +3280,9 @@ def __init__(self, plugin, viewer_type='scatter', app=None, *args, **kwargs):
app = jglue()

self._app = app
self._plugin = plugin
self.viewer = app.new_data_viewer(viewer_type, show=False)
self.viewer._plugin = plugin
self._viewer_type = viewer_type
if viewer_type == 'histogram':
self._viewer_components = ('x',)
Expand Down
27 changes: 27 additions & 0 deletions jdaviz/core/tests/test_tools.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
from numpy.testing import assert_allclose


Expand Down Expand Up @@ -41,3 +42,29 @@ def test_rangezoom(specviz_helper, spectrum1d):
t.interact.selected = [14, 15]
t.on_update_zoom()
assert_allclose(_get_lims(sv), [6500, 7000, 14, 15])


def test_stretch_bounds(imviz_helper):
imviz_helper.load_data(np.ones((2, 2)))

plot_options = imviz_helper.plugins['Plot Options']._obj
print(plot_options.stretch_vmin_value)
print(plot_options.stretch_vmax_value)
rosteen marked this conversation as resolved.
Show resolved Hide resolved
stretch_tool = plot_options.stretch_histogram.toolbar.tools["jdaviz:stretch_bounds"]
plot_options.stretch_histogram.toolbar.active_tool = stretch_tool

min_msg = {'event': 'click', 'pixel': {'x': 40, 'y': 322},
'domain': {'x': 0.1, 'y': 342},
'button': 0, 'altKey': False, 'ctrlKey': False, 'metaKey': False}

max_msg = {'event': 'click', 'pixel': {'x': 40, 'y': 322},
'domain': {'x': 1.3, 'y': 342},
'button': 0, 'altKey': True, 'ctrlKey': False, 'metaKey': False}

stretch_tool.on_mouse_event(min_msg)
stretch_tool.on_mouse_event(max_msg)
kecnry marked this conversation as resolved.
Show resolved Hide resolved

assert plot_options.stretch_vmin_value == 0.1
assert plot_options.stretch_vmax_value == 1.3

plot_options.stretch_histogram.toolbar.active_tool = None
34 changes: 34 additions & 0 deletions jdaviz/core/tools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import time

import numpy as np
from echo import delay_callback
Expand Down Expand Up @@ -338,6 +339,39 @@ def is_visible(self):
return len([m for m in self.viewer.figure.marks if isinstance(m, SpectralLine)]) > 0


@viewer_tool
class StretchBounds(CheckableTool):
icon = os.path.join(ICON_DIR, 'line_select.svg')
tool_id = 'jdaviz:stretch_bounds'
action_text = 'Set Stretch VMin and VMax'
tool_tip = 'Set closest stretch bound (VMin/VMax) with click or click+drag'

def __init__(self, viewer, **kwargs):
self._time_last = 0
super().__init__(viewer, **kwargs)

def activate(self):
self.viewer.add_event_callback(self.on_mouse_event,
events=['dragmove', 'click'])

def deactivate(self):
self.viewer.remove_event_callback(self.on_mouse_event)

def on_mouse_event(self, data):
if (time.time() - self._time_last) <= 0.2:
# throttle to 200ms
return
kecnry marked this conversation as resolved.
Show resolved Hide resolved

event_x = data['domain']['x']
current_bounds = [self.viewer._plugin.stretch_vmin_value,
self.viewer._plugin.stretch_vmax_value,]
att_names = ["stretch_vmin_value", "stretch_vmax_value"]
closest_bound_ind = np.argmin([abs(current_bounds[0] - event_x),
abs(current_bounds[1] - event_x)])

setattr(self.viewer._plugin, att_names[closest_bound_ind], event_x)


class _BaseSidebarShortcut(Tool):
plugin_name = None # define in subclass
viewer_attr = 'viewer'
Expand Down
Loading