如何在ggplot桑基图中让右侧节点显示关联左侧节点的全部颜色?
问题描述
我用ggplot结合ggsankey包绘制桑基图,希望右侧节点能与左侧关联节点对应:若有多种来自左侧节点的颜色流入右侧节点,右侧节点需显示全部对应颜色。请问该需求是否可实现?若可以,该如何操作?
原数据集
df2 = structure(list(x = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), levels = c("Method_Group", "Topic"), class = "factor"), node = c("BRUV + Both", "Behavioural Ecology", "BRUV + Both", "Conservation Methods", "BRUV + Both", "Other Drivers", "Animal Borne + No Receiver", "Behavioural Ecology", "Controlled + Receiver", "Behavioural Ecology", "Controlled + Receiver", "Reproductive Ecology", "Controlled + Receiver", "Other Drivers", "Controlled + Receiver", "Behavioural Ecology", "Controlled + Receiver", "Methodological", "Animal Borne + No Receiver", "Behavioural Ecology", "Animal Borne + No Receiver", "Methodological", "Stationary + No Receiver", "Reproductive Ecology", "Stationary + No Receiver", "Landuse Management", "Stationary + No Receiver", "Other Drivers", "Animal Borne + No Receiver", "Behavioural Ecology", "Animal Borne + No Receiver", "Methodological", "Animal Borne + No Receiver", "Reproductive Ecology", "Stationary + Receiver", "Behavioural Ecology", "Stationary + Receiver", "Fisheries Managemenet", "Stationary + Receiver", "Behavioural Ecology", "Stationary + Receiver", "Methodological", "Stationary + Receiver", "Fisheries Managemenet", "BRUV + Both", "Behavioural Ecology", "BRUV + Both", "Methodological", "BRUV + Both", "Conservation Methods"), next_x = structure(c(2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA, 2L, NA), levels = c("Method_Group", "Topic"), class = "factor"), next_node = c("Behavioural Ecology", NA, "Conservation Methods", NA, "Other Drivers", NA, "Behavioural Ecology", NA, "Behavioural Ecology", NA, "Reproductive Ecology", NA, "Other Drivers", NA, "Behavioural Ecology", NA, "Methodological", NA, "Behavioural Ecology", NA, "Methodological", NA, "Reproductive Ecology", NA, "Landuse Management", NA, "Other Drivers", NA, "Behavioural Ecology", NA, "Methodological", NA, "Reproductive Ecology", NA, "Behavioural Ecology", NA, "Fisheries Managemenet", NA, "Behavioural Ecology", NA, "Methodological", NA, "Fisheries Managemenet", NA, "Behavioural Ecology", NA, "Methodological", NA, "Conservation Methods", NA)), row.names = c(NA, -50L), class = c("tbl_df", "tbl", "data.frame" ))
原绘图代码
devtools::install_github("davidsjoberg/ggsankey") library(ggsankey) library(dplyr) library(ggplot2) ggplot(df2, aes(x = x, next_x = next_x, node = node, next_node = next_node, fill = factor(node), label = node)) + geom_sankey(flow.alpha = 1, node.color = "black",show.legend = FALSE, width=0.40) + geom_sankey_label(size = 5, color = "black", fill= "white") + theme_bw() + theme(axis.title = element_blank() , axis.text.y = element_blank() , axis.text.x = element_blank() , axis.ticks = element_blank() , panel.grid = element_blank())+ scale_fill_viridis(discrete=TRUE)
解决方案
该需求可实现,核心逻辑是将右侧节点按流入的左侧节点拆分,让每个拆分出的子节点对应左侧节点的颜色,再通过布局堆叠让子节点视觉上合并为一个完整节点。具体操作如下:
步骤1:预处理数据集
先聚合原数据统计流量,再为右侧节点添加左侧节点标识,实现节点拆分:
library(dplyr) library(ggsankey) library(ggplot2) # 聚合统计左侧节点到右侧节点的流量,避免重复计算 df_agg <- df2 %>% filter(x == "Method_Group") %>% count(node, next_node, name = "flow") %>% ungroup() # 转换为ggsankey格式,为右侧节点绑定左侧节点标识用于拆分 df_sankey <- df_agg %>% make_long(node, next_node) %>% mutate(node = ifelse(x == 2, paste0(node, "_", previous), node))
步骤2:绘制桑基图并调整布局
修改绘图代码,让右侧拆分节点堆叠显示,同时保持标签统一:
ggplot(df_sankey, aes(x = x, next_x = next_x, node = node, next_node = next_node, fill = previous, label = ifelse(x == 2, gsub("_.*", "", node), node))) + # 堆叠右侧子节点,形成完整节点视觉效果 geom_sankey(flow.alpha = 1, node.color = "black", show.legend = FALSE, width = 0.4, position = position_stack(vjust = 0.5)) + # 右侧节点显示原名称,去掉拆分用的后缀 geom_sankey_label(size = 5, color = "black", fill = "white") + theme_bw() + theme(axis.title = element_blank(), axis.text.y = element_blank(), axis.text.x = element_blank(), axis.ticks = element_blank(), panel.grid = element_blank()) + scale_fill_viridis(discrete = TRUE)
关键逻辑解释
- 数据聚合:原数据存在重复行,先统计流量确保桑基图的流宽度准确。
- 节点拆分:为右侧节点添加左侧节点后缀,让ggsankey识别为不同子节点,但通过标签处理隐藏后缀,视觉上仍为一个节点。
- 堆叠布局:
position_stack(vjust = 0.5)让拆分后的子节点紧密堆叠,形成完整节点的视觉效果,每个子节点颜色对应流入的左侧节点。
内容的提问来源于stack exchange,提问作者Kristen Cyr
相关产品推荐
相关产品推荐

