liana (LIANA+)
import liana as li. Submodules: li.mt methods, li.pp preprocessing (spatial graphs,
transforms), li.rs prior knowledge, li.pl plots, li.ms multi-sample helpers, li.ds datasets.
Every method accepts an AnnData or a MuData. Snippets also assume import scanpy as sc, mudata as mu, decoupler as dc, numpy as np, pandas as pd.
Workflow
- Intake. Ask for the object or a path to it, and say explicitly that a description of the
data is fine instead if it cannot be shared (patient data, privacy). Raw vendor output is not an
object yet: a Space Ranger
outs/ folder loads with sc.read_visium, a 10x .h5 with
sc.read_10x_h5, Xenium, CosMx or MERSCOPE exports with spatialdata_io. If a path is given,
run the snippet below and infer what you can; then ask only what the object cannot tell you,
usually the aim and, when several columns qualify, which one holds the condition or cell type.
Without an object, ask in plain words and only what the message left open: tissue and
technology; one or several samples and how they group; whether cell types are annotated;
species; any modality beyond RNA (protein, measured metabolites); and what they want to learn.
Ask about coordinate units only for spatial data, and whether counts were normalised and
log-transformed (e.g. scanpy normalize_total + log1p) only if the snippet could not run.
- Select the branch from the table.
- Read that one reference file. Also read
prior-knowledge.md for non-human data or a custom
LR list, and outputs-and-plotting.md before plotting or interpreting liana_res.
- Run, then explain in one paragraph without column names: what was scored, which method and
why, what a high score means, and the main caveat. Name any bandwidth or threshold you chose.
import anndata as ad, mudata as mu, numpy as np
a = mu.read(path) if path.endswith(".h5mu") else ad.read_h5ad(path)
print(type(a).__name__, a.shape, "mods:", list(getattr(a, "mod", {})))
for c in a.obs.columns:
if a.obs[c].dtype.kind not in "biuf":
u = a.obs[c].unique()
print(c, len(u), list(u[:6]))
print("obsm:", list(a.obsm), "obsp:", list(a.obsp), "uns:", list(a.uns))
d = lambda M: M.toarray() if hasattr(M, "toarray") else np.asarray(M)
for name, m in (a.mod.items() if hasattr(a, "mod") else [("", a)]): # a MuData has no .X or .layers
X = d(m.X[:200])
print(name, "layers:", list(m.layers), "X min/max:", X.min(), X.max(),
"integer-like:", np.allclose(X, X.round()), "var sample:", list(m.var_names[:5]))
if m.raw is not None:
R = d(m.raw.X[:200])
print(name, "raw min/max:", R.min(), R.max(), "(negative = scaled, do not use)")
if "spatial" in a.obsm:
print(
"coords min/max:",
a.obsm["spatial"].min(0),
a.obsm["spatial"].max(0),
"uns spatial:",
list(a.uns.get("spatial", {})),
)
Selection
| Data and aim |
Read |
| Dissociated single cells, one dataset: rank LR interactions between cell types |
single-cell-lr.md |
| Dissociated single cells, several samples or conditions: what changes between them |
multisample.md |
| Spatial spots (Visium) or cells: where do ligand and receptor co-vary in space, local and global scores |
spatial-bivariate.md |
| Spatial single cells with cell-type labels (Xenium, MERFISH, CosMx): which types signal to which via which LRs |
inflow.md |
| Spatial single cells: at what distance do interactions occur, spatial scale of cell-type pairs |
lric.md |
| Spatial, unsupervised: what in a spot's neighbourhood predicts its expression, multi-view learning |
misty.md |
| Metabolite-mediated CCC, estimated from RNA or measured (MSI) |
metabolites.md |
| Resources, organism translation, custom LR lists, gene sets from LRs |
prior-knowledge.md |
Reading liana_res, score semantics, plotting |
outputs-and-plotting.md |
The table is a starting point, not a rule: methods are modular and combine. Multi-modal input is
not a branch. Every method takes a MuData; each file ends with a Variants section saying how, and
offer those variants only when the data calls for them.
Widen the question. Every branch also covers non-protein mediators. Any RNA dataset, dissociated or
spatial, can be scored for metabolite-mediated CCC by estimating metabolite abundance from enzyme and
transporter expression (MetalinksDB), and a second modality (protein, measured metabolites) can
supply the ligands or the receptors. Offer this whenever the user wants the complete picture, names
metabolites, neurotransmitters, hormones or lipids, or has such a modality: read metabolites.md.
Facts that apply everywhere
- Input: (typically) non-negative, library-size normalised, log1p expression in
.X (or layer=).
use_raw defaults to False. The single-cell methods reject negative input with ValueError: mat contains negative values, so scaled or z-scored values cannot be passed to them at all. They
also check for raw counts: all-integral values, or a maximum above 50, warn that the matrix does
not look log1p-normalised, and, wherever a log-fold-change is computed (li.mt.logfc, and so
rank_aggregate), a maximum above ~709 -- where inverting the log overflows -- raises
ValueError: mat contains values too large to have been log-transformed.
Spatial methods with x_transform/y_transform (bivariate, MISTy) also accept scaled input.
- "Please check if appropriate organism/ID type was provided!" means the resource and
var_names do not overlap. Tell the user both causes: var_names that are not gene symbols
(Ensembl IDs, the wrong matrix), and non-human data with the human consensus resource. For
mouse use resource_name="mouseconsensus"; for a fuller map or any other organism translate
the resource with HCOP orthologs (li.rs.get_hcop_orthologs, read prior-knowledge.md).
- Complexes: subunits joined by
_. ligand_complex / receptor_complex hold the full name.
ligand / receptor hold the least-expressed subunit; both they and *_means / *_props are
in a single method's result and in rank_aggregate's.
- Where results land: single-cell methods write
adata.uns["liana_res"] in place;
bivariate and inflow return a new AnnData; lric, cross_pcf and MISTy write .uns keys.
- Two thresholds, both 0.05 by default and worth tuning:
expr_prop (single-cell methods, and
lric's cell-type-directed mode) is the fraction of cells within a cell-type group expressing a
gene; nz_prop (spatial methods only) is the fraction of all cells or spots with a non-zero value.
- Plot with
li.pl.* (plotnine, returns a ggplot). Do not rebuild these plots from matplotlib primitives.
- Extras: MOFA, Tensor-cell2cell, pseudobulk DE, causal networks and MetalinksDB need
pip install 'liana[extras]'. Before writing code for such a route, import the package it needs
(pydeseq2, decoupler, muon, cell2cell, corneto) and, on ImportError, give the user that
command first. Downloads (li.ds.kang_2018, HCOP tables, MetalinksDB) are cached under
scanpy.settings.datasetdir (default ./data); set sc.settings.datasetdir to redirect them.
Citing
Always cite LIANA+ (Dimitrov et al., Nat Cell Biol 2024, doi:10.1038/s41556-024-01469-w) plus the
original paper of the method and resource used: li.mt.<method>.reference holds each single-cell
method's citation, and li.rs.show_resources() names the resource databases. For the consensus resource
and rank aggregate also cite Dimitrov et al., Nat Commun 2022 (doi:10.1038/s41467-022-30755-0). Inflow and
LRIC are unpublished (Alsayah et al., in preparation): cite LIANA+ for them meanwhile.
1---2name: liana3description: Cell-cell communication (CCC) inference with the liana Python package (LIANA+, scverse). Use for any task involving liana or ligand-receptor (LR) analysis of AnnData/MuData objects. Triggers on steady-state LR scoring (rank_aggregate, CellPhoneDB, CellChat, NATMI, Connectome, SingleCellSignalR, logFC, scSeqComm); multi-sample or differential CCC (by_sample, MOFA+, Tensor-cell2cell, df_to_lr, pyCrossTalkeR); spatial CCC on Visium, Xenium, MERFISH, CosMx or slide-seq (spatial_neighbors, bivariate local/global metrics, Moran's R, Inflow, LRIC, cross-PCF, MISTy); multimodal CITE-seq or spatial metabolomics; metabolite-mediated CCC via MetalinksDB; LR resources and orthology for mouse or other organisms (consensus, mouseconsensus, OmniPath, HCOP); liana plots (dotplot, tileplot, circle). Also use when the user says cell-cell interactions, crosstalk, signalling between cell types, sender and receiver, or niche signalling, even without naming liana.4---56# liana (LIANA+)78`import liana as li`. Submodules: `li.mt` methods, `li.pp` preprocessing (spatial graphs,9transforms), `li.rs` prior knowledge, `li.pl` plots, `li.ms` multi-sample helpers, `li.ds` datasets.10Every method accepts an `AnnData` or a `MuData`. Snippets also assume `import scanpy as sc, mudata as mu,11decoupler as dc, numpy as np, pandas as pd`.1213## Workflow14151. **Intake.** Ask for the object or a path to it, and say explicitly that a description of the16 data is fine instead if it cannot be shared (patient data, privacy). Raw vendor output is not an17 object yet: a Space Ranger `outs/` folder loads with `sc.read_visium`, a 10x `.h5` with18 `sc.read_10x_h5`, Xenium, CosMx or MERSCOPE exports with `spatialdata_io`. If a path is given,19 run the snippet below and infer what you can; then ask only what the object cannot tell you,20 usually the aim and, when several columns qualify, which one holds the condition or cell type.21 Without an object, ask in plain words and only what the message left open: tissue and22 technology; one or several samples and how they group; whether cell types are annotated;23 species; any modality beyond RNA (protein, measured metabolites); and what they want to learn.24 Ask about coordinate units only for spatial data, and whether counts were normalised and25 log-transformed (e.g. scanpy `normalize_total` + `log1p`) only if the snippet could not run.262. **Select** the branch from the table.273. **Read** that one reference file. Also read `prior-knowledge.md` for non-human data or a custom28 LR list, and `outputs-and-plotting.md` before plotting or interpreting `liana_res`.294. **Run**, then explain in one paragraph without column names: what was scored, which method and30 why, what a high score means, and the main caveat. Name any bandwidth or threshold you chose.3132```python33import anndata as ad, mudata as mu, numpy as np3435a = mu.read(path) if path.endswith(".h5mu") else ad.read_h5ad(path)36print(type(a).__name__, a.shape, "mods:", list(getattr(a, "mod", {})))37for c in a.obs.columns:38 if a.obs[c].dtype.kind not in "biuf":39 u = a.obs[c].unique()40 print(c, len(u), list(u[:6]))41print("obsm:", list(a.obsm), "obsp:", list(a.obsp), "uns:", list(a.uns))42d = lambda M: M.toarray() if hasattr(M, "toarray") else np.asarray(M)43for name, m in (a.mod.items() if hasattr(a, "mod") else [("", a)]): # a MuData has no .X or .layers44 X = d(m.X[:200])45 print(name, "layers:", list(m.layers), "X min/max:", X.min(), X.max(),46 "integer-like:", np.allclose(X, X.round()), "var sample:", list(m.var_names[:5]))47 if m.raw is not None:48 R = d(m.raw.X[:200])49 print(name, "raw min/max:", R.min(), R.max(), "(negative = scaled, do not use)")50if "spatial" in a.obsm:51 print(52 "coords min/max:",53 a.obsm["spatial"].min(0),54 a.obsm["spatial"].max(0),55 "uns spatial:",56 list(a.uns.get("spatial", {})),57 )58```5960## Selection6162| Data and aim | Read |63|---|---|64| Dissociated single cells, one dataset: rank LR interactions between cell types | [single-cell-lr.md](references/single-cell-lr.md) |65| Dissociated single cells, several samples or conditions: what changes between them | [multisample.md](references/multisample.md) |66| Spatial spots (Visium) or cells: where do ligand and receptor co-vary in space, local and global scores | [spatial-bivariate.md](references/spatial-bivariate.md) |67| Spatial single cells with cell-type labels (Xenium, MERFISH, CosMx): which types signal to which via which LRs | [inflow.md](references/inflow.md) |68| Spatial single cells: at what distance do interactions occur, spatial scale of cell-type pairs | [lric.md](references/lric.md) |69| Spatial, unsupervised: what in a spot's neighbourhood predicts its expression, multi-view learning | [misty.md](references/misty.md) |70| Metabolite-mediated CCC, estimated from RNA or measured (MSI) | [metabolites.md](references/metabolites.md) |71| Resources, organism translation, custom LR lists, gene sets from LRs | [prior-knowledge.md](references/prior-knowledge.md) |72| Reading `liana_res`, score semantics, plotting | [outputs-and-plotting.md](references/outputs-and-plotting.md) |7374The table is a starting point, not a rule: methods are modular and combine. Multi-modal input is75not a branch. Every method takes a `MuData`; each file ends with a Variants section saying how, and76offer those variants only when the data calls for them.7778**Widen the question.** Every branch also covers non-protein mediators. Any RNA dataset, dissociated or79spatial, can be scored for metabolite-mediated CCC by estimating metabolite abundance from enzyme and80transporter expression (MetalinksDB), and a second modality (protein, measured metabolites) can81supply the ligands or the receptors. Offer this whenever the user wants the complete picture, names82metabolites, neurotransmitters, hormones or lipids, or has such a modality: read `metabolites.md`.8384## Facts that apply everywhere8586- **Input**: (typically) non-negative, library-size normalised, log1p expression in `.X` (or `layer=`).87 `use_raw` defaults to `False`. The single-cell methods reject negative input with `ValueError: mat88 contains negative values`, so scaled or z-scored values cannot be passed to them at all. They89 also check for raw counts: all-integral values, or a maximum above 50, warn that the matrix does90 not look log1p-normalised, and, wherever a log-fold-change is computed (`li.mt.logfc`, and so91 `rank_aggregate`), a maximum above ~709 -- where inverting the log overflows -- raises92 `ValueError: mat contains values too large to have been log-transformed`.93 Spatial methods with `x_transform`/`y_transform` (bivariate, MISTy) also accept scaled input.94- **"Please check if appropriate organism/ID type was provided!"** means the resource and95 `var_names` do not overlap. Tell the user both causes: `var_names` that are not gene symbols96 (Ensembl IDs, the wrong matrix), and non-human data with the human `consensus` resource. For97 mouse use `resource_name="mouseconsensus"`; for a fuller map or any other organism translate98 the resource with HCOP orthologs (`li.rs.get_hcop_orthologs`, read `prior-knowledge.md`).99- **Complexes**: subunits joined by `_`. `ligand_complex` / `receptor_complex` hold the full name.100 `ligand` / `receptor` hold the least-expressed subunit; both they and `*_means` / `*_props` are101 in a single method's result and in `rank_aggregate`'s.102- **Where results land**: single-cell methods write `adata.uns["liana_res"]` in place;103 `bivariate` and `inflow` return a **new** AnnData; `lric`, `cross_pcf` and MISTy write `.uns` keys.104- **Two thresholds**, both 0.05 by default and worth tuning: `expr_prop` (single-cell methods, and105 `lric`'s cell-type-directed mode) is the fraction of cells within a cell-type group expressing a106 gene; `nz_prop` (spatial methods only) is the fraction of all cells or spots with a non-zero value.107- Plot with `li.pl.*` (plotnine, returns a `ggplot`). Do not rebuild these plots from matplotlib primitives.108- Extras: MOFA, Tensor-cell2cell, pseudobulk DE, causal networks and MetalinksDB need109 `pip install 'liana[extras]'`. Before writing code for such a route, import the package it needs110 (`pydeseq2`, `decoupler`, `muon`, `cell2cell`, `corneto`) and, on ImportError, give the user that111 command first. Downloads (`li.ds.kang_2018`, HCOP tables, MetalinksDB) are cached under112 `scanpy.settings.datasetdir` (default `./data`); set `sc.settings.datasetdir` to redirect them.113114## Citing115116Always cite LIANA+ (Dimitrov et al., Nat Cell Biol 2024, doi:10.1038/s41556-024-01469-w) plus the117original paper of the method and resource used: `li.mt.<method>.reference` holds each single-cell118method's citation, and `li.rs.show_resources()` names the resource databases. For the consensus resource119and rank aggregate also cite Dimitrov et al., Nat Commun 2022 (doi:10.1038/s41467-022-30755-0). Inflow and120LRIC are unpublished (Alsayah et al., in preparation): cite LIANA+ for them meanwhile.