|
4 | 4 | #' secondary axis, positioned opposite of the primary axis. All secondary
|
5 | 5 | #' axes must be based on a one-to-one transformation of the primary axes.
|
6 | 6 | #'
|
7 |
| -#' @param trans A transformation formula |
| 7 | +#' @param trans A formula or function of transformation |
8 | 8 | #'
|
9 | 9 | #' @param name The name of the secondary axis
|
10 | 10 | #'
|
|
33 | 33 | #' Unlike other continuous scales, secondary axis transformations for date and datetime scales
|
34 | 34 | #' must respect their primary POSIX data structure.
|
35 | 35 | #' This means they may only be transformed via addition or subtraction, e.g.
|
36 |
| -#' `~. + hms::hms(days = 8)`, or |
37 |
| -#' `~.- 8*60*60`. Nonlinear transformations will return an error. |
| 36 | +#' `~ . + hms::hms(days = 8)`, or |
| 37 | +#' `~ . - 8*60*60`. Nonlinear transformations will return an error. |
38 | 38 | #' To produce a time-since-event secondary axis in this context, users
|
39 | 39 | #' may consider adapting secondary axis labels.
|
40 | 40 | #'
|
|
43 | 43 | #' geom_point()
|
44 | 44 | #'
|
45 | 45 | #' # Create a simple secondary axis
|
46 |
| -#' p + scale_y_continuous(sec.axis = sec_axis(~.+10)) |
| 46 | +#' p + scale_y_continuous(sec.axis = sec_axis(~ . + 10)) |
47 | 47 | #'
|
48 | 48 | #' # Inherit the name from the primary axis
|
49 |
| -#' p + scale_y_continuous("Miles/gallon", sec.axis = sec_axis(~.+10, name = derive())) |
| 49 | +#' p + scale_y_continuous("Miles/gallon", sec.axis = sec_axis(~ . + 10, name = derive())) |
50 | 50 | #'
|
51 | 51 | #' # Duplicate the primary axis
|
52 | 52 | #' p + scale_y_continuous(sec.axis = dup_axis())
|
53 | 53 | #'
|
54 | 54 | #' # You can pass in a formula as a shorthand
|
55 |
| -#' p + scale_y_continuous(sec.axis = ~.^2) |
| 55 | +#' p + scale_y_continuous(sec.axis = ~ .^2) |
56 | 56 | #'
|
57 | 57 | #' # Secondary axes work for date and datetime scales too:
|
58 | 58 | #' df <- data.frame(
|
|
75 | 75 | #' # or to transform axes for different timezones
|
76 | 76 | #' ggplot(df, aes(x = dx, y = price)) + geom_line() +
|
77 | 77 | #' scale_x_datetime("GMT", date_labels = "%b %d %I %p",
|
78 |
| -#' sec.axis = sec_axis(~. + 8*3600, name = "GMT+8", |
| 78 | +#' sec.axis = sec_axis(~ . + 8 * 3600, name = "GMT+8", |
79 | 79 | #' labels = scales::time_format("%b %d %I %p")))
|
80 | 80 | #'
|
81 | 81 | #' @export
|
82 | 82 | sec_axis <- function(trans = NULL, name = waiver(), breaks = waiver(), labels = waiver()) {
|
83 |
| - if (!is.formula(trans)) stop("transformation for secondary axes must be a formula", call. = FALSE) |
| 83 | + # sec_axis() historically accpeted two-sided formula, so be permissive. |
| 84 | + if (length(trans) > 2) trans <- trans[c(1,3)] |
| 85 | + |
| 86 | + trans <- rlang::as_function(trans) |
84 | 87 | ggproto(NULL, AxisSecondary,
|
85 | 88 | trans = trans,
|
86 | 89 | name = name,
|
@@ -142,20 +145,15 @@ AxisSecondary <- ggproto("AxisSecondary", NULL,
|
142 | 145 | # Inherit settings from the primary axis/scale
|
143 | 146 | init = function(self, scale) {
|
144 | 147 | if (self$empty()) return()
|
145 |
| - if (!is.formula(self$trans)) stop("transformation for secondary axes must be a formula", call. = FALSE) |
| 148 | + if (!is.function(self$trans)) stop("transformation for secondary axes must be a function", call. = FALSE) |
146 | 149 | if (is.derived(self$name) && !is.waive(scale$name)) self$name <- scale$name
|
147 | 150 | if (is.derived(self$breaks)) self$breaks <- scale$breaks
|
148 | 151 | if (is.waive(self$breaks)) self$breaks <- scale$trans$breaks
|
149 | 152 | if (is.derived(self$labels)) self$labels <- scale$labels
|
150 | 153 | },
|
151 | 154 |
|
152 | 155 | transform_range = function(self, range) {
|
153 |
| - range <- new_data_frame(list(. = range)) |
154 |
| - rlang::eval_tidy( |
155 |
| - rlang::f_rhs(self$trans), |
156 |
| - data = range, |
157 |
| - env = rlang::f_env(self$trans) |
158 |
| - ) |
| 156 | + self$trans(range) |
159 | 157 | },
|
160 | 158 |
|
161 | 159 | mono_test = function(self, scale){
|
|
0 commit comments