如何为含不同数值序列的ggplot2组合图添加底部统一图例
ggplot2组合图底部添加统一图例实现方案
问题背景
使用cowplot::plot_grid()拼接两张ggplot2子图时,需要在组合图底部添加跨子图的统一图例,涉及三类折线序列:
- 子图A:
targeted(色值#0072b2)、non_targeted(色值#d55e00) - 子图B:
response(对应字段nuisance_reports,色值#f0e442)
当前代码运行效果如下:
原有问题代码
A <- ggplot(placeholder) + geom_line(aes(x=date, y= targeted), color='#0072b2', group= 1, size=1.25) + geom_line(aes(x=date, y= non_targeted), color='#d55e00' , group= 1, size=1.25) + theme(axis.text.x = element_text(angle = 90)) + labs(y= "Y1", x = "Date") + theme_classic() + theme(axis.text.x = element_text(angle = 90)) A B <- ggplot(media_analysis) + geom_line(aes(x=date, y= nuisance_reports), color='#f0e442', group= 1, size=1.25) + theme(axis.text.x = element_text(angle = 90)) + labs(y= "Y2", x = "Date") + theme_classic() + theme(axis.text.x = element_text(angle = 90)) B combined <- plot_grid(A, B, labels = c("A", "B"), ncol = 2, nrow = 1) combined
问题原因
原有代码将折线颜色硬编码在geom_line()的aes()外部,ggplot不会为硬编码的美学属性生成图例,因此无法直接提取共享图例。
修改后可运行代码
核心修改逻辑:
- 将颜色映射移入
aes()内部,为三类折线统一指定分类标识 - 用
scale_color_manual()全局统一三类折线的颜色映射,同时隐藏子图自带的图例避免重复 - 单独构建水平排列的底部共享图例,通过
get_legend()提取后拼接到组合图底部
library(ggplot2) library(cowplot) # 绘制子图A A <- ggplot(placeholder) + geom_line(aes(x = date, y = targeted, color = "targeted"), group = 1, size = 1.25) + geom_line(aes(x = date, y = non_targeted, color = "non_targeted"), group = 1, size = 1.25) + scale_color_manual( values = c("targeted" = "#0072b2", "non_targeted" = "#d55e00", "response" = "#f0e442"), breaks = c("targeted", "non_targeted", "response") ) + labs(y = "Y1", x = "Date") + theme_classic() + theme( axis.text.x = element_text(angle = 90), legend.position = "none" # 关闭子图自带图例 ) # 绘制子图B B <- ggplot(media_analysis) + geom_line(aes(x = date, y = nuisance_reports, color = "response"), group = 1, size = 1.25) + scale_color_manual( values = c("targeted" = "#0072b2", "non_targeted" = "#d55e00", "response" = "#f0e442"), breaks = c("targeted", "non_targeted", "response") ) + labs(y = "Y2", x = "Date") + theme_classic() + theme( axis.text.x = element_text(angle = 90), legend.position = "none" # 关闭子图自带图例 ) # 构建并提取水平排列的共享图例 legend_tmp <- ggplot() + geom_line( data = data.frame(x = 1, y = 1, type = factor(c("targeted", "non_targeted", "response"), levels = c("targeted", "non_targeted", "response"))), aes(x = x, y = y, color = type), size = 1.25 ) + scale_color_manual( values = c("targeted" = "#0072b2", "non_targeted" = "#d55e00", "response" = "#f0e442"), labels = c("targeted", "non_targeted", "response") ) + labs(color = NULL) + theme_classic() + theme( legend.position = "bottom", legend.direction = "horizontal", legend.box = "horizontal" ) shared_legend <- get_legend(legend_tmp) # 拼接最终组合图 combined_subplots <- plot_grid( A, B, labels = c("A", "B"), ncol = 2, nrow = 1 ) final_plot <- plot_grid( combined_subplots, shared_legend, ncol = 1, rel_heights = c(1, 0.12) # 可根据显示效果调整图例占比,数值越大图例区域越高 ) # 输出图像 print(final_plot)
调整说明
- 两个子图中
scale_color_manual()的values、breaks参数必须完全一致,否则会出现颜色和类别不匹配的问题 rel_heights参数可根据输出尺寸灵活调整,若图例显示被裁剪可适当增大第二个数值- 若需要给图例加标题,删除
labs(color = NULL)这一行,在括号内填入需要的标题文本即可
内容的提问来源于stack exchange,提问作者Hartje
相关产品推荐
相关产品推荐

