MultiAssaySpatialExperiment

Multi-modal spatial transcriptomics with Bioconductor

License: MIT Bioconductor

Overview

MultiAssaySpatialExperiment extends MultiAssayExperiment with spatial context for integrated analysis of spatially resolved multi-omics data. It provides:

Installation

# From Bioconductor (devel)
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

BiocManager::install("MultiAssaySpatialExperiment", version = "devel")

# Or install from a local source checkout
# R CMD INSTALL path/to/MultiAssaySpatialExperiment

Quick Start

Load vendor data directly

library(MultiAssaySpatialExperiment)

# Read 10x Xenium data
mase <- readXeniumMASE("path/to/xenium/output")

# Read 10x Visium HD data
mase <- readVisiumHDMASE("path/to/visium_hd/output",
                         bin_size = c("008", "016"))

# Read Vizgen MERSCOPE data
mase <- readMERSCOPEMASE("path/to/merscope/output",
                         segmentation = "cellpose",
                         load_transcripts = TRUE)

# Read NanoString CosMx data
mase <- readCosMxMASE("path/to/cosmx/output")

# Read standard 10x Visium data
mase <- readVisiumMASE("path/to/visium/output")

Supported technologies: Xenium, Visium, Visium HD, MERSCOPE (Vizgen), CosMx (NanoString)

Build from components

# Create from scratch
mase <- MultiAssaySpatialExperiment(
    experiments = ExperimentList(
        rna = rna_counts,
        protein = protein_counts
    ),
    colData = sample_metadata,
    sampleMap = sample_map,
    points = PointsLayerList(
        transcripts = transcript_coords,
        centroids = cell_centroids
    ),
    shapes = ShapesLayerList(
        cells = cell_polygons,
        tissue = tissue_boundary
    ),
    spatialMap = spatial_map
)

Convert from existing objects

# From SpatialExperiment
spe <- SpatialExperiment(...)
mase <- as(spe, "MultiAssaySpatialExperiment")

# From SpatialFeatureExperiment
sfe <- SpatialFeatureExperiment(...)
mase <- as(sfe, "MultiAssaySpatialExperiment")

Core Features

Spatial Operations

# Point-in-polygon annotation
mase <- annotateWithRegions(mase,
                            points = "centroids",
                            shapes = "cells")

# Aggregate expression by spatial region
cell_expr <- aggregateByRegion(mase,
                               by = "cells",
                               FUN = "sum")

# Spatial subsetting
library(sf)
roi <- st_polygon(list(matrix(c(0, 0, 1000, 0, 1000, 1000, 0, 1000, 0, 0),
                              ncol = 2, byrow = TRUE)))
mase_tissue <- subsetByPolygon(mase, roi)

mase_bbox <- subsetByBoundingBox(mase,
                                 xmin = 0, xmax = 1000,
                                 ymin = 0, ymax = 1000)

Standard Subsetting

Uses the same subsetBy* API as MultiAssayExperiment — no separate spatial query API. Specimen subsetting ([, j], subsetByColData) and observation filtering (subsetByColumn with a list) both propagate to spatialMap, imgData, and linked points, shapes, images, and labels.

# By sample, assay, column, or observation metadata
mase[, colData(mase)$tissue_type == "tumor"]
mase[c("rna", "protein"), ]
subsetByAssay(mase, "rna")
cdf <- colData(experiments(mase)[["rna"]])
subsetByColumn(mase, list(rna = cdf$region == "core"))

Construction helpers

spmap <- buildSpatialMap(sampleMap(mase), region = "cells", element_type = "shapes")
prepared <- prepMASE(experiments(mase), colData(mase), sampleMap(mase),
                     points = spatialPoints(mase), spatialMap = spmap)
mase2 <- do.call(MultiAssaySpatialExperiment, prepared)

Access Spatial Data

# Points (DataFrame with coordinates)
transcripts <- spatialPoints(mase)$transcripts
centroids <- spatialPoints(mase)$centroids

