Skip to content

Commit 67bb3bb

Browse files
authored
<rel> and <unit> theme inheritance (#5403)
* Allow rel in element tree * Allow combining of rel elements * Add test * Add news bullet * Fix test for pre-R4.0.0 units * Also apply `rel` to numerics
1 parent 22ed73c commit 67bb3bb

File tree

4 files changed

+39
-12
lines changed

4 files changed

+39
-12
lines changed

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ggplot2 (development version)
22

3+
* In `theme()`, some elements can be specified with `rel()` to inherit from
4+
`unit`-class objects in a relative fashion (@teunbrand, #3951).
5+
36
* `stat_ydensity()` with incomplete groups calculates the default `width`
47
parameter more stably (@teunbrand, #5396)
58

R/theme-elements.R

+12-12
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,12 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
448448
axis.text.y.left = el_def("element_text", "axis.text.y"),
449449
axis.text.y.right = el_def("element_text", "axis.text.y"),
450450
axis.ticks.length = el_def("unit"),
451-
axis.ticks.length.x = el_def("unit", "axis.ticks.length"),
452-
axis.ticks.length.x.top = el_def("unit", "axis.ticks.length.x"),
453-
axis.ticks.length.x.bottom = el_def("unit", "axis.ticks.length.x"),
454-
axis.ticks.length.y = el_def("unit", "axis.ticks.length"),
455-
axis.ticks.length.y.left = el_def("unit", "axis.ticks.length.y"),
456-
axis.ticks.length.y.right = el_def("unit", "axis.ticks.length.y"),
451+
axis.ticks.length.x = el_def(c("unit", "rel"), "axis.ticks.length"),
452+
axis.ticks.length.x.top = el_def(c("unit", "rel"), "axis.ticks.length.x"),
453+
axis.ticks.length.x.bottom = el_def(c("unit", "rel"), "axis.ticks.length.x"),
454+
axis.ticks.length.y = el_def(c("unit", "rel"), "axis.ticks.length"),
455+
axis.ticks.length.y.left = el_def(c("unit", "rel"), "axis.ticks.length.y"),
456+
axis.ticks.length.y.right = el_def(c("unit", "rel"), "axis.ticks.length.y"),
457457
axis.ticks.x = el_def("element_line", "axis.ticks"),
458458
axis.ticks.x.top = el_def("element_line", "axis.ticks.x"),
459459
axis.ticks.x.bottom = el_def("element_line", "axis.ticks.x"),
@@ -470,11 +470,11 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
470470
legend.background = el_def("element_rect", "rect"),
471471
legend.margin = el_def("margin"),
472472
legend.spacing = el_def("unit"),
473-
legend.spacing.x = el_def("unit", "legend.spacing"),
474-
legend.spacing.y = el_def("unit", "legend.spacing"),
473+
legend.spacing.x = el_def(c("unit", "rel"), "legend.spacing"),
474+
legend.spacing.y = el_def(c("unit", "rel"), "legend.spacing"),
475475
legend.key = el_def("element_rect", "rect"),
476-
legend.key.height = el_def("unit", "legend.key.size"),
477-
legend.key.width = el_def("unit", "legend.key.size"),
476+
legend.key.height = el_def(c("unit", "rel"), "legend.key.size"),
477+
legend.key.width = el_def(c("unit", "rel"), "legend.key.size"),
478478
legend.text = el_def("element_text", "text"),
479479
legend.title = el_def("element_text", "title"),
480480
legend.position = el_def(c("character", "numeric", "integer")),
@@ -489,8 +489,8 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
489489
panel.background = el_def("element_rect", "rect"),
490490
panel.border = el_def("element_rect", "rect"),
491491
panel.spacing = el_def("unit"),
492-
panel.spacing.x = el_def("unit", "panel.spacing"),
493-
panel.spacing.y = el_def("unit", "panel.spacing"),
492+
panel.spacing.x = el_def(c("unit", "rel"), "panel.spacing"),
493+
panel.spacing.y = el_def(c("unit", "rel"), "panel.spacing"),
494494
panel.grid.major.x = el_def("element_line", "panel.grid.major"),
495495
panel.grid.major.y = el_def("element_line", "panel.grid.major"),
496496
panel.grid.minor.x = el_def("element_line", "panel.grid.minor"),

R/theme.R

+14
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,20 @@ combine_elements <- function(e1, e2) {
724724
return(e2)
725725
}
726726

727+
# Inheritance of rel objects
728+
if (is.rel(e1)) {
729+
# Both e1 and e2 are rel, give product as another rel
730+
if (is.rel(e2)) {
731+
return(rel(unclass(e1) * unclass(e2)))
732+
}
733+
# If e2 is a unit/numeric, return modified unit/numeric
734+
# Note that unit objects are considered numeric
735+
if (is.numeric(e2) || is.unit(e2)) {
736+
return(unclass(e1) * e2)
737+
}
738+
return(e1)
739+
}
740+
727741
# If neither of e1 or e2 are element_* objects, return e1
728742
if (!inherits(e1, "element") && !inherits(e2, "element")) {
729743
return(e1)

tests/testthat/test-theme.R

+10
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ test_that("calculating theme element inheritance works", {
170170
e1 <- ggplot2:::calc_element("strip.text.x", theme)
171171
e2 <- ggplot2:::calc_element("strip.text", theme)
172172
expect_identical(e1, e2)
173+
174+
# Check that rel units are computed appropriately
175+
theme <- theme_gray() +
176+
theme(axis.ticks.length = unit(1, "cm"),
177+
axis.ticks.length.x = rel(0.5),
178+
axis.ticks.length.x.bottom = rel(4))
179+
180+
expect_equal(calc_element("axis.ticks.length.y.left", theme), unit(1, "cm"))
181+
expect_equal(calc_element("axis.ticks.length.x.top", theme), unit(1, "cm") * 0.5)
182+
expect_equal(calc_element("axis.ticks.length.x.bottom", theme), unit(1, "cm") * 0.5 * 4)
173183
})
174184

175185
test_that("complete and non-complete themes interact correctly with each other", {

0 commit comments

Comments
 (0)