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

如何为含不同数值序列的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不会为硬编码的美学属性生成图例,因此无法直接提取共享图例。

修改后可运行代码

核心修改逻辑:

  1. 将颜色映射移入aes()内部,为三类折线统一指定分类标识
  2. 用scale_color_manual()全局统一三类折线的颜色映射,同时隐藏子图自带的图例避免重复
  3. 单独构建水平排列的底部共享图例,通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:45:40