Viewer tutorial#

Welcome to the tutorial on the napari viewer!

This tutorial assumes you have already installed napari and know how to launch the viewer. For help with installation see our installation tutorial. For help launching the viewer see our getting started tutorial.

This tutorial will teach you about the napari viewer, including how to use its graphical user interface (GUI) and how the data within it is organized. At the end of the tutorial, you should understand both the layout of the viewer on the screen and the data inside of it.

Launching the viewer#

As discussed in the getting started tutorial, the napari viewer can be launched from the command-line, a python script, an IPython console, or a Jupyter notebook. All four methods launch the same viewer, and anything related to interacting with the viewer on the screen applies equally to all of them. We will use the syntax for running the code inside a jupyter notebook with each code block below pasted into its own cell, but if you’d like to use a python script instead, simply copy and paste the code blocks into scripts with napari.run() as the final line (this starts an event loop which will open an interactive viewer) and run them.

Note: There is also an IPython console available in napari, when napari is launched from the terminal, from a Python script, or when you use the napari bundled app. You can open it with the IPython console button (far left viewer button) or with the menu option Window > console. You can use this console to programmatically interact with an open viewer using the API methods illustrated in this tutorial.

Let’s get started by launching a viewer with a simple 2D image.

The fastest way to open a viewer with an image on the canvas is using imshow:

from skimage import data

import napari

viewer, image_layer = napari.imshow(data.astronaut(), rgb=True)

Calling imshow will return a Viewer object that is the main object inside napari and a Image layer object. All the data you add to napari will be stored inside the Viewer object and will be accessible from it. This command will also open the viewer to create a GUI that you can interact with. The Image will contain information about the image and allow you to access image methods.

You can also create an empty Viewer directly and then start adding images to it. For example:

from skimage import data

import napari

viewer = napari.Viewer()
new_layer = viewer.add_image(data.astronaut(), rgb=True)

add_image accepts the same arguments as imshow but only returns an Image layer instead of both the Viewer and Image layer (as you must already have a viewer to use it).

After running either of those two commands, you should be able to see the photograph of the astronaut in the napari viewer as shown below:

Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="photograph of an astronaut in napari viewer")
photograph of an astronaut in napari viewer

imshow and the add_image methods accept any numpy-array like object as input, including n-dimensional arrays. For more information on adding images to the viewer see the image layer guide.

Now we will continue exploring the rest of the viewer.

Layout of the viewer#

The viewer is organized into a few key areas which are explained in the next sections:

  • Main Menu (top bar menu)

  • Layer Controls

  • Layer Buttons

  • Layer List

  • Viewer Buttons

  • Status Bar

  • Canvas

  • Dimension Sliders

  • Scroll Buttons

  • Frame Playback

The image below has the areas of the viewer labeled:

image: viewer layout

We’ll go through each of these in the next sections.

Canvas#

The canvas is in the center of the viewer and contains the visual display of the data passed to napari, including Images, Points, Shapes, and other supported data types. Under the hood, the canvas is a vispy.scene.SceneCanvas object which has built-in support for features such as zooming and panning. As vispy uses OpenGL and your graphics card, panning and zooming are highly performant. You can return to the original zoom level by clicking the home button in the viewer buttons panel.

Layer list#

Layers are one of the basic napari objects. There are different layer types for Image, Points, Shapes, and other data types. They can be added to the viewer either programmatically or through the GUI. Once added, they populate the layer list located on the bottom left side of the canvas.

The layer list contains one widget for each of the layers that have been added to the viewer and includes a thumbnail that shows a miniaturized version of the currently viewed data, a name that is an editable text box, a visibility button (eye icon) that can be toggled on or off to show or hide the layer, and an icon for the layer type. Note that you can Option/Alt-click on the visibility button to show just that one layer, hiding all others. If you then Option/Alt-click on the visibility button of a layer a second time, the visibility state of all layers will be restored. Alternately, you can cycle through layers in the layer list, showing only one at a time, by using Shift+Option/Alt and the Up or Down keys.

Adding the following three image layers using the code below adds three-layer widgets to the layer list as follows:

import napari

from skimage import data

viewer = napari.Viewer()
viewer.add_image(data.astronaut(), name='astronaut')
viewer.add_image(data.moon(), name='moon')
viewer.add_image(data.camera(), name='camera')
Hide code cell source
nbscreenshot(viewer, alt_text="3 image layers shown in napari viewer with the canvas displaying a photograph of a man looking through a camcorder")
3 image layers shown in napari viewer with the canvas displaying a photograph of a man looking through a camcorder

