1. 单细胞轨迹分析到底在解决什么问题
单细胞测序技术发展到今天,大家手里攒下的数据量已经远远超出了“分群看marker”这个层面。你跑完Seurat或者Scanpy,拿到十几个cluster,UMAP图上花花绿绿一团一团的,然后呢?审稿人或者老板下一个问题一定是:这些细胞群体之间是什么关系?谁来源于谁?哪个群体更“原始”,哪个更“成熟”?这就是单细胞轨迹分析要回答的核心问题。
我做了几年单细胞数据分析,接触过的项目从早期胚胎发育、器官再生到肿瘤异质性,几乎每个课题都绕不开“分化潜能”和“状态转换”这两个关键词。Monocle和CytoTRACE是目前最常被搭配使用的两个工具,但它们的设计哲学完全不同。Monocle走的是“降维+拟时序”的路线,通过构建细胞之间的最小生成树来推断发育轨迹;CytoTRACE则是从基因表达多样性(gene expression diversity)的角度出发,直接给每个细胞打一个分化潜能分数。一个管“路径”,一个管“起点”,两者结合能把一个静态的细胞快照还原成动态的发育过程。
这篇文章适合谁看?如果你已经跑过基础的Seurat流程,能看懂UMAP和marker基因热图,但对“怎么做轨迹”“怎么解释分化潜能”还停留在“听说过”的阶段,那这篇内容就是写给你的。我会把Monocle和CytoTRACE的实操流程拆开揉碎,从数据准备、参数选择、结果解读到常见报错,全部按我实际项目中的做法来讲。不堆公式,不抄文档,只讲能直接上手的东西。
2. 工具选型与核心原理拆解
2.1 Monocle和CytoTRACE各自擅长什么
先说Monocle。目前主流用的是Monocle 3,它和Monocle 2在算法上有本质区别。Monocle 2用的是反向图嵌入(DDRTree),需要你手动指定root节点和分支点;Monocle 3改用了UMAP+最小生成树(MST)的思路,自动化程度更高,对大规模细胞数据的处理也更稳。我现在的项目基本都用Monocle 3,除非有特殊需求要复现老流程。
Monocle 3的核心逻辑是这样的:先把细胞投影到低维空间(默认UMAP),然后在这个空间里构建一棵最小生成树,树的节点是细胞,边是细胞之间的转录组相似性。轨迹的方向性通过“root”来定义,你可以根据生物学知识指定某个cluster作为起点,也可以让算法自动推断。最终输出的是每个细胞在轨迹上的伪时间(pseudotime)值,以及分支相关的基因表达变化。
CytoTRACE的切入点完全不同。它基于一个很朴素的观察:分化潜能越高的细胞,表达的基因种类越多(基因表达多样性越高)。干细胞能表达大量不同的基因,随着分化进行,细胞逐渐“锁定”到特定谱系,表达的基因种类减少。CytoTRACE用这个多样性指标,结合基因表达与多样性的相关性,计算出一个0到1之间的分化潜能分数。分数越高,细胞越“原始”。
这两个工具的关系不是替代,而是互补。Monocle告诉你细胞怎么走,CytoTRACE告诉你谁先出发。在实际项目中,我通常先用CytoTRACE确定分化潜能最高的细胞群体,把这个信息作为Monocle的root选择依据,这样轨迹的方向就有了生物学锚点,而不是完全靠算法猜。
2.2 为什么不能只用其中一个
只用Monocle的问题在于,轨迹的起点选择有时候很主观。Monocle 3虽然能自动推断root,但它的推断依据是转录组相似性和图结构,不一定符合生物学预期。我遇到过好几次,算法把一群明显是终末分化的细胞放到了轨迹起点,原因仅仅是这群细胞在UMAP上比较分散。这时候如果没有CytoTRACE的独立验证,你很难判断轨迹方向对不对。
只用CytoTRACE的问题更明显:它只给一个分数,不告诉你细胞之间的转换路径。你知道A群体比B群体更原始,但不知道A到B中间经历了哪些状态、哪些基因在驱动这个转变。而且CytoTRACE对某些特定组织(比如肿瘤)的适用性需要谨慎评估,因为肿瘤细胞的基因表达多样性可能受到基因组不稳定的干扰,分数解读不能照搬正常发育的逻辑。
所以我的标准流程是:CytoTRACE定起点和方向,Monocle 3建轨迹和找分支,最后用分支相关的差异基因分析来验证轨迹的生物学意义。这套组合拳打下来,结果的可信度比单用任何一个工具都高出一截。
2.3 数据准备阶段的几个关键决策
在跑轨迹分析之前,有几个决策会直接影响后续结果的质量,我一个个说。
第一个是细胞过滤。轨迹分析对低质量细胞非常敏感,因为MST会把它们当成真实的过渡状态。我的做法是在Seurat阶段就严格过滤:nFeature_RNA控制在500到6000之间(具体看组织类型),percent.mt小于10%(神经组织可以放宽到15%),同时用DoubletFinder去掉双细胞。宁可少要一些细胞,也不要让噪声细胞把轨迹带偏。
第二个是基因选择。Monocle 3默认使用所有基因,但实际跑的时候我建议先用Seurat的FindVariableFeatures选2000到3000个高变基因,然后把这些基因传给Monocle。全基因跑不是不行,但计算量大、噪声多,而且很多低表达基因对轨迹的贡献基本是随机的。用高变基因能把信号集中在真正驱动细胞状态差异的基因上。
第三个是批次效应处理。如果你的数据来自多个样本或多个时间点,一定要先做整合。Monocle 3本身没有内置的批次校正功能,所以要在Seurat或Scanpy阶段用Harmony、CCA或者scVI把批次处理好,再把整合后的表达矩阵和降维结果传给Monocle。我试过直接把未整合的数据扔给Monocle,结果MST把不同批次的同一群细胞分成了两条平行轨迹,完全没法解释。
3. Monocle 3实操流程与参数详解
3.1 从Seurat对象到CellDataSet的转换
Monocle 3支持直接读取Seurat对象,但中间有几个坑需要注意。我一般用以下代码做转换:
library(Seurat) library(monocle3) # 假设seu是你的Seurat对象,已经完成了聚类和UMAP # 提取表达矩阵、细胞元数据和基因注释 expression_matrix <- GetAssayData(seu, assay = "RNA", slot = "counts") cell_metadata <- seu@meta.data gene_annotation <- data.frame(gene_short_name = rownames(expression_matrix)) rownames(gene_annotation) <- rownames(expression_matrix) # 构建CellDataSet cds <- new_cell_data_set(expression_matrix, cell_metadata = cell_metadata, gene_metadata = gene_annotation)这里有个关键点:Monocle 3的new_cell_data_set默认使用counts矩阵,不要传归一化后的数据。它内部会自己做归一化和尺寸因子校正。如果你传了已经归一化的数据,后续的preprocess_cds会再归一化一次,导致表达值被过度校正。
另一个坑是基因注释的格式。gene_annotation必须是一个data.frame,行名是基因ID,且必须有一列叫gene_short_name。如果你的Seurat对象用的是基因symbol作为行名,那gene_short_name直接复制行名就行。如果用的是Ensembl ID,那需要额外提供symbol映射,否则后续画基因表达轨迹图的时候会显示一堆ID,没法看。
3.2 预处理与降维参数怎么定
转换完成后,下一步是preprocess_cds:
cds <- preprocess_cds(cds, num_dim = 50, method = "PCA")num_dim这个参数我一般设50,但实际用多少要看plot_pc_variance_explained的结果。如果前30个PC已经解释了80%以上的方差,那用30就够了。设太多会把噪声主成分带进去,导致UMAP上出现一些莫名其妙的细长分支。
接下来是批次校正。如果你的数据有批次,在preprocess_cds之后加一步:
cds <- align_cds(cds, alignment_group = "batch")这里的alignment_group填你的批次列名。Monocle 3用的是基于回归的校正方法,效果不如Harmony那么强,但胜在和后续的轨迹构建兼容性好。我试过先用Harmony整合再传给Monocle,结果UMAP和轨迹的对应关系有时候会错位,所以现在统一在Monocle内部做校正。
降维用UMAP:
cds <- reduce_dimension(cds, reduction_method = "UMAP", preprocess_method = "PCA")preprocess_method选PCA就行,不要选LSI(那是做ATAC用的)。UMAP的参数用默认的min_dist = 0.1和n_neighbors = 30在大多数情况下都合理。如果你的细胞数超过5万,可以把n_neighbors调到50,让UMAP更关注全局结构。
3.3 聚类与轨迹构建的衔接
Monocle 3有自己的聚类函数cluster_cells:
cds <- cluster_cells(cds, resolution = 1e-3)这个resolution参数和Seurat的resolution逻辑类似,但取值范围小得多。默认的1e-3对大多数数据都适用。如果你发现聚类太碎,调到5e-4;如果聚类太粗,调到2e-3。我一般会把这个结果和Seurat的聚类对比一下,如果Monocle的聚类和Seurat的聚类差异很大,说明预处理阶段可能有问题,需要回头检查。
轨迹构建是核心步骤:
cds <- learn_graph(cds, use_partition = TRUE)use_partition = TRUE表示在聚类分区的基础上构建轨迹,这样不同分区之间的轨迹不会乱连。如果你的细胞类型比较连续,没有明显的分区结构,可以设FALSE,让算法在全图上构建MST。
构建完轨迹后,需要指定root节点。有两种方式:
# 方式一:手动选择root细胞 cds <- order_cells(cds, root_cells = c("cell_id_1", "cell_id_2")) # 方式二:基于CytoTRACE结果选择root群体 # 假设CytoTRACE分数最高的群体是"stem_cluster" root_cells <- colnames(cds)[cds@clusters$UMAP$clusters == "stem_cluster"] cds <- order_cells(cds, root_cells = root_cells)我强烈推荐方式二。手动选root细胞很容易被个别细胞的噪声影响,而用CytoTRACE确定的root群体更稳健。具体操作是:先把CytoTRACE分数映射到Monocle的细胞元数据里,然后选分数最高的那个cluster的所有细胞作为root。
3.4 轨迹可视化与基因表达动态
跑完order_cells后,可以用plot_cells画轨迹图:
plot_cells(cds, color_cells_by = "pseudotime", label_cell_groups = FALSE, label_leaves = TRUE, label_branch_points = TRUE, graph_label_size = 3)这张图上,颜色从深到浅代表伪时间从早到晚,黑色的线和节点是MST的主干和分支点。我一般会同时画一张按cluster着色的图,对比着看哪些cluster位于轨迹的早期、哪些在晚期、哪些在分支点上。
基因表达动态分析用graph_test:
# 找轨迹相关的基因 pr_graph_test_res <- graph_test(cds, neighbor_graph = "principal_graph", cores = 8) pr_deg_ids <- row.names(subset(pr_graph_test_res, q_value < 0.05)) # 按表达模式聚类 gene_module_df <- find_gene_modules(cds[pr_deg_ids, ], resolution = 1e-2) # 可视化模块 plot_cells(cds, genes = gene_module_df, show_trajectory_graph = FALSE, label_cell_groups = FALSE)graph_test用的是Moran's I统计量,检验每个基因的表达是否在轨迹上呈现非随机的空间模式。q_value < 0.05是常用的阈值,但我一般还会加一个morans_I > 0.1的条件,过滤掉那些虽然显著但效应量很小的基因。
find_gene_modules把轨迹相关基因聚成模块,每个模块代表一种表达动态模式。比如模块1可能在早期高表达、后期下降,模块2可能在分支点之后才上升。这些模块的生物学解释才是轨迹分析最有价值的部分。
4. CytoTRACE实操与分化潜能解读
4.1 CytoTRACE的输入要求与运行
CytoTRACE有R包和Python版本,我用R包比较多,因为和Monocle的衔接更顺。安装:
# 从GitHub安装 devtools::install_github("digitalcytometry/cytotrace2", subdir = "cytotrace2_r")CytoTRACE 2是更新版本,支持人类和小鼠数据,输入可以是Seurat对象或表达矩阵。我一般直接传Seurat对象:
library(CytoTRACE2) # 假设seu是过滤后的Seurat对象 cytotrace_results <- cytotrace2(seu, is_seurat = TRUE, slot_type = "counts", species = "human", ncores = 8)slot_type一定要选counts,CytoTRACE对归一化方式敏感,传原始counts让它内部处理最稳妥。species参数选human或mouse,影响基因同源映射。
运行时间取决于细胞数,1万个细胞大概10到15分钟(8核)。如果细胞数超过5万,建议先做亚采样或者用Python版本,R版本在大数据量下内存消耗比较猛。
4.2 分化潜能分数的解读与验证
CytoTRACE输出的核心是CytoTRACE分数,范围0到1。分数越高,分化潜能越强。但怎么判断这个分数是否可信?我一般做三件事:
第一,看分数在UMAP上的分布。如果高分细胞集中在某个已知的干细胞/祖细胞群体,低分细胞集中在已知的终末分化群体,那说明结果和生物学知识一致,可信度高。如果高分细胞散落在各个群体里,那要么是数据质量有问题,要么是这个组织的分化层级本身就不明显。
第二,看分数和已知marker的关系。比如在造血系统中,如果HSC marker(CD34、Kit)高表达的细胞确实拿到高分,而成熟T细胞marker(CD3、CD8)高表达的细胞拿到低分,那就是一个强有力的验证。
第三,和Monocle的伪时间做相关性分析。理论上,CytoTRACE高分应该对应Monocle伪时间低值(早期)。如果两者相关性很弱甚至负相关,那说明两个工具对“起点”的判断不一致,需要回头检查root选择或者数据整合是否有问题。
# 计算CytoTRACE分数与pseudotime的相关性 cor.test(cytotrace_results$CytoTRACE, pseudotime(cds), method = "spearman")我一般期望看到Spearman相关系数在-0.5到-0.8之间。如果绝对值低于0.3,那这两个结果至少有一个需要重新审视。
4.3 把CytoTRACE结果整合进Monocle轨迹
整合的关键是把CytoTRACE分数加到Monocle的细胞元数据里,然后用它来辅助root选择和结果展示:
# 把CytoTRACE分数加到cds的元数据 cds$CytoTRACE <- cytotrace_results$CytoTRACE[match(colnames(cds), names(cytotrace_results$CytoTRACE))] # 按CytoTRACE分数着色画轨迹 plot_cells(cds, color_cells_by = "CytoTRACE", label_cell_groups = FALSE, show_trajectory_graph = TRUE)这张图能直观展示分化潜能沿轨迹的变化。理想情况下,你应该看到轨迹起点区域富集高CytoTRACE分数的细胞,随着伪时间增加,分数逐渐降低。如果轨迹中间某个分支点之后分数反而升高,那可能意味着这个分支代表了一种去分化或者状态逆转的过程,这在肿瘤或者再生研究中是有意义的发现。
我还会做一个CytoTRACE分数沿伪时间的散点图:
plot(pseudotime(cds), cds$CytoTRACE, pch = 16, cex = 0.5, xlab = "Pseudotime", ylab = "CytoTRACE Score", col = rgb(0, 0, 0, 0.3)) lines(loess.smooth(pseudotime(cds), cds$CytoTRACE), col = "red", lwd = 2)这个图能看出分化潜能随轨迹变化的整体趋势。如果趋势是单调下降的,说明轨迹方向合理;如果有波动,需要结合分支点的基因表达来具体分析。
5. 常见报错与排查经验实录
5.1 Monocle 3跑不动或者报内存错误
这是最常见的问题。Monocle 3的learn_graph步骤在细胞数超过3万时非常吃内存。我的解决方案有三个:
第一,先做细胞亚采样。如果总细胞数超过5万,按cluster比例随机抽取2到3万个细胞跑轨迹,跑通后再把全部细胞投影上去。Monocle 3支持project_cds函数做投影。
第二,用reduce_dimension时把num_dim从50降到30。少20个主成分能省不少内存,对轨迹结构的影响通常很小。
第三,把learn_graph的use_partition设为TRUE,这样算法只在分区内部构建MST,计算量会降低。
注意:亚采样会丢失一些稀有细胞群体,如果你的研究关注的是稀有过渡态细胞,不要亚采样,而是升级硬件或者用服务器跑。
5.2 轨迹出现不合理的“断裂”或“绕圈”
有时候UMAP上会看到轨迹线突然断掉,或者绕了一个大圈又回到原点。这通常是两个原因造成的:
一是UMAP的min_dist设得太小。min_dist = 0.01会让UMAP把细胞压得很紧,MST容易在局部形成环路。改成min_dist = 0.1或者0.3通常能解决。
二是批次效应没处理好。不同批次的细胞在UMAP上形成两个分离的岛,MST强行把它们连起来就会产生一条很长的“桥”。这时候需要回到align_cds步骤,检查批次校正是否充分。
5.3 CytoTRACE分数普遍偏高或偏低
如果所有细胞的CytoTRACE分数都在0.8以上,或者都在0.2以下,那说明分数没有区分度。可能的原因:
- 输入的是归一化数据而不是counts。CytoTRACE对输入数据的尺度很敏感,一定要传原始counts。
- 细胞周期效应没回归。增殖中的细胞基因表达多样性天然偏高,会拉高CytoTRACE分数。在Seurat阶段用
CellCycleScoring把S期和G2M期分数回归掉,再跑CytoTRACE。 - 数据质量太差。如果nFeature_RNA普遍低于500,基因表达多样性的计算会很不稳定。回到过滤步骤,提高nFeature_RNA的下限。
5.4 轨迹相关基因太少或者太多
graph_test跑出来显著基因少于100个,或者多于5000个,都不太正常。太少说明轨迹结构本身不清晰,可能是细胞类型太单一或者预处理过度;太多说明阈值太松,或者数据里存在强批次效应导致假阳性。
我的经验值是:一个中等复杂度的发育轨迹(3到5个分支),显著基因在500到2000之间比较合理。如果偏离这个范围,先检查q_value阈值,再检查数据整合质量。
5.5 分支点基因表达模式无法解释
有时候find_gene_modules跑出来的模块,基因表达模式在分支点前后没有明显差异。这通常是因为分支点附近的细胞太少,统计功效不足。解决办法:
- 在
learn_graph之前,对分支点附近的细胞做富集分析,确保有足够的细胞支持分支。 - 降低
find_gene_modules的resolution参数,让模块更粗,每个模块包含更多基因,模式更稳定。 - 如果分支本身在生物学上就不明确,考虑简化轨迹模型,把分支合并。
6. 从轨迹到生物学故事的转化技巧
6.1 如何选择展示的基因和模块
跑完轨迹分析,你手里会有几百上千个轨迹相关基因。全放上去肯定不行,审稿人也不会看。我的筛选策略是:
第一,优先选已知的谱系marker。比如做神经发育,SOX2、NES、TUBB3、GFAP这些基因必须展示,因为它们能给读者一个熟悉的锚点。
第二,选graph_test里Moran's I最高的前20个基因。这些是轨迹结构最强的驱动基因,通常包含一些意想不到的调控因子。
第三,选每个基因模块里表达模式最清晰的代表基因。一个模块选3到5个就够,不要把一个模块的所有基因都画出来。
展示方式上,我一般用plot_genes_in_pseudotime画基因表达沿伪时间的平滑曲线,每个分支用不同颜色。这张图比热图更直观,能清楚看到基因在哪个分支点开始分化。
6.2 分支点的差异表达分析
分支点是轨迹分析最有价值的部分,因为它代表了细胞命运决定的关键节点。Monocle 3提供了graph_test的neighbor_graph = "principal_graph"选项来找分支相关基因,但我更推荐手动做分支间的差异表达:
# 假设分支点把细胞分成两个分支:branch1和branch2 branch1_cells <- colnames(cds)[cds@principal_graph_aux$UMAP$pr_graph_cell_proj_closest_vertex %in% branch1_vertices] branch2_cells <- colnames(cds)[cds@principal_graph_aux$UMAP$pr_graph_cell_proj_closest_vertex %in% branch2_vertices] # 用Seurat做差异表达 de_res <- FindMarkers(seu, ident.1 = branch1_cells, ident.2 = branch2_cells, logfc.threshold = 0.5, min.pct = 0.25)这样得到的差异基因直接对应分支命运决定,比全轨迹的graph_test更有针对性。我一般会把这些基因做GO富集或者KEGG通路分析,看看两个分支分别对应什么生物学过程。
6.3 轨迹结果的独立验证思路
轨迹分析本质上是计算推断,不是实验证据。所以有条件的话,一定要做独立验证。我常用的验证手段:
- 用RNA速率(RNA velocity)验证轨迹方向。如果RNA速率箭头和Monocle伪时间方向一致,那轨迹的可信度就很高。
- 用已知的时间序列数据验证。如果你的数据有多个时间点,检查轨迹上的细胞是否按时间点顺序分布。
- 用功能实验验证关键分支基因。这个成本高,但如果是核心结论,值得做。
提示:RNA速率和Monocle的整合可以用
velocyto.R或者scVelo,但要注意RNA速率对剪接信息的依赖,不是所有数据都能跑出可靠结果。
7. 参数速查与避坑清单
7.1 关键参数推荐值
| 步骤 | 参数 | 推荐值 | 说明 |
|---|---|---|---|
| Seurat过滤 | nFeature_RNA | 500-6000 | 根据组织类型调整 |
| Seurat过滤 | percent.mt | <10% | 神经组织可放宽到15% |
| preprocess_cds | num_dim | 30-50 | 看PC方差解释率 |
| reduce_dimension | min_dist | 0.1-0.3 | 太小容易绕圈 |
| reduce_dimension | n_neighbors | 30-50 | 大细胞数用50 |
| cluster_cells | resolution | 1e-3 | 范围5e-4到2e-3 |
| graph_test | q_value | <0.05 | 可加morans_I>0.1 |
| find_gene_modules | resolution | 1e-2 | 范围5e-3到5e-2 |
| CytoTRACE | slot_type | counts | 必须用原始counts |
| CytoTRACE | species | human/mouse | 影响同源映射 |
7.2 我踩过的五个坑
第一个坑:用归一化数据跑CytoTRACE。结果分数全部挤在0.5附近,完全没有区分度。后来改成counts,分数分布立刻拉开了。
第二个坑:Monocle 3的root选在了终末分化群体。原因是那个群体在UMAP上最分散,MST把它当成了起点。后来用CytoTRACE分数辅助选root,问题解决。
第三个坑:批次校正不充分导致轨迹分叉。两个批次的同一群细胞被MST连成了一条长桥,伪时间在这段桥上完全失真。后来在align_cds里加强了校正,桥消失了。
第四个坑:graph_test跑出来3000多个显著基因,GO富集全是核糖体相关。原因是数据里残留了细胞周期效应,增殖细胞的基因表达模式主导了轨迹信号。回归细胞周期分数后,显著基因降到800个,富集结果变成了神经发育相关。
第五个坑:分支点基因模块无法解释。后来发现是分支点附近的细胞数太少(不到50个),统计功效不足。把cluster_cells的resolution调小,让分支点附近的细胞归入同一个cluster,问题缓解。
7.3 什么情况下不适合做轨迹分析
不是所有单细胞数据都适合跑轨迹。以下几种情况我建议直接放弃:
- 细胞类型之间没有明显的发育关系。比如你把外周血里的T细胞、B细胞、单核细胞放在一起跑轨迹,得到的“轨迹”只是不同谱系之间的转录组距离,没有生物学意义。
- 数据质量太差,nFeature_RNA中位数低于300。这种数据连细胞类型都分不清楚,更别说轨迹了。
- 样本量太小,每个cluster不到50个细胞。MST在这种稀疏数据上极不稳定,结果不可重复。
- 没有明确的生物学起点。如果你完全不知道哪个群体更原始,CytoTRACE和Monocle的root选择都会变成盲猜。
遇到这些情况,老老实实做差异表达和富集分析,比强行跑轨迹然后编故事要靠谱得多。
8. 结果展示与图表制作建议
8.1 轨迹图的美化与标注
Monocle 3默认的plot_cells出图比较朴素,直接放文章里不够好看。我一般用ggplot2的语法做二次美化:
p <- plot_cells(cds, color_cells_by = "pseudotime", label_cell_groups = FALSE, label_leaves = TRUE, label_branch_points = TRUE, graph_label_size = 3) + scale_color_viridis_c(option = "plasma") + theme(legend.position = "right", panel.background = element_rect(fill = "white"), axis.line = element_line(color = "black")) ggsave("trajectory_pseudotime.pdf", p, width = 6, height = 5)配色上,伪时间用viridis的plasma或者magma,CytoTRACE分数用RdYlBu反向。分支点和叶节点用不同形状标注,图例里写清楚。
8.2 基因表达动态图的排版
plot_genes_in_pseudotime默认把多个基因分面画,但分面太多会显得碎。我一般选6到9个基因,分3行3列,每个基因的曲线用loess平滑,置信区间用半透明填充。如果基因属于不同模块,用不同颜色区分。
对于分支相关的基因,我会在图上用竖虚线标出分支点的伪时间位置,让读者一眼看出基因是在分支前还是分支后开始差异表达。
8.3 补充材料的整理
轨迹分析的补充材料我一般包括:
- 所有轨迹相关基因的
graph_test结果表(按Moran's I排序) - 基因模块的完整列表和每个模块的GO富集结果
- CytoTRACE分数与伪时间的相关性散点图
- 不同参数下的轨迹稳定性测试(比如num_dim从30到50,轨迹结构是否一致)
这些材料不放在正文里,但审稿人问起来能直接给,省得临时补分析。
9. 我个人在实际操作中的几点体会
做了这么多单细胞轨迹项目,最大的体会是:轨迹分析的结果好不好,八成取决于前面的数据预处理和生物学问题设计,只有两成取决于Monocle和CytoTRACE的参数调优。我见过太多人花大量时间调learn_graph的参数,但数据里的批次效应和低质量细胞根本没处理干净,调什么参数都是白搭。
另一个体会是,不要迷信算法的自动推断。Monocle 3的自动root选择和CytoTRACE的分数都是参考,最终的方向判断一定要结合生物学知识。如果你对系统的发育层级完全没有先验知识,那轨迹分析可能不是最合适的工具,先做marker基因的文献调研和实验验证更重要。
最后分享一个小技巧:跑完轨迹后,把伪时间值导出来,和已知的发育时间点或者临床指标做关联分析。比如在肿瘤数据里,把伪时间和病理分级做Spearman相关,如果高伪时间对应高分级,那轨迹的临床意义就立住了。这一步不需要额外实验,但能让你的轨迹分析从“计算练习”变成“有生物学意义的发现”。