Skip to content

confusius.plotting

plotting

Plotting module for fUSI data.

Modules:

  • image

    Image visualization utilities for fUSI data.

Classes:

  • VolumePlotter

    Manager for volume slice plots with coordinate-based overlay support.

Functions:

  • draw_napari_labels

    Open a napari viewer to interactively paint integer labels over fUSI data.

  • labels_from_layer

    Convert a napari Labels layer to an integer label map DataArray.

  • plot_carpet

    Plot voxel intensities across time as a raster image.

  • plot_contours

    Plot mask contours as a grid of 2D slice panels.

  • plot_napari

    Display fUSI data using the napari viewer.

  • plot_volume

    Plot 2D slices of a volume using matplotlib.

VolumePlotter

Manager for volume slice plots with coordinate-based overlay support.

This class maintains the state of a figure with multiple axes, each representing a slice through a volume at a specific coordinate. It enables overlaying multiple volumes on the same axes by matching coordinates.

Parameters:

  • slice_mode

    (str, default: 'z' ) –

    The dimension along which slices are taken (e.g., "z").

  • figure

    (Figure, default: None ) –

    The figure containing the axes. If not provided, a new figure will be created on the first call to add_volume.

  • axes

    (ndarray, default: None ) –

    2D array of matplotlib.axes.Axes. If not provided, axes will be created on the first call to add_volume.

  • black_bg

    (bool, default: True ) –

    Whether to set the figure background to black.

  • yincrease

    (bool, default: False ) –

    Whether the y-axis increases upward. When False, y coordinates decrease upward.

  • xincrease

    (bool, default: True ) –

    Whether the x-axis increases to the right.

Methods:

  • add_contours

    Add mask contours to existing axes.

  • add_volume

    Plot or overlay a volume on the axes.

  • close

    Close the figure and release resources.

  • savefig

    Save the figure to a file.

  • show

    Display the figure.

add_contours

add_contours(
    mask: DataArray,
    *,
    colors: dict[int | str, str] | str | None = None,
    linewidths: float = 1.5,
    linestyles: str = "solid",
    match_coordinates: bool = True,
    slice_coords: list[float] | None = None,
    **kwargs,
) -> VolumePlotter

Add mask contours to existing axes.

Parameters:

  • mask
    (DataArray) –

    Integer label map in one of two formats:

    • Flat label map: Spatial dims only, e.g. (z, y, x). Background voxels labeled 0; each unique non-zero integer identifies a distinct, non-overlapping region. The region coordinate of the output holds the integer label values.
    • Stacked mask format: Has a leading mask dimension followed by spatial dims, e.g. (mask, z, y, x). Each layer has values in {0, region_id} and regions may overlap. The region coordinate of the output holds the mask coordinate values (e.g., region label).
  • colors
    (dict[int | str, str] or str, default: None ) –

    Color specification for contour lines.

    • dict: maps each label (integer index) or region acronym (string) to a color string.
    • str: applies one color to all regions.
    • None: colors are derived from attrs["cmap"] and attrs["norm"] when present, otherwise from the tab10/tab20 colormap.
  • linewidths
    (float, default: 1.5 ) –

    Width of contour lines in points.

  • linestyles
    (str, default: "solid" ) –

    Line style for contour lines (e.g. "solid", "dashed").

  • match_coordinates
    (bool, default: True ) –

    If True, overlay contours on axes whose slice coordinate matches the mask. If False, plot sequentially on all axes.

  • slice_coords
    (list[float], default: None ) –

    Coordinate values along the plotter's slice_mode at which to draw contours. Slices are selected by nearest-neighbour lookup. If not provided, all coordinate values along slice_mode are used.

  • **kwargs

    Additional keyword arguments passed to matplotlib.axes.Axes.plot.

Returns:

Raises:

  • ValueError

    If the plotter's slice_mode is not a dimension of mask.

  • ValueError

    If mask is not 3D or 4D with a leading mask dimension.

add_volume