# Shapes (sf objects with geometries)
cell_boundaries <- spatialShapes(mase)$cells
tissue_outline <- spatialShapes(mase)$tissue

# Images and labels
spatialImages(mase)
spatialLabels(mase)

# Spatial mapping table
spatialMap(mase)

Why MultiAssaySpatialExperiment?

For SpatialExperiment users

Problem: SpatialExperiment handles one assay per object. Multi-assay data requires managing separate objects or ad-hoc lists.

Solution: MASE provides a unified multi-assay container with shared spatial layers. Subset once, filter everywhere. Full coercion support maintains interoperability.

# Instead of managing multiple SPE objects
spe_rna <- SpatialExperiment(...)
spe_protein <- SpatialExperiment(...)

# Use one MASE object
mase <- MultiAssaySpatialExperiment(
    experiments = ExperimentList(rna = spe_rna, protein = spe_protein),
    ...
)

For SpatialFeatureExperiment users

Problem: SFE extends SPE with rich geometry support but is single-assay.

Solution: MASE provides the multi-assay scaffold. Each assay can be an SFE. Instance-level spatialMap links columns across assays to shared spatial features.

# Multi-assay with SFE-compatible structure
mase <- MultiAssaySpatialExperiment(
    experiments = ExperimentList(
        rna = sfe_rna,        # SFE object
        morphology = sfe_morph # SFE object
    ),
    shapes = ShapesLayerList(cells = boundaries),
    spatialMap = map  # Links both assays to same cells
)

Architecture

Core Components

Inherited from MultiAssayExperiment:

Spatial extensions:

The spatialMap Table

Links assay columns to spatial features at instance level:

assay colname element_type region instance_id
rna ACGT-1 shapes cells cell_001
rna ACGT-2 shapes cells cell_002
protein ACGT-1 shapes cells cell_001

Data Readers

Built-in support for major spatial transcriptomics platforms:

Technology Reader Function Data Types Special Features
10x Xenium readXeniumMASE() Counts, cells, boundaries, transcripts Auto-format detection (HDF5/Parquet)
10x Visium readVisiumMASE() Counts, positions, images H&E integration, spot geometries
10x Visium HD readVisiumHDMASE() Multi-bin counts, images Multiple resolutions (002µm, 008µm, 016µm)
Vizgen MERSCOPE readMERSCOPEMASE() FOV-based, transcripts, boundaries Multi-FOV, cellpose/watershed segmentation
NanoString CosMx readCosMxMASE() FOV-based, expression, boundaries Multi-FOV, GeoParquet geometries

All readers:

Documentation

Vignettes

  1. Introduction to MultiAssaySpatialExperiment: overview, construction, basic operations, and a quick-reference table
  2. Working with MultiAssaySpatialExperiment: subsetting, spatial annotation, aggregation, labels ↔ shapes
  3. MultiAssaySpatialExperiment use cases: real-data workflows with readers, multi-assay integration, coordinate transforms
browseVignettes("MultiAssaySpatialExperiment")

Key Functions

Data import:

Spatial operations:

Accessors:

Coercion:

Design Principles

Terminology and spatialdata alignment

MASE aligns with spatialdata (Python) for interoperability:

See ?MultiAssaySpatialExperiment for detailed terminology documentation.

Instance-Level Validation

instance_id validation ensures referential integrity:

Helps catch data inconsistencies early.

Performance and Extensibility

S4 Generics for File I/O

All readers use S4 generics (readParquetForMASE(), readGeoParquetForMASE(), etc.) enabling:

Component-Based Architecture

Technology readers orchestrate reusable components:

Add new platforms without modifying core code.

Package Statistics

Development Status

Version 0.9.3 - Pre-release for community feedback

Getting Help

License

MIT License — see DESCRIPTION.

Copyright (c) 2023-2026 Genentech, Inc.

Related Projects