Note that we’ve also named each of the layers using the name keyword argument in add_image, and that name appears as a string in the layer widget. The layer name is coerced into being unique so it can be used to index into the LayerList.

You can select layers, which highlights them, by clicking on their layer widget. Multiple layers can be simultaneously selected using either shift click to select all the layers in between two clicked-on layers or Ctrl+click (Windows) or Command+click to select just the clicked on layers respectively.

You can rearrange the order of the layers by dragging them, including dragging multiple layers at the same time.

The Viewer object also contains the LayerList object that allows access to the data of all the layers with:

viewer.layers
[<Image layer 'astronaut' at 0x7fbba0058f70>, <Image layer 'moon' at 0x7fbb92f35f60>, <Image layer 'camera' at 0x7fbba89727a0>]

This object can be indexed like a normal list using an int or using the str name of the layer as follows:

viewer.layers[0]
<Image layer 'astronaut' at 0x7fbba0058f70>
viewer.layers['astronaut']
<Image layer 'astronaut' at 0x7fbba0058f70>

You can rearrange layers by clicking and dragging them.

Layer controls#

Above the layer list in the top left corner of the viewer there is a box that contains the layer controls. The controls that are available depend on the layer type selected.

For example, if you add a Points layer after adding an Image layer, the new Points layer will be ‘selected’ and you will now see different controls.

import numpy as np
from skimage import data

import napari

viewer, image_layer = napari.imshow(data.astronaut(), rgb=True)
points = np.array([[100, 100], [200, 200], [300, 100]])
viewer.add_points(points, size=30)
Hide code cell source
nbscreenshot(viewer, alt_text="points layer showing 3 white points layered on top of astronaut image in napari viewer")
points layer showing 3 white points layered on top of astronaut image in napari viewer

Adjusting these properties in the layers list will cause corresponding changes to properties on the selected individual layers. These properties can also be changed and accessed in the console through viewer.layers.

For example, the name and opacity of a layer can be changed within the console as follows:

viewer.layers[0].name = 'astronaut'
viewer.layers[0].opacity = 0.7

and these changes will instantly propagate to the GUI. For more information about the different properties for different layer types please see our layer specific tutorials listed at the bottom of this tutorial.

Create Layer buttons#

New empty Points, Shapes, and Labels layers can be added to the viewer using the layer buttons between the layer controls and layer list. This is equivalent to, for example, the following code to make an empty Points layer:

viewer.add_points()

Once added, either in the GUI or via the console, these layers become accessible in the layers list section of the GUI and at viewer.layers. For example, an empty Points layer created using the code snippet above can be accessed using viewer.layers['Points'].

Layers can be deleted by selecting them and clicking on the delete button with the trash icon (or using the keybinding as set in the Preferences).

In the console a layer at index i can be removed by:

viewer.layers.pop(i)

Dimension sliders#

One of the main strengths of napari is that it has been designed from the beginning to handle n-dimensional data. While much consumer photography is 2D and RGB, scientific image data can often be volumetric (i.e. 3D), volumetric timeseries (i.e. 4D), or even higher dimensional. napari places no limits on the dimensionality of its input data for all its layer types.

Adding data with a dimensionality greater than 2D will cause dimension sliders to appear directly underneath the canvas and above the status bar. As many sliders as needed will appear to ensure the data can be fully browsed. For example, a 3D dataset needs one slider, a 4D dataset needs two sliders, and so on. The widths of the scroll bars of the dimension sliders are directly related to how many slices are in each dimension. To the left of each slider will be an integer indicating which dimension is being controlled by that slider. These integers are automatically updated when changing which dimensions are to be displayed. Alternately, the sliders can be labeled by double-clicking on the integer and editing the field. The labels can be retrieved programatically as follows:

# To get the dimension labels
viewer.dims.axis_labels
('0', '1')

You can also set the axis labels programatically as follows:

# To set new axis labels
viewer.dims.axis_labels = ("label_1", "label_2")

It is also possible to mix data of different shapes and dimensionality in different layers. If a 2D and 4D dataset are both added to the viewer then the sliders will affect only the 4D dataset, the 2D dataset will remain the same. Effectively, the two datasets are broadcast together using NumPy broadcasting rules.