add_volume(
    data: DataArray,
    *,
    slice_coords: Sequence[float] | None = None,
    match_coordinates: bool = True,
    cmap: str | Colormap | None = None,
    norm: Normalize | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    threshold: float | None = None,
    threshold_mode: Literal["lower", "upper"] = "lower",
    alpha: float = 1.0,
    show_colorbar: bool = True,
    cbar_label: str | None = None,
    show_titles: bool = True,
    show_axis_labels: bool = True,
    show_axis_ticks: bool = True,
    show_axes: bool = True,
    nrows: int | None = None,
    ncols: int | None = None,
    dpi: int | None = None,
) -> VolumePlotter

Plot or overlay a volume on the axes.

Parameters:

  • data
    (DataArray) –

    3D volume data. Unitary dimensions (except slice_mode) are squeezed before processing.

  • slice_coords
    (list[float], default: None ) –

    Specific coordinates to plot. If None, uses all coordinates from data.

  • match_coordinates
    (bool, default: True ) –

    If True, match slice coordinates to the stored coordinate mapping (for overlays). If False, plot sequentially on all axes (requires exact axis count match).

  • cmap
    (str or Colormap, default: None ) –

    Colormap. When not provided, falls back to data.attrs["cmap"] if present, otherwise "gray".

  • norm
    (Normalize, default: None ) –

    Normalization instance (e.g. BoundaryNorm for integer label maps). When not provided, falls back to data.attrs["norm"] if present. When a norm is active, vmin and vmax are ignored.

  • vmin
    (float, default: None ) –

    Lower bound of the colormap. Defaults to the 2nd percentile. Ignored when norm is provided explicitly (that is, not just inherited from data attributes).

  • vmax
    (float, default: None ) –

    Upper bound of the colormap. Defaults to the 98th percentile. Ignored when norm is provided explicitly (that is, not just inherited from data attributes).

  • threshold
    (float, default: None ) –

    Threshold value for masking.

  • threshold_mode
    ((lower, upper), default: "lower" ) –

    Whether to mask values below or above threshold.

  • alpha
    (float, default: 1.0 ) –

    Opacity of the image.

  • show_colorbar
    (bool, default: True ) –

    Whether to add a colorbar.

  • cbar_label
    (str, default: None ) –

    Label for the colorbar.

  • show_titles
    (bool, default: True ) –

    Whether to display subplot titles.

  • show_axis_labels
    (bool, default: True ) –

    Whether to display axis labels.

  • show_axis_ticks
    (bool, default: True ) –

    Whether to display axis tick labels.

  • show_axes
    (bool, default: True ) –

    Whether to show all axis decorations (spines, ticks, labels). When False, overrides show_axis_labels and show_axis_ticks.

  • nrows
    (int, default: None ) –

    Number of rows in the subplot grid when creating a new figure. If not provided, computed automatically.

  • ncols
    (int, default: None ) –

    Number of columns in the subplot grid when creating a new figure. If not provided, computed automatically.

  • dpi
    (int, default: None ) –

    Figure resolution in dots per inch. Ignored when using an existing figure.

Returns:

Raises:

  • ValueError

    If no matching coordinates are found or axis count doesn't match.

close

close() -> None

Close the figure and release resources.

savefig

savefig(fname: str, **kwargs) -> None

Save the figure to a file.

Parameters:

Raises:

  • RuntimeError

    If called before any data has been plotted.

show

show() -> None

Display the figure.

Raises:

  • RuntimeError

    If called before any data has been plotted.

draw_napari_labels

draw_napari_labels(
    data: DataArray,
    labels_layer_name: str = "labels",
    viewer: Viewer | None = None,
    **kwargs,
) -> tuple[Viewer, Labels]

Open a napari viewer to interactively paint integer labels over fUSI data.

Displays the data as an image layer and adds an empty Labels layer on top. The user can paint integer labels directly on the image using napari's brush tool. After painting, call labels_from_layer with the returned Labels layer and the original data to obtain an integer label map as a DataArray with the same spatial coordinates.

Parameters:

  • data

    (DataArray) –

    Input data array to display as the background image. Typically a time-averaged power Doppler frame, e.g. data.mean("time").

  • labels_layer_name

    (str, default: "labels" ) –

    Name assigned to the Labels layer added to the viewer.

  • viewer

    (Viewer, default: None ) –

    Existing napari viewer to add layers to. If not provided, a new viewer is created via plot_napari.

  • **kwargs

    Additional keyword arguments forwarded to plot_napari for the image layer (e.g. colormap, contrast_limits).

