Technology focus: Visium HD (SpaceRanger 4.0)#
This notebook demonstrates how to work with Visium HD data from SpaceRanger 4.0, which introduces cell and nucleus segmentation capabilities. Unlike the binned Visium HD workflow, where data is represented as bins at multiple resolutions (2µm, 8µm, 16µm), this notebook focuses on analyzing cell-level segmentations. We will load nucleus and cell segmentations, perform quality control, clustering, and visualize gene expression at the single-cell level. The dataset used here is a Visium HD Mouse Brain (Fresh Frozen) processed with SpaceRanger 4.0.1.
import spatialdata as sd
import spatialdata_io as sdio
import matplotlib.pyplot as plt
import scanpy as sc
import spatialdata_plot # noqa: F401
print(f"spatialdata_io=={sdio.__version__}")
print(f"spatialdata=={sd.__version__}")
spatialdata_io==0.5.1
spatialdata==0.6.2.dev1+g53b9438a3
Download Visium HD example dataset from 10x public data repository#
You’ll need approximately 15 Gb of disk space. The data can be downloaded from the 10x public data repository.
Information regarding data licensing and attribution for the dataset listed above are also available at: https://github.com/scverse/spatialdata-notebooks/tree/main/datasets.
Simple convenience scripts for downloading the data and converting it to SpatialData Zarr are available in spatialdata-sandbox.
spatialdata-io supports Visium HD 4.0 data#
Crucially, the script to_zarr.py uses spatialdata-io for reading the Visium HD SpaceRanger 4.0 data. Here we use the parameters:
load_segmentation_only=True, to avoid loading the bins and only focus on cell segmentation;load_nucleus_segmentation=True, to derive the gene expression information by aggregating bins into nuclei geometries. Please consult the documentation forvisium_hd()for all the possible configurations.
Read in Visium HD data#
After downloading the data and converting it to the SpatialData Zarr format, create symlinks so the subsequent command can access it.
visium_hd_mouse_brain = sd.read_zarr("visium_hd_4.0.1.zarr")
visium_hd_mouse_brain
SpatialData object, with associated Zarr store: /Users/macbook/embl/projects/basel/spatialdata-sandbox/visium_hd_4.0.1_io/data.zarr
├── Images
│ ├── 'Visium_HD_3prime_Mouse_Brain_hires_image': DataArray[cyx] (3, 5492, 6000)
│ └── 'Visium_HD_3prime_Mouse_Brain_lowres_image': DataArray[cyx] (3, 549, 600)
├── Shapes
│ ├── 'Visium_HD_3prime_Mouse_Brain_cell_segmentations': GeoDataFrame shape: (84031, 2) (2D shapes)
│ └── 'Visium_HD_3prime_Mouse_Brain_nucleus_segmentations': GeoDataFrame shape: (83153, 2) (2D shapes)
└── Tables
├── 'cell_segmentations': AnnData (84031, 33696)
└── 'nucleus_segmentations': AnnData (83153, 33696)
with coordinate systems:
▸ 'Visium_HD_3prime_Mouse_Brain', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_hires', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_lowres', with elements:
Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
Visualize the images and segmentations#
visium_hd_mouse_brain.pl.render_images().pl.show()
INFO Rasterizing image for faster rendering.
INFO Rasterizing image for faster rendering.
(
visium_hd_mouse_brain.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_shapes("Visium_HD_3prime_Mouse_Brain_cell_segmentations")
.pl.show(coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
INFO Using 'datashader' backend with 'None' as reduction method to speed up plotting. Depending on the
reduction method, the value range of the plot might change. Set method to 'matplotlib' to disable this
behaviour.
Now let’s visualizes a relevant gene Hpca
gene_name = "Hpca"
(
visium_hd_mouse_brain.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_shapes("Visium_HD_3prime_Mouse_Brain_cell_segmentations", color=gene_name)
.pl.show(coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
INFO Using 'datashader' backend with 'None' as reduction method to speed up plotting. Depending on the
reduction method, the value range of the plot might change. Set method to 'matplotlib' to disable this
behaviour.
INFO Using the datashader reduction "mean". "max" will give an output very close to the matplotlib result.
Quality control and filtering#
visium_hd_mouse_brain
SpatialData object, with associated Zarr store: /Users/macbook/embl/projects/basel/spatialdata-sandbox/visium_hd_4.0.1_io/data.zarr
├── Images
│ ├── 'Visium_HD_3prime_Mouse_Brain_hires_image': DataArray[cyx] (3, 5492, 6000)
│ └── 'Visium_HD_3prime_Mouse_Brain_lowres_image': DataArray[cyx] (3, 549, 600)
├── Shapes
│ ├── 'Visium_HD_3prime_Mouse_Brain_cell_segmentations': GeoDataFrame shape: (84031, 2) (2D shapes)
│ └── 'Visium_HD_3prime_Mouse_Brain_nucleus_segmentations': GeoDataFrame shape: (83153, 2) (2D shapes)
└── Tables
├── 'cell_segmentations': AnnData (84031, 33696)
└── 'nucleus_segmentations': AnnData (83153, 33696)
with coordinate systems:
▸ 'Visium_HD_3prime_Mouse_Brain', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_hires', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_lowres', with elements:
Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
# Add mitochondrial gene calculation for QC
visium_hd_mouse_brain.tables["cell_segmentations"].var["mt"] = visium_hd_mouse_brain.tables[
"cell_segmentations"
].var_names.str.startswith(("MT-", "mt-"))
sc.pp.calculate_qc_metrics(
visium_hd_mouse_brain.tables["cell_segmentations"], qc_vars=["mt"], inplace=True, percent_top=None
)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
sc.pl.violin(
adata=visium_hd_mouse_brain.tables["cell_segmentations"],
keys=["log1p_total_counts"],
stripplot=False,
inner="box",
ax=axes[0, 0],
show=False,
)
axes[0, 0].set_title("Total UMI")
sc.pl.violin(
adata=visium_hd_mouse_brain.tables["cell_segmentations"],
keys=["log1p_n_genes_by_counts"],
stripplot=False,
inner="box",
ax=axes[0, 1],
show=False,
)
axes[0, 1].set_title("Total Genes")
sc.pl.violin(
adata=visium_hd_mouse_brain.tables["cell_segmentations"],
keys=["log1p_total_counts_mt"],
stripplot=False,
inner="box",
ax=axes[1, 0],
show=False,
)
axes[1, 0].set_title("Mitochondrial Genes")
# Hide the unused subplot
axes[1, 1].axis("off")
plt.tight_layout()
plt.show()
plt.close("all")
Normalization and Clustering#
sc.pp.normalize_total(visium_hd_mouse_brain.tables["cell_segmentations"], target_sum=None)
sc.pp.log1p(visium_hd_mouse_brain.tables["cell_segmentations"])
sc.tl.pca(visium_hd_mouse_brain.tables["cell_segmentations"])
# neighborhood and clustering resolution
RES = 0.5 # clustering resolution
NEIGHBORS = 30 # number of neighbors
MIN_DIST = 0.5 # default 0.5
SPREAD = 2 # default 1
sc.pp.neighbors(
visium_hd_mouse_brain.tables["cell_segmentations"], n_neighbors=NEIGHBORS, use_rep="X_pca", metric="correlation"
)
sc.tl.leiden(
visium_hd_mouse_brain.tables["cell_segmentations"],
flavor="igraph",
key_added="clusters",
resolution=RES,
random_state=0,
)
(
visium_hd_mouse_brain.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_shapes(
"Visium_HD_3prime_Mouse_Brain_cell_segmentations", color="clusters", table_name="cell_segmentations"
)
.pl.show(title="clusters over H&E image", coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
INFO Using 'datashader' backend with 'None' as reduction method to speed up plotting. Depending on the
reduction method, the value range of the plot might change. Set method to 'matplotlib' to disable this
behaviour.
def crop0_lowres(data, min_x, max_x, min_y, max_y, target_coordinate_system):
return sd.bounding_box_query(
data,
min_coordinate=[min_x, min_y],
max_coordinate=[max_x, max_y],
axes=("x", "y"),
target_coordinate_system=target_coordinate_system,
)
(
crop0_lowres(visium_hd_mouse_brain, 150, 250, 300, 500, "Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_shapes(
"Visium_HD_3prime_Mouse_Brain_cell_segmentations", color="clusters", outline_width=0.10, outline_alpha=1
)
.pl.show(title="Mouse Hypothalamus Clusters", coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
Calculate centroids#
Use nucleus centroids for this calculation for use in analyses like cell cell communication
centroids = sd.get_centroids(
visium_hd_mouse_brain.shapes["Visium_HD_3prime_Mouse_Brain_nucleus_segmentations"],
coordinate_system="Visium_HD_3prime_Mouse_Brain_downscaled_lowres",
)
visium_hd_mouse_brain.points["Visium_HD_3prime_Mouse_Brain_nucleus_centroids"] = centroids
visium_hd_mouse_brain
SpatialData object, with associated Zarr store: /Users/macbook/embl/projects/basel/spatialdata-sandbox/visium_hd_4.0.1_io/data.zarr
├── Images
│ ├── 'Visium_HD_3prime_Mouse_Brain_hires_image': DataArray[cyx] (3, 5492, 6000)
│ └── 'Visium_HD_3prime_Mouse_Brain_lowres_image': DataArray[cyx] (3, 549, 600)
├── Points
│ └── 'Visium_HD_3prime_Mouse_Brain_nucleus_centroids': DataFrame with shape: (<Delayed>, 2) (2D points)
├── Shapes
│ ├── 'Visium_HD_3prime_Mouse_Brain_cell_segmentations': GeoDataFrame shape: (84031, 2) (2D shapes)
│ └── 'Visium_HD_3prime_Mouse_Brain_nucleus_segmentations': GeoDataFrame shape: (83153, 2) (2D shapes)
└── Tables
├── 'cell_segmentations': AnnData (84031, 33696)
└── 'nucleus_segmentations': AnnData (83153, 33696)
with coordinate systems:
▸ 'Visium_HD_3prime_Mouse_Brain', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_hires', with elements:
Visium_HD_3prime_Mouse_Brain_hires_image (Images), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
▸ 'Visium_HD_3prime_Mouse_Brain_downscaled_lowres', with elements:
Visium_HD_3prime_Mouse_Brain_lowres_image (Images), Visium_HD_3prime_Mouse_Brain_nucleus_centroids (Points), Visium_HD_3prime_Mouse_Brain_cell_segmentations (Shapes), Visium_HD_3prime_Mouse_Brain_nucleus_segmentations (Shapes)
with the following elements not in the Zarr store:
▸ Visium_HD_3prime_Mouse_Brain_nucleus_centroids (Points)
(
visium_hd_mouse_brain.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_points("Visium_HD_3prime_Mouse_Brain_nucleus_centroids", size=0.2, color="black")
.pl.show(title="Centroids over H&E image", coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
INFO Value for parameter 'color' appears to be a color, using it as such.
INFO Using 'datashader' backend with 'None' as reduction method to speed up plotting. Depending on the
reduction method, the value range of the plot might change. Set method to 'matplotlib' do disable this
behaviour.
(
crop0_lowres(visium_hd_mouse_brain, 150, 250, 300, 500, "Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
.pl.render_images("Visium_HD_3prime_Mouse_Brain_lowres_image")
.pl.render_points("Visium_HD_3prime_Mouse_Brain_nucleus_centroids", size=0.2, color="black")
.pl.show(title="Mouse Hypothalamus Centroids", coordinate_systems="Visium_HD_3prime_Mouse_Brain_downscaled_lowres")
)
INFO Value for parameter 'color' appears to be a color, using it as such.