10x Genomics Visium captures spatially resolved gene expression by measuring transcriptomes at defined spots arrayed across a tissue section. Each spot retains its physical coordinates and is co-registered with a histology image, enabling joint spatial-statistical analysis.
scConvert preserves every spatial component during conversion: spot coordinates, high-resolution and low-resolution tissue images, and scale factors. The same dataset can therefore be analyzed in Seurat (R) and squidpy (Python) without any data loss or manual reformatting.
The stxBrain.h5ad file contains the 10x Genomics mouse
brain anterior section distributed with the Seurat spatial vignette
(2,696 spots, 31,053 genes, ~70 MB).
h5ad_path <- "../stxBrain.h5ad"
t0 <- proc.time()
brain <- readH5AD(h5ad_path, verbose = FALSE)
elapsed <- (proc.time() - t0)[["elapsed"]]
cat(sprintf("Loaded: %d spots x %d genes in %.2fs\n",
ncol(brain), nrow(brain), elapsed))
#> Loaded: 2696 spots x 31053 genes in 2.29s
cat(sprintf("Images: %s\n",
paste(names(brain@images), collapse = ", ")))
#> Images: anterior1
cat(sprintf("Reductions: %s\n",
paste(names(brain@reductions), collapse = ", ")))
#> Reductions:
Hpca (hippocalcin) is a marker of hippocampal neurons;
Ttr (transthyretin) marks the choroid plexus. Plotting both
on the tissue section confirms that scConvert preserves coordinate
registration with the histology image.
SpatialFeaturePlot(brain, features = c("Hpca", "Ttr"), ncol = 2)
A standard Seurat workflow — normalization, variable feature selection, PCA, graph construction, clustering, and UMAP — is applied to the spatial data. The spatial context does not require any modification of the pipeline.
brain <- NormalizeData(brain, verbose = FALSE)
brain <- FindVariableFeatures(brain, verbose = FALSE)
brain <- ScaleData(brain, verbose = FALSE)
brain <- RunPCA(brain, verbose = FALSE)
brain <- FindNeighbors(brain, verbose = FALSE)
brain <- FindClusters(brain, verbose = FALSE)
brain <- RunUMAP(brain, dims = 1:30, verbose = FALSE)
cat(sprintf("Clusters: %d\n",
length(unique(brain$seurat_clusters))))
#> Clusters: 15
Each spot is colored by its Leiden cluster identity, overlaid on the histology image. Cluster boundaries align with anatomical structures visible in the tissue.
SpatialDimPlot(brain, label = TRUE, label.size = 3)
The UMAP projection separates clusters that map to distinct spatial regions, consistent with region-specific transcriptional programs.
DimPlot(brain, reduction = "umap", label = TRUE, pt.size = 0.5) +
labs(title = "UMAP: mouse brain anterior section") +
theme(plot.title = element_text(size = 12))
writeH5AD() serializes the Seurat object including
spatial coordinates, the tissue image, scale factors, cluster labels,
and dimensionality reduction embeddings.
out_h5ad <- file.path(tempdir(), "stxBrain_seurat.h5ad")
t0 <- proc.time()
writeH5AD(brain, out_h5ad, overwrite = TRUE)
elapsed <- (proc.time() - t0)[["elapsed"]]
cat(sprintf("Wrote h5ad: %.2fs | %.1f MB\n",
elapsed, file.size(out_h5ad) / 1e6))
#> Wrote h5ad: 4.61s | 76.8 MB
The exported h5ad is read by anndata and visualized with squidpy to confirm that spatial coordinates and cluster labels survived the round-trip.
import anndata
import squidpy as sq
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
adata = anndata.read_h5ad(r.out_h5ad)
print(f"Loaded: {adata.n_obs} spots x {adata.n_vars} genes")
#> Loaded: 2696 spots x 31053 genes
print(f"Has spatial: {'spatial' in adata.obsm}")
#> Has spatial: True
print(f"Clusters: {adata.obs['seurat_clusters'].nunique()}")
#> Clusters: 15
sq.pl.spatial_scatter(adata, color="seurat_clusters", figsize=(6, 5))
plt.tight_layout()
plt.show()
Every spatial component required for downstream Python analysis is written verbatim by scConvert.
| Component | h5ad location | Preserved by scConvert |
|---|---|---|
| Expression matrix | X / raw/X | Yes |
| Spot coordinates | obsm/spatial | Yes |
| Tissue image | uns/spatial/*/images | Yes |
| Scale factors | uns/spatial/*/scalefactors | Yes |
| Cell metadata | obs | Yes |
| Cluster labels | obs/seurat_clusters | Yes |
| PCA embedding | obsm/X_pca | Yes |
| UMAP embedding | obsm/X_umap | Yes |
Scale factors are written as HDF5 scalars (shape=()),
matching the convention expected by squidpy and scanpy for spot-size
calculations.
scConvert handles a range of spatial platforms beyond Visium:
readGEF() and converted to h5adAll platforms share the same read/write API: readH5AD(),
writeH5AD(), and the scConvert()
dispatcher.