Skip to content

Commit 5b70f2a

Browse files
committed
Layout top/bottom legends horizontally
Fixes #1842
1 parent d919df3 commit 5b70f2a

File tree

5 files changed

+38
-41
lines changed

5 files changed

+38
-41
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ There were also a number of other smaller changes
126126
* Theme element inheritance is now easier to work with. Modification now
127127
overrides default `element_blank` elements (#1555, #1557, #1565, #1567)
128128

129+
* Horizontal legends (i.e. legends on the top or bottom) are horizontally
130+
aligned by default (#1842). Use `legend.box = "vertical"` to override the
131+
default.
132+
129133
* `element_line()` now takes an `arrow` argument to specify arrows at the end of
130134
lines (#1740)
131135

R/guides-.r

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@
4545
#'
4646
#' # position of guides
4747
#'
48-
#' p + theme(legend.position = "bottom", legend.box = "horizontal")
49-
#'
5048
#' # Set order for multiple guides
5149
#' ggplot(mpg, aes(displ, cty)) +
5250
#' geom_point(aes(size = hwy, colour = cyl, shape = drv)) +
@@ -93,32 +91,24 @@ update_guides <- function(p, guides) {
9391
# arrange all ggrobs
9492

9593
build_guides <- function(scales, layers, default_mapping, position, theme, guides, labels) {
96-
97-
# set themes w.r.t. guides
98-
# should these theme$legend.XXX be renamed to theme$guide.XXX ?
99-
100-
# by default, guide boxes are vertically aligned
101-
theme$legend.box <- theme$legend.box %||% "vertical"
102-
103-
# size of key (also used for bar in colorbar guide)
10494
theme$legend.key.width <- theme$legend.key.width %||% theme$legend.key.size
10595
theme$legend.key.height <- theme$legend.key.height %||% theme$legend.key.size
10696

107-
# by default, direction of each guide depends on the position of the guide.
108-
theme$legend.direction <-
109-
theme$legend.direction %||%
110-
if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
111-
switch(position[1], top = , bottom = "horizontal", left = , right = "vertical")
112-
else
113-
"vertical"
114-
115-
# justification of legend boxes
116-
theme$legend.box.just <-
117-
theme$legend.box.just %||%
118-
if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
119-
switch(position, bottom = , top = c("center", "top"), left = , right = c("left", "top"))
120-
else
121-
c("center", "center")
97+
# Layout of legends depends on their overall location
98+
position <- legend_position(position)
99+
if (position == "inside") {
100+
theme$legend.box <- theme$legend.box %||% "vertical"
101+
theme$legend.direction <- theme$legend.direction %||% "vertical"
102+
theme$legend.box.just <- theme$legend.box.just %||% c("center", "center")
103+
} else if (position == "vertical") {
104+
theme$legend.box <- theme$legend.box %||% "vertical"
105+
theme$legend.direction <- theme$legend.direction %||% "vertical"
106+
theme$legend.box.just <- theme$legend.box.just %||% c("left", "top")
107+
} else if (position == "horizontal") {
108+
theme$legend.box <- theme$legend.box %||% "horizontal"
109+
theme$legend.direction <- theme$legend.direction %||% "horizontal"
110+
theme$legend.box.just <- theme$legend.box.just %||% c("center", "top")
111+
}
122112

123113
# scales -> data for guides
124114
gdefs <- guides_train(scales = scales, theme = theme, guides = guides, labels = labels)
@@ -140,6 +130,19 @@ build_guides <- function(scales, layers, default_mapping, position, theme, guide
140130
grobs
141131
}
142132

133+
# Simplify legend position to one of horizontal/vertical/inside
134+
legend_position <- function(position) {
135+
if (length(position) == 1) {
136+
if (position %in% c("top", "bottom")) {
137+
"horizontal"
138+
} else {
139+
"vertical"
140+
}
141+
} else {
142+
"inside"
143+
}
144+
}
145+
143146
# validate guide object
144147
validate_guide <- function(guide) {
145148
# if guide is specified by character, then find the corresponding guide

R/theme.r

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -274,18 +274,14 @@ print.theme <- function(x, ...) utils::str(x)
274274
#' # Position
275275
#' p2 + theme(legend.position = "none")
276276
#' p2 + theme(legend.justification = "top")
277-
#'
278277
#' p2 + theme(legend.position = "bottom")
279-
#' p2 + theme(
280-
#' legend.position = "bottom",
281-
#' legend.box = "horizontal",
282-
#' legend.justification = "left"
283-
#' )
278+
#'
284279
#' # Or place inside the plot using relative coordinates between 0 and 1
280+
#' # legend.justification sets the corner that the position refers to
285281
#' p2 + theme(
282+
#' legend.position = c(.95, .95),
286283
#' legend.justification = c("right", "top"),
287284
#' legend.box.just = "right",
288-
#' legend.position = c(.95, .95),
289285
#' legend.margin = margin(6, 6, 6, 6)
290286
#' )
291287
#'

man/guides.Rd

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/theme.Rd

Lines changed: 3 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)