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

为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:07:50