ggplot2 - 如何在使用grid.arrange制作多个图形时添加唯一的图例?

6

我有一个使用ggplot2grid.arrange制作的包含4个面板的图。每个面板都有一个图例,这些图例都是相同的。

如何删除这4个图例,并在图的底部创建一个唯一的图例?

以下是我的样本数据和图:

set.seed(100)
df_1 = data.frame(lat = rnorm(20), 
                  lon = rnorm(20), 
                  cor = c(rep('positive', 7), rep('negative', 13)), 
                  sign = c(rep(99, 5), rep(95, 6), rep(90,9)))

lst_df = list(df_1, df_1, df_1, df_1)


library(ggplot2)
library(gridExtra)
library(grid)

for (i in 1:length(lst_df)) {
p[[i]] = ggplot() +

    geom_point(data=lst_df[[i]], aes(x=lon, y=lat, size=sign, colour = cor), alpha = 0.5) +

    scale_color_manual(values=c("blue", "orange"),
                       name='col', 
                       labels = c('neg', 'pos'),
                       guide = guide_legend(override.aes = list(alpha = 1, size = 3))) +

    scale_size(range = c(1,3), 
               breaks = c(90, 95, 99),
               labels = c(1, 5, 10),
               name = 'test',
               guide = guide_legend(override.aes = list(colour = 'black', 
                                                        alpha = 1)))
}


grid.arrange(p[[1]], p[[2]], p[[3]], p[[4]], 
             ncol=2, nrow=2,
             top=textGrob(expression(bold("test")), gp=gpar(fontsize=25, face= 'bold')))

在这里输入图像描述

有什么建议吗?谢谢。


2
如果你想从 grid.arrange 切换到 cowplot 包,那么在 cowplot 中做到这一点的方法有一个非常好的文档 - camille
2个回答

8
这是一个使用cowplot的工作流程,它提供了一些很棒的功能,可以将grobs组合在一起并提取元素,如图例。他们有一个详细的vignette,介绍了如何创建具有共享图例的绘图网格,就像您所寻找的那样。同样,绘图注释的vignette介绍了cowplot函数用于创建和添加标签--它们的功能与其他绘图元素类似,并且可以在cowplot::plot_grid中使用。
该过程基本上是:
  1. 使用lapply(也可以是循环)创建没有图例的绘图列表
  2. 提取其中一个图例--无论哪个,因为它们都是相同的--已设置为位于底部
  3. 为标题创建文本grob
  4. 从无图例的绘图列表创建网格
  5. 从标题、无图例的绘图网格和图例创建网格
作为旁注,加载cowplot会使其设置默认的ggplot主题,我不是特别喜欢,因此我使用cowplot::function符号代替library(cowplot)
您可以调整用于制作最终网格的相对高度 - 这是对我有效的第一个比例。
如果需要,我在几个月前发布了一个关于使draw_label grob采取主题指南的问题,就像您预期在正常的ggplot元素(如标题)中一样; 包作者和我的专业功能的答案在这里
library(ggplot2)
...

p_no_legend <- lapply(p, function(x) x + theme(legend.position = "none"))
legend <- cowplot::get_legend(p[[1]] + theme(legend.position = "bottom"))

title <- cowplot::ggdraw() + cowplot::draw_label("test", fontface = "bold")

p_grid <- cowplot::plot_grid(plotlist = p_no_legend, ncol = 2)
cowplot::plot_grid(title, p_grid, legend, ncol = 1, rel_heights = c(0.1, 1, 0.2))

这段文字是在2018年9月11日由reprex包(v0.2.0)创建的。


嗨!也许你可以在这里提供帮助:https://stackoverflow.com/questions/52666473/ggplot2-add-x-and-y-labels-to-multiple-plots-figure - aaaaa

