Monocle3:拟时序分析

写在前面:今天突然想写这个教程,花了一下午看资料,其实我前面是有一些基础的,但是看的还是会很乱,所以想把这个包的脉络写一下,希望能够可以跟大家讨论一下并且自己以后使用这个包的时候也相当于翻阅说明书吧!!!

首先讲一段话
我的一个使用情景是,当我跑完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 <- pbmc@meta.data

#然后要获得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啦

第一种方法:


F0F93078D92B4FDE3F6F39C7937218F3.png

8B7BA300D52E5421428CC98EF7C97EB7.png

可以看出我选择红点的地方为发育起始点,我用的是第一种方法

第二种方法:


7C4`[PLYFY`)RHLO8NB(`LA.png

上面的发育轨迹是在一个二维的坐标上看的,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
0148242A1BCE467DCF9F971A4C5D8E4E.png

3FFFA58676E8137C01219D5B9CB444BD.png

然后就是还可以做一个寻找共表达模块,怎么应用呢,就可以说是这个模块导致他们状态发生变化,然后查看一个模块里的基因,再讲一些东西

##寻找共表达模块
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")
21F9A0DCB5AA08E0063B6474FC781EA4.png

最后,我们可以把monocle的拟时序结果导入seurat对象里了

#提取拟时分析结果返回seurat对象
pseudotime <- pseudotime(cds, reduction_method = 'UMAP')
pseudotime <- pseudotime[rownames(pbmc@meta.data)]
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)

假如有讲错或理解不到位的地方欢迎大家指出哈!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容