单细胞转录组 / 细胞通讯

CellChat 细胞通讯分析教程:从 Seurat 对象到通讯网络、通路与多组比较

本页按 CellChat 2.2.0.9001(GitHub main,2026-03)、Seurat 5.5.1 写成,代码在 10x PBMC 3k 和 Kang 2018 干扰素刺激 PBMC 两组数据上跑通。重点是官方教程没有展开的部分:v1 与 v2 的差异,参数怎么选、改了以后通讯数量变多少,图怎么读,多组比较和常见报错怎么处理。

直接答案

CellChat v2 的标准流程是:从 Seurat v5 对象用 LayerData(layer = "data") 取 log 归一化矩阵(先 JoinLayers,不能用 counts 或 scale.data),细胞类型标签去掉 NA 和未使用的因子水平;人用 CellChatDB.human、小鼠用 CellChatDB.mouse,一般用 subsetDB(CellChatDB) 去掉 Non-protein Signaling;依次运行 subsetData、identifyOverExpressedGenes、identifyOverExpressedInteractions、computeCommunProb、filterCommunication(min.cells = 10)、computeCommunProbPathway、aggregateNet。默认 type = "triMean" 要求一个基因在某群中至少 25% 的细胞表达,浅测序数据上通讯偏少,可改用 type = "truncatedMean", trim = 0.1(门槛 10%)。多组比较时每组单独计算、参数相同,细胞类型不一致先 liftCellChat 再 mergeCellChat。

先确认版本

CellChat 的仓库从 sqjin/CellChat 迁到 jinworks/CellChat。当前 GitHub main 是 2.2.0.9001(2026-03-04 最后提交),最后一个 release 标签是 v2.1.2。网上标着“v3”的是独立的 SpatialCellChat 包,只用于空间转录组;单细胞数据继续用 CellChat v2。

写论文方法部分时记录 packageVersion("CellChat") 和安装日期。GitHub main 在两次 release 之间也在变化,例如 2026-02-19 合入的 PR #438 改变了并行行为,2026-03-04 修改了 rankNet。

