Skip to content

neighLDA

neighLDA

neighLDA(
    data,
    xCoordinate="X_centroid",
    yCoordinate="Y_centroid",
    zCoordinate=None,
    phenotype="phenotype",
    neighbor_method="radius",
    radius=30,
    knn=10,
    imageId="imageid",
    numMotifs=10,
    randomState=0,
    subset=None,
    inferenceMode="phenotype_driven",
    layer=None,
    subsetMarker=None,
    streamData=False,
    verbose=True,
    label="neighLDA",
    outputDir=None,
    sdataTable=None,
    **kwargs
)

Latent Dirichlet Allocation motifs over neighbourhood composition.

Each cell's neighbourhood becomes a bag of cell-type "words"; LDA then finds numMotifs latent topics over those documents. Every cell gets a probability distribution over motifs instead of a single label, so tissue regions that are genuinely mixtures come out as mixtures.

uns[label] holds the per-cell motif weights and uns[label + "_probability"] the full probability matrix. Cluster the weights with cluster(mode="spatial") if you do want discrete neighbourhoods in the end.

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
xCoordinate str

Column in obs holding x positions.

'X_centroid'
yCoordinate str

Column in obs holding y positions.

'Y_centroid'
zCoordinate str

Column in obs holding z positions. Leave as None for 2D data; set it and the neighbourhood search becomes three-dimensional.

None
phenotype str

Column in obs holding the cell type labels.

'phenotype'
neighbor_method str

'radius' or 'knn'. Named with an underscore here, unlike the method parameter of the sibling functions.

'radius'
radius float

Neighbourhood radius for neighbor_method='radius'.

30
knn int

Neighbour count for neighbor_method='knn'.

10
imageId str

Column in obs holding image identifiers. Neighbourhoods never cross images.

'imageid'
numMotifs int

Number of latent motifs to fit. This is the main thing to tune: too few and distinct neighbourhoods merge, too many and they fragment.

10
randomState int

Seed for LDA. Fix it for reproducible motifs.

0
subset str

Process only this image.

None
inferenceMode str

'phenotype_driven' builds the neighbourhood matrix from phenotype labels; 'marker_driven' builds it from marker expression, reading the matrix selected by layer and binarising it if needed.

'phenotype_driven'
layer str

Which matrix to read for inferenceMode='marker_driven'. None uses .X.

None
subsetMarker list

Restrict 'marker_driven' counting to these markers.

None
label str

Key in uns the motif weights are written to. label + "_probability" holds the probability matrix.

'neighLDA'
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
**kwargs dict

Forwarded to sklearn.decomposition.LatentDirichletAllocation.

{}

Returns:

Name Type Description
adata AnnData | SpatialData | None

The updated object with uns[label] and uns[label + "_probability"]. None in streaming mode.

Example
adata = sp.tl.neighLDA(
    adata, phenotype="phenotype", neighbor_method="radius", radius=50,
    numMotifs=10, label="ldaRadius50",
)
adata.uns["ldaRadius50"].head()

# Turn the soft motifs into discrete neighbourhoods.
adata = sp.tl.cluster(
    adata, mode="spatial", layer="ldaRadius50", method="kmeans", k=6,
    label="rcn",
)