Visualizing Data

For data visualization, starfish relies on the napari package, which is a fast image viewer for in-memory data stored as numpy arrays. Starfish provides a wrapper over napari called display(), and maintains a stable version of the package. To use the napari Viewer you must have followed Installation to install the napari extra and enabled the qt environment in IPython.

The display() function can be used to visually inspect your raw images, filtered images, results of spot finding, and cell segmentation masks. All of these can be overlaid on the same coordinates as layers that can be toggled on/off, making it extremely easy to compare the inputs and outputs of starfish functions. The table below shows which starfish data structures can be viewed with display() and how.

Data Structure

display parameter

napari layer type

ImageStack

stack

image

IntensityTable

spots

points

BinaryMaskCollection

masks

labels

Note

Currently starfish does not support displaying SpotFindingResults directly (see: #1721). One option is to use a TraceBuildingStrategy or a DecodeSpotsAlgorithm to create an IntensityTable or :py:class:.DecodedIntensityTable`, respectively. But if you need to directly view the results of your spot finding, see the last section of this tutorial.

Basic examples of visualizing data with display() can be found in Interactive Image Viewer: display() and application-specific examples are scattered throughout the tutorials. This tutorial will demonstrate some more advanced functions of the image Viewer using napari commands. Due to the GUI, the code cannot be rendered here, but you can use the same code in your IPython console.

Start with the Quick Start tutorial

For this demonstration, we will use the Quick Start data registered_imgs, decoded, and masks, which are an ImageStack, DecodedIntensityTable, and BinaryMaskCollection, respectively.

If you run display() like so:

>>> %gui qt
>>> display(stack=registered_imgs, spots=decoded, masks=masks)

An image Viewer should pop up that looks something like this:

../../_images/napari-viewer.png

Using the GUI

We recommend, checking out the napari viewer tutorial to see everything you can do with the GUI but some basic functions you can try include using your scroll wheel to zoom, sliding the sliders to view different rounds and channels, and toggling the layer visibilities.

Adding additional layers

Now you may want to view more than one of each data structure in the same Viewer. For example, to compare an ImageStack before and after filtering. display() only accepts one argument for each parameter, so to have two layers of the same type you have to call display() a second time and pass it the name of the first image Viewer.

>>> viewer = display(stack=registered_imgs, spots=decoded, masks=masks)
>>> viewer = display(stack=imgs_wth, viewer=viewer)

This adds another layer named stack [1] to differentiate it from the original stack.

../../_images/quickstart-napari-screenshot-3.png

Naming your layers with napari commands

By default, display() names every ImageStack layer stack, every IntensityTable layer spots, and every BinaryMaskCollection layer masks. If you want to give the layers custom names, you could use the GUI and double click the names to edit. Or you can use napari methods, which gives you many more options to tweak your layer properties (see napari).

However, napari doesn’t natively support starfish data structures, so to use napari methods follow the example below. Adding IntensityTables is pretty complex, so we recommend sticking with display() for that or using the method in the next section.

>>> import napari
>>> viewer.add_image(dots_wth.xarray, name='dots')
>>> viewer.add_labels(masks.to_label_image().label_image, name='cells')
../../_images/quickstart-napari-screenshot-4.png

Directly visualizing SpotFindingResults

You can convert the SpotAttributes from each round and channel of SpotFindingResults to a numpy array and then use napari commands to display them in your Viewer.

# save SpotAttributes for each (round,channel) as numpy array in list
spots_numpy = list()
for rnd in spots.round_labels:
    for ch in spots.ch_labels:
        spots_numpy.append(spots[{Axes.CH:ch, Axes.ROUND:rnd}].spot_attrs.data[['z', 'y',
        'x']].to_numpy())

# display found spots for each (round,channel) as a layer in napari
viewer = display(stack=imgs)
layer_index = 0
for rnd in spots.round_labels:
    for ch in spots.ch_labels:
        viewer.add_points(data=spots_numpy[layer_index], symbol='ring', face_color='red',
                          size=5, name=f'r: {rnd}, ch: {ch}', visible=False)
        layer_index = layer_index + 1
../../_images/quickstart-napari-screenshot-5.png

Gallery generated by Sphinx-Gallery