0

I am struggling a little bit of sharing common legend between two ggplot plots, which I have arranged using arrange.grid. The closest I got is this:

Plot a legend and well-spaced universal y-axis and main titles in grid.arrange but using ideas from here I only get common legend either at the bottom or at the top. Here is my attempt:

library(ggplot2)
p1<-ggplot(data=diamonds)+geom_bar(aes(x=cut,fill=color))+scale_x_discrete("")+ylab("")+ggtitle("Title 1")
p2<-ggplot(data=diamonds)+geom_bar(aes(x=cut,fill=color))+scale_x_discrete("")+ylab("")+ggtitle("Title 2")
legend = gtable_filter(ggplotGrob(p1), "guide-box") 
grid.arrange(arrangeGrob(p1 + theme(legend.position="none"), 
                         p2 + theme(legend.position="none"),
                         nrow = 1,
                         top = textGrob("Main Title", vjust = -6, gp = gpar(fontface = "bold", cex = 1.5)),
                         left = textGrob("Global Y-axis Label", rot = 90, vjust = 2.5),
                         bottom = textGrob("Global X-axis Label", vjust =-1)),
             legend,
             nrow=1)

Also this tutorials only shows how to put either at the bottom or at the side:

https://cran.r-project.org/web/packages/cowplot/vignettes/shared_legends.html

Using this solution helps but the graph still looks quite ugly.

p1<-ggplot(data=diamonds)+geom_bar(aes(x=cut,fill=color))+scale_x_discrete("")+ylab("")+ggtitle("Title 1")+guides(fill = guide_legend(title.position = "top",nrow=1))+theme(legend.position = "top", plot.title=element_text(hjust = 0,vjust=-1))
p2<-ggplot(data=diamonds)+geom_bar(aes(x=cut,fill=color))+scale_x_discrete("")+ylab("")+ggtitle("Title 2")

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

mylegend<-g_legend(p1)

grid.arrange(mylegend,nrow=2,heights=c(0.2,1),
             arrangeGrob(p1+ theme(legend.position="none"),
                         p2+ theme(legend.position="none"),
                        top = textGrob("Main Title", vjust =-6, gp = gpar(fontface = "bold", cex = 1.5)),
                        left = textGrob("Global Y-axis Label", rot = 90, vjust = 2.5),
                        bottom = textGrob("Global X-axis Label", vjust =-1),
                        nrow=1))
Vitalijs
  • 938
  • 7
  • 18

1 Answers1

2

You can use this function

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

And then you can do the following

plot1 <- ggplot(...) + ... 

mylegend<-g_legend(plot1)

plot2 <- ggplot(...) + ... +  theme(legend.position="none")



  grid.arrange(arrangeGrob(plot1+ theme(legend.position="none")
                          ,plot2
                          nrow=1),
          mylegend,nrow=2,heights=c(10,1))

UPDATE

To put the legend on top try this

  grid.arrange(mylegend,nrow=2,heights=c(0.05,1),
               arrangeGrob( plot1+ theme(legend.position="none")
                           ,plot2
                           ,nrow=1)
               )

You might need to experiment a bit with the 0.05 in the heights=c(0.05,1)

quant
  • 4,062
  • 5
  • 29
  • 70
  • This legend will appear at the bottom of the joint plot not at the top – Vitalijs May 30 '17 at 14:47
  • Did you try at your first plot putting the `legend.position = "top"` ? – quant May 30 '17 at 14:53
  • I added your solution but it still does not help because now legend is above my main title – Vitalijs May 30 '17 at 15:21
  • Maybe try doing the same, but then with R Markdown ? Because there you can put a title on the page, and then add the graph below, which in your case will be the same graph as before, but without the title. Otherwise I cannot see any other way to go through it – quant May 31 '17 at 10:03