您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# R语言怎么实现桑基图
## 什么是桑基图
桑基图(Sankey Diagram)是一种流图,用于描述系统中能量、物质或成本的流动情况。它以宽度表示流量的大小,通过节点和连接线展示不同类别之间的转移关系。桑基图最初由爱尔兰工程师Matthew Henry Phineas Riall Sankey于1898年提出,用于展示蒸汽机的能量效率。
### 桑基图的典型应用场景
1. **能源流动分析**:如电力系统中能源的转换和消耗
2. **资金流动追踪**:企业预算分配或资金流向
3. **人口迁移研究**:展示人口在不同地区间的流动
4. **网站用户行为分析**:用户在不同页面间的跳转路径
5. **供应链管理**:物料在生产环节中的流转
## R语言实现桑基图的三种主要方法
### 方法一:使用networkD3包
`networkD3`是最常用的桑基图绘制包之一,它基于D3.js库,可以创建交互式可视化。
#### 安装与加载
```r
install.packages("networkD3")
library(networkD3)
桑基图需要两种数据: 1. 节点数据:包含所有唯一类别 2. 连接数据:描述节点间的流动关系
# 创建节点数据框
nodes <- data.frame(
name = c("能源生产", "煤炭", "石油", "天然气",
"工业", "居民", "商业", "运输")
)
# 创建连接数据框
links <- data.frame(
source = c(0, 0, 0, 1, 1, 2, 2, 3, 3, 3),
target = c(1, 2, 3, 4, 5, 4, 6, 5, 6, 7),
value = c(100, 80, 60, 70, 30, 50, 30, 20, 30, 10)
)
# 注意:networkD3中节点索引从0开始
sankeyNetwork(
Links = links,
Nodes = nodes,
Source = "source",
Target = "target",
Value = "value",
NodeID = "name",
fontSize = 12,
nodeWidth = 30
)
sankeyNetwork(
Links = links,
Nodes = nodes,
Source = "source",
Target = "target",
Value = "value",
NodeID = "name",
fontSize = 14,
nodeWidth = 30,
nodePadding = 20,
colourScale = JS('d3.scaleOrdinal().domain(["能源生产"]).range(["#FF0000"])'),
sinksRight = FALSE # 控制最后一个节点是否在右侧
)
ggalluvial
基于ggplot2语法,适合熟悉ggplot生态的用户。
install.packages("ggalluvial")
library(ggalluvial)
library(ggplot2)
energy <- data.frame(
source = rep(c("煤炭", "石油", "天然气"), each = 3),
target = rep(c("工业", "居民", "商业"), 3),
value = c(70, 30, 0, 50, 10, 20, 20, 30, 10)
)
ggplot(energy,
aes(y = value, axis1 = source, axis2 = target)) +
geom_alluvium(aes(fill = source), width = 1/12) +
geom_stratum(width = 1/12, fill = "grey80", color = "grey30") +
geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
scale_x_discrete(limits = c("来源", "去向"), expand = c(0.05, 0.05)) +
scale_fill_brewer(type = "qual", palette = "Set1") +
theme_minimal() +
labs(title = "能源分配桑基图", y = "能量值(TJ)")
# 添加时间维度
energy_multi <- data.frame(
year = rep(2010:2012, each = 9),
source = rep(rep(c("煤炭", "石油", "天然气"), each = 3), 3),
target = rep(c("工业", "居民", "商业"), 9),
value = round(runif(27, 10, 50))
ggplot(energy_multi,
aes(y = value, axis1 = source, axis2 = target)) +
geom_alluvium(aes(fill = source)) +
geom_stratum() +
geom_text(stat = "stratum", aes(label = after_stat(stratum))) +
facet_wrap(~year, ncol = 1) +
theme_bw()
plotly
可以创建交互式桑基图,并支持丰富的交互功能。
install.packages("plotly")
library(plotly)
nodes <- data.frame(
label = c("生产", "煤炭", "石油", "工业", "居民", "商业"),
color = c("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b")
)
links <- data.frame(
source = c(0, 0, 1, 1, 2, 2),
target = c(1, 2, 3, 4, 3, 5),
value = c(100, 80, 70, 30, 50, 30)
)
fig <- plot_ly(
type = "sankey",
orientation = "h",
node = list(
label = nodes$label,
color = nodes$color,
pad = 15,
thickness = 20,
line = list(color = "black", width = 0.5)
),
link = list(
source = links$source,
target = links$target,
value = links$value
)
)
fig <- fig %>% layout(
title = "能源流动桑基图",
font = list(size = 12)
)
fig
实际数据通常需要转换才能用于桑基图。以下是一个典型的数据处理流程:
library(dplyr)
library(tidyr)
# 原始数据示例
raw_data <- data.frame(
year = rep(2020:2022, each = 100),
source = sample(c("A", "B", "C"), 300, replace = TRUE),
target = sample(c("X", "Y", "Z"), 300, replace = TRUE),
amount = runif(300, 1, 10)
)
# 数据处理步骤
sankey_data <- raw_data %>%
group_by(source, target) %>%
summarise(value = sum(amount), .groups = "drop") %>%
filter(value > 15) # 过滤小流量
# 构建节点列表
nodes <- data.frame(
name = unique(c(sankey_data$source, sankey_data$target))
)
# 转换连接关系
links <- sankey_data %>%
mutate(
source = match(source, nodes$name) - 1,
target = match(target, nodes$name) - 1
)
当数据中存在循环流动时(如A→B→C→A),需要特殊处理:
# 添加中间节点打破循环
nodes <- data.frame(name = c("A", "B", "C", "A'"))
links <- data.frame(
source = c(0, 1, 2, 2),
target = c(1, 2, 3, 0),
value = c(10, 8, 5, 3)
)
node_colors <- 'd3.scaleOrdinal()
.domain(["煤炭", "石油", "工业", "居民"])
.range(["#8dd3c7", "#ffffb3", "#bebada", "#fb8072"])'
link_colors <- 'd3.scaleLinear()
.domain([0,1])
.range(["#fde725", "#440154"])'
# 在networkD3中添加JavaScript交互
sankeyNetwork(
# 基本参数...
) %>%
htmlwidgets::onRender('
function(el, x) {
d3.selectAll(".node text").style("font-weight", "bold");
d3.selectAll(".link").style("opacity", 0.7);
}
')
# 保存为HTML
library(htmlwidgets)
saveWidget(sankeyNetwork(...), file = "sankey.html")
# 嵌入R Markdown
```{r}
sankeyNetwork(...)
## 常见问题解决方案
### 问题1:节点重叠或标签溢出
**解决方案**:
- 调整`fontSize`和`nodePadding`参数
- 使用`nodeWidth`增加节点宽度
- 旋转标签:`d3.selectAll(".node text").attr("transform", "rotate(-45)")`
### 问题2:流量显示不清晰
**解决方案**:
- 设置最小流量阈值过滤小流量
- 使用对数刻度:`value = log(original_value + 1)`
- 调整颜色对比度
### 问题3:大数据集性能问题
**优化策略**:
1. 聚合小流量类别为"其他"
2. 使用`data.table`处理大数据
3. 考虑使用WebGL版本的实现
```r
# 聚合小流量示例
major_flows <- links %>%
group_by(source) %>%
mutate(percent = value/sum(value)) %>%
filter(percent > 0.1)
user_paths <- data.frame(
session_id = rep(1:1000, each = 3),
step = rep(c("首页", "产品页", "购物车"), 1000),
next_step = rep(c("产品页", "购物车", "支付"), 1000),
count = sample(1:10, 3000, replace = TRUE)
)
# 聚合路径数据
path_agg <- user_paths %>%
group_by(step, next_step) %>%
summarise(total = sum(count), .groups = "drop") %>%
filter(total > quantile(total, 0.75)) # 只保留前25%的流量
nodes <- data.frame(name = unique(c(path_agg$step, path_agg$next_step)))
links <- path_agg %>%
mutate(
source = match(step, nodes$name) - 1,
target = match(next_step, nodes$name) - 1,
value = total
)
sankeyNetwork(
Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
units = "访问量", fontSize = 14,
nodeWidth = 20, nodePadding = 15
)
特性 | networkD3 | ggalluvial | plotly |
---|---|---|---|
交互性 | 高 | 低 | 高 |
语法风格 | 专用函数 | ggplot2 | 专用函数 |
定制灵活性 | 中 | 高 | 中 |
大数据支持 | 一般 | 较好 | 较好 |
学习曲线 | 平缓 | 中等 | 中等 |
官方文档:
在线示例:
相关论文:
通过本文介绍,您应该已经掌握了在R中创建桑基图的多种方法。根据您的具体需求选择合适的方法,并利用数据预处理和视觉优化技巧,可以创建出专业级的流动可视化图表。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。