| name | bio-spatial-transcriptomics-spatial-data-io |
| description | Load spatial transcriptomics data from Visium, Xenium, MERFISH, Slide-seq, and other platforms using Squidpy and SpatialData. Read Space Ranger outputs, convert formats, and access spatial coordinates. Use when loading Visium, Xenium, MERFISH, or other spatial data. |
| tool_type | python |
| primary_tool | squidpy |
Version Compatibility
Reference examples tested with: anndata 0.10+, numpy 1.26+, pandas 2.2+, scanpy 1.10+, spatialdata 0.1+, squidpy 1.3+
Before using code patterns, verify installed versions match. If versions differ:
- Python:
pip show <package> then help(module.function) to check signatures
If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.
Spatial Data I/O
"Load my Visium spatial data" → Read spatial transcriptomics outputs (Visium, Xenium, MERFISH, Slide-seq) into AnnData objects with spatial coordinates and tissue images.
- Python:
squidpy.read.visium('spaceranger_out/'), spatialdata.read_zarr()
Load and work with spatial transcriptomics data from various platforms.
Required Imports
import squidpy as sq
import scanpy as sc
import anndata as ad
import spatialdata as sd
import spatialdata_io as sdio
Load 10X Visium Data
Goal: Load Visium spatial transcriptomics data from Space Ranger output into an AnnData object.
Approach: Use Squidpy's read.visium to parse the output directory, which loads expression, spatial coordinates, and tissue images.
adata = sq.read.visium('path/to/spaceranger/output/')
print(f'Loaded {adata.n_obs} spots, {adata.n_vars} genes')
print(f"Spatial coords shape: {adata.obsm['spatial'].shape}")
library_id = list(adata.uns['spatial'].keys())[0]
print(f'Library ID: {library_id}')
Load Visium with Scanpy
Goal: Load Visium data using Scanpy's built-in reader as an alternative to Squidpy.
Approach: Use sc.read_visium to parse Space Ranger output, then access images and scale factors from adata.uns['spatial'].
adata = sc.read_visium('path/to/spaceranger/output/')
img = adata.uns['spatial'][library_id]['images']['hires']
scale_factor = adata.uns['spatial'][library_id]['scalefactors']['tissue_hires_scalef']
Load 10X Xenium Data
Goal: Load single-cell resolution Xenium spatial data.
Approach: Use Squidpy's read.xenium to parse Xenium output, yielding per-cell expression and coordinates.
adata = sq.read.xenium('path/to/xenium/output/')
print(f'Loaded {adata.n_obs} cells')
print(f"Cell coordinates: {adata.obsm['spatial'].shape}")
Load with SpatialData (Recommended for New Projects)
Goal: Load spatial data into SpatialData objects for unified multi-modal representation.
Approach: Use spatialdata-io readers per platform, which organize expression, shapes, and images into a single object.
import spatialdata_io as sdio
sdata = sdio.visium('path/to/spaceranger/output/')
print(sdata)
sdata = sdio.xenium('path/to/xenium/output/')
table = sdata.tables['table']
shapes = sdata.shapes
images = sdata.images
Load MERFISH Data
Goal: Load MERFISH (Vizgen MERSCOPE) spatial data.
Approach: Use spatialdata-io or Squidpy readers to parse MERSCOPE output with cell-by-gene counts and metadata.
sdata = sdio.merscope('path/to/merscope/output/')
adata = sq.read.vizgen('path/to/vizgen/output/', counts_file='cell_by_gene.csv', meta_file='cell_metadata.csv')
Load Slide-seq Data
adata = sq.read.slideseq('beads.csv', coordinates_file='coords.csv')
Load Nanostring CosMx
sdata = sdio.cosmx('path/to/cosmx/output/')
Load Stereo-seq Data
sdata = sdio.stereoseq('path/to/stereoseq/output/')
Load from H5AD with Spatial Coordinates
adata = sc.read_h5ad('spatial_data.h5ad')
if 'spatial' in adata.obsm:
print('Has spatial coordinates')
if 'spatial' in adata.uns:
print('Has image data')
Create Spatial AnnData from Scratch
Goal: Construct a spatial AnnData object from raw expression and coordinate arrays.
Approach: Build an AnnData with spatial coordinates in obsm['spatial'] and minimal metadata in uns['spatial'] for Squidpy compatibility.
import numpy as np
import pandas as pd
X = np.random.poisson(5, size=(1000, 500))
spatial_coords = np.random.rand(1000, 2) * 1000
adata = ad.AnnData(X)
adata.obs_names = [f'spot_{i}' for i in range(1000)]
adata.var_names = [f'gene_{i}' for i in range(500)]
adata.obsm['spatial'] = spatial_coords
adata.uns['spatial'] = {
'library_id': {
'scalefactors': {'tissue_hires_scalef': 1.0, 'spot_diameter_fullres': 50},
}
}
Access Spatial Coordinates
coords = adata.obsm['spatial']
x_coords = coords[:, 0]
y_coords = coords[:, 1]
coord_df = pd.DataFrame(adata.obsm['spatial'], index=adata.obs_names, columns=['x', 'y'])
Access Tissue Images
library_id = list(adata.uns['spatial'].keys())[0]
hires_img = adata.uns['spatial'][library_id]['images']['hires']
lowres_img = adata.uns['spatial'][library_id]['images']['lowres']
scalef = adata.uns['spatial'][library_id]['scalefactors']
print(f"Hires scale: {scalef['tissue_hires_scalef']}")
print(f"Spot diameter: {scalef['spot_diameter_fullres']}")
Convert Between Formats
Goal: Convert spatial data between SpatialData and AnnData representations.
Approach: Extract tables and coordinate arrays from SpatialData, then save as h5ad or zarr.
sdata = sdio.visium('path/to/data/')
adata = sdata.tables['table'].copy()
adata.obsm['spatial'] = np.array(sdata.shapes['spots'][['x', 'y']])
adata.write_h5ad('spatial_converted.h5ad')
sdata.write('spatial_data.zarr')
Load Multiple Samples
Goal: Load and merge spatial data from multiple Visium samples into a single AnnData.
Approach: Iterate over sample directories, tag each with a sample label, then concatenate with ad.concat.
samples = ['sample1', 'sample2', 'sample3']
adatas = []
for sample in samples:
adata = sq.read.visium(f'data/{sample}/')
adata.obs['sample'] = sample
adatas.append(adata)
adata_combined = ad.concat(adatas, label='sample', keys=samples)
print(f'Combined: {adata_combined.n_obs} spots')
Subset by Spatial Region
Goal: Extract spots within a rectangular spatial region of interest.
Approach: Apply coordinate-based boolean masking on obsm['spatial'] to filter spots by x/y bounds.
x_min, x_max = 1000, 2000
y_min, y_max = 1500, 2500
coords = adata.obsm['spatial']
in_region = (coords[:, 0] >= x_min) & (coords[:, 0] <= x_max) & (coords[:, 1] >= y_min) & (coords[:, 1] <= y_max)
adata_region = adata[in_region].copy()
print(f'Selected {adata_region.n_obs} spots')
Related Skills
- spatial-preprocessing - QC and normalization after loading
- spatial-visualization - Plot spatial data
- single-cell/data-io - Non-spatial scRNA-seq data loading