Returns:

  • viewer ( Viewer ) –

    The napari viewer instance with the image and Labels layers.

  • labels_layer ( Labels ) –

    The empty Labels layer initialised to zeros. After the user paints labels in the viewer, pass this layer to labels_from_layer to obtain an integer label map.

Notes

The Labels layer is initialised with the same scale and translate parameters as the image layer so that the napari canvas shows a consistent physical coordinate frame regardless of voxel spacing or data origin.

Examples:

>>> import xarray as xr
>>> import confusius  # Register accessor.
>>> pwd = xr.open_zarr("output.zarr")["power_doppler"].compute()
>>> # Display the time-averaged image and add an interactive Labels layer.
>>> viewer, labels_layer = draw_napari_labels(pwd.mean("time"))
>>> # … paint labels in the viewer …
>>> # Convert painted labels to an integer label map DataArray.
>>> label_map = labels_from_layer(labels_layer, pwd.mean("time"))

labels_from_layer

labels_from_layer(
    labels_layer: Labels, data: DataArray
) -> DataArray

Convert a napari Labels layer to an integer label map DataArray.

Reads the integer array painted in labels_layer and wraps it in a DataArray whose spatial dimensions and coordinates match those of data. The result is compatible with extract_with_labels, plot_contours, and VolumePlotter.add_contours.

Parameters:

  • labels_layer

    (Labels) –

    A Labels layer populated by the user (e.g. via draw_napari_labels). Integer values identify distinct regions; zero is the background and is excluded from downstream analyses.

  • data

    (DataArray) –

    Reference data array. Its spatial dimensions and coordinates define the shape and labelling of the output. A time dimension, if present, is ignored: the label map is purely spatial.

Returns:

  • DataArray

    Stacked integer DataArray with dims ["mask", *spatial_dims], where the mask coordinate holds each unique non-zero label integer. Each layer mask=k has values k where the user painted label k and 0 elsewhere. This format is directly compatible with extract_with_labels, plot_contours, and VolumePlotter.add_contours, and can be sliced by label (e.g. label_map.sel(mask=2)) for per-label display. The attrs dict carries:

    • "long_name" — human-readable name.
    • "labels_layer_name" — name of the source napari layer.
    • "rgb_lookup"dict[int, list[int]] mapping each non-zero label to its [r, g, b] color (0–255) as painted in napari.
Notes

The label array is taken directly from labels_layer.data. No rasterisation is performed: this is a direct read of the painted values.

Per-label colors are read from labels_layer.get_color(label), which works for both the default cyclic colormap and any DirectLabelColormap set on the layer.

Examples:

>>> import xarray as xr
>>> import confusius  # Register accessor.
>>> pwd = xr.open_zarr("output.zarr")["power_doppler"].compute()
>>> viewer, labels_layer = draw_napari_labels(pwd.mean("time"))
>>> # … paint labels in the viewer …
>>> label_map = labels_from_layer(labels_layer, pwd.mean("time"))
>>> label_map.dims
('mask', 'z', 'y', 'x')
>>> # Slice a single label for display alongside a seed map.
>>> label_map.sel(mask=2)
>>> # Use the label map for region-based analysis.
>>> from confusius.extract import extract_with_labels
>>> signals = extract_with_labels(pwd, label_map)

plot_carpet

plot_carpet(
    data: DataArray,
    mask: DataArray | None = None,
    detrend_order: int | None = None,
    standardize: bool = True,
    cmap: str | Colormap = "gray",
    vmin: float | None = None,
    vmax: float | None = None,
    decimation_threshold: int | None = 800,
    figsize: tuple[float, float] = (10, 5),
    title: str | None = None,
    black_bg: bool = False,
    ax: Axes | None = None,
) -> tuple[Figure | SubFigure, Axes]

Plot voxel intensities across time as a raster image.

A carpet plot (also known as "grayplot" or "Power plot") displays voxel intensities as a 2D raster image with time on the x-axis and voxels on the y-axis. Each row represents one voxel's time series, typically standardized to z-scores.

