Jdaviz
jdaviz
is a package of astronomical data analysis visualization
tools based on the Jupyter platform. These GUI-based tools link data
visualization and interactive analysis. They are designed to work
within a Jupyter notebook cell, as a standalone desktop application,
or as embedded windows within a website – all with nearly identical
user interfaces.
jdaviz
applications currently include tools for interactive
visualization of spectroscopic and imaging data.
Imviz is a tool for visualization and quick-look analysis for 2D astronomical images.
Specviz is a tool for visualization and quick-look analysis of 1D astronomical spectra.
Cubeviz provides a view of spectroscopic data cubes (like those
to be produced by JWST MIRI), along with 1D spectra extracted from the
cube.
Mosviz is a visualization tool for many astronomical
spectra, typically the output of a multi-object spectrograph (e.g.,
JWST NIRSpec), and includes viewers for 1D and 2D spectra as well as
contextual information like on-sky views of the spectrograph slit.
Note
jdaviz
is one tool that is part of STScI’s larger
Data Analysis Tools Ecosystem.
Note
The offline version of this documentation can be downloaded from Jdaviz zipped HTML downloads page.
JWST Instrument Modes in Jdaviz
This tool is designed with instrument modes from the James Webb Space Telescope (JWST) in mind, but the tool should be flexible enough to read in data from many astronomical telescopes. The table below summarizes Jdaviz file support specific to JWST instrument modes.
Instrument |
Template Mode |
File Type |
Pipeline Level |
Primary Configuration |
---|---|---|---|---|
NIRSpec |
MOS |
S2D |
2b,3 |
Mosviz |
X1D |
2b,3 |
Specviz |
||
IFU |
S3D |
2b,3 |
Cubeviz |
|
X1D |
2b,3 |
Specviz |
||
FS |
S2D |
2b,3 |
Specviz2d |
|
X1D |
2b,3 |
Specviz |
||
BOTS |
X1DINTS |
– |
No Support |
|
NIRISS |
IMAGING |
I2D |
2b,3 |
Imviz |
WFSS |
X1D |
2b |
Specviz |
|
AMI |
AMINORM |
– |
No Support |
|
SOSS |
X1DINTS |
– |
No Support |
|
NIRCam |
Imaging |
I2D |
2b,3 |
Imviz |
Coronagraphic Imaging |
I2D |
2b,3 |
Imviz |
|
WFSS |
X1D |
2b |
Specviz |
|
Grism TSO |
X1DINTS |
– |
No Support |
|
MIRI |
Imaging |
I2D |
2b,3 |
Imviz |
Coronagraphic Imaging |
I2D |
2b,3 |
Imviz |
|
LRS-slit |
S2D |
2b,3 |
Specviz2d |
|
X1D |
2b,3 |
Specviz |
||
LRS-slitless |
X1DINTS |
– |
No Support |
|
MRS |
S3D |
2b,3 |
Cubeviz |
|
X1D |
2b, 3 |
Specviz |
Using Jdaviz
Installation
Note
jdaviz
is undergoing constant development. We encourage users to always update
to the latest version. In general, it is good practice to install the development
version following the instructions below as full released versions may lag behind.
User Installation
Windows-Specific Dependencies
Some of our dependencies require C++ compilers to install properly. These are usually included with macOS and most Linux distributions, but are not included by default in Windows. Microsoft provides these tools as part of their Build Tools for Visual Studio, which can be found under “Tools for Visual Studio” towards the bottom of the page.
Create Your Local Environment
Some of Jdaviz’s dependencies require non-Python packages to work
(particularly the front-end stack that is part of the Jupyter ecosystem).
We recommend using Miniconda
to easily manage a compatible Python environment for jdaviz
; it should work
with most modern shells, except CSH/TCSH.
You may want to consider installing jdaviz
in a new virtual or conda environment
to avoid version conflicts with other packages you may have installed, for example:
conda create -n jdaviz-env python=3.9
conda activate jdaviz-env
Pip Install
As noted above, we typically recommend installing the latest development version:
pip install git+https://github.com/spacetelescope/jdaviz --upgrade
A normal install will also work by installing the latest release version:
pip install jdaviz --upgrade
Common Issues
If you encounter problems while following these installation instructions, please consult known installation issues.
Note that jdaviz
requires Python 3.8 or newer. If your pip
corresponds to an older version of
Python, it will raise an error that it cannot find a valid package.
Users occasionally encounter problems running the pure pip
install above. For those
using conda
, some problems may be resolved by pulling the following from conda
instead of pip
:
conda install bottleneck
conda install -c conda-forge notebook
conda install -c conda-forge jupyterlab
conda install -c conda-forge voila
You might also want to enable the ipywidgets
notebook extension, as follows:
jupyter nbextension enable --py widgetsnbextension
Developer Installation
If you wish to contribute to Jdaviz, please fork the project to your
own GitHub account. The following instructions assume your have forked
the project and have connected
your GitHub to SSH
and username
is your GitHub username. This is a one-setup setup:
git clone git@github.com:username/jdaviz.git
cd jdaviz
git remote add upstream git@github.com:spacetelescope/jdaviz.git
git fetch upstream main
git fetch upstream --tags
To work on a new feature or bug-fix, it is recommended that you build upon
the latest dev code in a new branch (e.g., my-new-feature
).
You also need the up-to-date tags for proper software versioning:
git checkout -b my-new-feature
git fetch upstream --tags
git fetch upstream main
git rebase upstream/main
For the rest of contributing workflow, it is very similar to
how to make code contribution to astropy,
except for the change log.
If your patch requires a change log, see CHANGES.rst
for examples.
To install jdaviz
for development or from source in an editable mode
(i.e., changes to the locally checked out code would reflect in runtime
after you restarted the Python kernel):
pip install -e .
Optionally, to enable the hot reloading of Vue.js templates, install
watchdog
:
pip install watchdog
After installing watchdog
, to use it, add the following to the top
of a notebook:
from jdaviz import enable_hot_reloading
enable_hot_reloading()
Imviz

Imviz is a tool for visualization and analysis of 2D astronomical images.
It incorporates visualization tools with analysis capabilities, such as Astropy
regions and photutils packages.
Users can interact with their data from within the tool.
Imviz also provides programmatic access to its viewers using
Astrowidgets API;
see AstrowidgetsImageViewerMixin
for available functionality.
Data can be both imported into and exported out of the tool so users can continue their
desired workflow within the notebook.
This documentation provides details on the various capabilities, demo videos, and example notebooks.
Using Imviz
Importing Data into Imviz
Imviz can load data in the form of a filename (FITS, JPEG, or PNG),
an NDData
object, or a NumPy array if the data is 2D.
See jdaviz.configs.imviz.helper.Imviz.load_data()
for more information.
Note
Loading too many datasets will cause performance problems due to the number of links necessary; see The linking framework for more information.
Importing data through the Command Line
When running the Imviz application via the command line, you must provide a path to a compatible file, which will be loaded into the app on initialization:
jdaviz imviz /my/image/data.fits
Importing data through the GUI
You can load your data into the Imviz application
by clicking the Import Data button at the top left of the application’s
user interface. This opens a dialogue where the user can select a file
that can be parsed as a NDData
, HDUList
,
or ImageHDU
in the text field.
After clicking Import, the data file will be parsed and loaded into the application. A notification will appear to let users know if the data import was successful. Afterward, the new data set can be found in the Data tab of each viewer’s options menu as described in Selecting a Data Set.
Importing data via the API
Alternatively, users who work in a coding environment like a Jupyter
notebook can access the Imviz helper class API. Using this API, users can
load data into the application through code with the
load_data()
method, which takes as input either the name of a local file or an
NDData
, HDUList
,
or ImageHDU
object.
FITS Files
The example below loads the first science extension of the given FITS file into Imviz:
from jdaviz import Imviz
imviz = Imviz()
imviz.load_data("/path/to/data/image.fits")
imviz.show()
Creating Your Own Array
You can create your own array to load into Imviz:
import numpy as np
from jdaviz import Imviz
arr = np.arange(100).reshape((10, 10))
imviz = Imviz()
imviz.load_data(arr, data_label='my_array')
imviz.show()
JWST datamodels
If you have a jwst.datamodels object, you can load it into Imviz as follows:
import numpy as np
from astropy.nddata import NDData
from jdaviz import Imviz
# mydatamodel is a jwst.datamodels object
ndd = NDData(np.array(mydatamodel.data), wcs=mydatamodel.get_fits_wcs())
imviz = Imviz()
imviz.load_data(ndd, data_label='my_data_model')
imviz.show()
There is no plan to natively load such objects until datamodels
is separated from the jwst
pipeline package.
Batch Loading Multiple Images
To save on performance while loading multiple images into Imviz, you can optionally use
batch_load()
to parse all of the data first (within a for
loop or multiple calls to load_data
, for example), and defer the linking and loading of the new
data entries into the viewer until after the parsing is complete:
from jdaviz import Imviz
imviz = Imviz()
with imviz.batch_load():
for filepath in filepaths:
imviz.load_data(filepaths)
imviz.show()
Importing catalogs via the API
If you have a catalog file supported by astropy.table.Table
, you
can load the catalog into Imviz and add markers to Imviz viewers to show
positions from the catalog. These markers are different than Imviz
spatial regions as they are only meant to mark catalog positions.
Loading markers can be done with the following commands:
viewer.marker = {'color': 'green', 'alpha': 0.8, 'markersize': 10, 'fill': False}
my_markers = Table.read('my_catalog.ecsv')
coord_i2d = Table({'coord': [SkyCoord(ra=my_catalog['sky_centroid'].ra.degree,
dec=my_catalog['sky_centroid'].dec.degree,
unit="deg")]})
viewer.add_markers(coord_i2d, use_skycoord=True, marker_name='my_markers')
If you have a large catalog, you might want to filter your table to the
marks of interest before adding them to Imviz, in order to avoid performance
issues associated with adding large numbers of markers. For instance, if your
image has FITS WCS, you could use astropy.wcs.WCS.footprint_contains
if you
only want the marks within a footprint. Alternately, you could filter by
relevant columns in your catalogs, such as brightness, distance, etc.
And to remove those markers:
viewer.remove_markers(marker_name='my_markers')
Importing regions via the API
If you have a region file supported by Reading/Writing Region Files, you can load the regions into Imviz as follows:
imviz.load_regions_from_file("/path/to/data/myregions.reg")
Unsupported regions will be skipped and trigger a warning. Those that
failed to load, if any, can be returned as a list of tuples of the
form (region, reason)
:
bad_regions = imviz.load_regions_from_file("/path/to/data/myregions.reg", return_bad_regions=True)
You could also define Region Shapes programmatically and load them; e.g.:
from regions import CirclePixelRegion, PixCoord
aper_1 = CirclePixelRegion(center=PixCoord(x=42, y=43), radius=4.2)
aper_2 = CirclePixelRegion(center=PixCoord(x=10, y=20), radius=3)
imviz.load_regions([aper_1, aper_2])
For more details on the API, please see
load_regions_from_file()
and load_regions()
methods
in Imviz.
Displaying Images
Imviz uses image viewers to visualize data from supported formats. Much of the functionality is available both from the application GUI and from the Jupyter notebook using API calls. The Toolbar below gives you several image display options. Right-click will open a dropdown with access to different options for each button.

Selecting a Data Set
Data can be selected and de-selected in each viewer’s data menu, opened by clicking the
button in the top left of the viewer. Here, you can click a
checkbox next to the listed data to make the data visible (checked) or invisible (unchecked).
The datasets available in each viewer are filtered
to include only compatible data, so you may not see all loaded data in the menu for
every viewer. For example, 1D spectra will not be available in the image viewers.
Cursor Information
By moving your cursor along the image viewer, you will be able to see information on the cursor’s location in pixel space (X and Y), the RA and Dec at that point, and the value of the data there. This information is displayed in the top bar of the UI, on the middle-right side.
Notes on GWCS
If your reference data has GWCS with a bounding box, any coordinates transformation outside that bounding box is less reliable. This still applies even when you are looking at some other data that is not the reference data if they are linked by WCS because all transformations in glue go through the reference data. Such a situation is indicated by “(est.)” and the affected coordinates becoming gray.
If your data of interest also has a GWCS with a bounding box, only the mouseover data where it overlaps with the reference data’s bounding box is completely reliable. Unreliable coordinates transformation here will also gray out in a similar fashion as above.
To avoid inaccurate transforms, consider one of the following workflows:
Make sure your reference data’s GWCS has a bounding box that encompasses all the other data you are trying to visualize together.
If the above is not possible, avoid overlaying different data with GWCS that do not overlap.
Warning
If you rely on the GWCS bounding box, it will be set to None when
you data is loaded into Imviz, but the original bounding box,
if available, is now in a hidden _orig_bounding_box
attribute of the GWCS object. You can restore the bounding box by
assigning the value of _orig_bounding_box
back to its
bounding_box
attribute.
Note that FITS WCS has no similar concept of bounding box.
Home
This button will reset your zoom and panning to display the entire image.
Previous zoom is also available by right-clicking on the home icon and selecting the previous zoom icon. This will revert to the last saved zoom state. Zoom states are saved when beginning a zoom selection or when activating a pan/zoom tool.
Box Zoom and Linked Box Zoom
Linked Box Zoom is an Imviz-specific feature that allows the user to zoom images in multiple different viewers simultaneously, not unlike Pan/Zoom and Linked Pan/Zoom.
Single-viewer Box Zoom is also available and is used in a similar way as in other Jdaviz tools. To access this option, right-click on the Linked Box Zoom button and left-click on the second option down to select it.
Pan/Zoom and Linked Pan/Zoom
Linked Pan/Zoom is an Imviz-specific feature that allows the user to pan and zoom images in multiple different viewers simultaneously. This works by matching images based on the way they are linked together. Images are linked by pixels on load time, but you can re-link them via WCS using Link Control.
Single-viewer Pan/Zoom is also available and is used in a similar way as in other Jdaviz tools. To access this option, right-click on the Linked Pan/Zoom button and left-click on the second option down to select it.
When in either of these modes, clicking on the image will recenter the image to the location under cursor.
From the API
From the API, you can programmatically zoom in and out. Zoom level:
1 - real-pixel-size
2 - zoomed in by a factor of 2
0.5 - zoomed out by a factor of 2
'fit'
- zoomed to fit the whole image width into display
For example:
viewer = imviz.default_viewer
viewer.zoom_level
viewer.zoom_level = 1 # Set the zoom level directly.
viewer.zoom(2) # Set the relative zoom based on current zoom level.
Defining Spatial Regions
Spatial regions allow users to select subsets of the data array for use in specific analysis functions in the plugin toolbar, for example in the Simple Aperture Photometry plugin. Users can create spatial regions either in Imviz or the Jupyter notebook.
Regions can be created by first clicking the icon (to draw a circular region),
then clicking and dragging (using the mouse) until the
desired region is covered by a colored shape, after which you release the mouse button.
If you want to draw other shapes, right click on the icon to see a dropdown of supported shapes
and left click on it to choose the shape, then draw as mentioned above.
Once you have completed the action of clicking and dragging, there is an opportunity to reposition the region of interest by clicking on it and moving the region to a different location in the image viewer. If you are satisfied with the positioning of your region of interest, simply click another part of the viewer to lock it in place.
There are other options available for region of interest. At the top of the user interface, there is a section that says either “+ No selection (create new)” or “Subset n” where n is an integer that tells you which Subset is currently selected. To the right of this area, are red circles that allow you to change the method of region selection. The options are:
replace
: will remove the previously created selection and place the newly created subset.add
: allows you to create another subset that extends the existing subset.and
: only leaves behind the overlapping region between the existing subset and any additional subsets.xor
: only leaves behind the non-overlapping region between the existing subset and any additional subsets.remove
: will de-select any parts of the existing subset that overlaps with any additional subsets.
You can use these options to further adjust the region of interest and adapt it to your use case.
See also
- Importing Spatial Regions
Importing regions from within the Jupyter notebook.
See also
- Exporting Spatial Regions
Exporting regions from within the Jupyter notebook.
You can import and export regions from the API.
See also
- Defining subsets using Glue
Glueviz documentation on defining and refining subsets. Slightly different UI but same approach.
There are options available in the Layer tab under the icon
to make subsets visible or invisible, to change their color, and to change their opacity.
Single-Pixel Selection
This tool allows the user to create a single-pixel spatial region in an image viewer. Activate this tool and then left-click to create the new region. Click again to move the region to a new location under the cursor. Holding down the alt key (Alt key on Windows, Option key on Mac) while clicking pixels creates a new region at each point instead of moving the previously created region. You can also use the subset modes that are explained in the Spatial Regions section above in the same way you would with the other subset selection tools.
When you have multiple images loaded and linked by WCS (see Link Control), the region defined is with respect to the reference image, which might not be the image you are viewing.
Warning
Region created might not accurately represent area you think you are clicking under the mouse if you click on an image that is zoomed out too much. It is recommended that you zoom in sufficiently to see the individual pixels to use this feature.
Note
Creating too many single-pixel regions may affect performance.
Blinking
Blinking is an Imviz-specific functionality that allows a user to quickly switch
between viewing two or more images, as long as they are linked (see Pan/Zoom and Linked Pan/Zoom for
more on linking behavior). This can be done by selecting the icon and
then left-clicking on the image to blink forward; right-clicking would blink backwards.
You can also blink forward by pressing the “b” key on your keyboard while moused over the image. If you press Shift + “b” (“B”), you may blink backwards.
From the API
From the API within the Jupyter notebook:
viewer = imviz.default_viewer
viewer.blink_once()
And to blink backwards:
viewer.blink_once(reversed=True)
Contrast/Bias
In addition to changing Contrast and Bias in the Display Settings,
Imviz has a button under the
menu that can also
adjust those values.
After right-clicking on the blink icon, left click on the constrast/bias icon to activate it. Now you can click and drag on the image viewer to change to change the contrast and bias. Moving along the X-axis will change the bias and moving along the Y-axis will change the contrast. If you would like to reset to the default contrast and bias settings, you can double-click on the display while the mode is active.
Display Settings
To access all of the different display settings for an image viewer, click the
icon in the viewer toolbar or open the Plot Options plugin.
Changing the display settings DOES NOT change the underlying data, only the
visualization of that data.
If you wish to access plot options via API
(also see PlotOptions
),
you can do the following:
plot_options = imviz.plugins['Plot Options']
Layer
This option allows you to change which layer you are changing the settings for.
Attribute
This shows which extension of the data is being displayed in the current viewer.
Contour
This option selects whether to show or hide contours.
The Contours of a second image can also be plotted over a first image or cube. Add the second image as data in the data dropdown tab, and select both images. To visualize the contours of the second image, go to the Layer tab, select the layer to be contour-mapped, and set its Contour to be on and its Bitmap to be off. The contours of the second image will appear superimposed on the first image. In the second figure below, we show the contours of an image generated using the Collapse plugin plotted over leftmost cube viewer. If you overplot them on a cube, the contours will remain unchanged as you scrub through the cube.
Bitmap
This option selects whether to show or hide the bitmap (image) in the viewer.
Opacity
Change the translucence of the image.
Contrast
Change the luminance of the color in the image.
Bias
Set a constant to subtract from every point in the data array before applying the conversion between data value and displayed pixel saturation. The bias slider center position is 0 bias, such that a user can apply negative bias values by sliding it left.
Stretch
Change the equation that is used to convert data values between min and max to the 0 to 1 scale of pixel saturation on the displayed image.
To set the stretch function for just the image being displayed. The acceptable values are as defined by glue backend:
viewer = imviz.default_viewer
viewer.stretch_options
viewer.stretch = 'sqrt'
To set the stretch function for all the images at once.
The acceptable values are the same as the GUI menu options
can be accessed with plot_options.stretch_function.choices
:
plot_options = imviz.plugins['Plot Options']
plot_options.select_all()
plot_options.stretch_function = 'Square Root'
Percentile
Can be used to set the min and max values based on percentiles of the data.
If the percentile is “custom”, then the data value corresponding to the minimum of the colormap scale (e.g., black in grayscale) can be set.
If the percentile is “custom”, then the data value corresponding to the maximum of the colormap scale (e.g., white in grayscale) can be set.
To set the percentile for just the image being displayed:
viewer = imviz.default_viewer
viewer.cuts = '95%' # Preset
viewer.cuts = (0, 1000) # Custom
To set the percentile for all the images at once:
plot_options = imviz.plugins['Plot Options']
plot_options.select_all()
# Preset
plot_options.stretch_preset = '95%'
# Custom
plot_options.stretch_preset = 'Custom'
plot_options.stretch_vmin = 0
plot_options.stretch_vmax = 1000
Colormap
The spectrum of colors used to visualize data can be changed using this drop down.
To set the colormap for just the image being displayed:
viewer = imviz.default_viewer
viewer.colormap_options
viewer.set_colormap('Viridis')
To set the colormap for all the images at once:
plot_options = imviz.plugins['Plot Options']
plot_options.select_all()
plot_options.image_colormap = 'Viridis'
A custom colormap can only be added when Imviz is run in a notebook, not from the
command line. The custom colormap must be added to Glue before starting Imviz.
The example below adds a random colormap generated by photutils
into Glue:
from glue.config import colormaps
from photutils.utils import make_random_cmap
randcmap = make_random_cmap(ncolors=256)
randcmap.colors[0] = 0. # To make your background black
colormaps.add('photutils_cmap', randcmap)
Only after the above is done can you start Imviz and use the custom colormap:
imviz = Imviz()
imviz.load_data('myimage.fits')
imviz.default_viewer.set_colormap('photutils_cmap')
Adding New Viewers
In the toolbar towards the top of the UI, there is a icon
that when clicked will add new viewers to the application. You can then select from the data
that has been loaded into the application to be visualized in these additional viewers.
You can then utilize some of the Imviz-specific features, like Pan/Zoom and Linked Pan/Zoom.
From the API
From the API within the Jupyter notebook:
viewer_2_name = 'Window 2'
viewer_2 = imviz.create_image_viewer(viewer_name=viewer_2_name)
imviz.app.add_data_to_viewer(viewer_2_name, 'MyImportedData')
where 'MyImportedData'
is a data set that has already been imported into Imviz.
Data Analysis Plugins
The Imviz data analysis plugins are meant to aid quick-look analysis of 2D image data. All plugins are accessed via the plugin icon in the upper right corner of the Imviz application.