项目v1 时期教程(2021–2023)当前 v2照抄旧写法的后果
数据库规模CellChatDB.human 约 1,939 对3,233 对:v1 来源 1,920 对,v2 新增 1,313 对(994 对 Non-protein Signaling、233 对 Cell-Cell Contact、83 对 Secreted);mouse 3,379 对直接用全库会把代谢物和神经递质信号混进来
过表达基因检验Seurat 风格 Wilcoxon默认 do.fast = TRUE 调用 presto;未装 presto 直接报错PBMC 3k 同一数据:presto 得到 400 个过表达信号基因,do.fast = FALSE 得到 744 个,v1 与 v2 的结果不能直接对比
PPI 平滑projectData(cellchat, PPI.human)改名 smoothData,必须写 adj = PPI.human报 is(adj, "matrix") || is(adj, "sparseMatrix") is not TRUE(GitHub #185)
对象槽位data.projectdata.smooth旧对象报 no slot of name "data.smooth";维护者未修复,用户的做法是 obj@data.smooth <- matrix(nrow = 0, ncol = 0)(GitHub #202)
meta只需标签列还需要 samples 列;缺失时自动设为 sample1 并给警告多样本合并后无法用 min.samples 过滤
并行plan("multiprocess")future 已删除 multiprocess 后端报 No such backend for futures: 'multiprocess'
空间转录组v1.6 起支持 Visiumv2 支持多种空间技术;单细胞分辨率空转用 SpatialCellChat(v3)—

第 1 步

CellChat 只能从 GitHub 安装,包含 C++ 代码,需要编译器。依赖中最容易出问题的是 NMF(CRAN,需要 Biobase)、ComplexHeatmap 与 BiocNeighbors(Bioconductor)、presto(GitHub)。本页用 conda 装好其余依赖后,NMF、presto、CellChat 三个包编译安装共 2.5 分钟,没有报错。Nature Protocols 给出的最低配置是双核 CPU、16 GB 内存。

本页实测的安装方式bash
# 方案 A:conda 装依赖(本页实测,macOS arm64,约 4 分钟 + 编译 2.5 分钟)
micromamba create -y -n cellchat -c conda-forge -c bioconda \
  r-base=4.5 r-seurat r-remotes r-rcppeigen c-compiler cxx-compiler fortran-compiler make \
  r-future r-future.apply r-pbapply r-irlba r-ggalluvial r-svglite r-ggrepel r-circlize \
  bioconductor-complexheatmap bioconductor-biocneighbors bioconductor-biobase \
  r-rspectra r-reticulate r-sna r-fnn r-shape r-ggpubr r-ggnetwork r-plotly r-shiny r-bslib \
  r-collapse r-pkgmaker r-registry r-rngtools r-gridbase r-doparallel r-cowplot r-uwot
micromamba run -n cellchat Rscript -e '
options(repos = c(CRAN = "https://cloud.r-project.org"))
install.packages("NMF")                                        # conda-forge 没有 r-nmf
remotes::install_github("immunogenomics/presto", upgrade = "never")
remotes::install_github("jinworks/CellChat", upgrade = "never")
packageVersion("CellChat")'

# 方案 B:已有 R 4.4 以上
# install.packages(c("BiocManager", "remotes", "NMF"))
# BiocManager::install(c("ComplexHeatmap", "BiocNeighbors", "Biobase"))
# remotes::install_github(c("immunogenomics/presto", "jinworks/CellChat"), upgrade = "never")
报错或现象原因解决
Skipping 3 packages not available: Biobase, BiocNeighbors, BiocGenericsremotes 不会自动装 Bioconductor 包先 BiocManager::install(c("Biobase", "BiocNeighbors", "BiocGenerics", "ComplexHeatmap"))
Failed to connect to github.com / 下载超时国内访问 GitHub 不稳定conda 或 Bioconductor 镜像装好依赖,只剩 presto 与 CellChat 两个 GitHub 包;仍失败时下载源码 zip 后 R CMD INSTALL
installation of package ... had non-zero exit status(macOS)Xcode 命令行工具缺失或损坏重新安装 Xcode 命令行工具(GitHub #226 两位用户确认),或用 conda 的 c-compiler、cxx-compiler
no member named 'Rlog1p' in namespace 'std'Apple 芯片上旧版 R 与编译器的组合问题export PKG_CPPFLAGS="-DHAVE_WORKING_LOG1P" 后重装(中文经验帖,2023)
CMake was not found on the PATH某个依赖需要 CMakeconda install cmake
dependencies 'RSpectra', 'RcppEigen', 'ggpubr', 'BiocNeighbors' are not availableCRAN 与 Bioconductor 依赖未装全BiocManager::install() 补装,或用 conda-forge 的 r-* 包
For a faster implementation of the Wilcoxon Test, please install the presto packagev2 默认用 prestoremotes::install_github("immunogenomics/presto");装不上时 identifyOverExpressedGenes(do.fast = FALSE),但结果与 presto 不同

第 2 步

CellChat 需要两样东西:log 归一化的表达矩阵(基因为行、细胞为列)和每个细胞的分组标签。下面的写法在 Seurat 5.5.1 上验证过,注释说明了每一行防止的错误。

从 Seurat v5 对象创建 CellChat 对象r
library(Seurat)
library(CellChat)

seu <- readRDS("pbmc3k_annot.rds")          # 已注释的 Seurat v5 对象
seu <- JoinLayers(seu)                       # 多样本对象先合并 layer,否则只取到第一层
seu$celltype <- droplevels(factor(seu$celltype))
stopifnot(!anyNA(seu$celltype))              # 标签不能有 NA

data.input <- LayerData(seu, assay = "RNA", layer = "data")   # log 归一化值,不是 counts
stopifnot(min(data.input) >= 0)              # 不能用 scale.data 或 integrated
meta <- data.frame(
  labels  = seu$celltype,
  samples = factor(seu$orig.ident),          # v2 需要 samples 列
  row.names = colnames(seu)
)
# 数字聚类号要加前缀,CellChat 不接受标签 "0"
# meta$labels <- factor(paste0("C", seu$seurat_clusters))

cellchat <- createCellChat(object = data.input, meta = meta, group.by = "labels")
table(cellchat@idents)

为什么用归一化数据

CellChat 先把矩阵除以全局最大值,再代入 Hill 函数(Kh = 0.5)计算概率。用 counts 时最大值是几百,缩放后几乎所有值接近 0。本页实测:PBMC 3k 用 counts 不报错,通讯 170 条(正确输入 152 条),通路相同,总强度只有正确值的约 1/800。强度在组间和数据集间的比较因此失效。

scale.data 和 integrated 都不能用

直接传 Seurat 对象时 createCellChat 会检查负值并报错;传矩阵时不检查。本页把 scale.data(2,000 个高变基因、含负值)当矩阵传入,流程跑完且得到 201 条通讯,没有任何提示。integrated assay 只有部分基因且经过校正,CellChat 会给警告。SCT assay 的 data 层是 log1p 后的校正计数,可以使用。

拆分 layer 的对象

Seurat v5 多样本对象在 IntegrateLayers 前后可能处于拆分状态(data.A、data.B)。本页实测:直接传对象报 invalid 'row.names' length;LayerData(layer = "data") 只给警告,返回第一层的 1,319 个细胞(共 2,638 个)。先 JoinLayers。

标签的四条要求

不能含 NA;因子不能有未使用的水平;不能是数字 0(Seurat 聚类号直接用会报 Cell labels cannot contain `0`!);每个群建议多于 10 个细胞。前两条的报错相同:Please check `unique(object@idents)` and ensure that the factor levels are correct!

标签粒度:大类还是亚群

CellChat 在群与群之间计算,群内异质性会被平均掉。Nature Protocols 把这列为局限,建议需要时先做亚聚类再运行。代价是群数增加后运行时间和图的复杂度上升:GitHub #167 中一位用户 133 个群、1.1 万个细胞运行超过 11 小时。常见做法是先用大类得到全局网络,再对关心的大类拆分亚群单独运行。没有找到维护者给出的具体群数建议。

多样本数据怎么组织

维护者 sqjin 在 GitHub #62 的建议是把同一条件的所有样本合并成一个对象运行,与整合后聚类的思路一致。为减少只在单个样本中出现的通讯,meta 中写 samples 列,再用 filterCommunication(min.samples = 2) 要求通讯至少在 2 个样本中出现(v2.1.2 起)。用户在同一 issue 中报告,合并运行比逐样本运行多出 4–5% 的独有通讯。

空间转录组的额外输入

createCellChat(datatype = "spatial", coordinates = ..., spatial.factors = data.frame(ratio = ..., tol = ...)):coordinates 是全分辨率图像的像素坐标,ratio 是像素到微米的换算(Visium 为 65 / spot_diameter_fullres),tol 取 spot 直径的一半(32.5)。computeCommunProb 中 interaction.range = 250、Visium 的 contact.range = 100;单细胞分辨率技术的 contact.range 约 10。单细胞分辨率空转用 SpatialCellChat。

第 3 步

CellChatDB 把配体-受体对分为四类。官方教程示例只用 Secreted Signaling,但这只是示例;子集的选择对结果数量的影响大于任何算法参数。

只用 Secreted Signaling 的利弊

好处是结果少、图清楚、与早期文献可比。代价是免疫细胞之间最主要的接触型信号(MHC-I/II、CD45、ICAM、SELPLG 等)全部缺失:PBMC 3k 上加入 Cell-Cell Contact 后通路从 13 条增加到 34 条。研究免疫突触、T 细胞与 APC 相互作用、肿瘤免疫检查点时,用 subsetDB(CellChatDB)。

Non-protein Signaling 默认不用

官方教程写明不建议直接使用整个 CellChatDB。这一类的配体量由合成酶和转运体基因推断,单细胞数据中代谢物本身不可测。神经系统研究需要神经递质信号时单独加入,并在结果中与蛋白类信号分开解读。

物种与基因名

人用 CellChatDB.human,小鼠用 CellChatDB.mouse,另有 CellChatDB.zebrafish。基因名必须是官方 symbol:Ensembl ID 或人鼠混用时 subsetData 后几乎没有信号基因,下游报 data.use[RsubunitsV, ] 等错误。其他物种先做同源基因转换。

增加自定义配受体对

用 updateCellChatDB() 合并自己整理的 interaction、complex、cofactor、geneInfo 表(官方 Update-CellChatDB 教程)。新增的对没有通路归属时,通路层面的图不会显示它们。

类别human 对数说明PBMC 3k 实测(triMean / truncatedMean 0.1)
Secreted Signaling1,280分泌型旁分泌、自分泌信号152 / 241 条,6 / 13 条通路
ECM-Receptor424细胞外基质-受体,组织样本中重要,血液样本中少—
Cell-Cell Contact535需要细胞直接接触,如 MHC、ICAM、CD86前三类合计(subsetDB(CellChatDB)):437 / 967 条,14 / 34 条通路
Non-protein Signaling994代谢物与神经递质,由合成酶和转运体表达推断配体量全库:445 / 1,055 条,其中 Non-protein 8 / 88 条

第 4 步

下面是在 PBMC 3k 上跑通的核心流程。参数的含义与取值依据见代码后的表格,改动后的实测影响见下一节。

推断通讯网络r
CellChatDB <- CellChatDB.human               # 小鼠用 CellChatDB.mouse
cellchat@DB <- subsetDB(CellChatDB)          # 去掉 Non-protein Signaling 的全部蛋白类配受体
# cellchat@DB <- subsetDB(CellChatDB, search = "Secreted Signaling", key = "annotation")

future::plan("sequential")                   # 小数据集顺序执行更快
cellchat <- subsetData(cellchat)
cellchat <- identifyOverExpressedGenes(cellchat)          # 默认用 presto 做 Wilcoxon
cellchat <- identifyOverExpressedInteractions(cellchat)

cellchat <- computeCommunProb(cellchat,
                              type = "truncatedMean", trim = 0.1,  # trim 只在 truncatedMean 下生效
                              population.size = FALSE)              # 未分选样本可设 TRUE
cellchat <- filterCommunication(cellchat, min.cells = 10)
cellchat <- computeCommunProbPathway(cellchat)
cellchat <- aggregateNet(cellchat)

df.net  <- subsetCommunication(cellchat)                      # 配体-受体层面
df.netP <- subsetCommunication(cellchat, slot.name = "netP")  # 通路层面
nrow(df.net); cellchat@netP$pathways
saveRDS(cellchat, "cellchat_pbmc3k.rds")
参数默认作用与取值依据
identifyOverExpressedGenes 的 thresh.p0.05用未校正 p 值筛每群过表达的信号基因;thresh.fc = 0、thresh.pc = 0。只要配体或受体之一过表达,这对就进入计算
computeCommunProb 的 type"triMean"triMean 是 Q1、Q2、Q2、Q3 四个分位数的均值:表达细胞比例低于 25% 时组平均为 0,25%–50% 时只剩 Q3/4。结果少、偏强信号
type = "truncatedMean" 的 trim0.1两端各去掉 trim 比例后求均值:表达比例低于 trim 时组平均为 0。0.1 对应 10% 门槛,0.05 对应 5%。trim 只在 truncatedMean(以及未写进教程的 thresholdedMean)下生效。Nature Protocols 的建议:一般用 trim = 0.1;研究体系中公认的信号没有出现时,再降低 trim
computeAveExpr(features = , type = , trim = )—在定 trim 之前查看关心的配体、受体在各群中的组平均值;某基因在 triMean 下为 0、在 trim = 0.1 下不为 0,说明它的表达比例在 10%–25% 之间(Nature Protocols 推荐的做法)
population.sizeFALSETRUE 时概率乘以两群细胞比例,适合未分选样本;分选或按细胞类型富集的样本用 FALSE
nboot100置换检验次数,p 值精度为 1/nboot。实测 20 次 4.3 秒、938 条,100 次 22.6 秒、967 条,1,000 次 493 秒、972 条
filterCommunication 的 min.cells10删除细胞数小于等于 min.cells 的群(源码用 <=),恰好 10 个细胞的群也会被删
raw.useTRUEFALSE 时使用 smoothData 平滑后的表达,用于浅测序数据补偿亚基缺失,代价是可能引入假阳性

参数实测

本页实测:CellChat 2.2.0.9001,Seurat 官方 PBMC 3k 流程得到的 2,638 个细胞、9 个群(血小板 13 个、DC 32 个),nboot = 100。表中“通讯”是 subsetCommunication 返回的行数(来源群-目标群-配受体对)。Nature Protocols 在特应性皮炎皮肤数据(5,011 个细胞、12 个群)上比较 triMean、trim 0.1、trim 0.05,方向相同:trim 越小,配受体对和通路越多,新增的多为弱信号。

triMean 在浅测序数据上会漏掉已知信号

PBMC 3k(Cell Ranger 1.1,每细胞中位 817 个基因)用 triMean 时 CCL、CXCL、IFN-II 三条通路都没有。改为 trim = 0.1 后出现 NK→CD14 单核、NK→FCGR3A 单核、NK→DC 的 IFNG–IFNGR1/IFNGR2,与 NK 细胞分泌 IFN-γ 的已知生物学一致。深测序数据上两种方法的差距会小一些。

trim 越小,假阳性越多

trim = 0.1 时 CCL5–CCR1 的来源包括 B 细胞和初始 CD4 T 细胞,这些群只有少量细胞表达 CCL5。置换检验的显著性是相对于随机打乱标签而言的,表达比例刚过门槛的配体也能显著。trim = 0.05 的结果适合探索,写进论文的结论建议在 trim = 0.1 和 triMean 下都成立。

population.size 改变排名,不改变列表

truncatedMean 0.1 下,TRUE 与 FALSE 的显著通讯逐行一致(241 条),总强度从 5.71 降到 0.058。发送强度排名:FALSE 时 DC 第一,TRUE 时 Memory CD4 T 第一、DC 降到第七。DC 只有 32 个细胞,这个参数决定了“小群强信号”能否排在前面。

min.cells 主要影响小群

血小板 13 个细胞:min.cells = 10 保留,trim = 0.05 时有 45 条通讯涉及血小板;min.cells = 20 全部删除。identifyOverExpressedGenes 也有 min.cells = 10 的参数,只影响差异检验。

数据库type / trim通讯配受体对通路涉及血小板(min.cells = 10)min.cells = 20 时通讯
SecretedtriMean1521061151
SecretedtruncatedMean 0.251511063148
SecretedtruncatedMean 0.1241191313228
SecretedtruncatedMean 0.05402372345357
去掉 Non-proteintriMean437411436401
去掉 Non-proteintruncatedMean 0.1967793498869
去掉 Non-proteintruncatedMean 0.051,375116511861,189
全库truncatedMean 0.051,527130572031,324
population.size 取 TRUE 或 FALSE 时,每个组合的通讯行完全相同,所以表中未分列。

第 5 步

aggregateNet 产生两个矩阵:net$count 是两群之间显著配受体对的个数,net$weight 是这些对的通讯概率之和。数量反映“有多少种信号”,强度反映“信号总量”,两者的排名经常不同。

作图与系统分析r
groupSize <- as.numeric(table(cellchat@idents))
par(mfrow = c(1, 2), xpd = TRUE)
netVisual_circle(cellchat@net$count,  vertex.weight = groupSize, weight.scale = TRUE,
                 label.edge = FALSE, title.name = "Number of interactions")
netVisual_circle(cellchat@net$weight, vertex.weight = groupSize, weight.scale = TRUE,
                 label.edge = FALSE, title.name = "Interaction strength")

pathways.show <- "MIF"                       # 先确认它在 cellchat@netP$pathways 里
netVisual_aggregate(cellchat, signaling = pathways.show, layout = "chord")
netVisual_heatmap(cellchat, signaling = pathways.show, color.heatmap = "Reds")
netVisual_bubble(cellchat, sources.use = c("CD14 Mono", "FCGR3A Mono"),
                 targets.use = c("CD8 T", "NK", "B"), remove.isolate = FALSE)

cellchat <- netAnalysis_computeCentrality(cellchat, slot.name = "netP")
netAnalysis_signalingRole_scatter(cellchat)
netAnalysis_signalingRole_heatmap(cellchat, pattern = "outgoing") +
  netAnalysis_signalingRole_heatmap(cellchat, pattern = "incoming")

library(NMF); library(ggalluvial)
selectK(cellchat, pattern = "outgoing", k.range = 2:6, nrun = 10)   # 默认 2:10、nrun = 30 很慢
cellchat <- identifyCommunicationPatterns(cellchat, pattern = "outgoing", k = 3)
netAnalysis_river(cellchat, pattern = "outgoing")

总强度主要来自少数通路

PBMC 3k(trim = 0.1)中 MIF、GALECTIN、CypA 三条通路占总强度的 88%。全局圆图上的“最强发送者”基本反映这三条通路。解读全局网络前先看 netP 中各通路的强度,必要时用 signaling.exclude 或只画关心的通路。

信号角色分析

netAnalysis_computeCentrality 在每条通路的网络上计算出度(发送)、入度(接收)、流介数(中介)和信息中心性(影响者)。2D 散点图的横轴是发出强度、纵轴是接收强度,点大小是连接数,适合一句话概括“哪个群主要在发信号”。

模式识别与 selectK

identifyCommunicationPatterns 用 NMF 把群与通路分解为 k 个模式。selectK 默认 k = 2:10、每个 k 跑 30 次,本页 13 条通路、9 个群用了 78 秒;k = 2:6、nrun = 5 用 34 秒。通路达到 50 条以上、群达到 20 个以上时 selectK 需要数十分钟到数小时。官方解释是选 Cophenetic 和 Silhouette 开始明显下降前的 k;通路很少(少于 10 条)时模式分析信息量很低,可以跳过。

概率值本身没有绝对意义

通讯概率依赖于全局最大表达值、Hill 函数参数和平均方法。同一数据换 type 或 trim,概率会整体变化;只有参数和归一化方式相同时,数据集之间的概率才可比较。

图函数回答的问题注意
圆图(全局)netVisual_circle(net$count 或 net$weight)哪些群之间通讯多、哪个群是主要发送者比较两个数据集时用 edge.weight.max 统一尺度
单通路圆图、和弦图、层级图netVisual_aggregate(signaling = , layout = )某条通路由谁发、谁收通路不显著时报 There is no significant communication of XXX;先查 cellchat@netP$pathways
热图netVisual_heatmap(signaling = )某条通路在所有群对之间的强度矩阵颜色按该通路内部缩放,不能跨通路比较颜色
气泡图netVisual_bubble(sources.use, targets.use)指定群之间具体是哪些配受体对、概率和 p 值最适合放进论文正文;群可以用名称或序号指定
配受体和弦图netVisual_chord_gene某个群发出或收到的全部配受体对对太多时字重叠,调 small.gap 或限定 signaling
贡献图netAnalysis_contribution某条通路中哪个配受体对贡献最大—
信号角色netAnalysis_signalingRole_scatter / _heatmap / _network每个群是发送者、接收者、中介还是影响者先运行 netAnalysis_computeCentrality;热图按行缩放

第 6 步

CellChat 的比较流程是每组单独运行、再合并。前提是:两组用同一套注释(同一列、同样的名称)、同样的数据库子集和参数;两组的细胞类型集合一致,不一致时先 liftCellChat。

两组比较(Kang 2018 干扰素刺激 PBMC 上跑通)r
run_cellchat <- function(obj) {
  meta <- data.frame(labels = droplevels(obj$celltype),  # 本组没有的类型必须去掉
                      samples = factor(obj$sample), row.names = colnames(obj))
  cc <- createCellChat(LayerData(obj, assay = "RNA", layer = "data"), meta = meta, group.by = "labels")
  cc@DB <- subsetDB(CellChatDB.human, search = "Secreted Signaling", key = "annotation")
  cc <- subsetData(cc)
  cc <- identifyOverExpressedGenes(cc)
  cc <- identifyOverExpressedInteractions(cc)
  cc <- computeCommunProb(cc, type = "truncatedMean", trim = 0.1)  # 两组参数必须相同
  cc <- filterCommunication(cc, min.cells = 10)
  cc <- computeCommunProbPathway(cc)
  cc <- aggregateNet(cc)
  netAnalysis_computeCentrality(cc, slot.name = "netP")
}
# 两组使用同一套标签(同一列注释、同样的写法)
seu$celltype <- factor(seu$celltype)
cc.ctrl <- run_cellchat(subset(seu, stim == "CTRL"))
cc.stim <- run_cellchat(subset(seu, stim == "STIM"))

# 某组缺少某个细胞类型时,先补齐到同一组标签
grp <- union(levels(cc.ctrl@idents), levels(cc.stim@idents))
if (!identical(levels(cc.ctrl@idents), levels(cc.stim@idents))) {
  cc.ctrl <- liftCellChat(cc.ctrl, group.new = grp)
  cc.stim <- liftCellChat(cc.stim, group.new = grp)
}
object.list <- list(CTRL = cc.ctrl, STIM = cc.stim)
cellchat <- mergeCellChat(object.list, add.names = names(object.list))

compareInteractions(cellchat, show.legend = FALSE, group = c(1, 2)) +
  compareInteractions(cellchat, show.legend = FALSE, group = c(1, 2), measure = "weight")
netVisual_diffInteraction(cellchat, weight.scale = TRUE, measure = "weight")  # 红色 = STIM 增强
rankNet(cellchat, mode = "comparison", measure = "weight", stacked = TRUE, do.stat = TRUE)
netVisual_bubble(cellchat, sources.use = "CD14 Mono", comparison = c(1, 2),
                 max.dataset = 2, title.name = "Increased in STIM", angle.x = 45, remove.isolate = TRUE)

因子水平:每组 droplevels,再 lift

常见做法是给两组设同样的因子水平,以保证顺序一致。当某组缺少某个细胞类型时,这会让 computeCommunProb 报 factor levels 错误。正确顺序是每组单独 droplevels,计算完成后用 liftCellChat(group.new = union(...)) 补齐。不 lift 直接合并,mergeCellChat 本身不报错,后续 netVisual_diffInteraction 报 non-conformable arrays。

本页两组实测

Kang 2018 数据(CTRL 6,548 个细胞,STIM 7,451 个,13 类),Secreted、trim = 0.1:CTRL 421 条通讯、13 条通路,STIM 542 条、14 条;总强度 4.30 到 10.79。CD14 单核发出的增强配受体对包括 CXCL10/CXCL11–CXCR3、CCL8–CCR1、CCL7–CCR1,符合干扰素诱导趋化因子的预期。每组计算 26–43 秒,两组流程峰值内存 3.3–3.6 GB。

两种“差异”的区别

netVisual_bubble(comparison, max.dataset) 和 rankNet 比较的是通讯概率;netMappingDEG 按条件间差异表达筛选配体或受体上调的对。v2 用 presto 计算的 logFC 比 v1 小,官方把 thresh.fc 从 0.1 改为 0.05。同一配受体对可能同时出现在上调和下调结果中,原因是差异分析在每个细胞群内分别进行;需要忽略细胞群时设 group.DE.combined = TRUE。

统计检验的单位

rankNet(do.stat = TRUE) 的配对 Wilcoxon 检验以群对为单位,不考虑生物学重复。每组只有一个合并样本时,“显著上调的通路”只能说明这次测序中的差异。有多个样本时,用 min.samples 过滤,或改用以样本为单位建模的 MultiNicheNet、LIANA+ 做补充。

组成差异大的数据集

例如胚胎皮肤与成年伤口:netVisual_diffInteraction 和功能相似性(computeNetSimilarityPairwise(type = "functional"))不再适用,结构相似性(type = "structural")和各自的圆图仍可用。

作图时统一尺度

分别画两组的圆图时,用 getMaxWeight(object.list, attribute = c("idents", "count")) 取两组的最大值,传给 edge.weight.max 和 vertex.weight.max;否则两张图各自归一化,线宽不能比较。

排错

下表的报错原文来自本页复现或 GitHub issue,按出现的步骤排列。

并行:本页在 2,638 个细胞上实测,future::plan("multisession", workers = 4) 让 identifyOverExpressedGenes 从 0.1 秒变成 25.1 秒,computeCommunProb 从 5.8 秒变成 26.3 秒。GitHub #357 中多位用户报告相同现象(Ubuntu 上从 0.9 秒变成 368 秒)。PR #438(2026-02-19 合入)把置换检验循环改为并行,PR 作者报告 4 万个细胞、64 核从约 46 小时降到 5.2 小时。因此一万个细胞以下用 plan("sequential");大数据先确认安装的是 2026-02-19 之后的 main,再用 multisession,并设置 options(future.globals.maxSize = 4e9)。来源之间存在分歧:Nature Protocols 报告约 30 万个细胞的皮肤图谱推断约 15 分钟,而 GitHub 上多位用户报告数万细胞需要数小时,差异来自群数、数据库子集、nboot、版本和并行设置。另一位用户的经验是 9 万个细胞、6 个群、单核 500 GB 内存时,computeCommunProb 之前的步骤约 4 小时完成(GitHub #167)。

大数据还可以先降采样:Seurat 的 subset(obj, downsample = 500) 或 CellChat 的 sketchData,对大群抽样、小群全保留。降采样后显著通讯的列表通常稳定,强度会变化。

报错原文原因处理
Cell labels cannot contain `0`!直接用 Seurat 聚类号作标签factor(paste0("C", seurat_clusters))
Please check `unique(object@idents)` and ensure that the factor levels are correct!标签有 NA,或因子有未使用水平(subset 后最常见)删除 NA 细胞;meta$labels <- droplevels(meta$labels)
invalid 'row.names' length(Seurat 对象输入)Seurat v5 layer 处于拆分状态JoinLayers(obj) 后再创建
Error in if (sum(P1) == 0) : missing value where TRUE/FALSE needed输入含负值或 NA,例如 scale.data、integrated 或 Python 端标准化后的矩阵(GitHub #79)换成 log 归一化的 data 层
Error in integer(n) : invalid 'length' argument2023 年 11 月以前的 v2 用全库时 LTE4-DPEP1 复合物导致(GitHub #1);Seurat 也有同名的 subsetData更新 CellChat;调用写成 CellChat::subsetData(cellchat)
There is no significant communication of XXX该通路在本数据中不显著从 cellchat@netP$pathways 中选择通路
netVisual_circle: need finite 'xlim' valuesnet$count 全为 0:没有显著通讯查 subsetCommunication(cellchat) 行数;检查物种数据库、基因名、标签;放宽 type 或 trim
某组 aggregateNet 后某个群没有任何通讯该群细胞数 ≤ min.cells 被过滤,或该群确实无显著信号table(cellchat@idents) 确认细胞数;比较时用 liftCellChat 保持群一致
The input `color.use` should be a named vector!自定义颜色未命名或数量与群不一致color.use 用 setNames(颜色, levels(cellchat@idents))
Length of new attribute value...(netVisual_circle)igraph 1.4.0 的兼容问题(Nature Protocols 表 1)igraph 降到 1.3.5,或 updateCellChat(),或重装 CellChat
合并对象上 netAnalysis_computeCentrality 报错该函数要在每个单独对象上运行(Nature Protocols 表 1)对 object.list 中每个对象先运行 netAnalysis_computeCentrality,再 mergeCellChat
多核设置后运行变慢数倍multisession 的进程间传输开销;2026-02 以前的版本只并行了一小部分计算见下一段

工具选择

Dimitrov 等(Nature Communications 2022)比较了 16 个数据库和 7 种方法,结论是方法和数据库的选择都会显著改变预测结果。Liu 等(Genome Biology 2022)用空间转录组作参照评估 16 种方法,CellChat、CellPhoneDB、NicheNet、ICELLNET 整体表现较好,作者建议至少用两种方法交叉验证。

工具语言回答的问题适合不适合
CellChat v2R群与群之间哪些配受体对、哪些通路显著,网络角色和模式Seurat 用户;需要大量现成图和两组比较多样本、多条件的统计建模
CellPhoneDB v5Python哪些配受体对在特定群对中特异,考虑多亚基复合物人类数据;需要与 Vento-Tormo 实验室的图谱和空间微环境方法对接小鼠数据(需同源转换)
NicheNet / MultiNicheNetR哪个配体能解释接收细胞中的下游基因变化已有处理组与对照组的差异基因,想找上游配体;MultiNicheNet 支持多样本多条件没有对照组时的探索性描述
LIANA+Python(另有 R 版 liana)多种方法与数据库的共识排名;多样本可接 Tensor-cell2cell、MOFAScanpy 用户;想同时得到 CellChat、CellPhoneDB 等方法的打分只需要 CellChat 风格图表时
  • CellChat 的结果来自 mRNA 表达和先验数据库,表示“表达上具备通讯条件”,不能证明蛋白层面的相互作用发生。
  • 单细胞数据丢失了空间位置。两个群表达配体与受体,并不意味着它们在组织中相邻;空间数据或原位实验可以补上这一环。
  • 数据库之外的配受体对不会出现在结果中,CellChatDB 偏向文献中研究较多的信号。
  • 强度数值依赖参数与归一化,只在同一参数下比较。论文中应写清数据库子集、type、trim、population.size、min.cells 和版本。
  • CellChat 的跨条件分析以两两比较为主,多条件、时间序列的变化分析需要自己组织(Nature Protocols 列出的局限)。
  • 后续验证常用配体或受体的 RNAscope、免疫荧光共定位、受体阻断或中和抗体实验。

本页实测

本页实测:macOS arm64(Apple M2,8 核,16 GB),R 4.5.3、Seurat 5.5.1、CellChat 2.2.0.9001、presto 1.1.0、NMF 0.28、ComplexHeatmap 2.26.1、future 1.76.0。测试时同一台机器还在运行其他任务,耗时只用来看量级。

项目PBMC 3kKang 2018 两组
细胞与分群2,638 个细胞,9 群CTRL 6,548 / STIM 7,451 个细胞,13 类
默认流程(Secreted、triMean)152 条通讯、6 条通路;computeCommunProb 9.6 秒;峰值内存 1.28 GBCTRL 158 条 / STIM 254 条
truncatedMean 0.1241 条、13 条通路CTRL 421 条 / STIM 542 条;每组 26–43 秒
本页代码块全流程去掉 Non-protein + trim 0.1:967 条、34 条通路;含作图 56 秒,1.49 GB两组比较 73 秒,3.30 GB
selectK默认 78 秒;k = 2:6、nrun = 5 为 34 秒未运行
  • 本页复现的报错:标签含 0、标签含 NA、未使用因子水平、拆分 layer、两组因子水平相同时缺类型、未 lift 合并后作图。
  • 静默错误:counts 输入、scale.data 作为矩阵输入、LayerData 在拆分 layer 上只返回第一层,三者都不报错。
  • 空间转录组(datatype = "spatial"、SpatialCellChat)、smoothData、CellPhoneDB、NicheNet、LIANA+ 未在本机运行,只核对了文档中的函数与参数名。

国内经验

以下来自腾讯云开发者社区转载的公众号文章,只收录带报错原文或作者实测、且与官方文档或本页实测一致的内容。

聚类号 0 不能做标签

生信补给站(2023 年 11 月)在 Visium 数据上把 0–9 号聚类改为 C0–C9 后才跑通。本页复现的报错原文是 Cell labels cannot contain `0`!,维护者在 GitHub #16 的回复中也提到标签不能是 "0"。

“未使用的因子”实际是 NA

天意生信云(2025 年 3 月)遇到 factor levels 报错,检查发现每个水平都有细胞,真正原因是注释列里有 NA,删除这些细胞后解决。本页实测 NA 与未使用水平报同一条错误,排查时两种情况都要看:sum(is.na(meta$labels)) 和 setdiff(levels(meta$labels), unique(meta$labels))。

Apple 芯片 Mac 的编译报错

R小白(2023 年 5 月)在 M 芯片 Mac 上安装时遇到 no member named 'Rlog1p' in namespace 'std',设置 export PKG_CPPFLAGS="-DHAVE_WORKING_LOG1P" 后通过;CMake was not found on the PATH 用 conda install cmake 解决。本页用 conda 编译器与 R 4.5.3 安装时没有遇到,旧版 R 环境仍可参考。

快速检查用 nboot = 20

生信技能树(2025 年 6 月)的空转教程在调参阶段设 nboot = 20。本页实测 nboot = 20 与 100 的显著通讯重合 96%(930 / 967 条),耗时约为五分之一,适合先确定数据库和 trim,最终结果再用 100。

“v3”是独立的空转包

KS科研(2026 年 5 月)指出 SpatialCellChat 是从 CellChat 拆出的空间转录组包,安装依赖 MERINGUE、ALRA、BiocNeighbors、RcppML,与官方 README 一致;单细胞数据继续用 CellChat v2。

两处需要更新的旧写法

多篇中文教程仍写 computeCommunProb(trim = 0.1) 而不改 type,以及 Windows 用 plan("multiprocess")。前者 trim 不生效;后者在当前 future 中报 No such backend for futures: 'multiprocess',改用 plan("multisession") 或直接顺序运行。

交给 Agent

可以用一句话描述分析任务,由 Scientify 的科学智能体在云电脑中完成。

指令示例:“用 data/annotated.rds(Seurat v5,celltype 列为注释,condition 列为对照和处理,sample 列为 6 个样本)做 CellChat v2 分析:两组分别运行,数据库去掉 Non-protein Signaling,type 分别用 triMean 和 truncatedMean 0.1 并比较结果,filterCommunication 设 min.samples = 2;合并后输出两组的通讯数量与强度对比、增强和减弱的通路、巨噬细胞发出的上调配受体对气泡图,并整理成表。”

智能体在云电脑中安装 CellChat 及依赖,记录版本;检查 layer 是否拆分、标签是否有 NA 和未使用水平、两组细胞类型是否一致,必要时 liftCellChat;按两套参数运行并列出只在一种参数下出现的通讯;输出圆图、气泡图、信号角色图和差异表。智能体会对结果做对抗审阅,例如检查强度是否被 MIF 等少数通路主导、显著通讯是否只来自单个样本。工作区保留脚本、参数、日志和 rds 文件,可以复现;关闭本机后任务继续运行。

你仍需要自己核对:注释是否可靠,数据库子集是否与研究问题对应,候选配受体对在文献和组织背景中是否合理,以及哪些结论需要实验验证。

参考资料

常见问题

CellChat 结果里通讯很少,只有 MIF、GALECTIN 几条通路,正常吗?

在浅测序数据上用默认 triMean 时是常见现象。triMean 要求基因在一个群中至少 25% 的细胞表达。本页 PBMC 3k 上 triMean 只有 6 条通路,改为 type = "truncatedMean", trim = 0.1 后 13 条,数据库加入 Cell-Cell Contact 后 34 条。同时检查物种数据库、基因名和标签是否正确。

CellChat 输入用 counts 还是 data?

用 log 归一化的 data 层。用 counts 不会报错,但概率整体变得极小(本页实测总强度约为正确值的 1/800),强度比较失效。只有 counts 时用 CellChat::normalizeData(counts),它与 Seurat 的 LogNormalize 结果完全相同。

population.size 应该设 TRUE 还是 FALSE?

未分选的组织样本可设 TRUE,分选或富集过的样本设 FALSE。本页实测它不改变显著通讯的列表,只改变强度和排名:TRUE 时大群的发送强度排名靠前,小群(如 DC)会靠后。

两组比较时 mergeCellChat 后作图报 non-conformable arrays 怎么办?

两组的细胞类型集合不一致。每组计算时先 droplevels,计算完成后对缺少类型的对象运行 liftCellChat(obj, group.new = union(levels(a@idents), levels(b@idents))),再 mergeCellChat。

CellChat 运行太慢,开多核反而更慢?

一万个细胞以下用 future::plan("sequential"),本页实测 multisession 让两个步骤各慢 4 倍以上。大数据先更新到 2026-02-19 之后的 GitHub main(PR #438 并行了置换循环),再开 multisession;也可以用 nboot = 20 调参、对大群降采样。

CellChat 和 CellPhoneDB 选哪个?

Seurat 用户、需要两组比较和丰富图表时用 CellChat;人类数据、需要考虑复合物特异性或对接 Vento-Tormo 实验室图谱时用 CellPhoneDB。方法和数据库的选择会显著改变结果,重要结论建议用两种方法或 LIANA+ 的共识排名交叉验证。

把细胞通讯分析交给 Scientify

科学智能体在隔离云电脑中安装 CellChat、检查输入对象、按多套参数运行并比较、完成两组比较和作图,保留全部脚本、参数和日志。新注册用户免费获得 5 美元等值额度。