如何在R中绘制桑基图?

92
我正在尝试使用Sankey图在R中可视化我的数据流。
我发现这篇博客文章链接到一个生成Sankey图的R脚本;不幸的是,它相当原始且有些受限(请参见下面的示例代码和数据)。
是否有人知道其他脚本或甚至是更完善的包?我的最终目标是通过图表组件的相对大小来可视化数据流和百分比,就像这些Sankey图的示例一样。
我在r-help列表上发布了一个类似的问题,但两周过去了没有任何回应,所以我在stackoverflow上试试运气。
谢谢, Eric
PS. 我知道Parallel Sets Plot,但那不是我要找的。
# thanks to, https://tonybreyal.wordpress.com/2011/11/24/source_https-sourcing-an-r-script-from-github/
  sourc.https     <- function(url, ...) {
# install and load the RCurl package 
if (match('RCurl', nomatch=0, installed.packages()[,1])==0) {
  install.packages(c("RCurl"), dependencies = TRUE)
  require(RCurl)  
} else require(RCurl)    

# parse and evaluate each .R script
  sapply(c(url, ...), function(u) {
    eval(parse(text = getURL(u, followlocation = TRUE, 
    cainfo  = system.file("CurlSSL", "cacert.pem", 
    package = "RCurl"))), envir = .GlobalEnv)
 } )
 }

# from https://gist.github.com/1423501
sourc.https("https://raw.github.com/gist/1423501/55b3c6f11e4918cb6264492528b1ad01c429e581/Sankey.R")

# My example (there is another example inside Sankey.R):
inputs = c(6, 144)
losses = c(6,47,14,7, 7, 35, 34)
unit = "n ="

labels = c("Transfers",
           "Referrals\n",
           "Unable to Engage",
           "Consultation only",
           "Did not complete the intake",
           "Did not engage in Treatment",
           "Discontinued Mid-Treatment",
           "Completed Treatment",
           "Active in \nTreatment")

SankeyR(inputs,losses,unit,labels)

# Clean up my mess
rm("inputs", "labels", "losses", "SankeyR", "sourc.https", "unit")

使用上述代码生成的桑基图,Sankey Diagram produced with the code above