Metadata Viewer
This plugin allows viewing of any metadata associated with the selected data.
If the data is loaded from multi-extension FITS that contains a primary header, you will also see a Show primary header toggle, when enabled, would display just the primary header metadata.
Plot Options
This plugin gives access to per-viewer and per-layer plotting options.
See also
- Display Settings
Documentation on various display settings in the Jdaviz viewers.
Subset Tools
This plugin allows you to select an existing subset to modify, or to select Create new to create a new subset by selecting and using the region selector in the spectrum viewer toolbar. You can also choose the operation that will be applied by the selector tool. Note that these are synched with the subset tools in the app-level toolbar. It might not show some static regions loaded via the API unless an interactive region is drawn after.
If an existing subset is selected, the parameters of the subset will also be
shown. Note that while parameters for compound regions (e.g., a subset with
multiple disjoint regions) are displayed, the logical operations joining them
(OR
, AND
, etc.) are not shown.
For a simple subset in Imviz only, you can choose to recenter it based
on the selected Data. The centroid is calculated by
photutils.aperture.ApertureStats.centroid
, which is the
center-of-mass of the data within the aperture.
No background subtraction is performed. Click Recenter
to change its parameters and move it to the calculated centroid.
Note
If you want accurate centroid calculations, it is recommended that you
use a background-subtracted image. Alternately, you could calculate
the centroid outside of Jdaviz (e.g., using photutils
) and then
manually edit the subset (see below) or load your own aperture object
(Importing regions via the API).
For a simple subset, you can edit its parameters by changing the values in the corresponding editable text fields. Once you have entered the new value(s), click Update to apply. You should see the subset parameters, shape, and orientation (if applicable) all update concurrently.
Angle is counter-clockwise rotation around the center in degrees.
Link Control
This plugin is used to re-link images by pixels or WCS using
link_image_data()
.
All images are automatically linked by pixels on load but you can use
it to re-link by pixels or WCS as needed.
For WCS linking, the “fast approximation” option uses an affine transform to represent the offset between images, if possible. It is much more performant at the cost of accuracy but should be accurate to within a pixel for most cases. If approximation fails, WCS linking still automatically falls back to full transformation.
For the best experience, it is recommended that you decide what kind of link you want and set it at the beginning of your Imviz session, rather than later.
For more details on linking, see Linking of datasets in glue.
From the API
From the API within the Jupyter notebook (if linking by WCS):
imviz.link_data(link_type='wcs')
Compass
For an image with a valid WCS, the compass will show directions to North (N) and East (E) for ICRS sky coordinates. It also shows the currently displayed data label, the X and Y directions, and the zoom box.
When you have multiple viewers created in Imviz, use the Viewer dropdown menu to change the active viewer that it tracks.
Line Profiles
This plugin plots line profiles across X and Y for the pixel under cursor
when l
key is pressed on the image viewer. You can also manually type in the
values of X and Y, and then press the PLOT button.
The top visible image, the same one displayed under Compass,
will be used for these plots.
This plugin only considers pixel locations, not sky coordinates.
Simple Aperture Photometry
This plugin performs simple aperture photometry and plots a radial profile for one object within an interactively selected region. A typical workflow is as follows:
Load image(s) in Imviz (see Importing Data into Imviz).
Draw a region over the object of interest (see Defining Spatial Regions).
Select the desired image using the Data dropdown menu.
Select the desired region using the Subset dropdown menu. You can use the Subset Tools plugin to center it first on the object of interest using its center of mass, if you wish. Depending on the object, it may take several iterations for re-centering to converge, or it may never converge at all.
If you want to subtract background before performing photometry, you have the following 3 options. Otherwise if your image is already background subtracted, choose “Manual” and leave the background set at 0:
Manual: Enter the background value in the Background value field. This value must be in the same unit as display data, if applicable.
Annulus: Enter its inner radius and width in the Annulus inner radius and Annulus width, respectively. Median of the pixels within the annulus region will be used but the annulus shape will not be shown on display.
Subset: Define a region for background calculation (median) using Subset draw tool and select that region using the Background dropdown menu. Only regions created with the replace option are acceptable as background regions (see Defining Spatial Regions).
For some JWST and HST images, pixel area in arcsec squared is automatically populated in the Pixel area field from image metadata. If it does not auto-populate for you, you can manually enter a value but it must be in the unit of arcsec squared. This field is only used if per steradian is detected in display data unit. Otherwise, it is only informational. If this field is not applicable for you, leave it at 0. This field resets every time Data selection changes if auto-population not possible.
If you also want photometry result in the unit of counts, you can enter a conversion factor in the Counts conversion factor field. The value must be in the unit of display data unit per counts. This is used to convert linear flux unit (e.g., MJy/sr) to counts. This field is only used if data has a valid unit. If this field is not applicable for you, leave it at 0. This field resets every time Data selection changes.
If you also want photometry result in magnitude unit, you can enter a flux scaling factor in the Flux scaling field. Flux scaling is populated for JWST images if MJy/sr data unit is detected and pixel area is given to factor out the per-steradian unit. The value used, if this is the case, is the scaling to convert MJy to AB magnitude. Otherwise, the value must be in the same unit as display data unit. A magnitude is then calculated using
-2.5 * log(flux / flux_scaling)
. This calculation only makes sense if your display data unit is already in linear flux unit. Setting this to 1 is equivalent to not applying any scaling. This field is only used if data has a valid unit. If this field is not applicable for you, leave it at 0. This field resets every time Data selection changes.Select the desired radial profile plot type using the Plot Type dropdown menu:
Curve of Growth:
sum
(sum of flux in the aperture) across radii from center out to the edge of the aperture. This is calculated in the same way as the final aperture sum in the output table, which is explained farther down on this page.Radial Profile: Binned average as a function of radius from the center of the region.
Radial Profile (Raw): Raw image data points as a function of radius from the center of the region. Caution: having too many data points may cause performance issues with this feature. The exact limitations depend on your hardware.
Toggle Fit Gaussian on to fit a
Gaussian1D
model to the radial profile data. This is disabled for curve-of-growth.Once all inputs are populated correctly, click on the CALCULATE button to perform simple aperture photometry.
Note
Masking and weights by uncertainty are currently not supported. However, if NaN exists in data, it will be treated as 0.
When calculation is complete, a plot would show the radial profile of the background subtracted data and the photometry and model fitting (if requested) results are displayed under the CALCULATE button.

Radial profile.

Radial profile (raw).
See also
- Export Photometry
Documentation on exporting photometry results.
Catalog Search
This plugin queries a catalog around the zoom window of the active image, marks the sources from the results of the query, and provides the number of sources found. After zooming into a specific region of the image, the query uses the center point of the region with a radius determined by the farthest edge point of the region. Clicking on CLEAR will remove all markers on the active viewer.
To select which catalog you would like to use for the search, please pick one of the available options from the catalog dropdown menu.
Note
This plugin is still under active development. As a result, the search only uses the SDSS DR17 catalog and works best when you only have a single image loaded in a viewer.
To load a catalog from a supported JWST ECSV catalog file, choose “From File…”.
The file must be able to be parsed by astropy.table.Table.read
and contain a column labeled ‘sky_centroid’.
Clicking SEARCH will show markers for any entry within the filtered zoom window.
If you have multiple viewers open, you will see another dropdown menu to select the active viewer.
Additionally, the query starts anew every time SEARCH is clicked, so previous results and marks are not stored. To save the current result before submitting a new query, you can save the table to a variable:
results = imviz.get_catalog_source_results()
Note
The table returned from the API above may cover more sources than shown in the currently zoomed-in portion of the image. Additional steps will be needed to filter out these points, if necessary.
Export Plot
This plugin allows exporting the plot in a given viewer to a PNG or SVG file.
Exporting Data from Imviz
Spatial Regions
You can extract supported spatial regions as follows:
regions = imviz.get_interactive_regions()
regions
Aperture Photometry
If you opted to fit a Gaussian1D
to the radial profile, the last fitted model parameters will be displayed
under the radial profile plot. The model itself can be obtained as follows.
See Models and Fitting (astropy.modeling) on how to manipulate the model:
my_gaussian1d = imviz.app.fitted_models['phot_radial_profile']
You can also retrieve the photometry results as QTable
as follows,
assuming imviz
is the instance of your Imviz application:
results = imviz.get_aperture_photometry_results()
When multiple calculations are done in the same session (e.g., calculating
aperture photometry for the same region across different images or for
different regions on the same image), imviz.get_aperture_photometry_results()
will return all the calculations in the same table, if possible.
However, if the newest result is incompatible with the existing ones (e.g., two
images have very different units), only the newest is kept in the table.
When you are unsure, save the results after each calculation as different
variables in your Python session.
The output table contains the results you see in the plugin and then some. The columns are as follow:
id
: ID number assigned to the row, starting from 1.xcenter
,ycenter
: Center of the aperture (0-indexed).sky_center
:SkyCoord
associated with the center. If WCS is not available, this field isNone
.background
: The value from Background value, with unit attached.sum
: Sum of flux in the aperture. If per steradian is in input data unit, total pixel area covered in steradian is already multiplied here, if applicable, so there will be no per steradian in its unit. Otherwise, it has the same unit as input data. For more details on how the photometry is done, see Aperture Photometry (photutils.aperture).sum_aper_area
: The pixel area covered by the region. Partial coverage is reported as fraction.pixarea_tot
: If per steradian is in input data unit and pixel area is provided, this contains the conversion factor for the sum to take out the steradian unit. Otherwise, it isNone
.aperture_sum_counts
: This is the aperture sum converted to counts, if Counts conversion factor was set. Otherwise, it isNone
. This calculation is done without taking account ofpixarea_tot
, even when it is available.aperture_sum_counts_err
: This is the Poisson uncertainty (square root) foraperture_sum_counts
. Other uncertainty factors like readnoise are not included. In the plugin, it is displayed within parenthesis next to the value foraperture_sum_counts
, if applicable.counts_fac
: The value from Counts conversion factor, with unit attached, if applicable. Otherwise, it isNone
.aperture_sum_mag
: This is the aperture sum converted to magnitude, if Flux scaling was set. Otherwise, it isNone
. This calculation is done without taking account ofpixarea_tot
, even when it is available.flux_scaling
: The value from Flux scaling, with unit attached, if applicable. Otherwise, it isNone
.min
,max
,mean
,median
,mode
,std
,mad_std
,var
,biweight_location
,biweight_midvariance
: Basic statistics from the aperture.fwhm
,semimajor_sigma
,semiminor_sigma
,orientation
,eccentricity
: Properties of a 2D Gaussian function that has the same second-order central moments as the source.data_label
: Data label of the image used.subset_label
: Subset label of the region used.timestamp
: Timestamp of when the photometry was performed asTime
.
Note
Aperture sum and statistics are done on the originally drawn aperture only. You can use the Subset Tools plugin to center it first on the object of interest, if you wish.
Once you have the results in a table, you can further manipulated them as documented in Data Tables (astropy.table).
Examples
Below is a quick introductory tour of the Imviz configuration and its features. To get started, we recommend cloning the Jdaviz repo and running the ImvizExample notebook.
See also
- Example notebooks
A number of additional example notebooks.
Open Image Data
Overplotting a Catalog
Aligning Images
Exploring the Plugin Toolbar
Aperture Photometry
Specviz

Specviz is a tool for visualization and quick-look analysis of 1D astronomical spectra. It incorporates visualization tools with analysis capabilities, such as Astropy regions and specutils packages. Users can interact with their data from within the tool.
Specviz allows spectra to be easily plotted and examined. It supports flexible spectral unit conversions, custom plotting attributes, interactive selections, multiple plots, and other features. Specviz notably includes a measurement tool for spectral lines which enables the user, with a few mouse actions, to perform and record measurements. It has a model fitting capability that enables the user to create simple (e.g., single Gaussian) or multi-component models (e.g., multiple Gaussians for emission and absorption lines in addition to regions of flat continua).
A typical data-analysis workflow might involve data exploration using Specviz and then scripting to create more complex measurements or modeling workflows using specutils. Data can be both imported into and exported out of the tool so users can continue their desired workflow within the notebook. This documentation provides details on its various capabilities alongside demo videos and example notebooks.
Using Specviz
Importing Data Into Specviz
By design, Specviz only supports data that can be parsed as Spectrum1D
objects,
as that allows the Python-level interface and parsing tools to be defined in specutils
instead of being duplicated in Jdaviz.
Spectrum1D
objects are very flexible in their capabilities, however,
and hence should address most astronomical spectrum use cases.
See also
- Reading from a File
Specutils documentation on loading data as
Spectrum1D
objects.
Importing data through the Command Line
You can load your data into the Specviz application through the command line:
jdaviz specviz /my/directory/spectrum.fits
Importing data through the GUI
You can load your data into the Specviz application
by clicking the Import Data button at the top left of the application’s
user interface. This opens a dialogue where the user can select a file
that can be parsed as a Spectrum1D
.
After clicking Import, the data file will be parsed and loaded into the application. A notification will appear to let users know if the data import was successful. Afterward, the new data set can be found in the Data tab of each viewer’s options menu as described in Selecting a Data Set.
Importing data via the API
Alternatively, users who work in a coding environment like a Jupyter
notebook can access the Specviz helper class API. Using this API, users can
load data into the application through code with the
load_spectrum()
method, which takes as input a Spectrum1D
object.
FITS Files
The example below loads a FITS file into Specviz:
from specutils import Spectrum1D
spec1d = Spectrum1D.read("/path/to/data/file")
specviz = Specviz()
specviz.load_spectrum(spec1d, data_label="my_spec")
specviz.show()
You can also pass the path to a file that Spectrum1D
understands directly to the
load_spectrum()
method:
specviz.load_spectrum("path/to/data/file")
Creating Your Own Array
You can create your own array to load into Specviz:
import numpy as np
import astropy.units as u
from specutils import Spectrum1D
from jdaviz import Specviz
flux = np.random.randn(200) * u.Jy
wavelength = np.arange(5100, 5300) * u.AA
spec1d = Spectrum1D(spectral_axis=wavelength, flux=flux)
specviz = Specviz()
specviz.load_spectrum(spec1d, data_label="my_spec")
specviz.show()
JWST datamodels
If you have a jwst.datamodels object, you can load it into Specviz as follows:
from specutils import Spectrum1D
from jdaviz import Specviz
# mydatamodel is a jwst.datamodels.MultiSpecModel object
a = mydatamodel.spec[0]
flux = a.spec_table['FLUX']
wave = a.spec_table['WAVELENGTH']
spec1d = Spectrum1D(flux=flux, spectral_axis=wave)
specviz = Specviz()
specviz.load_spectrum(spec1d, data_label="MultiSpecModel")
specviz.show()
There is no plan to natively load such objects until datamodels
is separated from the jwst
pipeline package.
Importing a SpectrumList
The load_spectrum()
also accepts
a SpectrumList
object, in which case it will both load the
individual Spectrum1D
objects in the list and additionally attempt
to stitch together the spectra into a single data object so that
they can be manipulated and analyzed in the application as a single entity:
from specutils import SpectrumList
spec_list = SpectrumList([spec1d_1, spec1d_2])
specviz.load_spectrum(spec_list)
specviz.show()
In the screenshot below, the combined spectrum is plotted in gray, and one of the single component spectra are also selected and plotted in red. Note that the “stitching” algorithm to combine the spectra is a simple concatenation of data, so in areas where the wavelength ranges of component spectra overlap you may see the line plot jumping between points of the two spectra, as at the beginning and end of the red region in the screenshot below:

This functionality is also available in limited instances by providing a directory path
to the load_spectrum()
method. Note
that the read
method of SpectrumList
is only set up to handle
directory input in limited cases, for example JWST MIRI MRS data, and will throw an error
in other cases. In cases that it does work, only files in the directory level specified
will be read, with no recursion into deeper folders.
The load_spectrum()
method also takes
an optional keyword argument concat_by_file
. When set to True
, the spectra
loaded in the SpectrumList
will be concatenated together into one
combined spectrum per loaded file, which may be useful for MIRI observations, for example.
Displaying Spectra
Because of its use of glue as the underlying data-handling layer and its applicability in several different contexts, Specviz takes a modular approach to displaying data that has been loaded.
The first spectrum you load will be automatically displayed in the viewer with the view window set by the extent of the spectrum. Additional spectra may not be fully shown if they exceed the bounds of the plotted area, which are set based on the first displayed spectrum. The bounds can be changed via the Pan/Zoom tool or by deselecting the current spectra and selecting a different spectrum for display.
Much of the Specviz functionality can be handled within the tool or the Jupyter notebook using an API. The Toolbar below gives you several spectroscopic display options. Right click will open a dropdown with access to different options for each button.

