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 initial implementation of Imviz #429

Merged
merged 24 commits into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6534768
Added imviz proof of concepts
astrofrog Feb 16, 2021
c610120
Add coordinate overlay tool
astrofrog Mar 2, 2021
1a11a8e
Simplify imviz tools, make coordinate overlay and blinking be 'always…
astrofrog Apr 2, 2021
002a3d3
Added ImViz example notebook
astrofrog Apr 2, 2021
cd95982
Fix code style issues
astrofrog Apr 2, 2021
82690d9
Fixed tests
astrofrog Apr 2, 2021
be7e22e
Fixed long line
astrofrog Apr 2, 2021
9deec9d
Enable CLI usage and add a new tool to create a new image viewer
astrofrog Apr 8, 2021
2bc9b1a
Fix code style
astrofrog Apr 8, 2021
4f7c140
Fixed bug in _viewer_item_by_id
astrofrog Apr 8, 2021
bb4d2e4
Improve error message if a viewer is not found
astrofrog Apr 8, 2021
e738659
Removed leftover debug statement
astrofrog Apr 8, 2021
8f84269
Remove hard-coded 2-panel imviz
astrofrog Apr 8, 2021
169ccbd
Add WCS auto-linking of datasets
astrofrog Apr 8, 2021
3c70835
Updated ImVizExample notebook
astrofrog Apr 8, 2021
8bf8075
Be specific about which events we need
astrofrog Apr 8, 2021
523d2f1
Branding: Use Imviz, not ImViz.
pllim Apr 8, 2021
99ea2c6
DOC: Add user-facing doc.
pllim Apr 8, 2021
87a8d99
Merge pull request #1 from pllim/pr429
astrofrog Apr 8, 2021
f6c14c7
Update deps for Imviz
pllim Apr 13, 2021
82ee520
Merge pull request #2 from pllim/pr429
astrofrog Apr 13, 2021
8eb022f
Fix bugs with mouseover coordinates and only auto-link datasets when …
astrofrog Apr 15, 2021
afc59b9
Updated notebook to use remote datasets
astrofrog Apr 15, 2021
09a1abd
Enable tabs in imviz
astrofrog Apr 15, 2021
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
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ NIRSpec), and includes viewers for 1D and 2D spectra as well as
contextual information like on-sky views of the spectrograph slit.
**Cubeviz** provides a view of spectroscopic data cubes (like those to be
produced by JWST MIRI), along with 1D spectra extracted from the cube.
**Imviz** provides visualization and quick-look analysis for 2D astronomical
images.


Installing
Expand All @@ -41,7 +43,6 @@ For details on installing and using JDAViz, see the
`Jdaviz documentation <https://jdaviz.readthedocs.io/en/latest/>`_.



License
-------

Expand Down
30 changes: 30 additions & 0 deletions docs/imviz/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.. image:: ../logos/imviz.svg
:width: 400

.. _imviz:

#####
Imviz
#####

Imviz is a tool for visualization and quick-look analysis for 2D astronomical
images. Like the rest of `jdaviz`, it is written in the Python programming
language, and therefore can be run anywhere Python is supported
(see :doc:`../installation`). Imviz is built on top of the
`Glupyter <https://glue-jupyter.readthedocs.io>`_ backend, providing a visual,
interactive interface to the analysis capabilities in that library.

Imviz allows images to be easily displayed and examined. It supports WCS
and so on. (TODO: Add content.)


Using Imviz
-----------

To run Imviz in a notebook::

from jdaviz import Imviz
imviz = Imviz()
imviz.app

(TODO: Add content.)
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Using Jdaviz
specviz/index.rst
cubeviz/index.rst
mosviz/index.rst
imviz/index.rst

Reference/API
=============
Expand Down
2 changes: 1 addition & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ or simply start a new Jupyter notebook and run the following in a cell::
app

To learn more about the various ``jdaviz`` application configurations and loading data, see the :ref:`cubeviz`,
:ref:`specviz`, or :ref:`mosviz` tools.
:ref:`specviz`, :ref:`mosviz`, or :ref:`imviz` tools.
1 change: 1 addition & 0 deletions jdaviz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
from jdaviz.configs.specviz2d import Specviz2d # noqa
from jdaviz.configs.mosviz import MosViz # noqa
from jdaviz.configs.cubeviz import CubeViz # noqa
from jdaviz.configs.imviz import Imviz # noqa
10 changes: 9 additions & 1 deletion jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,9 @@ def find_viewer_item(stack_items):
return viewer_item

if len(stack_item.get('children')) > 0:
return find_viewer_item(stack_item.get('children'))
result = find_viewer_item(stack_item.get('children'))
if result is not None:
return result

viewer_item = find_viewer_item(self.state.stack_items)

Expand Down Expand Up @@ -872,6 +874,9 @@ def vue_data_item_selected(self, event):
viewer_id, item_id, checked = event['id'], event['item_id'], event['checked']
viewer_item = self._viewer_item_by_id(viewer_id)

if viewer_item is None:
raise ValueError(f'viewer {viewer_id} not found')