2
箭头看起来不错,似乎你只需要微调文本就可以了,你同意吗? - Roman Luštrik
@Roman Luštrik,我同意,这个图表并不差,但是我的R技能还有限,所以我不能在R中进行太多的微调,如果那是你的意思的话?当然,我可以在Adobe Illustrator或类似软件中完成它,但那将违反可重复研究的原则,对我来说,这是任何(学术)工作的核心要素。你看过我在帖子中链接的示例了吗?(http://www.sankey-diagrams.com/tag/software/) - Eric Fail
1
我能想到的唯一地方可能是crossvalidated.com。 - Roman Luštrik
@AlexReynolds,那是我两周前做的第一件事情(请看我问题中的第四段)。 - Eric Fail
@RobinGower,说得好。问题是我在一个实验室工作,没有太多的技术资源,所以使用R之外的东西来制作这个图表是行不通的。很遗憾。通常情况下,R在数据可视化方面非常出色,所以我很惊讶地发现没有人制作出能够生成桑基图的包。 - Eric Fail
显示剩余3条评论
10个回答

68

通过 networkD3 包可以创建此图。它允许您创建交互式桑基图。您可以在此处找到一个示例。我还添加了一个截图,以便您了解其外观。

# Load package
library(networkD3)

# Load energy projection data
# Load energy projection data
URL <- paste0(
        "https://cdn.rawgit.com/christophergandrud/networkD3/",
        "master/JSONdata/energy.json")
Energy <- jsonlite::fromJSON(URL)
# Plot
sankeyNetwork(Links = Energy$links, Nodes = Energy$nodes, Source = "source",
             Target = "target", Value = "value", NodeID = "name",
             units = "TWh", fontSize = 12, nodeWidth = 30)

在此输入图片描述


4
示例链接已损坏。 - Nelson Auner
1
确实。自从引入htmlwidgets以来,更好的选择是来自networkD3包的桑基图。我已经更新了帖子。 - Jonas Tundo
1
是否可以将数字值作为标题而不是整数? 值被正确地获取,但标题似乎被四舍五入了。 例如:value = 0.8和value = 0.2具有不同的线宽度,但标题对于两者都是“0”。 - Naveen Mathew
如果您尝试使用自己的数据样本来重现此内容,请确保第一个源ID以0开头,并且源和目标ID是连续的。 - Richard

47

我创建了一个包 (riverplot),与Sankey函数有略微不同但重叠的功能,并且可以产生像这样的图表:

输入图片描述


这看起来真的很不错!我会尽快查看它。 - Eric Fail

40
如果您想使用R语言实现此功能,@Roman所提出的建议似乎是最佳选择 - 改进SankeyR函数。例如,以下是我的快速修复-仅将标签垂直排列,稍微偏移它们,并降低输入引用的字体大小,使其看起来更好一些。此修改仅更改了SankeyR函数中的第171和223行:
    #line171 - change oversized font size of input label
    fontsize = max(0.5,frInputs[j]*1.5)#1.5 instead of 2.5 

    #line223 - srt changes from 35 to 90 to orient labels vertically, 
    #and offset adjusts them to get better alignment with arrows
    text(txtX, txtY, fullLabel, cex=fontsize, pos=4, srt=90, offset=0.1)

在此输入图像描述

虽然我不是三角学专家,但这确实是你需要改变箭头方向的方法。在我看来,如果您可以调整松散的箭头使其水平而不是垂直,则会更理想。否则,尽管我的解决方案修复了标签方向的问题,但它并没有使图表更易读...


1
那是个不错的技巧,谢谢。我已经将它改进得更好了。你有我的点赞,如果没有更好的方案出现,时间到了我很乐意把奖励转给你。另外,我喜欢你的用户名。 - Eric Fail

25
除了rCharts外,现在还可以使用googleVis(版本>=0.5.0)在R中生成桑基图。例如,这篇文章描述了如何使用googleVis生成下面的图表: enter image description here


16

R的包也可以实现这个功能(来自?alluvial)。

# install.packages(c("alluvial"), dependencies = TRUE)
require(alluvial)

# Titanic data
tit <- as.data.frame(Titanic)

# 4d
alluvial( tit[,1:4], freq=tit$Freq, border=NA,
     hide = tit$Freq < quantile(tit$Freq, .50),
     col=ifelse( tit$Class == "3rd" & tit$Sex == "Male", "red", "gray") )

这里输入图片描述


是的,但请参见https://github.com/corybrunson/ggalluvial/issues/11 - Paul Schmidt

12

7

为了完整起见,还有ggalluvial包,它是一个用于制作流程图/桑基图的ggplot2扩展

这里是从该包文档中提取的一个示例:

# devtools::install_github("corybrunson/ggalluvial", ref = "optimization")
library(ggalluvial)

titanic_wide <- data.frame(Titanic)
ggplot(data = titanic_wide,
       aes(axis1 = Class, axis2 = Sex, axis3 = Age,
           y = Freq)) +
  scale_x_discrete(limits = c("Class", "Sex", "Age"), expand = c(.1, .05)) +
  xlab("Demographic") +
  geom_alluvium(aes(fill = Survived)) +
  geom_stratum() + geom_text(stat = "stratum", label.strata = TRUE) +
  theme_minimal() +
  ggtitle("passengers on the maiden voyage of the Titanic",
          "stratified by demographics and survival") +
  theme(legend.position = 'bottom')

ggplot(titanic_wide,
       aes(y = Freq,
           axis1 = Survived, axis2 = Sex, axis3 = Class)) +
  geom_alluvium(aes(fill = Class),
                width = 0, knot.pos = 0, reverse = FALSE) +
  guides(fill = FALSE) +
  geom_stratum(width = 1/8, reverse = FALSE) +
  geom_text(stat = "stratum", label.strata = TRUE, reverse = FALSE) +
  scale_x_continuous(expand = c(0, 0), 
                     breaks = 1:3, labels = c("Survived", "Sex", "Class")) +
  scale_y_discrete(expand = c(0, 0)) +
  coord_flip() +
  ggtitle("Titanic survival by class and sex")

此文档由reprex package (v0.2.1.9000)于2018-11-13创建


是的,但请参见 https://github.com/corybrunson/ggalluvial/issues/11 - Paul Schmidt

6
根据这些定义,这个函数与平行设置图一样,缺乏分割和合并流的能力(即通过多个转换)。
由于桑基图是有向加权图,因此像qgraph这样的软件包可能很有用。
如果按降序排序损失,则SankeyR函数提供更清晰的标签,因为文本靠近箭头头部而不重叠。

1
将损失按降序排序会破坏图表的方向性。如果您仔细观察我提交的图表,您会发现时间在x轴上,因此是当前顺序。我知道sankey-diagrams.com和相关文章,当我看到该网站时,我的第一个想法是打开R并使用ggplot2生成漂亮的桑基图。 - Eric Fail

5
请查看//sankeybuilder.com,它提供了一个即插即用的解决方案,您可以上传数据并在时间轴上回放。转换效果很好(类似于您问题中的YouTube演示)。如果您加载SankeyTrend演示,它包括许多时间段(多年的数据)。加载后(自动构建桑基图),单击页面右上角的播放按钮以回放时间段,甚至可以暂停和恢复时间。演示网址在此处:SankeyTrend希望这有助于您寻找完美的桑基图。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接