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 the
contrast, opacity, colormaps and blending mode. You will also understand how
to add and manipulate a variety of different types of images both from the GUI
and from the console.
A simple example¶
You can 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, you can
add an image to it using viewer.add_image
. The api of 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')
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="Cells")
Arguments of view_image
and add_image
¶
view_image()
and add_image()
accept the same layer-creation parameters.
help(napari.view_image)
Help on function view_image in module napari.view_layers:
view_image(data=None, *, channel_axis=None, rgb=None, colormap=None, contrast_limits=None, gamma=1, interpolation2d='nearest', interpolation3d='linear', rendering='mip', depiction='volume', iso_threshold=0.5, attenuation=0.05, name=None, metadata=None, scale=None, translate=None, rotate=None, shear=None, affine=None, opacity=1, blending=None, visible=True, multiscale=None, cache=True, plane=None, experimental_clipping_planes=None, title='napari', ndisplay=2, order=(), axis_labels=(), show=True) -> 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,
all other parameters MAY be provided as lists, and the Nth value
will be applied to the Nth channel in the data. If a single value
is provided, it will be broadcast to all Layers.
rgb : bool or list
Whether the image is rgb RGB or RGBA. If not specified by user and
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.
If a list then must be same length as the axis that is being
expanded as channels.
colormap : str, napari.utils.Colormap, tuple, dict, list
Colormaps to use for luminance images. If a string must be the name
of a supported colormap from vispy or matplotlib. 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. If a list then must be same length as the axis that is
being expanded as channels, and each colormap is applied to each
new image layer.
contrast_limits : list (2,)
Color limits to be used for determining the colormap bounds for
luminance images. If not passed is calculated as the min and max of
the image. If list of lists then must be same length as the axis
that is being expanded and then each colormap is applied to each
image.
gamma : list, float
Gamma correction for determining colormap linearity. Defaults to 1.
If a list then must be same length as the axis that is being
expanded as channels.
interpolation : str or list
Interpolation 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.
rendering : str or list
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.
depiction : str
Selects a preset volume depiction mode in vispy
* volume: images are rendered as 3D volumes.
* plane: images are rendered as 2D planes embedded in 3D.
iso_threshold : float or list
Threshold for isosurface. If a list then must be same length as the
axis that is being expanded as channels.
attenuation : float or list
Attenuation rate for attenuated maximum intensity projection. If a
list then must be same length as the axis that is being expanded as
channels.
name : str or list of str
Name of the layer. If a list then must be same length as the axis
that is being expanded as channels.
metadata : dict or list of dict
Layer metadata. If a list then must be a list of dicts with the
same length as the axis that is being expanded as channels.
scale : tuple of float or list
Scale factors for the layer. If a list then must be a list of
tuples of float with the same length as the axis that is being
expanded as channels.
translate : tuple of float or list
Translation values for the layer. If a list then must be a list of
tuples of float with the same length as the axis that is being
expanded as channels.
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. If a list then must have same length as
the axis that is being expanded as channels.
shear : 1-D array or list.
A vector of shear values for an upper triangular n-D shear matrix.
If a list then must have 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.
opacity : float or list
Opacity of the layer visual, between 0.0 and 1.0. If a list then
must be same length as the axis that is being expanded as channels.
blending : str or list
One of a list of preset blending modes that determines how RGB and
alpha values of the layer visual get mixed. Allowed values are
{'opaque', 'translucent', and 'additive'}. If a list then
must be same length as the axis that is being expanded as channels.
visible : bool or list of bool
Whether the layer visual is currently being displayed.
If a list then must be same length as the axis that is
being expanded as channels.
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.
cache : bool
Whether slices of out-of-core datasets should be cached upon
retrieval. Currently, this only applies to dask arrays.
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'}.
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.
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 just 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 as we’ll handle 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 load or compute on data that you’re not looking at. 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, so that 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, however you don’t have a precomputed multiscale image but try and show a exceptionally large image napari will try and compute the multiscale image for you unless you tell it not too.
You can use the multiscale
keyword argument to specify if your data is a
multiscale image or not. If you don’t provide this value, then 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.
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]],
)
Viewing RGB vs luminance (grayscale) images¶
In this example we explicitly set the rgb
keyword to be True
because we know we are working with an rgb
image:
viewer = napari.view_image(data.astronaut(), rgb=True)
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")
If we had left that keyword argument out napari would have successfully guessed
that we were trying to show an rgb
or rgba
image because the final dimension
was 3 or 4. If you have a luminance image where the last dimension is 3 or 4 you
can set the rgb
property to False
so napari handles the image correctly.
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)
['PiYG',
'blue',
'bop blue',
'bop orange',
'bop purple',
'cyan',
'gist_earth',
'gray',
'gray_r',
'green',
'hsv',
'inferno',
'magenta',
'magma',
'plasma',
'red',
'turbo',
'twilight',
'twilight_shifted',
'viridis',
'yellow']
Passing any of these strings as follows to set the image colormap:
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
here.
Briefly, you can pass Colormap
a list of length 3 or length 4 lists,
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 do the following:
import napari
import numpy as np
from vispy.color import Colormap
cmap = Colormap([[1, 0, 0], [0, 0, 0], [0, 0, 1]])
image = np.random.random((100, 100))
viewer = napari.view_image(image, colormap=('diverging', cmap))
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="napari viewer with colormap example using random data")
Note in this example how we passed the colormap keyword argument as a tuple containing both a name for our new custom colormap and the colormap itself. If we had only passed the colormap it would have been given a default name.
The named colormap now appears in the dropdown menu alongside a little 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. The 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, 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)
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="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 the adjusts the smaller value, one that adjusts the larger value.
As of right now adjusting the contrast limits has no effect for rgb
data.
If no contrast limits are passed, then napari will compute them. If your data is small, then napari will just 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 have passed an image pyramid then napari will just use 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 you explicitly set the contrast limits if you can.
Currently if you pass contrast limits as a keyword argument to a layer then full extent of the contrast limits range slider will be set to those values.