Selecting/Showing Data Sets
Data can be selected and de-selected in each viewer’s data menu, opened by clicking the
button in the top left of the viewer. Here, you can click a
checkbox next to the listed data to make the data visible (checked) or invisible (unchecked).
In addition to toggling the visibility of a data layer, the data can be unloaded from a viewer by clicking the “x” button on the right. Data unloaded from the viewer will also be excluded as options from dataset dropdown menus in the various plugins. Unloaded data will be available to re-load into the viewer or remove permanently from the app from an expandable section in the data menu.

Home
This button will reset your zoom and panning to display the entire image.
Box Zoom
The (box) and
(x-range) zoom tools allow you to zoom by
clicking and dragging with your mouse. The box zoom tool adjusts both the x and y range of
the plot, whereas the x-range tool zooms only the x-axis to the selected region. While
clicking and dragging you will see the selected region as a gray box, as below.
You can switch between the x-range zoom tool and the plot tool by right-clicking (or your trackpad equivalent) on the currently selected zoom icon on the viewer toolbar, which will open a menu of choices as in the screenshot below.
Pan Zoom
There are several ways to pan around a spectrum or zoom in on features of interest. Right click will open a dropdown with access to different options described below.
Interactive Pan/Zoom (Desktop or Notebook Interface)
You can find the following Pan/Zoom tools available in the viewer toolbar on the top right of the viewer.
This button will reset your zoom and panning to display the spectrum.
Previous zoom is also available by right-clicking on the home icon and selecting the previous zoom icon. This will revert to the last saved zoom state. Zoom states are saved when beginning a zoom selection or when activating a pan/zoom tool.
The icon allows you to zoom using the scroll wheel.
The window will zoom into the area around your cursor.
To pan, simply click and drag the window.
The (horizontal) and
(vertical) Zoom tools allow you to zoom along each axis, while locking the other. You can also zoom by scrolling.
From the API
The Specviz helper contains a set of convenience methods to programmatically define the view of the spectrum viewer. You may instantiate a Specviz Helper via:
from jdaviz import Specviz
# Instantiate an instance of Specviz
specviz = Specviz()
# Display Specviz
specviz.show()
You can use the methods x_limits()
and
y_limits()
to modify the field of
view of Specviz. You can provide a scalar (which assumes the units of the loaded spectra),
a Quantity
, or 'auto'
to automatically scale:
from astropy import units as u
specviz.x_limits()
specviz.x_limits(650*u.nm,750*u.nm)
specviz.y_limits('auto', 110.0)
Additionally, you can provide the limit methods with a SpectralRegion
. Specviz shall set the bounds the upper and lower bounds of the SpectralRegion:
from specutils import SpectralRegion
bounds = SpectralRegion(0.45*u.nm, 0.6*u.nm)
specviz.x_limits(bounds)
You can also quickly return to the default zoom using
autoscale_x()
and
autoscale_y()
.
To quickly flip an axis to change to and from ascending/descending, use
flip_x()
and
flip_y()
.
Defining Spectral Regions
Spectral regions can be defined by clicking on the icon at the right of the
viewer toolbar.
To select a region of interest, move the cursor to one of the end points (in wavelength) of the region you want to select, and drag it to the other end point. The selected region background will display in light gray color, and the spectral trace in color, coded to subset number and listed under the subsets dropdown.
Clicking on that selector, you can add more regions by selecting the “create new” entry.
From the API, you can use the get_spectral_regions()
method:

Line Selection
This button will allow you to click and select a vertical line when multiple lines from a line list are over-plotted. Futher analysis can be performed on this line of interest.
See also
- Line Lists
Documentation on using line lists within Specviz.
Plot Settings
To access plot settings for a particular viewer (including the spectrum viewer),
click the icon in the viewer toolbar or open the
Plot Options plugin.
Layer
The top section of the Layer tab contains options to change the color
of the spectrum (click the icon to see a color change menu),
change visibility of the spectrum (
icon), and a dropdown box to select
which layer will have its settings changed.
Line Width
Width of the line for the spectrum in pixels. Larger values are thicker lines on the plot.
Line Opacity
Opacity of the line. Maximum (1) is fully opaque and minimum (0) is fully transparent.
Plot profile as steps
Toggle on to view the spectrum as a continuous line or a step function.
Plot uncertainties
Toggle on to view uncertainties attached to the spectrum, if any.
plot_options = specviz.plugins['Plot Options']
plot_options.uncertainty_visible = True
Data Analysis Plugins
The Specviz data analysis plugins are meant to aid quick-look analysis
of 1D spectroscopic data. All plugins are accessed via the plugin
icon in the upper right corner of the Specviz application. These plugins are
built upon :ref:specutils
to do the actual analysis work

Any spectra generated by plugins (e.g., Gaussian Smooth) will generally be automatically displayed in the spectral viewer, and one can always see the spectra available and toggle their visibility in the data selection dropdown menu (see Selecting Data Set for more detail). If you are working in the notebook, you can also enable more reproducible analysis by using the Python API.
Metadata Viewer
See also
- Metadata Viewer
Imviz documentation on using the metadata viewer.
Plot Options
See also
- Spectral Plot Options
Documentation on further details regarding the plot setting controls.
Subset Tools
See also
- Subset Tools
Imviz documentation describing the concept of subsets in Jdaviz.
Gaussian Smooth
Gaussian Smooth is performed on a Spectrum1D data object. The spectrum is convolved with a Gaussian function. The Gaussian standard deviation in pixels must be entered into the Standard deviation field in the plugin.
A new Spectrum1D object is generated and is added to the spectrum viewer. It can be selected and shown in the viewer via the Data icon in the viewer toolbar.
Model Fitting

Astropy models can be fit to a spectrum via the Model Fitting plugin. Model components are selected via the Model Component pulldown menu. The Add Component button adds a Model Components block.
Model Parameters are automatically initialized with a guess. These starting values can be edited by the user. They may also be fixed by selecting the checkbox, so that they are not fit or changed by the model fitting.
A mathematical expression must be entered into the Equation Editor to specify the mathematical combination of models. This is also necessary even if there is only one model component. The model components are specified by their labels and the equation defaults to the sum of all created components, but can be modified to exclude some of components without needing to delete them entirely or to change to subtraction, for example.
After fitting, the expandable menu for each component model will update to show the fitted value of each parameter rather than the initial value, and will additionally show the standard deviation uncertainty of the fitted parameter value if the parameter was not set to be fixed to the initial value.
See also
- Export Models
Documentation on exporting model fitting results.
Unit Conversion
The spectral flux density and spectral axis units can be converted using the Unit Conversion plugin. The Spectrum1D object to be converted is the currently selected spectrum in the spectrum viewer Data icon in the viewer toolbar.
Select the frequency, wavelength, or energy unit in the New Spectral Axis Unit pulldown (e.g. Angstrom, Hertz, erg).
Select the flux density unit in the New Flux Unit pulldown (e.g. Jansky, W/(Hz/m2), ph/(Angstrom cm2 s)).
The Apply button will convert the flux density and/or spectral axis units and create a new Spectrum1D object that is automatically switched to in the spectrum viewer. The name of the new Spectrum1D object is “_units_copy_” plus the flux and spectral units of the spectrum.
Line Lists
Line wavelengths can be plotted in the spectrum viewer using the Line Lists plugin.
Line lists (e.g. Common Stellar, SDSS, CO) can be selected from Preset Line Lists via the Available Line Lists pulldown. They are loaded and displayed by pressing Load List. Each loaded list is shown under Loaded Lines. Loaded line lists may be removed by pressing the circled-x button.

The Loaded Lines include a Custom line list which is automatically created, but populated with no lines. Lines may be added to the Custom line list by entering Line Name, Rest Value, and Unit for the spectral axis and pressing Add Line. Selected lines may be hidden by deselecting the associated check box.
The color of each line list may be adjusted with the color and saturation sliders. Entire line lists may be hidden in the display via Show All and Hide All, located at the bottom of each list. Similarly, all of the line lists may be shown or hidden via Plot All and Erase All, located at the bottom of the plugin.
Importing Custom Line Lists
Jdaviz comes with curated line lists built by the scientific community. If you cannot find the lines you need, you can add your own by constructing an astropy table; For example:
from astropy.table import QTable
from astropy import units as u
my_line_list = QTable()
my_line_list['linename'] = ['Hbeta','Halpha']
my_line_list['rest'] = [4851.3, 6563]*u.AA
viz.load_line_list(my_line_list)
# Show all imported line lists
viz.spectral_lines
Redshift Slider
Warning
Using the redshift slider with many active spectral lines causes performance issues. If the shifting of spectral lines lag behind the slider, try plotting less lines. You can deselect lines using, e.g., the “Erase All” button in the line lists UI.
The plugin also contains a redshift slider which shifts all of the plotted lines according to the provided redshift/RV. The slider applies a delta-redshift, snaps back to the center when releasing, and has limits that default based on the x-limits of the spectrum viewer. This provides a convenient method to fine-tune the position of the redshifted lines to the observed lines in the spectrum.
The range and step size of the slider can be set from a notebook cell using the
set_redshift_slider_bounds()
method in Specviz by specifying the range
or step
keywords, respectively.
Setting either keyword to 'auto'
means its value will be calculated
automatically based on the x-limits of the spectrum plot.
The redshift itself can be set from the notebook using the set_redshift
method.
Any set redshift values are applied to spectra output using the
get_spectra()
helper method.
Note that using the lower-level app data retrieval (e.g.,
specviz.app.get_data_from_viewer()
) will return the data as
originally loaded, with the redshift unchanged.
Line Analysis
The Line Analysis plugin returns specutils analysis for a single spectral line. The line is selected via the region tool in the spectrum viewer to select a spectral subset. Note that you can have multiple subsets in Specviz, but the plugin will only show statistics for the selected subset.
A linear continuum is fitted and subtracted (divided for the case of equivalenth width) before computing the line statistics. By default, the continuum is fitted to a region surrounding the select line. The width of this region can be adjusted, with a visual indicator shown in the spectrum plot while the plugin is open. The thick line shows the linear fit which is then interpolated into the line region as shown by a thin line. Alternatively, a custom secondary region can be created and selected as the region to fit the linear continuum.
The statistics returned include the line centroid, gaussian sigma width, gaussian FWHM, total flux, and equivalent width.
The line flux results are automatically converted to Watts/meter^2, when appropriate.
Redshift from Centroid
Following the table of statistics, the centroid can be used to set the redshift by assigning
the centroid value to a line added in the Line List Plugin. Select the
corresponding line from the dropdown, or by locking the selection to the identified line and
using the (line selector) tool in the spectrum viewer.
Export Plot
This plugin allows a given viewer’s plot to be exported to various image formats.
Exporting Data From Specviz
1D Spectra
After data have been manipulated or analyzed, it is possible to export those data currently back into your Jupyter notebook:
specviz.get_spectra()
which yields a specutils.Spectrum1D
object that you can manipulate however
you wish. You can then load the modified spectrum back into the notebook via
the API described in Importing data via the API.
Alternatively, if you want more control over Specviz, you can access it the
via the lower-level application interface that connects to the glue-jupyter
application level. This is accessed via the .app
attribute of the
Specviz
helper class. For example:
specviz.app.get_data_from_viewer('spectrum-viewer')
To extract a specific spectral subset:
specviz.app.get_data_from_viewer('spectrum-viewer', 'Subset 1')
For more on what you can do with this lower-level object, see the API sections and the glue-jupyter documentation.
See also
- Export From Plugins
Calculations (i.e., not spectroscopic data) from the plugins can also be exported back into the Jupyter notebook in some cases.
Spectral Regions
If you have spectral region subsets, you can extract the parameters of these subsets as a specutils spectral region. For a list of available spectral regions to extract, you can type:
regions = specviz.get_spectral_regions()
regions
To extract the spectral region you want:
myregion = regions["Subset 2"]
Model Fits
For a list of model labels:
models = specviz.get_models()
models
Once you know the model labels, to get a specific model:
mymodel = specviz.get_models(model_label="ModelLabel")
To extract all of the model parameters:
myparams = specviz.get_model_parameters(model_label="ModelLabel")
myparams
where the model_label
parameter identifies which model should be returned.
Examples
Below is a quick introductory tour of the Specviz configuration and its features. To get started, we recommend cloning the Jdaviz repo and running the SpecvizExample notebook.
See also
- Example notebooks
A number of additional example notebooks.
Open a Spectrum
Model Fitting
Line Analysis
Cubeviz

Cubeviz is a visualization and analysis toolbox for data cubes from integral field units (IFUs). It is built as part of the Glue visualization tool. Cubeviz is designed to work with data cubes from the NIRSpec and MIRI instruments on JWST, and will work with IFU data cubes. It uses the specutils package from Astropy .
Cubeviz is a tool for visualization and quick-look analysis of 3D data cubes, primarily from integral field units (IFUs). It incorporates visualization tools with analysis capabilities, such as Astropy regions and specutils packages. Users can interact with their data from within the tool. Cubeviz allows spectra of regions within the cube to be easily plotted and examined, offering all the same capabilities as Specviz.
In addition, Cubeviz also allows users to interacting with their cube to:
view the wavelength slices (RA, DEC),
view flux, error, and data quality cubes simultaneously,
view spectra from selected spatial (RA, DEC) regions,
smooth cubes spatially (RA, DEC) and spectrally (wavelength),
create and display contour maps,
collapse cubes over selected wavelength regions,
fit spectral lines,
create moment maps, including line flux and kinematic maps (rotation velocity and velocity dispersion),
overlay spectral line lists,
save edited cubes,
save figures,
fit models to every spaxel
Using Cubeviz
Importing Data into Cubeviz
By design, Cubeviz only supports data that can be parsed as
Spectrum1D
objects. Despite the name, Spectrum1D
now supports 3D cubes and allows the Python-level interface and parsing tools to
be defined in specutils
instead of being duplicated in Jdaviz.
Spectrum1D
objects are very flexible in their capabilities, however,
and hence should address most astronomical spectrum use cases.
Cubeviz will automatically parse the data into the multiple viewers as described in
Displaying Cubes. For the best experience, data loaded into Cubeviz should contain valid WCS
keywords. For more information on how Spectrum1D
uses WCS, please go to the Spectrum1D defining WCS section.
To check if your FITS file contains valid WCS keywords, please use
Astropy WCS validate
.
For an example on loading a cube with valid WCS keywords, please see the Importing data via the API
section below.
Loading data without WCS is also possible as long as they are compatible
with Spectrum1D
. However, not all plugins will work with this data.
In Cubeviz, two image viewers at the top display your data:
Top Left:flux-viewer
Top Right:uncert-viewer
There is also a third viewer called spectrum-viewer
at the bottom that
will display the collapsed spectrum from flux-viewer
.
Note
Only a single cube can be displayed in an instance of Cubeviz at a given time. To open a second cube, you must first initiate a second instance of Cubeviz.
To then extract your data from Cubeviz, please see the Exporting Data from Cubeviz section.
Importing data through the Command Line
You can load your data into the Cubeviz application through the command line:
jdaviz cubeviz /my/directory/cube.fits
Importing data through the GUI
Users may load data into the Cubeviz application
by clicking the Import Data button at the top left of the application’s
user interface. This opens a dialogue with a prompt to select a file
that can be parsed as a Spectrum1D
object.
After clicking Import, the data file will be parsed and loaded into the application. A notification will appear to confirm whether the data import was successful. Afterward, the new data set can be found in the Data tab of each viewer’s options menu as described in Selecting a Data Set.
Importing data via the API
Alternatively, users who work in a coding environment like a Jupyter
notebook can access the Cubeviz helper class API. Using this API, users can
load data into the application through code with the load_spectrum()
method, which takes as input a Spectrum1D
object.
FITS Files
The example below loads a FITS file into Cubeviz:
from jdaviz import Cubeviz
cubeviz = Cubeviz()
cubeviz.load_data("/path/to/data/file.fits")
cubeviz.show()
Spectrum1D (from file)
For cases where the built-in parser is unable to understand your file format,
you can try the Spectrum1D
parser directly and then pass the object to the
load_data()
method:
from specutils import Spectrum1D
from jdaviz import Cubeviz
spec3d = Spectrum1D.read("/path/to/data/file.fits")
cubeviz = Cubeviz()
cubeviz.load_data(spec3d, data_label='My Cube')
cubeviz.show()
Spectrum1D (from array)
You can create your own Spectrum1D
object by hand to load into Cubeviz:
import numpy as np
from astropy import units as u
from astropy.wcs import WCS
from specutils import Spectrum1D
from jdaviz import Cubeviz
flux = np.arange(16).reshape((2, 2, 4)) * u.Jy
wcs_dict = {"CTYPE1": "WAVE-LOG, "CTYPE2": "DEC--TAN", "CTYPE3": "RA---TAN",
"CRVAL1": 4.622e-7, "CRVAL2": 27, "CRVAL3": 205,
"CDELT1": 8e-11, "CDELT2": 0.0001, "CDELT3": -0.0001,
"CRPIX1": 0, "CRPIX2": 0, "CRPIX3": 0}
w = WCS(wcs_dict)
cube = Spectrum1D(flux=flux, wcs=w)
cubeviz = Cubeviz()
cubeviz.load_data(cube, data_label='My Cube')
cubeviz.show()
JWST datamodels
If you have a jwst.datamodels object, you can load it into Cubeviz as follows:
import numpy as np
import astropy.wcs as fitswcs
from jdaviz import Cubeviz
# mydatamodel is a jwst.datamodels object
# Due to current schema in jwst.datamodels, you'll need to create your own WCS object before you create your Spectrum1D object
wcs_dict = {"CTYPE1": mydatamodel.meta.wcsinfo.ctype3, "CTYPE2": mydatamodel.meta.wcsinfo.ctype2,
"CTYPE3": mydatamodel.meta.wcsinfo.ctype1,
"CRVAL1": mydatamodel.meta.wcsinfo.crval3, "CRVAL2": mydatamodel.meta.wcsinfo.crval2,
"CRVAL3": mydatamodel.meta.wcsinfo.crval1,
"CDELT1": mydatamodel.meta.wcsinfo.cdelt3, "CDELT2": mydatamodel.meta.wcsinfo.cdelt2,
"CDELT3": mydatamodel.meta.wcsinfo.cdelt1,
"CRPIX1": mydatamodel.meta.wcsinfo.crpix3, "CRPIX2": mydatamodel.meta.wcsinfo.crpix2,
"CRPIX3": mydatamodel.meta.wcsinfo.crpix1}
my_wcs = WCS(wcs_dict)
# Next, you need to make sure your spectral axis is the 3rd dimension
data = mydatamodel.data * (u.MJy / u.sr)
data = np.swapaxes(data, 0, 1)
data = np.swapaxes(data, 1, 2)
# Create your spectrum1
spec3d = Spectrum1D(data, wcs=my_wcs)
cubeviz = Cubeviz()
cubeviz.load_spectrum(spec3d, data_label='My Cube')
cubeviz.show()
There is no plan to natively load such objects until datamodels
is separated from the jwst
pipeline package.
Numpy array
To load a plain Numpy array without WCS:
import numpy as np
from jdaviz import Cubeviz
flux = np.arange(16).reshape((2, 2, 4)) # x, y, z
cubeviz.load_data(flux, data_label='My Cube')
cubeviz.show()
Importing regions via the API
If you have a region file supported by Reading/Writing Region Files, you can load the regions into Cubeviz as follows:
cubeviz.load_regions_from_file("/path/to/data/myregions.reg")
Unsupported regions will be skipped and trigger a warning. Those that
failed to load, if any, can be returned as a list of tuples of the
form (region, reason)
:
bad_regions = cubeviz.load_regions_from_file("/path/to/data/myregions.reg", return_bad_regions=True)
Note
Sky regions are currently unsupported in Cubeviz, unlike Imviz.
For more details on the API, please see
load_regions_from_file()
and load_regions()
methods
in Cubeviz.
Displaying Cubes
The Cubeviz layout includes two image viewers (at the top of the app) and one spectrum viewer (at the bottom of the app), which it attempts to populate automatically when the first dataset is loaded. By default, Cubeviz attempts to parse and display the flux in the top left viewer, the uncertainty in the top right viewer. The spectrum viewer is populated by default by collapsing the spatial axes using the “Sum” function. The indicators that the load machinery looks for in each HDU to populate the viewers are below (note that in all cases, header values are converted to lower case):
Flux viewer:
hdu.name
is in the set['flux', 'sci']
Uncertainty viewer:
hdu.header.keys()
includes “errtype” orhdu.name
is in the set['ivar', 'err', 'var', 'uncert']
Loaded but not displayed:
hdu.data.dtype
isint
,numpy.uint
ornumpy.uint32
, orhdu.name
is in the set['mask', 'dq']
The next section describes how to manually select data in cases where a viewer is not automatically populated or a user wants to change the data displayed. Different statistics for collapsing the spectrum displayed in the spectrum viewer can be chosen as described in Display Settings. Note that any spatial subsets will also be collapsed into a spectrum using the same statistic and displayed in the spectrum viewer along with the spectrum resulting from collapsing all the data in each spectral slice.
Much of the Cubeviz functionality can be handled within the tool or the Jupyter notebook using an API. The Toolbar below gives you several spectroscopic display options. Right click will open a dropdown with access to different options for each button.

