Skip to content
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)

* `update_geom_defaults()` and `update_stat_defaults()` can now use `new = NULL`
to reset the original defaults (@teunbrand, #4993).

* `ggsave()` no longer sometimes creates new directories, which is now
controlled by the new `create.dir` argument (#5489).

Expand Down
94 changes: 70 additions & 24 deletions R/geom-defaults.R
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
cache_geom_defaults <- new.env(parent = emptyenv())
cache_stats_defaults <- new.env(parent = emptyenv())

#' Modify geom/stat aesthetic defaults for future plots
#'
#' @param stat,geom Name of geom/stat to modify (like `"point"` or
#' `"bin"`), or a Geom/Stat object (like `GeomPoint` or
#' `StatBin`).
#' @param new Named list of aesthetics.
#' @param stat,geom Name of geom/stat to modify (like `"point"` or `"bin"`),
#' or a Geom/Stat object (like `GeomPoint` or `StatBin`).
#' @param new Named list of aesthetics. Alternatively, `NULL` to reset the
#' defaults.
#' @keywords internal
#' @name update_defaults
#' @export
#' @examples
#'
#' # updating a geom's default aesthetic settings
#' # example: change geom_point()'s default color
#' GeomPoint$default_aes
#' update_geom_defaults("point", aes(color = "red"))
#' GeomPoint$default_aes
#' ggplot(mtcars, aes(mpg, wt)) + geom_point()
#'
#' # reset default
#' update_geom_defaults("point", aes(color = "black"))
#'
#' # Reset defaults by using `new = NULL`
#' update_geom_defaults("point", NULL)
#'
#' # updating a stat's default aesthetic settings
#' # example: change stat_bin()'s default y-axis to the density scale
Expand All @@ -29,27 +31,71 @@
#' geom_function(fun = dnorm, color = "red")
#'
#' # reset default
#' update_stat_defaults("bin", aes(y = after_stat(count)))
#'
#' update_stat_defaults("bin", NULL)

#' @rdname update_defaults
update_geom_defaults <- function(geom, new) {
g <- check_subclass(geom, "Geom", env = parent.frame())
old <- g$default_aes
new <- rename_aes(new)
new_names_order <- unique(c(names(old), names(new)))
new <- defaults(new, old)[new_names_order]
g$default_aes[names(new)] <- new
invisible()
if (is.null(new)) {

if (!inherits(geom, "Geom")) {
check_string(geom)
} else {
geom <- check_subclass(geom, "Geom", env = parent.frame())
geom <- gsub("^geom_", "", snake_class(geom))
}
old <- cache_geom_defaults[[geom]]
if (!is.null(old)) {
new <- update_geom_defaults(geom, old)
}
invisible(new)

} else {

g <- check_subclass(geom, "Geom", env = parent.frame())
old <- g$default_aes
# Only update cache the first time
if (!geom %in% ls(cache_geom_defaults)) {
cache_geom_defaults[[geom]] <- old
}
new <- rename_aes(new)
new_names_order <- unique(c(names(old), names(new)))
new <- defaults(new, old)[new_names_order]
g$default_aes[names(new)] <- new
invisible(old)

}
}

#' @rdname update_defaults
#' @export
update_stat_defaults <- function(stat, new) {
g <- check_subclass(stat, "Stat", env = parent.frame())
old <- g$default_aes
new <- rename_aes(new)
new_names_order <- unique(c(names(old), names(new)))
new <- defaults(new, old)[new_names_order]
g$default_aes[names(new)] <- new
invisible()
if (is.null(new)) {

if (!inherits(stat, "Stat")) {
check_string(stat)
} else {
stat <- check_subclass(stat, "Stat", env = parent.frame())
stat <- gsub("^stat_", "", snake_class(stat))
}
old <- cache_stats_defaults[[stat]]
if (!is.null(old)) {
new <- update_stat_defaults(stat, old)
}
invisible(new)

} else {

g <- check_subclass(stat, "Stat", env = parent.frame())
old <- g$default_aes
# Only update cache the first time
if (!stat %in% ls(cache_stats_defaults)) {
cache_stats_defaults[[stat]] <- old
}
new <- rename_aes(new)
new_names_order <- unique(c(names(old), names(new)))
new <- defaults(new, old)[new_names_order]
g$default_aes[names(new)] <- new
invisible(old)

}
}
20 changes: 9 additions & 11 deletions man/update_defaults.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 17 additions & 7 deletions tests/testthat/test-geom-.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ test_that("aesthetic checking in geom throws correct errors", {
expect_snapshot_error(check_aesthetics(aes, 4))
})

test_that("geom defaults can be set and reset", {
l <- geom_point()
test <- l$geom$use_defaults(data_frame0())
expect_equal(test$colour, "black")

inv <- update_geom_defaults("point", list(colour = "red"))
test <- l$geom$use_defaults(data_frame0())
expect_equal(test$colour, "red")
expect_equal(inv$colour, "black")

inv <- update_geom_defaults("point", NULL)
test <- l$geom$use_defaults(data_frame0())
expect_equal(test$colour, "black")
expect_equal(inv$colour, "red")
})


test_that("updating geom aesthetic defaults preserves class and order", {
Expand All @@ -23,13 +38,9 @@ test_that("updating geom aesthetic defaults preserves class and order", {

expect_equal(updated_defaults, intended_defaults)

update_geom_defaults("point", original_defaults)

update_geom_defaults("point", NULL)
})




test_that("updating stat aesthetic defaults preserves class and order", {

original_defaults <- StatBin$default_aes
Expand All @@ -46,6 +57,5 @@ test_that("updating stat aesthetic defaults preserves class and order", {

expect_equal(updated_defaults, intended_defaults)

update_stat_defaults("bin", original_defaults)

update_stat_defaults("bin", NULL)
})