SpatialData.plotSpatialData.plot provides a visualization suit for SpatialData objects in ggplot2-style, with support for multi-scale images and labels, points and shapes, and layering of elements into composite plots. For the latter, POINT, POLYGON, and MULTIPOLYGON geometries are supported. For all but images, there is support to pass information from annotation tables as aesthetics (e.g., colData or assay data). For images, auto-contrasting and multi-channel color merging are supported. Each layer returns a standard ggplot object, allowing for customization (e.g., using ggnewscale for layer-specific fill/color scales), or multi-panel arrangement (e.g., using patchwork).
SpatialData.plot 0.99.12
SpatialData.plot can be installed as follows:
if (require("BiocManager", quietly=TRUE))
install.packages("BiocManager")
BiocManager::install("SpatialData.plot")
For the purpose of this vignette, we require the following dependencies:
library(ggplot2)
library(patchwork)
library(ggnewscale)
library(spatialdataR)
library(SpatialData.plot)
The SpatialData.plot package contains a set of plotting functions for
spatial omics data stored as SpatialData
.zarr files that follow OME-NGFF specs.
Each SpatialData object is composed of five layers: images, labels, shapes,
points, and tables. Each layer may contain an arbitrary number of elements.
Images and labels are represented as ZarrArrays (Rarr).
Points and shapes are represented as arrow objects linked
to an on-disk .parquet file. As such, all data are represented out of memory.
Element annotation as well as cross-layer summarizations (e.g., count matrices)
are represented as SingleCellExperiment as tables.
We here demonstrate package functionality using a trivial example dataset.
For more realistic technology-focused examples, we refer readers to the
companion demo website.
In particular, the blobs dataset from spatialdataR (provided by the
scverse/Python) serves to represent all possible types of elements: an
image (RGB), label (masks), different shapes (circles, multi-/polygons),
points (gene transcripts), and a table annotating the label element.
x <- file.path("extdata", "blobs.zarr")
x <- system.file(x, package="spatialdataR")
(x <- readSpatialData(x))
## class: SpatialData
## - images(2): blobs_image blobs_multiscale_image
## - labels(2): blobs_labels blobs_multiscale_labels
## - points(1):
## - blobs_points (200)
## - shapes(3):
## - blobs_circles (5,circle)
## - blobs_multipolygons (2,polygon)
## - blobs_polygons (5,polygon)
## - tables(1):
## - table (3,10) [blobs_labels]
## coordinate systems(5):
## - global(8): blobs_image blobs_multiscale_image ... blobs_polygons
## blobs_points
## - scale(1): blobs_labels
## - translation(1): blobs_labels
## - affine(1): blobs_labels
## - sequence(1): blobs_labels
SpatialData.plot provides 5 user-facing plotting functions:
plotSpatialData() renders a base (blank) ggplot with simple aesthetics
and, importantly, a fixed axial ratio as to not distort spatial coordinates.plotImage/Label/Point/Shape() render specific SpatialData elements;
each requires specification of the element index/name i, and coordinate
system j (by default, the first available element/system will be rendered);
different functions further accept different arguments to control aesthetics.Image/LabelArrays are linked to potentially multiscale .zarr stores.
Their show method includes the scales available for a given element:
image(x, "blobs_image")
## class: SpatialDataImage
## Scales (1): (3,64,64)
image(x, "blobs_multiscale_image")
## class: SpatialDataImage (MultiScale)
## Scales (3): (3,64,64 3,32,32 3,16,16)
Internally, multiscale ImageArrays are stored as a list of ZarrArray, e.g.:
i <- image(x, "blobs_multiscale_image")
vapply(data(i, k=NULL), dim, numeric(3))
## [,1] [,2] [,3]
## [1,] 3 3 3
## [2,] 64 32 16
## [3,] 64 32 16
To retrieve a specific scale’s ZarrArray, we can use data(., k),
where k specifies the target scale. This also works for plotting:
wrap_plots(nrow=1, lapply(seq(3), \(.)
plotSpatialData(x) + plotImage(i=2, k=.)))
Like images, labels are represented as ZarrArray. Array values, however,
are integers that correspond to different instances, typically linked to a
table of annotations (e.g., expression values, observation metadata, etc.).
i <- "blobs_labels"
t <- getTable(x, i)
t$id <- sample(letters, ncol(t))
table(x) <- t
p <- plotSpatialData(x)
pal_d <- hcl.colors(10, "Spectral")
pal_c <- hcl.colors(9, "Inferno")[-9]
a <- p + plotLabel(i, pal="grey") # binary
b <- p + plotLabel(i, c="id", pal=pal_d) # metadata
c <- p + plotLabel(i, c="channel_1_sum", pal=pal_c) # assay
(a | b | c) +
plot_layout(guides="collect") &
theme(legend.position="bottom")
Elements of the points layer are rendered using geom_point(),
and accepts both discrete and continuous color specifications.
i <- "blobs_points"
a <- p + plotPoint(i=i)
b <- p + plotPoint(i=i, col="genes") # discrete
c <- p + plotPoint(i=i, col="instance_id") # continuous
(a | b | c)
For demonstration, we render each shape element present in the object,
which includes all possible types: circles and (multi)polygons.
p <- plotSpatialData(x)
a <- p +
labs(title="polygons") +
plotShape(i="blobs_polygons")
b <- p +
labs(title="multipolygons") +
plotShape(i="blobs_multipolygons")
c <- p +
labs(title="circles") +
plotShape(i="blobs_circles")
(a | b | c)
Several SpatialData elements (images, labels, points, shapes) can be layered
on-top of each other in ggplot-style using the +-operator. The return value
of each such call remains a ggplot object, which accepts additional aesthetics.
Note that specifying layer-specific fill/color requires setting up a new scale
with ggnewscale::new_scale_fill/color(); an example is as follows:
p <- plotSpatialData(x)
# joint
all <- p +
plotImage() +
plotLabel(a=1/3) +
plotShape(i=1) +
plotShape(i=3) +
new_scale_color() +
plotPoint(col="genes") +
labs(title="layered")
# split
one <- list(
p + plotImage() + labs(title="image"),
p + plotLabel() + labs(title="labels"),
p + plotShape(i=1) + labs(title="circles"),
p + plotShape(i=3) + labs(title="polygons"),
p + plotPoint(col="genes") + labs(title="points"))
wrap_plots(c(list(all), one), nrow=2)
A scalebar of a specified length (in the annotated unit) can be added using
the scalebar() function.
plotSpatialData(x) +
plotImage() +
plotLabel(a=1/3) +
scalebar(len=10, xrel=0.05, yrel=0.95)
## R version 4.6.1 Patched (2026-06-24 r90190)
## Platform: x86_64-apple-darwin20
## Running under: macOS Ventura 13.7.8
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.6-x86_64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.6-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
##
## locale:
## [1] C/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: America/New_York
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] SpatialData.plot_0.99.12 spatialdataR_0.99.47 ggnewscale_0.5.2
## [4] patchwork_1.3.2 ggplot2_4.0.3 BiocStyle_2.41.0
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 grumpy_0.1.1
## [3] blob_1.3.0 dplyr_1.2.1
## [5] farver_2.1.2 R.utils_2.13.0
## [7] S7_0.2.2 fastmap_1.2.0
## [9] SingleCellExperiment_1.35.2 duckdb_1.5.6
## [11] digest_0.6.39 lifecycle_1.0.5
## [13] sf_1.1-3 paws.storage_0.11.0
## [15] magrittr_2.0.5 compiler_4.6.1
## [17] rlang_1.3.0 sass_0.4.10
## [19] tools_4.6.1 yaml_2.3.12
## [21] knitr_1.52 labeling_0.4.3
## [23] S4Arrays_1.13.2 classInt_0.4-11
## [25] curl_8.1.0 reticulate_1.47.0
## [27] DelayedArray_0.39.8 RColorBrewer_1.1-3
## [29] abind_1.4-8 KernSmooth_2.23-27
## [31] withr_3.0.3 purrr_1.2.2
## [33] BiocGenerics_0.59.12 R.oo_1.27.1
## [35] grid_4.6.1 stats4_4.6.1
## [37] e1071_1.7-17 progressr_1.1.0
## [39] scales_1.4.0 tinytex_0.61
## [41] dichromat_2.0-1 SummarizedExperiment_1.43.0
## [43] cli_3.6.6 rmarkdown_2.32
## [45] crayon_1.5.3 generics_0.1.4
## [47] otel_0.2.0 DBI_1.3.0
## [49] cachem_1.1.0 proxy_0.4-29
## [51] BiocManager_1.30.27 XVector_0.53.0
## [53] matrixStats_1.5.0 vctrs_0.7.3
## [55] Matrix_1.7-6 jsonlite_2.0.0
## [57] bookdown_0.48 IRanges_2.47.5
## [59] S4Vectors_0.51.10 RBGL_1.89.0
## [61] magick_2.9.1 jquerylib_0.1.4
## [63] units_1.0-1 glue_1.8.1
## [65] ZarrArray_1.1.7 gtable_0.3.6
## [67] Rarr_2.1.48 GenomicRanges_1.65.4
## [69] tibble_3.3.1 pillar_1.11.1
## [71] htmltools_0.5.9 Seqinfo_1.3.2
## [73] graph_1.91.0 dbplyr_2.6.0
## [75] R6_2.6.1 httr2_1.3.0
## [77] wk_0.9.5 evaluate_1.0.5
## [79] lattice_0.23-1 Biobase_2.73.2
## [81] R.methodsS3_1.8.2 png_0.1-9
## [83] duckspatial_1.3.0 paws.common_0.9.0
## [85] bslib_0.12.0 class_7.3-24
## [87] uuid_1.2-2 Rcpp_1.1.2
## [89] SparseArray_1.13.4 anndataR_1.3.3
## [91] xfun_0.62 MatrixGenerics_1.25.0
## [93] pkgconfig_2.0.3