Sharing a Legend between two combined ggplots

2019-05-30 02:38发布

I'm currently trying to present two time series using ggplot2, both with very different scales, using two ggplots. I've combined the two separate ggplots, one on top of the other, using grid.arrange. In order to aid visualization, I'd like to make each line a different colour, and have this legend below the combined plot.

As this may be relevant, I'm currently working in the confines of creating a shiny section of an R markdown document. Hence the renderPlot wrapper around grid.arrange.

The following is similar to the code that I currently have.

testdata = data.frame(var1 = seq(0,10,by=1), var2 = runif(11), 
var3 = runif(11, min = 100, max = 500))

renderPlot({grid.arrange(
ggplot(data = testdata, aes(x = var1, y = var2))
+ geom_line(colour = "blue") + xlab(NULL),
ggplot(data = testdata, aes(x = var1, y = var3)) + geom_line(colour = "red"))})

Does anyone have any suggestions about how to create the shared legend? Thanks very much for your help.

1条回答
迷人小祖宗
2楼-- · 2019-05-30 03:28

using ggplot2 I usually use the following 2 methods to create a common legend:

Method 1 : When scales are similar

By using facet_grid or just the color parameter in combination with reshape2 package, you can easily combine multiple plots with same legend. But this is ideal in case the values in your variables have a similar magnitude order.

Using color & reshape2:

library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')

ggplot(data_melt)+
  geom_line(aes(x=var1,y=Value,color=variable))

High difference in magnitude leads to a poor plot, but similar scales might result in a good plot

Using color, facet_grid & reshape2:

library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')

ggplot(data_melt)+
 geom_line(aes(x=var1,y=Value,color=variable))+
 facet_grid(~variable)

High difference in magnitude leads to a poor plot, but similar scales might result in a good plot

Method 2: When scales differ wildly

Value vs ID plot : combined

As you can see,the final plot is great! All you need is to create a plot having your legend & pass it as an input parameter to the custom function created in the wiki here.

testdata = data.frame(var1 = seq(0,10,by=1), var2 = runif(11), 
                  var3 = runif(11, min = 100, max = 500))

library('reshape2')
data_melt<-melt(data=testdata,value.name='Value',id.vars='var1')

p1=ggplot(data = testdata)+
  geom_line(aes(x = var1, y = var2,color='blue'))

p2=ggplot(data = testdata) + 
  geom_line(aes(x = var1, y = var3,color='red'))

p3=ggplot(data_melt)+
   geom_line(aes(x=var1,y=Value,color=variable))

grid.arrange(p1,p2,nrow=2,main='Line Plots')

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

legend <- g_legend(p3)
lwidth <- sum(legend$width)

## using grid.arrange for convenience
## could also manually push viewports
grid.arrange(arrangeGrob(p1 + theme(legend.position="none"),
                         p2 + theme(legend.position="none"),
                         main ="Variable Name",
                         left = "Value"),
             legend, 
             widths=unit.c(unit(1, "npc") - lwidth, lwidth), nrow=1)
查看更多
登录 后发表回答