-
Notifications
You must be signed in to change notification settings - Fork 0
Add new vignette #68
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
Add new vignette #68
Changes from 3 commits
1f4e6e8
4dfea9b
5dc6fb4
2e4d705
fd1fc49
860776b
f3b570d
6d723cc
418750a
271a880
80bfd5e
7dba211
228499e
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 |
|---|---|---|
|
|
@@ -3,7 +3,9 @@ CDISC | |
| Forkers | ||
| UI | ||
| mimicks | ||
| pre | ||
| reactives | ||
| runnable | ||
| schemas | ||
| stratifiers | ||
| tidyselect | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,226 @@ | ||||
| --- | ||||
| title: "Choices and selections in teal.picks" | ||||
| author: "NEST CoreDev" | ||||
| date: "`r Sys.Date()`" | ||||
| vignette: > | ||||
| %\VignetteIndexEntry{Choices and selections in teal.picks} | ||||
| %\VignetteEngine{knitr::rmarkdown} | ||||
| %\VignetteEncoding{UTF-8} | ||||
| output: | ||||
| rmarkdown::html_vignette: | ||||
| toc: true | ||||
| --- | ||||
|
|
||||
| ```{r setup, include = FALSE} | ||||
| knitr::opts_chunk$set(comment = NA) | ||||
| ``` | ||||
|
|
||||
| ## Overview | ||||
|
|
||||
| Every `picks()` object is built from three kinds of building blocks: `datasets()`, `variables()`, | ||||
| and `values()`. Each one carries two core arguments: | ||||
|
|
||||
| - `choices` — the full set of options the app user can pick from. | ||||
| - `selected` — the subset that is pre-selected when the app starts. | ||||
|
|
||||
| ``` | ||||
| picks( | ||||
| datasets(choices = <what datasets the user may choose>, selected = <default dataset>), | ||||
| variables(choices = <what columns the user may choose>, selected = <default columns>), | ||||
| values(choices = <what values the user may filter to>, selected = <default filter values>) | ||||
| ) | ||||
| ``` | ||||
|
|
||||
| Choices and selections can be expressed in three ways: | ||||
|
|
||||
| | Approach | Works with | | ||||
| |---|---| | ||||
| | Explicit — character vector, integer index, or numeric range | `datasets()`, `variables()`, `values()` | | ||||
|
Contributor
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. Consider adding a default row of what happens when defaults are assumed
Contributor
Author
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. Nice suggestion. Done here. |
||||
| | `tidyselect` helpers — `everything()`, `starts_with()`, `where()`, … | `datasets()`, `variables()` only | | ||||
| | Function — an R function applied at runtime to the data | `datasets()`, `variables()`, `values()` | | ||||
|
|
||||
| The sections below walk through each approach with runnable examples. | ||||
|
Contributor
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. Just move this information and the below to the main vignette
Contributor
Author
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. Done in here! |
||||
|
|
||||
| ```{r data, message = FALSE} | ||||
| library(teal.data) | ||||
| library(teal.picks) | ||||
|
Contributor
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.
Suggested change
Contributor
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. We need 1 of these for the vignette to build :-) it cannot be silent as in examples
Contributor
Author
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. I removed anyway as the data is loaded by the main vignette |
||||
|
|
||||
| data <- teal_data() | ||||
| data <- within(data, { | ||||
| ADSL <- data.frame( | ||||
| USUBJID = sprintf("S%03d", 1:10), | ||||
| AGE = sample(40:75, 10, replace = TRUE), | ||||
| SEX = rep(c("M", "F"), 5), | ||||
| ARM = rep(c("A", "B"), 5), | ||||
| stringsAsFactors = FALSE | ||||
| ) | ||||
| ADLB <- data.frame( | ||||
| USUBJID = rep(sprintf("S%03d", 1:10), each = 3), | ||||
| PARAM = rep(c("ALT", "AST", "CRP"), 10), | ||||
| AVAL = round(rnorm(30, mean = 40, sd = 8), 1), | ||||
| stringsAsFactors = FALSE | ||||
| ) | ||||
| }) | ||||
|
|
||||
| join_keys(data) <- join_keys( | ||||
| teal.data::join_key("ADSL", "ADLB", keys = "USUBJID") | ||||
|
Contributor
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. These datasets are very incomplete, why not use Or add
Contributor
Author
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. I added the
Contributor
Author
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. I added the |
||||
| ) | ||||
| ``` | ||||
|
|
||||
| --- | ||||
|
|
||||
| ## 1. Explicit choices | ||||
|
Contributor
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 explicit the right term? User-defined, static, ? Should it also reference what happens when choice doesn't exist resolver(
teal.picks::picks(teal.picks::datasets("ADSL"), teal.picks::variables(c("yada"))),
teal.data::teal_data(ADSL = teal.data::rADSL)
)
#' warnings...
#' <picks>
#' <datasets>:
#' choices: ADSL
#' selected: ADSL
#' multiple=FALSE, ordered=FALSE, fixed=TRUE
#' <variables>:
#' choices: ~
#' selected: ~
#' multiple=FALSE, ordered=FALSE, fixed=TRUE, allow-clear=FALSE |
||||
|
|
||||
| Pass a character vector to `choices` to enumerate options exactly. Use `selected` to set the | ||||
| default. Integer indices work too (for example `selected = 1L` means the first element of | ||||
| `choices`). | ||||
|
|
||||
| ```{r explicit} | ||||
| # Datasets — user may switch between ADSL and ADLB; ADSL is the default | ||||
| p_datasets <- picks( | ||||
| datasets( | ||||
| choices = c("ADSL", "ADLB"), | ||||
| selected = "ADSL" | ||||
| ) | ||||
| ) | ||||
|
|
||||
| # Variables — only a named subset is offered; first column pre-selected | ||||
| p_variables <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables( | ||||
| choices = c("AGE", "SEX", "ARM"), | ||||
| selected = "AGE", | ||||
| multiple = FALSE | ||||
| ) | ||||
| ) | ||||
|
|
||||
| # Values — categorical filter; two levels pre-selected | ||||
| p_values <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables(choices = "SEX", selected = "SEX", multiple = FALSE), | ||||
| values( | ||||
| choices = c("M", "F"), | ||||
| selected = "F" | ||||
| ) | ||||
| ) | ||||
|
|
||||
| resolver(x = p_datasets, data = as.list(data)) | ||||
| resolver(x = p_variables, data = as.list(data)) | ||||
| resolver(x = p_values, data = as.list(data)) | ||||
|
Contributor
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 resolver an exported funtion? Do user need to know this function?
Contributor
Author
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. We do not need it. Indeed it is confusing. I removed here. It is exported, btw. |
||||
| ``` | ||||
|
|
||||
| --- | ||||
|
|
||||
| ## 2. `tidyselect` helpers | ||||
|
|
||||
| `tidyselect` predicates let `choices` and `selected` adapt to the actual data at runtime instead | ||||
| of being hard-coded. This is supported for `datasets()` and `variables()`. | ||||
|
averissimo marked this conversation as resolved.
Outdated
|
||||
|
|
||||
| Commonly used helpers: | ||||
|
|
||||
| - `tidyselect::everything()` — all items | ||||
| - `tidyselect::starts_with()` / `tidyselect::ends_with()` / `tidyselect::contains()` — pattern matching | ||||
| - `tidyselect::matches()` — regex matching | ||||
| - `tidyselect::where(predicate)` — columns satisfying a predicate function | ||||
| - `tidyselect::all_of()` / `tidyselect::any_of()` — vector-based selection (error-safe or silent) | ||||
| - Integer indices such as `1L`, `1L:3L` — select by position | ||||
|
|
||||
| > Note: `tidyselect` is not supported by `values()`. Use explicit vectors or a function | ||||
| > there instead (see [Section 3](#functions)). | ||||
|
|
||||
| ```{r tidyselect} | ||||
| # Datasets — offer any data.frame in the teal_data object | ||||
| p_any_dataset <- picks( | ||||
| datasets( | ||||
| choices = tidyselect::where(is.data.frame), | ||||
| selected = 1L # first dataset by default | ||||
| ) | ||||
| ) | ||||
|
|
||||
| # Variables — all numeric columns; first one pre-selected | ||||
| p_numeric_vars <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables( | ||||
| choices = tidyselect::where(is.numeric), | ||||
| selected = 1L, | ||||
| multiple = FALSE | ||||
| ) | ||||
| ) | ||||
|
|
||||
| # Variables — columns whose names start with "A"; first two pre-selected | ||||
| p_a_prefix <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables( | ||||
| choices = tidyselect::starts_with("A"), | ||||
| selected = 1L:2L, | ||||
| multiple = TRUE | ||||
| ) | ||||
| ) | ||||
|
|
||||
| resolver(x = p_any_dataset, data = as.list(data)) | ||||
| resolver(x = p_numeric_vars, data = as.list(data)) | ||||
| resolver(x = p_a_prefix, data = as.list(data)) | ||||
| ``` | ||||
|
|
||||
| --- | ||||
|
|
||||
| ## 3. Functions {#functions} | ||||
|
|
||||
| You can pass a plain R function as `choices` or `selected`. The function receives the relevant | ||||
| context object (the current dataset for `datasets()` and `variables()`, the current column vector | ||||
| for `values()`) and must return the subset to use. This is the only runtime-dynamic approach | ||||
| supported by `values()`. | ||||
|
|
||||
| ```{r functions} | ||||
| # Variables — use the package helper is_categorical() as a column predicate. | ||||
| # Without "des-delayed", the resolver calls it via vapply(data, fn, logical(1)), | ||||
| # so it must accept one column and return a single logical value — which is_categorical() does. | ||||
| p_cat_vars <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables( | ||||
| choices = is_categorical(), | ||||
| selected = 1L, | ||||
| multiple = TRUE | ||||
| ) | ||||
| ) | ||||
|
|
||||
| # Values — select only even ages from the AGE column. | ||||
| # Functions passed to values() must carry the "des-delayed" class so the resolver | ||||
| # calls them with the column vector rather than treating them as a column predicate. | ||||
| even_vals <- function(x) sort(unique(x[x %% 2 == 0])) | ||||
| class(even_vals) <- append(class(even_vals), "des-delayed") | ||||
|
|
||||
| p_even_ages <- picks( | ||||
| datasets(choices = "ADSL", selected = "ADSL"), | ||||
| variables(choices = "AGE", selected = "AGE", multiple = FALSE), | ||||
| values( | ||||
| choices = even_vals, | ||||
| selected = even_vals | ||||
| ) | ||||
| ) | ||||
|
|
||||
| resolver(x = p_cat_vars, data = as.list(data)) | ||||
| resolver(x = p_even_ages, data = as.list(data)) | ||||
| ``` | ||||
|
|
||||
| --- | ||||
|
|
||||
| ## Summary | ||||
|
|
||||
| | | Explicit | `tidyselect` | Function | | ||||
| |---|:---:|:---:|:---:| | ||||
| | `datasets()` | yes | yes | yes | | ||||
| | `variables()` | yes | yes | yes | | ||||
| | `values()` | yes | **no** | yes | | ||||
|
|
||||
| Use **explicit** choices when the set of options is fixed and known at app-development time. | ||||
| Use **`tidyselect`** when you want the choices to adapt to the shape of the data without writing | ||||
| a custom function. Use **functions** when the logic is more involved, or when you need runtime | ||||
| behavior for `values()`. | ||||
|
|
||||
| ## See also | ||||
|
|
||||
| - `?picks` — full reference for `picks()`, `datasets()`, `variables()`, and `values()`. | ||||
| - `?tidyselectors` — package-specific tidyselect helpers such as `is_categorical()`. | ||||
| - `vignette("teal-picks-in-teal", package = "teal.picks")` — wiring `picks` into a `teal` module. | ||||
| - `vignette("teal-picks-standalone-shiny", package = "teal.picks")` — using `picks` in plain Shiny. | ||||
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.
I don't think we need a new vignette, since we already have a vignette with the overall information like this
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.
Merged to the main vignette here. On the other hand now the vignette is not as short as it used to be.