Using the shapes
layer#
In this document, you will learn about the napari
shapes
layer, including
how to display and edit shapes like rectangle, ellipses, polygons, paths, and
lines. You will also understand how to add a shapes
layer and edit it from the
GUI and from the console.
For more information about layers, refer to Layers at a glance.
When to use the shapes
layer#
The shapes
layer allows you to display a list of an NxD arrays, where each
array corresponds to one shape, specified by N points in D coordinates. You can
adjust the position, size, face color, edge color, and opacity of all the shapes
independently, both programmatically and from the GUI.
Controlling the shapes
layer using the GUI#
Before we start talking about all the controls on the GUI, here is an overview
of how to handle the shapes
layer.
Selecting, resizing, moving, editing, and deleting shapes#
All shapes are edited in the same way:
Click the select shapes tool.
Draw a box around the shape you want to edit.
Adjust the size or contour of the shape using the square handles that appear on the bounding box of the shape. When resizing a layer, hold down the
shift
key to lock the aspect ratio of the shape. Then you can continue to resize the shape with a fixed aspect ratio. Note: you have to hold theshift
key down and when finished release the mouse button first! Here is a shape being resized:Change the face or edge color by clicking on the thumbnail to the right of
face color:
oredge color:
and choosing or creating a color from the pallette.Change the edge width of a shape or the width of a line or path by clicking the circle next to
edge width:
and dragging it to a new width.Move the shape by dragging it.
Rotate the shape by clicking and dragging on the rotation handle above the shape bounding box.
Select multiple shapes by continuing to
shift
+click additional shapes after the first, or drag a box around the shapes to select.Select all the shapes in the current slice by clicking the
a
key if you are in select mode. Once selected you can delete the shapes by clicking the delete button in the layer controls panel or pressing the delete key on the keyboard.
Copying and pasting shapes#
Copy and paste any selected shapes using the ctrl-c
and ctrl-v
keybindings
respectively. If you have a multidimensional shapes layer you can copy shapes
from one slice to another by pasting them into the new slice. The coordinates of
the shapes in the visible dimensions will be in the same place on the new slice
as in the old slice, but the rest of the coordinates will be updated with the
new slice values.
Adding (inserting), editing, and deleting (removing) individual vertices#
Creating a new shapes
layer#
You can create a brand-new empty shapes
layer by clicking the
New shapes layer
button at the top of the layer list
panel. The shape of the
new layer is defined by the shapes inside it, as new shapes are added the new
shape layer will adjust as needed. The dimension of the new shapes layer will
default to the largest dimension of any layer currently in the viewer, or to 2
if no other layers are present in the viewer.
Controls#
Opacity
Click and hold the oval on the opacity slider bar and adjust it to any value between 0.00 (clear) and 1.00 (completely opaque).
Edge width
Click and drag the circle on the
edge width
slider bar to adjustedge width
from 0 to 40.Blending
blending
has the options ofopaque
,translucent
,translucent no depth
,additive
, andminimum
in the dropdown. Refer to the Blending layers section of Layers at a glance for an explanation of each type of blending.Face and edge colors
To change the shape color properties from the GUI, first select the shapes whose properties you want to change, otherwise you will just be initializing the color for the next shape to add. Select the shape you want to change, click the thumbnail next to
face color:
oredge color:
to select or create a color from the pallette.Display text
Check this box to turn
display text
on or off. Text can be added to the points only programmatically and not through the GUI. Refer to Add points with multicolor text for more information.
Other tools#
2D/3D button or
Toggle ndisplay
buttonAll layers can be rendered in both 2D and 3D. The
Toggle ndisplay
button at the bottom of the left panel toggles between these 2 modes. When in 2D, the button looks like this: , ready to switch to 3D mode. When in 3D, the button looks like this: , ready to switch to 2D mode.You can also switch modes by pressing
ctrl+y
.Note that when entering 3D rendering mode the GUI
Add point
,Delete selected points
, andSelect points
tools are all disabled. Those options are supported only when viewing a layer using 2D rendering.New shapes layer
buttonCreate a brand new empty
shapes
layer by clicking theNew shapes layer
button at the top of thelayers list
panel. The shape of this layer is defined by the shapes inside it, as new shapes are added the layer will adjust as needed.
Controlling the shapes layer programmatically#
A simple example#
You can create a new viewer and add a list of shapes in one go using the
napari.view_shapes()
method, or if you already have an existing viewer,
you can add shapes to it using viewer.add_shapes
. The API of both methods is
the same. In these examples we’ll mainly use add_shapes
to overlay shapes onto
an existing image.
In this example, we will overlay shapes on the image of a photographer:
import napari
import numpy as np
from skimage import data
# create the list of polygons
triangle = np.array([[11, 13], [111, 113], [22, 246]])
person = np.array([[505, 60], [402, 71], [383, 42], [251, 95],
[212, 59], [131, 137], [126, 187], [191, 204],
[171, 248], [211, 260], [273, 243], [264, 225],
[430, 173], [512, 160]])
building = np.array([[310, 382], [229, 381], [209, 401], [221, 411],
[258, 411], [300, 412], [306, 435], [268, 434],
[265, 454], [298, 461], [307, 461], [307, 507],
[349, 510], [352, 369], [330, 366], [330, 366]])
polygons = [triangle, person, building]
# add the image
viewer = napari.view_image(data.camera(), name='photographer')
# add the polygons
shapes_layer = viewer.add_shapes(
polygons,
shape_type='polygon',
edge_width=5,
edge_color='coral',
face_color='royalblue'
)
Show code cell source
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="Shapes overlaid on image")
Arguments of view_shapes
and add_shapes
#
view_shapes()
and add_shapes()
accept the same layer-creation parameters.
help(napari.view_shapes)
Show code cell output
Help on function view_shapes in module napari.view_layers:
view_shapes(data=None, ndim=None, *, affine=None, blending='translucent', cache=True, edge_color='#777777', edge_color_cycle=None, edge_colormap='viridis', edge_contrast_limits=None, edge_width=1, experimental_clipping_planes=None, face_color='white', face_color_cycle=None, face_colormap='viridis', face_contrast_limits=None, feature_defaults=None, features=None, metadata=None, name=None, opacity=0.7, projection_mode='none', properties=None, property_choices=None, rotate=None, scale=None, shape_type='rectangle', shear=None, text=None, translate=None, units=None, visible=True, z_index=0, title='napari', ndisplay=2, order=(), 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 a shapes layer.
Parameters
----------
data : list or array
List of shape data, where each element is an (N, D) array of the
N vertices of a shape in D dimensions. Can be an 3-dimensional
array if each shape has the same number of vertices.
ndim : int
Number of dimensions for shapes. When data is not None, ndim must be D.
An empty shapes layer can be instantiated with arbitrary ndim.
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.
axis_labels : tuple of str, optional
Dimension names of the layer data.
If not provided, axis_labels will be set to (..., 'axis -2', 'axis -1').
blending : 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
{'opaque', 'translucent', and 'additive'}.
cache : bool
Whether slices of out-of-core datasets should be cached upon retrieval.
Currently, this only applies to dask arrays.
edge_color : str, array-like
If string can be any color name recognized by vispy or hex value if
starting with `#`. If array-like must be 1-dimensional array with 3
or 4 elements. If a list is supplied it must be the same length as
the length of `data` and each element will be applied to each shape
otherwise the same value will be used for all shapes.
edge_color_cycle : np.ndarray, list
Cycle of colors (provided as string name, RGB, or RGBA) to map to edge_color if a
categorical attribute is used color the vectors.
edge_colormap : str, napari.utils.Colormap
Colormap to set edge_color if a continuous attribute is used to set face_color.
edge_contrast_limits : None, (float, float)
clims for mapping the property to a color map. These are the min and max value
of the specified property that are mapped to 0 and 1, respectively.
The default value is None. If set the none, the clims will be set to
(property.min(), property.max())
edge_width : float or list
Thickness of lines and edges. If a list is supplied it must be the
same length as the length of `data` and each element will be
applied to each shape otherwise the same value will be used for all
shapes.
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.
face_color : str, array-like
If string can be any color name recognized by vispy or hex value if
starting with `#`. If array-like must be 1-dimensional array with 3
or 4 elements. If a list is supplied it must be the same length as
the length of `data` and each element will be applied to each shape
otherwise the same value will be used for all shapes.
face_color_cycle : np.ndarray, list
Cycle of colors (provided as string name, RGB, or RGBA) to map to face_color if a
categorical attribute is used color the vectors.
face_colormap : str, napari.utils.Colormap
Colormap to set face_color if a continuous attribute is used to set face_color.
face_contrast_limits : None, (float, float)
clims for mapping the property to a color map. These are the min and max value
of the specified property that are mapped to 0 and 1, respectively.
The default value is None. If set the none, the clims will be set to
(property.min(), property.max())
feature_defaults : dict[str, Any] or Dataframe-like
The default value of each feature in a table with one row.
features : dict[str, array-like] or Dataframe-like
Features table where each row corresponds to a shape and each column
is a feature.
metadata : dict
Layer metadata.
name : str
Name of the layer.
opacity : float
Opacity of the layer visual, between 0.0 and 1.0.
projection_mode : str
How data outside the viewed dimensions but inside the thick Dims slice will
be projected onto the viewed dimenions.
properties : dict {str: array (N,)}, DataFrame
Properties for each shape. Each property should be an array of length N,
where N is the number of shapes.
property_choices : dict {str: array (N,)}
possible values for each property.
rotate : float, 3-tuple of float, or n-D array.
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
Scale factors for the layer.
shape_type : string or list
String of shape shape_type, must be one of "{'line', 'rectangle',
'ellipse', 'path', 'polygon'}". If a list is supplied it must be
the same length as the length of `data` and each element will be
applied to each shape otherwise the same value will be used for all
shapes.
shear : 1-D array or n-D array
Either a vector of upper triangular values, or an nD shear matrix with
ones along the main diagonal.
text : str, dict
Text to be displayed with the shapes. If text is set to a key in properties,
the value of that property will be displayed. Multiple properties can be
composed using f-string-like syntax (e.g., '{property_1}, {float_property:.2f}).
A dictionary can be provided with keyword arguments to set the text values
and display properties. See TextManager.__init__() for the valid keyword arguments.
For example usage, see /napari/examples/add_shapes_with_text.py.
translate : tuple of float
Translation values for the layer.
units : tuple of str or pint.Unit, optional
Units of the layer data in world coordinates.
If not provided, the default units are assumed to be pixels.
visible : bool
Whether the layer visual is currently being displayed.
z_index : int or list
Specifier of z order priority. Shapes with higher z order are
displayed ontop of others. If a list is supplied it must be the
same length as the length of `data` and each element will be
applied to each shape otherwise the same value will be used for all
shapes.
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.
Shapes data#
The input data to the shapes
layer must be a list of NxD NumPy array, with
each array containing the coordinates of the N vertices in D dimensions that
make up the shape. The ordering of these dimensions is the same as the ordering
of the dimensions for image layers. This list of arrays is always accessible
through the layer.data
property and will grow or shrink as new shapes are
added or deleted. By storing data as a list of arrays it is possible for each
shape to have a different number of vertices in it. This is especially useful
when drawing polygons and paths.
Adding different shape types#
Right now the shapes layer supports 5 types of shapes, Lines
, Rectangles
,
Ellipses
, Polygons
, and Paths
. When adding new data can set the shape type
through the shape_type
keyword argument, as either a single shape type if all
the shapes to be added have the same type or as a list of shape types if some of
the shapes have different types. The actual shape types of all the shapes is
accessible through the layer.shape_types
property.
Lines
consist of two vertices representing the end points of the line. The line creation tool can be selected from the layer control panel or by pressing thel
key when the shapes layer is selected. When adding a new line the first click will coordinates of the first endpoint and the second click will mark the coordinates of the second endpoint. You’ll then be able to add another line.Rectangles
can be added using two vertices representing the corners of the rectangle for axis aligned rectangle, or using four corners so that non-axis aligned rectangle can be represented. Internally we use the four vertex representation so we can always support rotated rectangles.Ellipses
can be added using either two vectors, one representing the center position of the ellipse and the other representing the radii of the ellipse in all dimensions for an axis aligned ellipse, or by using the four corners of the ellipse bounding box for a non-axis aligned ellipse. Internally we use the four vertex representation so we can always support rotated ellipses.Polygons
can be added using an array of N vertices. Polygons are closed by default, so you don’t also need to include the first point at the end of the array. The order of the vertices will determine the triangulation of the polygon, which can be non-convex, but cannot have holes. For drawing polygons, multiple tools can be used.Paths
are like polygons but are not closed or filled in. They can be added using an array of N vertices.
Adding new shapes#
You can add new shapes to an existing shapes
layer programmatically using the
add
method. This allows you to pass in a shape_type
list when there is mixed
shape data (data for different types of shapes).
import napari
import numpy as np
from skimage import data
# add the image
viewer = napari.view_image(data.camera(), name='photographer')
# create a triangle
triangle = np.array([[11, 13], [111, 113], [22, 246]])
# create an ellipse
ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]])
# put both shapes in a list
mixed_shapes = [triangle, ellipse]
# add an empty shapes layer
shapes_layer = viewer.add_shapes()
# add mixed shapes using the `add` method
shapes_layer.add(
mixed_shapes,
shape_type=['polygon', 'ellipse'],
edge_width=5,
edge_color='coral',
face_color='royalblue'
)
Show code cell source
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="Add new shapes to an existing shapes layer")
Finally, each shape type has its own convenience method for adding new shapes to
a layer. Their arguments are identical to those of the add
method, but they do
not take a shape_type
.
import napari
import numpy as np
from skimage import data
# add the image
viewer = napari.view_image(data.camera(), name='photographer')
# create some ellipses
ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]])
ellipse2 = np.array([[165, 329], [165, 401], [234, 401], [234, 329]])
# put both shapes in a list
ellipses = [ellipse, ellipse2]
# add an empty shapes layer
shapes_layer = viewer.add_shapes()
# add ellipses using their convenience method
shapes_layer.add_ellipses(
ellipses,
edge_width=5,
edge_color='coral',
face_color='royalblue'
)
Show code cell source
from napari.utils import nbscreenshot
nbscreenshot(viewer, alt_text="Add new ellipses to an existing shapes layer using the specific method for this layer type")