0

I used marrangeGrob() instead of facet_wrap() to produce my plots from a list of plots. However, I can't seem to add a legend.

I already extracted my legend using

    g_legend<-function(a.gplot){
      tmp <- ggplot_gtable(ggplot_build(a.gplot))
      leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
      legend <- tmp$grobs[[leg]]
      return(legend)}

However, I am unable to add it it my plot. Does anyone know a way?

Sean Xu
  • 11
  • 1
  • 3
  • Well, we need to see what code you're running, preferably with sample data that allows us to recreate your plots and legend, to see what's going wrong. If you have, say, two plots, `p1` and `p2` and you heve the legend in an object called `leg`, then, for example, `marrangeGrob(p1, p2, leg, widths=c(5,5,1))` should work. – eipi10 Mar 04 '17 at 00:26
  • hmmm it more like I have a grob named leg and plot1<-marrangeGrob(list_of_plots,ncol=4,nrow=5). I want to add legend onto the pdf I produce from this – Sean Xu Mar 04 '17 at 00:55
  • The `g_legend` function returns a grob of the legend. You need to include this grob in the call to `marrangeGrob`. If you provide a reproducible example, I can provide code. – eipi10 Mar 04 '17 at 01:13

1 Answers1

1

Here's an example using the built-in diamonds data frame:

library(ggplot2)
library(gridExtra)
library(dplyr)

g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}

First we'll create two plots to lay out together:

df <- count(diamonds, cut)

p1 = ggplot(df, aes(x=cut, y=n, label=format(n, big.mark=","), fill=cut)) +
  geom_bar(stat="identity") +
  geom_text(aes(y=0.5*n), colour="white") +
  coord_flip() +
  theme(legend.position="bottom")

p2 = ggplot(diamonds %>% sample_n(1000), aes(x=carat, y=price, colour=cut)) +
  geom_point() 

Now save the legend from p1 as a separate grob:

leg = g_legend(p1)

Lay out the two plots side-by-side using arrangeGrob and then use marrangeGrob to lay out the two-plot layout and the legend beneath it. Note that we also remove the legends from the original plots.

marrangeGrob(grobs=list(
  arrangeGrob(grobs=lapply(list(p1,p2), function(p) {
    p + guides(colour=FALSE, fill=FALSE)
  }), ncol=2),
  leg), ncol=1, nrow=2, heights=c(20,1))

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • In my case, instead of having p1 and p2, my dataframes were orginally in a list. list_df = [df1],[df2],.... I used lapply(list_df,ggplot) to create a list of ggplots. Would your solution still work with this? – Sean Xu Mar 04 '17 at 01:26
  • My solution uses a list of ggplots (`list(p1, p2)`). In your case, the list is `plot_list = lapply(list_df, ggplot)` or whatever you do to create your list of plots. – eipi10 Mar 04 '17 at 01:31
  • 1
    I see I got it working but I am also looking to create the plots on multiple pages (I have 40 and want to make 2 pages of 20). Is there a way I can implement that onto arrangeGrob() – Sean Xu Mar 08 '17 at 20:18
  • also I tried to make the legend on the side by doing ncol=2 nrow=1 height=c(20) but the legend takes up half the page. Is there a way to change that? – Sean Xu Mar 08 '17 at 20:26
  • For the second question, allocate less space to the legend by using `widths=c(10,1)` when you lay out the two plots and legend side-by-side. – eipi10 Mar 08 '17 at 21:52
  • Thank you so much! I figured it out! – Sean Xu Mar 08 '17 at 22:58