前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >桑基图在单细胞数据探索中的应用

桑基图在单细胞数据探索中的应用

作者头像
生信技能树jimmy
发布2020-03-27 12:41:01
1.9K0
发布2020-03-27 12:41:01
举报
文章被收录于专栏:单细胞天地

分享是一种态度

作者 | 周运来

男,

一个长大了才会遇到的帅哥,

稳健,潇洒,大方,靠谱。

一段生信缘,一棵技能树,

一枚大型测序工厂的螺丝钉,

一个随机森林中提灯觅食的津门旅客。

什么是桑基图

桑基图(Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,图中延伸的分支的宽度对应数据流量的大小,比较适用于用户流量等数据的可视化分析。因1898年Matthew Henry Phineas Riall Sankey绘制的“蒸汽机的能源效率图”而闻名,此后便以其名字命名为“桑基图”。

用一个故事来介绍一下桑基图:

这个非常著名的图是Charles Minard在1869年所作的拿破仑东征俄国的信息图。Charles Minard是信息图表的之父,他是信息图领域的创始者。这张图描绘的是拿破仑在1812到1813年进攻俄国的情况。它的背景是一个真实的地图,西边是波兰的边境,东边是莫斯科。图上那条主线的宽度代表拿破仑军队的人数,黄色表示进攻路线,黑色表示撤退的路线:他开始于42万人,在向莫斯科进军的过程中丧失了很多人,到达莫斯科时只剩下10万人,而最后从莫斯科活着返回的只剩下1万人。

为什么说这个图好呢,因为除了主线的宽度之外,这张图还告诉了你更多的东西。画面下面的折线图告诉你当时的温度,其中最高的点是0度,最低到达过零下30度,回城的黑线周围还标注了月份,可以看出,拿破仑的军队在到达莫斯科的时候已经是将近十月分了,等到完全撤离俄国已经是12月份了,如果你仔细观察,会发现在撤退过程中他们路过了一条叫Studienska的河,军队人数在河两岸出现了剧减,原来那个时候天气寒冷,军队长促情况下淌水过河,于是在这条寒冷的河中冻死了很多人。

根据Edward Tufte所总结的信息设计原则:

  • 这个图让显示出了比较关系(Show comparisons, contrasts, differences),比如军队人数的起始时候的宽度和结束时候的宽度的强烈对比,比如过那条河流的时候军队人数的剧烈的变化等等。
  • 这个图解释了因果关系(Show causality, mechanism, structure, explanation),比如时间,温度和军队人数的关系。
  • 这个图有多个变量(Multivariate analysis),1), 军队人数。2), 地理的位置(经度和纬度)3), 军队的行进方向。4), 温度。5), 时间。

所有的这些信息都不是独立存在的,他们结合在一起,将观众带入当时的拿破仑的旅程,同时能让人感受到无情的战争夺走人们生命的痛苦。

桑基图怎么看

  • 线条的走向
  • 粗细的变化
  • 节点间的比较

绘制属于自己的桑基图

在单细胞数据分析中有一个关键的步骤FindClusters(分群,以启发样本中可能有的细胞类型数量),但是这个目前用的方法是非监督聚类,也就是数据驱动的,不依赖生物学背景。而且常常带来参数诅咒:如kmeans的K值不同,得到的分群数量不同;Seurat中FindClusters的不同 resolution 参数也会带来不同的分群数量。

于是,我的样本中到底有多少细胞类型?

所以只靠一个参数,往往不能满足要求,或者说启发的力度还不够。那就尝试多个分群参数吧,得到的结果可能是这样的:

代码语言:javascript
复制
> head(pbmc_small@meta.data)
                  orig.ident nCount_RNA nFeature_RNA RNA_snn_res.0.8 letter.idents groups RNA_snn_res.1 RNA_snn_res.0.4
ATGCCAGAACGACT SeuratProject         70           47               0             A     g2             0               0
CATGGCCTGTGCAT SeuratProject         85           52               0             A     g1             0               0
GAACCTGATGAACC SeuratProject         87           50               0             B     g2             0               0
TGACTGGATTCTCA SeuratProject        127           56               0             A     g2             0               0
AGTCAGACTGCACA SeuratProject        173           53               0             A     g2             0               0
TCTGATACACGTGT SeuratProject         70           48               0             A     g1             0               0
               RNA_snn_res.1.2 RNA_snn_res.1.6 seurat_clusters RNA_snn_res.0.6 RNA_snn_res.1.4
