|
21 | 21 | #' If `f` is missing, then `...` will specify the computation.
|
22 | 22 | #' @param ... Additional arguments to pass to the function or formula specified
|
23 | 23 | #' via `f`. Alternatively, if `f` is missing, then the `...` is interpreted as
|
24 |
| -#' a ["data-masking"][rlang::args_data_masking] expression or expressions for |
25 |
| -#' tidy evaluation; in addition to referring columns directly by name, the |
26 |
| -#' expressions have access to `.data` and `.env` pronouns as in `dplyr` verbs, |
27 |
| -#' and can also refer to `.x`, `.group_key`, and `.ref_time_value`. See |
28 |
| -#' details. |
29 |
| -#' @param new_col_name String indicating the name of the new column that will |
30 |
| -#' contain the derivative values. The default is "slide_value" unless your |
31 |
| -#' slide computations output data frames, in which case they will be unpacked |
32 |
| -#' into the constituent columns and those names used. Note that setting |
33 |
| -#' `new_col_name` equal to an existing column name will overwrite this column. |
| 24 | +#' an expression for tidy evaluation; in addition to referring to columns |
| 25 | +#' directly by name, the expression has access to `.data` and `.env` pronouns |
| 26 | +#' as in `dplyr` verbs, and can also refer to `.x`, `.group_key`, and |
| 27 | +#' `.ref_time_value`. See details. |
34 | 28 | #'
|
35 | 29 | #' @template basic-slide-details
|
36 | 30 | #'
|
|
85 | 79 | #' before = 1, as_list_col = TRUE
|
86 | 80 | #' ) %>%
|
87 | 81 | #' ungroup()
|
88 |
| -epi_slide <- function(x, f, ..., before = NULL, after = NULL, ref_time_values = NULL, |
89 |
| - new_col_name = NULL, all_rows = FALSE, |
90 |
| - as_list_col = deprecated(), names_sep = deprecated()) { |
| 82 | +epi_slide <- function( |
| 83 | + x, f, ..., |
| 84 | + .window_size = 0, .align = c("right", "center", "left"), .ref_time_values = NULL, .all_rows = FALSE) { |
| 85 | + |
| 86 | + if (any(map(c(n, before, after, ref_time_values, new_col_name, as_list_col, names_sep, all_rows), Negate(is.null)))) { |
| 87 | + cli_abort( |
| 88 | + "epi_slide: deprecated arguments `n`, `before`, `after`, `ref_time_values`, `new_col_name`, `as_list_col`, |
| 89 | + `names_sep`, and `all_rows` have been removed. Please use `.n`, `.align`, `.ref_time_values`, |
| 90 | + `.new_col_name`, `.as_list_col`, and `.names_sep` instead." |
| 91 | + ) |
| 92 | + } |
| 93 | + |
91 | 94 | assert_class(x, "epi_df")
|
92 | 95 |
|
93 | 96 | if (nrow(x) == 0L) {
|
94 | 97 | return(x)
|
95 | 98 | }
|
96 | 99 |
|
97 |
| - if (is.null(ref_time_values)) { |
98 |
| - ref_time_values <- unique(x$time_value) |
| 100 | + if (is.null(.ref_time_values)) { |
| 101 | + .ref_time_values <- unique(x$time_value) |
99 | 102 | } else {
|
100 |
| - assert_numeric(ref_time_values, min.len = 1L, null.ok = FALSE, any.missing = FALSE) |
101 |
| - if (!test_subset(ref_time_values, unique(x$time_value))) { |
| 103 | + assert_numeric(.ref_time_values, min.len = 1L, null.ok = FALSE, any.missing = FALSE) |
| 104 | + if (!test_subset(.ref_time_values, unique(x$time_value))) { |
102 | 105 | cli_abort(
|
103 | 106 | "`ref_time_values` must be a unique subset of the time values in `x`.",
|
104 | 107 | class = "epi_slide__invalid_ref_time_values"
|
105 | 108 | )
|
106 | 109 | }
|
107 |
| - if (anyDuplicated(ref_time_values) != 0L) { |
| 110 | + |
| 111 | + if (anyDuplicated(.ref_time_values) != 0L) { |
108 | 112 | cli_abort(
|
109 |
| - "`ref_time_values` must not contain any duplicates; use `unique` if appropriate.", |
| 113 | + "`.ref_time_values` must not contain any duplicates; use `unique` if appropriate.", |
110 | 114 | class = "epi_slide__invalid_ref_time_values"
|
111 | 115 | )
|
112 | 116 | }
|
113 | 117 | }
|
114 |
| - ref_time_values <- sort(ref_time_values) |
| 118 | + .ref_time_values <- sort(.ref_time_values) |
115 | 119 |
|
116 |
| - # Handle defaults for before/after |
117 |
| - time_type <- attr(x, "metadata")$time_type |
118 |
| - if (is.null(before) && !is.null(after)) { |
119 |
| - if (inherits(after, "difftime")) { |
120 |
| - before <- as.difftime(0, units = units(after)) |
121 |
| - } else { |
122 |
| - before <- 0 |
123 |
| - } |
| 120 | + if (!is.null(before) || !is.null(after)) { |
| 121 | + cli_abort("`before` and `after` are deprecated for `epi_slide`. Use `n` instead.") |
124 | 122 | }
|
125 |
| - if (is.null(after) && !is.null(before)) { |
126 |
| - if (inherits(before, "difftime")) { |
127 |
| - after <- as.difftime(0, units = units(before)) |
128 |
| - } else { |
129 |
| - if (identical(before, Inf) && time_type %in% c("day", "week")) { |
| 123 | + |
| 124 | + # Handle window arguments |
| 125 | + align <- rlang::arg_match(.align) |
| 126 | + time_type <- attr(x, "metadata")$time_type |
| 127 | + validate_slide_window_arg(.window_size, time_type) |
| 128 | + if (identical(.window_size, Inf)) { |
| 129 | + if (align == "right") { |
| 130 | + before <- Inf |
| 131 | + if (time_type %in% c("day", "week")) { |
130 | 132 | after <- as.difftime(0, units = glue::glue("{time_type}s"))
|
131 | 133 | } else {
|
132 | 134 | after <- 0
|
133 | 135 | }
|
| 136 | + } else { |
| 137 | + cli_abort( |
| 138 | + "`epi_slide`: center and left alignment are not supported with an infinite window size." |
| 139 | + ) |
| 140 | + } |
| 141 | + } else { |
| 142 | + if (align == "right") { |
| 143 | + before <- .window_size - 1 |
| 144 | + after <- 0 |
| 145 | + } else if (align == "center") { |
| 146 | + # For n = 5, before = 2, after = 2. For n = 4, before = 2, after = 1. |
| 147 | + before <- floor(.window_size / 2) |
| 148 | + after <- .window_size - before - 1 |
| 149 | + } else if (align == "left") { |
| 150 | + before <- 0 |
| 151 | + after <- .window_size - 1 |
134 | 152 | }
|
135 | 153 | }
|
136 |
| - validate_slide_window_arg(before, time_type) |
137 |
| - validate_slide_window_arg(after, time_type, allow_inf = FALSE) |
138 | 154 |
|
139 | 155 | # Arrange by increasing time_value
|
140 | 156 | x <- arrange(x, .data$time_value)
|
141 | 157 |
|
142 | 158 | # Now set up starts and stops for sliding/hopping
|
143 |
| - starts <- ref_time_values - before |
144 |
| - stops <- ref_time_values + after |
| 159 | + starts <- .ref_time_values - before |
| 160 | + stops <- .ref_time_values + after |
145 | 161 |
|
146 | 162 | # If `f` is missing, interpret ... as an expression for tidy evaluation
|
147 | 163 | if (missing(f)) {
|
@@ -220,6 +236,7 @@ epi_slide <- function(x, f, ..., before = NULL, after = NULL, ref_time_values =
|
220 | 236 | return(f_wrapper)
|
221 | 237 | }
|
222 | 238 |
|
| 239 | + |
223 | 240 | # Computation for one group, all time values
|
224 | 241 | slide_one_grp <- function(.data_group,
|
225 | 242 | .group_key, # see `?group_modify`
|
@@ -282,6 +299,7 @@ epi_slide <- function(x, f, ..., before = NULL, after = NULL, ref_time_values =
|
282 | 299 |
|
283 | 300 | slide_values <- vctrs::list_unchop(slide_values_list)
|
284 | 301 |
|
| 302 | + |
285 | 303 | if (
|
286 | 304 | all(purrr::map_int(slide_values_list, vctrs::vec_size) == 1L) &&
|
287 | 305 | length(slide_values_list) != 0L
|
@@ -333,12 +351,13 @@ epi_slide <- function(x, f, ..., before = NULL, after = NULL, ref_time_values =
|
333 | 351 | f_factory = f_wrapper_factory,
|
334 | 352 | starts = starts,
|
335 | 353 | stops = stops,
|
336 |
| - ref_time_values = ref_time_values, |
337 |
| - all_rows = all_rows, |
| 354 | + ref_time_values = .ref_time_values, |
| 355 | + all_rows = .all_rows, |
338 | 356 | new_col_name = new_col_name,
|
339 | 357 | .keep = FALSE
|
340 | 358 | )
|
341 | 359 |
|
| 360 | + |
342 | 361 | return(x)
|
343 | 362 | }
|
344 | 363 |
|
|
0 commit comments