共有OTU占比 桑基图绘制小试

背景

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

桑基图我们上百度一查都能查到很多好看的示例,比如:


我今天要做的可比这些看起来轻松简单许多了
来自于这篇文献中的Fig 2(c)
Spread of airborne antibiotic resistance from animal farms to the environment: Dispersal pattern and exposure risk
https://doi.org/10.1016/j.envint.2021.106927


乍一看很粗糙哈,没有花里胡哨的颜色,没有天花乱坠的连接一切都是那么简单和朴素,文献中关于这部分信息也有了简单的描述,这里使用了networkD3 R包进行绘制,那我们就尝试一下

上官网教程网址 Sankey plot | the R Graph Gallery (r-graph-gallery.com),官网中非常人性的提供了逐步进行绘制的代码,甚至提供了多种绘制模式可供选择

就在我按照文献中给的方法进行复刻的时候,我遇到了难度,我发现无论我如何按照代码的形式进行绘图绘制的结果一定都像官方网址中第一个图所示的一样,所有的连线(灰色的宽带)从流出端都是占满了整个条带,流入端占比加起来也为100%,这就与文献中的图形展示形式不符了,思考人生……

我们还是看看基础的桑基图作图过程是什么样的吧,官网中提供了两种可选择的构建links数据的方式

第一种

# Library
library(networkD3)
library(dplyr)

# A connection data frame is a list of flows with intensity for each flow
links <- data.frame(
  source=c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"), 
  target=c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"), 
  value=c(2,3, 2, 3, 1, 3)
  )

# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(
  name=c(as.character(links$source), 
  as.character(links$target)) %>% unique()
)

# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
links$IDsource <- match(links$source, nodes$name)-1 
links$IDtarget <- match(links$target, nodes$name)-1

# Make the Network
p <- sankeyNetwork(Links = links, Nodes = nodes,
              Source = "IDsource", Target = "IDtarget",
              Value = "value", NodeID = "name", 
              sinksRight=FALSE)
p
saveNetwork(p,"sankey.html")

# save the widget
# library(htmlwidgets)
# saveWidget(p, file=paste0( getwd(), "/HtmlWidget/sankeyBasic1.html"))

总共由4部分组成,第一部分就是构建links数据框,第二部分获得桑集图中所有nodes节点信息,第三部分获得节点间的连接关系,第四部分就是作图了

第二种

# Library
library(networkD3)
library(dplyr)

# Create an incidence matrix. Usually the flow goes from the row names to the column names.
# Remember that our connection are directed since we are working with a flow.
set.seed(1)
data <- matrix(sample( seq(0,40), 49, replace=T ), 7, 7)
data[data < 35] <- 0
colnames(data) = rownames(data) = c("group_A", "group_B", "group_C", "group_D", "group_E", "group_F", "group_G")

# Transform it to connection data frame with tidyr from the tidyverse:
links <- data %>% 
  as.data.frame() %>% 
  rownames_to_column(var="source") %>% 
  gather(key="target", value="value", -1) %>%
  filter(value != 0)

# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(
  name=c(as.character(links$source), as.character(links$target)) %>% 
    unique()
  )

# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
links$IDsource <- match(links$source, nodes$name)-1 
links$IDtarget <- match(links$target, nodes$name)-1

# Make the Network
p <- sankeyNetwork(Links = links, Nodes = nodes,
                     Source = "IDsource", Target = "IDtarget",
                     Value = "value", NodeID = "name", 
                     sinksRight=FALSE)

p

# save the widget
# library(htmlwidgets)
# saveWidget(p, file=paste0( getwd(), "/HtmlWidget/sankeyBasic2.html"))

和第一种差不多,这里的数据框使用sample指令随机生成的


比如我现在要模仿绘制Fig 2(c),我们先来看下他的组成情况



由四部分组成,我们不妨从左到右将他们依次命名为ABCD,可以看到A连着B,B连着C,B连着D,C连着D,通过官网教程的第一种示例,我们可以得知,这一步是进行手动构建links的,value值对应着被连接的部分与连接部分共同的大小

links <- data.frame(
  source=c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"), 
  target=c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"), 
  value=c(2,3, 2, 3, 1, 3)
  )

根据这一原则,我们假设A共有6份,B共有7份,C共有11份,D共有8份(根据figure2c 大致假设),其中AB共有3,BC共有7,DB共有3 CD没有共有
那我么这里的links可以这样写

links <- data.frame(
  source=c("A","B", "B"), 
  target=c("B","C", "D""), 
  value=c(3,7, 3)
  )

执行代码后此时的links是这样的

links
  source target value
1      A      B     3
2      B      C     7
3      B      D     3

进行图形绘制后结果变为



可以看到这样的数据输入并不能确定A组包含的份数,而且由于B与C,B与D连接,脚本看来他们就应该放在一列,这这这这这这这这这与文献中差的可有点远了,尝试从其他的R包入手画这张图都没有实现作者的原图,而且作者就是用的networkD3这个包画的,难道中国人骗中国人不成?


所以我这里面临的主要问题就是每一个连接块的数量占比问题,以及如何让D图排到第四列的位置而不是在C的下面
既然第一个连接块无法进行份数设置,而且它这里还延伸一半出来,那有没有可能存在着一条隐形的连接线和连接块呢?
我在这里假设存在了一个连接块E,并且让它与C相连,然后再将C与D相连,这样就解决了CD排列在一列的问题并且可以有效的为A连接块与C连接块流出部分空余的问题,我干嘛假设呀,我直接再连一个E出来,说连就连,这里大致计算了一下连接之间的份数,然后按照以下的数量构建links

links <- data.frame(
  source=c("A","A","B","C","C","B"), 
  target=c("B","C","C","D","E","D"), 
  value=c(15,15,20,15,20,10)
)

画图

哎~ 差不多了,感觉很近了,现在其实就是多了AC之间的连接,CD之间的连接(你要问我为什么要连CD,不连他俩不能把CD并列放置),CE之间的连接,BE之间的连接

那这个连接该怎么删除呢?
有没有发现第一种方法里面我最后写了saveNetwork(p,"sankey.html") 这句代码,没想到吧,其实这个桑基图在网页上是可以进行拉动的,是交互的,所以我们这里把它保存为网页的格式,接下来呢,接下来就简单了,用网页的F12调试台删除掉多余的部分

上菜

是不是有点那个意思了?唯一的缺点就是每次都得好好算一算比例组成,烦恼

要是你有更妙的点子,欢迎同我分享,拯救一下我这繁杂的人工过程吧

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

推荐阅读更多精彩内容