For example, the following commands from the console will add both 2D and 3D datasets to the same viewer:

import numpy as np
from skimage import data

import napari

viewer = napari.Viewer()
viewer.add_image(data.moon(), name='moon')
blobs = np.stack(
    [
        data.binary_blobs(
            length=512, blob_size_fraction=0.05, n_dim=2, volume_fraction=f
        )
        for f in np.linspace(0.05, 0.5, 10)
    ],
    axis=0,
).astype(float)
viewer.add_image(blobs, name='blobs', opacity=0.5, colormap='red')
Hide code cell source
nbscreenshot(viewer, alt_text="A 2d view of the moon on top of which is overlaid a 3d volume containing blobs through which you can navigate using the dimension slider.")
A 2d view of the moon on top of which is overlaid a 3d volume containing blobs through which you can navigate using the dimension slider.

In this example there are three dimensions. In order to get or update the current position of the sliders, use:

# To get the current position returned as tuple of length 3
viewer.dims.current_step
(0, 255, 255)

And to change the current position of the sliders use:

# To change the current position of this example to step 3
viewer.dims.current_step = (3, 255, 255)

The length of the current_step tuple corresponds to the number of dimensions. Note that in this example, the last two dimensions are displayed (don’t have a slider) and thus changing the last two elements of the tuple will have no effect until the axes order is changed.

Lastly, viewer.dims.point contains the position in world coordinates (i.e., including scale and translate transformations).

Scroll buttons#

On the left and right ends of the dimension sliders are scroll buttons that take you to the edge of the image or one page back. If you press and hold it, it will scroll through the layers of the image.

Frame Playback button#

On the left end of the dimension slider is the frame playback button. Right clicking on this button brings up a control panel that allows you to enter the number of frames per second; the play direction, either forward or backward; and the play mode, once, loop, or back and forth. Left clicking this button will play the image back according to these parameters.

Viewer buttons#

Below the layer list is a row containing these buttons:

  • Console

  • 2D/3D

  • Roll Dimensions

  • Transpose Dimensions

  • Grid display

  • Home

image: Viewer buttons

Each one is explained below.

Console button#

The first button on the left end of the row is the Console button. It shows or hides the console and allows you to interact with the python kernel. Inside the console, for example, you can access the Viewer instance using the viewer argument.

This button is enabled if you launch napari from the command line, a script, or use the napari bundled app. The console is disabled if the napari viewer is opened from a Jupyter notebook or launched from within IPython, in favor of the user continuing to use the existing interactive console.

The console (when available) appears at the bottom of the viewer as shown below:

image: console within napari

Toggle 2D/3D button#

The second button from the left is the 2D/3D button which toggles between 2D and 3D renderings of the data. For example, run the following code:

from skimage import data
from scipy import ndimage as ndi

import napari


blobs = data.binary_blobs(length=128, volume_fraction=0.1, n_dim=3)
viewer, image_layer = napari.imshow(blobs.astype(float), name='blobs')
labeled = ndi.label(blobs)[0]
viewer.add_labels(labeled, name='blob ID')

then, by clicking the 2D/3D button, you can switch to viewing the 3D rendering. Note that the icon will change to the following, to indicate 3D mode:

image: 3D_button

This mode can be entered programmatically using:

viewer.dims.ndisplay = 3

In this mode, when you can drag with the mouse you will rotate the 3D rendering (change the camera view of the image) and see what it looks like from the side, back, or a different angle. To do this, click on the image and drag the cursor to a new position, which will give something like the following view:

Hide code cell source
# programmatically adjust the camera angle
viewer.dims.ndisplay = 3
viewer.camera.zoom = 2
viewer.camera.angles = (3, 38, 53)
nbscreenshot(viewer, alt_text="A rotated 3D view")
A rotated 3D view

Note that if you want to drag the canvas/rendering itself, instead of rotating the view, you have to hold down the Shift key while dragging with the mouse. Finally, while in 3D mode you can change the perspective of the 3D view by holding Shift, pressing the right mouse button (on macOS holding Control) and dragging the mouse or by right-clicking (on macOS holding Control and clicking) on the 2D/3D mode button, which will bring up the perspective slider. The camera perspective can also be altered programmatically:

viewer.camera.perspective = 45

Roll dimensions#

The third button rolls the dimensions that are currently displayed in the viewer. For example if you have a ZYX volume and are looking at the YX slice, this will then show you the ZY slice. You can also right-click this button to pop-up a widget that allows you to re-order the dimensions by drag-and-drop or lock a dimension, by clicking on the padlock icon:

image: roll dimensions widget with padlock icons

Locking prevents a dimension from being rolled (reordered). This can be particularly useful, for example, with a 3D+time dataset where you may want to fix the time dimension, while being able to roll through the spatial dimensions.

The dimension order can also be checked programmatically as follows:

# To get the current dimension order as tuple of int
viewer.dims.order
(0, 1, 2)

And then, changed programmatically as follows:

# To change the current dimension order
viewer.dims.order = (2, 1, 0)

In this case the third dimension will be controlled by the slider and the first and second dimension will be visible. Note that this has no effect on the order of viewer.dims.current_step. The first element still corresponds to the first dimension for example. These are just examples; the only requirement is that the length of the tuple is the same as the number of dimensions.

Transpose dimensions#

The fourth button transposes the displayed dimensions.

Grid button#

Then there is a grid button that toggles grid mode. When clicked it displays each layer of the image in its own tile. You can right-click this button to adjust the way the tiles are presented, such as the grid dimensions, the order of the layers in the tiles, and whether layers are overlaid in the tiles.

Home button#

Finally, there is the home button. It resets the camera to its initial values.

Status bar#

At the very bottom of the GUI there is a status bar that contains useful updates and tips.

On the left side of the status bar there is a message about the position of the mouse and the values of any images or the indices of any Points that are currently hovered over, depending on which layer is selected. When there are buttons in the layer controls panel, the status bar displays information about the layer controls button you are clicking. The buttons are not available for every layer type.

The right side of the status bar contains some helpful tips depending on which layer and tools are currently selected.

Right-click menu#

A context-sensitive menu is available when you right-click on any of the layers. The type of layer determines which options are available. Note that if you have multiple layers selected, the menu actions will affect all of the selected layers. The options that are not available for a layer are greyed out. The following options are available depending on which layer type you have selected:

  • Toggle visibility - invert the visibility state (hides or show) of selected layers: hidden layers will be shown, visible layers will be hidden.

  • Show All Selected Layers - Set all selected layers to visible.

  • Hide All Selected Layers - Set all selected layers to hidden.

  • Show All Unselected Layers - Set all unselected layers to visible.

  • Hide All Unselected Layers - Set all unselected layers to hidden.

  • Duplicate Layer - creates a second copy of the selected layer. Can be used on Points, Shapes, Labels, and Image layers. This is useful for testing your analysis on a copy instead of on the original image.

  • Convert to Labels - converts an Image layer to a Labels layer (if the data is already of type int it is not copied or altered, only the representation is changed, making this fully reversible). This is useful for converting a binary image segmentation map to a labels layer with each segmented object denoted by its own integer. Can also be used on a Shapes layer, in this case a new Labels layer will be created.

  • Convert to Image - converts a Labels layer into an Image layer (the data is not copied or altered, only the representation is changed, making this fully reversible).

  • Convert datatype - converts a Labels layer into int8, int16, int32, int64, uint8, uint16, uint32, or uint64 data types. The initial data type is the data type of the data itself.

  • Make Projection - can be used only on a layer with more than 2 dimensions, also known as a stack. It creates a new layer that is a projection of the layer stack with the characteristic the user selects, reducing the number of dimensions by 1. More information about the types of projections is available here. The following projections are available:

    • Max - maximum intensity projection. At each pixel position, we go through the stacks, find the pixel with the maximum intensity, and that becomes the intensity of that pixel value in the projected image.

    • Min - minimum intensity projection. Similar to the maximum intensity projection, except that the minimum pixel value is used for the projected image instead of the maximum pixel value.

    • Std - the standard deviation projection. At each pixel position, the standard deviation of the pixel intensities through the stack is the assigned value of that pixel position. Positions with large differences in the pixel intensities through the stack appear brighter in this projection.

    • Sum - the sum projection simply adds together all the pixel values in the stack for a given position. In this projection, the image is typically re-scaled to a 16-bit image, as the sum of all the pixel intensity values usually exceeds 255, which would result in a completely white 8-bit image.

    • Mean - the mean projection is the average intensity projection. It simply averages all the pixel values in the stacks to make the final projected image.

    • Median - the median projection takes the median pixel intensity for the final projected image.

  • Split RGB - if the image layer is an RGB image, it will be split into 3 new layers with red, green, and blue values in separate layers.

  • Split Stack - if an image layer is a stack (has 3 or more dimensions), it is split into a list of layers along the axis. This option takes a little time to execute. Properties will be changed as follows:

    • Colormap: (magenta, green) for a stack with 2 channels, (CYMRGB) for stacks with more than 2 channels

    • Blending: additive

    • Contrast_limits: min and max values of the layer

    • All other properties, such as Scale and Translate will be propagated from the original stack.

  • Merge to Stack - combines a set of layers to a single-layer stack. The resulting layer stack will contain the layers with their original ordering in the layer list. Layers must be of the same type (e.g. An Image layer can be merged only with other Image layers.) and must have the same dimensionality. (e.g. a 1024 x 1024 layer can only be merged with another 1024 x 1024 layer.)

  • Link Layers - links the selected layers. Once layers are linked, any action performed on one layer will be performed on all linked layers at the same time. The layer control panel will show only when a single layer is selected. Changing properties with that layer’s control panel will change properties in all of the linked layers.

  • Unlink Layers - appears when layers are linked. It unlinks the layers so that changes to one of the layer’s properties no longer result in the same changes to the previously linked layers.

  • Select Linked Layers - appears only when layers are linked. Selects all layers linked to a given layer.

