Using the surface layer#

In this document, you will learn about the napari surface layer, including how to display surface data and edit the properties of surfaces like the contrast, opacity, colormaps and blending mode. You will also understand how to add and manipulate surfaces mostly from the console. There are a few slider controls that are available in the GUI.

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

Note

Surface layers can be created only programmatically, i.e. in the console, or using a script, not from the GUI. Please refer to A simple example and use the code there to add a surface layer first, then explore the GUI controls.

When to use the surface layer#

The surface layer allows you to display a precomputed surface mesh that is defined by an NxD array of N vertices in D coordinates, an Mx3 integer array of the indices of the triangles making up the faces of the surface, and a length N list of values to associate with each vertex to use alongside a colormap.

A simple example#

You can create a new viewer and add a surface in one go using the napari.view_surface() method, or if you already have an existing viewer, you can add an image to it using viewer.add_surface. The API of both methods is the same. In these examples we’ll mainly use view_surface.

A simple example of viewing a surface follows. You can copy and paste these statements into the napari console to see how they work:

import napari
import numpy as np

vertices = np.array([[0, 0], [0, 20], [10, 0], [10, 10]])
faces = np.array([[0, 1, 2], [1, 2, 3]])
values = np.linspace(0, 1, len(vertices))
surface = (vertices, faces, values)

viewer = napari.view_surface(surface)  # add the surface
MESA: error: ZINK: vkCreateInstance failed (VK_ERROR_INCOMPATIBLE_DRIVER)
glx: failed to create drisw screen
Hide code cell source
from napari.utils import nbscreenshot

nbscreenshot(viewer, alt_text="A viewer with a surface")
A viewer with a surface

GUI controls for the surface layer#

Once you have created a surface layer programmatically, the following GUI controls are available in the viewer:

  • Buttons

    • Pan/zoom - image: Pan/zoom tool is the default mode of the layer and supports panning and zooming. Press the 1 key when the layer is selected to use this mode.

    • Transform - image: Transform enables you to rotate, scale, or translate the layer. Note: at present this feature is limited to 2D viewer display mode. To reset the transformation, you can Option/Alt-click the transform button (a confirmation dialog will open to confirm the reset). Press the 2 key when the layer is selected to use this mode.

  • Controls

    • Opacity - use this slider control to assign opacity from 0 to 1.00 where 0 is transparent and 1.00 is completely opaque.

    • Contrast Limits - click and slide the dots on either end of the slider bar to adjust upper and lower contrast limits.

    • Auto-contrast - choose once or continuous.

    • Gamma - Click on the oval on the gamma slider bar and adjust it to any value between 0.20 and 2.00. Gamma correction or gamma is a nonlinear operation used to encode and decode luminance or tristimulus values in video or still image systems.

    • Colormap - select a value from the dropdown list.

    • Blending - Choose opaque, translucent, translucent no depth, or additive from the dropdown. Refer to the Blending layers section of Layers at a glance for an explanation of each type of blending.

    • Shading - Choose none, flat, or smooth from the dropdown.

Arguments of view_surface and add_surface#

view_surface() and add_surface() accept the same layer-creation parameters.

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

view_surface(data, *, affine=None, blending='translucent', cache=True, colormap='gray', contrast_limits=None, experimental_clipping_planes=None, feature_defaults=None, features=None, gamma=1.0, metadata=None, name=None, normals=None, opacity=1.0, projection_mode='none', rotate=None, scale=None, shading='flat', shear=None, texcoords=None, texture=None, translate=None, units=None, vertex_colors=None, visible=True, wireframe=None, 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 surface layer.
    
    Parameters
    ----------
    data : 2-tuple or 3-tuple of array
        The first element of the tuple is an (N, D) array of vertices of
        mesh triangles.
    
        The second is an (M, 3) array of int of indices of the mesh triangles.
    
        The optional third element is the (K0, ..., KL, N) array of values
        (vertex_values) used to color vertices where the additional L
        dimensions are used to color the same mesh with different values. If
        not provided, it defaults to ones.
    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.
    colormap : str, napari.utils.Colormap, tuple, dict
        Colormap 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.
    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.
    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.
    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.
    gamma : float
        Gamma correction for determining colormap linearity. Defaults to 1.
    metadata : dict
        Layer metadata.
    name : str
        Name of the layer.
    normals : None, dict or SurfaceNormals
        Whether and how to display the face and vertex normals of the surface mesh.
    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.
    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.
    shading : str, Shading
        One of a list of preset shading modes that determine the lighting model
        using when rendering the surface in 3D.
    
        * ``Shading.NONE``
          Corresponds to ``shading='none'``.
        * ``Shading.FLAT``
          Corresponds to ``shading='flat'``.
        * ``Shading.SMOOTH``
          Corresponds to ``shading='smooth'``.
    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.
    texcoords: (N, 2) array
        2D coordinates for each vertex, mapping into the texture.
        The number of texture coords must match the number of vertices (N).
        Coordinates should be in [0.0, 1.0] and are scaled to sample the 2D
        texture. Coordinates outside this range will wrap, but this behavior
        should be considered an implementation detail: there are no plans to
        change it, but it's a feature of the underlying vispy visual.
    texture: (I, J) or (I, J, C) array
        A 2D texture to be mapped onto the mesh using `texcoords`.
        C may be 3 (RGB) or 4 (RGBA) channels for a color texture.
    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.
    vertex_colors: (N, C) or (K0, ..., KL, N, C) array of color values
        Take care that the (optional) L additional dimensions match those of
        vertex_values for proper slicing.
        C may be 3 (RGB) or 4 (RGBA) channels..
    visible : bool
        Whether the layer visual is currently being displayed.
    wireframe : None, dict or SurfaceWireframe
        Whether and how to display the edges of the surface mesh with a wireframe.
        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.

Surface data#

The data for a surface layer is defined by a 3-tuple of its vertices, faces, and vertex values. The vertices are an NxD array of N vertices in D coordinates. The faces are an Mx3 integer array of the indices of the triangles making up the faces of the surface. The vertex values are a length N list of values to associate with each vertex to use alongside a colormap. This 3-tuple is accessible through the layer.data property.

3D rendering#

All layers can be rendered in both 2D and 3D. One of the viewer buttons at the bottom of the left panel can toggle between these 2 modes. When in 2D, the button looks like this: image: 2D/3D button, ready to switch to 3D mode. When in 3D, the button looks like this: image: 2D/3D button, ready to switch to 2D mode.

The number of dimensions sliders will be 2 or 3 less than the total number of dimensions of the layer, allowing you to browse volumetric timeseries data and other high dimensional data. An example is these brain surfaces rendered in 3D:

Working with colormaps#

The same colormaps available for the image layer are also available for the surface layer. 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. Please see the list below.

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']

Passing any of these as keyword arguments will set the colormap of that surface. 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 it’s full documentation here. For more detail see the image layer guide.

Adjusting contrast limits#

The vertex values of the surface layer get mapped through its colormap according to values called contrast limits. These are a 2-tuple of values defining how what values get applied the minimum and maximum of the colormap and follow the same principles as the contrast_limits described in the image layer guide. They are also accessible through the same keyword arguments, properties, and GUI layer controls as in the image layer.