g_legend
reposition_legend
grid_arrange_shared_legend
ggplot2
by default places the legend in the margin of the entire plot. This is in many instances a nice solution. If this is not desired, theme(legend.position)
can be used to place the legend in relative measures on the entire plot:
library(ggplot2)
library(grid)
library(gridExtra)
dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
(d <- ggplot(dsamp, aes(carat, price)) +
geom_point(aes(colour = clarity)) +
theme(legend.position = c(0.06, 0.75))
)
This is however prone to badly positioning, if e.g. the plot is resized or font size changed:
With our function, we can specify exactly how we want it in the plotting area:
And it stays there.
The left plot is printed in full size at the end of this document.
For our final trick in this act, we reposition a legend with multiple guides. For this, use theme(legend.box.background)
to put a background around the entire legend, not just the individual guides.
d2 <- d + aes(shape=cut) +
theme(legend.box.background = element_rect(fill='#fffafa'),
legend.background = element_blank())
reposition_legend(d2, 'left')
## Warning: Using shapes for an ordinal variable is not advised
## Warning: Using shapes for an ordinal variable is not advised
The guidebox uses a solid background (subject to the chosen theme), and prior to lemon version 0.3.1, the entire legend was placed as the top most element. In the examples above, this was not an issue. With axis lines drawn, this effectively overpainted some of the axis (same applies to the panel border).
The guidebox is therefore placed under the lowest axis line, if and only if z = Inf
. To place as top most, specify a large z-index.
To adjust the guidebox so it does not overpaint the panel border, use arguments x
and y
,
… or use the argument offset
:
To our knowledge, there exists two methods for extracting the legend:
g1 <- function(a.gplot){
if (!gtable::is.gtable(a.gplot))
a.gplot <- ggplotGrob(a.gplot)
leg <- which(sapply(a.gplot$grobs, function(x) x$name) == "guide-box")
a.gplot$grobs[[leg]]
}
g2 <- function(a.gplot){
if (!gtable::is.gtable(a.gplot))
a.gplot <- ggplotGrob(a.gplot)
gtable::gtable_filter(a.gplot, 'guide-box', fixed=TRUE)
}
There is very little difference between them, as the latter essentially does the same as the former. The latter however encapsulated the former in a gtable. This is even more evident with multiple guides:
(da <- ggplot(dsamp, aes(carat, price)) +
geom_point(aes(colour = clarity, shape=cut)) +
theme(legend.box = 'horizontal')
)
## Warning: Using shapes for an ordinal variable is not advised
## Warning: Using shapes for an ordinal variable is not advised
## TableGrob (5 x 7) "guide-box": 3 grobs
## z cells name
## 99_86c3b14d399915779b8ee8f468a98f91 1 (3-3,3-3) guides
## 99_e48d95bbf9bfaae50e1c3ba1663f2112 2 (3-3,5-5) guides
## 0 (2-4,2-6) legend.box.background
## grob
## 99_86c3b14d399915779b8ee8f468a98f91 gtable[layout]
## 99_e48d95bbf9bfaae50e1c3ba1663f2112 gtable[layout]
## zeroGrob[NULL]
## Warning: Using shapes for an ordinal variable is not advised
## TableGrob (1 x 1) "layout": 1 grobs
## z cells name grob
## 1 14 (1-1,1-1) guide-box gtable[guide-box]
The function reposition_legend
assumes the method given in g1
, which is also given in g_legend
.
The above demonstration finds the panel named panel
. This is default. If using facetting, the panels are typically named panel-{column}-{row}
. We use gtable_show_names
to display the names of the facetted panels.
So to place the legend in a specific panel, specify it’s name in the panel
argument.
g <- ggplotGrob(d2)
panels <- grepl('panel',g$layout$name)
right.most <- max(g$layout$r[panels])
one.of.them <- with(g$layout, which(panels & r == right.most)[1])
panel_name <- g$layout$name[one.of.them]
reposition_legend(d2, 'top left', panel = panel_name)
Likewise for facet_wrap
. Incidentally, empty panels are also named here:
Modifying the legend is done via usual routines of ggplot2:
d3 <- d + facet_wrap(~cut, ncol=3) + scale_color_discrete(guide=guide_legend(ncol=3))
reposition_legend(d3, 'center', panel='panel-3-2')
Also supports spanning multiple panels:
d4 <- d + facet_wrap(~cut, ncol=4) + scale_color_discrete(guide=guide_legend(nrow=2))
reposition_legend(d4, 'center', panel=c('panel-2-2','panel-4-2'))
The panel names are not easy to figure, especially those from facet_wrap
. We refer to gtable_show_names
to get a look at where they are:
p <- ggplot(dsamp, aes(x=cut, y=price, colour=clarity)) + geom_point(position=position_jitter(width=0.2)) +
coord_flex_cart(bottom=brackets_horizontal(), left=capped_vertical('none')) +
theme_bw() + theme(panel.border=element_blank(), axis.line = element_line(),
legend.background = element_rect(colour='grey'))
g <- reposition_legend(p, 'top left', plot=TRUE)
g_legend
was proposed as early as June 2012 by Baptiste Auguié (http://baptiste.github.io/) on ggplot2’s wiki. It has since propogated throughout Stack Overflow answers.
Originally brought to you by (Baptiste Auguié)[http://baptiste.github.io/] (https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs) and (Shaun Jackman)[http://rpubs.com/sjackman] (http://rpubs.com/sjackman/grid_arrange_shared_legend). It has been further modified here.
reposition_legend
was coded by Stefan McKinnon Edwards/