Parameters:

  • data

    (DataArray) –

    Input data array with a 'time' dimension.

  • mask

    (DataArray, default: None ) –

    Boolean mask with same spatial dimensions and coordinates as data. True values indicate voxels to include. If not provided, all non-zero voxels from the data are included.

  • detrend_order

    (int, default: None ) –

    Polynomial order for detrending:

    • 0: Remove mean (constant detrending).
    • 1: Remove linear trend using least squares regression.
    • 2+: Remove polynomial trend of specified order.

    If not provided, no detrending is applied.

  • standardize

    (bool, default: True ) –

    Whether to standardize each voxel's time series to z-scores.

  • cmap

    (str, default: "gray" ) –

    Matplotlib colormap name.

  • vmin

    (float, default: None ) –

    Minimum value for colormap. If not provided, uses mean - 2*std.

  • vmax

    (float, default: None ) –

    Maximum value for colormap. If not provided, uses mean + 2*std.

  • decimation_threshold

    (int or None, default: 800 ) –

    If the number of timepoints exceeds this value, data is downsampled along the time axis to improve plotting performance. Set to None to disable downsampling.

  • figsize

    (tuple[float, float], default: (10, 5) ) –

    Figure size in inches (width, height).

  • title

    (str, default: None ) –

    Plot title.

  • black_bg

    (bool, default: False ) –

    Whether to use a black figure background with white foreground elements (spines, ticks, labels). Use True for dark-themed figures.

  • ax

    (Axes, default: None ) –

    Axes to plot on. If not provided, creates new figure and axes.

Returns:

  • figure ( Figure or SubFigure ) –

    Figure object containing the carpet plot.

  • axes ( Axes ) –

    Axes object with the carpet plot.

Notes

Complex-valued data is converted to magnitude before processing.

This function was inspired by Nilearn's nilearn.plotting.plot_carpet.

References

  1. Power, Jonathan D. “A Simple but Useful Way to Assess fMRI Scan Qualities.” NeuroImage, vol. 154, July 2017, pp. 150–58. DOI.org (Crossref), https://doi.org/10.1016/j.neuroimage.2016.08.009

Examples:

>>> import xarray as xr
>>> from confusius.plotting import plot_carpet
>>> data = xr.open_zarr("output.zarr")["iq"]
>>> fig, ax = plot_carpet(data)
>>> # With linear detrending
>>> fig, ax = plot_carpet(data, detrend_order=1)
>>> # With mask
>>> import numpy as np
>>> mask = xr.DataArray(
...     np.abs(data.isel(time=0)) > threshold,
...     dims=["z", "y", "x"],
... )
>>> fig, ax = plot_carpet(data, mask=mask)

plot_contours

plot_contours(
    mask: DataArray,
    *,
    colors: dict[int | str, str] | str | None = None,
    linewidths: float = 1.5,
    linestyles: str = "solid",
    slice_mode: str = "z",
    slice_coords: list[float] | None = None,
    yincrease: bool = False,
    xincrease: bool = True,
    black_bg: bool = True,
    figure: Figure | None = None,
    axes: NDArray[Any] | None = None,
    **kwargs,
) -> VolumePlotter

Plot mask contours as a grid of 2D slice panels.

Displays contour lines for each labeled region in mask across a grid of subplots. Each panel shows the contours for one slice along slice_mode, drawn in physical coordinates when available.

