Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# ggplot2 (development version)

* In the theme element hierarchy, parent elements that are a strict subclass
of child elements now confer their subclass upon the children (#5457).

* Legend titles no longer take up space if they've been removed by setting
`legend.title = element_blank()` (@teunbrand, #3587).

Expand Down
12 changes: 12 additions & 0 deletions R/theme.R
Original file line number Diff line number Diff line change
Expand Up @@ -767,9 +767,21 @@ combine_elements <- function(e1, e2) {
e1$linewidth <- e2$linewidth * unclass(e1$linewidth)
}

# If e2 is 'richer' than e1, fill e2 with e1 parameters
if (is.subclass(e2, e1)) {
new <- defaults(e1, e2)
e2[names(new)] <- new
return(e2)
}

e1
}

is.subclass <- function(x, y) {
inheritance <- inherits(x, class(y), which = TRUE)
!any(inheritance == 0) && length(setdiff(class(x), class(y))) > 0
}

#' Reports whether x is a theme object
#' @param x An object to test
#' @export
Expand Down
45 changes: 45 additions & 0 deletions tests/testthat/test-theme.R
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,51 @@ test_that("Theme validation behaves as expected", {
expect_snapshot_error(validate_element("A", "aspect.ratio", tree))
})

test_that("Element subclasses are inherited", {

# `rich` is subclass of `poor`
poor <- element_line(colour = "red", linetype = 3)
rich <- element_line(linetype = 2, linewidth = 2)
class(rich) <- c("element_rich", class(rich))

# `poor` should acquire `rich`
test <- combine_elements(poor, rich)
expect_s3_class(test, "element_rich")
expect_equal(
test[c("colour", "linetype", "linewidth")],
list(colour = "red", linetype = 3, linewidth = 2)
)

# `rich` should stay `rich`
test <- combine_elements(rich, poor)
expect_s3_class(test, "element_rich")
expect_equal(
test[c("colour", "linetype", "linewidth")],
list(colour = "red", linetype = 2, linewidth = 2)
)

# `sibling` is not strict subclass of `rich`
sibling <- poor
class(sibling) <- c("element_sibling", class(sibling))

# `sibling` should stay `sibling`
test <- combine_elements(sibling, rich)
expect_s3_class(test, "element_sibling")
expect_equal(
test[c("colour", "linetype", "linewidth")],
list(colour = "red", linetype = 3, linewidth = 2)
)

# `rich` should stay `rich`
test <- combine_elements(rich, sibling)
expect_s3_class(test, "element_rich")
expect_equal(
test[c("colour", "linetype", "linewidth")],
list(colour = "red", linetype = 2, linewidth = 2)
)

})

# Visual tests ------------------------------------------------------------

test_that("aspect ratio is honored", {
Expand Down