Skip to content

Commit

Permalink
Fixing vignettes (#183)
Browse files Browse the repository at this point in the history
this is part of
#176

- [x] Sanity check of all vignettes, make sure there is no typo, no
wrong format, etc.

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: m7pr <[email protected]>
Co-authored-by: Marcin <[email protected]>
  • Loading branch information
3 people authored Feb 13, 2024
1 parent f20642a commit 6accb86
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 92 deletions.
65 changes: 37 additions & 28 deletions vignettes/data-extract-merge.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,24 @@ knitr::opts_chunk$set(
)
```

`teal.transform` provides `merge_expression_srv` which converts `data_extract_srv` into R expression to transform data
for analytical purposes. For example, we may wish to select `AGE` from `ADSL` and select `AVAL` from `ADTTE` filtered
for rows where `PARAMCD` is `OS` and merge the results (using the primary keys) to create an analysis dataset
`ANL` to be used in the module, as this diagram shows:
`teal.transform` provides `merge_expression_srv`, which converts `data_extract_srv` into `R` expressions to transform data
for analytical purposes.
For example, you may wish to select `AGE` from `ADSL` and select `AVAL` from `ADTTE`, filtered for rows where `PARAMCD` is `OS`, and then merge the results using the primary keys to create an analysis dataset `ANL`.
This diagram illustrates the concept:

```{r echo=FALSE, out.width='100%'}
knitr::include_graphics("./images/data_extract_spec/basic_concept.png")
```

In the following code block we create a `data_extract_spec` object per dataset as illustrated above.
In the following code block, we create a `data_extract_spec` object for each dataset, as illustrated above.

```{r}
library(teal.transform)
library(teal.widgets)
library(teal.data)
library(shiny)
adsl_extract <- teal.transform::data_extract_spec(
adsl_extract <- data_extract_spec(
dataname = "ADSL",
select = select_spec(
label = "Select variable:",
Expand All @@ -43,7 +45,7 @@ adsl_extract <- teal.transform::data_extract_spec(
)
)
adtte_extract <- teal.transform::data_extract_spec(
adtte_extract <- data_extract_spec(
dataname = "ADTTE",
select = select_spec(
choices = c("AVAL", "ASEQ"),
Expand All @@ -63,24 +65,24 @@ data_extracts <- list(adsl_extract = adsl_extract, adtte_extract = adtte_extract

#### Example module

Here, we create the `merge_ui` and the `merge_srv` functions which will be used to create the `ui` and the `srv`
components of the shiny app, respectively.
Here, we define the `merge_ui` and `merge_srv` functions, which will be used to create the UI and the server
components of the `shiny` app, respectively.

```{r}
merge_ui <- function(id, data_extracts) {
ns <- NS(id)
teal.widgets::standard_layout(
output = teal.widgets::white_small_well(
standard_layout(
output = white_small_well(
verbatimTextOutput(ns("expr")),
dataTableOutput(ns("data"))
),
encoding = div(
teal.transform::data_extract_ui(
data_extract_ui(
ns("adsl_extract"), # must correspond with data_extracts list names
label = "ADSL extract",
data_extracts[[1]]
),
teal.transform::data_extract_ui(
data_extract_ui(
ns("adtte_extract"), # must correspond with data_extracts list names
label = "ADTTE extract",
data_extracts[[2]]
Expand All @@ -91,51 +93,58 @@ merge_ui <- function(id, data_extracts) {
merge_srv <- function(id, datasets, data_extracts, join_keys) {
moduleServer(id, function(input, output, session) {
selector_list <- teal.transform::data_extract_multiple_srv(data_extracts, datasets, join_keys)
merged_data <- teal.transform::merge_expression_srv(
selector_list <- data_extract_multiple_srv(data_extracts, datasets, join_keys)
merged_data <- merge_expression_srv(
selector_list = selector_list,
datasets = datasets,
join_keys = join_keys,
merge_function = "dplyr::left_join"
)
ANL <- reactive({ # nolint
eval(envir = list2env(datasets), expr = as.expression(merged_data()$expr))

Check warning on line 103 in vignettes/data-extract-merge.Rmd

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=vignettes/data-extract-merge.Rmd,line=103,col=1,[trailing_whitespace_linter] Trailing whitespace is superfluous.
ANL <- reactive({

Check warning on line 104 in vignettes/data-extract-merge.Rmd

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=vignettes/data-extract-merge.Rmd,line=104,col=5,[object_name_linter] Variable and function name style should match snake_case or symbols.
data_list <- lapply(datasets, function(ds) ds())
eval(envir = list2env(data_list), expr = as.expression(merged_data()$expr))
})

Check warning on line 108 in vignettes/data-extract-merge.Rmd

View workflow job for this annotation

GitHub Actions / SuperLinter 🦸‍♀️ / Lint R code 🧶

file=vignettes/data-extract-merge.Rmd,line=108,col=1,[trailing_whitespace_linter] Trailing whitespace is superfluous.
output$expr <- renderText(paste(merged_data()$expr, collapse = "\n"))
output$data <- renderDataTable(ANL())
})
}
```

Output from `data_extract_srv` (`reactive`) should be passed to `merge_expression_srv` together with `datasets`
(list of `data.frame` objects) and `join_keys` list. `merge_expression_srv` returns a reactive list containing merge expression and information needed to perform the transformation - see more in `merge_expression_srv` documentation.
(list of reactive `data.frame` objects) and `join_keys` object.
`merge_expression_srv` returns a reactive list containing merge expression and information needed to perform the transformation - see more in `merge_expression_srv` documentation.

#### Example data

`data_extract_srv` module depends on either a list of reactive or non-reactive `data.frame` objects. Here, we show the
usage of a list of `data.frame` objects as input to `datasets`
where a list of necessary join keys per `data.frame` object is required:
The `data_extract_srv` module depends on a list of reactive or non-reactive `data.frame` objects.
Here, we demonstrate the usage of a list of reactive `data.frame` objects as input to `datasets`,
along with a list of necessary join keys per `data.frame` object:


```{r}
# Define data.frame objects
ADSL <- teal.transform::rADSL # nolint
ADTTE <- teal.transform::rADTTE # nolint
# create a list of data.frame objects
datasets <- list(ADSL = ADSL, ADTTE = ADTTE)
# create a list of reactive data.frame objects
datasets <- list(
ADSL = reactive(ADSL),
ADTTE = reactive(ADTTE)
)
# create join_keys
join_keys <- teal.data::join_keys(
teal.data::join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")),
teal.data::join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")),
teal.data::join_key("ADTTE", "ADTTE", c("STUDYID", "USUBJID", "PARAMCD"))
join_keys <- join_keys(
join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")),
join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")),
join_key("ADTTE", "ADTTE", c("STUDYID", "USUBJID", "PARAMCD"))
)
```

#### Shiny app

Finally, we pass `merge_ui` and `merge_srv` to the `ui` and `server` functions of the `shinyApp`
Finally, we include `merge_ui` and `merge_srv` to the UI and server component of the `shinyApp`, respectively,
using the `data_extract`s defined in the first code block and the `datasets` object:

```{r eval=FALSE}
Expand Down
60 changes: 32 additions & 28 deletions vignettes/data-extract.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,37 @@ knitr::opts_chunk$set(
)
```

There are times when an app developer wants to showcase more than just one fixed slice of their dataset in their
custom module. Relinquishing control of the application to a user demands the developer gives their users a degree
of freedom. In case of analyzing data, `teal` allows app developers to open up their applications to users, letting them
decide exactly what app data to analyze in the module.

A lot of `teal` modules use `data_extract_spec` objects and modules to tackle user input. You can find many examples in
e.g. `teal.modules.general` and `teal.modules.clinical`.
There are times when an app developer wants to offer users more flexibility in analyzing data within their custom module.
In such cases, relinquishing control of the application to users requires developers to provide a degree of freedom.
With `teal`, app developers can open up their applications to users, allowing them to decide exactly which app data to
analyze within the module.

Many `teal` modules leverage `data_extract_spec` objects and modules to handle user input.
Examples can be found in `teal.modules.general` and `teal.modules.clinical`.

### `data_extract_spec`

`data_extract_spec`'s task is two-fold: create a UI component in a `shiny` application and pass the user input from the
UI to the module itself. Having that formulated, let's have a look at how it supports both its responsibilities.
The role of `data_extract_spec` is twofold: to create a UI component in a `shiny` application and to pass user input
from the UI to the module itself.
Let's delve into how it fulfills both of these responsibilities.

#### Example module

In order to showcase different initialization options of `data_extract_spec`, first we define a `shiny` module which
uses `data_extract_ui` and `data_extract_srv` designed to handle `data_extract_spec` objects. The module creates a UI
component for a single `data_extract_spec` and prints a list of values returned from `data_extract_srv` module. Please see
package documentation for more information about `data_extract_ui` and `data_extract_srv`.
To demonstrate different initialization options of `data_extract_spec`, let's first define a `shiny` module that
utilizes `data_extract_ui` and `data_extract_srv` to handle `data_extract_spec` objects.
This module creates a UI component for a single `data_extract_spec` and prints a list of values returned from the `data_extract_srv` module.
For more information about `data_extract_ui` and `data_extract_srv`, please refer to the package documentation.

```{r}
library(teal.transform)
library(teal.widgets)
library(teal.data)
library(shiny)
extract_ui <- function(id, data_extract) {
ns <- NS(id)
teal.widgets::standard_layout(
output = teal.widgets::white_small_well(verbatimTextOutput(ns("output"))),
standard_layout(
output = white_small_well(verbatimTextOutput(ns("output"))),
encoding = data_extract_ui(ns("data_extract"), label = "variable", data_extract)
)
}
Expand All @@ -66,29 +68,31 @@ extract_srv <- function(id, datasets, data_extract, join_keys) {

#### Example data

`data_extract_srv` module depends on either a list of reactive or non-reactive `data.frame` objects. Here, we show the
usage of a list of `data.frame` objects as input to `datasets`
where a list of necessary join keys per `data.frame` object is required:
The `data_extract_srv` module depends on a list of reactive or non-reactive `data.frame` objects.
Here, we demonstrate the usage of a list of reactive `data.frame` objects as input to `datasets`,
along with a list of necessary join keys per `data.frame` object:

```{r}
# Define data.frame objects
ADSL <- teal.transform::rADSL # nolint
ADTTE <- teal.transform::rADTTE # nolint
# create a list of data.frame objects
datasets <- list(ADSL = ADSL, ADTTE = ADTTE)
# create a list of reactive data.frame objects
datasets <- list(
ADSL = reactive(ADSL),
ADTTE = reactive(ADTTE)
)
# create join_keys
join_keys <- teal.data::join_keys(
teal.data::join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")),
teal.data::join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")),
teal.data::join_key("ADTTE", "ADTTE", c("STUDYID", "USUBJID", "PARAMCD"))
join_keys <- join_keys(
join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")),
join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")),
join_key("ADTTE", "ADTTE", c("STUDYID", "USUBJID", "PARAMCD"))
)
```

Consider the following example, where we create two UI elements, one to filter on a specific level from `SEX` variable,
and a second one to select a variable from `c("BMRKR1", "AGE")`. `data_extract_spec` object is handed over to the shiny
app and gives instructions to generate UI components.
and a second one to select a variable from `c("BMRKR1", "AGE")`.
`data_extract_spec` object is handed over to the `shiny` app and gives instructions to generate UI components.

```{r}
simple_des <- data_extract_spec(
Expand All @@ -100,7 +104,7 @@ simple_des <- data_extract_spec(

#### Shiny app

Finally, we pass `extract_ui` to the `ui` of the `shinyApp` and we use `extract_srv` in the server function of the `shinyApp`:
Finally, we include `extract_ui` in the UI of the `shinyApp`, and utilize `extract_srv` in the server function of the `shinyApp`:

```{r eval=FALSE}
shinyApp(
Expand Down
Loading

0 comments on commit 6accb86

Please sign in to comment.