Parameters:

  • mask

    (DataArray) –

    Integer label map in one of two formats:

    • Flat label map: Spatial dims only, e.g. (z, y, x). Background voxels labeled 0; each unique non-zero integer identifies a distinct, non-overlapping region. The regions coordinate of the output holds the integer label values.
    • Stacked mask format: Has a leading masks dimension followed by spatial dims, e.g. (masks, z, y, x). Each layer has values in {0, region_id} and regions may overlap. The regions coordinate of the output holds the masks coordinate values (e.g., region label).
  • colors

    (dict[int | str, str] or str, default: None ) –

    Color specification for contour lines. A dict maps each label (integer index or region acronym string) to a color; a str applies one color to all regions. If not provided, colors are derived from attrs["cmap"] and attrs["norm"] when present, otherwise from the tab10/tab20 colormap.

  • linewidths

    (float, default: 1.5 ) –

    Width of contour lines in points.

  • linestyles

    (str, default: "solid" ) –

    Line style for contour lines (e.g. "solid", "dashed").

  • slice_mode

    (str, default: "z" ) –

    Dimension along which to slice (e.g. "x", "y", "z"). After slicing, each panel must be 2D.

  • slice_coords

    (list[float], default: None ) –

    Coordinate values along slice_mode at which to extract slices. Slices are selected by nearest-neighbour lookup. If not provided, all coordinate values along slice_mode are used.

  • yincrease

    (bool, default: False ) –

    Whether the y-axis increases upward (True) or downward (False).

  • xincrease

    (bool, default: True ) –

    Whether the x-axis increases to the right (True) or left (False).

  • black_bg

    (bool, default: True ) –

    Whether to set the figure background to black.

  • figure

    (Figure, default: None ) –

    Existing figure to draw into. If not provided, a new figure is created.

  • axes

    (ndarray, default: None ) –

    Existing 2D array of matplotlib.axes.Axes to draw into. If not provided, new axes are created inside figure.

  • **kwargs

    Additional keyword arguments passed to matplotlib.axes.Axes.plot.

Returns:

  • VolumePlotter

    Object managing the figure, axes, and coordinate mapping for overlays.

Raises:

Notes

Contours are computed with skimage.measure.find_contours on a binary mask for each label, then mapped to physical coordinates via linear interpolation between coordinate centers. Each panel has aspect="equal" so that 1 unit in x matches 1 unit in y.

The returned VolumePlotter stores the coordinate-to-axis mapping, so you can overlay a volume afterwards with VolumePlotter.add_volume.

Examples:

>>> import xarray as xr
>>> from confusius.plotting import plot_contours
>>> mask = xr.open_zarr("output.zarr")["roi_mask"]
>>> plotter = plot_contours(mask, slice_mode="z")
>>> # Custom colors per label.
>>> plotter = plot_contours(mask, slice_mode="z", colors={1: "red", 2: "cyan"})
>>> # Overlay contours on an existing volume plot.
>>> from confusius.plotting import plot_volume
>>> volume = xr.open_zarr("output.zarr")["power_doppler"]
>>> plotter = plot_volume(volume, slice_mode="z")
>>> plotter.add_contours(mask, colors="yellow")

plot_napari

plot_napari(
    data: DataArray,
    show_colorbar: bool = True,
    show_scale_bar: bool = True,
    dim_order: tuple[str, ...] | None = None,
    viewer: Viewer | None = None,
    layer_type: Literal["image", "labels"] = "image",
    **layer_kwargs,
) -> tuple[Viewer, Image | Labels]

Display fUSI data using the napari viewer.

Parameters:

  • data

    (DataArray) –

    Input data array to visualize. Expected dimensions are (time, z, y, x) where z is the elevation/stacking axis, y is depth, and x is lateral. Use dim_order to specify a different dimension ordering. Can be image data or label/mask data (e.g., ROIs, segmentations).

  • show_colorbar

    (bool, default: True ) –

    Whether to show the colorbar. Only applies to image layers.

  • show_scale_bar

    (bool, default: True ) –

    Whether to show the scale bar.

  • dim_order

    (tuple[str, ...], default: None ) –

    Dimension ordering for the spatial axes (last three dimensions). If not provided, the ordering of the last three dimensions in data is used.

  • viewer

    (Viewer, default: None ) –

    Existing napari viewer to add the layer to. If not provided, a new viewer is created.

  • layer_type

    ((image, labels), default: "image" ) –

    Type of layer to create. Use "image" for fUSI data and "labels" for ROI masks, segmentations, or other label data.

  • **layer_kwargs

    Additional keyword arguments passed to the layer creation method (napari.imshow for images or viewer.add_labels for labels). For image layers, if data.attrs contains "cmap" and "colormap" is not in layer_kwargs, the attribute is used as the colormap. For labels layers, if data.attrs contains "cmap" and "norm" (as set by atlas functions) and "colormap" is not in layer_kwargs, a per-label color dict is built automatically from those attributes.

