Using the image layer#

In this document, you will learn how to use the napari image layer, including the types of images that can be displayed, and how to set properties like contrast limits, opacity, colormaps, blending and interpolation. You will also understand how to add and manipulate a variety of different types of images both from the GUI and from the console.

For more information about layers, refer to Layers at a glance.

Controlling the image layer using the GUI#

The GUI contains following tools in the layer controls panel for the image layer:

  • Opacity

  • Contrast Limits

  • Auto-contrast

  • Gamma

  • Colormap

  • Blending

  • Interpolation

Before we can use any of the GUI layer controls, we must load an image.

  1. Start napari.

  2. Click File > Open Sample > napari builtins > Cells (3D+2Ch) or any sample image of your choice.

The GUI controls may be adjusted as follows:

  • opacity is adjusted by moving the circle along the slider until the image has the opacity you want. 0 is transparent and 1 is completely opaque.

  • contrast limits are adjusted by moving the minimum and maximum circles along the slider until you have the contrast limits you want. For more precise control, including the ability to set specific numerical values, you can right-click on the slider. Note: Contrast limits are explained in Adjusting contrast limits.

  • auto-contrast is adjusted by selecting either once or continuous. once adjusts the contrast one time while continuous adjusts the contrast as you explore the image.

  • gamma can be adjusted from a minimum of 0.20 to a maximum of 2.00. Gamma correction or gamma is a nonlinear operation used to encode and decode luminance or tristimulus values.

  • colormap is selected from the dropdown. Note: If the image you select is an RGB or RGBA image, the colormap is automatically assigned RGB and cannot be changed. You can find out if your image is RGB or RGBA by looking at the .rgb property of the image layer.

  • blending has the options of translucent, translucent no depth, additive, minimum, or opaque in the dropdown. Refer to the Blending layers section of Layers at a glance for an explanation of each type of blending.

  • interpolation may be assigned one of the following from the dropdown:

    • cubic

    • linear

    • kaiser

    • nearest - default

    • spline36

    Note: There is a brief explation of interpolation in Layers at a glance.

Controlling the image layer from the console#

A simple example#

Create a new viewer and add an image in one go using the napari.view_image() function, or if you already have an existing viewer, add an image to it using viewer.add_image. The API for both methods is the same. In these examples we’ll mainly use view_image.

A simple example of viewing an image is as follows:

import napari
from skimage import data

cells = data.cells3d()[30, 1]  # grab some data
viewer = napari.view_image(cells, colormap='magma')
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="Cells")
Cells

Arguments of view_image and add_image#

view_image() and add_image() accept the same layer-creation parameters.

help(napari.view_image)
Hide code cell output
Help on function view_image in module napari.view_layers:

view_image(data=None, *, channel_axis=None, affine=None, attenuation=0.05, blending=None, cache=True, colormap=None, contrast_limits=None, custom_interpolation_kernel_2d=None, depiction='volume', experimental_clipping_planes=None, gamma=1.0, interpolation2d='nearest', interpolation3d='linear', iso_threshold=None, metadata=None, multiscale=None, name=None, opacity=1.0, plane=None, projection_mode='none', rendering='mip', rgb=None, rotate=None, scale=None, shear=None, translate=None, visible=True, title='napari', ndisplay=2, order=(), axis_labels=(), show=True, camera: napari.components.camera.Camera = None, cursor: napari.components.cursor.Cursor = None, dims: napari.components.dims.Dims = None, grid: napari.components.grid.GridCanvas = None, layers: napari.components.layerlist.LayerList = None, help: str = '', status: Union[str, dict] = 'Ready', tooltip: napari.components.tooltip.Tooltip = None, theme: str = None, mouse_over_canvas: bool = False) -> napari.viewer.Viewer
    Create a viewer and add an image layer.
    
    Parameters
    ----------
    data : array or list of array
        Image data. Can be N >= 2 dimensional. If the last dimension has length
        3 or 4 can be interpreted as RGB or RGBA if rgb is `True`. If a
        list and arrays are decreasing in shape then the data is treated as
        a multiscale image. Please note multiscale rendering is only
        supported in 2D. In 3D, only the lowest resolution scale is
        displayed.
    channel_axis : int, optional
        Axis to expand image along. If provided, each channel in the data
        will be added as an individual image layer. In channel_axis mode,
        other parameters MAY be provided as lists. The Nth value of the list
        will be applied to the Nth channel in the data. If a single value
        is provided, it will be broadcast to all Layers.
        All parameters except data, rgb, and multiscale can be provided as
        list of values. If a list is provided, it must be the same length as
        the axis that is being expanded as channels.
    affine : n-D array or napari.utils.transforms.Affine
        (N+1, N+1) affine transformation matrix in homogeneous coordinates.
        The first (N, N) entries correspond to a linear transform and
        the final column is a length N translation vector and a 1 or a
        napari `Affine` transform object. Applied as an extra transform on
        top of the provided scale, rotate, and shear values.
    attenuation : float or list of float
        Attenuation rate for attenuated maximum intensity projection.
    blending : str or list of str
        One of a list of preset blending modes that determines how RGB and
        alpha values of the layer visual get mixed. Allowed values are
        {'translucent', 'translucent_no_depth', 'additive', 'minimum', 'opaque'}.
    cache : bool or list of bool
        Whether slices of out-of-core datasets should be cached upon
        retrieval. Currently, this only applies to dask arrays.
    colormap : str, napari.utils.Colormap, tuple, dict, list or list of these types
        Colormaps to use for luminance images. If a string, it can be the name
        of a supported colormap from vispy or matplotlib or the name of
        a vispy color or a hexadecimal RGB color representation.
        If a tuple, the first value must be a string to assign as a name to a
        colormap and the second item must be a Colormap. If a dict, the key must
        be a string to assign as a name to a colormap and the value must be a
        Colormap.
    contrast_limits : list (2,)
        Intensity value limits to be used for determining the minimum and maximum colormap bounds for
        luminance images. If not passed, they will be calculated as the min and max intensity value of
        the image.
    custom_interpolation_kernel_2d : np.ndarray
        Convolution kernel used with the 'custom' interpolation mode in 2D rendering.
    depiction : str or list of str
        3D Depiction mode. Must be one of {'volume', 'plane'}.
        The default value is 'volume'.
    experimental_clipping_planes : list of dicts, list of ClippingPlane, or ClippingPlaneList
        Each dict defines a clipping plane in 3D in data coordinates.
        Valid dictionary keys are {'position', 'normal', and 'enabled'}.
        Values on the negative side of the normal are discarded if the plane is enabled.
    gamma : float or list of float
        Gamma correction for determining colormap linearity; defaults to 1.
    interpolation2d : str or list of str
        Interpolation mode used by vispy for rendering 2d data.
        Must be one of our supported modes.
        (for list of supported modes see Interpolation enum)
        'custom' is a special mode for 2D interpolation in which a regular grid
        of samples is taken from the texture around a position using 'linear'
        interpolation before being multiplied with a custom interpolation kernel
        (provided with 'custom_interpolation_kernel_2d').
    interpolation3d : str or list of str
        Same as 'interpolation2d' but for 3D rendering.
    iso_threshold : float or list of float
        Threshold for isosurface.
    metadata : dict or list of dict
        Layer metadata.
    multiscale : bool
        Whether the data is a multiscale image or not. Multiscale data is
        represented by a list of array-like image data. If not specified by
        the user and if the data is a list of arrays that decrease in shape,
        then it will be taken to be multiscale. The first image in the list
        should be the largest. Please note multiscale rendering is only
        supported in 2D. In 3D, only the lowest resolution scale is
        displayed.
    name : str or list of str
        Name of the layer.
    opacity : float or list
        Opacity of the layer visual, between 0.0 and 1.0.
    plane : dict or SlicingPlane
        Properties defining plane rendering in 3D. Properties are defined in
        data coordinates. Valid dictionary keys are
        {'position', 'normal', 'thickness', and 'enabled'}.
    projection_mode : str
        How data outside the viewed dimensions, but inside the thick Dims slice will
        be projected onto the viewed dimensions. Must fit to cls._projectionclass
    rendering : str or list of str
        Rendering mode used by vispy. Must be one of our supported
        modes. If a list then must be same length as the axis that is being
        expanded as channels.
    rgb : bool, optional
        Whether the image is RGB or RGBA if rgb. If not
        specified by user, but the last dimension of the data has length 3 or 4,
        it will be set as `True`. If `False`, the image is interpreted as a
        luminance image.
    rotate : float, 3-tuple of float, n-D array or list.
        If a float, convert into a 2D rotation matrix using that value as an
        angle. If 3-tuple, convert into a 3D rotation matrix, using a yaw,
        pitch, roll convention. Otherwise, assume an nD rotation. Angles are
        assumed to be in degrees. They can be converted from radians with
        'np.degrees' if needed.
    scale : tuple of float or list of tuple of float
        Scale factors for the layer.
    shear : 1-D array or list.
        A vector of shear values for an upper triangular n-D shear matrix.
    translate : tuple of float or list of tuple of float
        Translation values for the layer.
    visible : bool or list of bool
        Whether the layer visual is currently being displayed.
        title : string, optional
        The title of the viewer window. By default 'napari'.
    ndisplay : {2, 3}, optional
        Number of displayed dimensions. By default 2.
    order : tuple of int, optional
        Order in which dimensions are displayed where the last two or last
        three dimensions correspond to row x column or plane x row x column if
        ndisplay is 2 or 3. By default None
    axis_labels : list of str, optional
        Dimension names. By default they are labeled with sequential numbers
    show : bool, optional
        Whether to show the viewer after instantiation. By default True.
    
    
    Returns
    -------
    viewer : :class:`napari.Viewer`
        The newly-created viewer.

