From 37cd8c8554ec2851a7d9ffc9edd5b3ea736ef689 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Thu, 13 May 2021 14:35:56 +0100 Subject: [PATCH 1/3] Make the WCS match tool into a pan/zoom with WCS matching tool --- jdaviz/configs/imviz/plugins/tools.py | 59 ++++--- jdaviz/configs/imviz/plugins/viewers.py | 10 +- jdaviz/data/icons/pan_wcs.png | Bin 0 -> 8532 bytes jdaviz/data/icons/pan_wcs.svg | 211 ++++++++++++++++++++++++ 4 files changed, 254 insertions(+), 26 deletions(-) create mode 100644 jdaviz/data/icons/pan_wcs.png create mode 100644 jdaviz/data/icons/pan_wcs.svg diff --git a/jdaviz/configs/imviz/plugins/tools.py b/jdaviz/configs/imviz/plugins/tools.py index c217314481..10b8eda603 100644 --- a/jdaviz/configs/imviz/plugins/tools.py +++ b/jdaviz/configs/imviz/plugins/tools.py @@ -1,13 +1,19 @@ import time +import os + from echo import delay_callback + from glue.config import viewer_tool from glue.core import BaseData from glue_jupyter.bqplot.common.tools import Tool from glue.viewers.common.tool import CheckableTool from glue.plugins.wcs_autolinking.wcs_autolinking import wcs_autolink, WCSLink +from glue_jupyter.bqplot.common.tools import BqplotPanZoomMode __all__ = [] +ICON_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'data', 'icons') + @viewer_tool class BlinkOnce(Tool): @@ -25,22 +31,23 @@ def activate(self): @viewer_tool -class BqplotMatchWCS(CheckableTool): - - icon = 'glue_link' - tool_id = 'bqplot:matchwcs' - action_text = 'Match WCS between images' - tool_tip = 'Click on image to have the other image viewer show the same coordinates' +class BqplotMatchWCS(BqplotPanZoomMode): - def __init__(self, viewer, **kwargs): - - super().__init__(viewer, **kwargs) + icon = os.path.join(ICON_DIR, 'pan_wcs.png') + tool_id = 'bqplot:panzoomwcs' + action_text = 'Pan, matching WCS between viwers' + tool_tip = 'Pan and Zoom in this viewer to see the same regions in other viewers' def activate(self): - self.viewer.add_event_callback(self.on_mouse_or_key_event, events=['click']) + super().activate() + + self.viewer.state.add_callback('x_min', self.on_limits_change) + self.viewer.state.add_callback('x_max', self.on_limits_change) + self.viewer.state.add_callback('y_min', self.on_limits_change) + self.viewer.state.add_callback('y_max', self.on_limits_change) - # For now clickling this will automatically set up links between datasets. We + # For now clicking this will automatically set up links between datasets. We # do this when activating this tool so that this ends up being 'opt-in' only # when the user wants to match WCS. @@ -55,7 +62,6 @@ def activate(self): if (link.data1 is existing_link.data1 and link.data2 is existing_link.data2): exists = True - break if not exists: self.viewer.session.data_collection.add_link(link) @@ -72,21 +78,26 @@ def activate(self): break viewer.state.reference_data = self.viewer.state.reference_data + # Trigger a sync so the initial limits match + self.on_limits_change() + def deactivate(self): - self.viewer.remove_event_callback(self.on_mouse_or_key_event) - def on_mouse_or_key_event(self, data): - if data['event'] == 'click': - x = data['domain']['x'] - y = data['domain']['y'] - dx = self.viewer.state.x_max - self.viewer.state.x_min - dy = self.viewer.state.y_max - self.viewer.state.y_min - for viewer in self.viewer.session.application.viewers: + self.viewer.state.remove_callback('x_min', self.on_limits_change) + self.viewer.state.remove_callback('x_max', self.on_limits_change) + self.viewer.state.remove_callback('y_min', self.on_limits_change) + self.viewer.state.remove_callback('y_max', self.on_limits_change) + + super().deactivate() + + def on_limits_change(self, *args): + for viewer in self.viewer.session.application.viewers: + if viewer is not self.viewer: with delay_callback(viewer.state, 'x_min', 'x_max', 'y_min', 'y_max'): - viewer.state.x_min = x - dx / 2 - viewer.state.x_max = x + dx / 2 - viewer.state.y_min = y - dy / 2 - viewer.state.y_max = y + dy / 2 + viewer.state.x_min = self.viewer.state.x_min + viewer.state.x_max = self.viewer.state.x_max + viewer.state.y_min = self.viewer.state.y_min + viewer.state.y_max = self.viewer.state.y_max @viewer_tool diff --git a/jdaviz/configs/imviz/plugins/viewers.py b/jdaviz/configs/imviz/plugins/viewers.py index bc981ff8f5..588e30d011 100644 --- a/jdaviz/configs/imviz/plugins/viewers.py +++ b/jdaviz/configs/imviz/plugins/viewers.py @@ -14,8 +14,14 @@ @viewer_registry("imviz-image-viewer", label="Image 2D (Imviz)") class ImvizImageView(BqplotImageView): - tools = ['bqplot:panzoom', 'bqplot:contrastbias', 'bqplot:blinkonce', 'bqplot:rectangle', - 'bqplot:circle', 'bqplot:matchwcs'] + # Whether to inherit tools from glue-jupyter automatically. Set this to + # False to have full control here over which tools are shown in case new + # ones are added in glue-jupyter in future that we don't want here. + inherit_tools = False + + tools = ['bqplot:home', 'bqplot:panzoom', 'bqplot:panzoomwcs', + 'bqplot:contrastbias', 'bqplot:blinkonce', + 'bqplot:rectangle', 'bqplot:circle'] default_class = None def __init__(self, *args, **kwargs): diff --git a/jdaviz/data/icons/pan_wcs.png b/jdaviz/data/icons/pan_wcs.png new file mode 100644 index 0000000000000000000000000000000000000000..ad10b9c1caf4cee0d04a23b031a1704523a5cbc9 GIT binary patch literal 8532 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 O0000 + + +image/svg+xml \ No newline at end of file From b63be85bd92b613d662f0c508cfd1b173a6214a7 Mon Sep 17 00:00:00 2001 From: Pey Lian Lim <2090236+pllim@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:28:46 -0400 Subject: [PATCH 2/3] It's all about that rebase --- jdaviz/configs/imviz/plugins/tools.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jdaviz/configs/imviz/plugins/tools.py b/jdaviz/configs/imviz/plugins/tools.py index 10b8eda603..39dfc2af01 100644 --- a/jdaviz/configs/imviz/plugins/tools.py +++ b/jdaviz/configs/imviz/plugins/tools.py @@ -23,9 +23,6 @@ class BlinkOnce(Tool): tool_tip = ('Click on this button to display the next image, ' 'or you can also press the "b" key anytime') - def __init__(self, viewer, **kwargs): - super().__init__(viewer, **kwargs) - def activate(self): self.viewer.blink_once() @@ -62,6 +59,7 @@ def activate(self): if (link.data1 is existing_link.data1 and link.data2 is existing_link.data2): exists = True + break if not exists: self.viewer.session.data_collection.add_link(link) From 77870927a8435ede79014598f2a9b7cb5373b630 Mon Sep 17 00:00:00 2001 From: Pey Lian Lim <2090236+pllim@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:36:22 -0400 Subject: [PATCH 3/3] Fix example lable name --- notebooks/ImvizExample.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notebooks/ImvizExample.ipynb b/notebooks/ImvizExample.ipynb index f92088d958..2318be6f5e 100644 --- a/notebooks/ImvizExample.ipynb +++ b/notebooks/ImvizExample.ipynb @@ -207,7 +207,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = imviz.app.get_data_from_viewer('viewer-1', 'gc_2mass_j')" + "data = imviz.app.get_data_from_viewer('viewer-1', 'gc_2mass_j[PRIMARY,1]')" ] }, {