如何用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,因此无法合并图例。
修改步骤
- 在每个
scale_color_manual、scale_linetype_manual、scale_shape_manual中添加drop=FALSE参数,强制保留所有定义的breaks类别,确保三个子图的scale完全一致。 - (可选)将重复的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
相关产品推荐
相关产品推荐