Selecting a Data Set
If you have already imported data into Cubeviz, you can select and deselect data within a viewer.
See also
- Selecting a Data Set
Documentation on selecting data sets in the Jdaviz viewers.
Home
This button will reset your zoom and panning to display the entire image.
Box Zoom and Linked Box Zoom
See also
- Box Zoom and Linked Box Zoom in Imviz
Documentation on panning and zooming in Imviz.
Pan/Zoom and Linked Pan/Zoom
See also
- Pan/Zoom and Linked Pan/Zoom in Imviz
Documentation on panning and zooming in Imviz.
Note
Pan/Zoom API and click-to-center feature in Imviz is not yet available on Cubeviz.
Defining Spatial Regions
See also
- Defining Spatial Regions
Documentation on defining spatial regions in an image viewer.
Spatial regions allow users to select subsets of the data array for specific analysis function in the plugin toolbar. Users can create spatial regions either in Cubeviz or the Jupyter notebook. Once a region is selected, the cube will be collapsed in wavelength space over the region, and the resulting spectrum will be displayed in the 1D spectrum viewer at the bottom of the UI.

Spectrum At Spaxel
This tool allows the user to create a one spaxel subset in an image viewer. This subset will then be visualized in the spectrum viewer by showing the spectrum at that spaxel. Activate this tool and then left-click to create the new region. Click again to move the region to a new location under the cursor. Holding down the alt key (Alt key on Windows, Option key on Mac) while clicking on a spaxel creates a new subset at that point instead of moving the previously created region. You can then compare spectra at different spaxels using the spectrum viewer. You can also use the subset modes that are explained in the Spatial Regions section above in the same way you would with the other subset selection tools.
Display Settings
See also
- Display Settings
Documentation on various display settings in the jdaviz viewers.
To access all of the different display settings for an image viewer, click the
icon in the viewer toolbar or open the Plot Options plugin.
Changing the display settings does not change the underlying data, only the
visualization of that data.
Displaying Spectra
A collapsed spectrum of the cube displayed in the upper-left viewer
automatically appears in the 1D spectrum viewer, using the Maximum
collapse method. The collapse method can be changed in the Viewer
tab of the icon in the spectrum viewer. Additional spectra
can be loaded into the spectrum viewer, as detailed in the linked documentation
below.
See also
- Displaying Spectra (Specviz)
Documentation on displaying spectra in a 1D spectrum viewer.
There is one important difference when using the API to access Specviz from within Cubeviz.
The functionality of the jdaviz.configs.specviz.helper.Specviz
API can be accessed in Cubeviz via
the specviz
attribute, e.g. cubeviz.specviz.get_spectra()
.
Data Analysis Plugins
The Cubeviz data analysis plugins are meant to aid quick-look analysis of 2D image data. All plugins are accessed via the plugin icon in the upper right corner of the Cubeviz application.

The data analysis plugins are meant to aid quick-look analysis
of both 3D and 1D spectroscopic data. In many cases, functions can be applied to
Spectrum1D
objects, which include both 3D and 1D datasets.
Plugins that are specific to 1D spectra are described in
more detail under Specviz: Data Analysis Plugins.
In many cases, these capabilities can be further applied on a per spaxel basis
within a cube.
Metadata Viewer
See also
- Metadata Viewer
Documentation on using the metadata viewer.
Plot Options
This plugin gives access to per-viewer and per-layer plotting options.
See also
- Image Plot Options
Documentation on Imviz display settings in the Jdaviz viewers.
See also
- Spectral Plot Options
Documentation on Specviz display settings in the Jdaviz viewers.
Subset Tools
See also
- Subset Tools
Imviz documentation describing the concept of subsets in Jdaviz.
Slice
The slice plugin provides the ability to select the slice of the cube currently visible in the image viewers, with the corresponding wavelength highlighted in the spectrum viewer.
The slider can be grabbed to scrub through the cube. To choose a specific slice, enter a slice number (integer) or an approximate wavelength (in which case the nearest slice will be selected and the wavelength entry will update to the exact value of that slice).
The spectrum viewer also contains a tool to allow clicking and dragging in the spectrum plot to choose the currently selected slice. When the slice tool is active, clicking anywhere on the spectrum viewer will select the nearest slice across all viewers, even if the indicator is off-screen.
For your convenience, there are also player-style buttons with the following functionality:
Jump to first
Play/Pause
Next slice
Jump to last
Gaussian Smooth
Gaussian smoothing can be applied either to the spectral or spatial dimensions of a cube.
See also
- Gaussian Smooth
Specviz documentation on gaussian smoothing in the spectral dimension of 1D spectra.
Collapse

The Collapse plugin collapses a spectral cube along the wavelength axis to create a 2D spatial image. For spatial axes, the full extent of the selected dimension is included in the collapse. For the spectral axis, a wavelength range for collapse can be specified using a spectral subset or by entering the wavelength range manually.
To make a 2D image, first go to the Collapse plugin and select the cube dataset using the Data pulldown. Next, select the method for collapse (Mean, Median, Min, Max, or Sum) in the Method pulldown. To collapse a limited spectral subregion, you can either create and select a Region in the spectrum viewer, or enter the lower and upper spectral bounds manually. When you APPLY the Collapse, a 2D image is created. You can load this into any image viewer pane to inspect the result. For example, the Collapse Sum over an emission line is shown in the middle image viewer of the above figure.
Model Fitting
See also
- Model Fitting
Specviz documentation on fitting spectral models.
For Cubeviz, there is an additional option to fit the model over each individual spaxel by enabling the Cube Fit toggle before pressing Fit Model. The best-fit parameters for each spaxel are stored in planes and saved in a data structure. The resulting model itself is saved with the label specified in the Output Data Label field.
See also
- Export Models
Documentation on exporting model fitting results.
Unit Conversion
See also
- Unit Conversion
Specviz documentation on unit conversion.
Line Lists
See also
- Line Lists
Specviz documentation on line lists.
Line Analysis
See also
- Line Analysis
Specviz documentation on line analysis.
Currently the Line Analysis plugin in Cubeviz will calculate statistics for spectral features in the collapsed spectrum, which is visualized in the spectrum viewer. The propagation of uncertainties from the uncertainty cube to the collapsed spectrum is still work in progress. As a result, uncertainties on values provided by the Line Analysis plugin are not provided.
Moment Maps

The Moment Maps plugin can be used to create a 2D image from a data cube. Mathematically, a moment is an integral of a 1D curve multiplied by the abscissa to some power. The plugin integrates the flux density along the spectral axis to compute a moment map. The order of the moment map (0, 1, 2, …) indicates the power-law index to which the spectral axis is raised. A ‘moment 0’ map gives the integrated flux over a spectral region. Similarly, ‘moment 1’ is the flux-weighted centroid (e.g., line center) and ‘moment 2’ is the dispersion (e.g., wavelength or velocity dispersion) along the spectral axis. Moments 3 and 4 are less commonly utilized, but correspond to the skewness and kurtosis of a spectral feature.
To make a moment map, first go to the Moment Maps plugin and select the cube dataset using the Data pulldown. To specify the spectral feature of interest, you can either create and select a Region in the spectrum viewer, or enter the lower and upper spectral bounds manually in the plugin. Next, enter the Moment index to specify the order of the moment map. When you press CALCULATE, a 2D moment map is created. You can load this into any image viewer pane to inspect the result. You can also save the result to a FITS format file by pressing SAVE AS FITS.
For example, the middle image viewer in the screenshot above shows the Moment 1 map for a continuum-subtracted cube. Note that the cube should first be continuum-subtracted in order to create continuum-free moment maps of an emission line. Moment maps of continuum emission can also be created, but moments other than moment 0 may not be physically meaningful. Also note that the units in the moment 1 and moment 2 maps reflect the units of the spectral axis (Angstroms in this case). The units of the input cube should first be converted to velocity units before running the plugin if those units are desired for the output moment maps.
Line or Continuum Maps

There are at least three ways to make a line map using one of three Cubeviz plugins: Collapse, Moment Maps, or Model Fitting. Line maps created using the first two methods require an input data cube that is already continuum-subtracted. Continuum maps can be created in a similar way for data that is not continuum-subtracted.
To make a line or continuum map using the Collapse Plugin, first import a data cube into Cubeviz. Next, go to the Collapse plugin and select the input data using the Data pulldown. Then set the Axis to the wavelength axis (e.g. 0 for JWST data) and the method to ‘Sum’ (or any other desired method). Next either create and select a Region in the spectrum viewer, or enter the lower and upper spectral bounds manually. When you Apply the Collapse, a 2D image of the spectral region is created. You can load this line map in any image viewer pane to inspect the result.
A line map can also be created using the Moment Maps Plugin using a similar workflow. Select the (continuum-subtracted) dataset in the Plugin using the Data pulldown. Then either select a subset in the Spectral Region pulldown or enter the lower and upper spectral bounds. Enter ‘0’ for Moment and press Calculate to create the moment 0 map. The resultant 2D image is the flux integral of the cube over the selected spectral region, and may be displayed in any image viewer, as shown in the middle image viewer in the figure above.
The third method to create a map is via the Model Fitting Plugin. First create and fit a model (e.g. a Gaussian plus continuum model) to an individual spectrum. Next, fit this model to every spaxel in your data cube. The resultant model parameter cube can be retrieved in a notebook. The line or continuum flux in each spatial pixel can then be computed by integrating over the line or continuum spectral region of interest.
Export Plot
This plugin allows exporting the plot in a given viewer to various image formats.
Exporting Data from Cubeviz
After data have been manipulated or analyzed, it is possible to export those data currently back into your Jupyter notebook.
Spatial Regions
See also
- Export Spatial Regions
Documentation on how to export spatial regions.
Since Specviz can be accessed from Cubeviz, the following line of code can be used to extract the spectrum of a spatial subset named “Subset 1”:
subset1_spec1d = cubeviz.specviz.get_spectra("Subset 1")
An example without accessing Specviz:
subset1_spec1d = cubeviz.app.get_data_from_viewer("flux-viewer", data_label="Subset 1")
To get all subsets from the spectrum viewer:
subset1_spec1d = cubeviz.app.get_subsets_from_viewer("spectrum-viewer")
To access the spatial regions themselves:
regions = cubeviz.get_interactive_regions()
regions
1D Spectra and Spectral Regions
See also
- Export Spectra
Documentation on how to export data from the
spectrum-viewer
.
The following line of code can be used to extract a spectral subset named “Subset 2”:
subset2_spec1d = cubeviz.specviz.get_spectra("Subset 2")
2D Images and 3D Data Cubes
2D images and 3D data cubes can be extracted from their respective
viewers. The viewer options in the Cubeviz configuration are
flux-viewer
, uncert-viewer
, and mask-viewer
.
For example, to list the data available in a particular viewer:
mydata = cubeviz.app.get_data_from_viewer("flux-viewer")
To extract the data you want (replace “data_name” with the name of your data):
mydata = cubeviz.app.get_data_from_viewer("uncert-viewer", "data_name")
The data is returned as a glue-jupyter
object. To convert to a numpy array:
mydata_flux = mydata["flux"]
To retrieve the data cube as a specutils.Spectrum1D
object, you can do the following:
from specutils import Spectrum1D
mydata.get_object(cls=Spectrum1D, statistic=None)
Alternatively, you can wrap this all into a single command:
mydata = cubeviz.app.get_data_from_viewer("uncert-viewer", "data_name")
Data can also be accessed directly from data_collection
using the following code:
cubeviz.app.data_collection[0]
Which is returned as a Data
object. The
DataCollection
object
can be indexed to return all available data (i.e., not just using 0 like in the
previous example).
Model Fits
For a list of model labels:
models = cubeviz.get_models()
models
Once you know the model labels, to get a specific model:
mymodel = cubeviz.get_models(model_label="ModelLabel", x=10)
To extract all of the model parameters:
myparams = cubeviz.get_model_parameters(model_label="ModelLabel", x=x, y=y)
myparams
where the model_label
parameter identifies which model should be returned and
the x
and y
parameters identify specifically which spaxel fits are to be returned,
for models applied to every spaxel using the Apply to Cube button.
Leaving x
or y
as None
will mean that the models fit to every spaxel
across that axis will be returned.
Examples
Below is a quick introductory tour of the Cubeviz configuration and its features. To get started, we recommend cloning the Jdaviz repo and running the CubevizExample notebook.
See also
- Example notebooks
A number of additional example notebooks.
Open and Explore a Cube
Selecting Subsets
Model Fitting
Line Analysis
Specviz2D
Specviz2d is a tool for visualization and quick-look analysis of 2D astronomical spectra. It incorporates visualization tools with analysis capabilities, such as Astropy regions and specreduce and specutils packages.
Using Specviz2D
Importing Data Into Specviz2D
By design, Specviz2D only supports data that can be parsed as Spectrum1D
objects,
as that allows the Python-level interface and parsing tools to be defined in specutils
instead of being duplicated in Jdaviz.
Spectrum1D
objects are very flexible in their capabilities, however,
and hence should address most astronomical spectrum use cases.
See also
- Reading from a File
Specutils documentation on loading data as
Spectrum1D
objects.
Specviz2D can either take both a 2D and 1D spectrum as input, or can automatically extract a 1D spectrum if only a 2D spectrum is provided. To view the extraction parameters and override the extraction, see the spectral extraction plugin.
Importing data through the Command Line
You can load your data into the Specviz2D application through the command line (NOTE: this currently only supports passing a 2D spectrum object and will automatically extract the 1D spectrum):
jdaviz specviz2d /my/directory/spectrum.fits
Importing data through the GUI
You can load your data into the Specviz2D application
by clicking the Import Data button at the top left of the application’s
user interface. This opens a dialogue where the user can select a file
that can be parsed as a Spectrum1D
.
After clicking Import, the data file will be parsed and loaded into the application.
Importing data via the API
Alternatively, users who work in a coding environment like a Jupyter
notebook can access the Specviz2D helper class API. Using this API, users can
load data into the application through code with the
load_data()
method, which takes as input a Spectrum1D
object or filename for the
2D spectrum and (optionally) the 1D spectrum.
By default, extension 1 of the 2D
file is loaded, but you can specify another extension by providing an integer
to the ext
keyword. In case you want to load an uncalibrated spectrum
that is dispersed vertically, you can also set the transpose
keyword to flip
the spectrum to be horizontal:
specviz2d.load_data(fn, ext=7, transpose=True)
Displaying Spectra
Specviz2D consists of a 2D spectrum viewer and a 1D spectrum viewer, with linked x-axes. Each viewer window contains a toolbar, including a data menu.
See also
- Specviz: Displaying Spectra
Specviz documentation on the spectrum viewer.
Data Analysis Plugins
The Specviz2D data analysis plugins are meant to aid quick-look analysis of 2D spectroscopic data. All plugins are accessed via the plugin icon in the upper right corner of the Specviz application.
Metadata Viewer
See also
- Metadata Viewer
Imviz documentation on using the metadata viewer.
Plot Options
See also
- Plot Options
Specviz documentation on the plot options plugin.
Subset Tools
See also
- Subset Tools
Imviz documentation describing the concept of subsets in Jdaviz.
Spectral Extraction
The Spectral Extraction plugin exposes specreduce methods for tracing, background subtraction, and spectral extraction from 2D spectra.
To interact with the plugin via the API in a notebook, access the plugin object via:
sp_ext = viz.app.get_tray_item_from_name('spectral-extraction')
Trace
The first section of the plugin allows for creating and visualizing
specreduce.tracing.Trace
objects.
Once you interact with any of the inputs in the extract step or hover over that area of the plugin, the live visualization will change to show the trace as a solid line in the 2D spectrum viewer.
To create a new trace in the plugin, choose the desired “Trace Type” and edit any input arguments. A preview of the trace will update in real time in the 2D spectrum viewer.
To export the trace as a data object into the 2D spectrum viewer (to access via the API or to adjust plotting options), open the “Export Trace” panel, choose a label for the new data entry, and click “Create”. Note that this step is not required to create an extraction with simple workflows.
Trace objects created outside of jdaviz can be loaded into the app via load_trace()
:
viz.load_trace(my_trace, data_label="my trace")
and then added to the viewer through the data menu.
Suppose you have 2D spectra of an extended source, and you have already created a trace that follows the bright central region of the source. It is possible to create a new trace, with the same 2D shape as the trace of the central region, but offset in the spatial direction. This might be useful for extracting spectra from the faint outer regions of the extended source, while using a trace computed from the brighter inner region. You can create a new trace based on the existing trace by clicking the “Trace” dropdown and selecting the existing trace. Then, offset it in the spatial direction by clicking or entering the spatial offset, and save it by creating a new trace or overwriting the existing trace entry.
To export and access the specreduce Trace object defined in the plugin, call
export_trace()
:
trace = sp_ext.export_trace()
To import the parameters from a specreduce Trace object, whether it’s new or was exported and modified in the notebook, call import_trace()
:
sp_ext.import_trace(trace)
Background
The background step of the plugin allows for creating background and background-subtracted
images via specreduce.background
.
Once you interact with any of the inputs in the background step or hover over that area of the plugin, the live visualization in the 2D spectrum viewer will change to show the center (dotted line) and edges (solid lines) of the background region(s). The 1D representation of the background will also be visualized in the 1D spectrum viewer (thin, solid line).
Backgrounds can either be created around the trace defined in the earlier Trace section or around a new, flat trace by selecting “Manual” in the Background Type dropdown.
To visualize the resulting background or background-subtracted image, click on the respective panel, and choose a label for the new data entry. The exported images will now appear in the data dropdown menu in the 2D spectrum viewer, and can be exported into the notebook via the API. To refine the trace based on the background-subtracted image, return to the Trace step and select the exported background-subtracted image as input.
To export and access the specreduce Background object defined in the plugin, call export_bg()
:
bg = sp_ext.export_bg()
To access the background image, background spectrum, or background-subtracted image as a Spectrum1D
object,
call export_bg_img()
,
export_bg_spectrum()
,
or export_bg_sub()
, respectively.
To import the parameters from a specreduce Background object into the plugin, whether it’s new or was exported and modified in the notebook, call import_bg()
:
sp_ext.import_bg(bg)
Extract
The extraction step of the plugin extracts a 1D spectrum from an input 2D spectrum via
specreduce.extract
.
Once you interact with any of the inputs in the extract step or hover over that area of the plugin, the live visualization will change to show the center (dotted line) and edges (solid lines) of the extraction region.
The input 2D spectrum defaults to “From Plugin”, which will use the settings defined in the Background step to create a background-subtracted image without needing to export it into the app itself. To use a different 2D spectrum loaded in the app (or exported from the Background step), choose that from the dropdown instead. To skip background subtraction, choose the original 2D spectrum as input.
To visualize or export the resulting 2D spectrum, provide a data label and click “Extract”. The resulting spectrum object can be accessed from the API in the same way as any other data product in the spectrum viewer.
To export and access the specreduce extraction object defined in the plugin, call export_extract()
:
ext = sp_ext.export_extract()
To access the extracted spectrum as a Spectrum1D
object, call export_extract_spectrum()
.
To import the parameters from a specreduce extraction object (either a new object, or an exported one modified in the notebook) into the plugin, call import_extract()
:
sp_ext.import_extract(ext)
Note
Horne extraction uses uncertainties on the input 2D spectrum. If the spectrum uncertainties are not explicitly assigned a type, they are assumed to be standard deviation uncertainties.
Gaussian Smooth
See also
- Gaussian Smooth
Specviz documentation on Gaussian Smooth.
Model Fitting
See also
- Model Fitting
Specviz documentation on Model Fitting.
Unit Conversion
See also
- Unit Conversion
Specviz documentation on Unit Conversion.
Line Lists
Note
The line lists plugin is currently disabled if the 1D spectrum was automatically extracted and/or the 1D spectrum’s x-axis is in pixels.
See also
- Line Lists
Specviz documentation on Line Lists.
Line Analysis
Note
The line analysis plugin is currently disabled if the 1D spectrum was automatically extracted and/or the 1D spectrum’s x-axis is in pixels.
See also
- Line Analysis
Specviz documentation on Line Analysis.
Export Plot
This plugin allows exporting the plot in a given viewer to various image formats.
Exporting Data From Specviz2D
2D Spectra
Images in the 2D spectrum viewer can be exported as specutils.Spectrum1D
objects into
the notebook:
specviz2d.app.get_data_from_viewer('spectrum-2d-viewer')
which returns a dictionary, with the loaded data labels as keywords and specutils.Spectrum1D
objects as values. To return only a single specutils.Spectrum1D
object, pass the data label:
specviz2d.app.get_data_from_viewer('spectrum-2d-viewer', 'my-data-label')
1D Spectra
Similarly, the 1D spectrum data objects can be exported into the notebook:
specviz2d.app.get_data_from_viewer('spectrum-viewer')
or:
specviz2d.app.get_data_from_viewer('spectrum-viewer', 'my-data-label')
An instance of Specviz can also be accessed, which exposes some helper methods from Specviz:
specviz2d.specviz.get_spectra()
See also
- Specviz: Export Data
Specviz documentation on exporting spectra.
Mosviz