2
正如Camille所指出的,cowplot有一种非常简单的方法来实现这一点。您还可以通过手动排列grobs来完成此操作。如果您具有不同宽度、比例和间断的绘图,则此方法特别有效。 这里有一个示例。 手动执行此操作的好处是,除非cowplot可以自动执行,否则可以指定哪些绘图获取x轴标签和y轴标题/标签,因此最终您只能在底部网格上拥有x轴标题/标签,在左侧网格上拥有y轴标题/标签。缺点是,如果您有多个绘图,则定义多个绘图函数会很繁琐。
df_plots <- lapply(lst_df, function(x) {
ggplot() +    
geom_point(data=lst_df[[i]], aes(x=lon, y=lat, size=sign, colour = cor), alpha = 0.5) +
scale_color_manual(values=c("blue", "orange"),
                   name='col', 
                   labels = c('neg', 'pos'),
                   guide = guide_legend(override.aes = list(alpha = 1, size = 3))) +
scale_size(range = c(1,3), 
           breaks = c(90, 95, 99),
           labels = c(1, 5, 10),
           name = 'test',
           guide = guide_legend(override.aes = list(colour = 'black', 
                                                    alpha = 1)))
})

df_leg <-  get_legend(df_plots[[1]]) # get legend

df_plots_noleg <- lapply(lst_df, function(x) { # make plots with no legends, however you want to do this
ggplot() +

geom_point(data=lst_df[[i]], aes(x=lon, y=lat, size=sign, colour = cor), alpha = 0.5) +

scale_color_manual(values=c("blue", "orange"),
                   name='col', 
                   labels = c('neg', 'pos'),
                   guide = guide_legend(override.aes = list(alpha = 1, size = 3))) +
theme(legend.position = "none")
})

如果您的图形开始在宽度上变化,对齐坐标轴非常重要。由于在本例中它们都是相同的,因此这并不重要。
#maxWidth_df_plots <- grid::unit.pmax(df_plots_noleg1$widths[2:5], df_plots_noleg2$widths[2:5], df_plots_noleg3$widths[2:5], df_plots_noleg4$widths[2:5]) #get your grob widths

#df_plots_noleg1$widths[2:5] <- as.list(maxWidth1Page1)
#df_plots_noleg2$widths[2:5] <- as.list(maxWidth1Page1)
#df_plots_noleg3$widths[2:5] <- as.list(maxWidth1Page1)
#df_plots_noleg4$widths[2:5] <- as.list(maxWidth1Page1)

df_plots1 <- ggplotGrob(df_plots_noleg[[1]])
df_plots2 <- ggplotGrob(df_plots_noleg[[2]])
df_plots3 <- ggplotGrob(df_plots_noleg[[3]])
df_plots4 <- ggplotGrob(df_plots_noleg[[4]])

df_plot_arranged <- grid.arrange(arrangeGrob(df_plots1, df_plots2, df_plots3, df_plots4, nrow = 2),
                             arrangeGrob(nullGrob(), df_leg, nullGrob(), nrow = 1), ncol = 1, heights = c(4,0.5),
                             top = textGrob("Title Text Holder Here", gp = gpar(fotsize = 12, font = 2)))

我提到的好处是您可以控制图表的标签。这就是控制宽度有所帮助的地方,正如您在图像中所看到的右侧图形比左侧图形更宽,而顶部的图形比底部的图形更高。

df_plots1 <- df_plots_noleg[[1]] + theme(axis.title.x = element_blank(), axis.text.x = element_blank())

df_plots2 <- df_plots_noleg[[2]] + theme(axis.title.x = element_blank(), axis.title.y = element_blank(),
                               axis.text.x = element_blank(), axis.text.y = element_blank())

df_plots4 <- df_plots_noleg[[4]] + theme(axis.title.y = element_blank(), axis.text.y = element_blank())

df_plots1 <- ggplotGrob(df_plots1)
df_plots2 <- ggplotGrob(df_plots2)
df_plots3 <- ggplotGrob(df_plots_noleg[[3]])
df_plots4 <- ggplotGrob(df_plots4)

df_plot_arranged <- grid.arrange(arrangeGrob(df_plots1, df_plots2, df_plots3, df_plots4, nrow = 2),
                             arrangeGrob(nullGrob(), df_leg, nullGrob(), nrow = 1), ncol = 1, heights = c(4,0.5),
                             top = textGrob("Title Text Holder Here", gp = gpar(fotsize = 12, font = 2)))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接