if checked:
selected_items = [*viewer_item['selected_data_items'], item_id]
else:
Expand Down Expand Up @@ -1068,6 +1073,7 @@ def _on_new_viewer(self, msg):
viewer : `~glue_jupyter.bqplot.common.BqplotBaseView`
The new viewer instance.
"""

viewer = self._application_handler.new_data_viewer(
msg.cls, data=msg.data, show=False)

Expand Down Expand Up @@ -1095,6 +1101,8 @@ def _on_new_viewer(self, msg):
sender=self)
self.hub.broadcast(snackbar_message)

self.session.application.viewers.append(viewer)

return viewer

def load_configuration(self, path=None, config=None):
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
default='default',
nargs=1,
show_default=True,
type=click.Choice(['default', 'cubeviz', 'specviz', 'mosviz'],
type=click.Choice(['default', 'cubeviz', 'specviz', 'mosviz', 'imviz'],
case_sensitive=False),
help="Configuration to use on application startup")
@click.option('--browser',
Expand Down
1 change: 1 addition & 0 deletions jdaviz/configs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .specviz import * # noqa
from .default import * # noqa
from .mosviz import * # noqa
from .imviz import * # noqa
2 changes: 2 additions & 0 deletions jdaviz/configs/imviz/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .plugins import * # noqa
from .helper import Imviz # noqa
6 changes: 6 additions & 0 deletions jdaviz/configs/imviz/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from jdaviz.core.helpers import ConfigHelper


class Imviz(ConfigHelper):
"""Imviz Helper class"""
_default_configuration = 'imviz'
38 changes: 38 additions & 0 deletions jdaviz/configs/imviz/imviz.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from jdaviz import Imviz\n",
"\n",
"imviz = Imviz()\n",
"imviz.load_data('DATA_FILENAME')\n",
"imviz.app"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
24 changes: 24 additions & 0 deletions jdaviz/configs/imviz/imviz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
settings:
configuration: imviz
data:
auto_populate: true
visible:
menu_bar: false
toolbar: true
tray: true
tab_headers: true
context:
notebook:
max_height: 600px
toolbar:
- g-data-tools
- g-subset-tools
- g-image-viewer-creator
viewer_area:
- container: col
children:
- container: row
viewers:
- name: Image
plot: imviz-image-viewer
reference: viewer-1
3 changes: 3 additions & 0 deletions jdaviz/configs/imviz/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .tools import * # noqa
from .viewers import * # noqa
from .image_viewer_creator import * # noqa
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .image_viewer_creator import * # noqa
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from traitlets import List

from jdaviz.core.events import NewViewerMessage
from jdaviz.core.template_mixin import TemplateMixin
from jdaviz.core.registries import tool_registry
from jdaviz.configs.imviz.plugins.viewers import ImvizImageView
from jdaviz.utils import load_template

__all__ = ['ImageViewerCreator']


@tool_registry('g-image-viewer-creator')
class ImageViewerCreator(TemplateMixin):

template = load_template("image_viewer_creator.vue", __file__).tag(sync=True)
viewer_types = List([]).tag(sync=True)

def vue_create_image_viewer(self, *args, **kwargs):

new_viewer_message = NewViewerMessage(
ImvizImageView, data=None, sender=self)

self.hub.broadcast(new_viewer_message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<v-btn icon tile @click="create_image_viewer()">
<v-icon>mdi-image-plus</v-icon>
</v-btn>
</template>
70 changes: 70 additions & 0 deletions jdaviz/configs/imviz/plugins/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from echo import delay_callback
from glue.config import viewer_tool
from glue_jupyter.bqplot.common.tools import InteractCheckableTool
from glue.plugins.wcs_autolinking.wcs_autolinking import wcs_autolink, WCSLink

__all__ = []


@viewer_tool
class BqplotMatchWCS(InteractCheckableTool):

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'

def __init__(self, viewer, **kwargs):

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

def activate(self):

self.viewer.add_event_callback(self.on_mouse_or_key_event, events=['click'])

# For now clickling 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.

# Find all possible WCS links in the data collection
wcs_links = wcs_autolink(self.viewer.session.data_collection)

# Add only those links that don't already exist
for link in wcs_links:
exists = False
for existing_link in self.viewer.session.data_collection.external_links:
if isinstance(existing_link, WCSLink):
if (link.data1 is existing_link.data1
and link.data2 is existing_link.data2):
exists = True
if not exists:
self.viewer.session.data_collection.add_link(link)

# Set the reference data in other viewers to be the same as the current viewer.
# If adding the data to the viewer, make sure it is not actually shown since the
# user didn't request it.
for viewer in self.viewer.session.application.viewers:
if viewer is not self.viewer:
if self.viewer.state.reference_data not in viewer.state.layers_data:
viewer.add_data(self.viewer.state.reference_data)
for layer in viewer.state.layers:
if layer.layer is self.viewer.state.reference_data:
layer.visible = False
break
viewer.state.reference_data = self.viewer.state.reference_data

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:
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
Loading