Returns:

  • viewer ( Viewer ) –

    The napari viewer instance with the layer added.

  • layer ( Image or Labels ) –

    The layer added to the viewer.

Notes

If all spatial dimensions have coordinates, their spacing is used as the scale parameter for napari to ensure correct physical scaling. If any spatial dimension is missing coordinates, no scaling is applied. The spacing is computed as the median difference between consecutive coordinate values.

When spatial coordinates carry a units attribute (e.g. "m"), the unit list is forwarded to napari as the units layer parameter, which populates the status bar with physical coordinates. The scale bar is also updated to reflect the first found unit; it falls back to "mm" when no units are present on the coordinates.

For unitary dimensions (e.g., a single-slice elevation axis in 2D+t data), the spacing cannot be inferred from coordinates. In that case, the function looks for a voxdim attribute on the coordinate variable (data.coords[dim].attrs["voxdim"]) and uses it as the spacing. If no such attribute is found, unit spacing is assumed and a warning is emitted.

The first coordinate value of each spatial dimension is used as the translate parameter so that the image is positioned at its correct physical origin. For dimensions without coordinates, a translate of 0.0 is used. This ensures that multiple datasets with different fields of view overlay correctly when added to the same viewer.

Examples:

>>> import xarray as xr
>>> from confusius.plotting import plot_napari
>>> data = xr.open_zarr("output.zarr")["iq"]
>>> viewer, layer = plot_napari(data)
>>> # Custom contrast limits
>>> viewer, layer = plot_napari(data, contrast_limits=(0, 100))
>>> # Different dimension ordering (e.g., depth, elevation, lateral)
>>> viewer, layer = plot_napari(data, dim_order=("y", "z", "x"))
>>> # Add a second dataset as a new layer in an existing viewer
>>> viewer, layer = plot_napari(data1)
>>> viewer, layer = plot_napari(data2, viewer=viewer)
>>> # Display ROI labels (e.g., segmentation mask)
>>> roi_mask = xr.open_zarr("output.zarr")["roi_mask"]
>>> viewer, layer = plot_napari(roi_mask, layer_type="labels")
>>> # Overlay labels on existing image
>>> viewer, layer = plot_napari(data)
>>> viewer, layer = plot_napari(roi_mask, viewer=viewer, layer_type="labels")

plot_volume

plot_volume(
    data: DataArray,
    *,
    slice_coords: list[float] | None = None,
    slice_mode: str = "z",
    cmap: str | Colormap | None = None,
    norm: Normalize | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    threshold: float | None = None,
    threshold_mode: Literal["lower", "upper"] = "lower",
    alpha: float = 1.0,
    show_colorbar: bool = True,
    cbar_label: str | None = None,
    show_titles: bool = True,
    show_axis_labels: bool = True,
    show_axis_ticks: bool = True,
    show_axes: bool = True,
    yincrease: bool = False,
    xincrease: bool = True,
    black_bg: bool = True,
    figure: Figure | None = None,
    axes: NDArray[Any] | None = None,
    nrows: int | None = None,
    ncols: int | None = None,
    dpi: int | None = None,
) -> VolumePlotter

Plot 2D slices of a volume using matplotlib.

Displays a series of 2D slices extracted along slice_mode as a grid of subplots. Each slice is rendered using physical coordinates for axis ticks when available.

