Skip to content

Commit 80db793

Browse files
authored
Long legend title justification (#5570)
* justify titles when larger than legend * add test * add news bullet * apply logical to `guide_custom` too
1 parent e51ca46 commit 80db793

File tree

5 files changed

+155
-28
lines changed

5 files changed

+155
-28
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ggplot2 (development version)
22

3+
* When legend titles are larger than the legend, title justification extends
4+
to the placement of keys and labels (#1903).
5+
36
* `draw_key_label()` now better reflects the appearance of labels.
47

58
* The `minor_breaks` function argument in scales can now take a function with

R/guide-custom.R

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,17 @@ GuideCustom <- ggproto(
124124
title.position <- "none"
125125
}
126126

127-
width <- convertWidth(params$width, "cm")
128-
height <- convertHeight(params$height, "cm")
129-
gt <- gtable(widths = width, heights = height)
127+
width <- convertWidth(params$width, "cm", valueOnly = TRUE)
128+
height <- convertHeight(params$height, "cm", valueOnly = TRUE)
129+
gt <- gtable(widths = unit(width, "cm"), heights = unit(height, "cm"))
130130
gt <- gtable_add_grob(gt, params$grob, t = 1, l = 1, clip = "off")
131131

132+
extra_width <- max(0, width_cm(title) - width)
133+
extra_height <- max(0, height_cm(title) - height)
134+
just <- with(elems$title, rotate_just(angle, hjust, vjust))
135+
hjust <- just$hjust
136+
vjust <- just$vjust
137+
132138
if (params$title.position == "top") {
133139
gt <- gtable_add_rows(gt, elems$margin[1], pos = 0)
134140
gt <- gtable_add_rows(gt, unit(height_cm(title), "cm"), pos = 0)
@@ -146,6 +152,14 @@ GuideCustom <- ggproto(
146152
gt <- gtable_add_cols(gt, unit(width_cm(title), "cm"), pos = 0)
147153
gt <- gtable_add_grob(gt, title, t = 1, l = -1, name = "title", clip = "off")
148154
}
155+
if (params$title.position %in% c("top", "bottom")) {
156+
gt <- gtable_add_cols(gt, unit(extra_width * hjust, "cm"), pos = 0)
157+
gt <- gtable_add_cols(gt, unit(extra_width * (1 - hjust), "cm"), pos = -1)
158+
} else {
159+
gt <- gtable_add_rows(gt, unit(extra_height * (1 - vjust), "cm"), pos = 0)
160+
gt <- gtable_add_rows(gt, unit(extra_height * vjust, "cm"), pos = -1)
161+
}
162+
149163
gt <- gtable_add_padding(gt, elems$margin)
150164

151165
background <- element_grob(elems$background)

R/guide-legend.R

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -603,19 +603,24 @@ GuideLegend <- ggproto(
603603
# Measure title
604604
title_width <- width_cm(grobs$title)
605605
title_height <- height_cm(grobs$title)
606+
extra_width <- max(0, title_width - sum(widths))
607+
extra_height <- max(0, title_height - sum(heights))
608+
just <- with(elements$title, rotate_just(angle, hjust, vjust))
609+
hjust <- just$hjust
610+
vjust <- just$vjust
606611

607612
# Combine title with rest of the sizes based on its position
608613
widths <- switch(
609614
params$title.position,
610615
"left" = c(title_width, widths),
611616
"right" = c(widths, title_width),
612-
c(widths, max(0, title_width - sum(widths)))
617+
c(extra_width * hjust, widths, extra_width * (1 - hjust))
613618
)
614619
heights <- switch(
615620
params$title.position,
616621
"top" = c(title_height, heights),
617622
"bottom" = c(heights, title_height),
618-
c(heights, max(0, title_height - sum(heights)))
623+
c(extra_height * (1 - vjust), heights, extra_height * vjust)
619624
)
620625
}
621626

@@ -670,29 +675,19 @@ GuideLegend <- ggproto(
670675

671676
# Offset layout based on title position
672677
if (sizes$has_title) {
673-
switch(
674-
params$title.position,
675-
"top" = {
676-
key_row <- key_row + 1
677-
label_row <- label_row + 1
678-
title_row <- 2
679-
title_col <- seq_along(sizes$widths) + 1
680-
},
681-
"bottom" = {
682-
title_row <- length(sizes$heights) + 1
683-
title_col <- seq_along(sizes$widths) + 1
684-
},
685-
"left" = {
686-
key_col <- key_col + 1
687-
label_col <- label_col + 1
688-
title_row <- seq_along(sizes$heights) + 1
689-
title_col <- 2
690-
},
691-
"right" = {
692-
title_row <- seq_along(sizes$heights) + 1
693-
title_col <- length(sizes$widths) + 1
694-
}
695-
)
678+
position <- params$title.position
679+
if (position != "right") {
680+
key_col <- key_col + 1
681+
label_col <- label_col + 1
682+
}
683+
if (position != "bottom") {
684+
key_row <- key_row + 1
685+
label_row <- label_row + 1
686+
}
687+
nrow <- length(sizes$heights)
688+
ncol <- length(sizes$widths)
689+
title_row <- switch(position, top = 1, bottom = nrow, seq_len(nrow)) + 1
690+
title_col <- switch(position, left = 1, right = ncol, seq_len(ncol)) + 1
696691
} else {
697692
title_row <- NA
698693
title_col <- NA
Lines changed: 99 additions & 0 deletions
Loading

tests/testthat/test-guides.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,22 @@ test_that("guides title and text are positioned correctly", {
831831
)
832832

833833
expect_doppelganger("rotated guide titles and labels", p )
834+
835+
# title justification
836+
p <- ggplot(data.frame(x = 1:2)) +
837+
aes(x, x, colour = factor(x), fill = factor(x), shape = factor(x), alpha = x) +
838+
geom_point() +
839+
scale_alpha(breaks = 1:2) +
840+
guides(
841+
colour = guide_legend("colour title with hjust = 0", title.hjust = 0, order = 1),
842+
fill = guide_legend("fill title with hjust = 1", title.hjust = 1, order = 2,
843+
title.position = "bottom", override.aes = list(shape = 21)),
844+
alpha = guide_legend("Title\nfor\nalpha\nwith\nvjust=0", title.vjust = 0,
845+
title.position = "left", order = 3),
846+
shape = guide_legend("Title\nfor\nshape\nwith\nvjust=1", title.vjust = 1,
847+
title.position = "right", order = 4)
848+
)
849+
expect_doppelganger("legends with all title justifications", p)
834850
})
835851

836852
test_that("size and linewidth affect key size", {

0 commit comments

Comments
 (0)