pycea.tl.ancestral_linkage#
- pycea.tl.ancestral_linkage(tdata, groupby, target=None, aggregate=None, metric='lca', symmetrize='mean', normalize=True, min_size=1, test=None, alternative='one-sided', permutation_mode='non_target', n_permutations=100, n_threads=None, by_tree=False, depth_key='depth', random_state=None, key_added=None, tree=None, copy=False)#
Quantify relatedness of cells in different categories.
For each cell, the tree distance to the nearest cell of each target category is computed. These per-cell distances are then averaged across all cells of the same source category to produce a directional linkage score: a low path distance (or high LCA depth) between two categories means they tend to share recent common ancestors, i.e. they are closely related on the tree.
Pairwise mode (
target=None): computes a category × category matrix of mean linkage scores and stores it intdata.uns['{key_added}_linkage'].Single-target mode (
target=<category>): computes the per-cell distance to the nearest cell of the given category and stores it intdata.obs['{target}_linkage'].- Parameters:
tdata (
TreeData) – The TreeData object.groupby (
str) – Column intdata.obsthat defines cell categories.target (
str|None(default:None)) – If specified, compute the per-cell distance to the nearest cell of this category and store the result intdata.obs['{target}_linkage'].aggregateis ignored in this mode. IfNone(default), compute the full pairwise category × category matrix.aggregate (
Literal['min','max','mean'] |Callable|None(default:None)) –How per-cell distances to the target category are aggregated into a single per-cell score (pairwise mode only). Defaults to
'min'formetric='path'and'max'formetric='lca', both of which select the nearest relative:'min': distance to the closest target cell (natural for'path').'max': depth of the deepest (most recent) LCA across target cells (natural for'lca').'mean': mean distance across all target cells.A callable
f(array) -> floatfor custom aggregation.
metric (
Literal['lca','path'] (default:'lca')) –How tree distance between two cells is measured:
'lca'(default): depth of the lowest common ancestor . Larger values mean closer relatives.'path': branch-length path distance . Smaller values mean closer relatives.
symmetrize (
Literal['mean','max','min',False] (default:'mean')) –How to symmetrize the pairwise linkage matrix (pairwise mode only). Because linkage is directional (source → target), the raw matrix is generally asymmetric; symmetrization combines both directions:
'mean'(default): average of and .'max'/'min': element-wise maximum / minimum.False: leave the matrix asymmetric.
normalize (
bool(default:True)) – IfTrue(default), subtract the permuted mean from the observed values: pairwise linkage matrix becomesobserved - permuted_mean; single-targettdata.obs['{target}_linkage']becomescell_score - category_permuted_mean. This works regardless oftest: a single permutation is run to estimate the permuted mean whentest=None(seen_permutations).min_size (
int(default:1)) – Minimum number of cells a category must have to be included (pairwise mode only). Categories with fewer thanmin_sizecells are dropped before the linkage matrix is computed, so they appear as neither source rows nor target columns and their cells do not contribute to any score. Defaults to1(no filtering). A warning lists any retained categories with fewer than 10 cells, whose linkage will be noisy.test (
Literal['permutation',None] (default:None)) –Optional significance test:
'permutation': randomly shuffle cell-category labelsn_permutationstimes and recompute linkage each time to build a null distribution. Z-scores and p-values are added to the stats table.
alternative (
Literal['two-sided','one-sided'] (default:'one-sided')) –The alternative hypothesis for the permutation test (ignored when
test=None):'one-sided'(default): one-tailed test in the “more closely related than chance” direction — p-value is the fraction of permutations with LCA depth ≥ observed (metric='lca') or path distance ≤ observed (metric='path').'two-sided': two-tailed test — p-value is the fraction of permutations whose deviation from the null mean is at least as large as the observed deviation.
permutation_mode (
Literal['all','non_target'] (default:'non_target')) –How category labels are shuffled to build the permutation null (used both for the significance test and for the
normalizepermuted mean):'non_target'(default): fix the target category’s leaves at their tree positions and shuffle only the non-target labels. The null therefore reflects “random cells near this specific target cluster,” which removes inflation caused by small, tightly clustered target categories. In pairwise mode each target column gets its own independent null distribution.'all': shuffle all cell-category labels across all leaves. Tests whether the two categories are more associated on the tree than random, but does not control for the target category’s cluster structure.
n_permutations (
int(default:100)) – Number of label permutations used whentest='permutation'. Whentest=Nonea single permutation is used to estimate the permuted mean fornormalize.n_threads (
int|None(default:None)) – Number of worker processes for parallel permutation computation.None(default) runs serially. On Linux, parallel execution usesfork-based processes, which copy the parent’s memory without serialisation overhead. On other platforms this argument is ignored.depth_key (
str(default:'depth')) – Node attribute intdata.obst[tree]that stores each node’s depth.random_state (
int|None(default:None)) – Random seed for reproducibility of permutation tests.key_added (
str|None(default:None)) – Base key for output storage. Defaults togroupby.tree (
str|Sequence[str] |None(default:None)) – Theobstkey or keys of the trees to use. IfNone, all trees are used.copy (
Literal[True,False] (default:False)) – IfTrue, return the result as aDataFrame.
- Return type:
- Returns:
Returns
Noneifcopy=False, otherwise returns aDataFrame.Sets the following fields:
tdata.obs['{target}_linkage']Series(dtypefloat) – single-target mode only.Per-cell distance to the nearest cell of the target category. When
normalize=True, replaced bycell_score - category_permuted_mean.
tdata.uns['{key_added}_linkage']DataFrame– pairwise mode only.Category × category linkage matrix (source rows, target columns). When
normalize=True, containsobserved - permuted_meaninstead of raw distances.
tdata.uns['{key_added}_linkage_params']dict– pairwise mode only.Parameters used to compute the linkage matrix.
tdata.uns['{key_added}_linkage_stats']DataFrame– pairwise mode only.Long-form table with one row per (source, target) pair containing
value,source_n,target_n, andpermuted_value(always, from at least one permutation), plusz_scoreandp_valuewhentest='permutation'.
tdata.uns['{key_added}_symmetrized_linkage_stats']DataFrame– pairwise mode, only when
symmetrizeis notFalseandtest='permutation'. Long-form table with one row per unordered {source, target} pair (upper triangle, including the diagonal) containing the symmetrizedvalue,source_n,target_n,permuted_value,z_score, andp_value. The p-value tests the symmetrized linkage value against a null built by symmetrizing each permutation.
Examples
Compute pairwise linkage between all cell types using path distance:
>>> tdata = py.datasets.koblan25() >>> py.tl.ancestral_linkage(tdata, groupby="celltype")
Compute per-cell distance to the closest cell of type “B” with permutation test:
>>> py.tl.ancestral_linkage(tdata, groupby="celltype", target="B", test="permutation")