Changing the viewer theme#

Currently, napari comes with light, dark themes for the viewer; the default is dark. Additionally, there is the system virtual theme that will attempt to match the viewer theme (light or dark) to your system theme on macOS, Windows, and some Linux. To change the preferred theme used for all viewers you can use the Preferences menu item in the File or napari menu and then select the Appearance tab. You can also change the theme property of the current viewer by using the following code:

from skimage import data

import napari

viewer, image_layer = napari.imshow(data.astronaut(), name='astronaut')

# change the viewer theme
viewer.theme = 'light'
Hide code cell source
nbscreenshot(viewer, alt_text="A napari viewer changed to light theme")
A napari viewer changed to light theme

You can also change the theme using the “Toggle theme” keyboard shortcut, by default Command/Control+Shift+T. Note that changing the theme using this shortcut will only change the current viewer theme. If you wish to make the change permanent for all viewers, make sure to also change your settings in the Appearance tab of the Preferences menu.

Adding your own custom theme isn’t too hard but it requires creating your own color palette and rebuilding the icons. It’s also possible for plugins to contribute a theme. If people want more themes, we’re happy to add them or you can look at our contributing guidelines for more information about building the icons and add one yourself!

Custom keybinding#

napari provides a number of built-in keyboard shortcuts, which you can access and change in Preferences>Shortcuts.

Note: Preferences is under the File menu on Windows and under napari on macOS.)

One of the promises of napari is to provide a beginner friendly environment for interactive analysis. For example, we want to enable workflows where people can interact with the GUI, say, click on the centers of some objects or paint over some regions and then perform custom analysis. As a first step towards enabling custom interactivity we’ve provided support to add your own custom keybindings to the Viewer or individual Layer objects such that when the corresponding key gets clicked, your custom function gets executed. Depending on which object you bind your key to, your function will either get access to the state of the entire Viewer or Layer object.

For example, to bind a function that loops through all layers in the viewer and prints their names to your console when you press the p key you can do the following:

from skimage import data

import napari

viewer, image_layer = napari.imshow(data.astronaut(), name='astronaut')

@viewer.bind_key('p')
def print_names(viewer):
    print([layer.name for layer in viewer.layers])

By default, your key will bind to the key press event, but it is also possible to bind to the key release event by including a yield inside your function. All code before the yield will get executed on key press and all code after the yield will get executed on key release. The following example will print hello when you start to press the m key and print goodbye when you release it.

viewer, image_layer = napari.imshow(data.astronaut(), name='astronaut')

@viewer.bind_key('m')
def print_message(viewer):
    print('hello')
    yield
    print('goodbye')

Keys can be bound both to the object class or a particular instance depending on if you want the keybinding to apply to all instances of the class or only one particular instance.

Currently the keybindings only work when the canvas is in focus, we are working to ensure they always work.

The ability to add custom keybindings dramatically increases what is possible within napari and we hope you take full advantage of them.

Next steps#

This tutorial has given you an overview of the functionality available on the napari viewer, including the LayerList and some of the different layer types. To learn more about the different layer types napari supports, check out our guides on using layers.

For a more detailed introduction to layer manipulation see Layers at a glance.