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

如何用patchwork/ggarrange合并ggplot多图的统一图例?

解决ggplot多子图合并公共图例的问题

我现在遇到了ggplot子图图例合并的问题:用patchwork的plot_layout(guides="collect")或者ggarrange的公共图例功能,都无法将三个子图的图例合并成一个。每个子图都设置了相同的scale_*_manual()参数,但因为子图过滤后的数据只包含部分food类别,最终还是生成了三个独立图例。

当前图形效果:
当前图形效果

期望的图形效果:
期望图形效果

原代码如下:

plot_size_p = ggplot (filter(snail_size, food %in% c("C","J","K","L")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_linerange(aes(ymin=mean_size-SEM_size, ymax=mean_size+SEM_size, color=food)) +
  geom_point (aes(color = food, shape=infected)) +
  geom_line (aes(color = food, linetype=infected))+
  scale_color_manual(breaks = c("F","I","H","G","L","K","J","O","N","M","C"),labels = c("100% Pleco Wafers","High N","Med N","Low N","High P","Med P","Low P","High (N+P)","Med (N+P)","Low (N+P)", "Baseline"),values = c("green4", brewer.pal(9, "Reds")[7],brewer.pal(9, "Reds")[6],brewer.pal(9, "Reds")[5],brewer.pal(9, "Blues")[7],brewer.pal(9, "Blues")[6],brewer.pal(9, "Blues")[5],brewer.pal(9, "Purples")[7],brewer.pal(9, "Purples")[6],brewer.pal(9, "Purples")[5], "grey"))+
  scale_linetype_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(1,2))+
  scale_shape_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(19,17))

plot_size_n = ggplot (filter(snail_size, food %in% c("C","G","H","I")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_linerange(aes(ymin=mean_size-SEM_size, ymax=mean_size+SEM_size, color=food)) +
  geom_point (aes(color = food, shape=infected)) +
  geom_line (aes(color = food, linetype=infected))+
  scale_color_manual(breaks = c("F","I","H","G","L","K","J","O","N","M","C"),labels = c("100% Pleco Wafers","High N","Med N","Low N","High P","Med P","Low P","High (N+P)","Med (N+P)","Low (N+P)", "Baseline"),values = c("green4", brewer.pal(9, "Reds")[7],brewer.pal(9, "Reds")[6],brewer.pal(9, "Reds")[5],brewer.pal(9, "Blues")[7],brewer.pal(9, "Blues")[6],brewer.pal(9, "Blues")[5],brewer.pal(9, "Purples")[7],brewer.pal(9, "Purples")[6],brewer.pal(9, "Purples")[5], "grey"))+
  scale_linetype_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(1,2))+
  scale_shape_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(19,17))

plot_size_np = ggplot (filter(snail_size, food %in% c("C","M","N","O")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_point (aes(color = food, shape=infected)) +
  geom_line (aes(color = food, linetype=infected))+
  scale_color_manual(breaks = c("F","I","H","G","L","K","J","O","N","M","C"),labels = c("100% Pleco Wafers","High N","Med N","Low N","High P","Med P","Low P","High (N+P)","Med (N+P)","Low (N+P)", "Baseline"),values = c("green4", brewer.pal(9, "Reds")[7],brewer.pal(9, "Reds")[6],brewer.pal(9, "Reds")[5],brewer.pal(9, "Blues")[7],brewer.pal(9, "Blues")[6],brewer.pal(9, "Blues")[5],brewer.pal(9, "Purples")[7],brewer.pal(9, "Purples")[6], brewer.pal(9, "Purples")[5], "grey"))+
  scale_linetype_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(1,2))+
  scale_shape_manual(breaks=c(0,1), labels=c("Uninfected","Infected"), values=c(19,17))

size_plots = wrap_plots(plot_size_p,plot_size_n,plot_size_np, nrow = 1, ncol = 3)+ 
  plot_layout(guides = "collect")
size_plots

解决方案

问题根源

ggplot的scale_*_manual()默认参数drop=TRUE,会自动移除当前子图数据中不存在的类别。这导致每个子图的scale实际包含的类别不一致,patchwork无法识别为统一的scale,因此无法合并图例。

修改步骤

  1. 在每个scale_color_manual、scale_linetype_manual、scale_shape_manual中添加drop=FALSE参数,强制保留所有定义的breaks类别,确保三个子图的scale完全一致。
  2. (可选)将重复的scale定义提取为变量,减少代码冗余,方便后续维护。

修改后的完整代码

# 先定义统一的scale变量,避免重复代码
color_scale <- scale_color_manual(
  breaks = c("F","I","H","G","L","K","J","O","N","M","C"),
  labels = c("100% Pleco Wafers","High N","Med N","Low N","High P","Med P","Low P","High (N+P)","Med (N+P)","Low (N+P)", "Baseline"),
  values = c("green4", brewer.pal(9, "Reds")[7],brewer.pal(9, "Reds")[6],brewer.pal(9, "Reds")[5],
             brewer.pal(9, "Blues")[7],brewer.pal(9, "Blues")[6],brewer.pal(9, "Blues")[5],
             brewer.pal(9, "Purples")[7],brewer.pal(9, "Purples")[6],brewer.pal(9, "Purples")[5], "grey"),
  drop = FALSE  # 关键参数:保留所有breaks类别
)

linetype_scale <- scale_linetype_manual(
  breaks=c(0,1), 
  labels=c("Uninfected","Infected"), 
  values=c(1,2),
  drop = FALSE
)

shape_scale <- scale_shape_manual(
  breaks=c(0,1), 
  labels=c("Uninfected","Infected"), 
  values=c(19,17),
  drop = FALSE
)

# 绘制子图
plot_size_p = ggplot (filter(snail_size, food %in% c("C","J","K","L")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_linerange(aes(ymin=mean_size-SEM_size, ymax=mean_size+SEM_size, color=food)) +
  geom_point() +
  geom_line() +
  color_scale +
  linetype_scale +
  shape_scale

plot_size_n = ggplot (filter(snail_size, food %in% c("C","G","H","I")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_linerange(aes(ymin=mean_size-SEM_size, ymax=mean_size+SEM_size, color=food)) +
  geom_point() +
  geom_line() +
  color_scale +
  linetype_scale +
  shape_scale

plot_size_np = ggplot (filter(snail_size, food %in% c("C","M","N","O")), aes(x = week, y = mean_size, color = food, shape=infected, linetype=infected)) +
  labs(color = "Resource Type",
       linetype = "Parasite Status",
       shape = "Parasite Status")+
  geom_point() +
  geom_line() +
  color_scale +
  linetype_scale +
  shape_scale

# 合并子图并收集图例
size_plots = wrap_plots(plot_size_p,plot_size_n,plot_size_np, nrow = 1, ncol = 3) + 
  plot_layout(guides = "collect")
size_plots

效果说明

添加drop=FALSE后,三个子图的scale完全匹配,patchwork的guides="collect"会自动将所有图例合并为一个,放置在图形右侧(或指定位置),与期望的效果一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:57:01