You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整数据使ggalluvial中数据流在节点处精准衔接?

问题根源

你当前的错误在于把t1→t2和t2→t3的数据流拆成了独立的flow组,导致中间节点(如D)被ggalluvial识别为两个不同的分层元素,尺寸叠加成流入+流出的总和,同时数据流无法连贯衔接。桑基图要求每个完整的跨时段路径(t1→t2→t3)对应唯一的alluvium(即flow标识),这样才能保证节点衔接正确、尺寸符合实际流量。

解决方案

1. 构建完整路径数据集

首先要把两段流动数据合并为包含t1-t2-t3完整路径的数据集,同时保证中间节点的流入总量等于流出总量(桑基图的核心逻辑,否则节点尺寸会矛盾)。

针对你的示例数据,先调整data2的value使其与data1中t2的流入量匹配(如果实际业务中中间节点有人员增减,可参考后续的流量不守恒处理方案):

library(dplyr)
library(ggalluvial)
library(tidyr)

# 原始输入数据
data_1 <- tibble(t1 = c("A", "B", "B","C"),  
                 t2 = c("D", "E", "F", "G"),
                 value = c(99, 50, 50, 100))

# 调整data2的value,与data1中t2的流入量匹配(保证流量守恒)
data_2 <- tibble(t2 = c("D", "E", "F", "G"),  
                 t3 = c("H", "H", "I", "J"),
                 value = c(99, 50, 50, 100))

# 合并为t1→t2→t3的完整路径数据,每个路径对应唯一flow
data_full <- inner_join(data_1, data_2, by = "t2") %>%
  mutate(value = pmin(value.x, value.y), # 取流入流出的最小值确保守恒
         flow = 1:n()) %>%
  select(t1, t2, t3, value, flow)

# 转换为ggalluvial要求的长格式
data_long <- data_full %>%
  pivot_longer(cols = c(t1, t2, t3), 
               names_to = "time", 
               values_to = "district")

2. 绘制正确的桑基图

使用完整路径的长格式数据绘图,此时数据流会连贯穿过三个时间段,中间节点尺寸为对应流量的总和:

plot_alluvial <- ggplot(data = data_long,
                       aes(x = time,
                           stratum = district,
                           alluvium = flow,
                           y = value,
                           label = district)) +
  geom_flow(stat = "alluvium", lode.guidance = "backfront", color = "darkgray") +
  geom_stratum() +
  geom_text(stat = "stratum") +
  theme(legend.position = "bottom")

plot_alluvial

3. 处理流量不守恒的场景

如果实际业务中t2节点的流入和流出确实不相等(比如有人员滞留或新增),可以通过添加"增量/减量路径"来保证流量守恒。以你的原始数据为例(D流入99、流出100;E流入50、流出100等):

# 计算t2每个节点的流入流出差值
t2_balance <- data_1 %>%
  group_by(t2) %>%
  summarise(in_flow = sum(value)) %>%
  inner_join(data_2 %>% group_by(t2) %>% summarise(out_flow = sum(value)), by = "t2") %>%
  mutate(balance = out_flow - in_flow)

# 生成增量路径(比如D节点需要补充1单位流量,E节点补充50单位)
extra_flow <- t2_balance %>%
  filter(balance > 0) %>%
  mutate(t1 = "新增", # 用"新增"标识外部流入的流量
         t3 = data_2$t3[match(t2, data_2$t2)],
         value = balance) %>%
  select(t1, t2, t3, value)

# 合并原始路径和增量路径
data_full_with_extra <- bind_rows(
  inner_join(data_1, data_2, by = "t2") %>% mutate(value = pmin(value.x, value.y)),
  extra_flow
) %>%
  mutate(flow = 1:n())

# 转换长格式并绘图
data_long_extra <- data_full_with_extra %>%
  pivot_longer(cols = c(t1, t2, t3), names_to = "time", values_to = "district")

ggplot(data = data_long_extra,
       aes(x = time,
           stratum = district,
           alluvium = flow,
           y = value,
           label = district)) +
  geom_flow(stat = "alluvium", lode.guidance = "backfront", color = "darkgray") +
  geom_stratum() +
  geom_text(stat = "stratum") +
  theme(legend.position = "bottom")
核心要点
  • flow必须对应完整的跨时段路径,不能拆分两段独立定义,否则中间节点会被重复识别。
  • 桑基图要求中间节点的流入总量=流出总量,这是保证节点尺寸和数据流衔接正确的前提,需根据业务逻辑调整数据。

内容的提问来源于stack exchange,提问作者L Smeets

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 12:05:02