【R画图学习4】桑基图
桑基图,其实我用的不太多。最近常见还是在分析单细胞数据的时候,展示细胞通讯用的比较多的一种类型的图。例如下面一张就是cellchat画的一张桑基图。
![](https://img.haomeiwen.com/i24339453/1683f88fdbcab674.png)
x先看一下,百度对于桑基图的定义。桑基图(Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,右图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的可视化分析。因1898年Matthew Henry Phineas Riall Sankey绘制的“蒸汽机的能源效率图”而闻名,此后便以其名字命名为“桑基图”。
所以从定义来看,一个简单的桑基图应该具备,node和link。node分为source node和target node。而link衡量source node和target node之间的数据流量的大小。
library(networkD3)
library(ggplot2)
我们先来设置一个简单的node和link文件
nodes = data.frame("name" =
c("Node A", # Node 0
"Node B", # Node 1
"Node C", # Node 2
"Node D"))# Node 3
links = as.data.frame(matrix(c(
0, 1, 10, # Each row represents a link. The first number
0, 2, 20, # represents the node being conntected from.
1, 3, 30, # the second number represents the node connected to.
2, 3, 40),# The third number is the value of the node
byrow = TRUE, ncol = 3))
names(links) = c("source", "target", "value")
从简单的测试数据来看,我们给定了4个node,并且设置了source node和target node之间的数据流动情况。需要注意的是node是从0开始计数的,这点和java一样。
![](https://img.haomeiwen.com/i24339453/b49ed71f9fc29229.png)
sankeyNetwork(Links = links, Nodes = nodes,Source = "source", Target = "target",Value = "value", NodeID = "name",fontSize= 12, nodeWidth = 30)
出来就是一个简单的桑基图的样子。value表示这些链接与之关联的值,该值由链接的厚度表示。在示例中,连接节点A和节点B的第一条链接的宽度是连接A和C的第二条链接的宽度的一半。
![](https://img.haomeiwen.com/i24339453/78fc4fbce21cce95.png)
这个函数的详细参数解释,大家也可以自己看下。Links指的就是我们输入的node之间的links文件,Nodes文件就是node的指定文件。Source,Target,Value和NodeID指定source、target、value和name。
![](https://img.haomeiwen.com/i24339453/a5527e7e66c54b44.png)
下面测试一下我们自己的数据,先来一个简单点的。
这个是我们的第一个简单的测试数据:
![](https://img.haomeiwen.com/i24339453/8d3c46f3a3b19cb9.png)
links <- read.csv("links.csv",header = T, fileEncoding = "UTF-8-BOM")
nodes <- read.csv("nodes.csv", header = T, fileEncoding = "UTF-8-BOM")
我们从csv文件读入,后面fileEncoding主要是为了处理编码问题,有时候不知道为什么会出现乱码,主要是中文等格式的问题。
sankeyNetwork(Links = links, Nodes = nodes,
Source = "source",
Target = "target",
Value = "value",
NodeID = "name",
fontSize = 12,
nodeWidth = 30,
nodePadding = 8
)
画图的函数和前面一样。而 fontSize = 12, 表示节点的字体大小;nodeWidth = 30, 表示节点的宽度;nodePadding = 8 表示节点之间的距离。
![](https://img.haomeiwen.com/i24339453/28650a89dbff2d46.png)
换个稍微复杂点的数据集试下:
![](https://img.haomeiwen.com/i24339453/aadf0664c162ba72.png)
![](https://img.haomeiwen.com/i24339453/596d625abee03d62.png)
nodes <- read.csv("nodes1.csv",header = T, fileEncoding = "UTF-8-BOM")
links <- read.csv("links1.csv",header = T, fileEncoding = "UTF-8-BOM")
sn <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
units = "TWh", fontSize = 8, nodeWidth = 30)
![](https://img.haomeiwen.com/i24339453/d1733c7c6f0dc7a5.png)
也可以自己修改node或者link的颜色。
官网是这样说的:You can use this information to create a JavaScript color attribution object and call it using the Nodegroup argument.
就是我们可以自己创建一个javascript的颜色,好像java写的包,还真是麻烦。
my_color <- 'd3.scaleOrdinal() .domain(["c1", "c2","c3"]) .range(["red", "steelblue","green"])' //我们根据每个node的group来指定颜色。
sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
units = "TWh", fontSize = 8, nodeWidth = 30, colourScale=my_color, NodeGroup="group")
![](https://img.haomeiwen.com/i24339453/d38038ee25741413.png)
感觉这个包颜色设置不太方面。
可以根据link的分类来分别设置颜色。
my_color <- 'd3.scaleOrdinal() .domain(["c1", "c2","c3","type_a","type_b","type_c","type_d"]) .range(["red", "blue","green","#69b3a2", "steelblue", "grey","cyan"])'
sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
units = "TWh", fontSize = 8, nodeWidth = 30, colourScale=my_color, NodeGroup="group",LinkGroup="group")
![](https://img.haomeiwen.com/i24339453/1ed8b132e761a4dd.png)
还有一个问题,真个生成的是html,如果我们想转化成我们常规的图片格式,需要安装这个包:
install.packages("webshot")
if(!is_phantomjs_installed()){
install_phantomjs()
}
library(webshot)
sn<-sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
units = "TWh", fontSize = 8, nodeWidth = 30, colourScale=my_color, NodeGroup="group",LinkGroup="group")
saveNetwork(sn, "sn.html")
webshot("sn.html" , "sn.pdf")
就可以存成pdf格式了。