Skip to content

cluster

cluster

cluster(
    data,
    mode="expression",
    layer="raw",
    subsetMarkers=None,
    method="kmeans",
    k=10,
    nPcs=None,
    leidenResolution=1,
    leidenNearestNeighbors=30,
    dbscanEps=0.5,
    dbscanMinSamples=5,
    log=True,
    randomState=0,
    subCluster=None,
    subClusterGroup=None,
    collapseLabels=False,
    label=None,
    verbose=True,
    outputDir=None,
    maxWorkers=None,
    streamData=False,
    sdataTable=None,
)

Cluster cells by expression, or by their neighbourhood composition.

Three methods are available — kmeans, leiden, and dbscan — over either of two inputs:

  • mode="expression" clusters the marker matrix chosen by layer. This is ordinary phenotyping-by-clustering.
  • mode="spatial" clusters a neighbourhood matrix in uns, where layer names a uns key rather than a layers key. Feed it the output of neighCount, neighExp, neighLDA, or neighNMF and you get Recurrent Cellular Neighbourhoods. This replaces scimap's separate spatial_cluster.

Sub-clustering is built in: set subCluster to an existing label column and subClusterGroup to the labels you want to split, and only those cells are re-clustered.

Parameters:

Name Type Description Default
data (AnnData | SpatialData | str, required)

The cell table. An AnnData, a path to an .h5ad file, a SpatialData object, or a path to a .zarr SpatialData store.

required
mode str

'expression' reads the marker matrix; 'spatial' reads uns[layer].

'expression'
layer str

In expression mode: 'raw' uses .raw.X, None uses .X, any other string names a key in .layers. In spatial mode: the key in uns holding the neighbourhood matrix.

'raw'
subsetMarkers list

Cluster on these markers only. Expression mode.

None
method str

'kmeans', 'leiden', or 'dbscan'.

'kmeans'
k int

Number of clusters, for method='kmeans'.

10
nPcs int

Principal components to reduce to before clustering, for 'leiden' and 'dbscan'. None skips the PCA.

None
leidenResolution float

Leiden resolution. Higher gives more, smaller clusters.

1
leidenNearestNeighbors int

Neighbours used to build the Leiden graph.

30
dbscanEps float

DBSCAN neighbourhood radius, in the units of the clustered matrix.

0.5
dbscanMinSamples int

Minimum points for a DBSCAN core point.

5
log bool

Apply log1p before clustering.

True
randomState int

Seed, for reproducible clusters.

0
subCluster str

Column in obs holding existing labels to sub-cluster within.

None
subClusterGroup list

Which labels of subCluster to split. All of them when None.

None
collapseLabels bool

Give cells outside subClusterGroup their original subCluster label instead of leaving them unlabelled, so the output stays complete.

False
label str

Column in obs the cluster labels are written to. Defaults to the method name, e.g. 'kmeans'.

None
maxWorkers int

Cap on parallel workers. Defaults to max(1, cpu_count() - 1). Lower it to cut peak memory.

None
verbose bool

Print progress messages.

True
outputDir str

Directory to write the updated object to. With None the object is returned instead.

None
streamData bool

Run out of core against an .h5ad path with CAP-AnnData, reading only the sections this function needs and writing back only what it changes. Requires data to be a path; the file is updated in place and None is returned.

False
sdataTable str

Which SpatialData table to work on. Ignored for AnnData input, and optional when the store has exactly one table.

None

Returns:

Name Type Description
adata AnnData | SpatialData | None

The updated object with obs[label] holding the cluster labels. None in streaming mode.

Example
# Cluster on expression.
adata = sp.tl.cluster(adata, method="leiden", leidenResolution=1.0, label="leiden")
adata = sp.tl.umap(adata)
sp.pl.clusterPlots(adata, groupBy="leiden")

# Recurrent Cellular Neighbourhoods: cluster the neighbourhood matrix.
adata = sp.tl.neighCount(adata, phenotype="phenotype", radius=30)
adata = sp.tl.cluster(
    adata, mode="spatial", layer="neighCount", method="kmeans", k=6,
    label="neighbourhood",
)
sp.pl.spatialScatterPlot(adata, colorBy="neighbourhood", s=3)

# Split one existing cluster further, keeping the others intact.
adata = sp.tl.cluster(
    adata,
    method="kmeans",
    k=4,
    subCluster="leiden",
    subClusterGroup=["3"],
    collapseLabels=True,
    label="leiden_refined",
)