ATGCCAGAACGACT               0               3               3               0               4
CATGGCCTGTGCAT               5              10              10               0               8
GAACCTGATGAACC               5               9               9               0               6
TGACTGGATTCTCA               0               7               7               0               1
AGTCAGACTGCACA               0               3               3               0               4
TCTGATACACGTGT               0               3               3               0               4

如果用人类的肉眼来比较不同RNA_snn_res.下的分群结果可能会比较困难。不过,借助R方便地看出某一分群下,每个群的细胞数量:

代码语言:javascript
复制
> table(pbmc_small@meta.data$RNA_snn_res.1.6)

 0  1 10 11  2  3  4  5  6  7  8  9 
17 14  2  2  9  6  7  5  5  3  6  4 

但是有了桑基图情况就不一样了,变得一目了然起来:

代码语言:javascript
复制
#先执行不同resolution 下的分群
library(Seurat)
pbmc_small <- FindClusters(
  object = pbmc_small,
  resolution = c(seq(.4,1.6,.2))
)

绘制细胞分群的桑基图:

代码语言:javascript
复制
#install.packages("ggalluvial")
library(ggalluvial)
library(tidyverse)

head(pbmc_small@meta.data)
ggplot(data = pbmc_small@meta.data,
       aes(axis1 = RNA_snn_res.0.4, axis2 = RNA_snn_res.0.6,axis3 = RNA_snn_res.0.8,axis4 = RNA_snn_res.1,
           axis5 = RNA_snn_res.1.2,axis6 = RNA_snn_res.1.4,axis7 = RNA_snn_res.1.6)) +
  scale_x_discrete(limits = c(paste0("RNA_snn_res.",seq(.4,1.6,.2))), expand = c(.01, .05)) +
  geom_alluvium(aes(fill = RNA_snn_res.1.6)) +
  geom_stratum() + geom_text(stat = "stratum", infer.label = TRUE) +
  #coord_polar()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  ggtitle("cell number in each cluster")

可以清晰地看出,RNA_snn_res.1.6每个群的来源,也可以启发在RNA_snn_res.1.2时cluster0可能有三个亚群,cluster4有两个亚群。这不仅解析了resolution 参数(其他的分群算法也一样),同时启发了样本的异质性。

有了这个桑基图的框架,其实很多我们想在这个图上展示的metadata信息就变得容易了,比如我们可以看一下某一细胞类型流向或者样本的流向,只需要在metadata中加上一列即可。

代码语言:javascript
复制
ggplot(data = pbmc_small@meta.data,
       aes(axis1 = RNA_snn_res.0.4, axis2 = RNA_snn_res.0.6,axis3 = RNA_snn_res.0.8,axis4 = RNA_snn_res.1,
           axis5 = RNA_snn_res.1.2,axis6 = RNA_snn_res.1.4,axis7 = RNA_snn_res.1.6)) +
  scale_x_discrete(limits = c(paste0("RNA_snn_res.",seq(.4,1.6,.2))), expand = c(.01, .05)) +
  geom_alluvium(aes(fill = groups)) +
  geom_stratum() + geom_text(stat = "stratum", infer.label = TRUE) +
  #coord_polar()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  ggtitle("cell number in each cluster")

或者看nFeature_RNA 的变化,即是不是nFeature_RNA 高的分到一群呢?

代码语言:javascript
复制
ggplot(data = pbmc_small@meta.data,
       aes(axis1 = RNA_snn_res.0.4, axis2 = RNA_snn_res.0.6,axis3 = RNA_snn_res.0.8,axis4 = RNA_snn_res.1,
           axis5 = RNA_snn_res.1.2,axis6 = RNA_snn_res.1.4,axis7 = RNA_snn_res.1.6)) +
  scale_x_discrete(limits = c(paste0("RNA_snn_res.",seq(.4,1.6,.2))), expand = c(.01, .05)) +
  geom_alluvium(aes(fill = nFeature_RNA )) +
  geom_stratum() + geom_text(stat = "stratum", infer.label = TRUE) +
  #coord_polar()+
  theme(axis.text.x = element_text(angle = 90, hjust = 1))+
  ggtitle("cell number in each cluster")

image

clustertree

在聚类分析中,由于它的启发性本质,经常需要比较不同分群的结果。下面提供另一种(简单直白的)“桑基图“,供大家参考:

代码语言:javascript
复制
clustree(pbmc_small@meta.data, prefix = "RNA_snn_res.")
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 单细胞天地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是桑基图
  • 桑基图怎么看
  • 绘制属于自己的桑基图
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档