diff --git a/R/dummy_functions.R b/R/dummy_functions.R index d2a1f48c17..3d447daf3e 100644 --- a/R/dummy_functions.R +++ b/R/dummy_functions.R @@ -5,7 +5,7 @@ #' This module creates an object called `object` that can be modified with decorators. #' The `object` is determined by what's selected in `Choose a dataset` input in UI. #' The object can be anything that can be handled by `renderPrint()`. -#' See the `vignette("customizing-module-output", package = "teal")` or [`teal_transform_module`] +#' See the `vignette("transform-module-output", package = "teal")` or [`teal_transform_module`] #' to read more about decorators. #' #' @inheritParams teal_modules diff --git a/R/modules.R b/R/modules.R index 88638af184..92cb31227c 100644 --- a/R/modules.R +++ b/R/modules.R @@ -74,7 +74,7 @@ setOldClass("teal_modules") #' @param ui_args (named `list`) with additional arguments passed on to the UI function. #' @param x (`teal_module` or `teal_modules`) Object to format/print. #' @param transformators (`list` of `teal_transform_module`) that will be applied to transform module's data input. -#' To learn more check `vignette("data-transform-as-shiny-module", package = "teal")`. +#' To learn more check `vignette("transform-input-data", package = "teal")`. #' #' @param ... #' - For `modules()`: (`teal_module` or `teal_modules`) Objects to wrap into a tab. diff --git a/R/teal_transform_module.R b/R/teal_transform_module.R index 1812d6d6b5..71ba28ca1b 100644 --- a/R/teal_transform_module.R +++ b/R/teal_transform_module.R @@ -13,7 +13,7 @@ #' The primary advantage of `teal_transform_module` over custom modules is in its error handling, where all warnings and #' errors are managed by `teal`, allowing developers to focus on transformation logic. #' -#' For more details, see the vignette: `vignette("data-transform-as-shiny-module", package = "teal")`. +#' For more details, see the vignette: `vignette("transform-input-data", package = "teal")`. #' #' # Customizing Module Outputs #' @@ -23,7 +23,7 @@ #' To manage these `decorators` within your module, use [`ui_transform_teal_data()`] and [`srv_transform_teal_data()`]. #' (For further guidance on managing decorators, refer to `ui_args` and `srv_args` in the vignette documentation.) #' -#' See the vignette `vignette("customizing-module-output", package = "teal")` for additional examples. +#' See the vignette `vignette("transform-module-output", package = "teal")` for additional examples. #' #' # `server` as a language #' @@ -141,7 +141,7 @@ teal_transform_module <- function(ui = NULL, "teal_transform_module() ", "Using eventReactive in teal_transform module server code should be avoided as it ", "may lead to unexpected behavior. See the vignettes for more information ", - "(`vignette(\"data-transform-as-shiny-module\", package = \"teal\")`).", + "(`vignette(\"transform-input-data\", package = \"teal\")`).", call. = FALSE ) } diff --git a/_pkgdown.yml b/_pkgdown.yml index 6c34189050..468399619f 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -62,13 +62,13 @@ articles: - including-data-in-teal-applications - data-as-shiny-module - filter-panel - - data-transform-as-shiny-module + - transform-input-data - title: Extending `teal` navbar: Extending `teal` contents: - creating-custom-modules - adding-support-for-reporting - - customizing-module-output + - transform-module-output - title: Using `teal` navbar: Using `teal` contents: diff --git a/inst/design/teal-transform-module-decorators.drawio b/inst/design/teal-transform-module-decorators.drawio new file mode 100644 index 0000000000..0a15f30de3 --- /dev/null +++ b/inst/design/teal-transform-module-decorators.drawio @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/inst/design/teal-transform-module-transformators.drawio b/inst/design/teal-transform-module-transformators.drawio new file mode 100644 index 0000000000..923f827991 --- /dev/null +++ b/inst/design/teal-transform-module-transformators.drawio @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/man/example_module.Rd b/man/example_module.Rd index e49df8f22d..7e5251a87a 100644 --- a/man/example_module.Rd +++ b/man/example_module.Rd @@ -25,7 +25,7 @@ argument. }} \item{transformators}{(\code{list} of \code{teal_transform_module}) that will be applied to transform module's data input. -To learn more check \code{vignette("data-transform-as-shiny-module", package = "teal")}.} +To learn more check \code{vignette("transform-input-data", package = "teal")}.} \item{decorators}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} (\code{list} of \code{teal_transform_module}) optional, decorator for \code{object} included in the module.} @@ -40,7 +40,7 @@ A \code{teal} module which can be included in the \code{modules} argument to \co This module creates an object called \code{object} that can be modified with decorators. The \code{object} is determined by what's selected in \verb{Choose a dataset} input in UI. The object can be anything that can be handled by \code{renderPrint()}. -See the \code{vignette("customizing-module-output", package = "teal")} or \code{\link{teal_transform_module}} +See the \code{vignette("transform-module-output", package = "teal")} or \code{\link{teal_transform_module}} to read more about decorators. } \examples{ diff --git a/man/module_transform_data.Rd b/man/module_transform_data.Rd index 0bc78405d0..fca1273403 100644 --- a/man/module_transform_data.Rd +++ b/man/module_transform_data.Rd @@ -20,7 +20,7 @@ srv_transform_teal_data( \item{id}{(\code{character(1)}) \code{shiny} module instance id.} \item{transformators}{(\code{list} of \code{teal_transform_module}) that will be applied to transform module's data input. -To learn more check \code{vignette("data-transform-as-shiny-module", package = "teal")}.} +To learn more check \code{vignette("transform-input-data", package = "teal")}.} \item{class}{(character(1)) CSS class to be added in the \code{div} wrapper tag.} diff --git a/man/teal_modules.Rd b/man/teal_modules.Rd index 1632a4e8cd..5adff2df5e 100644 --- a/man/teal_modules.Rd +++ b/man/teal_modules.Rd @@ -85,7 +85,7 @@ argument. \item{ui_args}{(named \code{list}) with additional arguments passed on to the UI function.} \item{transformators}{(\code{list} of \code{teal_transform_module}) that will be applied to transform module's data input. -To learn more check \code{vignette("data-transform-as-shiny-module", package = "teal")}.} +To learn more check \code{vignette("transform-input-data", package = "teal")}.} \item{...}{\itemize{ \item For \code{modules()}: (\code{teal_module} or \code{teal_modules}) Objects to wrap into a tab. diff --git a/man/teal_transform_module.Rd b/man/teal_transform_module.Rd index 46f0192e31..0c17362429 100644 --- a/man/teal_transform_module.Rd +++ b/man/teal_transform_module.Rd @@ -39,7 +39,7 @@ The transformed data is then passed to the \code{server} of \code{\link[=teal_mo The primary advantage of \code{teal_transform_module} over custom modules is in its error handling, where all warnings and errors are managed by \code{teal}, allowing developers to focus on transformation logic. -For more details, see the vignette: \code{vignette("data-transform-as-shiny-module", package = "teal")}. +For more details, see the vignette: \code{vignette("transform-input-data", package = "teal")}. } \section{Customizing Module Outputs}{ @@ -49,7 +49,7 @@ Some \code{\link{teal_modules}} permit developers to inject custom \code{shiny} To manage these \code{decorators} within your module, use \code{\link[=ui_transform_teal_data]{ui_transform_teal_data()}} and \code{\link[=srv_transform_teal_data]{srv_transform_teal_data()}}. (For further guidance on managing decorators, refer to \code{ui_args} and \code{srv_args} in the vignette documentation.) -See the vignette \code{vignette("customizing-module-output", package = "teal")} for additional examples. +See the vignette \code{vignette("transform-module-output", package = "teal")} for additional examples. } \section{\code{server} as a language}{ diff --git a/vignettes/images/teal-transform-module-decorators.svg b/vignettes/images/teal-transform-module-decorators.svg new file mode 100644 index 0000000000..3b3eb2ca2f --- /dev/null +++ b/vignettes/images/teal-transform-module-decorators.svg @@ -0,0 +1 @@ +
Input Data Transformations
Input Data Transformations
Module Output Decoration
Module Output Decoration
Teal Module Logic
Teal Module Logic
teal_dataFilter PanelFiltered teal_dataTransform Panel (transformators)Module LogicGenerated outputs (plots/tables) withinteal_dataDecorated outputs withinteal_dataTransformed teal_dataTransforming module outputs (decorators)Transforming teal_datateal_transform_moduleteal_datateal_transform_moduleTransformed teal_data
...
...
Logicteal_dataTransform Logic
Legend
Legend
Text is not SVG - cannot display
\ No newline at end of file diff --git a/vignettes/images/teal-transform-module-transformators.svg b/vignettes/images/teal-transform-module-transformators.svg new file mode 100644 index 0000000000..847cfc8337 --- /dev/null +++ b/vignettes/images/teal-transform-module-transformators.svg @@ -0,0 +1 @@ +
Input Data Transformations
Input Data Transformations
Module Output Decoration
Module Output Decoration
Teal Module Logic
Teal Module Logic
teal_dataFilter PanelFiltered teal_dataModule LogicGenerated outputs (plots/tables) withinteal_dataTransforming module outputs (decorators)Decorated outputs withinteal_dataTransformed teal_dataTransform Panel (transformators)Transforming teal_datateal_transform_moduleteal_datateal_transform_moduleTransformed teal_data
...
...
Logicteal_dataTransform Logic
Legend
Legend
Text is not SVG - cannot display
\ No newline at end of file diff --git a/vignettes/data-transform-as-shiny-module.Rmd b/vignettes/transform-input-data.Rmd similarity index 95% rename from vignettes/data-transform-as-shiny-module.Rmd rename to vignettes/transform-input-data.Rmd index 0fd9d03bb0..1cc19d30e5 100644 --- a/vignettes/data-transform-as-shiny-module.Rmd +++ b/vignettes/transform-input-data.Rmd @@ -1,11 +1,11 @@ --- -title: "Data Transformations as Shiny Module" +title: "Transform Input Data" author: "NEST CoreDev" output: rmarkdown::html_vignette: toc: true vignette: > - %\VignetteIndexEntry{Data Transformations as shiny Module} + %\VignetteIndexEntry{Transform Input Data} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -13,7 +13,7 @@ vignette: > ## Introduction `teal` version `0.16` introduced a new, optional argument in `teal::module`, `transformators`. -This argument accepts a `list` of `teal_transform_module` objects, which are a special class of `teal_data_module` created using the `teal_transform_module()` function. +This argument accepts a `list` of `teal_transform_module` objects, which are created using the `teal_transform_module()` function. `teal_transform_module()` takes `ui` and `server` arguments to create a `shiny` module that encodes data transformations. When transformators are passed to a module, `teal` will execute data transformations when that module is loaded as well as whenever the original data changes. @@ -23,6 +23,10 @@ The `ui` elements of the transform module will be added to the filter panel, whi This vignette describes how to manage custom data transformations in `teal` apps. +Transforming teal_data + +In this vignette we will focus on using the `teal_transform_module` for transforming the input data using the `transformators` argument in `teal::module` function. + ## Creating a data transformation module Let us initialize a simple `teal` app by providing `iris` and `mtcars` as input datasets. diff --git a/vignettes/customizing-module-output.Rmd b/vignettes/transform-module-output.Rmd similarity index 80% rename from vignettes/customizing-module-output.Rmd rename to vignettes/transform-module-output.Rmd index cd18778d10..64658fa2f5 100644 --- a/vignettes/customizing-module-output.Rmd +++ b/vignettes/transform-module-output.Rmd @@ -1,11 +1,11 @@ --- -title: "Customizing Module Output" +title: "Transform Module Output" author: "NEST CoreDev" output: rmarkdown::html_vignette: toc: true vignette: > - %\VignetteIndexEntry{Customizing Module Output} + %\VignetteIndexEntry{Transform Module Output} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -19,39 +19,42 @@ library(ggplot2) ## Introduction The outputs produced by `teal` modules, like graphs or tables, are created by the module developer and look a certain way. -It is impossible to design an output that will satisfy every possible user, so the form of the output should be considered a default value that can be customized. -Here we describe the concept of _decoration_, whereby a `teal_transform_module` can modify an output created by a `teal_module`, enabling you to tailor outputs to your specific requirements without rewriting the original module code. +It is hard to design an output that will satisfy every possible user, so the form of the output should be considered a default value that can be customized. +In [Transform Input Data](transform-input-data.html) we described how `teal_module`'s input data can be modified using `teal_transform_module`. Here we present how to utilize `teal_transform_module` to modify an output created by a `teal_module`, enabling you to tailor outputs to your specific requirements without rewriting the original module code. -While it is not required, reading [this vignette](data-transform-as-shiny-module.html) may give you a fuller understanding. +Transforming teal_data +## How to Transform outputs? -## Decorators - -Decorators are created with `teal_transform_module` and thus they are `shiny` modules. +Custom transformations for the output objects can be created with `teal_transform_module()` and thus they are `shiny` modules. They are passed to `teal_module` constructors as arguments (see below). Their server logic will be used to modify objects such as plots or tables that exist in the server function of a `teal_module`. -A `ui` function can provide interactivity but that is optional, an app developer is free to use decorator modules that do not require user input. +A `ui` function can provide interactivity but that is optional, an app developer is free to transform outputs objects of a `teal` module that do not require user input. ### Requirements and Limitations -Using decorators requires the following: +Transforming `teal` module output requires the following: 1. **Module Support**:
-`teal` will apply decorators to `teal_module` outputs but the module in question must explicitly support this functionality. -It the responsibility of to the module developer to ensure that decorators can be used. +`teal` will apply transformations to `teal_module` outputs, but the module in question must explicitly support this functionality. +It is the responsibility of to the module developer to accept and consume the list of `teal_transform_module`. 2. **Matching Object Names**:
-Decorators will reference variables that exist in the `teal_module` server function and therefore must use the appropriate variable names. -Module developers are encouraged to provide the relevant names in the module's documentation, otherwise the person writing a decorator must follow the source code. +Transformations have to reference variables that already exist in the `teal_module` server function and therefore must use the appropriate variable names. +Think of it as extending the plot/table code that already exists in the module. +Module developers are encouraged to provide the relevant names in the module's documentation, otherwise the person writing the output transformation must follow the source code. 3. **Maintaining Object Classes**:
-A decorator must not alter the class of the object that it modifies. +A transformation must not alter the class of the object that it modifies. This is because a different class may require a different rendering function and that is part of the module structure, which beyond the control of decorators. +If change of this magnitude is required, it is recommended to create a new module. + +## Building Output Transformations (Decorators) -## Building Decorators +For simplicity, we will refer to the output transformers as **decorators** in the code examples below. ### Server -Here we create a simple decorator that does not provide user input. +Here we create a simple transformator that does not provide any user input. Knowing that the module contains an object of class `ggplot2` named `plot`, we will modify its title and x-axis title: ```{r static_decorator} @@ -75,7 +78,7 @@ static_decorator <- teal_transform_module( ### UI -If decoration requires user input, a `ui` function can be added. +If the transformation requires a user input, a `ui` function can be added. Here, the x-axis title is obtained from a `textInput` widget, giving the user some flexibility. Note how the input values are passed to the `within()` function using its `...` argument. See `?teal.code::within.qenv` for more examples. @@ -110,10 +113,10 @@ interactive_decorator <- teal_transform_module( ### Variable Names as Arguments -The server function of a decorating `teal_transform_module` must conform to the names of the variables that exist in the server function of the decorated `teal_module`. -Writing a universal decorator that applies to any module is impossible because different modules may use different variable names for their output elements. -It is possible, however, to create a decorator that will take the relevant variable names as arguments. -Here, the `output_name` variable name is passed to a decorator, allowing it to work with multiple modules. +The server function of a transforming `teal_transform_module` must conform to the names of the variables that exist in the server function of the transformed `teal_module`. +Writing a universal transformator that applies to any module is impossible because different modules may use different variable names for their output elements. +It is possible, however, to create a transformator that will take the relevant variable names as arguments. +Here, the `output_name` variable name is passed to a transformator, allowing it to work with multiple modules. ```{r dynamic_decorator} dynamic_decorator <- function(output_name) { @@ -147,20 +150,21 @@ dynamic_decorator <- function(output_name) { Note that when the function is used, `output_name` will be passed a character string but the expression passed to `within` needs a `name`/`symbol`, a language object, hence the argument value must be converted to a `name`. -## Using Decorators +## Using Output Transformations (Decorators) -Decorators are applied to a `teal` module as follows: +Transformations are applied to a `teal` module as follows: -1. A list of decorators is passed to the module constructor function (_e.g._ `tm_my_module`). -2. The module constructor calls the module generator function (`teal::module`) and passes the decorators to the `ui_args` and `server_args` arguments. -3. The module functions, UI and server, take a list of decorators as arguments and resolve them using `ui_transform_teal_data` and `srv_transform_teal_data`, respectively. +1. A list of transformations is passed to the module constructor function (_e.g._ `tm_my_module`). +2. The module constructor calls the module generator function (`teal::module`) and passes the transformations to the `ui_args` and `server_args` arguments. +3. The module functions, UI and server, take a list of transformations as arguments and resolve them using `ui_transform_teal_data` and `srv_transform_teal_data`, respectively. Here is a minimal illustration: ```{r pseudo_module, eval = FALSE} +# styler: off pseudo_decorated_module <- function( label = "Pseudo Module with Decorator Support", - decorators = list() # <--- added block (1) + decorators = list() # <--- added block (1) ) { module( label = label, @@ -191,13 +195,14 @@ pseudo_decorated_module <- function( } ) } +# styler: on ``` -The following examples demonstrate various uses of decorators. +The following examples demonstrate various uses of output transformations. -### Single Decoration +### Single Transformation (Decoration) -In the first example we will apply one decoration to one output. +In the first example we will apply one transformation to one output. ### Module @@ -288,7 +293,7 @@ tm_decorated_plot <- function(label = "module", decorators = list()) { #### Application -Note that every call to the module constructor (`tm_decorated_plot`) takes a list containing _one_ decorator. +Note that every call to the module constructor (`tm_decorated_plot`) takes a list containing _one_ transformator. ```{r app_1} app <- init( @@ -321,13 +326,13 @@ knitr::include_url(url, height = "800px") ``` -### Decorating Multiple Outputs +### Transforming Multiple Outputs (Decorators) -Here we will apply decoration to two outputs in one module. +Here we will apply transformation to two outputs in one module. -#### Decorators +#### Transformators -The plot decorator adds a user-provided title to a `ggplot2` object. +The plot transformators adds a user-provided title to a `ggplot2` object. ```{r plot_decorator} plot_decorator <- teal_transform_module( @@ -356,7 +361,7 @@ plot_decorator <- teal_transform_module( ) ``` -The table decorator adds a column to a `data.frame`. +The table transformators adds a column to a `data.frame`. ```{r table_decorator} table_decorator <- teal_transform_module( @@ -381,7 +386,7 @@ table_decorator <- teal_transform_module( The following module uses `ggplot2` to generate a scatter plot, and presents a simple `data.frame` as a summary table. Code for both outputs is also displayed. -Note that the module constructor accepts one list of decorators and the decorators are then manually separated in the module functions. +Note that the module constructor accepts one list of transformations and the transformations are then manually separated in the module functions. ```{r tm_decorated_plot_table} tm_decorated_plot_table <- function(label = "module with two outputs", decorators = list()) { @@ -479,7 +484,7 @@ tm_decorated_plot_table <- function(label = "module with two outputs", decorator #### Application -Note that a named list of decorators is passed to the module constructor. +Note that a named list of transformations is passed to the module constructor. ```{r app_2} app <- init( @@ -516,14 +521,14 @@ knitr::include_url(url, height = "800px") ## Convenience -Here we present some ways to work with decorators more conveniently. +Here we present some ways to work with transformators more conveniently. These are purely optional. ### Reducing Boilerplate -The function `make_teal_transform_server` can be used to reduce the amount of boilerplate code when writing new decorators. +The function `make_teal_transform_server` can be used to reduce the amount of boilerplate code when writing new transformators. It takes `language` as input and requires you to use `input` object names directly in the expression. -The following calls yield the same decorator module. +The following calls yield the same transformator module. Note that the combination of `my_title = input$x_axis_title` and `xlab(my_title)` is replaced by a simple `xlab(x_axis_table)`. ```{r, eval=FALSE} teal_transform_module( @@ -567,9 +572,9 @@ teal_transform_module( ``` -### Multiple Decorators +### Multiple Transformations -Consider these constructs to accommodate an arbitrary number of decorators in your module. +Consider these constructs to accommodate an arbitrary number of transformators in your module. Note that with this method all decorations will be applied to one output. ```{r, eval=FALSE} # in the module UI function