Mosviz is a quick-look analysis and visualization tool for multi-object spectroscopy (MOS). It is designed to work with pipeline output: spectra and associated images, or just with spectra. Mosviz is created to work with data from any telescope/instrument, but is built with the micro-shutter assembly (MSA) on the JWST/NIRSpec spectrograph and the JWST/NIRCam imager in mind. As such, Mosviz has some features specific to NIRSpec and NIRCam data.
The NIRSpec MSA can produce ~100 spectra per pointing. Many users will perform surveys with the MSA that will result in data sets containing many spectra. This tool allows users to inspect the locations of astronomical sources within shutters, the location of background apertures in the observed field, the quality of the 2D spectra, and the quality of the 1D extracted spectra. It also often involves simple interactive measurements of quantities such as wavelengths, velocities, line fluxes, widths.
Quickstart
To load a sample NIRISS Nirspec Data Set into Mosviz
in the standalone app, unzip the downloaded zip file and run:
jdaviz mosviz /path/to/mosviz_nirspec_data_0.3/level3
Or to load in a Jupyter notebook, see the MosvizExample notebook or MosvizNIRISSExample notebook.
Using Mosviz
Importing Data into Mosviz
Mosviz provides two different ways to load data: auto-recognition directory loading and manual loading.
Automatic Directory Loading
Mosviz provides instrument-specific directory parsers for select instruments. At this time, Mosviz supports automatic parsing for the following instruments:
JWST NIRSpec (levels 2 and 3)
JWST NIRISS
JWST NIRCam
The NIRSpec parser expects a directory with either level 2 files:
*_cal.fits
: Single file containing level 2 2D spectra for all objects.*_x1d.fits
: Single file containing level 2 1D spectra for all objects.
or level 3 files:
*_s2d.fits
: N files containing level 3 2D spectra, where N is the number of objects.*_x1d.fits
: N files containing level 3 1D spectra, where N is the number of objects.
In either the level 2 or 3 case, the NIRSpec data directory may contain a sub-directory
named images
, cutouts
, or mosviz_cutouts
. This sub-directory should contain FITS files
containing images corresponding to each target, which may be sourced from a non-JWST telescope.
The NIRISS parser expects a directory with the following types of files:
*_i2d.fits
: Level 3 2D images from thecalwebb_image3
imaging pipeline*_cat.ecsv
: Level 3 source catalog from thecalwebb_image3
imaging pipeline (For best performance, it’s recommended that your directory only contain one.)*_cal.fits
: Level 2 2D spectra in vertical (R) and horizontal (C) orientations from thecalwebb_spec2
spectroscopic pipeline (C spectra are shown first in 2D viewer by default.)*_x1d.fits
: Level 2 1D spectra in vertical (R) and horizontal (C) orientations from thecalwebb_spec2
spectroscopic pipeline (C spectra are shown first in 1D viewer by default.)
The NIRCam parser expects *_cal.fits
and *_x1d
files in the same format as the NIRISS parser.
In a Jupyter context (notebook or Lab), you must specify the instrument with a directory as such:
from jdaviz import Mosviz
mosviz = Mosviz()
mosviz.load_data(directory="path/to/my/data", instrument="nirspec")
mosviz.show()
or for NIRISS:
mosviz.load_data(directory="path/to/my/data", instrument="niriss")
Similarly, an instrument keyword can be specified by the command line. For NIRSpec:
jdaviz mosviz /path/to/my/data --instrument=nirspec
and for NIRISS:
jdaviz mosviz /path/to/my/data --instrument=niriss
If a directory is input in either case without specifying an instrument, Mosviz will raise an error.
Manual Loading
If an automatic parser is not provided yet for your data, Mosviz provides manual loading by
specifying which files are which, and the associations between them. This is done by
generating three lists containing the filenames for the 1D spectra,
2D spectra, and images in your dataset. These three lists are taken as arguments
by load_data()
. The association between files is
assumed to be the order of each list (e.g., the first object consists of the first filename
specified in each list, the second target is the second in each list, and so forth).
Currently, manual loading is supported in the Jupyter context only.
An example is given below, where file_dir
is a
directory that contains all the files for the dataset to be loaded:
from jdaviz import Mosviz
mosviz = Mosviz()
spectra_1d = ['target1_1d.fits', 'target2_1d.fits']
spectra_2d = ['target1_2d.fits', 'target2_2d.fits']
images = ['target1_img.fits', 'target2_img.fits']
mosviz.load_data(spectra_1d, spectra_2d, images)
mosviz.show()
Displaying Spectra
The spectra linked to the source selected in the table viewer will be automatically displayed in the viewers, with 2d spectra populating the top right viewer, and 1d spectra populating the viewer 2nd from top on the right.
See also
- Display Spectra
Specviz documentation on displaying spectra.
The functionality of the Specviz API can be accessed in Mosviz via
the specviz
attribute, e.g.,
mosviz.specviz.get_spectra()
.
Pan/Zoom
For an overview on general pan/zoom functionality, please see Pan/Zoom and Linked Pan/Zoom
Mosviz assumes the 1D and 2D spectra objects share a relationship in spectral space. As a result, the 1D and 2D spectral viewers have their spectral axes (the horizontal x-axis) linked. As you pan and zoom in spectral space (horizontally) in either of the two spectral viewers, the other will follow, simultaneously panning and zooming by the same amounts.
Warning
If you pan too far away from the bounds of the dataset provided in the 1D or 2D spectral viewers, a warning will be displayed to notify the user. If you go too far, there is a risk of desynchronizing the two viewers.
Defining Spectral Regions
For an overview on spectral regions, please see Defining Spectral Regions
Plot Settings
Plot settings for the 1d spectrum viewer can be found in the Specviz section.
See also
- Plot Settings
Specviz documentation on plot settings for a 1d spectrum viewer.
Display settings for the 2d spectrum viewer can be found in the Cubeviz section.
See also
- Display Settings
Cubeviz documentation on display settings for an image viewer (2d spectrum viewer in this case).
Data Analysis Plugins
The Mosviz data analysis plugins include operations on both 2D images and Spectrum1D one dimensional datasets. Plugins that are specific to 1D spectra are described in more detail under Specviz:Data Analysis Plugins. All plugins are accessed via the plugin icon in the upper right corner of the Mosviz application.
Metadata Viewer
This plugin allows viewing of any metadata associated with the selected data.
If the data is loaded from multi-extension FITS that contains a primary header, you will also see a Show primary header toggle, when enabled, would display just the primary header metadata.
Export Plot
This plugin allows exporting the plot in a given viewer to various image formats.
Plot Options
This plugin gives access to per-viewer and per-layer plotting options.
Subset Tools
See also
- Subset Tools
Imviz documentation describing the concept of subsets in Jdaviz.
Gaussian Smooth
Gaussian smoothing of a spectrum is described under Specviz:Data Analysis Plugins:Gaussian Smoothing.
See also
- Gaussian Smooth
Specviz documentation on gaussian smoothing of 1D spectra.
Model Fitting
The Model Fitting plugin is described in more detail by the Specviz:Data Analysis Plugins:Model Fitting documentation.
See also
- Model Fitting
Specviz documentation on fitting spectral models.
Line Lists
See also
- Line Lists
Specviz documentation on line lists.
Warning
Using the redshift slider with many active spectral lines causes performance issues. If the shifting of spectral lines lag behind the slider, try plotting less lines. You can deselect lines using, e.g., the “Erase All” button in the line lists UI.
As in Specviz, the Line Lists Plugin includes a slider to adjust the redshift or radial velocity. In Mosviz, this is applied to the current row in the table and is stored (and shown) in a column of the table.
See also
- Setting Redshift/RV
Setting Redshift/RV from the Notebook in Mosviz.
Line Analysis
See also
- Line Analysis
Specviz documentation on line analysis.
Slit Overlay
A slit can be added to the image viewer by opening the Slit Overlay plugin and clicking the Apply button. The Remove button can be used to remove a slit once it has been applied to the image viewer.
In order to plot a slit onto the image viewer, we need WCS information from an image and slit position from a 2D spectrum.
The slit position is calculated using the S_REGION
header extension value, located in the
meta
attribute of the Spectrum1D
object
that is active in the 2D spectrum viewer.
Setting Redshift/RV
The Line Lists Plugin contains a redshift slider as well as the ability to view and set the redshift and/or radial velocity.
Additionally, the Line Analysis Plugin includes the capability to compute and assign the redshift based on the measured centroid of a line.
From the notebook
In the notebook, the value of the Redshift column can be changed for all rows or a single row
using update_column()
.
The 1D and 2D spectrum objects can be retrieved (with redshift optionally applied) using
get_spectrum_1d()
and get_spectrum_2d()
,
respectively.
See the notebooks/MosvizNIRISSExample.ipynb
notebook in the
repository to see examples of
manipulating MOS Table data, including the redshift.
Using Mosviz in a Jupyter Notebook
To initialize an instance of the Mosviz app in a Jupyter notebook, simply run the following code in a cell of the notebook:
from jdaviz import Mosviz
mosviz = Mosviz()
mosviz.show()
After running the code above, you can interact with the Mosviz application from
subsequent notebook cells via the API methods attached to the
Mosviz
object,
for example loading data into the app as described in Importing Data into Mosviz.
See also
- Cubeviz data export
Cubeviz documentation on data exporting.
The Mosviz
helper class can be used similarly to how
Cubeviz
is used in Exporting Data from Cubeviz.
The viewers in Mosviz that can be used that way are image-viewer
, spectrum-viewer
,
and spectrum-2d-viewer
.
It is also possible to extract the contents of the table viewer using
to_csv
:
mosviz.to_csv(filename="MOS_data.csv", selected=False)
Which will save the data from the Mosviz table into the given CSV filename.
If the selected
keyword is set to True
, only the checked
rows in the table will be output. A previous CSV file of the same name can
be overwritten by setting the overwrite
keyword to True
.
The contents of table-viewer
can also be extracted to a notebook cell by
running to_table()
:
mosviz.to_table()
Accessing Plugin APIs
Each plugin object is wrapped by a public user API which enables interacting with the plugin from
the notebook directly. The plugin API object for each plugin is accessible through viz.plugins
.
For example:
plugin = viz.plugins['Plot Options']
plugin.open_in_tray()
plugin.show('popout')
Saving the State of Your Jdaviz Session
While Jdaviz has no Save button, the various data products created within Jdaviz can be exported to the notebook and, ultimately, saved locally using standard Python write commands. This is the suggested workflow to ensure reproducibility in your analysis without having to retrace your steps in Jdaviz each time you run a notebook. We also encourage users to manually record steps in their Jupyter notebook (or anywhere of convenience) with any details that may be of interest when running Jdaviz.
Customizing Notebook Display Layout
By default, calling show()
will display your visualization tool inline in your notebook,
that is the tool will show underneath the notebook cell it was called from:
from jdaviz import Imviz
imviz = Imviz()
imviz.show()
imviz.load_data('filename.fits')
The height of the application in the notebook can be changed by passing an integer
specifying the height in pixels to the height
argument of show
, for example:
imviz.show(height=800)
You can additionally specify the location with the loc
argument.
For example, inline
can be specified manually with:
imviz.show(loc='inline')
Detached Popout
Jdaviz can also be displayed in a detached window, separate from your working Jupyter interface.
Note
Popups must be allowed in your browser to display properly.
The following shows jdaviz
in a new popout window:
imviz.show(loc='popout')
To manually specify the anchor location, append the anchor to popout, separated by a colon:
imviz.show(loc='popout:window')
You can also popout to a new browser tab by specifying a tab
anchor:
imviz.show(loc='popout:tab')
Sidecar (Jupyter Lab)
In Jupyter Lab, sidecar
provides additional methods to customize where to show the viewer
in your workspace. The following shows jdaviz
in the default sidecar location,
to the right of the notebook:
imviz.show(loc='sidecar')
To manually specify the anchor location, append the anchor to sidecar, separated by a colon:
imviz.show(loc='sidecar:right')
Other anchors include: split-right
, split-left
, split-top
, split-bottom
,
tab-before
, tab-after
, right
. An up-to-date list can be found at
jupyterlab-sidecar.
Sample Notebooks
jdaviz
is one tool that is part of STScI’s larger Data Analysis Tools Ecosystem.
These tools include three types of example Jupyter notebooks.
Sample Jdaviz Notebooks that illustrate how to use Jdaviz and various API calls. These notebooks are located in the
notebooks
sub-directory of the git repository.Sample JDAT notebooks that illustrate likely science workflows with data obtained from the various JWST instruments. These notebook incorporate
astropy
and Jdaviz when possible.Sample JWST pipeline notebooks that illustrate how to run the JWST science calibration pipeline.
Reference/API
Developers
Here is some documentation specific for developers.
Package Release Instructions
This document outlines the steps for releasing a versioned Jdaviz package to
PyPI. Currently, these do not cover submitting package updates to other
distribution outlets, such as astroconda
or conda-forge
.
This process currently requires you (the release manager) to have sufficient GitHub
permissions to tag, push, and create a GitHub release on Jdaviz repository. These
instructions assume that the origin
remote points to your personal fork,
and that upstream
points to the
STScI repository.
It is recommended that you lock the main
branch after the “feature freeze”
for the release and only unlock it when release is out on PyPI. Any urgent
pull request that needs to go in after the freeze needs your blessing.
A lock can be as simple as bumping the “reviews required” protection rule
for the main
branch to a very high number; Any rule that will prevent
co-maintainers from merging pull requests without your blessing would do.
If you deem it necessary, you may choose to release a Release Candidate (RC) first before the actual release. In that case, instead of “vX.Y.Z”, it would be “vX.YrcN” (also see PEP 440).
Note
These instructions are adapted from the Astropy package template releasing instructions. Replace “vX.Y.Z” with the actual version tag of the release you are about to make.
Choose your adventure:
Releasing a minor or major version
The automated release infrastructure has proven to be reliable for a good number of releases now, so we’ve been using this faster version as the default release procedure. The longer procedure we previously used is still available in the The old, long way section.
You can do a release from your fork directly without a clean code check-out.
Ensure CI on Actions for main and RTD build for latest are passing.
Lock down the
main
branch of the repository by setting the branch protection rule formain
to some high number required to merge, so that more PRs don’t get merged while you’re releasing.Create a new local branch and make sure you have updated tags too. Note that the “x” here should actually be the letter “x”, whereas the upper case “X” and “Y” should be replace by your major and minor version numbers:
git fetch upstream main
git fetch upstream --tags
git checkout upstream/main -b vX.Y.x
Update the
CHANGES.rst
file to make sure that all the user-facing changes are listed, and update the release date fromunreleased
to current date in theyyyy-mm-dd
format. Remove any empty subsections.Update the
CITATION.cff
file’sdate-released
andversion
fields. If there are new contributors to the project, add them in theauthors
section.Do not forget to commit your changes from the last two steps:
git add CHANGES.rst
git add CITATION.cff
git add .github/workflows/ci_workflows.yml
git commit -m "Preparing release vX.Y.0"
Push the
vX.Y.x
branch to upstream. Make sure the CI passes. If any of the CI fails, especially the job that says “Release”, abandon this way. Stop here; do not continue! Otherwise, go to the next step.Go to Releases on GitHub and create a new GitHub release targeting the new branch you created (not
main
!), and give it a newvX.Y.Z
tag (do not choose any existing tags). Copy the relevant section from CHANGES.rst into the release notes section and clean up any formatting problems.The most important step: Click the
Publish Release
button!Check Release on Actions to make sure that the new GitHub release triggered PyPI upload successfully. Also check that files on PyPI contain both the source tarball and the wheel for that release.
Check RTD builds to make sure that documentation built successfully for both
latest
and the newvX.Y.Z
tag.Check Zenodo page for Jdaviz. It should have picked up the GitHub Release automatically.
The release is basically done, but now you have to set it up for the next release cycle. In your release branch, add a new section above the current release section for the next bugfix release and push it to the new release branch:
A.B.1 (unreleased) ================== Bug Fixes --------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^
Checkout
main
and updateCHANGES.rst
andCITATIONS.cff
directly in that branch using your admin power. If you do not have sufficient access to do that, you will have to update it via a pull request from your fork. Make sure the section for the version just released matches the finalized change log from the release branch you created, and add a new section to the top ofCHANGES.rst
as follows, replacingA.C
with the next non-bugfix version, andA.B
with the version you just released:A.C (unreleased) ================ New Features ------------ Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ API Changes ----------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ Bug Fixes --------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ Other Changes and Additions --------------------------- A.B.1 (unreleased) ================== Bug Fixes --------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^
Commit your changes of the, uh, change log with a message, “Back to development: A.B.dev” and push directly to
main
.Follow procedures for Milestones bookkeeping and Labels bookkeeping.
For your own sanity unrelated to the release, grab the new tag for your fork:
git fetch upstream --tags
Congratulations, you have just released a new version of Jdaviz!
Releasing a bugfix version
Note
Make sure all necessary backports to vX.Y.x
are done before releasing.
Most should have been automatically backported. If you need to manually
backport something still, see Manual backport.
The procedure for a bugfix release is a little different from a feature release - you will
be cherry-picking bugfixes into an existing release branch, and will also need to do some
cleanup on the main
branch.
Lock down the
main
branch of the repository by setting the branch protection rule formain
to some high number required to merge, so that more PRs don’t get merged while you’re releasing.Review the appropriate Milestone to see which PRs should be released in this version.
Checkout the
vX.Y.x
branch corresponding to the last feature release.For any PRs to be released in this bugfix version, find the corresponding merge commit in main, copy the full SHA of that commit, and use git’s cherry-pick command to add those commits to the
vX.Y.x
branch, resolving any conflicts:
git cherry-pick -x -m1 [commit hash]
The
CHANGES.rst
should now have all of the bug fixes to be released. Delete the unreleased feature version section at the top of the changelog (if that was pulled in while cherry-picking) and update the release date of the bugfix release section fromunreleased
to current date in theyyyy-mm-dd
format. Remove any empty subsections.Update the
CITATION.cff
file’sdate-released
andversion
fields. If there are new contributors to the project, add them in theauthors
section.Do not forget to commit your changes from the last two steps:
git add CHANGES.rst
git add CITATION.cff
git commit -m "Preparing release vX.Y.Z"
Push the
vX.Y.x
branch to upstream. Make sure the CI passes. If any of the CI fails, especially the job that says “Release”, abandon this way. Stop here; do not continue! Otherwise, go to the next step.Go to Releases on GitHub and create a new GitHub release targeting the release branch
vX.Y.x
(notmain
!), and give it a newvX.Y.Z
tag (do not choose any existing tags). Copy the relevant section from CHANGES.rst into the release notes section and clean up any formatting problems.The most important step: Click the
Publish Release
button!Check Release on Actions to make sure that the new GitHub release triggered PyPI upload successfully. Also check that files on PyPI contain both the source tarball and the wheel for that release.
Check RTD builds to make sure that documentation built successfully for both
latest
and the newvX.Y.Z
tag.Check Zenodo page for Jdaviz. It should have picked up the GitHub Release automatically.
The release is basically done, but now you have to set it up for the next release cycle. Checkout the
main
branch and updateCHANGES.rst
using your admin power. If you do not have sufficient access to do that, you will have to update it via a pull request from your fork. Make sure the section for the version just released matches the finalized change log from the release branch (be sure to changeunreleased
to the appropriate date), and add a new bugfix release section below the next feature release section as follows, replacingX.Y.Z
with the next minor release number. For example, if you just released3.0.2
, a section for3.0.3
would go below the section for3.1
:X.Y.Z (unreleased) ================== Bug Fixes --------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^
Commit your changes of the, uh, change log with a message, “Back to development: A.B.dev”
Follow procedures for Milestones bookkeeping.
For your own sanity unrelated to the release, grab the new tag for your fork:
git fetch upstream --tags
Congratulations, you have just released a new version of Jdaviz!
Milestones bookkeeping
Go to Milestones.
Create a new milestone for the next release and the next bugfix release, if doing a feature release, or for just the next bugfix release if you just did one.
For the milestone of this release, if there are any open issues or pull requests still milestoned to it, move their milestones to the next feature or bugfix milestone as appropriate.
Make sure the milestone of this release ends up with “0 open” and then close it.
Remind the other devs of the open pull requests with milestone moved that they will need to move their change log entries to the new release section that you have created in
CHANGES.rst
during the release process.
Labels bookkeeping
This is only applicable if you are doing a new branched release.
In the instructions below, A.B
is the old release and A.C
is
the new release:
Go to Labels.
Find the old
backport-vA.B.x
label. Click its “Edit” button and add:zzz:
in front of it. This would send it all the way to the end of labels listing and indicate that it has been retired from usage.Click “New label” (big green button on top right). Enter
backport-vA.C.x
as the label name,on-merge: backport to vA.C.x
as the description, and#5319E7
as the color. Then click “Create label”.
Going forward, any PR that needs backporting to the vA.C.x
branch can
have this label applied before merge to trigger the auto-backport bot on merge.
For more info on the bot, see https://meeseeksbox.github.io/ .
Manual backport
Situations where a pull request might need to be manually backported
after being merged into main
branch:
Auto-backport failed.
Maintainer forgot to apply relevant label to trigger auto-backport (see Labels bookkeeping) before merging the pull request.
To manually backport pull request NNNN
to a vX.Y.x
branch;
abcdef
should be replaced by the actual merge commit hash
of that pull request that you can copy from main
branch history:
git fetch upstream vX.Y.x
git checkout upstream/vX.Y.x -b backport-of-pr-NNNN-on-vX.Y.x
git cherry-pick -x -m1 abcdef
You will likely have some merge/cherry-pick conflict here, fix them and commit. Then push the branch out to your fork:
git commit -am "Backport PR #NNNN: Original PR title"
git push origin backport-of-pr-NNNN-on-vX.Y.x
Create a backport pull request from that backport-of-pr-NNNN-on-vX.Y.x
branch you just pushed against upstream/vX.Y.x
(not upstream/main
).
Title it:
Backport PR #NNNN on branch vX.Y.x (Original PR title)
Also apply the correct label(s) and milestone. If the original pull request
has a Still Needs Manual Backport
label attached to it, you can also
remove that label now.
The old, long way
Note
This section is kept mainly for historical purposes, and to show how many of the things that are now automated can be done manually. Note that it is not up-to-date with the change to a branched release strategy.
This way is recommended if you are new to the process or wish to manually run some automated steps locally. It takes longer but has a smaller risk factor. It also gives you a chance to test things out on a machine that is different from the one used for deployment on GitHub Actions.
It is recommended for you to have a clean checkout of the Jdaviz repository (not the fork), especially if you also do a lot of development work. You can create a clean checkout as follows (requires SSH setup):
mkdir jdaviz_for_release
cd jdaviz_for_release
git clone git@github.com:spacetelescope/jdaviz.git .
git fetch origin --tags
Ensure CI on Actions for main and RTD build for latest are passing.
Update the
CHANGES.rst
file to make sure that all the user-facing changes are listed, and update the release date fromunreleased
to current date in theyyyy-mm-dd
format. Remove any empty subsections.Update the
CITATION.cff
file’sdate-released
andversion
fields. If there are new contributors to the project, add them in theauthors
section. Do not forget to commit your changes from the last two steps:
git add CHANGES.rst
git add CITATION.cff
git commit -m "Preparing release vX.Y.Z"
Remove any untracked files. (WARNING: This will permanently remove any files that have not been previously committed, so make sure that you don’t need to keep any of these files.) This step is not needed if you have a fresh code checkout, but does not hurt either:
git clean -xdf
Tag the version you are about to release and sign it (optional but it is a good practice). Signing requires GPG setup:
git tag -s "vX.Y.Z" -m "Tagging version vX.Y.Z"
Generate the package distribution files by first making sure the following packages are installed and up-to-date:
pip install build twine -U
Creating the source distribution and its wheel with:
python -m build --sdist --wheel .
Do a preliminary check of the generated files:
python -m twine check --strict dist/*
Fix any errors or warnings reported. Skip this step if not applicable.
Run unit tests using package you are about to release. It is recommended that you do this in a fresh Python environment. The following example uses
conda
, so if you use a non-conda
Python environment manager, replace theconda
commands accordingly:
conda create -n testenv python=3.9
conda activate testenv
pip install pytest pytest-astropy pytest-tornasync dist/*.whl
cd ..
python -c "import jdaviz; jdaviz.test(remote_data=True)"
cd jdaviz_for_release
Fix any test failures. Skip this step if not applicable.
Depending on the severity of the fixes above, you might need to submit the fixes as separate PRs and abandon the release. If that is the case, stop here, delete the
vX.Y.Z
tag, and start again from above when those fixes are in themain
branch. If there are no fixes (yay) or if you can justify pushing the fixes as part of this release (not recommended), continue on.Remove files generated by above steps:
git clean -xdf
Make sure code checkout state is clean and history is correct. If not, fix accordingly:
git status
git log
The release is basically done locally, but now you have to set it up for the next release cycle. Add a new section to the top of
CHANGES.rst
as follows, replacingA.B
with the next non-bugfix version:A.B (unreleased) ================ New Features ------------ Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ API Changes ----------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ Bug Fixes --------- Cubeviz ^^^^^^^ Imviz ^^^^^ Mosviz ^^^^^^ Specviz ^^^^^^^ Specviz2d ^^^^^^^^^ Other Changes and Additions ---------------------------
Commit your changes of the, uh, change log:
git add CHANGES.rst
git commit -m "Back to development: A.B.dev"
Push out the updated code and tag. If applicable, change
origin
to point to the remote that points to the repository being released:
git push origin main
git push origin vX.Y.Z
Go to Releases on GitHub and create a new GitHub release off the new
vX.Y.Z
tag.Check Release on Actions to make sure that the new GitHub release triggered PyPI upload successfully. Also check that files on PyPI contain both the source tarball and the wheel for that release.
Check RTD builds to make sure that documentation built successfully for both
latest
and the newvX.Y.Z
tag.Check Zenodo page for Jdaviz. It should have picked up the GitHub Release automatically.
Follow procedures for Milestones bookkeeping.
Congratulations, you have just released a new version of Jdaviz!
Jdaviz Design and Infrastructure
Note
At the time of writing, Jdaviz was still in heavy development. If you notice that this page has fallen behind, please report an issue to the Jdaviz GitHub issues.
This section outlines the top-level structure of Jdaviz. At the highest level, Jdaviz layers different, sometimes changing technologies in the Jupyter platform to do its visualization, and therefore provides a framework for these technologies to work together. This document describes that framework, as well as the high-level sets of components needed for the Jdaviz use cases; it lists the layers of the Jdaviz framework in essentially the order in which they contact users in a typical visualization-heavy workflow. An overview of the layers is in this diagram, and each is described in more details below:
This figure illustrates the basics of Jdaviz design and infrastructure. The top layer contains user-facing applications and supported interfaces. The middle layer encapsulates its component widgets and the visualization libraries involved. The bottom layer consists of low-level data analysis and I/O libraries.
Jdaviz: Interfaces and Applications
Interfaces
“Interfaces” are the tools the user is using to access the analysis tools. The word “platform” might at first seem more applicable, but in this case all of the interfaces are using Jupyter as the platform, to ensure a consistent look-and-feel and a single platform for which to target the tools. The interfaces are then specific interfaces through which users access this platform. The target interfaces are:
Notebook/Lab: While the actual app the user is running may be either JupyterLab or the “classic” Jupyter Notebook, the interface idiom is similar - a relatively linear notebook-style workflow. This is the most flexible interface as it allows the user to implement their own code free-form in the notebook and run it with cells using Jdaviz tools. Hence this layer particularly emphasizes modularity and flexibility.
Desktop: This interface is meant to behave like a more traditional “desktop app”, i.e., a window with a fixed set of functionality and a particular layout for a specific set of scientific use cases. This interface is accessed via a Voilà wrapper that loads the same machinery as the other interfaces but presents the outputs of notebook “cells” as the only view. This trades the flexibility of the notebook interface for a consistent and reproducible layout and simpler interface without the distraction of the notebook and associated code.
MAST: This interface is used by the Mikulski Archive for Space Telescopes (MAST), which embeds Jdaviz applications inside existing websites. This provides the capabilities of the Jdaviz tools in other websites, while providing the sites the freedom to be designed and laid out independently from the visualization tool framework. While this even further restricts the functionality, it provides maximum flexibility in embedding.
Each of these interfaces uses a common set of applications implemented in Python and leveraging ipywidgets as the communication layer between Python and the JavaScript-level layout, rendering, and interactivity libraries. Hence the following layers are primarily implemented in Python, but utilize tools like ipyvuetify and ipygoldenlayout to allow the Python code to interact with the JavaScript implementations at the interface level.
Applications
The next layer is the “application” layer for visualization. These applications in and of themselves do not implement significant functionality, but are particular layouts that combine the lower layers to accomplish specific visualization tasks. They have particular science goals that are then mainly reflected in the capabilities of the lower layers (widgets), but the functionality in them are connected together to solve those goals in the applications. The desktop app and embedded website interfaces will typically wrap exactly one of these applications, while the notebook/lab’s additional flexibility means it may include multiple applications, or a mix of applications and individual widgets.
Specific target applications include:
Specviz: A view into a single astronomical spectrum. It provides a UI to view the spectrum, as well as perform common scientific operations like marking spectral regions for further analysis (e.g., in a notebook), subtracting continua, measuring and fitting spectral lines, etc.
Mosviz: A view into many astronomical spectra, typically the output of a multi-object spectrograph (e.g., JWST NIRSpec). It provides capabilities for individual spectra like Specviz, but for multiple spectra at a time along with additional contextual information like on-sky views of the spectrograph slit.
Cubeviz: A view of spectroscopic data cubes (e.g., from JWST MIRI), along with 1D spectra extracted from the cube. In addition to common visualization capabilities like viewing slices or averages in image or wavelength space, the application will provide some standard manipulations like smoothing, moment maps, parallelized line fitting, etc.
Imviz: An image-viewer for 2D images leveraging the same machinery as the other applications. While this application is not intended to encapsulate a complete range of astronomical imaging-based workflows, it enables quick-look style visualization of images in a way that is compatible with the rest of the Jdaviz framework.
The applications are driven by a shared layer that connects the “high-level” layers to the “low-level” layers, as discussed below. The application engine manages this shared layer. Or more concretely, the application engine is the Python-level object that can be accessed by the user in any of the interfaces to interact with a particular application. It contains several sub-pieces to achieve this goal. The most directly-used portion of this is the layout configuration management: Jdaviz applications specify the UI layout they use via this part of the application engine. The application engine then constructs the layout using glue-jupyter, ipywidgets, and other layout libraries like ipyvuetify. The application engine also is responsible for managing application-level events and data. This is done via the built-in functionality of the glue-core library, so the application engine also provides the interface for registering new functionality (both UI and data/processing) via glue-core’s registries.
Note that most of the application engine implementation belongs in glue-jupyter or glue-core, as it is not unique to Jdaviz (or even astronomy). However, Jdaviz has customized it for specific use cases, though some of the implementations might be moved upstream as Jdaviz matures, especially if they are useful beyond Jdaviz.
Visualization: Component Widgets
The “component widgets” layer is the first of the “low-level” layers, i.e., the layers that actually implement specific visualization and analysis functionality. These widgets are self-contained and in general are meant to be composed in applications. However, for the notebook/lab interface, component widgets can and should be used directly by users for specialized scientific workflows. Component widgets in principle can be developed in any framework that can be exposed as an ipywidgets widget, although currently the plan is that most will be glue-jupyter viewers (using bqplot backend) combined with ipyvuetify layouts (that builds on Vue.js). As with the application engine, the general goal is to push any functionality necessary for these widgets upstream and not confine them to Jdaviz, but with allowances that some customization may be needed for Jdaviz-specific elements.
Note
GlueViz in the diagram above encapsulates all the libraries tied to the Glue visualization ecosystem. They include but not limited to glue-core, glue-jupyter, glue-astronomy, and bqplot-image-gl. Due to the complexity of Jdaviz’s dependency tree, we will not mention all of them in this section.
Known component widgets for the target applications include:
Spectrum viewer: A widget that shows a 1D astronomical data set, primarily aimed at astronomical spectra. Interactivity includes panning, zooming, and region marking.
Image viewer: A widget that shows an astronomical image, along with its on-sky coordinates when WCS are available. Interactivity includes panning, zooming, stretch (contrast and scale), and cut values.
Cube slicer: A widget for displaying slices or similar aggregate operations on spectroscopic data cubes. While similar to the image viewer in appearance and interactive capabilities, the core difference is that the main data object is expected to be a data cube rather than a 2D image, and this is reflected in additional aggregation/slicing operations.
Table viewer: A widget to show tabular datasets like
astropy.table.Table
objects. Primarily meant to be combined with other viewers to examine the complete set of properties from a selection made in another viewer. Interactivity focuses on sorting and selection of specific rows (to then be highlighted in other viewers or interacted with in notebook/lab).
In addition to the component widgets above, there are also plugins that go with them to provide the necessary user interactions. Each plugin is specialized to do one thing, e.g., a “model fitting” plugin to allow users to fit astropy models to spectra.
Data Analysis and I/O Libraries
The above layers are focused primarily on visualization. All actual operations and analysis tasks to be applied to visualized astronomical dataset are to be implemented in the respective Python libraries. It is important to note that these libraries are independent efforts from Jdaviz, and can therefore be used in whole, part, or not at all with the Jdaviz tools. This allows a full range of workflows, while also maintaining transparency to scientific users in regards to exactly how an operation in the Jdaviz tools actually works; i.e., they can at any time use the library directly instead of accessing it through Jdaviz.
Some common libraries include (this list is not exhaustive):
astropy (general astronomy-related functionality)
specutils (spectral analysis)
photutils (imaging photometry)
Note that those libraries themselves depend on the wider scientific Python ecosystem, so the list and the diagram above do not fully cover all of Jdaviz’s dependencies, but are the primary “top-level” data analysis or I/O libraries that most users are likely to focus on to complement or extend their Jdaviz workflows.
Note
In the diagram above, optional dependencies of Jdaviz have dotted lines. Optional dependencies mean they are only required for certain Jdaviz workflows and are not explicitly installed by default when you install Jdaviz.
Glupyter Framework Overview
The glue-jupyter (“glupyter”) package supports interacting with and visualizing data within the Jupyter environment using core elements from the glue python package. It is distinct because unlike the more prominent glue package, glupyter does not leverage Qt as the front-end GUI library. Instead, glupyter maintains the separation between the data model (e.g., the core elements from glue that are not dependent on the front-end library), and the view of the data (in this case, web-based tooling provided by Jupyter).
Glupyter implements a base JupyterApplication
object through which
users can manage their data, create viewers, and add links between data
sets. The data management and linking are controlled separate from the
viewers in that changes made directly to the data state propagate to the
UI – that is, the UI does not contain any state, which allows the application to be easily controlled from code. The viewers themselves are based on the
IPyWidget package which allows the creation of widgets that can be used
and interacted with in python, but rendered in a browser environment.
There are two distinct use cases for the glupyter environment:
As a means to procedurally interact with pieces of a user’s workflow in addition to their work in e.g., a Jupyter Notebook.
To provide users a web-based GUI to interact with and visualize their data while hiding the Python code, e.g., a standalone web application.
These two use cases describe a Python-first and GUI-first approach, respectively. This document will focus on detailing the design of the GUI-first approach, depicted in the following diagram.
Note
The .xml
file in the img
directory can be used to edit the
diagram using applications like, e.g.,
draw.io.

General user interface design
The general user interface is a parallel design to the Qt desktop interface. It is meant to be the standard scaffolding supporting the display of the individual viewers, and implementation of data management functions and user plugins in much the same way that the Qt desktop version does.
The implementation leverages three primary packages:
glue-jupyter: handles the data and state management, including the plugin infrastructure that provides the registry of available viewers, analysis functions, etc.
ipyvuetify: provides the UI widgets for composing the web-based front-end.
ipygoldenlayout: an additional widget that supports tabbing and docking the displayed viewers.
Widget design
There are two potential approaches to designing widgets using the ipyvuetify paradigm: composing everything in the python widget subclass as a collection of python ipyvuetify components; or break the state of the widget from its view and implement the latter as template file.
The first approach, while conceptually easier to understand, has a few
shortcomings. Chief of which is the fact that the view logic is jumbled
up with the state of the widget. That is, we are composing the visual
representation of the widget, defining the viewer logic, and defining
its state all during initialization. This is both extremely verbose –
as the nested nature of the Vuetify library means many of the
intermediate widget classes (e.g., Layout
, Container
, Row
,
etc) need to be defined as instance attributes – and, perhaps more
severe, makes it more difficult to design reactive UI behavior that
responds to state changes in the widget classes automatically. This
means that we must constantly interact with the UI widgets to change
their state directly instead of simply having the UI respond to state
changes in the custom widget class. Fundamentally, this approach means
that in addition to the state of the custom widget (e.g., Toolbar
),
we must also be aware of the state of each individual widget that
composes it. Put another way, there’s no central source of truth for
the state of the custom widget as each element may contain some kind of
stateful information about itself.
An alternative design, and the one used for the Jdaviz tools, is to have each widget implemented as a
VuetifyTemplate
object. In this way, custom widgets are defined as
ipywidget-like elements whose visual representation is described by a
Vuetify template. The template composes the visual representation of the
custom widget using the Vue formalism, while the state is implemented as
traitlets on the custom widget class. The template reads and responds to
state and state changes on the custom widget, and the custom widget need
not know or care about how that state is being represented (i.e. the
only state is that of the custom widget).
With this approach in hand, all widgets in the glupyter GUI are composed
of two files: the python file declaring the widget class (e.g.,
Toolbar
), and the .vue
file containing the template describing
how the widget is to be rendered using components from the Vuetify
library in the nominal Vue framework. In this way, there is a clear
separation between the state of each widget (contained in the python
file) and the view of that state (contained in the Vuetify file). Below
is an example of what such a widget might looking like:
<template>
<v-toolbar>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title>Title</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-sm-and-down">
<v-btn flat>Link One</v-btn>
<v-btn flat>Link Two</v-btn>
<v-btn flat>Link Three</v-btn>
</v-toolbar-items>
</v-toolbar>
</template>
with open(os.path.join(os.path.dirname(__file__), "toolbar.vue")) as f:
TEMPLATE = f.read()
class Toolbar(VuetifyTemplate):
template = Unicode(TEMPLATE).tag(sync=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
...
The state of the widget is contained in attributes on the python class
which allows them to be referenced in the Vuetify template. Notice in
the example below that the v-btn
instances simply respond to the
state of the Toolbar
widget’s button_names
attribute, and the
Toolbar
class could know nothing about how that state is being
represented.
<v-toolbar-items class="hidden-sm-and-down">
<v-btn flat v-for="name in button_names">{{ name }}</v-btn>
</v-toolbar-items>
class Toolbar(VuetifyTemplate):
template = Unicode(TEMPLATE).tag(sync=True)
button_names = List(['One', 'Two', 'Three']).tag(sync=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
...
The design of the interface can be broken down into three main areas:
the toolbar, the navigation drawer, and the dock area. Each of these
areas represents a single primary widget in the web-based application
built using ipyvuetify
, unified in the Application
class.
Widget communication
There are three fundamental forms of communication between widgets:
direction communication using the
observer
pattern using Traitlets,global communication using the centralized event hub provided by glue,
and callback properties on glue objects.
Direct messaging
Because the software stack utilizes the ipywidgets package, attributes
on defined widget classes (e.g., button_names
on the Toolbar
widget in the example above) are implemented as traitlets, which can be
observed for changes. In order to register callbacks in response to
changes to attributes defined on widget classes, interested parties must
have a direct reference to the widget instance. Traitlets are unique in that
they can be referenced in the front-end Vue code, so changing a traitlet-defined
attribute of a class will propagate that change to any front-end code that
references the value.
For example, if we consider that the Toolbar
class above is
implemented as part of a broader Application
, we can respond to
changes in the button_names
traitlet by setting a callback function
in the observe
method of the Toolbar
widget:
class Application(VuetifyTemplate):
template = Unicode("""
<template>
<custom-toolbar></custom-toolbar>
</template>
""").tag(sync=True)
def __init__(self, *args, **kwargs):
# Associate the `custom-toolbar` element with the `Toolbar` class
kwargs.set_default('components', {}).update({'custom-toolbar': Toolbar()})
super().__init__(*args, **kwargs)
self.toolbar = self.components['custom-toolbar']
# This sets up the child-to-parent behavior
self.toolbar.observe(self.on_button_names_changed, names='button_names')
# Here we take advantage of the way traitlets work
def on_button_names_changed(self, *args, **kwargs):
print("The list of button names has been changed.")
This type of direct child-to-parent (i.e. the parent is responding to changes on the child) communication compliments the direct parent-to-child communication (i.e. the parent passing data to the child). However, this does not solve the application-level issue of multiple components, conceivably several levels deep, trying to interact with and pass data to each other. In this case, we decouple the widgets from each other and instead have them interact with a central, application-level communication hub through message objects.
Global event handing
Communication between widgets that do not have a direct reference to
each other is handled using the Hub
class of the glue-core package
(a dependency of glue-jupyter). The hub implements the publish/subscribe
paradigm wherein widgets subscribe to particular messages on the hub and
are notified whenever those messages are published by any part of the
UI. This system allows us to break hard dependencies between widgets in
the UI that require passing references around and to develop widgets
independently.
The Jdaviz package includes a base class that can be used for adding
widgets that would need to communicate through global events. This is
is the TemplateMixin
class and allows passing glue session objects
to widgets upon their instantiation. The glue session contains the Hub
object available to the application and it, along with other useful
data objects, are easily accessible through the TemplateMixin
.
Using the glue event framework is covered in great detail in the glue documentation. The code snippet gives an example of how an event listener may be implemented inside a widget:
from jdaviz.core.template_mixin import TemplateMixin
from glue.core.message import DataMessage
class TestWidget(TemplateMixin):
text = Unicode("No messages...").tag(sync=True)
template = Unicode("""
<v-card>
<v-card-text>
<p>{{ text }}</p>
</v-card-text>
</v-card>
""").tag(sync=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.hub.subscribe(self, DataMessage,
handler=self.on_data_message_received)
def on_data_message_received(self, message):
self.text = "Received data message!"
Glue callback properties
In cases where traitlets are not appropriate (e.g., where some python object is
not a strict inherited class of HasTraitlet
), glue’s CallbackProperty
s
can be used in conjunction with a State
class object. It should be noted,
however, that glue callback properties do not interact with the front-end UI
as in the case using traitlets; that is, changing the value of a callback
property will not automatically propagate that change to the front-end. More
information on using glue callback properties can be be found in
Writing a custom viewer for glue.
Plugin design
As shown in the diagram above, Jdaviz applications are ostensibly collections of widgets and viewers along with a configuration file that describes how the widgets and viewers ought to be rendered in the front-end. These widgets and viewers are defined as “Plugins”, and everything in the front-end is an example of using plugins in conjunction with the configuration file.
The UI supports four main areas currently: the tool bar area, the menu bar area, the tray bar area, and the content area. Plugins can be associated with one of these areas. Plugins themselves must by IPyWidget subclasses, below is an example of a plugin that adds a single button to the tool bar area.
@tools('test-button')
class TestButton(TemplateMixin):
template = Unicode("""
<v-btn>Press me!</v-btn>
""").tag(sync=True)
On loading the application, plugins are registered to the internal plugins registry. Based on the configuration declaration file, registry items will be referenced from these registries when rendering the front-end. An example of using the above test button plugin class might be
components:
menu_bar: false
toolbar: true
tray_bar: true
content_area: true
toolbar:
- test-button
menu_bar:
tray_bar:
content_area:
Plugin classes should not make any direct reference to the application, and should communicate via events.
UI/UX Style Guide
Tray Plugins
In order to be consistent with layout, styling, and spacing, UI development on plugins should try to adhere to the following principles:
Any tray plugin should utilize
<j-tray-plugin :disabled_msg='disabled_msg'>
as the outer-container (which provides consistent styling rules). Any changes to style across all plugins should then take place in thej-tray-plugin
stylesheet (jdaviz/components/tray_plugin.vue
).Each item should be wrapped in a
v-row
, but avoid any unnecessary additional wrapping-components (v-card-*
,v-container
, etc).Only use
v-col
components (within the<v-row class="row-no-outside-padding">
) if multiple components are necessary in a single row. Always emphasize readability at the default/minimum width of the plugin tray, rather than using columns that result in a ton of text overflow.Action buttons should have
color="primary"
if it loads something into the plugin, orcolor="accent"
if applying something to the viewers/apps/data.To remove vertical padding from rows (i.e., two successive buttons stacked vertically), use
<v-row class="row-min-bottom-padding">
.Use
<v-row justify="end">
to align content to the right (such as action buttons).Use new
<j-plugin-section-header>Header Text</j-plugin-section-header>
to separate content within a plugin (instead of nested cards,v-card-subtitle
, etc).Number entries should use a
<v-text-field type="number" v-model="traitlet_name">
component unless requiring support for scientific notation (in which case<v-text-field @change="python_method">
can be used with stripping invalid characters and type-casting in python). To handle emptying the input component without raising a traceback, use anIntHandleEmpty
traitlet instead, along with form-validation (see below) and/or checks on the python-side to handle the case of an empty string.Use form validation wherever possible, and disable action buttons if the relevant validation does not pass. This is preferred to raising errors through snackbars after pressing an action button. To do this, wrap the relevant section in a
<v-form v-model="form_valid_section_name">
, create aform_valid_section_name = Bool(False).tag(sync=True)
in the python class for the plugin, add rules to any relevant inputs, and set:disabled="!form_valid_section_name"
to any action buttons.Select input elements should default whenever possible (not start as empty), and self-hide if only one valid option. Whenever possible, inputs should use form validation rules with red text explaining the error and disabling action buttons. When one selection/check makes others contextually irrelevant, those irrelevant items should be hidden entirely. When order needs to be enforced, future inputs should be hidden.
Re-usable components should be implemented in
template_mixin.py
by inheriting fromBasePluginComponent
along with an accompanying mixin and vue template file injdaviz/components
(which in turn are made available throughipyvue.register_component_from_file
calls inapp.py
. These components allow the traitlets to live in the plugin-level so they can easily be observed, and separating per-component logic from the plugin logic itself.
<template>
<j-tray-plugin
description='Plugin description.'
:link="'https://jdaviz.readthedocs.io/en/'+vdocs+'/'+config+'/plugins.html#plugin-name'"
:popout_button="popout_button">
<v-row>
....
</v-row>
<v-form v-model="form_valid">
<v-row>
<v-text-field
label="Label"
type="number"
v-model.number="int_handle_empty_traitlet"
:rules="[() => int_handle_empty_traitlet!=='' || 'This field is required']"
hint="Hint text."
persistent-hint
>
</v-text-field>
</v-row>
<v-row justify="end">
<v-btn
color="primary"
text
:disabled="!form_valid"
@click="(e) => {add_model(e); validate()}"
>Action Text
</v-btn>
</v-row>
</v-form>
</j-tray-plugin>
</template>
Plugin Components
Plugin components exist to provide re-usable UI elements across multiple plugins, both for consistency in behavior between plugins and also for simplification of code.
The general concept is to move as much shared code into these components, and out of the plugins, as possible.
Design Philosophy
Each component consists of three parts:
1. Python component class in the template_mixin
module, which inherits from BasePluginComponent
and
passes the string names of the traitlets it needs to the constructor as keyword arguments. This class isolates the
logic from the plugin itself, while still providing convenient access to the traitlets which are
defined in the plugin (and in doing so, allows using those same traitlets within the plugin
in the same way as any other traitlet in the plugin). Within this class, it is necessary to use
add_observe()
in the constructor
instead of the @observe
decorator on the callback method for all traitlets, so that the callback
can reference the traitlet in the plugin properly.
For example implementation, see SelectPluginComponent
.
2. Python mixin class in the template_mixin
module, which inherits from VuetifyTemplate
and
HubListener
. This class defines default traitlets as well as the attribute for the component
object itself for plugins to make use of the accompanying component. In some cases, the component
class will be used manually with custom traitlets (especially if/when using multiple instances of
the same component within a single plugin). For example implementation, see
SpectralSubsetSelectMixin
.
3. .vue
template file in jdaviz/components
, which are registered in app.py
using ipyvue.register_component_from_file()
. These
templates are not linked directly to the Python class, but rather should pass all necessary
traitlets and options when called from within the template file for the plugin itself. Note that
this means that the instance of the component cannot be rendered individually, but also allows for
components to interact with each other easily through traitlet events within the plugin. If nesting
these inside each other, it might be necessary to manually re-emit events higher up the tree with
something like @update:value="$emit('update_value', $event)"
in the relevant .vue
file.
BasePluginComponent
provides the following functionality to all components:
app
,hub
, andplugin
properties to access the respective instances.viewer_dicts
property to access a list of dictionaries, with keys:viewer
,id
,reference
, andlabel
(reference
if available, otherwiseid
).add_observe()
method to connect a callback to the proper traitlet in the parent plugin. This can optionally takefirst=True
to ensure the callback will be processed before any@observe
watchers in the plugin.overrides
getattr
andsetattr
to redirect any calls to the internal traitlet attributes to those in the plugin.
Motivations for this Design
We converged on this framework for several reasons (compared to alternate options). If ever considering changing to a different architecture, the following should be considered there as well:
Each class can only subscribe to each
Message
object once (viaself.hub.subscribe
), without introducing extra wrappers. By isolating the component-logic from the plugin, the component and the plugin itself can subscribe to the same message without issues which makes writing a plugin simpler without having to worry about breaking any message subscriptions.Having all the logic in a Mixin, instead of a Mixin wrapping around a separate “component” class would also prevent the ability to have multiple instances of the same component within a single plugin. This is needed in several places: subsets in line analysis and aperture photometry, for example.
Having each component class be standalone with its own linked template (so that it can be rendered individually) would complicate communication between components. The component would need its own traitlets which are then synced to traitlets in the plugin and/or message events would need to be used.
Considerations when Writing/Using Components
Plugin components are specifically designed to be used within plugins, and should not be used elsewhere.
Plugin components must use
add_observe
instead of@observe
for any traitlets referenced from the plugin itself.Plugins should use the Mixin whenever appropriate for so attributes are named consistently across plugins.
Specviz Selections
This section explains the working theory behind the selection tool and was inspired by the the introduction of two methods to the Specviz helper:
specviz.get_spectra()
specviz.get_spectral_regions()
Data loaded in are imported into Jdaviz and immediately converted into a
specutils.SpectralRegion
object. These are a spectral analog to the Astropy regions
(which instead focuses on spatial regions and their associated WCS). These spectral regions
are returned by the specviz.get_spectra()
method.
The selection tool allows the user to specify a specific range on the graph.
This is defined by the underlying Glue library upon which Jdaviz relies on as a
“Glue Subset.” Thus throughout the software documentation, we will refer to these
user defined ranges as “subsets.” Effectively, the selection tool defines a mask that
can be thought of as “definition” of which data is and is not included in the subset.
Upon extraction via specviz.get_spectral_regions()
, the method will return a new
specutils.SpectralRegion
object that applies that mask atop of the proper region
(data) displayed, and realizes the subset the user defined in Jdaviz.
Linking of datasets in glue
Note
The glue documentation includes a page about linking but the present page should be considered a more up-to-date guide with a focus on links useful to Jdaviz.
The ‘why’ of linking
Why is linking needed in the first place? Linking in glue is a way to describe the relationship between datasets, with two main goals: to know how to overplot datasets, and to know how to apply a subset defined in one dataset (such as a spectral range) to another dataset. Having linking means being able to show, say, multiple spectra in the same plot, or multiple images that are aligned in the same image viewer, or contours on top of an image.
There are various ways of setting up links in glue, but the two main ways that have been discussed and used in Jdaviz are linking by pixel coordinates and by world coordinates (WCS).
Linking by pixel coordinates with an identity link
Linking by pixel coordinates with an identity link means that glue considers that the datasets’ pixel grids are lined up at where the origins of the datasets overlap. This means that if one has two images, with shape (32,32) and (128,128), the (0,0) pixels will overlap, and the (32,32) dataset will be lined up with the first (32,32) pixels of the larger dataset, starting at the origin. This is equivalent to the “match image” mode in DS9.
An example of setting up an identity link in pixel coordinates between two n-dimensional datasets where n is the same for both datasets would look like:
from glue.core.link_helpers import LinkSame
pix_ids_1 = data1.pixel_component_ids
pix_ids_2 = data2.pixel_component_ids
links = []
for i in range(data1.ndim):
links.append(LinkSame(pix_ids_1[i], pix_ids_2[i]))
data_collection.add_link(links)
This can also be used to link, for example, the two spatial dimensions of a collapsed cube with the original cube, as done in the cube collapse functionality in Jdaviz:
pix_id_1 = self._selected_data.pixel_component_ids[i1]
pix_id_1c = self.data_collection[label].pixel_component_ids[i1c]
pix_id_2 = self._selected_data.pixel_component_ids[i2]
pix_id_2c = self.data_collection[label].pixel_component_ids[i2c]
self.data_collection.add_link(LinkSame(pix_id_1, pix_id_1c))
self.data_collection.add_link(LinkSame(pix_id_2, pix_id_2c))
This linking would then allow the collapsed dataset to be shown as contours on top of the original sliced cube.
This is by far the fastest way of linking, but it does rely on the datasets being lined up pixel-wise. This approach can be used in specific parsers where it is known that the datasets are on the same grid.
It is also possible to link all datasets using pixel links, but users will need to be aware that this then means specific features (such as stars) in different datasets will not line up when, e.g., blinking, and making a selection or region of a certain feature will not necessarily select the same feature in another dataset.
Linking by WCS
There are two main ways of linking by WCS, as follow.
Using WCSLink (recommended)
The more robust approach for linking datasets by WCS is to use the
WCSLink
class. Given two
datasets, and a list of pixel component IDs to link in each dataset, this class
will set up links between the pixel components by internally representing the
chain of WCS transformations required. As an example:
from glue.plugins.wcs_autolinking.wcs_autolinking import WCSLink
link = WCSLink(data1=data1, data2=data2,
cids1=data1.pixel_component_ids, cids2=data2.pixel_component_ids)
data_collection.add_link(link)
The example above will link all pixel axes between the two datasets, taking into account the WCS
of data1
and data2
.
Note that this should work with any APE 14-compliant WCS, so it could link both a FITS WCS to a GWCS instance, and vice versa.
Using LinkSame (not recommended)
The first is to do something similar to how pixel coordinates are linked in Linking by pixel coordinates with an identity link:
from glue.core.link_helpers import LinkSame
world_ids_1 = data1.world_component_ids
world_ids_2 = data2.world_component_ids
links = []
for i in range(data1.ndim):
links.append(LinkSame(world_ids_1[i], world_ids_2[i]))
data_collection.add_link(links)
or see the following example in app.py from Jdaviz:
def _link_new_data(self):
"""
When additional data is loaded, check to see if the spectral axis of
any components are compatible with already loaded data. If so, link
them so that they can be displayed on the same profile1D plot.
"""
new_len = len(self.data_collection)
# Can't link if there's no world_component_ids
wc_new = self.data_collection[new_len-1].world_component_ids
if wc_new == []:
return
# Link to the first dataset with compatible coordinates
for i in range(0, new_len-1):
wc_old = self.data_collection[i].world_component_ids
if wc_old == []:
continue
else:
self.data_collection.add_link(LinkSame(wc_old[0], wc_new[0]))
break
However, this kind of linking is not generally robust because it relies on the WCS actually being the same system between the two datasets - so it would fail for two images where one image was in equatorial coordinates and the other one galactic coordinates, because LinkSame would mean that RA was the same as Galactic longitude, which it is not. Likewise, this would result in, say, wavelength in one dataset being equated wrongly with frequency in another. The only place this kind of linking could be used is within parsers for specific data where it is known with certainty that two world coordinate systems are the same.
In general, one should avoid using LinkSame for world coordinates in Jdaviz.
Speeding up WCS links
In some cases, doing the full WCS transformations can be slow, and may not be
necessary if the two datasets are close to each other and have a similar WCS.
For the best performance, it is possible to approximate the
WCSLink
by a simple affine
transformation between the datasets. This can be done with the
as_affine_link()
method:
link = WCSLink(data1=data1, data2=data2,
cids1=data1.pixel_component_ids,
cids2=data2.pixel_component_ids)
fast_link = link.as_affine_link()
data_collection.add_link(fast_link)
The as_affine_link()
method takes a tolerance
argument which defaults to 1 pixel - if no
approximation can be found that transforms all positions in the image to within
that tolerance, an error of type NoAffineApproximation
is returned.
It is recommended that whenever WCSLink
is used
in Jdaviz, affine approximation should be used whenever possible.
For visualization purposes, it should be good enough for most cases.
DS9 uses a similar approach.
Speeding up adding links to the data collection
Each time a link, dataset, or component/attribute is added to the data
collection in glue, the link tree is recalculated. Unnecessary recalculations can be prevented by
using the
delay_link_manager_update()
context manager. Use this around any block that adds multiple datasets to the
data collection, components/attributes to datasets, or links to the data
collection, e.g.:
with data_collection.delay_link_manager_update():
for i in range(10):
data_collection.append(Data(...))
data_collection.add_link(...)
See pull request 762 for a more concrete example.
Setting or resetting all links in one go
If you want to prepare and set all links in one go, discarding any previous links,
you can make use of the set_links()
method, which takes a list of links:
data_collection.set_links([link1, link2, link3])
It is recommended to use this inside the
delay_link_manager_update()
context manager, as mentioned in Speeding up adding links to the data collection.
This method is ideal if you want to, say, switch between using pixel and WCS links as it will discard any existing links before adding the new ones.
This is necessary because the same two datasets cannot have both pixel and WCS links, as explained in Mixing link types.
Mixing link types
Glue can handle many different link types in a same session. For instance, if
there are three datasets, two of the datasets could be linked by a
WCSLink
while two other
datasets could be linked by pixel coordinates. However, the same two datasets
should not be linked both by WCSLink
and pixel coordinates at the same time, as which link takes precedence is not
defined, resulting in ambiguous behavior.
Developing on Windows
On some Windows OS versions, symbolic links cannot be created without
using a terminal started with administrative priviledge, which is not
recommended for security reasons. Therefore, setup.py
instead
creates a copy of the data files instead of using symbolic links.
As a result, if you are changing the contents in share
folder
under the source checkout’s root directory, you will need to rebuild
the package even in editable install mode. Otherwise, this should not
affect your development experience.
WSL2 and voila
voila
is unable to display when WSL2 cannot start up the
Windows-side browser executable. Unfortunately, unlike Jupyter
notebook, voila
does not have a --no-browser
option
with a tokenized URL you can copy-and-paste manually on the
Windows side (see https://github.com/voila-dashboards/voila/issues/773).
Therefore, you might need to install Jdaviz natively on Windows
to test its standalone application functionality.
API
Configurations
jdaviz.configs.cubeviz.helper Module
Classes
|
Cubeviz Helper class |
jdaviz.configs.imviz.helper Module
Functions
|
(Re)link loaded data in Imviz with the desired link type. |
Classes
|
Imviz Helper class. |
jdaviz.configs.mosviz.helper Module
Classes
|
Mosviz Helper class |
jdaviz.configs.specviz.helper Module
Classes
|
Specviz Helper class. |
jdaviz.configs.specviz2d.helper Module
Classes
|
Specviz2D Helper class |
Viewers
jdaviz.configs.default.plugins.viewers Module
Classes
|
jdaviz.configs.cubeviz.plugins.viewers Module
Classes
|
|
|
jdaviz.configs.imviz.plugins.viewers Module
Classes
|
jdaviz.configs.mosviz.plugins.viewers Module
Classes
|
|
|
|
|
jdaviz.configs.specviz.plugins.viewers Module
Classes
|
Parsers
jdaviz.configs.cubeviz.plugins.parsers Module
Functions
|
Attempts to parse a data file and auto-populate available viewers in cubeviz. |
jdaviz.configs.imviz.plugins.parsers Module
Functions
|
Parse a data file into Imviz. |
jdaviz.configs.mosviz.plugins.parsers Module
Functions
|
Attempts to parse a 1D spectrum object. |
|
Attempts to parse a 2D spectrum object. |
|
Attempts to parse an image-like object or list of images. |
jdaviz.configs.specviz.plugins.parsers Module
Functions
|
Loads a data file or |
jdaviz.configs.specviz2d.plugins.parsers Module
Functions
|
Generate a quicklook 1D spectrum from an input 2D spectrum by summing over the cross-dispersion axis. |
Plugins
jdaviz.configs.default.plugins.collapse.collapse Module
Classes
|
See the Collapse Plugin Documentation for more details. |
jdaviz.configs.default.plugins.data_tools.data_tools Module
Classes
|
Public constructor |
jdaviz.configs.default.plugins.export_plot.export_plot Module
Classes
|
See the Export Plot Plugin Documentation for more details. |
jdaviz.configs.default.plugins.gaussian_smooth.gaussian_smooth Module
Classes
|
See the Gaussian Smooth Plugin Documentation for more details. |
jdaviz.configs.default.plugins.line_lists.line_lists Module
Classes
|
Public constructor |
jdaviz.configs.default.plugins.metadata_viewer.metadata_viewer Module
Classes
|
See the Metadata Viewer Plugin Documentation for more details. |
jdaviz.configs.default.plugins.model_fitting.model_fitting Module
Classes
|
See the Model Fitting Plugin Documentation for more details. |
jdaviz.configs.default.plugins.plot_options.plot_options Module
Classes
|
The Plot Options Plugin gives access to per-viewer and per-layer options and enables setting across multiple viewers/layers simultaneously. |
jdaviz.configs.default.plugins.subset_plugin.subset_plugin Module
Classes
|
Public constructor |
jdaviz.configs.default.plugins.subset_tools.subset_tools Module
Classes
|
Public constructor |
jdaviz.configs.default.plugins.viewer_creator.viewer_creator Module
Classes
|
Public constructor |
jdaviz.configs.cubeviz.plugins.moment_maps.moment_maps Module
Classes
|
See the Moment Maps Plugin Documentation for more details. |
jdaviz.configs.cubeviz.plugins.slice.slice Module
Classes
|
See the Slice Plugin Documentation for more details. |
jdaviz.configs.imviz.plugins.aper_phot_simple.aper_phot_simple Module
Classes
|
Public constructor |
jdaviz.configs.imviz.plugins.catalogs.catalogs Module
Classes
|
See the Catalog Search Plugin Documentation for more details. |
jdaviz.configs.imviz.plugins.compass.compass Module
Classes
|
See the Compass Plugin Documentation for more details. |
jdaviz.configs.imviz.plugins.coords_info.coords_info Module
Classes
|
Public constructor |
jdaviz.configs.imviz.plugins.image_viewer_creator.image_viewer_creator Module
Classes
|
Public constructor |
jdaviz.configs.imviz.plugins.line_profile_xy.line_profile_xy Module
Classes
|
Public constructor |
jdaviz.configs.imviz.plugins.links_control.links_control Module
Classes
|
See the Links Control Plugin Documentation for more details. |
jdaviz.configs.mosviz.plugins.row_lock.row_lock Module
Classes
|
Public constructor |
jdaviz.configs.mosviz.plugins.slit_overlay.slit_overlay Module
Functions
|
Classes
|
Public constructor |
jdaviz.configs.specviz.plugins.line_analysis.line_analysis Module
Classes
|
The Line Analysis plugin returns specutils analysis for a single spectral line. |
jdaviz.configs.specviz.plugins.unit_conversion.unit_conversion Module
Classes
|
Public constructor |
jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction Module
Classes
|
The Spectral Extraction plugin exposes specreduce methods for tracing, background subtraction, and spectral extraction from 2D spectra. |
Nuts and Bolts
jdaviz.app Module
Classes
|
The main application object containing implementing the ipyvue/vuetify template instructions for composing the interface. |
jdaviz.configs.default.plugins.data_tools.file_chooser Module
Classes
|
FileChooser class. |
jdaviz.configs.default.plugins.line_lists.line_list_mixin Module
Classes
Line list-related methods and properties for use in the configuration helper classes. |
jdaviz.configs.default.plugins.model_fitting.fitting_backend Module
Functions
|
Fits a |
jdaviz.configs.default.plugins.model_fitting.initializers Module
This module is used to initialize spectral models to the data at hand.
This is used by model-fitting code that has to create spectral model instances with sensible parameter values such that they can be used as first guesses by the fitting algorithms.
Functions
|
Initialize given model. |
|
jdaviz.configs.imviz.wcs_utils Module
This module handles calculations based on world coordinate system (WCS).
Functions
|
Calculate WCS compass parameters. |
|
Visualize the compass using Matplotlib. |
jdaviz.core.astrowidgets_api Module
Classes
This class implements |
jdaviz.core.config Module
This file contains helper function related to configuration handling.
Functions
|
Loads a configuration from a YAML file. |
|
Retrieve a copy of a specified configuration. |
Get a list of pre-built configurations. |
jdaviz.core.custom_traitlets Module
Classes
|
Mixin to handle empty field. |
|
Mixin to handle empty integer field. |
|
Mixin to handle empty floating point field. |
jdaviz.core.data_formats Module
Functions
|
Guess the dimensionality of a file. |
|
Identify a best match Jdaviz configuration from a filename. |
|
Identify the data format and application configuration from a filename. |
jdaviz.core.events Module
Classes
|
Message to trigger viewer creation in the application. |
|
Unlike |
|
Message emitted after a viewer is destroyed by the application. |
|
Create a new message |
|
Create a new message |
|
Create a new message |
|
Create a new message |
|
Create a new message |
|
Create a new message |
|
Message generated by the cubeviz helper and processed by the slice plugin to sync slice selection across all viewers |
|
Message generated by the select slice plot plugin when activated/deactivated |
|
Message generated by Mosviz table to zoom to object on image |
|
Message generated when the WCS/pixel linking is changed |
|
Message generated when exiting the outermost batch_load context manager |
|
Message generated when markers are added/removed from an image viewer |
jdaviz.core.freezable_state Module
Classes
|
|
|
jdaviz.core.helpers Module
Helper classes are meant to provide a convenient user API for specific configurations. They allow a separation of “viztool-specific” API and the glue application objects.
See also https://github.com/spacetelescope/jdaviz/issues/104 for more details on the motivation behind this concept.
Classes
|
The Base Helper Class. |
|
|
jdaviz.core.linelists Module
Functions
Return metadata for line lists. |
|
Return all available line lists. |
|
|
Return one of the preset line lists, loaded into |
jdaviz.core.marks Module
Classes
|
|
|
Public constructor |
|
Subclass on bqplot Lines, mostly so that we can erase spectral lines by eliminating any SpectralLines objects from a figures marks list. |
|
Subclass on bqplot Lines to handle slice/wavelength indicator. |
Mixin class to propagate traits from one mark object to another. |
|
|
Create a white shadow line around another line to help make it standout on top of other lines. |
|
Label whose position shadows that of a parent |
|
Public constructor |
|
Public constructor |
|
Public constructor |
|
Public constructor |
|
Public constructor |
|
Public constructor |
|
Public constructor |
|
Public constructor |
jdaviz.core.region_translators Module
The region_translators
module houses translations of
Region Shapes to Aperture Photometry (photutils.aperture) apertures.
Functions
|
Convert a given |
|
Convert a given |
|
Convert a given |
jdaviz.core.registries Module
Functions
|
Converts camel-case strings to snake-case. |
Classes
Base registry class that handles hashmap-like associations between a string representation of a plugin and the class to be instantiated. |
|
Registry containing references to custom viewers. |
|
Registry containing references to plugins that will be added to the sidebar tray tabs. |
|
Registry containing references to plugins which will populate the application-level toolbar. |
|
Registry containing references to plugins that will populate the application-level menu bar. |
|
Registry containing parsing functions for attempting to auto-populate the application-defined initial viewers. |
jdaviz.core.template_mixin Module
Functions
|
Classes
|
Public constructor |
|
This base class can be inherited by all sidebar/tray plugins to expose common functionality. |
|
This base class handles attaching traitlets from the plugin itself to logic handled within the component, support for caching and clearing caches on properties, and common properties for accessing the app, etc. |
|
Plugin select, with support for single or multi-selection. |
|
Plugin select for subsets, with support for single or multi-selection. |
|
Applies the SubsetSelect component as a mixin in the base plugin. |
|
Applies the SubsetSelect component as a mixin in the base plugin. |
|
Adds a traitlet tracking whether self.dataset and self.spectral_subset overlap in the spectral axis. |
|
Plugin select for viewers, with support for single or multi-selection. |
|
Applies the ViewerSelect component as a mixin in the base plugin. |
|
Plugin select for layers, with support for single or multi-selection. |
|
Applies the LayerSelect component as a mixin in the base plugin. |
|
Plugin select for data entries, with support for single or multi-selection. |
|
Applies the DatasetSelect component as a mixin in the base plugin. |
|
Label component with the ability to synchronize to a plugin-provided default value or override with a custom value. |
|
Applies the AutoTextField component as a mixin in the base plugin. |
|
Plugin component for providing a data-label and selecting a viewer to add the results from the plugin. |
|
Applies the AddResults component as a mixin in the base plugin. |
|
Plugin component for syncing with glue state objects. |
jdaviz.core.validunits Module
Functions
|
Convert equivalencies into readable versions of the units. |
|
Get all possible conversions from current spectral_axis_unit. |
|
Get all possible conversions for flux from current flux units. |
jdaviz.models.physical_models Module
Models that have physical origins.
Classes
|
Blackbody model using the Planck function. |
Class Inheritance Diagram
jdaviz.utils Module
Functions
Use |
|
|
Clears a given |
|
Standardize given metadata so it can be viewed in Metadata Viewer plugin. |
|
Converts an index to label (A-Z, AA-ZZ). |
Classes
Class that performs the role of VSnackbarQueue, which is not implemented in ipyvuetify. |
|
|
Cycles through matplotlib's default color palette after first using the Glue default data color. |
Additional documentation
Known Issues
You can report an issue to the Jdaviz GitHub issues.
Some currently known but unresolved common issues that users encounter are as follow in their respective categories. This list is not exhaustive, so please also consult existing Jdaviz GitHub issues as well if you are unable to find your issue here:
Installation
On MacOS versions 10.13 and older, install fails due to scikit-image
This can be fixed by reinstalling scikit-image:
pip uninstall scikit-image
conda install scikit-image
The reason for this issue is that prebuilt binaries for scikit-image don’t work on Mac versions of 10.13 or older and conda installs an older version of scikit-image that works with those versions. Another way to get the up-to-date scikit-image version is:
pip install -U --no-binary scikit-image scikit-image.
Although this solution takes much longer (~5 minutes) to install than the first solution.
On some platforms, install fails due to vispy
The 0.6.4 version of vispy fails to build for some combinations of platform/OS and Python versions. vispy 0.6.5 has resolved this, but a workaround if you have an older version of vispy is to ensure you have a compatible version:
conda create -n jdaviz python=3.8
conda activate jdaviz
pip install vispy>=0.6.5
pip install jdaviz --no-cache-dir
See Issue #305 for updates on this topic.
On some platforms, install fails due to bottleneck
In a conda environment, where numpy was installed using conda, installing jdaviz using pip will attempt to pull bottleneck from PyPI. This might result in bottleneck trying to build numpy from source and crash, stalling the installation altogether. When this happens, exit the installation, install bottleneck with conda, and try to install jdaviz again.
Application-wide
Lab fails to start with IndexError
In some environments, you occasionally might not able to start Jdaviz in Jupyter Lab due to this error:
IndexError: pop from an empty deque
This is an upstream issue at https://github.com/jupyterlab/jupyterlab/issues/11934 that is not related to Jdaviz. The workaround is to find another environment where you do not see this error or use Jupyter Notebook instead.
Cubeviz
Cubeviz sometimes fails to run from command line interface
Running Cubeviz from the command line sometimes results in a failure
to initialize the app in the browser due to a RuntimeError
in
tornado/ioloop.py
. We are investigating, but in the meantime
reinstalling fresh in a new conda environment may help. Alternatively,
running Cubeviz in a Jupyter notebook instead of from the command line
will circumvent the problem.
Spectrum does not appear when running on a Linux VM
When running Jdaviz on a Linux virtual machine (VM), the spectrum may not appear
in the spectrum viewer. This is a
known bug in an underlying
package. Until it is fixed, the workaround is to run the following in a Jupyter
notebook cell before importing jdaviz
:
from glue_jupyter.bqplot.profile import layer_artist
layer_artist.USE_GL = False
Collapse and Moment Maps: Spectral bounds do not match Region selection
When trying to do a second collapse with the same spectral region, but with resized bounds: change to Region=None, resize the region, then reselect Region 1, the region bounds are correct. However, applying Collapse again, it errors out and the image viewer that contained the initial collapse goes blank.
Cube viewer contrast changes when collapsing Jupyter scroll window
In order to see the full Cubeviz app in a Jupyter notebook, one can click on the side of the cell output to collapse or expand the scrollable window. This has the unintended consequence of changing the contrast of the image displayed in the Cubeviz cube viewer.
Imviz
add_markers may not show markers
In some OS/browser combinations, imviz.add_markers(...)
might take a few tries
to show the markers, or not at all. This is a known bug reported in
https://github.com/glue-viz/glue-jupyter/issues/243 . If you encounter this,
try a different OS/browser combo.
Specviz
Spectrum does not appear when running on a Linux VM
See the identically named issue in Cubeviz.
Line List Plugin redshift and radial velocity do not roundtrip to full precision
Giving a redshift value will report a converted radial velocity, which if entered manually will not convert to the exact same redshift value. Note that the redshift value is always treated as the true value and used when plotting lines, etc.
License & Attribution
This project is Copyright (c) JDADF Developers and licensed under the terms of the BSD 3-Clause license.
This package is based upon the Astropy package template which is licensed under the BSD 3-clause licence. See the licenses folder for more information.
Cite jdaviz
via our Zenodo record: https://doi.org/10.5281/zenodo.5513927.