| name | cellchat-cell-communication |
| description | Infer and visualize intercellular communication from scRNA-seq with CellChat (R). Build CellChat from Seurat/counts → subset CellChatDB ligand-receptor pairs → over-expressed genes per group → communication probabilities → pathway signaling → network centrality (senders/receivers/influencers) → chord/heatmap/bubble plots → cross-condition compare. Human, mouse. Use liana for pure-Python. |
| license | MIT |
CellChat — Cell-Cell Communication Analysis
Overview
CellChat is an R package that infers and visualizes intercellular signaling networks from single-cell RNA-seq data. Starting from a normalized expression matrix and cluster labels, CellChat identifies ligand-receptor interactions supported by CellChatDB — a manually curated database of over 2,000 validated ligand-receptor pairs in human and mouse. Communication probability is modeled using the law of mass action, combining expression levels of ligands, receptors, and cofactors. CellChat aggregates pair-level probabilities into pathway-level signaling networks and quantifies each cell group's role as a signal sender, receiver, mediator, or influencer. The result is a rich, interpretable picture of which cell types talk to which, through which signaling pathways, and how these patterns change between conditions.
When to Use
- Characterizing which cell types are the dominant senders or receivers of paracrine and autocrine signals in a tissue atlas or disease sample
- Identifying specific ligand-receptor pairs mediating communication between a cell population of interest (e.g., tumor cells → T cells, fibroblasts → epithelial cells)
- Comparing intercellular signaling networks between two conditions (e.g., healthy vs. diseased, treatment vs. control) to find rewired or lost communication
- Discovering pathway-level signaling programs (e.g., MHC-II, COLLAGEN, VEGF) enriched in a particular cell-cell interaction
- Prioritizing targets for perturbation experiments by ranking signaling pathways by their aggregate communication strength or network centrality
- Use liana (Python/R) instead when you want a pure-Python workflow or a consensus ranking across multiple ligand-receptor databases (CellChat, CellPhoneDB, Connectome, NicheNet)
- Use NicheNet (R) instead when you need ligand-to-target gene regulatory inference — predicting which ligands from sender cells regulate which target genes in receiver cells
Prerequisites
- R packages:
CellChat (>= 2.0), Seurat (>= 4.0, for Seurat-based input), NMF, ggplot2, ggalluvial, igraph, dplyr, patchwork, reticulate (optional)
- Data requirements: Normalized scRNA-seq count matrix (genes × cells) and a cell group identity vector (cluster labels or cell types). Raw counts are acceptable if normalized inside CellChat.
- Species: CellChatDB available for human and mouse; other species require custom database construction
- Memory: 8 GB RAM minimum for datasets with 10,000–50,000 cells; 32 GB+ recommended for larger datasets
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install(c("BiocNeighbors", "ComplexHeatmap"))
install.packages("devtools")
devtools::install_github("jinworks/CellChat")
install.packages(c("NMF", "ggplot2", "ggalluvial", "igraph",
"dplyr", "patchwork", "circlize", "RColorBrewer"))
Quick Start
library(CellChat)
library(Seurat)
data.input <- GetAssayData(seurat_obj, assay = "RNA", slot = "data")
meta <- data.frame(labels = Idents(seurat_obj), row.names = names(Idents(seurat_obj)))
cellchat <- createCellChat(object = data.input, meta = meta, group.by = "labels")
cellchat@DB <- CellChatDB.human
cellchat <- subsetData(cellchat)
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- identifyOverExpressedInteractions(cellchat)
cellchat <- computeCommunProb(cellchat type
cellchat filterCommunicationcellchat min.cells
cellchat computeCommunProbPathwaycellchat
cellchat aggregateNetcellchat
printcellchat
Workflow
Step 1: Create CellChat Object
Build a CellChat object from either a Seurat object or a raw count matrix with accompanying metadata.
library(CellChat)
library(Seurat)
data.input <- GetAssayData(seurat_obj, assay = "RNA", slot = "data")
meta <- data.frame(
labels = Idents(seurat_obj),
row.names = colnames(seurat_obj)
)
cellchat <- createCellChat(object = data.input, meta = meta, group.by = "labels")
cellchat <- createCellChat(object = data.input, meta = data.frame(labels = identity),
group.by = "labels"
cat levelscellchatidents
cat ncoldata.input
Step 2: Set CellChatDB and Subset Interactions
Load the species-appropriate ligand-receptor database and optionally subset to a signaling category of interest.
CellChatDB <- CellChatDB.human
unique(CellChatDB$interaction$annotation)
cellchat@DB <- CellChatDB
CellChatDB.use <- subsetDB(CellChatDB, search = "Secreted Signaling",
key = "annotation")
cellchat@DB <- CellChatDB.use
cellchat <- subsetData(cellchat)
cat("Genes retained after database subset:", nrow(cellchat@data.signaling), "\n")
Step 3: Identify Over-Expressed Genes and Interactions
For each cell group, identify ligands and receptors that are significantly over-expressed compared to other groups.
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- identifyOverExpressedInteractions(cellchat)
df.net <- subsetCommunication(cellchat)
cat("Total inferred interactions:", nrow(df.net), "\n")
head(df.net[, c("source", "target", "ligand", "receptor", "prob")], 5)
Step 4: Infer Cell-Cell Communication Probabilities
Compute communication probability for each ligand-receptor pair between every ordered pair of cell groups using the law of mass action. CellChat accounts for multi-subunit complexes and co-stimulatory/co-inhibitory cofactors.
cellchat <- computeCommunProb(
cellchat,
type = "triMean",
trim = 0.1,
nboot = 100,
seed.use = 42,
population.size = TRUE
)
cellchat <- filterCommunication(cellchat, min.cells = 10)
df.net <- subsetCommunication(cellchat)
cat("Interactions after filtering:", nrow(df.net), "\n")
cat("Significant interactions (p<0.05):", df.netpval
Step 5: Compute Pathway-Level Communication
Aggregate ligand-receptor pair probabilities into signaling pathway-level networks (e.g., COLLAGEN, MHC-II, VEGF).
cellchat <- computeCommunProbPathway(cellchat)
cellchat <- aggregateNet(cellchat)
cat("Significant signaling pathways:\n")
print(cellchat@netP$pathways)
df.pathways <- subsetCommunication(cellchat, slot.name = "netP")
head(df.pathways[, c("source", "target", "pathway_name", "prob")], 5)
Step 6: Analyze Network Centrality — Senders, Receivers, Influencers
Identify each cell group's network role by computing information flow measures: out-strength (sender), in-strength (receiver), betweenness (mediator), and eigenvector centrality (influencer).
cellchat <- netAnalysis_computeCentrality(cellchat, slot.name = "netP")
netAnalysis_signalingRole_heatmap(
cellchat,
pattern = "all",
signaling = NULL,
height = 10,
color.heatmap = "OrRd"
)
library(NMF)
selectK(cellchat, pattern = "outgoing")
cellchat <- identifyCommunicationPatterns(
cellchat,
pattern = "outgoing",
k = 3,
width =
height
Step 7: Visualize — Chord Diagrams, Heatmaps, Bubble Plots
CellChat provides several visualization functions for both aggregate and pathway-specific interactions.
library(ggplot2)
library(patchwork)
par(mfrow = c(1, 2))
netVisual_circle(
cellchat@net$count,
vertex.weight = as.numeric(table(cellchat@idents)),
weight.scale = TRUE,
label.edge = FALSE,
title.name = "Number of interactions"
)
netVisual_circle(
cellchat@net$weight,
vertex.weight = as.numeric(table(cellchat@idents)),
weight.scale = TRUE,
label.edge = FALSE,
title.name =
p1 netVisual_heatmapcellchat measure color.heatmap
p2 netVisual_heatmapcellchat measure color.heatmap
p1 p2
netVisual_aggregate
cellchat
signaling
layout
vertex.receiver
netVisual_bubble
cellchat
sources.use
targets.use
signaling
remove.isolate
ggsave width height
Step 8: Compare Two CellChat Objects Across Conditions
When you have two conditions (e.g., healthy and diseased), merge the CellChat objects and compare signaling networks.
object.list <- list(Control = cellchat_ctrl, Disease = cellchat_disease)
cellchat_merged <- mergeCellChat(object.list, add.names = names(object.list))
compareInteractions(cellchat_merged, show.legend = FALSE,
group = c(1, 2), measure = "count")
compareInteractions(cellchat_merged, show.legend = FALSE,
group = c(1, 2), measure = "weight")
netVisual_diffInteraction(cellchat_merged weight.scale
rankNetcellchat_merged mode stacked do.stat
rankNetPairwise
cellchat_merged
comparison
slot.name
measure
Key Parameters
| Parameter | Function | Default | Range / Options | Effect |
|---|
type | computeCommunProb | "triMean" | "triMean", "truncatedMean", "thresholdedMean", "median" | Aggregation method for group-level expression; triMean is most stringent |
trim | computeCommunProb | 0.1 | 0–0.25 | Fraction trimmed from each tail; only applies when type="truncatedMean" |
nboot | computeCommunProb | 100 | 50–1000 | Bootstrap iterations for p-value estimation; higher = slower but more accurate |
population.size | computeCommunProb | TRUE | TRUE, FALSE | Weight communication probability by cell group size; recommended for heterogeneous data |
min.cells | filterCommunication | 10 | 5–50 | Minimum number of cells required per sender or receiver group to retain an interaction |
k | identifyCommunicationPatterns | required | 2–6 (choose via selectK) | Number of latent communication patterns; use selectK elbow to select |
thresh | netAnalysis_computeCentrality | 0.05 | 0.01–0.1 | P-value cutoff for retaining interactions in centrality analysis |
|
Key Concepts
Communication Probability Model
CellChat quantifies communication probability using the law of mass action. For a ligand L expressed in cell group A and receptor R (potentially a multi-subunit complex) expressed in cell group B:
P(A → B | L-R) = hill(expr_L_A) × hill(expr_R1_B) × hill(expr_R2_B) × ...
where hill(x) = x^n / (K^n + x^n) (Hill function, n=1 by default), and expression values are group-aggregated using the chosen type argument. Multi-subunit receptor complexes require all subunits to be expressed; the probability is the product of Hill-transformed subunit expressions.
CellChatDB Ligand-Receptor Database
CellChatDB is a curated database of experimentally validated ligand-receptor interactions organized into three categories:
dim(CellChatDB.human$interaction)
head(CellChatDB.human$interaction[, c("interaction_name", "pathway_name",
"ligand", "receptor", "annotation")], 4)
Three categories cover distinct biological mechanisms:
- Secreted Signaling: classical paracrine/autocrine ligands (cytokines, growth factors, morphogens)
- ECM-Receptor: extracellular matrix components binding membrane receptors
- Cell-Cell Contact: juxtacrine signals requiring direct cell contact (Notch, Ephrin, Semaphorin)
Network Centrality Roles
| Role | Centrality Measure | Interpretation |
|---|
| Sender | Out-degree / out-strength | Cell groups that broadcast signals to many targets |
| Receiver | In-degree / in-strength | Cell groups that receive signals from many sources |
| Mediator | Betweenness centrality | Cell groups that bridge communication between other groups |
| Influencer | Eigenvector centrality | Cell groups connected to other highly-connected groups |
Information Flow vs. Interaction Count
aggregateNet computes two complementary matrices:
cellchat@net$count: number of statistically significant ligand-receptor pairs per cell-group pair (raw interaction count)
cellchat@net$weight: sum of communication probabilities across all pairs (interaction strength / information flow)
High count with low weight indicates many weak interactions; high weight with low count indicates a few dominant pathways.
Common Recipes
Recipe: Extract All Significant Interactions as a Data Frame
Use when you want to export results, apply custom filtering, or feed interactions into downstream pathway analysis.
df.lr <- subsetCommunication(cellchat, slot.name = "net")
df.lr_sig <- df.lr[df.lr$pval < 0.05, ]
cat("Significant LR interactions:", nrow(df.lr_sig), "\n")
df.path <- subsetCommunication(cellchat, slot.name = "netP")
df.tumor_recv <- subsetCommunication(cellchat,
targets.use = "Tumor",
slot.name = "net")
cat("Interactions targeting Tumor cells:", nrow(df.tumor_recv), "\n")
write.csv(df.lr_sig, "cellchat_lr_interactions.csv" row.names
write.csvdf.path row.names
write.csvdf.tumor_recv row.names
Recipe: Visualize Signaling Role of a Specific Pathway
Use when you want a detailed view of which cell types send and receive via one pathway.
pathway <- "COLLAGEN"
netVisual_aggregate(cellchat, signaling = pathway, layout = "chord")
title(main = paste0(pathway, " signaling network"))
netAnalysis_contribution(cellchat, signaling = pathway)
plotGeneExpression(
cellchat,
signaling = pathway,
enriched.only = TRUE,
type = "violin"
)
Recipe: Save and Reload a CellChat Object
Use when checkpointing a completed run before visualization or comparison steps.
saveRDS(cellchat, file = "cellchat_analysis.rds")
cat("Saved to cellchat_analysis.rds\n")
cellchat_loaded <- readRDS("cellchat_analysis.rds")
cat("Cell groups:", levels(cellchat_loaded@idents), "\n")
cat("Pathways:", length(cellchat_loaded@netP$pathways), "\n")
slotNames(cellchat_loaded)
Recipe: Python-Equivalent Workflow with liana
Use when your pipeline is Python-based or you want a consensus ranking across multiple LR databases.
import liana
import scanpy as sc
import pandas as pd
adata = sc.read_h5ad("my_scrna.h5ad")
liana.mt.rank_aggregate(
adata,
groupby = "celltype",
resource_name = "consensus",
expr_prop = 0.1,
verbose = True
)
df = adata.uns["liana_res"]
df_sig = df[df["magnitude_rank"] < 0.05].sort_values("magnitude_rank")
print(df_sig[["source", "target", "ligand_complex", "receptor_complex",
"magnitude_rank"]].head(10))
df_sig.to_csv("liana_interactions.csv", index=False)
Expected Outputs
| Output | Type | Description |
|---|
cellchat@net$count | R matrix (n_groups × n_groups) | Number of significant LR interactions between each cell-group pair |
cellchat@net$weight | R matrix (n_groups × n_groups) | Aggregate communication probability (information flow) between cell-group pairs |
cellchat@netP$pathways | Character vector | Names of all inferred signaling pathways |
subsetCommunication(cellchat) | data.frame | Table of all LR-level interactions with source, target, ligand, receptor, probability, p-value |
subsetCommunication(cellchat, slot.name="netP") | data.frame | Pathway-level interaction table |
| Chord diagram (PDF/PNG) | Figure | Circular diagram showing interaction strength between cell groups |
| Heatmap (PDF/PNG) | Figure | Cell-group × cell-group interaction count or weight heatmap |
| Bubble plot (PDF/PNG) | Figure | Dot plot showing interaction probabilities per LR pair per group pair |
| Signaling role heatmap (PDF/PNG) | Figure | Pathway × cell-group centrality scores (sender/receiver roles) |
Troubleshooting
| Problem | Likely Cause | Solution |
|---|
Error in computeCommunProb: all probabilities are zero | Genes in CellChatDB not detected or filtered out | Confirm subsetData() retains genes: nrow(cellchat@data.signaling) > 0; check that expression matrix is log-normalized (not raw counts) and that gene names match CellChatDB (human: HGNC symbols; mouse: MGI symbols) |
Warning: groups with fewer than min.cells cells are removed | Small clusters dropped at filtering step | Lower min.cells in filterCommunication() (e.g., min.cells = 5) or merge rare clusters before creating the CellChat object |
identifyCommunicationPatterns NMF error or no convergence | Number of patterns k too high or data too sparse | Use selectK() to choose k from the elbow in cophenetic/dispersion curves; try k=2 or k=3 first |
Memory error / session crash during computeCommunProb | Dataset too large for available RAM | Subsample to ≤30,000 cells per condition; or run computeCommunProb with nboot = 50 to reduce bootstrap memory footprint |
| Chord diagram is unreadable (too many cell groups) | Many fine-grained clusters | Aggregate clusters into broader categories before creating CellChat object; or use netVisual_heatmap which scales better with many groups |
mergeCellChat error: cell group labels do not match | Cell type names differ between objects | Harmonize levels(cellchat_ctrl@idents) and levels(cellchat_disease@idents) before merging; use setIdent() to rename groups |
| Gene symbols not recognized (all probabilities 0) | Mixed human/mouse gene naming convention | Confirm species: human genes are ALL CAPS (e.g., TGFB1); mouse genes are title case (e.g., Tgfb1). Set CellChatDB.mouse for mouse data |
References