diff --git a/NEWS.md b/NEWS.md index 6bf14d4615..9d85070388 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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). diff --git a/R/geom-defaults.R b/R/geom-defaults.R index afd2e598d4..375650f8e1 100644 --- a/R/geom-defaults.R +++ b/R/geom-defaults.R @@ -1,13 +1,16 @@ +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 @@ -15,9 +18,8 @@ #' 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 @@ -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) + + } } diff --git a/man/update_defaults.Rd b/man/update_defaults.Rd index e009b99d32..8cb6b7b3f6 100644 --- a/man/update_defaults.Rd +++ b/man/update_defaults.Rd @@ -1,6 +1,7 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/geom-defaults.R -\name{update_geom_defaults} +\name{update_defaults} +\alias{update_defaults} \alias{update_geom_defaults} \alias{update_stat_defaults} \title{Modify geom/stat aesthetic defaults for future plots} @@ -10,17 +11,16 @@ update_geom_defaults(geom, new) update_stat_defaults(stat, new) } \arguments{ -\item{new}{Named list of aesthetics.} +\item{new}{Named list of aesthetics. Alternatively, \code{NULL} to reset the +defaults.} -\item{stat, geom}{Name of geom/stat to modify (like \code{"point"} or -\code{"bin"}), or a Geom/Stat object (like \code{GeomPoint} or -\code{StatBin}).} +\item{stat, geom}{Name of geom/stat to modify (like \code{"point"} or \code{"bin"}), +or a Geom/Stat object (like \code{GeomPoint} or \code{StatBin}).} } \description{ Modify geom/stat aesthetic defaults for future plots } \examples{ - # updating a geom's default aesthetic settings # example: change geom_point()'s default color GeomPoint$default_aes @@ -28,9 +28,8 @@ 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 @@ -42,7 +41,6 @@ ggplot(data.frame(x = rnorm(1e3)), aes(x)) + geom_function(fun = dnorm, color = "red") # reset default -update_stat_defaults("bin", aes(y = after_stat(count))) - +update_stat_defaults("bin", NULL) } \keyword{internal} diff --git a/tests/testthat/test-geom-.R b/tests/testthat/test-geom-.R index 409aa19b8f..2529e8fed1 100644 --- a/tests/testthat/test-geom-.R +++ b/tests/testthat/test-geom-.R @@ -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", { @@ -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 @@ -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) })