When a plot maps multiple aesthetics (colour, size, shape, etc.), ggplot2 creates separate legends for each. ggguides provides functions to control these legends individually:
Hide specific legends with
legend_hide()
Keep only certain legends with
legend_select()
Control display order with
legend_order_guides()
Force merge/split with
legend_merge() and legend_split()
Position legends separately using
by parameter on position functions
Style legends separately using by
parameter on legend_style()
# Plot with multiple aesthetics
p <- ggplot(mtcars, aes(mpg, wt,
color = factor(cyl),
size = hp,
shape = factor(am))) +
geom_point() +
labs(color = "Cylinders", size = "Horsepower", shape = "Transmission")
pUse legend_hide() to remove specific legends while
keeping others:
Use legend_select() to keep only certain legends
(inverse of legend_hide()):
By default, legends appear in an unspecified order. Use
legend_order_guides() to control the display order:
# Size legend first, then colour, then shape
p + legend_order_guides(size = 1, colour = 2, shape = 3)ggplot2 automatically merges legends when they have the same title
and matching labels. Use legend_merge() and
legend_split() to override this behavior.
# Plot where colour and fill map to the same variable
p_merge <- ggplot(mtcars, aes(mpg, wt, color = factor(cyl), fill = factor(cyl))) +
geom_point(shape = 21, size = 4, stroke = 1.5) +
labs(color = "Cylinders", fill = "Cylinders")
# Legends merge automatically when titles and labels match
p_mergePosition functions (legend_left(),
legend_right(), legend_top(),
legend_bottom()) accept a by parameter to
position specific legends:
# Place colour legend on the left, size legend at bottom
p +
legend_hide(shape) +
legend_left(by = "colour") +
legend_bottom(by = "size")# Colour legend on top, size on right
p +
legend_hide(shape) +
legend_top(by = "colour") +
legend_right(by = "size")Use the by parameter on legend_style() to
apply different styles to different legends:
p +
legend_hide(shape) +
legend_style(title_face = "bold", background = "grey95", by = "colour") +
legend_style(size = 10, by = "size")All functions work together:
# Complex example: hide shape, position colour on left with bold title,
# position size at bottom with smaller text
p +
legend_hide(shape) +
legend_left(by = "colour") +
legend_style(title_face = "bold", title_size = 14, by = "colour") +
legend_bottom(by = "size") +
legend_style(size = 9, direction = "horizontal", by = "size")When a plot has four legends and you want one on each side (top, bottom, left, right), you can fine-tune each legend along three axes:
Side placement —
legend_top/bottom/left/right(by = "<aes>")
Distance from the panel —
legend_style(by = "<aes>", margin = c(t, r, b, l))
Slide along the side —
legend_style(by = "<aes>", justification = ...)
For top/bottom legends, justification is
"left", "center", "right" (or a
number in [0, 1]). For left/right legends, it’s
"top", "center", "bottom" (or a
number).
p4 <- ggplot(mtcars, aes(mpg, wt,
colour = factor(cyl),
fill = factor(gear),
size = hp,
shape = factor(am))) +
geom_point(stroke = 1.2) +
labs(colour = "Cyl", fill = "Gear", size = "HP", shape = "AM")
p4 +
# 1. Send each legend to its side
legend_top (by = "colour") +
legend_bottom(by = "fill") +
legend_left (by = "size") +
legend_right (by = "shape") +
# 2. Slide each legend along its side
legend_style(by = "colour", justification = "left") +
legend_style(by = "fill", justification = "right") +
legend_style(by = "size", justification = "top") +
legend_style(by = "shape", justification = "bottom") +
# 3. Nudge each legend toward/away from the panel via margin (cm)
legend_style(by = "colour", margin = c(0, 0, 0.3, 0)) +
legend_style(by = "fill", margin = c(0.3, 0, 0, 0)) +
legend_style(by = "size", margin = c(0, 0.3, 0, 0)) +
legend_style(by = "shape", margin = c(0, 0, 0, 0.3))Each legend_style(by = ...) call is additive — you can
chain as many as you need to tune one legend at a time without affecting
the others.
More than one legend can share a side. ggplot2 stacks them in the order it resolves them, and ggguides lets you pick which legend goes where, slide it along the rail, and style it without touching the others. The plot below has six legends: two on top, two on the right, one on the bottom, one on the left.
p6 <- ggplot(mtcars, aes(mpg, wt)) +
geom_smooth(aes(linetype = factor(vs)), method = "lm", se = FALSE,
colour = "grey40") +
geom_point(aes(colour = factor(cyl),
fill = factor(gear),
size = hp,
alpha = qsec,
shape = factor(am)),
stroke = 1.2) +
scale_shape_manual(values = c(21, 24)) +
labs(colour = "Cyl", fill = "Gear", size = "HP",
alpha = "QSec", shape = "AM", linetype = "VS")
p6 +
# 1. Side placement — two legends share the top, two share the right
legend_top (by = "colour") +
legend_top (by = "fill") +
legend_right (by = "size") +
legend_right (by = "alpha") +
legend_bottom(by = "shape") +
legend_left (by = "linetype") +
# 2. Slide each legend along its rail
# top/bottom rails: "left" / "center" / "right" (or a number in [0,1])
# left/right rails: "top" / "center" / "bottom"
legend_style(by = "colour", justification = "left") +
legend_style(by = "fill", justification = "right") +
legend_style(by = "size", justification = "top") +
legend_style(by = "alpha", justification = "bottom") +
legend_style(by = "shape", justification = "center") +
legend_style(by = "linetype", justification = "center") +
# 3. Appearance — per-legend title weight, key size, direction, text size
legend_style(by = "colour", title_face = "bold",
key_width = 0.4, key_height = 0.4) +
legend_style(by = "fill", title_face = "bold",
key_width = 0.4, key_height = 0.4) +
legend_style(by = "size", title_size = 9, size = 8) +
legend_style(by = "alpha", title_size = 9, size = 8) +
legend_style(by = "shape", direction = "horizontal") +
legend_style(by = "linetype", direction = "vertical") +
# 4. Nudge each legend toward/away from the panel via margin (cm)
# order is c(top, right, bottom, left)
legend_style(by = "colour", margin = c(0, 0, 0.2, 0)) +
legend_style(by = "fill", margin = c(0, 0, 0.2, 0)) +
legend_style(by = "size", margin = c(0, 0, 0, 0.3)) +
legend_style(by = "alpha", margin = c(0, 0, 0, 0.3)) +
legend_style(by = "shape", margin = c(0.3, 0, 0, 0)) +
legend_style(by = "linetype", margin = c(0, 0.3, 0, 0))
#> `geom_smooth()` using formula = 'y ~ x'Step 1, side placement.
legend_<side>(by = "<aes>") sends one legend to
one side. Call it twice with different aesthetics and both legends land
on that side. In the example, colour and fill
share the top rail, size and alpha share the
right rail, and shape and linetype each get a
side of their own.
Step 2, slide along the rail.
legend_style(by = "<aes>", justification = ...)
repositions a single legend without affecting its neighbours. The
keyword interpretation depends on which rail the legend sits on:
Top or bottom rail (horizontal): "left",
"center", "right", or a number in
[0, 1] where 0 is flush left and 1 is flush right. In the
example, colour sits at the left end of the top rail and
fill at the right end, so the two top legends land in
opposite corners.
Left or right rail (vertical): "top",
"center", "bottom", or a number where 0 is
bottom and 1 is top. size sits at the top of the right rail
and alpha at the bottom.
The per-guide form is what you want when different legends need
different alignments. For a single alignment applied to every legend at
once, use legend_style(justification = ...) without
by.
Step 3, appearance. Anything
legend_style() accepts (title_face,
title_size, size for label text,
key_width, key_height, direction,
background, and so on) can be scoped to a single legend by
adding by = "<aes>". Each call tunes one legend and
leaves the others alone, so chaining several short calls is the intended
shape. In the example the top legends get bold titles and smaller keys,
the right legends get smaller text, shape is forced
horizontal so it fits the bottom rail, and linetype stays
vertical for the left rail.
Step 4, padding.
margin = c(top, right, bottom, left) (in cm) moves a single
legend toward or away from the panel. Pad on the side that faces the
panel: a bottom legend uses c(top, 0, 0, 0), a left legend
uses c(0, right, 0, 0). Without padding, legends often end
up pressed against the axis text; a few tenths of a centimetre usually
fixes it.
legend_style(by = "<aes>", ...) calls are
additive. You can fold every style argument for colour into
a single call, but splitting by concern (position, alignment,
appearance, padding) keeps each parameter on a line that is easy to
locate. When a reviewer asks to move the colour legend half a centimetre
down, the edit is one number on one line.
| Function | Purpose | Parameters |
|---|---|---|
legend_hide() |
Hide specific legends | Aesthetic names (unquoted) |
legend_select() |
Keep only specific legends | Aesthetic names (unquoted) |
legend_order_guides() |
Control legend display order | Named args: aes = order |
legend_merge() |
Force legends to merge | Aesthetic names (unquoted) |
legend_split() |
Force legends to stay separate | Aesthetic names (unquoted) |
legend_left(by=) |
Position one legend on left | by = "aesthetic" |
legend_style(by=) |
Style one legend | by = "aesthetic" + style args |
Learn more:
Legend Positioning for single-legend placement
Styling & Customization for legend appearance
Patchwork Integration for multi-panel plots