ggplot2: Two Or More Plots Sharing The Same Legend
Sometimes there is a need to combine two or more different plots that have a common legend. If these plots were placed in the same window, then one of the legends would be redundant.
This post shows how two ggplot2 plots can share the same legend. The solution was inspired by a thread on the ggplot2 mailinglist.
Let’s assume that we want to plot the following two relationships in the R’s built-in dataset mtcars, and use colour to display the cars with varying number of cylinders on the graph.:
a) Miles/(US) gallon – Gross horsepower – Number of cylinders
b) Weight (lb/1000) – Displacement (cu.in.) – Number of cylinders
Using qplot we first create the two plots, and make sure that the legends are not displayed by specifying opts(legend.position = "none"). Next we create a plot that displays only the legend, all the other elements of the plot are removed by opts(keep= "legend_box"). Finally, the two plots and the legend plot are placed onto a page with the help of grid.layout(), resulting in two plots with different axis sharing the same legend.
> library(ggplot2) > p <- qplot(data = mtcars, mpg, hp, geom = "point", colour = cyl) > p1 <- p + opts(legend.position = "none") > p2 <- qplot(data = mtcars, wt, disp, geom = "point", colour = cyl) + opts(legend.position = "none") > legend <- p + opts(keep = "legend_box") |
> Layout <- grid.layout(nrow = 2, ncol = 2, widths = unit(c(2, 0.4), c("null", "null")), heights = unit(c(1, 1), c("null", "null"))) > vplayout <- function(...) { grid.newpage() pushViewport(viewport(layout = Layout)) } > subplot <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y) |
> vplayout() > print(p1, vp = subplot(1, 1)) > print(p2, vp = subplot(2, 1)) > print(legend, vp = subplot(1:2, 2)) |

Thanks for this template! I built upon this post to make a 2D plot with histograms (or better: density plots) for each axis: http://blog.mckuhn.de/2009/09/learning-ggplot2-2d-plot-with.html
what about if the data frames for plot1 and plot2 are different how can we share a legend for the two plots while we put them in the same are likes the example you give ?
You can specify the data frame used by setting data=….
Legend is independent of plot1 and plot2, so it is up to you to come up with a suitable legend.
Thanks! I’m still learning ggplot2 learing-by-doing-style. Your post was more an more helpful than Hadley’s UseR book.
It seems the “viewport” function does not exist any more. Does anyone else have this problem (with an up-to-date ggplot2)? Is there a new, easier solution?
If you are using the new ggplot2 version (>=0.9.0), that’s the reason.
ggplot2 now has a NAMESPACE, so it doesn’t attach other packages like plyr, reshape2 or grid when loaded.
Since viewport is a function found on package grid, you should explicitly attach it using library(grid) to use it.
I’m actually looking for a solution to this issue. I’ll let you know as soon as I find something. Cheers, S.
When I run this code, I end up with a little squished plot in the right hand column, with the legend. How do I fix this?
ggplto2 syntax changed in version 0.9.2 – this might be the reason.
I try to make the same example in R but the part when I am supposed to create a plot with nly the legend usin opts(keep=”legend_box”) it doesn´t work. I keep gatting a the same plot p. Do you know what could be the reason?
Thanks
The syntax changed in version 0.9.0.
Check this link for inspiration.
in the ggplot2 mailing someone asked abut how to reproduce this example with the new syntax in ggplot 0.9.x and Hadley response was to use gtable() because is the more maintainable option for future version: http://article.gmane.org/gmane.comp.lang.r.ggplot2/5791
in the ggplot2 mailing someone asked abut how to reproduce this example with the new syntax in ggplot 0.9.x and Hadley response was to use gtable() because is the more maintainable option for future version: http://article.gmane.org/gmane.comp.lang.r.ggplot2/5791
>> QUOTE
Kohske Takahashi
wrote:
> Here is a 0.9.2 compatible example:
>
> […..]
> p1 \ p2 \
> gt1 \ gt2 \
> gt \ gt \ gt \ gt \
> grid.newpage()
> grid.draw(gt)
> […]
And this style of code (using gtables) will continue to work in the
future, except will hopefully provide better abstractions so that it’s
easier to see what’s going on.
Hadley
<<END-OF-QUOTE