Skip to content

purrr style lambda notation in scale arguments #4427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 28, 2021
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@

* `ggsave()` now returns the saved file location invisibly (#3379, @eliocamp).

* The scale arguments `limits`, `breaks`, `minor_breaks`, `labels`, `rescaler`
and `oob` now accept purrr style lambda notation (@teunbrand, #4427).

# ggplot2 3.3.3
This is a small patch release mainly intended to address changes in R and CRAN.
It further changes the licensing model of ggplot2 to an MIT license.
Expand Down
50 changes: 41 additions & 9 deletions R/scale-.r
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
#' [transformation object][scales::trans_new()]
#' - A numeric vector of positions
#' - A function that takes the limits as input and returns breaks
#' as output (e.g., a function returned by [scales::extended_breaks()])
#' as output (e.g., a function returned by [scales::extended_breaks()]).
#' Also accepts rlang [lambda][rlang::as_function()] function notation.
#' @param minor_breaks One of:
#' - `NULL` for no minor breaks
#' - `waiver()` for the default breaks (one minor break between
#' each major break)
#' - A numeric vector of positions
#' - A function that given the limits returns a vector of minor breaks.
#' - A function that given the limits returns a vector of minor breaks. Also
#' accepts rlang [lambda][rlang::as_function()] function notation.
#' @param n.breaks An integer guiding the number of major breaks. The algorithm
#' may choose a slightly different number to ensure nice break labels. Will
#' only have an effect if `breaks = waiver()`. Use `NULL` to use the default
Expand All @@ -35,24 +37,28 @@
#' transformation object
#' - A character vector giving labels (must be same length as `breaks`)
#' - A function that takes the breaks as input and returns labels
#' as output
#' as output. Also accepts rlang [lambda][rlang::as_function()] function
#' notation.
#' @param limits One of:
#' - `NULL` to use the default scale range
#' - A numeric vector of length two providing limits of the scale.
#' Use `NA` to refer to the existing minimum or maximum
#' - A function that accepts the existing (automatic) limits and returns
#' new limits
#' new limits. Also accepts rlang [lambda][rlang::as_function()] function
#' notation.
#' Note that setting limits on positional scales will **remove** data outside of the limits.
#' If the purpose is to zoom, use the limit argument in the coordinate system
#' (see [coord_cartesian()]).
#' @param rescaler A function used to scale the input values to the
#' range \[0, 1]. This is always [scales::rescale()], except for
#' diverging and n colour gradients (i.e., [scale_colour_gradient2()],
#' [scale_colour_gradientn()]). The `rescaler` is ignored by position
#' scales, which always use [scales::rescale()].
#' scales, which always use [scales::rescale()]. Also accepts rlang
#' [lambda][rlang::as_function()] function notation.
#' @param oob One of:
#' - Function that handles limits outside of the scale limits
#' (out of bounds).
#' (out of bounds). Also accepts rlang [lambda][rlang::as_function()]
#' function notation.
#' - The default ([scales::censor()]) replaces out of
#' bounds values with `NA`.
#' - [scales::squish()] for squishing out of bounds values into range.
Expand Down Expand Up @@ -104,6 +110,14 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(),
limits <- trans$transform(limits)
}

# Convert formula to function if appropriate
limits <- allow_lambda(limits)
breaks <- allow_lambda(breaks)
labels <- allow_lambda(labels)
rescaler <- allow_lambda(rescaler)
oob <- allow_lambda(oob)
minor_breaks <- allow_lambda(minor_breaks)

ggproto(NULL, super,
call = match.call(),

Expand Down Expand Up @@ -142,13 +156,15 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(),
#' - `waiver()` for the default breaks (the scale limits)
#' - A character vector of breaks
#' - A function that takes the limits as input and returns breaks
#' as output
#' as output. Also accepts rlang [lambda][rlang::as_function()] function
#' notation.
#' @param limits One of:
#' - `NULL` to use the default scale values
#' - A character vector that defines possible values of the scale and their
#' order
#' - A function that accepts the existing (automatic) values and returns
#' new ones
#' new ones. Also accepts rlang [lambda][rlang::as_function()] function
#' notation.
#' @param drop Should unused factor levels be omitted from the scale?
#' The default, `TRUE`, uses the levels that appear in the data;
#' `FALSE` uses all the levels in the factor.
Expand All @@ -168,6 +184,11 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(),

check_breaks_labels(breaks, labels)

# Convert formula input to function if appropriate
limits <- allow_lambda(limits)
breaks <- allow_lambda(breaks)
labels <- allow_lambda(labels)

if (!is.function(limits) && (length(limits) > 0) && !is.discrete(limits)) {
warn(
glue(
Expand Down Expand Up @@ -217,7 +238,7 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(),
#' instead of exactly evenly spaced between the limits. If `TRUE` (default)
#' the scale will ask the transformation object to create breaks, and this
#' may result in a different number of breaks than requested. Ignored if
#' breaks are given explicetly.
#' breaks are given explicitly.
#' @param right Should values on the border between bins be part of the right
#' (upper) bin?
#' @param show.limits should the limits of the scale appear as ticks
Expand All @@ -244,6 +265,13 @@ binned_scale <- function(aesthetics, scale_name, palette, name = waiver(),
limits <- trans$transform(limits)
}

# Convert formula input to function if appropriate
limits <- allow_lambda(limits)
breaks <- allow_lambda(breaks)
labels <- allow_lambda(labels)
rescaler <- allow_lambda(rescaler)
oob <- allow_lambda(oob)

ggproto(NULL, super,
call = match.call(),

Expand Down Expand Up @@ -1167,3 +1195,7 @@ check_transformation <- function(x, transformed, name, axis) {
trans_support_nbreaks <- function(trans) {
"n" %in% names(formals(trans$breaks))
}

allow_lambda <- function(x) {
if (is_formula(x)) as_function(x) else x
}
17 changes: 11 additions & 6 deletions man/binned_scale.Rd

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

18 changes: 12 additions & 6 deletions man/continuous_scale.Rd

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

9 changes: 6 additions & 3 deletions man/discrete_scale.Rd

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

14 changes: 9 additions & 5 deletions man/scale_binned.Rd

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

15 changes: 10 additions & 5 deletions man/scale_continuous.Rd

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

Loading