为ggplot2组合分面图添加独立分组图例的技术问询
为ggplot2分面条形图添加分面独立图例
现有数据集如下:
head(data,10) Ratio Wealthness Cash Quality Variants 1 A A E G r 2 D B A C u 3 C B C E s 4 A C E A s 5 D B A D y 6 C B D D x 7 B C D D v 8 D C C D y 9 B C B A x 10 A A D G u
基于现有代码生成了分面填充条形图,但当前所有分面共享一个顶部图例。由于实际数据中分组数量可达1-1000,部分分组仅出现一次,统一图例无法清晰区分各分面的分组对应关系,需要为每个分面(Ratio、Wealthness、Cash、Quality)添加独立图例,展示该变量专属的分组及对应颜色。
原绘图代码:
library(ggplot2) library(tidyr) color_clrs <- c( A = "white", B = "black", C = "black", D = "white", E = "black", F = "white", G = "white" ) fill_clrs <- c( A = "#1f3560", B = "#B0C4DE", C = "#f2f3f3", D = "#ff0000", E = "#A9A9A9", F = "#B22222", G = "#1E90FF" ) ggplot(data %>% pivot_longer(-Variants), aes(Variants, fill = value)) + geom_bar(position = "fill") + geom_text(stat = "count", aes(label = after_stat(count), color = value), position = position_fill(vjust = 0.5), show.legend = FALSE) + facet_wrap(~name) + scale_x_discrete(limit = rev) + scale_y_continuous(trans = "reverse") + scale_fill_manual(values = fill_clrs) + scale_color_manual(values = color_clrs) + coord_flip() + theme_classic() + theme(legend.position = "top", axis.ticks.x = element_blank(), axis.text.x = element_blank())
解决方案
ggplot2原生不支持分面独立图例,我们可以通过拆分每个变量单独绘图,再用patchwork包拼接的方式实现需求:
library(ggplot2) library(tidyr) library(patchwork) library(purrr) # 颜色配置保持不变 color_clrs <- c( A = "white", B = "black", C = "black", D = "white", E = "black", F = "white", G = "white" ) fill_clrs <- c( A = "#1f3560", B = "#B0C4DE", C = "#f2f3f3", D = "#ff0000", E = "#A9A9A9", F = "#B22222", G = "#1E90FF" ) # 整理数据并按变量拆分 long_data <- data %>% pivot_longer(-Variants) split_data <- split(long_data, long_data$name) # 定义绘图函数 plot_single_facet <- function(df) { # 获取当前变量的唯一分组值 current_values <- unique(df$value) # 过滤颜色映射,只保留当前分组的颜色 current_fill <- fill_clrs[names(fill_clrs) %in% current_values] current_color <- color_clrs[names(color_clrs) %in% current_values] ggplot(df, aes(Variants, fill = value)) + geom_bar(position = "fill") + geom_text(stat = "count", aes(label = after_stat(count), color = value), position = position_fill(vjust = 0.5), show.legend = FALSE) + scale_x_discrete(limit = rev) + scale_y_continuous(trans = "reverse") + scale_fill_manual(values = current_fill, name = unique(df$name)) + scale_color_manual(values = current_color) + coord_flip() + theme_classic() + theme( legend.position = "top", axis.ticks.x = element_blank(), axis.text.x = element_blank(), # 统一各图的轴标签,避免重复 axis.title.y = ifelse(unique(df$name) == names(split_data)[1], element_text(), element_blank()) ) } # 批量生成子图并拼接 plots <- map(split_data, plot_single_facet) wrap_plots(plots, ncol = 2) + plot_layout(guides = "collect")
关键说明
- 用
split()将长格式数据按变量名拆分为多个子集,每个子集对应一个分面的内容 - 自定义
plot_single_facet()函数,针对每个子集仅保留其出现过的分组颜色映射,确保图例只显示当前变量的分组 - 使用
patchwork的wrap_plots()拼接所有子图,通过plot_layout(guides = "collect")让每个图例对应各自的子图,布局更整齐 - 统一轴标签设置,避免多个子图重复显示Y轴标签
内容的提问来源于stack exchange,提问作者Bambeil
相关产品推荐
相关产品推荐

