OmicVerse Single-Cell — LIANA+ Cell-Cell Communication
Goal
Take a preprocessed annotated single-cell AnnData and run LIANA+ ligand-receptor inference, producing per-(sender, receiver, ligand, receptor) score columns in adata.uns['liana_res']. Then post-process via ov.single.to_comm_adata(...) into a communication AnnData keyed on the sender→receiver direction, classified against the CellChat / CellChatDB pathway taxonomy. Visualise with ov.pl.ccc_heatmap(...) — eight plot_type modes covering dot / tile / aggregation heatmap / pathway-bubble / role-heatmap / role-network / focused-heatmap.
This skill is the LIANA-side complement to the existing single-cell-cellphonedb-communication skill. They produce comparable hit sets but LIANA aggregates across multiple base methods (CellPhoneDB, NATMI, Connectome, SingleCellSignalR, CellChat) into a rank_aggregate consensus — typically more robust than any single method.
Quick Workflow
- Load a preprocessed annotated
AnnData (obs[group_key] populated; for the PBMC8k demo, bulk_labels).
- Optional: visualise the cohort embedding to confirm cluster labels look right (
ov.pl.embedding(adata, basis='X_umap', color='bulk_labels', frameon='small')).
- Run LIANA:
ov.single.run_liana(adata, groupby='bulk_labels', method='rank_aggregate', resource_name='consensus', key_added='liana_res', inplace=True). Result lands at adata.uns['liana_res'].
- Pathway-aware reshape:
comm_adata = ov.single.to_comm_adata(adata, result_uns_key='liana_res', score_key='specificity_rank', pvalue_key='specificity_rank', classification_reference='cellchat', classification_fallback='family'). Returns a CommAnnData with one var per (ligand, receptor) and a var['classification'] column mapping each pair to a CellChat pathway.
- Pathway dot plots:
ov.pl.ccc_heatmap(adata, plot_type='dot', display_by='interaction', score_key='specificity_rank', ...). Multiple plot_type modes share a uniform interface — see Branch Selection below.
- Aggregation heatmap:
plot_type='heatmap', display_by='aggregation' shows sender→receiver totals.
- Sender / receiver focus: pass
sender_use=<cluster> or receiver_use=<cluster> to filter to a single direction.
- Pathway-focused / role-network views:
plot_type='focused_heatmap', 'pathway_bubble', 'role_heatmap', 'role_network' — pick by question (see Branch Selection).
- Multi-condition comparison: stack LIANA results from multiple conditions, set
condition column on the result frames, and re-run plotters with the multi-condition adata.
Interface Summary
ov.single.run_liana(
adata, *,
groupby: str, # required — the cell-type column
method: str = 'rank_aggregate', # or 'cellphonedb', 'natmi', 'connectome', 'sca'
resource_name: str = 'consensus', # ligand-receptor DB; 'consensus', 'cellphonedb', 'cellchat', etc.
key_added: str = 'liana_res',
inplace: bool = True,
**kwargs # forwarded to liana.mt.<method>
)
# adata.uns[key_added] -> pd.DataFrame with one row per (sender, receiver, ligand_complex, receptor_complex)
# columns include: 'specificity_rank', 'magnitude_rank', 'lr_means', 'cellphone_pvals', etc.
ov.single.to_comm_adata(
adata: AnnData | None = None, *,
data: pd.DataFrame | None = None,
result_uns_key: str | None = None,
score_key: str = 'specificity_rank',
pvalue_key: str = 'specificity_rank',
inverse_score: bool = True, # smaller rank = better → invert for visualisation
inverse_pvalue: bool = False,
classification: str | Mapping[str, str] | None = None,
classification_reference: str | pd.DataFrame | None = 'cellchat',
classification_fallback: str | None = 'family',
separator: str = '|',
) -> AnnData
# Returns a "communication AnnData":
# .obs = (sender, receiver) directed pairs
# .var = (ligand, receptor) interactions; var['classification'] is the pathway label
# .X = score matrix (pairs × interactions)
# .layers = {'pvalue': ...}
ov.pl.ccc_heatmap(
adata_or_comm, *,
plot_type: str = 'dot', # see Branch Selection for full list
display_by: str = 'interaction', # 'interaction' or 'aggregation'
score_key: str = 'specificity_rank',
pvalue_key: str = 'specificity_rank',
classification_reference='cellchat',
classification_fallback='family',
sender_use: str | list | None = None,
receiver_use: str | list | None = None,
signaling: str | list | None = None, # focus on named pathways
pattern: str = 'incoming', # for role_heatmap / role_network: 'incoming' / 'outgoing'
pvalue_threshold: float = 0.05,
top_n: int = 10,
cmap: str = ...,
figsize: tuple = ...,
show: bool = False,
...,
) -> (fig, ax)
Boundary
Inside scope:
- LIANA fitting on a labeled
AnnData with run_liana.
- Reshaping to
CommAnnData with to_comm_adata (CellChat / CellPhoneDB / family classification).
- All eight
ov.pl.ccc_heatmap modes.
- Sender / receiver / pathway focusing.
- Multi-condition comparison via stacked result frames with a
condition column.
Outside scope — separate skill:
- CellPhoneDB-only inference +
CellChatViz workflow — see single-cell-cellphonedb-communication (existing skill).
- Spatial cell-cell communication with COMMOT / FlowSig — see
spatial-tutorials (existing skill).
- Building the upstream annotated AnnData — separate skill.
- Single-method LIANA (e.g. only NATMI) — supported by
method= kwarg but rare in practice; the consensus rank_aggregate is the canonical choice.
Branch Selection
method for run_liana
'rank_aggregate' (default) — consensus across CellPhoneDB / NATMI / Connectome / SingleCellSignalR / CellChat. The right default.
'cellphonedb' — single-method permutation-based; matches the CellPhoneDB v3 paper.
'natmi' — specificity edge-weighting; less conservative than CellPhoneDB.
'connectome' — scaled mean expression; gives both magnitude and specificity ranks.
'sca' (SingleCellSignalR) — LRscore-based; conservative.
resource_name
'consensus' (default) — union of CellChat + CellPhoneDB + Ramilowski + others.
'cellphonedb' — strict CellPhoneDB v4 only.
'cellchat' — strict CellChat only.
- For organism-specific runs, append
_human / _mouse to the resource name.
score_key and pvalue_key
'specificity_rank' — both score and pvalue (LIANA reuses the same column for the rank-aggregate output). For other methods, use the method-specific columns ('cellphone_pvals' for CellPhoneDB, 'lr_logfc' for NATMI, etc.).
'magnitude_rank' — alternate score that emphasises raw expression magnitude over specificity.
inverse_score=True (default in to_comm_adata): converts rank-style scores (lower=better) to score-style (higher=better) for visualisation.
plot_type for ccc_heatmap
'dot' — sender × receiver bubble plot, dot size = score, colour = pvalue. Default exploratory view.
'tile' — heat tile: rows = interactions, cols = sender→receiver pairs.
'heatmap' (with display_by='aggregation') — sender × receiver aggregated total CCC strength.
'focused_heatmap' — restrict to a named pathway (signaling=['ECM/Adhesion']).
'pathway_bubble' — pathway × sender→receiver bubble; needs signaling=[...].
'role_heatmap' — sender / receiver role intensity per cluster (pattern='incoming' | 'outgoing').
'role_network' — directed network plot of dominant signalling roles.
display_by
'interaction' — per (ligand, receptor) detail.
'aggregation' — summed across interactions per (sender, receiver). Use with plot_type='heatmap'.
sender_use / receiver_use
sender_use='CD34+' — show only signals originating from CD34+. Useful for "where does CD34+ talk to?"
receiver_use='CD34+' — show only signals received by CD34+. Useful for "what regulates CD34+?"
classification_reference
'cellchat' (default) — CellChat pathway taxonomy.
'family' (fallback) — chemokine / cytokine / TGF-β / etc. families.
- Pass a custom
pd.DataFrame keyed by ligand-receptor for arbitrary pathway labels.
Multi-condition comparison: build a stacked frame with a condition column, then call ov.pl.ccc_heatmap with that frame. Allows side-by-side baseline vs. stimulated visualisation.
Input Contract
AnnData with obs[group_key] populated (categorical or strings); typical group_keys: 'bulk_labels', 'cell_type', 'leiden'.
adata.X log-normalised expression. LIANA expects this scale; passing raw counts gives nonsensical specificity scores.
pip install liana (the omicverse install does not ship LIANA by default).
- For
to_comm_adata with classification_reference='cellchat': requires the CellChat ligand-receptor mapping shipped under omicverse.external.cellchat (always available in OmicVerse).
Minimal Execution Patterns
import omicverse as ov
import scanpy as sc
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
ov.plot_set(font_path='Arial')
# 1) Load a labeled AnnData
adata = sc.datasets.pbmc8k() # or your own
adata.obs['bulk_labels'] = ... # cluster labels
ov.pl.embedding(adata, basis='X_umap', color='bulk_labels', frameon='small')
# 2) Run LIANA
ov.single.run_liana(
adata,
groupby='bulk_labels',
method='rank_aggregate',
resource_name='consensus',
key_added='liana_res',
inplace=True,
)
print(adata.uns['liana_res'].head())
# 3) Reshape into a CommAnnData with CellChat pathway classification
comm_adata = ov.single.to_comm_adata(
adata,
result_uns_key='liana_res',
score_key='specificity_rank',
pvalue_key='specificity_rank',
classification_reference='cellchat',
classification_fallback='family',
)
print(comm_adata)
print(comm_adata.var['classification'].value_counts().head())
# 4) Dot plot — default exploratory view
fig, ax = ov.pl.ccc_heatmap(
adata,
plot_type='dot',
display_by='interaction',
score_key='specificity_rank',
pvalue_key='specificity_rank',
classification_reference='cellchat',
classification_fallback='family',
show=False,
)
# Sender / receiver focused dot plots
fig, ax = ov.pl.ccc_heatmap(
comm_adata, plot_type='dot', display_by='interaction',
score_key='specificity_rank', pvalue_key='specificity_rank',
sender_use='CD34+', top_n=6, pvalue_threshold=0.05,
show=False,
)
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='dot', display_by='interaction',
score_key='specificity_rank', pvalue_key='specificity_rank',
receiver_use='CD34+', top_n=5, pvalue_threshold=0.05,
show=False,
)
# Aggregation heatmap (sender × receiver totals)
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='heatmap', display_by='aggregation',
score_key='specificity_rank', pvalue_key='specificity_rank',
classification_reference='cellchat', classification_fallback='family',
cmap='YlGnBu', figsize=(4, 3), show=False,
)
# Focus on a specific pathway
focus = comm_adata.var['classification'].dropna().astype(str).unique().tolist()
focus = [v for v in focus if v not in {'Unclassified', 'nan'}]
focus_pathway = focus[0] if focus else 'Unclassified'
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='focused_heatmap',
signaling=[focus_pathway],
min_interaction_threshold=0.0,
cmap='YlGnBu', figsize=(4, 3), show=False,
)
# Pathway-bubble for a specific pathway
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='pathway_bubble',
signaling=['ECM/Adhesion'],
top_n=5, figsize=(3, 5), show=False,
)
# Role heatmap (incoming vs outgoing)
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='role_heatmap',
pattern='incoming', cmap='Greens',
figsize=(4, 3), show=False,
)
# Role network for a pathway
fig, ax = ov.pl.ccc_heatmap(
adata, plot_type='role_network',
signaling=['ECM/Adhesion'],
cmap='Greens', figsize=(8, 5), show=False,
)
Validation
- After
run_liana: adata.uns['liana_res'] is a non-empty DataFrame; key columns include source (sender), target (receiver), ligand_complex, receptor_complex, specificity_rank, magnitude_rank. For PBMC8k, expect 100k+ rows (n_clusters² × n_LR_pairs).
- After
to_comm_adata: comm_adata.shape is roughly (n_directional_pairs, n_LR_pairs). comm_adata.var['classification'] should have most entries non-null; null entries are unmapped LR pairs.
- For
plot_type='dot': dot size and colour scale should be readable; if the figure is empty, the pvalue_threshold is too strict OR score_key was wrong.
- Sender/receiver focus:
sender_use=<cluster> should reduce the number of bubbles substantially; if the figure is identical to the unfocused one, the cluster name was misspelled.
plot_type='focused_heatmap' empty: the named pathway has no LR pairs above the threshold OR the pathway name doesn't exist (check comm_adata.var['classification'].unique()).
- For multi-condition plots: each condition's frame must have the same column schema (
source, target, ligand_complex, receptor_complex, specificity_rank minimally).
- Compare LIANA
rank_aggregate hits against CellPhoneDB-only hits on the same cohort: typically 60–80 % overlap at the top-100; large disagreement (<30 %) means one method has bad calibration on this cohort.
Resource Map
- See
reference.md for compact copy-paste snippets.
- See
references/source-grounding.md for verified run_liana / to_comm_adata / ccc_heatmap signatures.
- For the alternative CellPhoneDB-only workflow + CellChatViz, see
single-cell-cellphonedb-communication.
- For spatial cell-cell communication (COMMOT / FlowSig), see
spatial-tutorials.
Examples
- "Run LIANA
rank_aggregate on a PBMC8k cohort grouped by bulk_labels and produce a sender × receiver dot plot."
- "Reshape the LIANA result into a CommAnnData classified against CellChat pathways and plot the role network for ECM/Adhesion."
- "Focus the dot plot on signals originating from CD34+ at
pvalue_threshold=0.05."
- "Compare LIANA results between baseline and stimulated conditions on the same cohort."
References
- Tutorial notebook:
t_ccc_liana.ipynb — PBMC8k LIANA + CellChat-style visualisation.
- LIANA+ paper: Dimitrov et al. 2022, Nature Communications — "Comparison of methods and resources for cell-cell communication inference".
- Live API verified — see
references/source-grounding.md.
1---2name: omicverse-single-cell-liana-communication3description: LIANA+ ligand-receptor inference on single-cell AnnData via `ov.single.run_liana`, plus the OmicVerse cell-cell communication (CCC) plotting stack with `ov.pl.ccc_heatmap` and `ov.single.to_comm_adata`. Use when computing ligand-receptor scores from a labeled AnnData (`bulk_labels` / `cell_type` / etc.), when post-processing LIANA results into a CommAnnData for pathway-aware visualisation, or when reproducing `t_ccc_liana`.4---56# OmicVerse Single-Cell — LIANA+ Cell-Cell Communication78## Goal910Take a preprocessed annotated single-cell `AnnData` and run **LIANA+** ligand-receptor inference, producing per-(sender, receiver, ligand, receptor) score columns in `adata.uns['liana_res']`. Then post-process via `ov.single.to_comm_adata(...)` into a *communication AnnData* keyed on the sender→receiver direction, classified against the **CellChat / CellChatDB** pathway taxonomy. Visualise with `ov.pl.ccc_heatmap(...)` — eight `plot_type` modes covering dot / tile / aggregation heatmap / pathway-bubble / role-heatmap / role-network / focused-heatmap.1112This skill is the LIANA-side complement to the existing `single-cell-cellphonedb-communication` skill. They produce comparable hit sets but LIANA aggregates across multiple base methods (CellPhoneDB, NATMI, Connectome, SingleCellSignalR, CellChat) into a `rank_aggregate` consensus — typically more robust than any single method.1314## Quick Workflow15161. Load a preprocessed annotated `AnnData` (`obs[group_key]` populated; for the PBMC8k demo, `bulk_labels`).172. Optional: visualise the cohort embedding to confirm cluster labels look right (`ov.pl.embedding(adata, basis='X_umap', color='bulk_labels', frameon='small')`).183. **Run LIANA**: `ov.single.run_liana(adata, groupby='bulk_labels', method='rank_aggregate', resource_name='consensus', key_added='liana_res', inplace=True)`. Result lands at `adata.uns['liana_res']`.194. **Pathway-aware reshape**: `comm_adata = ov.single.to_comm_adata(adata, result_uns_key='liana_res', score_key='specificity_rank', pvalue_key='specificity_rank', classification_reference='cellchat', classification_fallback='family')`. Returns a CommAnnData with one var per (ligand, receptor) and a `var['classification']` column mapping each pair to a CellChat pathway.205. **Pathway dot plots**: `ov.pl.ccc_heatmap(adata, plot_type='dot', display_by='interaction', score_key='specificity_rank', ...)`. Multiple `plot_type` modes share a uniform interface — see Branch Selection below.216. **Aggregation heatmap**: `plot_type='heatmap', display_by='aggregation'` shows sender→receiver totals.227. **Sender / receiver focus**: pass `sender_use=<cluster>` or `receiver_use=<cluster>` to filter to a single direction.238. **Pathway-focused / role-network views**: `plot_type='focused_heatmap'`, `'pathway_bubble'`, `'role_heatmap'`, `'role_network'` — pick by question (see Branch Selection).249. **Multi-condition comparison**: stack LIANA results from multiple conditions, set `condition` column on the result frames, and re-run plotters with the multi-condition adata.2526## Interface Summary2728```python29ov.single.run_liana(30 adata, *,31 groupby: str, # required — the cell-type column32 method: str = 'rank_aggregate', # or 'cellphonedb', 'natmi', 'connectome', 'sca'33 resource_name: str = 'consensus', # ligand-receptor DB; 'consensus', 'cellphonedb', 'cellchat', etc.34 key_added: str = 'liana_res',35 inplace: bool = True,36 **kwargs # forwarded to liana.mt.<method>37)38# adata.uns[key_added] -> pd.DataFrame with one row per (sender, receiver, ligand_complex, receptor_complex)39# columns include: 'specificity_rank', 'magnitude_rank', 'lr_means', 'cellphone_pvals', etc.40```4142```python43ov.single.to_comm_adata(44 adata: AnnData | None = None, *,45 data: pd.DataFrame | None = None,46 result_uns_key: str | None = None,47 score_key: str = 'specificity_rank',48 pvalue_key: str = 'specificity_rank',49 inverse_score: bool = True, # smaller rank = better → invert for visualisation50 inverse_pvalue: bool = False,51 classification: str | Mapping[str, str] | None = None,52 classification_reference: str | pd.DataFrame | None = 'cellchat',53 classification_fallback: str | None = 'family',54 separator: str = '|',55) -> AnnData56# Returns a "communication AnnData":57# .obs = (sender, receiver) directed pairs58# .var = (ligand, receptor) interactions; var['classification'] is the pathway label59# .X = score matrix (pairs × interactions)60# .layers = {'pvalue': ...}61```6263```python64ov.pl.ccc_heatmap(65 adata_or_comm, *,66 plot_type: str = 'dot', # see Branch Selection for full list67 display_by: str = 'interaction', # 'interaction' or 'aggregation'68 score_key: str = 'specificity_rank',69 pvalue_key: str = 'specificity_rank',70 classification_reference='cellchat',71 classification_fallback='family',72 sender_use: str | list | None = None,73 receiver_use: str | list | None = None,74 signaling: str | list | None = None, # focus on named pathways75 pattern: str = 'incoming', # for role_heatmap / role_network: 'incoming' / 'outgoing'76 pvalue_threshold: float = 0.05,77 top_n: int = 10,78 cmap: str = ...,79 figsize: tuple = ...,80 show: bool = False,81 ...,82) -> (fig, ax)83```8485## Boundary8687**Inside scope:**88- LIANA fitting on a labeled `AnnData` with `run_liana`.89- Reshaping to `CommAnnData` with `to_comm_adata` (CellChat / CellPhoneDB / family classification).90- All eight `ov.pl.ccc_heatmap` modes.91- Sender / receiver / pathway focusing.92- Multi-condition comparison via stacked result frames with a `condition` column.9394**Outside scope — separate skill:**95- CellPhoneDB-only inference + `CellChatViz` workflow — see `single-cell-cellphonedb-communication` (existing skill).96- Spatial cell-cell communication with COMMOT / FlowSig — see `spatial-tutorials` (existing skill).97- Building the upstream annotated AnnData — separate skill.98- Single-method LIANA (e.g. only NATMI) — supported by `method=` kwarg but rare in practice; the consensus `rank_aggregate` is the canonical choice.99100## Branch Selection101102**`method` for `run_liana`**103- `'rank_aggregate'` (default) — consensus across CellPhoneDB / NATMI / Connectome / SingleCellSignalR / CellChat. **The right default**.104- `'cellphonedb'` — single-method permutation-based; matches the CellPhoneDB v3 paper.105- `'natmi'` — specificity edge-weighting; less conservative than CellPhoneDB.106- `'connectome'` — scaled mean expression; gives both `magnitude` and `specificity` ranks.107- `'sca'` (SingleCellSignalR) — LRscore-based; conservative.108109**`resource_name`**110- `'consensus'` (default) — union of CellChat + CellPhoneDB + Ramilowski + others.111- `'cellphonedb'` — strict CellPhoneDB v4 only.112- `'cellchat'` — strict CellChat only.113- For organism-specific runs, append `_human` / `_mouse` to the resource name.114115**`score_key` and `pvalue_key`**116- `'specificity_rank'` — both score and pvalue (LIANA reuses the same column for the rank-aggregate output). For other methods, use the method-specific columns (`'cellphone_pvals'` for CellPhoneDB, `'lr_logfc'` for NATMI, etc.).117- `'magnitude_rank'` — alternate score that emphasises raw expression magnitude over specificity.118- `inverse_score=True` (default in `to_comm_adata`): converts rank-style scores (lower=better) to score-style (higher=better) for visualisation.119120**`plot_type` for `ccc_heatmap`**121- `'dot'` — sender × receiver bubble plot, dot size = score, colour = pvalue. Default exploratory view.122- `'tile'` — heat tile: rows = interactions, cols = sender→receiver pairs.123- `'heatmap'` (with `display_by='aggregation'`) — sender × receiver aggregated total CCC strength.124- `'focused_heatmap'` — restrict to a named pathway (`signaling=['ECM/Adhesion']`).125- `'pathway_bubble'` — pathway × sender→receiver bubble; needs `signaling=[...]`.126- `'role_heatmap'` — sender / receiver role intensity per cluster (`pattern='incoming' | 'outgoing'`).127- `'role_network'` — directed network plot of dominant signalling roles.128129**`display_by`**130- `'interaction'` — per (ligand, receptor) detail.131- `'aggregation'` — summed across interactions per (sender, receiver). Use with `plot_type='heatmap'`.132133**`sender_use` / `receiver_use`**134- `sender_use='CD34+'` — show only signals originating from CD34+. Useful for "where does CD34+ talk to?"135- `receiver_use='CD34+'` — show only signals received by CD34+. Useful for "what regulates CD34+?"136137**`classification_reference`**138- `'cellchat'` (default) — CellChat pathway taxonomy.139- `'family'` (fallback) — chemokine / cytokine / TGF-β / etc. families.140- Pass a custom `pd.DataFrame` keyed by ligand-receptor for arbitrary pathway labels.141142**Multi-condition comparison**: build a stacked frame with a `condition` column, then call `ov.pl.ccc_heatmap` with that frame. Allows side-by-side baseline vs. stimulated visualisation.143144## Input Contract145146- `AnnData` with `obs[group_key]` populated (categorical or strings); typical group_keys: `'bulk_labels'`, `'cell_type'`, `'leiden'`.147- `adata.X` log-normalised expression. LIANA expects this scale; passing raw counts gives nonsensical specificity scores.148- `pip install liana` (the omicverse install does not ship LIANA by default).149- For `to_comm_adata` with `classification_reference='cellchat'`: requires the CellChat ligand-receptor mapping shipped under `omicverse.external.cellchat` (always available in OmicVerse).150151## Minimal Execution Patterns152153```python154import omicverse as ov155import scanpy as sc156import warnings157warnings.filterwarnings("ignore", category=FutureWarning)158159ov.plot_set(font_path='Arial')160161# 1) Load a labeled AnnData162adata = sc.datasets.pbmc8k() # or your own163adata.obs['bulk_labels'] = ... # cluster labels164165ov.pl.embedding(adata, basis='X_umap', color='bulk_labels', frameon='small')166167# 2) Run LIANA168ov.single.run_liana(169 adata,170 groupby='bulk_labels',171 method='rank_aggregate',172 resource_name='consensus',173 key_added='liana_res',174 inplace=True,175)176print(adata.uns['liana_res'].head())177178# 3) Reshape into a CommAnnData with CellChat pathway classification179comm_adata = ov.single.to_comm_adata(180 adata,181 result_uns_key='liana_res',182 score_key='specificity_rank',183 pvalue_key='specificity_rank',184 classification_reference='cellchat',185 classification_fallback='family',186)187print(comm_adata)188print(comm_adata.var['classification'].value_counts().head())189190# 4) Dot plot — default exploratory view191fig, ax = ov.pl.ccc_heatmap(192 adata,193 plot_type='dot',194 display_by='interaction',195 score_key='specificity_rank',196 pvalue_key='specificity_rank',197 classification_reference='cellchat',198 classification_fallback='family',199 show=False,200)201```202203```python204# Sender / receiver focused dot plots205fig, ax = ov.pl.ccc_heatmap(206 comm_adata, plot_type='dot', display_by='interaction',207 score_key='specificity_rank', pvalue_key='specificity_rank',208 sender_use='CD34+', top_n=6, pvalue_threshold=0.05,209 show=False,210)211fig, ax = ov.pl.ccc_heatmap(212 adata, plot_type='dot', display_by='interaction',213 score_key='specificity_rank', pvalue_key='specificity_rank',214 receiver_use='CD34+', top_n=5, pvalue_threshold=0.05,215 show=False,216)217218# Aggregation heatmap (sender × receiver totals)219fig, ax = ov.pl.ccc_heatmap(220 adata, plot_type='heatmap', display_by='aggregation',221 score_key='specificity_rank', pvalue_key='specificity_rank',222 classification_reference='cellchat', classification_fallback='family',223 cmap='YlGnBu', figsize=(4, 3), show=False,224)225226# Focus on a specific pathway227focus = comm_adata.var['classification'].dropna().astype(str).unique().tolist()228focus = [v for v in focus if v not in {'Unclassified', 'nan'}]229focus_pathway = focus[0] if focus else 'Unclassified'230231fig, ax = ov.pl.ccc_heatmap(232 adata, plot_type='focused_heatmap',233 signaling=[focus_pathway],234 min_interaction_threshold=0.0,235 cmap='YlGnBu', figsize=(4, 3), show=False,236)237238# Pathway-bubble for a specific pathway239fig, ax = ov.pl.ccc_heatmap(240 adata, plot_type='pathway_bubble',241 signaling=['ECM/Adhesion'],242 top_n=5, figsize=(3, 5), show=False,243)244245# Role heatmap (incoming vs outgoing)246fig, ax = ov.pl.ccc_heatmap(247 adata, plot_type='role_heatmap',248 pattern='incoming', cmap='Greens',249 figsize=(4, 3), show=False,250)251252# Role network for a pathway253fig, ax = ov.pl.ccc_heatmap(254 adata, plot_type='role_network',255 signaling=['ECM/Adhesion'],256 cmap='Greens', figsize=(8, 5), show=False,257)258```259260## Validation261262- After `run_liana`: `adata.uns['liana_res']` is a non-empty DataFrame; key columns include `source` (sender), `target` (receiver), `ligand_complex`, `receptor_complex`, `specificity_rank`, `magnitude_rank`. For PBMC8k, expect 100k+ rows (n_clusters² × n_LR_pairs).263- After `to_comm_adata`: `comm_adata.shape` is roughly `(n_directional_pairs, n_LR_pairs)`. `comm_adata.var['classification']` should have most entries non-null; null entries are unmapped LR pairs.264- For `plot_type='dot'`: dot size and colour scale should be readable; if the figure is empty, the `pvalue_threshold` is too strict OR `score_key` was wrong.265- Sender/receiver focus: `sender_use=<cluster>` should reduce the number of bubbles substantially; if the figure is identical to the unfocused one, the cluster name was misspelled.266- `plot_type='focused_heatmap'` empty: the named pathway has no LR pairs above the threshold OR the pathway name doesn't exist (check `comm_adata.var['classification'].unique()`).267- For multi-condition plots: each condition's frame must have the same column schema (`source`, `target`, `ligand_complex`, `receptor_complex`, `specificity_rank` minimally).268- Compare LIANA `rank_aggregate` hits against CellPhoneDB-only hits on the same cohort: typically 60–80 % overlap at the top-100; large disagreement (<30 %) means one method has bad calibration on this cohort.269270## Resource Map271272- See [`reference.md`](reference.md) for compact copy-paste snippets.273- See [`references/source-grounding.md`](references/source-grounding.md) for verified `run_liana` / `to_comm_adata` / `ccc_heatmap` signatures.274- For the alternative CellPhoneDB-only workflow + CellChatViz, see `single-cell-cellphonedb-communication`.275- For spatial cell-cell communication (COMMOT / FlowSig), see `spatial-tutorials`.276277## Examples278- "Run LIANA `rank_aggregate` on a PBMC8k cohort grouped by `bulk_labels` and produce a sender × receiver dot plot."279- "Reshape the LIANA result into a CommAnnData classified against CellChat pathways and plot the role network for ECM/Adhesion."280- "Focus the dot plot on signals originating from CD34+ at `pvalue_threshold=0.05`."281- "Compare LIANA results between baseline and stimulated conditions on the same cohort."282283## References284- Tutorial notebook: [`t_ccc_liana.ipynb`](https://omicverse.readthedocs.io/en/latest/Tutorials-single/t_ccc_liana/) — PBMC8k LIANA + CellChat-style visualisation.285- LIANA+ paper: Dimitrov *et al.* 2022, *Nature Communications* — "Comparison of methods and resources for cell-cell communication inference".286- Live API verified — see [`references/source-grounding.md`](references/source-grounding.md).