Styling shapes and labels in spatialdata-plot#

color= decides what colour a shape or label gets; a separate set of arguments decides how it is drawn — how opaque the fill is, whether there is an outline, and how thick and what colour that outline is. This tutorial walks through those styling knobs for render_shapes and render_labels. By the end you should be able to:

  • Control fill opacity with fill_alpha.

  • Turn outlines on and style their width, colour, and opacity.

  • Draw hollow shapes (outline only) and translucent label masks over an image.

  • Trace segmentation boundaries with outline and contour_px on labels.

We use the synthetic blobs dataset throughout so the notebook stays small and reproducible.

Setup#

import spatialdata as sd
import spatialdata_plot  # noqa: F401  # registers the .pl accessor

sdata = sd.datasets.blobs()
sdata
SpatialData object
├── Images
│     ├── 'blobs_image': DataArray[cyx] (3, 512, 512)
│     └── 'blobs_multiscale_image': DataTree[cyx] (3, 512, 512), (3, 256, 256), (3, 128, 128)
├── Labels
│     ├── 'blobs_labels': DataArray[yx] (512, 512)
│     └── 'blobs_multiscale_labels': DataTree[yx] (512, 512), (256, 256), (128, 128)
├── Points
│     └── 'blobs_points': DataFrame with shape: (<Delayed>, 4) (2D points)
├── Shapes
│     ├── 'blobs_circles': GeoDataFrame shape: (5, 2) (2D shapes)
│     ├── 'blobs_multipolygons': GeoDataFrame shape: (2, 1) (2D shapes)
│     └── 'blobs_polygons': GeoDataFrame shape: (5, 1) (2D shapes)
└── Tables
      └── 'table': AnnData (26, 3)
with coordinate systems:
    ▸ 'global', with elements:
        blobs_image (Images), blobs_multiscale_image (Images), blobs_labels (Labels), blobs_multiscale_labels (Labels), blobs_points (Points), blobs_circles (Shapes), blobs_multipolygons (Shapes), blobs_polygons (Shapes)

1. Default shapes#

The element names used below (blobs_polygons, blobs_labels, blobs_image) are the keys shown in the sdata repr above. By default, shapes are drawn as filled patches with no outline. We start from blobs_polygons.

sdata.pl.render_shapes('blobs_polygons').pl.show()
../../_images/2cefdb4004845550ebe038f02ec8263808d7d2e2cd2418a014b96eb6215e7a8c.png

2. Fill opacity — fill_alpha#

fill_alpha sets how opaque the fill is, from 1.0 (solid) down to 0.0 (invisible). Lower it when shapes overlap or sit on top of an image you still want to see.

sdata.pl.render_shapes('blobs_polygons', fill_alpha=0.4).pl.show()
../../_images/a1c7b98851b42285be4f9b40c367cbd0b7965261f8207be077688c2ee1fc0271.png

3. Outlines — the outline toggle#

Pass outline=True to draw a border around each shape. Outlines are off by default (outline=None infers visibility from the outline_* settings); turning the toggle on gives every shape a crisp edge.

sdata.pl.render_shapes('blobs_polygons', outline=True).pl.show()
../../_images/5582e75775605a5f28bf5c332bb3c2ace8eef4e277047e51d797ab910511f25c.png

4. Styling the outline — width, colour, opacity#

outline_width, outline_color, and outline_alpha control the border once outline=True.

sdata.pl.render_shapes(
    'blobs_polygons',
    outline=True,
    outline_width=3.0,
    outline_color='black',
    outline_alpha=1.0,
).pl.show()
../../_images/9f8609028fd883e47b900701977049990e9a017615d50d505348b84d5b9159d1.png

5. Hollow shapes — outline only#

Combine a transparent fill (fill_alpha=0.0) with an outline to get outline-only shapes — useful for marking regions of interest without hiding what is underneath.

sdata.pl.render_shapes(
    'blobs_polygons',
    fill_alpha=0.0,
    outline=True,
    outline_width=2.0,
    outline_color='crimson',
).pl.show()
../../_images/ca7af4d165ce0898873ea8449c95f5bdf71abebc11f5598ec80a6c706833ab0a.png

6. Resizing geometries — scale#

scale multiplies each shape’s size about its centroid: shrink to separate crowded shapes, or grow to emphasise them. Here the polygons are drawn at 60% size with an outline.

sdata.pl.render_shapes('blobs_polygons', scale=0.6, outline=True).pl.show()
../../_images/c9cd7cdb7e70c31d6e0f19a955e9a7b517c06c92938fc5f607ba1f62bcc1174c.png

7. Labels use the same vocabulary#

Label (segmentation-mask) rendering shares the fill/outline arguments. By default, masks are drawn semi-transparent (fill_alpha=0.4), not solid — so anything layered beneath them still shows through.

sdata.pl.render_labels('blobs_labels').pl.show()
../../_images/9bc09723e60ccce9139e2a2507da571a88d39bb4b930d00310c1e5e9f2468c82.png

8. Translucent masks over an image — fill_alpha#

Lowering fill_alpha below its 0.4 default lets more of the underlying image show through — the standard way to overlay a segmentation on the raw data. We layer the labels on top of blobs_image.

(
    sdata.pl.render_images('blobs_image')
    .pl.render_labels('blobs_labels', fill_alpha=0.2)
).pl.show()
../../_images/52bf0ab8bfdc0e9679139e2742dc392c0f3057bf84f0f4b0865b269e8ae28cce.png

9. Segmentation boundaries — outline and contour_px#

For labels, outline=True traces each mask’s boundary. contour_px sets the boundary thickness in pixels, and outline_color/outline_alpha style it. Set fill_alpha=0.0 to show the boundaries alone.

(
    sdata.pl.render_images('blobs_image')
    .pl.render_labels(
        'blobs_labels',
        fill_alpha=0.0,
        outline=True,
        contour_px=3,
        outline_color='white',
    )
).pl.show()
../../_images/70f6555e7c5316d2a7a67874df866db23c578ebfb5aea9ce6e337199fb608036.png

10. Putting it together#

A translucent fill plus a crisp boundary over the image gives a readable segmentation overlay — the combination you will reach for most often.

(
    sdata.pl.render_images('blobs_image')
    .pl.render_labels(
        'blobs_labels',
        fill_alpha=0.3,
        outline=True,
        contour_px=2,
        outline_color='white',
        outline_alpha=1.0,
    )
).pl.show()
../../_images/aeda6acc4c51772e2bb4700289dce967390e12251d15baca47d6e7eb56907da4.png

Summary#

  • fill_alpha sets fill opacity for both shapes and labels.

  • outline=True adds a border for shapes and labels; style it with outline_width, outline_color, and outline_alpha, and for labels set the boundary thickness with contour_px.

  • A transparent fill plus an outline gives hollow shapes or boundary-only segmentation overlays.

  • scale resizes shape geometries about their centroids.

For reproducibility#

# ruff: noqa: F401, F811, I001, E402
# fmt: off
import warnings
import spatialdata_plot

%load_ext watermark
# fmt: on

%watermark -v -m -p spatialdata,spatialdata_plot,matplotlib,numpy,pandas
Python implementation: CPython
Python version       : 3.14.6
IPython version      : 9.14.1

spatialdata     : 0.7.3
spatialdata_plot: 0.4.1
matplotlib      : 3.11.0
numpy           : 2.4.6
pandas          : 2.3.3

Compiler    : Clang 20.1.8 
OS          : Darwin
Release     : 25.2.0
Machine     : arm64
Processor   : arm
CPU cores   : 8
Architecture: 64bit