Image data and NumPy-like arrays#

napari can take any NumPy-like array as input for its image layer. A NumPy-like array can be a numpy array, a dask array, an xarray, a zarr array, or any other object that you can index into and when you call np.asarray on it you get back a NumPy array.

The great thing about napari support of array-like objects is that you get to keep on using your favorite array libraries without worrying about any conversions. napari handles all of that for you.

napari will also wait until just before it displays data onto the screen to actually generate a NumPy array from your data, and so if you’re using a library like dask or zarr that supports lazy loading and lazy evaluation, we won’t force you to load or compute data that you’re not examining. This enables napari to seamlessly browse enormous datasets that are loaded in the right way. For example, here we are browsing over 100GB of lattice lightsheet data stored in a zarr file:

Multiscale images#

For exceptionally large datasets, napari supports multiscale images (sometimes called image pyramids). A multiscale image is a list of arrays, where each array is downsampling of the previous array in the list. This means you end up with images of successively smaller and smaller shapes. A standard multiscale image might have a 2x downsampling at each level, but napari can support any type of multiscale image as long as the shapes are getting smaller each time.

Multiscale images are especially useful for incredibly large 2D images when viewed in 2D or incredibly large 3D images when viewed in 3D. For example this ~100k x 200k pixel pathology image consists of 10 pyramid levels and can be easily browsed as at each moment in time we only load the level of the multiscale image and the part of the image that needs to be displayed:

This example had precomputed multiscale images stored in a zarr file, which is best for performance. If you don’t have a precomputed multiscale image but try and show an exceptionally large image, napari will try and compute the multiscale image for you unless you tell it not to.

You can use the boolean multiscale keyword argument when creating an image layer to specify if your data is a multiscale image or not. If you don’t provide this value, then napari will try and guess whether your data is or needs to be a multiscale image.

Loading multichannel images#

Each channel in a multichannel image can be displayed as an individual layer by using the channel_axis argument in viewer.add_image(). All the rest of the arguments to viewer.add_image() (e.g. name, colormap, contrast_limit) can take the form of a list of the same size as the number of channels.

For example, the multichannel image below has dimensions (60, 2, 256, 256) with axes ordered ZCYX (so the channel axis has an index of 1). It is loaded into napari in one line, as shown below:

import napari
from skimage import data

cells = data.cells3d() #ZCYX image data

# load multichannel image in one line
viewer = napari.view_image(cells, channel_axis=1)

# load multichannel image in one line, with additional options
viewer = napari.view_image(
    cells,
    channel_axis=1,
    name=["membrane", "nuclei"],
    colormap=["green", "magenta"],
    contrast_limits=[[1000, 20000], [1000, 50000]],
)
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="napari viewer with a multichannel image of cells displayed as two image layers: nuclei and membrane.")
napari viewer with a multichannel image of cells displayed as two image layers: nuclei and membrane.

Viewing RGB vs luminance (grayscale) images#

In this example, the rgb keyword is explicitly set to True because we know we are working with an rgb image:

viewer = napari.view_image(data.astronaut(), rgb=True)
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="napari viewer with the left sidebar layer controls and an image of astronaut Eileen Collins. In the layer controls, the colormap is fixed to RGB")
napari viewer with the left sidebar layer controls and an image of astronaut Eileen Collins. In the layer controls, the colormap is fixed to RGB

