In [ ]:
from __future__ import print_function, division, absolute_import
David Shupe, Caltech/IPAC
Scientist, ZTF and LSST Science User Interface
The astropy.visualization module provides a framework for transforming values in images (and more generally any arrays), typically for the purpose of visualization. Two main types of transformations are provided:
Normalization to the [0:1] range using lower and upper limits where $x$ represents the values in the original image:
$y = {{x - v_{min}} \over {v_{max} - v_{min}}}$
Stretching of values in the [0:1] range to the [0:1] range using a linear or non-linear function:
$z=f(y)$
In [ ]:
import astropy.io.fits as fits
import matplotlib.pylab as plt
from astropy.visualization import (MinMaxInterval, LogStretch,
ImageNormalize)
Here we use only the numpy array of the data.
In [ ]:
image = fits.getdata('data/w5.fits')
Astropy visualization functions for scaling and stretching
In [ ]:
# Scale to image minimum and maximum, stretch with log function
norm = ImageNormalize(image, interval=MinMaxInterval(),
stretch=LogStretch())
Note that astronomical images in FITS use origin="lower" which is not the matplotlib default
In [ ]:
%matplotlib inline
fig = plt.figure(figsize=(8,8))
plt.imshow(image, norm=norm, origin="lower", cmap='Greys_r');
In [ ]:
%matplotlib inline
from astropy.visualization import (ManualInterval, LogStretch,
ImageNormalize)
norm = ImageNormalize(image, interval=ManualInterval(vmin=370.0, vmax=1000.0),
stretch=LogStretch())
In [ ]:
%matplotlib inline
fig = plt.figure(figsize=(8,8))
#plt.imshow(image, norm=norm, origin="lower", cmap='Greys_r')
plt.contour(image, [550, 750, 950], origin='lower',
colors=['grey', 'green', 'blue']);
See this contour demo from the matplotlib documentation for more to do with contours
Prior to this point, we have visualized numpy arrays
In [ ]:
from astropy.wcs import WCS
hdu = fits.open('data/w5.fits')[0]
wcs = WCS(hdu.header)
In the case the World Coordinate System is a simple tangent projection
In [ ]:
wcs
In [ ]:
norm = ImageNormalize(hdu.data, interval=MinMaxInterval(),
stretch=LogStretch())
Make sure to pick a good sequential colormap and avoid the default 'jet'!
In [ ]:
%matplotlib inline
fig = plt.figure(figsize=(8,8))
ax = plt.subplot(projection=wcs)
plt.imshow(hdu.data, norm=norm, cmap='viridis', origin="lower")
plt.grid(color='white', ls='solid')
plt.xlabel('Right Ascension')
plt.ylabel('Declination')
In [ ]:
fig = plt.figure(figsize=(8,8))
ax = plt.subplot(projection=wcs)
overlay = ax.get_coords_overlay('galactic')
plt.imshow(hdu.data, norm=norm, origin="lower", cmap='Greys_r')
ax.coords['ra'].set_ticks(color='white')
ax.coords['dec'].set_ticks(color='white')
ax.coords['ra'].set_axislabel('Right Ascension')
ax.coords['dec'].set_axislabel('Declination')
ax.coords.grid(color='yellow', linestyle='solid', alpha=0.5)
overlay['l'].set_ticks(color='white')
overlay['b'].set_ticks(color='white')
overlay['l'].set_axislabel('Galactic Longitude')
overlay['b'].set_axislabel('Galactic Latitude')
overlay.grid(color='white', linestyle='solid', alpha=0.5)
In [ ]:
from astropy.table import Table
w5tbl = Table.read('data/w5_wise.tbl', format='ascii.ipac')
w5tbl = w5tbl[w5tbl['w4snr'] > 30.0]
In [ ]:
fit = plt.figure(figsize=(8,8))
hdu = fits.open('data/w5.fits')[0]
wcs = WCS(hdu.header)
ax = plt.subplot(projection=wcs)
plt.imshow(hdu.data, norm=norm, origin="lower", cmap='Greys_r')
ax.scatter(w5tbl['ra'], w5tbl['dec'], transform=ax.get_transform('world'))
plt.xlabel('Right Ascension')
plt.ylabel('Declination')
Toolkit for building viewers for scientific (esp. astronomical) data in Python
Written and maintained by s/w engineers at the Subaru Telescope, NAOJ
Image display object
Plugin-based; highly customizable
Installing Ginga will put ginga in your command path (same location as python).
This is the "reference viewer" which we can run from the command line.
In [ ]:
## uncomment to run
#!ginga ./data/w5.fits
Ginga can be run from the notebook.
To show some of Ginga's interactive capabilities, we will follow an excerpt of this online notebook.
In [ ]:
# setup
from ginga.web.pgw import ipg
# Set this to True if you have a non-buggy python OpenCv bindings--it greatly speeds up some operations
use_opencv = False
server = ipg.make_server(host='localhost', port=9914, use_opencv=use_opencv)
In [ ]:
# Start viewer server
# IMPORTANT: if running in an IPython/Jupyter notebook, use the no_ioloop=True option
server.start(no_ioloop=True)
In [ ]:
# Get a viewer
# This will get a handle to the viewer v1 = server.get_viewer('v1')
v1 = server.get_viewer('v1')
In [ ]:
# where is my viewer
v1.url
In [ ]:
# open the viewer in a new tab
v1.open()
NOTE: if you don't have the webbrowser module, open the link that was printed in the cell above in a new window to get the viewer.
You can open as many of these viewers as you want--just keep a handle to it and use a different name for each unique one.
Keyboard/mouse bindings in the viewer window: http://ginga.readthedocs.io/en/latest/quickref.html
In [ ]:
# Load an image into the viewer
# (change the path to where you downloaded the sample images, or use your own)
v1.load('./data/w5.fits')
In [ ]:
# Example of embedding a viewer
v1.embed(height=650)
In [ ]:
# capture the current state of the screen
v1.show()
Now set a pan position by shift-clicking somewhere in the viewer window.
In [ ]:
# Let's get the pan position we just set
dx, dy = v1.get_pan()
dx, dy
In [ ]:
# Getting values from the FITS header is also easy
img = v1.get_image()
hdr =img.get_header()
hdr['SURVEY']
In [ ]:
# What are the coordinates of the pan position?
# This uses astropy.wcs under the hood if you have it installed
img.pixtoradec(dx, dy)
In [ ]:
# Let's overlay some objects
# First, let's add a drawing canvas
canvas = v1.add_canvas()
In [ ]:
# Use our table from before
# Draw circles around all objects
Circle = canvas.get_draw_class('circle')
for (ra, dec) in zip(w5tbl['ra'],w5tbl['dec']):
x, y = img.radectopix(ra,dec)
canvas.add(Circle(x, y, radius=10, color='yellow'))
In [ ]:
v1.show()
Web-based visualizer
Basis for LSST Science User Interface
Remote server sits close to the data
Many operations performed by your browser
Developed for Spitzer Heritage Archive
Employed as IRSA Viewer
Can access user interface from IRSA
Example: Herschel High-Level Images http://irsa.ipac.caltech.edu/data/Herschel/HHLI/index.html
Search on W5
Overlay a WISE catalog
Download Firefly Standalone from release page (https://github.com/Caltech-IPAC/firefly/releases
Only requirement is java 1.8
Start with java -jar firefly-exec.war
By default, will be available on localhost port 80: http://localhost:8080/firefly/
In [ ]:
from firefly_client import FireflyClient
In [ ]:
fc = FireflyClient('localhost:8080', channel='mine')
In [ ]:
fc.launch_browser()
In [ ]:
fval = fc.upload_file('./data/w5.fits')
In [ ]:
fc.show_fits(fval, plot_id='w5_wise')
In [ ]:
tval = fc.upload_file('./data/w5_wise.tbl')
In [ ]:
fc.show_table(tval, title='Bright WISE W4')
The LSST stack can display images to Firefly.
Experimental Jupyter widgets have been developed.
Based on brushing-and-linking paradigm
Used for JWST
Images, scatter plots, histograms
To start from the notebook, execute the next line in its own cell
In [ ]:
%gui qt
In [ ]:
from glue import qglue
In [ ]:
qglue()
After quitting glue, try linking the data
In [ ]:
from glue.core.data_factories import load_data
from glue.core import DataCollection
from glue.core.link_helpers import LinkSame
from glue.app.qt.application import GlueApplication
import warnings
from astropy.utils.exceptions import AstropyWarning
#load 2 datasets from files
image = load_data('./data/w5.fits')
with warnings.catch_warnings():
warnings.simplefilter('ignore', AstropyWarning)
catalog = load_data('./data/w5_psc.vot')
dc = DataCollection([image, catalog])
In [ ]:
# link positional information
dc.add_link(LinkSame(image.id['Right Ascension'], catalog.id['RAJ2000']))
dc.add_link(LinkSame(image.id['Declination'], catalog.id['DEJ2000']))
In [ ]:
#start Glue
app = GlueApplication(dc)
app.start()
In [ ]:
image.component_ids()
In [ ]:
dc.links
In [ ]:
dc.subset_groups
In [ ]:
g1 = dc.subset_groups[0]
In [ ]:
g1.label
In [ ]: