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

如何为两个同美学映射的geom_col设置独立图例?

问题

想要绘制具有相同美学映射、不同条形宽度的重叠堆叠条形图。当前方案是添加两个geom_col,使用相同的填充美学映射(对应category),仅对数据集按status过滤后分别绘制,其中plan条形设为半透明(alpha=0.5),actual条形宽度设为0.5。但此时仅显示category的单一图例,尝试将alpha放入aes()并添加scale_alpha_manual后,虽得到额外图例,但填充颜色显示错误。如何实现目标绘图并拥有两个独立图例(一个对应category颜色,一个对应status透明度)?

示例代码:

library(tidyverse)

data <- tribble(
  ~status , ~category , ~month , ~value ,
  'plan' , 'A' , 'Jan' , 5000 ,
  'plan' , 'A' , 'Feb' , 4900 ,
  'plan' , 'A' , 'Mar' , 4900 ,
  'plan' , 'B' , 'Jan' , 0 ,
  'plan' , 'B' , 'Feb' , 499 ,
  'plan' , 'B' , 'Mar' , 600 ,
  'actual' , 'A' , 'Jan' , 5200 ,
  'actual' , 'A' , 'Feb' , 4950 ,
  'actual' , 'A' , 'Mar' , 4700 ,
  'actual' , 'B' , 'Jan' , 0 ,
  'actual' , 'B' , 'Feb' , 380 ,
  'actual' , 'B' , 'Mar' , 400
) |>
  mutate(month = factor(month , levels = month.abb[1:3]))

data |>
  ggplot(mapping = ggplot2::aes(x = month , y = value)) +
  geom_col(data = ~ . |> filter(status == 'plan') ,
                    mapping = ggplot2::aes(fill = category) ,
                    alpha = 0.5 ,
                    position = position_stack(reverse = TRUE)) +
  geom_col(data = ~ . |> filter(status == 'actual') ,
                    mapping = aes(fill = category) ,
                    position = position_stack(reverse = TRUE) ,
                    width = 0.5) +
  scale_fill_manual(name = 'Category' ,
                             values = c('A' = '#628395' , 'B' = '#95A472') ,
                             labels = c('A' = 'one' , 'B' = 'two'))

解决方案

核心思路是将status作为独立的美学映射绑定到alpha,同时保持fill与category的绑定,通过分别设置对应的scale来生成两个独立图例:

library(tidyverse)

data <- tribble(
  ~status , ~category , ~month , ~value ,
  'plan' , 'A' , 'Jan' , 5000 ,
  'plan' , 'A' , 'Feb' , 4900 ,
  'plan' , 'A' , 'Mar' , 4900 ,
  'plan' , 'B' , 'Jan' , 0 ,
  'plan' , 'B' , 'Feb' , 499 ,
  'plan' , 'B' , 'Mar' , 600 ,
  'actual' , 'A' , 'Jan' , 5200 ,
  'actual' , 'A' , 'Feb' , 4950 ,
  'actual' , 'A' , 'Mar' , 4700 ,
  'actual' , 'B' , 'Jan' , 0 ,
  'actual' , 'B' , 'Feb' , 380 ,
  'actual' , 'B' , 'Mar' , 400
) |>
  mutate(month = factor(month , levels = month.abb[1:3]))

data |>
  ggplot(mapping = aes(x = month , y = value)) +
  # 绘制plan堆叠条形,绑定alpha到status
  geom_col(data = ~ . |> filter(status == 'plan') ,
           mapping = aes(fill = category, alpha = status),
           position = position_stack(reverse = TRUE)) +
  # 绘制actual堆叠条形,绑定alpha到status,设置宽度
  geom_col(data = ~ . |> filter(status == 'actual') ,
           mapping = aes(fill = category, alpha = status),
           position = position_stack(reverse = TRUE),
           width = 0.5) +
  # 设置category对应的填充颜色与图例
  scale_fill_manual(name = 'Category' ,
                    values = c('A' = '#628395' , 'B' = '#95A472') ,
                    labels = c('A' = 'one' , 'B' = 'two')) +
  # 设置status对应的透明度与图例
  scale_alpha_manual(name = 'Status',
                     values = c('plan' = 0.5, 'actual' = 1),
                     labels = c('plan' = 'Plan', 'actual' = 'Actual')) +
  # 可选:调整图例位置避免重叠
  theme(legend.position = "bottom")

关键说明

  • 给每个geom_col的aes中添加alpha = status,让ggplot将status识别为独立的美学维度,从而生成透明度图例。
  • 通过scale_alpha_manual明确指定plan和actual对应的透明度值,同时自定义图例名称与标签,确保图例清晰易懂。
  • 保留fill与category的绑定关系,通过scale_fill_manual控制类别颜色,保证填充颜色与原需求一致。
  • 这种方式将两个美学映射(fill、alpha)完全独立,不会出现颜色显示异常的问题,最终会生成两个独立的图例:一个展示类别对应的颜色,一个展示状态对应的透明度区别。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:53:11