如何为两个同美学映射的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
相关产品推荐
相关产品推荐

