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))
)
## Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
## 3.5.0.
## ℹ Please use the `legend.position.inside` argument of `theme()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
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
## 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 grob
## 1 1 (3-3,3-3) guides gtable[layout]
## 2 2 (3-3,5-5) guides gtable[layout]
## 3 0 (2-4,2-6) legend.box.background zeroGrob[NULL]
## Warning: Using shapes for an ordinal variable is not advised
## TableGrob (9 x 9) "layout": 5 grobs
## z cells name grob
## 1 14 (5-5,9-9) guide-box-right gtable[guide-box]
## 2 15 (5-5,1-1) guide-box-left zeroGrob[NULL]
## 3 16 (9-9,5-5) guide-box-bottom zeroGrob[NULL]
## 4 17 (1-1,5-5) guide-box-top zeroGrob[NULL]
## 5 18 (5-5,5-5) guide-box-inside zeroGrob[NULL]
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, give its 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/