Skip to content

Commit b8cc043

Browse files
purrr style lambda notation in scale arguments (#4427)
* Add function for converting lambda formula input to functions * Convert formula input to function for arguments that allow functions * Mention in argument descriptions that functions can be in labmda notation * Add unit test for lambda notation * Fix typo * Regenerate docs * Add news bullet * Update tests/testthat/test-scales.r Co-authored-by: Hiroaki Yutani <[email protected]> Co-authored-by: Hiroaki Yutani <[email protected]>
1 parent 1a72f58 commit b8cc043

18 files changed

+211
-73
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@
112112

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

115+
* The scale arguments `limits`, `breaks`, `minor_breaks`, `labels`, `rescaler`
116+
and `oob` now accept purrr style lambda notation (@teunbrand, #4427).
117+
115118
# ggplot2 3.3.3
116119
This is a small patch release mainly intended to address changes in R and CRAN.
117120
It further changes the licensing model of ggplot2 to an MIT license.

R/scale-.r

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
#' [transformation object][scales::trans_new()]
1919
#' - A numeric vector of positions
2020
#' - A function that takes the limits as input and returns breaks
21-
#' as output (e.g., a function returned by [scales::extended_breaks()])
21+
#' as output (e.g., a function returned by [scales::extended_breaks()]).
22+
#' Also accepts rlang [lambda][rlang::as_function()] function notation.
2223
#' @param minor_breaks One of:
2324
#' - `NULL` for no minor breaks
2425
#' - `waiver()` for the default breaks (one minor break between
2526
#' each major break)
2627
#' - A numeric vector of positions
27-
#' - A function that given the limits returns a vector of minor breaks.
28+
#' - A function that given the limits returns a vector of minor breaks. Also
29+
#' accepts rlang [lambda][rlang::as_function()] function notation.
2830
#' @param n.breaks An integer guiding the number of major breaks. The algorithm
2931
#' may choose a slightly different number to ensure nice break labels. Will
3032
#' only have an effect if `breaks = waiver()`. Use `NULL` to use the default
@@ -35,24 +37,28 @@
3537
#' transformation object
3638
#' - A character vector giving labels (must be same length as `breaks`)
3739
#' - A function that takes the breaks as input and returns labels
38-
#' as output
40+
#' as output. Also accepts rlang [lambda][rlang::as_function()] function
41+
#' notation.
3942
#' @param limits One of:
4043
#' - `NULL` to use the default scale range
4144
#' - A numeric vector of length two providing limits of the scale.
4245
#' Use `NA` to refer to the existing minimum or maximum
4346
#' - A function that accepts the existing (automatic) limits and returns
44-
#' new limits
47+
#' new limits. Also accepts rlang [lambda][rlang::as_function()] function
48+
#' notation.
4549
#' Note that setting limits on positional scales will **remove** data outside of the limits.
4650
#' If the purpose is to zoom, use the limit argument in the coordinate system
4751
#' (see [coord_cartesian()]).
4852
#' @param rescaler A function used to scale the input values to the
4953
#' range \[0, 1]. This is always [scales::rescale()], except for
5054
#' diverging and n colour gradients (i.e., [scale_colour_gradient2()],
5155
#' [scale_colour_gradientn()]). The `rescaler` is ignored by position
52-
#' scales, which always use [scales::rescale()].
56+
#' scales, which always use [scales::rescale()]. Also accepts rlang
57+
#' [lambda][rlang::as_function()] function notation.
5358
#' @param oob One of:
5459
#' - Function that handles limits outside of the scale limits
55-
#' (out of bounds).
60+
#' (out of bounds). Also accepts rlang [lambda][rlang::as_function()]
61+
#' function notation.
5662
#' - The default ([scales::censor()]) replaces out of
5763
#' bounds values with `NA`.
5864
#' - [scales::squish()] for squishing out of bounds values into range.
@@ -104,6 +110,14 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(),
104110
limits <- trans$transform(limits)
105111
}
106112

113+
# Convert formula to function if appropriate
114+
limits <- allow_lambda(limits)
115+
breaks <- allow_lambda(breaks)
116+
labels <- allow_lambda(labels)
117+
rescaler <- allow_lambda(rescaler)
118+
oob <- allow_lambda(oob)
119+
minor_breaks <- allow_lambda(minor_breaks)
120+
107121
ggproto(NULL, super,
108122
call = match.call(),
109123

@@ -142,13 +156,15 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(),
142156
#' - `waiver()` for the default breaks (the scale limits)
143157
#' - A character vector of breaks
144158
#' - A function that takes the limits as input and returns breaks
145-
#' as output
159+
#' as output. Also accepts rlang [lambda][rlang::as_function()] function
160+
#' notation.
146161
#' @param limits One of:
147162
#' - `NULL` to use the default scale values
148163
#' - A character vector that defines possible values of the scale and their
149164
#' order
150165
#' - A function that accepts the existing (automatic) values and returns
151-
#' new ones
166+
#' new ones. Also accepts rlang [lambda][rlang::as_function()] function
167+
#' notation.
152168
#' @param drop Should unused factor levels be omitted from the scale?
153169
#' The default, `TRUE`, uses the levels that appear in the data;
154170
#' `FALSE` uses all the levels in the factor.
@@ -168,6 +184,11 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(),
168184

169185
check_breaks_labels(breaks, labels)
170186

187+
# Convert formula input to function if appropriate
188+
limits <- allow_lambda(limits)
189+
breaks <- allow_lambda(breaks)
190+
labels <- allow_lambda(labels)
191+
171192
if (!is.function(limits) && (length(limits) > 0) && !is.discrete(limits)) {
172193
warn(
173194
glue(
@@ -217,7 +238,7 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(),
217238
#' instead of exactly evenly spaced between the limits. If `TRUE` (default)
218239
#' the scale will ask the transformation object to create breaks, and this
219240
#' may result in a different number of breaks than requested. Ignored if
220-
#' breaks are given explicetly.
241+
#' breaks are given explicitly.
221242
#' @param right Should values on the border between bins be part of the right
222243
#' (upper) bin?
223244
#' @param show.limits should the limits of the scale appear as ticks
@@ -244,6 +265,13 @@ binned_scale <- function(aesthetics, scale_name, palette, name = waiver(),
244265
limits <- trans$transform(limits)
245266
}
246267

268+
# Convert formula input to function if appropriate
269+
limits <- allow_lambda(limits)
270+
breaks <- allow_lambda(breaks)
271+
labels <- allow_lambda(labels)
272+
rescaler <- allow_lambda(rescaler)
273+
oob <- allow_lambda(oob)
274+
247275
ggproto(NULL, super,
248276
call = match.call(),
249277

@@ -1167,3 +1195,7 @@ check_transformation <- function(x, transformed, name, axis) {
11671195
trans_support_nbreaks <- function(trans) {
11681196
"n" %in% names(formals(trans$breaks))
11691197
}
1198+
1199+
allow_lambda <- function(x) {
1200+
if (is_formula(x)) as_function(x) else x
1201+
}

man/binned_scale.Rd

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/continuous_scale.Rd

Lines changed: 12 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/discrete_scale.Rd

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_binned.Rd

Lines changed: 9 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_continuous.Rd

Lines changed: 10 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)