ggplot2-如何使用grid.arrange为多个图添加唯一图例?

时间:2018-09-11 14:46:36

标签: r ggplot2 legend

我有一个图,其中有四个由ggplot2grid.arrange组成的面板。每个面板都有一个图例,所有图例都相同。

如何删除图例中的底部的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')))

enter image description here

有什么建议吗? 谢谢

2 个答案:

答案 0 :(得分:5)

这是一个带有cowplot的工作流程,它提供了一些精巧的功能,用于将杂项组合在一起并提取图例等元素。他们有detailed vignette来创建带有共享图例的图网格,就像您正在寻找的图例一样。同样,plot annotations上的装饰图案会越过cowplot函数来创建和添加标签-它们的功能与其他图元素非常相似,并且可以在cowplot::plot_grid中使用。

该过程基本上是

  1. 使用lapply创建一个没有图例的地块列表(可以是循环)
  2. 提取其中一个传奇-无关紧要,因为它们都是相同的-设置在最下方
  3. 为标题创建文本框
  4. 从无图例的情节列表中创建网格
  5. 根据标题,无图例的情节网格和图例创建网格

顺便说一句,加载cowplot使其可以设置其默认的ggplot主题,这不是我特别喜欢的主题,因此我使用cowplot::function表示法代替了library(cowplot)

您可以调整用于制作最终网格的相对高度-这是最适合我的第一个比率。

如果出现的话,几个月前,我发布了一个问题,内容是如何使draw_label成为主题主题指南,就像您期望的一般ggplot元素(如标题)那样;软件包作者和我的专业职能部门提供的答案是here

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))

reprex package(v0.2.0)于2018-09-11创建。

答案 1 :(得分:2)

正如卡米尔指出的那样,cowplot有一个非常简单的方法。您也可以通过手动安排grobs来做到这一点。如果您的图具有不同的宽度,比例和折点,则效果特别好。 One example here.

除非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)))