If we had left the rgb keyword argument out, napari would have successfully guessed that we were trying to show an rgb or rgba image because the final dimension for the image array was 3 or 4. If you have a luminance image where the last dimension is 3 or 4, you can set the rgb argument to False to explicitly state this is not a color image and get a slider for that dimension.

rgb data must either be uint8, corresponding to values between 0 and 255, or float and between 0 and 1. If the values are float and outside the 0 to 1 range they will be clipped.

Working with colormaps#

napari supports any colormap that is created with vispy.color.Colormap. We provide access to some standard colormaps that you can set using a string of their name. These include:

list(napari.utils.colormaps.AVAILABLE_COLORMAPS)
['blue',
 'bop blue',
 'bop orange',
 'bop purple',
 'cyan',
 'gist_earth',
 'gray',
 'gray_r',
 'green',
 'hsv',
 'I Blue',
 'I Bordeaux',
 'I Forest',
 'I Orange',
 'I Purple',
 'inferno',
 'magenta',
 'magma',
 'PiYG',
 'plasma',
 'red',
 'turbo',
 'twilight',
 'twilight_shifted',
 'viridis',
 'yellow']

Pass any of these strings to set the image colormap as shown below:

viewer = napari.view_image(data.moon(), colormap='red')

You can also access the current colormap through the layer.colormap property which returns a tuple of the colormap name followed by the vispy colormap object. You can list all the available colormaps using layer.colormaps.

It is also possible to create your own colormaps using vispy’s vispy.color.Colormap object. See its full documentation. Briefly, you can pass Colormap a list of length 3 or 4, corresponding to the rgb or rgba values at different points along the colormap.

For example, to make a diverging colormap that goes from red to blue through black, and color a random array, you can use this example code:

import napari
from skimage.data import cell
from vispy.color import Colormap

cmap = Colormap([[1, 0, 0], [0, 0, 0], [0, 0, 1]])
image = cell()

viewer = napari.view_image(image, colormap=('diverging', cmap))
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="napari viewer with colormap example using the cell example from skimage")
napari viewer with colormap example using the cell example from skimage

Note in this example the colormap keyword argument was passed as a tuple containing both a name for the new custom colormap and the colormap itself. If we had passed only the colormap it would have been given a default name.

The named colormap now appears in the dropdown alongside a thumbnail of the full range of the colormap.

Adjusting contrast limits#

Each image layer gets mapped through its colormap according to values called contrast limits. Contrast limits are a 2-tuple where the second value is larger than the first. The smaller contrast limit corresponds to the value of the image data that will get mapped to the color defined by 0 in the colormap. All values of image data smaller than this value will also get mapped to this color. The larger contrast limit corresponds to the value of the image data that will get mapped to the color defined by 1 in the colormap. All values of image data larger than this value will also get mapped to this color.

For example, if you are looking at an image that has values between 0 and 100 with a standard gray colormap, and you set the contrast limits to (20, 75), then all the pixels with values less than 20 will get mapped to black, the color corresponding to 0 in the colormap, and all pixels with values greater than 75 will get mapped to white, the color corresponding to 1 in the colormap. All other pixel values between 20 and 75 will get linearly mapped onto the range of colors between black and white.

In napari you can set the contrast limits when creating an Image layer or on an existing layer using the contrast_limits keyword argument or property, respectively.

viewer = napari.view_image(data.moon(), name='moon')
viewer.layers['moon'].contrast_limits=(100, 175)
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="A viewer where the contrast limits have been adjusted")
A viewer where the contrast limits have been adjusted

Because the contrast limits are defined by two values, the corresponding slider has two handles: one adjusts the smaller value, and one adjusts the larger value.

As of right now, adjusting the contrast limits has no effect for rgb data.

If contrast limits are not passed, napari will compute them. If your data is small, napari will take the minimum and maximum values across your entire image. If your data is exceptionally large, this operation can be very time consuming and so if you pass an image pyramid then napari will use only the top level of that pyramid, or it will use the minimum and maximum values across the top, middle, and bottom slices of your image. In general, if working with big images, it is recommended to explicitly set the contrast limits if you can.

Currently if you pass contrast limits as a keyword argument to a layer, then the full extent of the contrast limits: range slider will be set to those values.

Saving without image compression#

When saving an image layer, lossless zlib compression is applied by default. To save with a different level of compression, consider using imageio.imwrite. Adjusting compression can be accomplished by including the appropriate kwargs as outlined in the following locations for tiff or png files.