写在前面:今天突然想写这个教程,花了一下午看资料,其实我前面是有一些基础的,但是看的还是会很乱,所以想把这个包的脉络写一下,希望能够可以跟大家讨论一下并且自己以后使用这个包的时候也相当于翻阅说明书吧!!!
首先讲一段话:
我的一个使用情景是,当我跑完seruat的标准流程后,不可能只看细胞数量之间的差异吧,所以想看细胞之间的发育轨迹,就想到了monocle,Attention:我是已经完成了seurat分析!!
所以大家能从上面这段话得到什么信息呢?信息:就是我只想用monocle对我的细胞进行轨迹分析,然而monocle这个包功能其实不单单是进行轨迹分析,它其实一直想要代替seruat这个包,所以它几乎包括seurat所有的分析流程
假如你是没有进行seurat分析的话,你可以尝试一下用monocle进行分析
#加载包
library(Seurat)
library(monocle3)
library(tidyverse)
library(patchwork)
#导入数据
#在这里你需要导入三个数据:细胞的表达矩阵,meta信息,gene_annotation
data <- 细胞的表达矩阵
cell_metadata <- meta信息
gene_annotation <- data.frame(gene_short_name = rownames(data))
rownames(gene_annotation) <- rownames(data)
#创建CDS对象
cds <- new_cell_data_set(data,
cell_metadata = cell_metadata,
gene_metadata = gene_annotation) #这样就获得了monocle的对象了,可类比于创建seurat对象
#思考一下我们在创建了seurat对象后要干嘛呢?降维聚类分群,那么monocle也不例外
#NormalizeData+ScaleData+RunPCA
cds <- preprocess_cds(cds, num_dim = 50) #preprocess_cds函数相当于seurat中NormalizeData+ScaleData+RunPCA
plot_pc_variance_explained(cds) #像seurat一样展示pc数
#umap降维
cds <- reduce_dimension(cds,preprocess_method = "PCA") #preprocess_method默认是PCA
#tSNE降维
cds <- reduce_dimension(cds, reduction_method="tSNE")
#聚类
cds <- cluster_cells(cds)
#那么我们到这里就完成了分群了,后面就是对于每一个群的细胞注释和细胞类型的结果展示了,这个大家可以去看周运来老师的,而我的目的不是这个
还记得我提出来的background吗,我已经用seurat进行降维聚类分群和细胞注释,所以我没有必要monocle包给我做这些,对于使用了seurat分析流程的我们只想用monocle来做一个拟时序分析该怎么做呢?
#加载包
library(Seurat)
library(monocle3)
library(tidyverse)
library(patchwork)
rm(list=ls())
#导入我们的用seurat包分析得到的S4对象
pbmc <- readRDS("scRNAsub.rds")
#容易弄混的地方来了
#首先我们要得到seurat对象的表达矩阵
data <- GetAssayData(pbmc, assay = 'RNA', slot = 'counts')
#其次获得meta信息
cell_metadata <- [email protected]
#然后要获得gene_annotation
gene_annotation <- data.frame(gene_short_name = rownames(data))
rownames(gene_annotation) <- rownames(data)
#创建CDS对象
cds <- new_cell_data_set(data,
cell_metadata = cell_metadata,
gene_metadata = gene_annotation)
#为啥要这样呢,这怎么解释呢,你用monocle的包,所以要听它的,还是要走一遍某些流程
#然后就是降维聚类分群
#NormalizeData+ScaleData+RunPCA
cds <- preprocess_cds(cds, num_dim = 50) #preprocess_cds函数相当于seurat中NormalizeData+ScaleData+RunPCA
plot_pc_variance_explained(cds) #像seurat一样展示pc数
#umap降维
cds <- reduce_dimension(cds,preprocess_method = "PCA") #preprocess_method默认是PCA
#tSNE降维
cds <- reduce_dimension(cds, reduction_method="tSNE")
#聚类
cds <- cluster_cells(cds)
这里必须强调一下:刚开始我会纠结,monocle的降维聚类分群的结果会不会跟seurat不一样呢,答案是肯定的,算法都不同,能一样吗,那岂不是改变了我们的初衷,只想做拟时序分析
那么解决办法来了,我们可以用seurat分析得到umap结果覆盖掉monocle分析得到的umap结果
cds.embed <- cds@int_colData$reducedDims$UMAP
int.embed <- Embeddings(pbmc, reduction = "umap")
int.embed <- int.embed[rownames(cds.embed),]
cds@int_colData$reducedDims$UMAP <- int.embed #因此我们以后只要是画umap的点图就跟seurat的图片形状是一样的
#画图看一下
plot_cells(cds, reduction_method="UMAP", color_cells_by="seurat_clusters")
在这里我要讲两点:
第一:为什么一定要做降维聚类分群,因为我们是用monocle创建了一个全新的对象,我们只是导入了seurat对象里的表达矩阵,meta信息和genelist,所以这个cds是没有进行降维聚类等操作,导致后面的拟时序分析是做不了的,假如你看了monocle的官网的话啊,你会知道的,官网上说-拟时序分析是基于低维度,所以必须对cds进行降维聚类分群。
第二:已经用seurat分析过的我们,可以在monocle流程里省去哪一些步骤呢,1.我们省去了找
marker基因,2.我们省去了细胞注释,但是我们加进去的meta信息里有细胞类型和其他的一些信息,所以其实这一步可以因为我们用了seurat分析并输入了它的meta信息而代替,所以我们还是相当于做了完整的monocle流程,只是有一些是用seurat做的结果罢了(欢迎一起讨论这一点)
下面开始才是我们想要的:
拟时序分析
第一步:轨迹推断
cds <- learn_graph(cds) #是的,就这么简单,用 learn_graph即可
#画图 我们可以根据meta信息来画出相关的图片
head(colData(cds))
plot_cells(cds,
color_cells_by = "celltype",
label_groups_by_cluster=FALSE,
label_leaves=FALSE,
label_branch_points=TRUE,
group_label_size=4,
cell_size=1.5) #这个图就可以看出细胞直接的分化轨迹了
#黑色的线显示的是graph的结构。
#数字带白色圆圈表示不同的结局,也就是叶子。
#数字带黑色圆圈代表分叉点,从这个点开始,细胞可以有多个结局。
#这些数字可以通过label_leaves和label_branch_points参数设置。
第二步:选择根 就是选择细胞的起源 这也是monocle3与monocle2最大的区别,手动选择(自定义)根 ,使用其中一种就可以!!!
#第一种:
cds = order_cells(cds) #在前阵子有bug 无法展示,现在好像又可以了
plot_cells(cds,
color_cells_by = "pseudotime",
label_cell_groups=FALSE,
label_leaves=TRUE,
label_branch_points=TRUE,
graph_label_size=1.5,
group_label_size=4,cell_size=1.5)
#第二种:用辅助线
p + geom_vline(xintercept = seq(-7,-6,0.25)) + geom_hline(yintercept = seq(0,1,0.25))
embed <- data.frame(Embeddings(pbmc, reduction = "umap"))
embed <- subset(embed, UMAP_1 > -6.75 & UMAP_1 < -6.5 & UMAP_2 > 0.24 & UMAP_2 < 0.25)
root.cell <- rownames(embed)
cds <- order_cells(cds, root_cells = root.cell) #这里就选择了根
plot_cells(cds, color_cells_by = "pseudotime", label_cell_groups = FALSE,
label_leaves = FALSE, label_branch_points = FALSE)
#第三种:定义一个函数
# a helper function to identify the root principal points:
get_earliest_principal_node <- function(cds, time_bin="epithelial cells"){
cell_ids <- which(colData(cds)[, "celltype"] == time_bin)
closest_vertex <-cds@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex
closest_vertex <- as.matrix(closest_vertex[colnames(cds), ])
root_pr_nodes <-
igraph::V(principal_graph(cds)[["UMAP"]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))]
root_pr_nodes
}
cds = order_cells(cds, root_pr_nodes=get_earliest_principal_node(cds)) #很多人这里一直在哭诉error,那是都没有理解这一步在干嘛,很多无脑运行别人的代码,别人代码选择XX细胞作为根,你的数据集里又没有,所以报错说没有node啦
第一种方法:
可以看出我选择红点的地方为发育起始点,我用的是第一种方法
第二种方法:
上面的发育轨迹是在一个二维的坐标上看的,monocle3搞了一个三维的发育轨迹,所以我们可以在三维空间内看发育轨迹(其实我觉得也那样,无非是加多一个维度罢了) 但是假如你想画三维的图,你要定义一个function,就像第三种找root一样,定义一个能找root的函数,因为就算是三维,你也要给别人一个根呀,否则怎么给你画顺序呢?
#第一步:定义一个function
get_earliest_principal_node <- function(cds, time_bin="epithelial cells"){
cell_ids <- which(colData(cds)[, "celltype"] == time_bin)
closest_vertex <-cds@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex
closest_vertex <- as.matrix(closest_vertex[colnames(cds), ])
root_pr_nodes <-
igraph::V(principal_graph(cds)[["UMAP"]])$name[as.numeric(names(which.max(table(closest_vertex[cell_ids,]))))]
root_pr_nodes
}
#第二步:降维到三维,并plot
cds_3d = reduce_dimension(cds, max_components = 3) #这里就降到三维嘛
cds_3d = cluster_cells(cds_3d)
cds_3d = learn_graph(cds_3d) #为啥这慢呢,因为他是在三维的基础上去进行learn
cds_3d = order_cells(cds_3d, root_pr_nodes=get_earliest_principal_node(cds))
cds_3d_plot_obj = plot_cells_3d(cds_3d, color_cells_by="celltype")
cds_3d_plot_obj #这个会由于网络的原因画不出来
到这里大家应该能体会到了为什么前面不管你是不是seurat处理过的,都要对cds这个对象进行降维了吧,不然法画图呀
接下来是差异分析,就是找出哪一些基因在这个轨迹中变化最大
#计算基因按照轨迹的变化
Track_genes <- graph_test(cds, neighbor_graph="principal_graph", cores=6)
Track_genes <- Track_genes[,c(5,2,3,4,1,6)] %>% filter(q_value < 1e-3)
#挑选top10画图展示
Track_genes_sig <- Track_genes %>% top_n(n=10, morans_I) %>%
pull(gene_short_name) %>% as.character()
#基因表达趋势图
plot_genes_in_pseudotime(cds[Track_genes_sig,], color_cells_by="celltype",
min_expr=0.5, ncol = 2)
#FeaturePlot图
plot_cells(cds, genes=Track_genes_sig, show_trajectory_graph=FALSE,
label_cell_groups=FALSE, label_leaves=FALSE)
#在这里运用到文章的话,应该可以这样用,你可以用这些变化top基因来讲一些东西,或者你可以show你自己fouce on的gene
然后就是还可以做一个寻找共表达模块,怎么应用呢,就可以说是这个模块导致他们状态发生变化,然后查看一个模块里的基因,再讲一些东西
##寻找共表达模块
genelist <- pull(Track_genes, gene_short_name) %>% as.character()
gene_module <- find_gene_modules(cds[genelist,], resolution=1e-2, cores = 10)
cell_group <- tibble::tibble(cell=row.names(colData(cds)),
cell_group=colData(cds)$celltype)
agg_mat <- aggregate_gene_expression(cds, gene_module, cell_group)
row.names(agg_mat) <- stringr::str_c("Module ", row.names(agg_mat))
pheatmap::pheatmap(agg_mat, scale="column", clustering_method="ward.D2")
最后,我们可以把monocle的拟时序结果导入seurat对象里了
#提取拟时分析结果返回seurat对象
pseudotime <- pseudotime(cds, reduction_method = 'UMAP')
pseudotime <- pseudotime[rownames([email protected])]
pbmc$pseudotime <- pseudotime
p = FeaturePlot(pbmc, reduction = "umap", features = "pseudotime")
# pseudotime中有无限值,无法绘图。
ggsave("Pseudotime_Seurat.pdf", plot = p, width = 8, height = 6)
saveRDS(pbmc, file = "sco_pseudotime.rds")
References:
单细胞分析十八般武艺5:monocle3 - 云+社区 - 腾讯云 (tencent.com)
scRNA-seq数据分析 || Monocle3 - (jianshu.com)
单细胞之轨迹分析-3:monocle3 - (jianshu.com)
假如有讲错或理解不到位的地方欢迎大家指出哈!!!