grassp.tl.resolve_soft_labels

grassp.tl.resolve_soft_labels#

resolve_soft_labels(data, prob_key, categories_key, seed_key=None, obsp_key='connectivities', unknown_label='unknown', unknown_gate=0.5, null='permutation', n_permutations=1000, alpha_fdr=0.05, class_balance=True, multi_label_cum=0.8, single_eff_k=1.5, eff_k_max=3.0, max_labels=3, min_secondary_mass=0.2, canonical_order=False, key_added=None, random_state=0, set_colors=True, inplace=True)[source]#

Resolve soft propagated probabilities into single / multi / unresolved labels.

A single min_probability cutoff on the top propagated probability cannot tell apart two opposite cases: a protein in an unresolved region (mass smeared over many compartments) and a genuine intermediate (mass concentrated on 2-3 clean compartments). Both have a low top probability, but the shape of the distribution differs. This function decides using the entropy of the propagated distribution, compared to a per-protein null.

For each protein it computes the Shannon entropy H of the propagated distribution over real compartments (unknown excluded and handled by a separate gate); the effective number of compartments is exp(H). It then tests H against a null in which the protein carries no local structure:

  • null="permutation" (default): randomly permute which seed vector sits on which protein, keep the graph fixed, re-propagate with the same math, recompute H. Repeated n_permutations times this gives a per-protein null entropy distribution (preserving graph geometry, each protein’s effective neighbourhood size, the class-balance normalization and the global class prior). A left-tail p-value is BH-FDR adjusted.

  • null="analytic": a fast approximation using the population mean seed and each protein’s effective neighbour count n_eff (E[H|H0] H(π̄) - (k-1)/(2 n_eff) with a delta-method variance), avoiding permutations.

  • null=None: no test; a protein is resolved iff exp(H) <= eff_k_max.

Decision per protein: unknown_mass >= unknown_gate -> unresolved; else a significantly-low entropy (q < alpha_fdr) -> single (exp(H) < single_eff_k) or multi; otherwise unresolved. For resolved proteins the emitted compartment set is the smallest reaching cumulative mass multi_label_cum.

Parameters:
data AnnData

AnnData carrying the propagated probabilities in data.obsm[prob_key] and the matching category order in data.uns[categories_key].

prob_key str

obsm key with the (n_obs, n_categories) propagated probability matrix (e.g. "ann_soft_probabilities").

categories_key str

uns key with the ordered category names for the columns of prob_key.

seed_key str | None (default: None)

obsm key with the soft seed matrix; required when null="permutation".

obsp_key str (default: 'connectivities')

Affinity graph used for (re-)propagation (default "connectivities").

unknown_label str | None (default: 'unknown')

Name of the background/unknown category in the vocabulary, or None if there is no such class. Used both to exclude it from the entropy and as a gate.

unknown_gate float (default: 0.5)

Proteins with unknown mass at or above this are called unresolved outright.

null Optional[Literal['permutation', 'analytic']] (default: 'permutation')

Null model, number of permutations, and FDR level (see above).

n_permutations int (default: 1000)

Null model, number of permutations, and FDR level (see above).

alpha_fdr float (default: 0.05)

Null model, number of permutations, and FDR level (see above).

class_balance bool (default: True)

Must match the setting used to produce prob_key so the null re-propagation is faithful.

multi_label_cum float (default: 0.8)

Cumulative probability mass used to select how many compartments to emit for the detailed multiloc_label.

single_eff_k float (default: 1.5)

exp(H) below this is labelled single, otherwise multi.

eff_k_max float (default: 3.0)

Only used when null=None: resolved iff exp(H) <= eff_k_max.

max_labels int (default: 3)

Hard cap on the number of compartments in the compact label_compact.

min_secondary_mass float (default: 0.2)

A secondary compartment is only added to label_compact if it holds at least this probability mass. This is what suppresses gene-set-overlap tails (e.g. a 0.16 Lipid-droplet share on ER proteins) and keeps the number of distinct compact labels small.

canonical_order bool (default: False)

If True, sort the compartments in label_compact alphabetically so that "A / B" and "B / A" collapse into one plot category (drops primary ordering). Default False keeps the primary compartment first.

key_added str | None (default: None)

Output prefix in .obs. Defaults to f"{prob_key}_resolved".

random_state int (default: 0)

Seed for the permutation null.

set_colors bool (default: True)

If True (default), assign consistent compartment colours to the emitted label columns via set_sensible_compartment_colors(), so the same compartment renders identically here and in other annotation columns. Ignored when inplace=False.

inplace bool (default: True)

If True (default) write results to data; otherwise return a dict.

Returns:

None or dict Writes obs[key] (primary label / NaN), obs[key+"_multiloc"] (bool), obs[key+"_multiloc_label"] (detailed "A / B" string from the cumulative-mass rule), obs[key+"_label_compact"] (plot-friendly label: primary + secondaries above min_secondary_mass, capped at max_labels) and obs[key+"_multiloc_compact"] (bool), obs[key+"_secondary"], obs[key+"_type"] and diagnostics _entropy, _eff_k, _zscore, _qvalue, _unknown_mass; a null summary in uns[key+"_null"].