Quickstart¶
This page runs one small dataset all the way through: raw single-cell quantification in, cell types and spatial statistics out. It uses the demo data — a single exemplar image with 11,201 cells and 9 markers.
If you would rather follow along cell by cell, the same material is available as executable notebooks under Tutorials.
1. Build a cell table¶
mcmicro-style quantification CSVs become an AnnData in one call:
The result carries expression in .X, marker names in .var_names, and
X_centroid, Y_centroid, Area, CellID, and imageid in .obs.
Already have an .h5ad? Every function accepts the path directly, so there is
nothing to load first.
2. Rescale expression to a common scale¶
Gates convert raw intensities to a 0–1 scale where 0.5 is the positive/negative boundary, which is what phenotyping expects:
With no gate, scimappro fits a two-component Gaussian mixture per marker per
image and uses the crossing point. Pass a CSV (or a DataFrame) with markers
and one column per image to override that with manual gates.
3. Assign cell types¶
Phenotyping is driven by a hierarchical workflow CSV: rows are cell types,
columns are markers, cells hold pos, neg, allpos, allneg, anypos, or
anyneg.
adata = sp.tl.phenotype(adata, phenotype="phenotype_workflow.csv")
adata.obs["phenotype"].value_counts()
Prefer unsupervised labels? tl.cluster runs kmeans,
leiden, or dbscan over the same matrix.
4. Look at what you got¶
sp.pl.heatmap(adata, groupBy="phenotype", standardScale="column")
sp.pl.spatialScatterPlot(adata, colorBy="phenotype", s=3)
sp.pl.pie(adata, phenotype="phenotype")
5. Measure spatial relationships¶
Average distance from every cell type to every other:
adata = sp.tl.spatialDistance(adata, phenotype="phenotype")
sp.pl.spatialDistanceHeatmap(adata, phenotype="phenotype")
Which cell types sit next to each other more often than chance, tested against a permutation null:
adata = sp.tl.spatialCooccurrence(adata, phenotype="phenotype", permutation=1000)
sp.pl.spatialCooccurrence(adata)
sp.pl.spatialInteractionNetwork(adata)
6. Find recurrent neighbourhoods¶
Count each cell's neighbours by type, then cluster those count vectors to get recurrent cellular neighbourhoods:
adata = sp.tl.neighCount(adata, phenotype="phenotype", method="radius", radius=30)
adata = sp.tl.cluster(adata, mode="spatial", layer="neighCount", method="kmeans", k=6,
label="neighbourhood") # (1)!
sp.pl.spatialScatterPlot(adata, colorBy="neighbourhood", s=3)
- In
mode="spatial",layernames a key inadata.uns, notadata.layers— it is wheretl.neighCountand friends leave their count matrix.
tl.neighLDA and
tl.neighNMF give the same idea as soft, overlapping
motifs instead of hard assignments.
7. Save¶
Or pass outputDir to any function and it writes rather than returns:
The whole thing¶
import scimappro as sp
adata = sp.pp.mcmicro_to_scimap("quantification/quant.csv")
adata = sp.pp.rescale(adata, gate="manual_gates.csv")
adata = sp.tl.phenotype(adata, phenotype="phenotype_workflow.csv")
adata = sp.tl.spatialDistance(adata, phenotype="phenotype")
adata = sp.tl.spatialCooccurrence(adata, phenotype="phenotype", permutation=1000)
sp.pl.heatmap(adata, groupBy="phenotype", standardScale="column")
sp.pl.spatialCooccurrence(adata)
adata.write("analysis.h5ad")
Next steps¶
- The same pipeline on a
SpatialDatastore: SpatialData. - The same pipeline on a file too large for memory: Streaming.
- Coming from the community edition: Migrating from scimap.
- Every parameter of every function: API index.