grassp.tl.competitive_diffusion

grassp.tl.competitive_diffusion#

competitive_diffusion(data, gt_col=None, fix_markers=False, renormalize_class_mass=True, min_probability=None, plot_optimization=True, inplace=True, obsp_key='connectivities', key_added='competitive_diffusion', iterative=False, max_iter=1000, rtol=0.0001, verbose=False, method='propagation', alpha=0.8, seed_obsm_key=None, seed_categories_uns_key=None, unknown_label='unknown')[source]#

Propagate categorical annotations along the k-NN graph.

For each observation the function inspects its neighbourhood in adata.obsp[obsp_key] (generated by scanpy.pp.neighbors()) and calculates the a weighted probability for each label category.

Parameters:
data AnnData

anndata.AnnData with a populated neighbour graph (distances or connectivities).

gt_col str | None (default: None)

Observation column containing the source annotations to be propagated.

fix_markers bool (default: False)

If True marker probabilities do not get overwritten by the propagated labels. Effectively required when iterative=True: without it nothing anchors the recursion and the class probabilities collapse (see iterative). Ignored, with a warning, when seeding from seed_obsm_key (a soft seed has no one-hot marker rows to clamp).

renormalize_class_mass bool (default: True)

If True (default) each compartment’s propagated mass is rescaled back to the mass it had in the seed, undoing the redistribution diffusion causes. This is not inverse-frequency weighting: a large compartment is not penalised for its size, it is returned to the share it started with. Named for what it does – tl.class_balance is an unrelated function that subsamples classes to equal size, and the two used to share a name.

min_probability float | None (default: None)

Confidence cutoff: if the probability of the most probable label is below this threshold, the label is set to np.nan. None (the default) applies no cutoff, i.e. it is equivalent to 0.0, so every protein keeps its most probable label and the full probability matrix in .obsm carries the confidence. Automatic, F1-optimal selection of the cutoff is not currently implemented.

plot_optimization bool (default: True)

Unused; accepted for backwards compatibility and ignored. It belonged to the automatic threshold selection described above.

obsp_key default: 'connectivities'

Name of the neighbour connectivity graph to use (default "connectivities"). If obsp_key="distances" is passed, a Gaussian RBF affinity W = exp(-d² / (2σ²)) is built on the kNN distance graph (with σ the median nonzero distance) and used as the spreading/propagation operator. The resulting matrix is cached at adata.obsp["W_spreading"] for inspection. This typically gives a narrower effective kernel than UMAP’s fuzzy-union connectivities, which is useful when you want boundary-localized uncertainty with method="spreading".

key_added str (default: 'competitive_diffusion')

Name of the new column that will hold the propagated annotation (default "competitive_diffusion").

iterative bool (default: False)

If True perform multi-step label propagation (in the style of sklearn.semi_supervised.LabelPropagation). At every step the label distribution is propagated along T and row-normalized; if fix_markers=True the labeled rows are then reset to their initial one-hot encoding. Iteration stops when the relative L1 change falls below rtol or when max_iter is reached. If False (default) only a single propagation step is performed. Ignored when method="spreading" (spreading is always iterative, and its soft clamp plays the role of fix_markers).

Pair this with fix_markers=True. Without the clamp the iteration has a degenerate fixed point — every class column converges to the graph’s stationary distribution and the probabilities collapse — and a warning is emitted.

max_iter int (default: 1000)

Maximum number of propagation iterations when iterative=True or method="spreading" (default 1000). A warning is emitted if it is reached before rtol is satisfied.

rtol float (default: 0.0001)

Relative convergence tolerance (default 1e-4). The L1 change between consecutive iterations is compared against rtol times a reference magnitude, so the same number means the same thing on maps of any size and with any number of compartments – unlike an absolute L1 sum, which tightens as either grows.

verbose bool (default: False)

If True print progress to the console.

method Literal['propagation', 'spreading'] (default: 'propagation')

Either "propagation" (default, Zhu & Ghahramani, 2002) or "spreading" (Zhou et al., 2003). Spreading uses the symmetric normalized operator S = D^{-1/2} W D^{-1/2} and a soft clamp controlled by alpha, which makes it more robust to noisy seeds.

alpha float (default: 0.8)

Soft-clamping parameter for label spreading, in [0, 1). The update rule is F(t+1) = alpha * S @ F(t) + (1 - alpha) * Y_0: small alpha keeps predictions close to the initial seeds, alpha close to 1 lets labeled rows drift. Ignored when method="propagation". Default 0.8. The update rule is the same one sklearn.semi_supervised.LabelSpreading uses, but note that its default is alpha=0.2: grassp therefore weights the neighbourhood four times as heavily out of the box.

seed_obsm_key str | None (default: None)

If given, seed the propagation with a soft per-observation label distribution stored in data.obsm[seed_obsm_key] (shape (n_obs, n_categories)) instead of a one-hot encoding of gt_col. Use this to propagate enrichment uncertainty produced by enrichment_to_cluster_distribution() / soft_cluster_annotation(). gt_col becomes optional when this is set, and fix_markers is disabled (its one-hot marker test does not apply to soft seeds).

seed_categories_uns_key str | None (default: None)

Name of the data.uns entry holding the ordered list of category names matching the columns of the soft seed matrix. Optional when the seed is a DataFrame, whose own column names are used instead; required when it is a bare ndarray, as written by grassp before labelled obsm matrices were introduced.

unknown_label str | None (default: 'unknown')

Name of the background/unknown category in the soft seed. Observations whose most probable label is this category are reported as unassigned (NaN) in data.obs[key_added] while the full probability matrix (including the unknown column) is kept in obsm. Set to None to keep the unknown label as a regular category. Only used with soft seeds.

inplace bool

Returns:

Modified anndata object with the following new entries: - .obsm[f”{key_added}_probabilities”] containing the propagated probabilities - .obs[f”{key_added}”] containing the propagated labels (most probable label) - .uns[f”{key_added}_colors”] to make sure plotting uses the same colors as the ground truth labels - .obs[f”{key_added}_probability”] containing the probability of the most probable label