做基因家族扩张收缩分析,CAFE5这个软件绕不开。如果你手里刚好有OrthoFinder聚类出的基因家族矩阵,也有一棵带分支时间的系统发育树,想搞清楚哪些基因家族在特定谱系里变多变少,那这篇就是给你准备的。我会把CAFE5从输入文件准备、命令行参数、结果解读,到最终可视化图表的完整流程拆开讲,把我实际跑项目时踩过的坑和总结出的经验一并写进来。
1. 先搞明白CAFE5到底在算什么
1.1 基因家族扩张收缩的生物学意义
物种间基因数目的差异不是随机的。一个基因在祖先基因组中存在,随着演化发生复制、丢失、假基因化,到了现生物种里,同一个基因家族的成员数量可能完全不同。比如某些植物里NBS-LRR抗病基因家族动辄几百个成员,而另一些物种只有几十个,这种扩张往往与适应性演化有关;反过来,有些寄生生物会丢掉大量代谢通路相关基因,出现明显的收缩。
基因家族扩张收缩分析,本质上就是在系统发育框架下,把“祖先节点基因数”估算出来,然后比较每个分支上家族大小的变化是否显著偏离随机漂变模型。显著的扩张或收缩通常被认为与环境适应、物种特异性表型相关,所以这类分析在比较基因组学论文里几乎是标配。
CAFE5(Computational Analysis of gene Family Evolution)就是专门干这件事的工具。它输入一棵树和一个基因家族计数矩阵,用随机出生-死亡模型模拟基因获得与丢失过程,输出每个基因家族在谱系上最可能的大小变化以及显著性检验结果。
1.2 CAFE5的核心模型与λ参数怎么选
CAFE5的核心是一个随机出生-死亡过程,简单理解就是:沿系统发育树的每条枝,基因家族大小按一定的“出生率”(获得新基因)和“死亡率”(丢失现有基因)发生随机变化。这个过程中有一个关键参数叫λ,代表基因获得/丢失的整体速率,是整个模型里最有生物学意义的全局参数。
CAFE5相比老版本CAFE 4.x最大的改进之一,是支持对树的不同分支分配不同的λ。比如你怀疑某个分支演化速率整体偏高,可以指定多个λ让模型去拟合。命令行里用 -k 参数控制λ个数:-k 1表示全树共享一个λ,-k 3表示允许3个不同的λ值分布在树上。实际分析里,可以先跑一个全局λ,再尝试多λ模型,用模型比较的方式判断哪一组更合理。
另一个关键点是显著性检验。CAFE5会为每个基因家族计算family-wide p-value,还会用Viterbi算法估算每个内部节点的最可能基因数。显著扩张/收缩的家族通常以 p-value < 0.05 为界筛选,后续再做功能富集,这是比较基因组学项目的标准流程。
1.3 为什么选择CAFE5而不是老版本
如果你是第一次做这个分析,直接选CAFE5。老版CAFE 4.x在32位系统上容易遇到内存问题,处理超大规模矩阵时效率偏低,输出结果也需要写更多脚本去解析。CAFE5用C++重写了核心算法,支持64位平台,命令行更简洁,结果文件结构清晰,特别是Base_change.tab和Base_family_results.txt,下游筛选非常方便。
另外,CAFE5对输入树的容忍度比老版本更友好,它对超度量树的检验仍然严格,但是报错信息比CAFE 4.x明确得多。对我这种习惯先跑通再细抠参数的人来说,能少花很多排查时间。
2. 开始前的硬性准备:这三大输入文件一个都不能少
2.1 超度量树:所有分析的前提
CAFE5要求输入一棵超度量树(ultrametric tree),也就是所有现生物种到根节点的距离相等。我从第一次跑就记住了一个教训:树不满足超度量,后面的分析结果无论多漂亮都没法用,根源上就错了。
超度量树的含义是:谱系间比较基因家族速率时,每个物种“可演化时间”要一致。你手里的树如果来自OrthoFinder的物种树,通常只有拓扑结构,没有进化时间信息,分支长度代表的是序列差异度,不能直接拿来用。需要先用单拷贝直系同源基因构建系统发育树,再用r8s或MCMCtree做分子钟校准,转换成分支长度代表时间(单位常用百万年)的超度量树。
手工检查树是否超度量其实很简单,用R的ape包,一行代码就能检验:
library(ape) tree <- read.tree("ultrametric_tree.nwk") library(phytools) is.ultrametric(tree) # 返回 TRUE 才符合 CAFE5 要求我自己的建议是,宁可多花一个下午处理树,也别把不靠谱的树喂给CAFE5。因为最终可视化时,树上的扩张/收缩数目、显著性标注,全部依赖于每个节点的祖先状态估算,树的分支长度一旦失真,祖先估算就会整体偏移。
2.2 基因家族计数矩阵:上游聚类结果怎么转
计数矩阵的每一行是一个基因家族,每一列是一个物种,每个数值代表该家族在对应物种中的基因拷贝数。绝大多数情况下,这个矩阵可以直接从OrthoFinder的结果里获取,路径一般是Orthogroups/Orthogroups.GeneCount.tsv。
但这份文件不能直接喂给CAFE5,需要做几项清洗:
第一,去掉表头里多余的描述列。OrthoFinder的GeneCount文件包含Orthogroup、Total以及各物种名共三组信息,CAFE5需要的是纯数值矩阵加一个格式化的表头。第二,如果有转录本ID(比如gene|transcript),需要按基因去重,避免同一个基因被重复计数。第三,基因家族规模实在太大的(比如超过200个拷贝的),建议单独评估,因为极端大基因家族容易让模型估计失真。
我平时会先用OrthoFinder原始结果生成一个未过滤矩阵,再看一下每个物种的总基因数分布,然后按“至少在一个物种中出现”以及“基因家族总数不过大”过滤。过滤后转换成CAFE5期望的文本格式,再开始正式分析。
2.3 文件格式细节与命名习惯
CAFE5的输入文件格式在生产文档里写得清楚,但很多人第一次还是会栽跟头,我整理成一张对照表:
| 项目 | 要求 | 常见错误 |
|---|---|---|
| 树文件 | Newick格式,分号结尾,分支长度必须存在 | 末尾漏分号、分支长度为0 |
| 计数矩阵第一行 | Desc: <空格分隔的物种名> | 写成了Description或者用逗号分隔 |
| 计数矩阵数据行 | 家族名后接空格分隔的整数数组 | 缺家族名、数值之间有多个空格没问题但不要制表符混用 |
| 缺失值 | CAFE5支持用基因家族在物种中缺失的计数,但不能有字符串NA | 空字段或NA会直接报错 |
计数矩阵的格式长这样:
Desc: Species_A Species_B Species_C Species_D Family1 10 5 0 12 Family2 3 8 7 6注意这里没有额外的空格命名列,也没有引号包裹物种名。文件保存为纯文本即可,扩展名随意,但我习惯用.txt。
有一个很多人都忽略的点:CAFE5对“表头名称”敏感程度没有那么高,但千万不能有中文空格或者特殊符号。如果你从Windows复制数据到服务器,务必用dos2unix转换换行符,我碰到过因为\r导致物种名对不上号的情况。
3. CAFE5完整实操:从命令到结果文件的逐行解读
3.1 安装:conda一条命令搞定
CAFE5的安装比老版本省心太多,推荐直接用conda安装:
conda create -n cafe5 -c bioconda cafe5 conda activate cafe5 cafe5 -h如果conda源有问题,也可以直接从GitHub clone源码编译,依赖主要是Boost和GSL,编译过程也不算复杂。但我个人的实际体验是,conda那套闭眼装就行,能省出不少时间。
装好之后,建议先跑一下自带的示例数据确认环境没问题,再去跑自己的数据。CAFE5安装包里有examples目录,里面有树文件和计数矩阵,运行一遍能顺便熟悉命令行参数。
3.2 核心命令与参数详解
CAFE5的典型运行命令长这样:
cafe5 -i Filtered_matrix.txt -t ultrametric_tree.nwk -o cafe5_output -c 8 -k 1每个参数的含义:
| 参数 | 作用 | 我的建议 |
|---|---|---|
-i | 指定输入计数矩阵 | 必须提前过滤清洗 |
-t | 指定超度量树文件 | 先跑is.ultrametric确认 |
-o | 输出目录 | 建议独立目录,避免污染 |
-c | CPU线程数 | 基因家族多时直接给满 |
-k | λ分组的数量 | 一般从1开始,再尝试3或5 |
-p | 指定λ初始值 | 不指定时CAFE5自动估计 |
-f | 输出结果的fdr校正 | 筛选显著家族建议加上 |
-k参数是CAFE5的一个大亮点。如果你怀疑某些谱系的基因获得/丢失速率明显快过背景,可以让模型学习多个λ。比如设定-k 3,CAFE5会尝试把树分成3个速率区组,并输出每个分支属于哪个速率组。这个结果本身就可以当作“哪些支系演化速率快”的证据。
但注意:多λ模型不是自动就更好,需要对比对数似然值。比如-k 1和-k 3都跑一遍,比较likelihood的改善程度,理解起来很像在数据可视化里对比不同拟合模型的R平方,改善不大就选简单的。
3.3 结果文件解读:Base_change.tab与Final_tree等
CAFE5跑完,输出目录里会出现一批文件。我每次拿到结果都会先打开这几个:
Base_change.tab:每个基因家族在每个分支上变化的最优估计,数值为正表示扩张,为负表示收缩。这是最核心的中间结果,后续绘制家族大小变化热图全靠它。Base_family_results.txt:每个基因家族的最终结果,包含family-wide p-value和Viterbi p-value。筛选显著家族时主要看这个文件。Final_tree.txt:带每个分支扩张/收缩数目的树,可以作为可视化底稿输入到FigTree或iTOL中。Base_asr.tab:内部节点祖先基因数估计。
实际做筛选时,我通常用一行awk解决:
awk 'NR>1 && $NF < 0.05 {print}' cafe5_output/Base_family_results.txt | wc -l这里$NF是最后一列,也就是显著性p-value,筛出小于0.05的家族数量。
然后从Base_change.tab里把显著家族对应到具体分支,统计每个分支显著扩张/收缩家族数量。统计结果可以直接画在树上,形成投影效果。很多高分文章里的那种“树节点上红蓝数字”图,就是从这里来的。
4. 可视化:把干巴巴的结果变成能放进论文的图
4.1 从CAFE5结果到可视化图表的基础思路
CAFE5本身不生产最终论文级图表,它输出的是表格和带注释的树文件。真正画图还需要自己写脚本或借助其他工具。可视化的目标很明确:让读者一眼看出哪些谱系发生了大规模扩张/收缩,以及显著基因家族的数量在哪些节点集中。
我习惯把可视化拆成三层:
- 第一层:系统发育树本身,标注每个分支的扩张/收缩数字。
- 第二层:显著扩张/收缩家族的柱状图或堆叠图,按分支展示数量。
- 第三层:对显著家族做功能富集,用气泡图或条形图展示富集的GO/KEGG条目。
这三层可以整合成一幅多面板图,也可以拆成独立图放进正文和补充材料。个人经验是:主图用“树+节点数字”这种最直观的形式,补充图再放富集结果,信息量足而且不显得堆砌。
4.2 用ggtree快速画出树上的扩张收缩标注
R语言的ggtree是我现在最顺手的方案。读取CAFE5的Final_tree.txt,把扩张/收缩数字解析成节点属性,然后映射到标签上,代码并不复杂。
library(ggtree) library(ggplot2) tree <- read.tree("cafe5_output/Final_tree.txt") # 假设能解析出 N扩张 / N收缩,作为节点标签 p <- ggtree(tree, size=0.8) + geom_tiplab(size=4) + geom_nodelab(aes(label=label), size=3, hjust=-0.2) p + geom_treescale()如果想让图更有“数据可视化”味,还可以在树旁边加一个热图面板,展示每个显著基因家族的拷贝数在现生物种中的分布。ggtree支持gheatmap,把计数矩阵和树拼接在一张图上,这种组合图在比较基因组学论文里很常见。
关键细节是:要把Base_asr.tab和Base_change.tab里的祖先状态映射回树节点,否则树节点上只有物种名,无法体现祖先层面的变化。
4.3 进阶:整合所有分析结果,做一张总览大图
做完整套CAFE5分析之后,我强烈建议把所有结果整合到一张总览图上,类似于平时做数据可视化大屏的思路——把分散的信息图层叠加到同一个画布上,方便审稿人和合作者快速抓重点。
我的总览图结构大概是:
- 顶部:带分支时间尺度的系统发育树,分支颜色表示不同速率区组。
- 中段:每个分支的显著扩张/收缩家族数量柱状图,红蓝配色对应扩张/收缩。
- 下半:关键显著基因家族在物种间的拷贝数热图,附基因ID和名称。
- 侧栏或底部:这些家族的GO/KEGG富集条目气泡图。
图用R的patchwork或cowplot拼接,逻辑上很像把多个可视化图表拼成一块可视化大屏。着色尽量统一:扩张用暖色系(红/橙),收缩用冷色系(蓝/紫),显著性则用透明度或点大小来体现。这样图一出,读者立刻能抓到重点。
4.4 在线工具与交互式可视化的补充
R脚本适合出静态图,如果要做交互式可视化,iTOL和Evolview是两个很好的补充。CAFE5的Final_tree.txt可以直接上传到iTOL,在网页端对分支进行着色和数字标注。Evolview还专门支持导入“每个分支的变化数值”,生成带柱状图叠加的系统发育树,操作门槛比R脚本低很多,适合组里没有专门做可视化的同学快速出图。
不过在线工具导出图片的分辨率和定制自由度,始终比不上自己用R或者Python画。我的习惯是在线工具用于快速检查结果,正式投稿的图一律用脚本重画。
5. 那些年踩过的坑:CAFE5常见报错与避坑实录
5.1 树文件:非超度量树和零分支长度
CAFE5启动时如果报错说树不是超度量树,第一反应不要怀疑软件,回去检查树。最常见的坑是用序列差异度树直接跑。另一个坑是树里某些分支长度非常小,接近0,CAFE5在计算转移概率矩阵时可能出现数值异常。解决办法是检查是否有多叉树,CAFE5要求树是二叉的,如果存在多叉需要先随机解析或者用r8s处理。
还有一次我遇到一个很隐蔽的问题:树的物种名和计数矩阵表头物种名顺序不一致。CAFE5不是按名称匹配,而是按文件中的顺序对应。如果两边顺序不一致,结果会“错位”得非常离谱,而且不会报错。跑之前一定用脚本核对物种名列表,顺序一致再开始。
5.2 计数矩阵:缺失值和基因家族大小分布
计数矩阵里0是很正常的,表示该家族在某个物种中不存在,但保留太多全部为0的行会让分析变慢且没有意义。建议把在所有物种中拷贝数总和小于某个阈值(比如1)的家族过滤掉。
另外一个常见坑是基因家族名称里有特殊符号。OrthoFinder的输出家族名一般安全,但如果自己构建矩阵,不要用带空格、冒号、括号的名称,CAFE5解析时容易出问题。
基因家族太多也会导致运行时间暴增。按我自己的项目经验,2万个左右家族用8线程跑,大约几十分钟到一个小时之间,但如果超过5万家族,耗时和内存都会明显上涨。可以先跑一个抽样的小矩阵测试整个流程是否通畅,再跑全量。
5.3 显著性家族太少或者太多怎么办
筛选完显著家族,如果发现数量为0,先别急着改阈值。检查一下是不是λ估计太大,导致模型认为所有变化都不过是一般速率波动。可以用-p参数手动指定一个较小的λ初始值,观察结果变化。
反过来,如果显著家族数量多到几千个,通常不是生物学信号强,而是数据质量出了状况:可能是某几个物种的基因组组装质量差导致基因注释不全,表现为大量家族“收缩”。这其实是在用CAFE5跑之前就该发现的,但很多人(包括我早期)都是等结果出来才意识到。建议在前期就统计每个物种的基因总数和BUSCO完整性,如果某些物种明显偏低,要么补数据,要么在解释结果时格外小心。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 报错“not ultrametric” | 树未做时间校准 | 用r8s/MCMCtree重新校准 |
| 物种数对不上 | 树和矩阵物种顺序不一致 | 写脚本核对物种列表 |
| 所有家族都不显著 | λ估计过大或过滤太严 | 调整 -p、放宽过滤条件 |
| 显著家族异常多 | 某个物种基因组质量差 | 检查BUSCO、序列完整性 |
| 内存不足 | 家族数过多或线程设置过高 | 减小输入、拆分运行 |
5.4 一个关于“可视化结果”的提醒
做可视化时,最怕的就是“美则美矣,没有意义”。比如把树上的数字标得很大很醒目,却忽略了显著性筛选,把所有扩张收缩都当作生物学结果展示。这一点尤其要提醒刚入门的朋友:先圈定显著家族,再做可视化,“显著”的标签应该贯穿到底。
我在最终图里,通常会在显著家族的柱状图上方标一个星号或者数字,同时在图注里写明统计阈值和检验方法。审稿人看到你用了CAFE5,一定会问p-value的校正方式。CAFE5默认提供原始p-value,建议在筛选时用FDR校正(运行时加-f参数),或者在后期用P.adjust再校正一次。这步处理得规范,能避免不少补分析的工作量。
写在最后
CAFE5跑起来不难,难的是把上游数据准备干净、把参数选对、把结果解释得有说服力。我做了几次基因家族演化项目后最大的体会是:CAFE5本身可能十分钟就跑完了,但花在树校准和矩阵清洗上的时间,往往占了整个分析的三分之二。可视化的部分更是如此,一张能讲清楚故事的总览图,往往是先花了大量时间梳理每一层数据逻辑,才在最后一环节顺手画出好图。
如果你正准备跑自己的数据,建议先从候选物种的基因组质量核查开始,逐步推进。使用CAFE5时多花一点时间读报错信息,细心检查树和矩阵的配对关系,做可视化时保持“显著性为主、美观为辅”的原则,整个流程会更加顺畅。