-
-
Notifications
You must be signed in to change notification settings - Fork 3
picks #270
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
base: main
Are you sure you want to change the base?
picks #270
Changes from all commits
e0e1571
707224e
9f9aacb
0d89dce
58182d2
c21591f
8023b1c
37225be
e1ec420
a8bb226
f4bf89a
a1678fa
06c0eb9
208fb53
cb94d6d
158eda9
d545331
99cadc2
b26695a
6600d17
df47b48
e90025c
a92f051
41800f3
3a39de2
6920d6e
d728739
6a85027
9993468
3624441
941b172
fe138e9
cf2d634
3385521
2c42af5
3cd9132
b780107
9cfb6f8
bad225d
c4c8e40
635ea9b
a30ec58
3031edc
81c3a9b
d7a005b
fa89e05
0142b78
521fd09
54058d3
957e59d
b440e3f
516c434
e82f500
d4d826e
56fa808
bcbf304
dabf731
78a8e1f
1426b06
ee357b0
b266116
8a2fcb6
b03e0d9
7f14c03
a19ed31
f146b4f
58fcf91
730aaa3
6aedd0a
4807d7d
33a18fc
711f92d
06c4b07
8145d93
0d032cd
c7f2675
b733b34
1134bbd
cc26a25
1c2ddad
4605b89
d27750f
810ce49
8cea674
cf4c5b2
4a3c2c8
59c6aff
11932a8
7b306fc
bec03ff
3c32eab
386232d
64c42e2
2a00dd2
a78ecce
6fa687e
18df6fc
5cadc43
72c975f
50576d6
a031ad9
1535244
1385c1f
85787b8
3fafc92
5ccfe34
10509da
5b8b51d
29c6500
3ba1bf5
ced9053
f3e3fa3
55a8537
6bf1af3
744a271
c773304
0638534
ce36549
a1fc90b
712781e
a3014a9
1ba7cd3
8342b1e
afb59bc
d209b13
61038cd
abd4b97
8794289
dfbef1f
a97a193
3ec348b
7044c69
4d91478
d1406e1
677d0cc
5815d26
e4e2b36
8b33a34
db9d038
905c787
5bde18e
67493a7
764333d
1307329
e6c39df
3302ffb
c3f8e42
a556485
394cbea
566a18c
621603d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,235 @@ | ||
| #' Convert data_extract_spec to picks | ||
| #' | ||
| #' @description | ||
| #' `r lifecycle::badge("experimental")` | ||
| #' Helper functions to ease transition between [data_extract_spec()] and [picks()]. | ||
| #' @inheritParams teal::teal_transform_module | ||
| #' @param x (`data_extract_spec`, `select_spec`, `filter_spec`) object to convert to [`picks`] | ||
| #' @details | ||
| #' With introduction of [`picks`], [`data_extract_spec`] will no longer serve a primary tool to | ||
| #' define variable choices and default selection in teal-modules and eventually [`data_extract_spec`] | ||
| #' will be deprecated. | ||
| #' To ease the transition to the new tool, we provide `as.picks` method which can handle 1:1 | ||
| #' conversion from [`data_extract_spec`] to [`picks`]. Unfortunately, when [`data_extract_spec`] | ||
| #' contains [`filter_spec`] then `as.picks` is unable to provide reliable [`picks`] equivalent. | ||
| #' | ||
| #' @examples | ||
| #' # convert des with eager select_spec | ||
| #' as.picks( | ||
| #' data_extract_spec( | ||
| #' dataname = "iris", | ||
| #' select_spec( | ||
| #' choices = c("Sepal.Length", "Sepal.Width", "Species"), | ||
| #' selected = c("Sepal.Length", "Species"), | ||
| #' multiple = TRUE, | ||
| #' ordered = TRUE | ||
| #' ) | ||
| #' ) | ||
| #' ) | ||
| #' | ||
| #' # convert des with delayed select_spec | ||
| #' as.picks( | ||
| #' data_extract_spec( | ||
| #' dataname = "iris", | ||
| #' select_spec( | ||
| #' choices = variable_choices("iris"), | ||
| #' selected = first_choice(), | ||
| #' multiple = TRUE, | ||
| #' ordered = TRUE | ||
| #' ) | ||
| #' ) | ||
| #' ) | ||
| #' | ||
| #' as.picks( | ||
| #' data_extract_spec( | ||
| #' dataname = "iris", | ||
| #' select_spec( | ||
| #' choices = variable_choices("iris", subset = function(data) names(Filter(is.numeric, data))), | ||
| #' selected = first_choice(), | ||
| #' multiple = TRUE, | ||
| #' ordered = TRUE | ||
| #' ) | ||
| #' ) | ||
| #' ) | ||
| #' | ||
| #' @export | ||
| as.picks <- function(x) { # nolint | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is all lintrs that we need ot exclude or can we exclude specific lintr while keeping others? |
||
| if (inherits(x, c("picks", "pick"))) { | ||
| x | ||
| } else if (checkmate::test_list(x, c("data_extract_spec", "filter_spec"))) { | ||
| Filter(length, lapply(x, as.picks)) | ||
| } else if (inherits(x, "data_extract_spec")) { | ||
| args <- Filter( | ||
| length, | ||
| list( | ||
| datasets(choices = x$dataname, fixed = TRUE), | ||
| as.picks(x$select), | ||
| as.picks(x$filter) | ||
| # filter_spec as they are not necessary linked with `select` (selected variables) | ||
| # as filter_spec can be specified on the variable(s) different than select_spec for example: | ||
| # for example: #pseudocode select = select_spec(AVAL); filter = filter_spec(PARAMCD)) | ||
| ) | ||
| ) | ||
| do.call(picks, args) | ||
| } else if (inherits(x, "select_spec")) { | ||
| .select_spec_to_variables(x) | ||
| } else if (inherits(x, "filter_spec")) { | ||
| # warning | ||
| warning( | ||
| "`filter_spec` are not convertible to picks - please use `transformers` argument", | ||
| "and create `teal_transform_module` containing necessary filter. See `?teal_transform_filter`" | ||
| ) | ||
|
|
||
| NULL | ||
| } | ||
| } | ||
|
|
||
| #' @rdname as.picks | ||
| #' @examples | ||
| #' # teal_transform_module build on teal.transform | ||
| #' | ||
| #' teal_transform_filter( | ||
| #' data_extract_spec( | ||
| #' dataname = "iris", | ||
| #' filter = filter_spec( | ||
| #' vars = "Species", | ||
| #' choices = c("setosa", "versicolor", "virginica"), | ||
| #' selected = c("setosa", "versicolor") | ||
| #' ) | ||
| #' ) | ||
| #' ) | ||
| #' | ||
| #' teal_transform_filter( | ||
| #' picks( | ||
| #' datasets(choices = "iris", select = "iris"), | ||
| #' variables(choices = "Species", "Species"), | ||
| #' values( | ||
| #' choices = c("setosa", "versicolor", "virginica"), | ||
| #' selected = c("setosa", "versicolor") | ||
| #' ) | ||
| #' ) | ||
| #' ) | ||
| #' | ||
| #' @export | ||
| teal_transform_filter <- function(x, label = "Filter") { | ||
| checkmate::assert_multi_class(x, c("data_extract_spec", "picks")) | ||
| if (inherits(x, "data_extract_spec")) { | ||
| lapply(.as.picks.filter(x), teal_transform_filter, label = label) | ||
| } else { | ||
| checkmate::assert_true("values" %in% names(x)) | ||
| teal::teal_transform_module( | ||
| label = label, | ||
| ui <- function(id) { | ||
| ns <- NS(id) | ||
| picks_ui(ns("transformer"), picks = x, container = div) | ||
| }, | ||
| server <- function(id, data) { | ||
| shiny::moduleServer(id, function(input, output, session) { | ||
| selector <- picks_srv("transformer", picks = x, data = data) | ||
| reactive({ | ||
| req(data(), selector()) | ||
| filter_call <- .make_filter_call( | ||
| datasets = selector()$datasets$selected, | ||
| variables = selector()$variables$selected, | ||
| values = selector()$values$selected | ||
| ) | ||
| teal.code::eval_code(data(), filter_call) | ||
| }) | ||
| }) | ||
| } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| .as.picks.filter <- function(x, dataname) { # nolint | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above, if the problem is from 1-3 lintr checks we can ignore specific lintrs while keeping lintr checks for the rest of the function. Otherwise it is ok to exclude all lintrs |
||
| if (inherits(x, "filter_spec")) { | ||
| if (inherits(x$choices, "delayed_data")) { | ||
| warning( | ||
| "filter_spec(choices) doesn't support delayed_data when using with teal_transform_filter. ", | ||
| "Setting to all possible choices..." | ||
| ) | ||
| x$choices <- function(x) TRUE | ||
| } | ||
| if (inherits(x$selected, "delayed_data")) { | ||
| warning( | ||
| "filter_spec(selected) doesn't support delayed_data when using with teal_transform_filter. ", | ||
| "Setting to all possible choices..." | ||
| ) | ||
| x$selected <- function(x) TRUE | ||
| } | ||
| picks( | ||
| datasets(choices = dataname, selected = dataname), | ||
| variables(choices = x$vars_choices, selected = x$vars_selected, multiple = FALSE), # can't be multiple | ||
| values(choices = x$choices, selected = x$selected, multiple = x$multiple) | ||
| ) | ||
| } else if (checkmate::test_list(x, "filter_spec")) { | ||
| lapply(x, .as.picks.filter, dataname = dataname) | ||
| } else if (inherits(x, "data_extract_spec")) { | ||
| .as.picks.filter(x$filter, dataname = x$dataname) | ||
| } else if (checkmate::test_list(x, c("data_extract_spec", "list", "NULL"))) { | ||
| unlist( | ||
| lapply(Filter(length, x), .as.picks.filter), | ||
| recursive = FALSE | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| .make_filter_call <- function(datasets, variables, values) { | ||
| checkmate::assert_character(datasets) | ||
| checkmate::assert_character(variables) | ||
| checkmate::assert_character(values) | ||
| substitute( | ||
| dataname <- dplyr::filter(dataname, varname %in% values), | ||
| list( | ||
| dataname = as.name(datasets), | ||
| varname = if (length(variables) == 1) { | ||
| as.name(variables) | ||
| } else { | ||
| as.call( | ||
| c( | ||
| quote(paste), | ||
| lapply(variables, as.name), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do |
||
| list(sep = ", ") | ||
| ) | ||
| ) | ||
| }, | ||
| values = values | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| .select_spec_to_variables <- function(x) { | ||
| if (length(x)) { | ||
| variables( | ||
| choices = if (inherits(x$choices, "delayed_data")) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because we are assigning "delayed_data" and "des-delayed" data many times, why not assigning those strings to variables like: To reuse the class string and only require to change the name in one place if necessary? |
||
| out <- x$choices$subset | ||
| if (is.null(out)) { | ||
| function(x) TRUE # same effect as tidyselect::everything | ||
| } else { | ||
| class(out) <- "des-delayed" | ||
| out | ||
| } | ||
| } else { | ||
| x$choices | ||
| }, | ||
| selected = if (inherits(x$selected, "delayed_choices")) { | ||
| out <- x$selected | ||
| class(out) <- "des-delayed" | ||
| out | ||
| } else if (inherits(x$selected, "delayed_data")) { | ||
| out <- x$selected$subset | ||
| if (is.null(out)) { | ||
| 1L | ||
| } else { | ||
| class(out) <- "des-delayed" | ||
| out | ||
| } | ||
| } else { | ||
| unname(x$selected) | ||
| }, | ||
| ordered = x$ordered, | ||
| multiple = x$multiple, | ||
| fixed = x$fixed | ||
| ) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no minimal version for
tealandteal.data?