Parameters:

  • data

    (DataArray) –

    Input data array. Unitary dimensions are squeezed before processing. After squeezing, data must be 3D. Complex-valued data is converted to magnitude before display.

  • slice_coords

    (list[float], default: None ) –

    Coordinate values along slice_mode at which to extract slices. Slices are selected by nearest-neighbour lookup. If not provided, all coordinate values along slice_mode are used.

  • slice_mode

    (str, default: "z" ) –

    Dimension along which to slice (e.g., "x", "y", "z", "time"). After slicing, each panel must be 2D.

  • cmap

    (str or Colormap, default: None ) –

    Colormap. When not provided, falls back to data.attrs["cmap"] if present, otherwise "gray".

  • norm

    (Normalize, default: None ) –

    Normalization instance (e.g. BoundaryNorm for integer label maps such as atlas annotations). When not provided, falls back to data.attrs["norm"] if present. When a norm is active, vmin and vmax are ignored.

  • vmin

    (float, default: None ) –

    Lower bound of the colormap. Defaults to the 2nd percentile. Ignored when a norm is active.

  • vmax

    (float, default: None ) –

    Upper bound of the colormap. Defaults to the 98th percentile. Ignored when a norm is active.

  • threshold

    (float, default: None ) –

    Threshold applied to |data|. See threshold_mode for the masking direction. If not provided, no thresholding is applied.

  • threshold_mode

    ((lower, upper), default: "lower" ) –

    Controls how threshold is applied:

    • "lower": set pixels where |data| < threshold to NaN.
    • "upper": set pixels where |data| > threshold to NaN.
  • alpha

    (float, default: 1.0 ) –

    Opacity of the image.

  • show_colorbar

    (bool, default: True ) –

    Whether to add a shared colorbar to the figure.

  • cbar_label

    (str, default: None ) –

    Label for the colorbar.

  • show_titles

    (bool, default: True ) –

    Whether to display subplot titles showing the slice coordinate.

  • show_axis_labels

    (bool, default: True ) –

    Whether to display axis labels (with units when available).

  • show_axis_ticks

    (bool, default: True ) –

    Whether to display axis tick labels.

  • show_axes

    (bool, default: True ) –

    Whether to show all axis decorations (spines, ticks, labels). When False, overrides show_axis_labels and show_axis_ticks.

  • yincrease

    (bool, default: False ) –

    Whether the y-axis increases upward (True) or downward (False).

  • xincrease

    (bool, default: True ) –

    Whether the x-axis increases to the right (True) or left (False).

  • black_bg

    (bool, default: True ) –

    Whether to set the figure background to black.

  • figure

    (Figure, default: None ) –

    Existing figure to draw into. If not provided, a new figure is created.

  • axes

    (ndarray, default: None ) –

    Existing 2D array of matplotlib.axes.Axes to draw into. Must contain at least as many elements as there are slices. If not provided, new axes are created inside figure.

  • nrows

    (int, default: None ) –

    Number of rows in the subplot grid. If not provided, computed automatically.

  • ncols

    (int, default: None ) –

    Number of columns in the subplot grid. If not provided, computed automatically.

  • dpi

    (int, default: None ) –

    Figure resolution in dots per inch. Ignored when figure is provided.

Returns:

  • VolumePlotter

    Object managing the figure, axes, and coordinate mapping for overlays.

Raises:

  • ValueError

    If slice_mode is not a dimension of data.

  • ValueError

    If data is not 3D after squeezing unitary dimensions.

  • ValueError

    If axes is provided but does not contain enough elements for all slices.

Notes

Rendering is done with pcolormesh, which accepts coordinate arrays directly and therefore handles non-uniform coordinate spacing correctly. Because each panel is drawn in physical coordinate space, multiple calls with different axes elements will overlay correctly as long as the displayed dimensions are the same.

The two dimensions that remain after slicing define the panel axes: the first remaining dimension maps to the vertical axis and the second to the horizontal axis. Coordinates are used directly as axis tick values; each axis has aspect="equal" so that 1 unit in x matches 1 unit in y.

NaN and Inf values (including those introduced by threshold) are rendered transparently via a masked array.

When the figure is created internally, layout="constrained" is used so that subplot titles, axis labels, tick labels, and the colorbar are spaced automatically without overlapping. When an external figure or axes is provided, layout management is left to the caller.

Examples:

>>> import xarray as xr
>>> from confusius.plotting import plot_volume
>>> data = xr.open_zarr("output.zarr")["power_doppler"]
>>> plotter = plot_volume(data, slice_mode="z")
>>> # Select specific z slices.
>>> plotter = plot_volume(data, slice_coords=[0.0, 1.5, 3.0], slice_mode="z")
>>> # Threshold noise and label the colorbar.
>>> plotter = plot_volume(
...     data,
...     slice_mode="z",
...     threshold=0.5,
...     threshold_mode="lower",
...     cbar_label="Power (dB)",
... )