From 3b0b69b32367c3c4b53227aea40a08c445595d87 Mon Sep 17 00:00:00 2001 From: m7pr Date: Fri, 6 Jun 2025 15:36:38 +0200 Subject: [PATCH 01/23] extend getting started vignette with the info about report parameter --- vignettes/getting-started-with-teal.Rmd | 80 ++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index 472dab4740..59ba8ff0a1 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -126,8 +126,84 @@ For further details see [Filter Panel vignette](filter-panel.html). ### Reporting -If any of the `modules` in your `teal` application support reporting (see [`teal.reporter`](https://insightsengineering.github.io/teal.reporter/) for more details), users of your application can add the outputs of the modules to a report. -This report can then be downloaded and a special _Report Previewer_ module will be added to your application as an additional tab, where users can view and configure their reports before downloading them. See more details in [this vignette](adding-support-for-reporting.html). +The `init` function includes a `reporter` parameter that controls the global reporting functionality of your `teal` application. This parameter determines whether and how users can generate reports from the analyses performed in your application. + +#### Configuring the Reporter Parameter + +The `reporter` parameter in `init` accepts three types of values: + +##### 1. Default Reporting (parameter omitted) +When you don't specify the `reporter` parameter, `teal` automatically enables default reporting functionality: + +```{r default_reporting} +# Default reporting - automatically enabled +app_default <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ) +) +``` + +With default reporting enabled: +- A "Report previewer" tab is automatically added to your application +- Users can add module outputs to reports and download them +- Reports include reproducible code for all analyses + +##### 2. Disabled Reporting (`reporter = NULL`) +To completely disable reporting functionality across your entire application: + +```{r disabled_reporting} +# Reporting disabled - no report functionality available +app_no_reporting <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ), + reporter = NULL +) +``` + +When `reporter = NULL`: +- No "Report previewer" tab appears +- Modules cannot add content to reports +- All reporting-related UI elements are hidden + +##### 3. Custom Reporter (R6 object) +For advanced use cases, you can provide a custom reporter object that inherits from the appropriate R6 class: + +```{r custom_reporter} +library(teal.reporter) + +# Create a custom reporter with specific configuration +custom_reporter <- teal.reporter::Reporter$new() + +# Use the custom reporter in your app +app_custom <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ), + reporter = custom_reporter +) +``` + +#### Choosing the Right Configuration + +* **Use default reporting** (omit parameter) for most applications where you want standard reporting functionality +* **Use `reporter = NULL`** when you want to disable reporting entirely, perhaps for: + - Demo applications + - Apps where reporting is not needed + - Performance-critical applications +* **Use a custom reporter** when you need: + - Special report formatting + - Custom report templates + - Integration with external reporting systems + +For more details on reporting functionality and how to implement it in your modules, see [this vignette](adding-support-for-reporting.html) and the [`teal.reporter`](https://insightsengineering.github.io/teal.reporter/) package documentation. ### Reproducible code From ad027a28e177ac85e7248a387c9b1c546b397beb Mon Sep 17 00:00:00 2001 From: m7pr Date: Fri, 6 Jun 2025 15:40:09 +0200 Subject: [PATCH 02/23] add info about `disable_report()` --- vignettes/getting-started-with-teal.Rmd | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index 59ba8ff0a1..cdf92f8972 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -191,6 +191,27 @@ app_custom <- init( ) ``` +#### Module-Level Reporting Control + +While the `reporter` parameter controls reporting globally, you can also disable reporting for specific modules using `disable_report()`. This allows you to have fine-grained control over which modules support reporting: + +```{r module_level_control} +# App with global reporting enabled, but specific modules excluded +app_selective <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), # Reporting enabled + disable_report(example_module("Analysis 2")), # Reporting disabled for this module + example_module("Analysis 3") # Reporting enabled + ) +) +``` + +In this example: +- "Analysis 1" and "Analysis 3" modules can add content to reports +- "Analysis 2" module cannot add content to reports (no "Add to Report" buttons appear) +- The "Report previewer" tab is still available since reporting is globally enabled + #### Choosing the Right Configuration * **Use default reporting** (omit parameter) for most applications where you want standard reporting functionality @@ -202,6 +223,10 @@ app_custom <- init( - Special report formatting - Custom report templates - Integration with external reporting systems +* **Use `disable_report()`** for individual modules when you want: + - Most modules to support reporting but exclude specific ones + - To disable reporting for modules that don't produce meaningful report content + - Fine-grained control over the reporting experience For more details on reporting functionality and how to implement it in your modules, see [this vignette](adding-support-for-reporting.html) and the [`teal.reporter`](https://insightsengineering.github.io/teal.reporter/) package documentation. From 91aa822c7f3d18a52bfa7985448a77a9ced896d3 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:18:07 +0200 Subject: [PATCH 03/23] Update vignettes/getting-started-with-teal.Rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/getting-started-with-teal.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index cdf92f8972..f85a55d20d 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -171,8 +171,8 @@ When `reporter = NULL`: - Modules cannot add content to reports - All reporting-related UI elements are hidden -##### 3. Custom Reporter (R6 object) -For advanced use cases, you can provide a custom reporter object that inherits from the appropriate R6 class: +##### 3. Custom Reporter +For advanced use cases, you can provide a custom initial reporter object: ```{r custom_reporter} library(teal.reporter) From f49d361a7d3f49db8f7ff1f552939ed5640959dd Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:18:05 +0200 Subject: [PATCH 04/23] simplify getting started --- vignettes/getting-started-with-teal.Rmd | 106 ++---------------------- 1 file changed, 7 insertions(+), 99 deletions(-) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index f85a55d20d..a39b6443c2 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -128,108 +128,16 @@ For further details see [Filter Panel vignette](filter-panel.html). The `init` function includes a `reporter` parameter that controls the global reporting functionality of your `teal` application. This parameter determines whether and how users can generate reports from the analyses performed in your application. -#### Configuring the Reporter Parameter - The `reporter` parameter in `init` accepts three types of values: -##### 1. Default Reporting (parameter omitted) -When you don't specify the `reporter` parameter, `teal` automatically enables default reporting functionality: - -```{r default_reporting} -# Default reporting - automatically enabled -app_default <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = modules( - example_module("Analysis 1"), - example_module("Analysis 2") - ) -) -``` - -With default reporting enabled: -- A "Report previewer" tab is automatically added to your application -- Users can add module outputs to reports and download them -- Reports include reproducible code for all analyses - -##### 2. Disabled Reporting (`reporter = NULL`) -To completely disable reporting functionality across your entire application: - -```{r disabled_reporting} -# Reporting disabled - no report functionality available -app_no_reporting <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = modules( - example_module("Analysis 1"), - example_module("Analysis 2") - ), - reporter = NULL -) -``` - -When `reporter = NULL`: -- No "Report previewer" tab appears -- Modules cannot add content to reports -- All reporting-related UI elements are hidden - -##### 3. Custom Reporter -For advanced use cases, you can provide a custom initial reporter object: - -```{r custom_reporter} -library(teal.reporter) - -# Create a custom reporter with specific configuration -custom_reporter <- teal.reporter::Reporter$new() - -# Use the custom reporter in your app -app_custom <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = modules( - example_module("Analysis 1"), - example_module("Analysis 2") - ), - reporter = custom_reporter -) -``` - -#### Module-Level Reporting Control - -While the `reporter` parameter controls reporting globally, you can also disable reporting for specific modules using `disable_report()`. This allows you to have fine-grained control over which modules support reporting: - -```{r module_level_control} -# App with global reporting enabled, but specific modules excluded -app_selective <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = modules( - example_module("Analysis 1"), # Reporting enabled - disable_report(example_module("Analysis 2")), # Reporting disabled for this module - example_module("Analysis 3") # Reporting enabled - ) -) -``` - -In this example: -- "Analysis 1" and "Analysis 3" modules can add content to reports -- "Analysis 2" module cannot add content to reports (no "Add to Report" buttons appear) -- The "Report previewer" tab is still available since reporting is globally enabled - -#### Choosing the Right Configuration - -* **Use default reporting** (omit parameter) for most applications where you want standard reporting functionality -* **Use `reporter = NULL`** when you want to disable reporting entirely, perhaps for: - - Demo applications - - Apps where reporting is not needed - - Performance-critical applications -* **Use a custom reporter** when you need: - - Special report formatting - - Custom report templates - - Integration with external reporting systems -* **Use `disable_report()`** for individual modules when you want: - - Most modules to support reporting but exclude specific ones - - To disable reporting for modules that don't produce meaningful report content - - Fine-grained control over the reporting experience - -For more details on reporting functionality and how to implement it in your modules, see [this vignette](adding-support-for-reporting.html) and the [`teal.reporter`](https://insightsengineering.github.io/teal.reporter/) package documentation. +* `NULL`: reporting is disabled globally. +* `teal.reporter::Report$new()`: predefined reporter object. +* `missing value`: reporting is enabled by default globally. +For more details on reporting functionality and how to implement it in your modules, see: +- [adding support for reporting](adding-support-for-reporting.html), +- [managing reproducible report documents in teal](managing-reproducible-report-documents-in-teal.html), +- [`teal.reporter`](https://insightsengineering.github.io/teal.reporter/) package documentation. ### Reproducible code From 1864d8266d7779e40102a13d78d92a11a5e36b60 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:18:40 +0200 Subject: [PATCH 05/23] rewrite adding support --- vignettes/adding-support-for-reporting.Rmd | 258 +++++---------------- 1 file changed, 58 insertions(+), 200 deletions(-) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index 4e04e3fb8f..1fa5b222cd 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -21,7 +21,7 @@ Thus the app user can interact with the report. The responsibilities of a module developer include: -- Adding support for reporting to their module. +- Adding support for reporting to their module, by returning a reactive `teal_data` object from the `server` function of the module. - Specifying the outputs that constitute a snapshot of their module. The entire life cycle of objects involved in creating the report and configuring the module to preview the report is handled by `teal`. @@ -93,23 +93,24 @@ knitr::include_url(url, height = "800px") ## Add support for reporting -### Modify the declaration of the server function +### Modify the body of the server function -The first step is to add an additional argument to the server function declaration - `reporter`. -This informs `teal` that the module requires `reporter`, and it will be included when the module is called. +To inform `teal` that the module requires reporting, return interactive `teal_data` from the `server` function. +Outputs of the module will be included in the report when the module is called. See below: ```{r module_2} my_module_with_reporting <- function(label = "example teal module") { module( label = label, - server = function(id, data, reporter) { + server = function(id, data) { moduleServer(id, function(input, output, session) { updateSelectInput(session, "dataname", choices = isolate(names(data()))) output$dataset <- renderPrint({ req(input$dataname) data()[[input$dataname]] }) + return(data) }) }, ui = function(id) { @@ -148,114 +149,36 @@ url <- roxy.shinylive::create_shinylive_url(code) knitr::include_url(url, height = "800px") ``` +### Add content to the report card -`teal` adds another tab to the application, titled `Report previewer`. -However, there is no visible change in how the module operates and appears and the user cannot add content to the report from this module. -That requires inserting UI and server elements of the `teal.reporter` module into the module body. - -### Insert `teal.reporter` module +To add content to a report card, we will utilize the `teal_report` class and its convenience function `teal_card`. +You can read about it [here](https://insightsengineering.github.io/teal.reporter/latest-tag/articles/teal-report-class.html). -The UI and the server logic necessary for adding cards from `my_module_with_reporting` to the report are provided by `teal.reporter::simple_reporter_ui` and `teal.reporter::simple_reporter_srv`. +Every input `teal_data` object in `teal` gets converted to a `teal_report` object. +This means that we can use the `teal_report` class to add content to the report card. -```{r module_3} +```{r module_4} my_module_with_reporting <- function(label = "example teal module") { module( label = label, server = function(id, data, reporter) { moduleServer(id, function(input, output, session) { - teal.reporter::simple_reporter_srv( - id = "reporter", - reporter = reporter, - card_fun = function(card) card - ) updateSelectInput(session, "dataname", choices = isolate(names(data()))) output$dataset <- renderPrint({ req(input$dataname) data()[[input$dataname]] }) - }) - }, - ui = function(id) { - ns <- NS(id) - sidebarLayout( - sidebarPanel( - teal.reporter::simple_reporter_ui(ns("reporter")), - selectInput(ns("dataname"), "Choose a dataset", choices = NULL) - ), - mainPanel(verbatimTextOutput(ns("dataset"))) - ) - } - ) -} -``` - -This updated module is now ready to be launched: - -```{r app_3} -app <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = my_module_with_reporting() -) - -if (interactive()) { - shinyApp(app$ui, app$server) -} -``` - -A new piece of `UI` has been added, and the buttons are clickable. -The user can now add a card to the report and view it in the `Report previewer` module but the preview is still empty since we have not instructed our module what to put on the card. - -```{r shinylive_iframe_3, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} -code <- paste0(c( - knitr::knit_code$get("as_interactive"), - knitr::knit_code$get("setup"), - knitr::knit_code$get("module_3"), - knitr::knit_code$get("app_3") -), collapse = "\n") -url <- roxy.shinylive::create_shinylive_url(code) -knitr::include_url(url, height = "800px") -``` - -### Add content to the card - -To add content to a card, we will utilize the public API exposed by the `TealReportCard` class. -The `teal.reporter::simple_reporter_srv` module accepts the `card_fun` argument that determines the appearance of the output from our custom module. -`ReportCard` and its derivatives allow the sequential addition of content according to the order of method calls. -To explore the content, we can use the `$get_content` method. -For further details, refer to the documentation of `TealReportCard` and `teal.reporter::ReportCard`. - -We will add simple text to the card by modifying the `card_fun` argument passed to `teal.reporter::simple_reporter_srv`. -The function must return the `teal_card` object, otherwise errors may occur in `teal`. - -```{r module_4} -custom_function <- function(card = teal.reporter::ReportCard$new()) { - card$append_text("This is content from a custom teal module!") - card -} - -my_module_with_reporting <- function(label = "example teal module") { - module( - label = label, - server = function(id, data, reporter) { - moduleServer(id, function(input, output, session) { - teal.reporter::simple_reporter_srv( - id = "reporter", - reporter = reporter, - card_fun = custom_function - ) - updateSelectInput(session, "dataname", choices = isolate(names(data()))) - output$dataset <- renderPrint({ - req(input$dataname) - data()[[input$dataname]] + rdata <- reactive({ + teal_card(data()) <- teal_card(data(), "## Example heading", head(iris)) }) + return(rdata) }) }, ui = function(id) { ns <- NS(id) sidebarLayout( sidebarPanel( - teal.reporter::simple_reporter_ui(ns("reporter")), selectInput(ns("dataname"), "Choose a dataset", choices = NULL) ), mainPanel(verbatimTextOutput(ns("dataset"))) @@ -276,7 +199,8 @@ if (interactive()) { } ``` -Now, an application user can see the text added by `custom_function` in the `Report previewer` module. +Now, an application user can see the text and `data.frame` added inside the `teal_card` in the `Report previewer` module. +You can also add other objects, like ggplot2, rtables, rlistings, etc. ```{r shinylive_iframe_4, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} code <- paste0(c( @@ -290,138 +214,72 @@ url <- roxy.shinylive::create_shinylive_url(code) knitr::include_url(url, height = "800px") ``` -### Add non-text content to the card - -`teal.reporter` supports the addition of tables, charts, and more. -For more information, explore the API of `teal.reporter::ReportCard` to learn about the supported content types. - -### `TealReportCard` - -`teal` exports the `TealReportCard` class, which extends the `teal.reporter::ReportCard` class and provides several convenient methods to facilitate working with `teal` features like the filter panel or source code. -For more details, refer to the documentation of `TealReportCard`. - -To support `TealReportCard`, the function that is passed to `teal.reporter::simple_reporter_srv` must define a default value for the card, as shown below: - -```{r} -custom_function <- function(card = TealReportCard$new()) { - # ... some code ... # - card -} -``` - -Without this definition, the API of `TealReportCard` will not be available within the function. - ## Example In conclusion, we have demonstrated how to build a standard `teal` app with code reproducibility and reporter functionalities. -Note that the server function requires the `filter_panel_api` argument so that the filter panel state can be added to the report. In the final example, we have incorporated `teal.code` snippets. `teal.code` is an `R` library that offers utilities for storing code and associating it with an execution environment. -This allows `ReporterCard` to store the code necessary to generate the table along with the table itself. +This allows `teal_report` to store the code necessary to generate the table along with the table itself. To learn more about `teal.code` see the vignette _`qenv`_ in `teal.code`. ```{r app_5} -example_reporter_module <- function(label = "Example") { +tm_simple_regression <- function(label = "Simple Regression") { module( label = label, - server = function(id, data, reporter, filter_panel_api) { - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelApi") - moduleServer(id, function(input, output, session) { - updateSelectInput(session, "dataname", choices = isolate(names(data()))) - dat <- reactive(data()[[input$dataname]]) - observe({ - req(input$dataname) - req(dat()) - updateSliderInput(session, "nrow", max = nrow(dat()), value = floor(nrow(dat()) / 5)) - }) - - table_q <- reactive({ - req(input$dataname) - req(input$nrow) - within( - data(), - result <- head(dataset, nrows), - dataset = as.name(input$dataname), - nrows = input$nrow - ) - }) - - output$table <- renderTable(table_q()[["result"]]) - - ### REPORTER - card_fun <- function(card = teal.reporter::ReportCard$new(), comment) { - card$set_name("Table Module") - card$append_text(paste("Selected dataset", input$dataname), "header2") - card$append_text("Selected Filters", "header3") - if (with_filter) { - card$append_text(filter_panel_api$get_filter_state(), "verbatim") - } - card$append_text("Encoding", "header3") - card$append_text( - yaml::as.yaml( - stats::setNames( - lapply(c("dataname", "nrow"), function(x) input[[x]]), c("dataname", "nrow") - ) - ), - "verbatim" - ) - card$append_text("Module Table", "header3") - card$append_table(table_q()[["result"]]) - card$append_text("Show R Code", "header3") - card$append_text(teal.code::get_code(table_q()), "verbatim") - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card - } - teal.reporter::add_card_button_srv( - "addReportCard", - reporter = reporter, - card_fun = card_fun + server = function(input, output, session, data, reporter, ...) { + + # Create the plot + output$plot <- renderPlot({ + req(input$x_var, input$y_var) + dataset <- data()[["iris"]] + plot(dataset[[input$x_var]], dataset[[input$y_var]]) + }) + + report_data <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- + c(teal.reporter::teal_card(obj), "# Module's computation") + eval_code( + obj, + sprintf( + "correlation <- cor(iris[['%s']], iris[['%s']]);correlation", + input$x_var, + input$y_var + ), + keep_output = TRUE ) - teal.reporter::download_report_button_srv("downloadButton", reporter = reporter) - teal.reporter::reset_report_button_srv("resetButton", reporter) - ### }) + report_data }, + ui = function(id) { ns <- NS(id) - - sidebarLayout( - sidebarPanel(selectInput(ns("dataname"), "Choose a dataset", choices = NULL)), - mainPanel( - teal.reporter::simple_reporter_ui(ns("reporter")), - verbatimTextOutput(ns("dataset")) - ) - ) - - sidebarLayout( - sidebarPanel( - tags$div( - teal.reporter::add_card_button_ui(ns("addReportCard")), - teal.reporter::download_report_button_ui(ns("downloadButton")), - teal.reporter::reset_report_button_ui(ns("resetButton")) + fluidPage( + h3("Simple Regression Plot"), + fluidRow( + column(6, + selectInput(ns("x_var"), "X Variable:", + choices = names(iris)[1:4], selected = "Sepal.Length") ), - selectInput(ns("dataname"), "Choose a dataset", choices = NULL), - sliderInput(ns("nrow"), "Number of rows", min = 1, max = 1, value = 1, step = 1) + column(6, + selectInput(ns("y_var"), "Y Variable:", + choices = names(iris)[1:4], selected = "Sepal.Width") + ) ), - mainPanel(tableOutput(ns("table"))) + plotOutput(ns("plot")) ) } ) } app <- init( - data = teal_data(AIR = airquality, IRIS = iris), - modules = list( - example_reporter_module(label = "with Reporter"), - my_module(label = "without Reporter") + data = teal_data(iris = iris), + modules = modules( + tm_simple_regression("Regression Analysis") ), - filter = teal_slices(teal_slice(dataname = "AIR", varname = "Temp", selected = c(72, 85))) -) |> - modify_header(tags$h2("Example teal app with reporter")) + header = "Simple Teal App with Reporting" +) if (interactive()) { shinyApp(app$ui, app$server) From 1c5b23dc78d0b9798aa0c4d9a319d7d1c832e24a Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:18:58 +0200 Subject: [PATCH 06/23] add managing reproducible report document in teal --- _pkgdown.yml | 1 + ...-reproducible-report-documents-in-teal.rmd | 151 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 vignettes/managing-reproducible-report-documents-in-teal.rmd diff --git a/_pkgdown.yml b/_pkgdown.yml index f0bc2d1578..6427e7f5ac 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -68,6 +68,7 @@ articles: contents: - creating-custom-modules - adding-support-for-reporting + - managing-reproducible-report-documents-in-teal - transform-module-output - title: Using `teal` navbar: Using `teal` diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd new file mode 100644 index 0000000000..45a2b141f5 --- /dev/null +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -0,0 +1,151 @@ +--- +title: "Managing Reproducible Report Documents in teal" +author: "NEST CoreDev" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Managing Reproducible Report Documents in teal} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## Introduction + +`teal` provides comprehensive reporting capabilities that allow users to generate reproducible documents from their analysis modules. This vignette covers the key components for managing report documents in `teal` applications. + +The reporting system offers three levels of control: + +1. **Global reporting control** via the `reporter` parameter in `init()` +2. **Module-level control** using `disable_report()` to exclude specific modules +3. **Report customization** with the `after` function to enhance report content + +This vignette demonstrates how to use these features effectively to create flexible and customized reporting workflows. + +## Global and Local Reporting Control + +##### 1. Default Reporting (parameter omitted) +When you don't specify the `reporter` parameter, `teal` automatically enables default reporting functionality: + +```{r default_reporting} +# Default reporting - automatically enabled +app_default <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ) +) +``` + +With default reporting enabled: +- A "Report previewer" tab is automatically added to your application +- Users can add module outputs to reports and download them +- Reports include reproducible code for all analyses + +##### 2. Disabled Reporting (`reporter = NULL`) +To completely disable reporting functionality across your entire application: + +```{r disabled_reporting} +# Reporting disabled - no report functionality available +app_no_reporting <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ), + reporter = NULL +) +``` + +When `reporter = NULL`: +- No "Report previewer" tab appears +- Modules cannot add content to reports +- All reporting-related UI elements are hidden + +##### 3. Custom Reporter +For advanced use cases, you can provide a custom initial reporter object: + +```{r custom_reporter} +library(teal.reporter) + +# Create a custom reporter with specific configuration +custom_reporter <- teal.reporter::Reporter$new() + +# Use the custom reporter in your app +app_custom <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ), + reporter = custom_reporter +) +``` + +#### Module-Level Reporting Control + +While the `reporter` parameter controls reporting globally, you can also disable reporting for specific modules using `disable_report()`. This allows you to have fine-grained control over which modules support reporting: + +```{r module_level_control} +# App with global reporting enabled, but specific modules excluded +app_selective <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), # Reporting enabled + disable_report(example_module("Analysis 2")), # Reporting disabled for this module + example_module("Analysis 3") # Reporting enabled + ) +) +``` + +In this example: +- "Analysis 1" and "Analysis 3" modules can add content to reports +- "Analysis 2" module cannot add content to reports (no "Add to Report" buttons appear) +- The "Report previewer" tab is still available since reporting is globally enabled + +#### Choosing the Right Configuration + +* **Use default reporting** (omit parameter) for most applications where you want standard reporting functionality +* **Use `reporter = NULL`** when you want to disable reporting entirely, perhaps for: + - Demo applications + - Apps where reporting is not needed + - Performance-critical applications +* **Use a custom reporter** when you need: + - Special report formatting + - Custom report templates + - Integration with external reporting systems +* **Use `disable_report()`** for individual modules when you want: + - Most modules to support reporting but exclude specific ones + - To disable reporting for modules that don't produce meaningful report content + - Fine-grained control over the reporting experience + + +## Adjusting the Report Card + +### Using the `after` Function to Customize Module Report Cards + +The `after` function in `teal` provides a mechanism to customize and enhance the report cards generated by modules. This function allows you to inject additional content, modify existing content, or perform post-processing operations on report cards before they are finalized. + +#### Understanding the `after` Function + +The `after` function is typically used within module definitions to specify custom logic that should be executed after the module's standard report card is created. This enables you to: + +- Add custom text, plots, or tables to the report +- Modify the formatting or structure of the report card +- Include additional metadata or context +- Perform validation or quality checks on the report content + +#### Basic Usage Pattern + +```{r after_basic_usage} +# Example module with custom report card adjustment +app_after <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1") |> + after(server = function(input, output, session, data) { + teal_card(data()) <- teal_card(data(), "## Custom Analysis Summary", head(iris)) + return(data) + }) + ) +) +``` \ No newline at end of file From 70e31d73200ceb41e36fe79c226a0298933ee1fb Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:32:32 +0200 Subject: [PATCH 07/23] reorder content in getting started --- vignettes/getting-started-with-teal.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index a39b6443c2..722bc095b6 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -130,9 +130,9 @@ The `init` function includes a `reporter` parameter that controls the global rep The `reporter` parameter in `init` accepts three types of values: +* `parameter is omitted`: reporting is enabled by default globally. * `NULL`: reporting is disabled globally. * `teal.reporter::Report$new()`: predefined reporter object. -* `missing value`: reporting is enabled by default globally. For more details on reporting functionality and how to implement it in your modules, see: - [adding support for reporting](adding-support-for-reporting.html), From e99b6a87fbe2a44121ca4fa7a3812688e8cca096 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:42:27 +0200 Subject: [PATCH 08/23] cleanup adding-support-for-reporting vignette --- vignettes/adding-support-for-reporting.Rmd | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index 1fa5b222cd..212c7dbdca 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -16,12 +16,12 @@ The `teal` package offers an integrated reporting feature utilizing the `teal.re For a comprehensive explanation of the reporting functionality itself, please refer to the documentation therein. This article is intended for module developers and aims to provide guidance on enhancing a custom `teal` module with an automatic reporting feature. -This enhancement enables users to incorporate snapshots of the module outputs into a report which can then be reviewed in another module automatically provided by `teal`. +This enhancement enables users to incorporate snapshots of the module outputs into a report, which can be viewed in another module called `Reporter previewer` (automatically provided by `teal`). Thus the app user can interact with the report. The responsibilities of a module developer include: -- Adding support for reporting to their module, by returning a reactive `teal_data` object from the `server` function of the module. +- Adding support for reporting to their module, by returning a reactive `teal_data` object from the module's `server` function. - Specifying the outputs that constitute a snapshot of their module. The entire life cycle of objects involved in creating the report and configuring the module to preview the report is handled by `teal`. @@ -170,7 +170,8 @@ my_module_with_reporting <- function(label = "example teal module") { }) rdata <- reactive({ - teal_card(data()) <- teal_card(data(), "## Example heading", head(iris)) + obj <- data() + teal_card(obj) <- c(teal_card(obj), "## Example heading", head(iris)) }) return(rdata) }) @@ -200,7 +201,7 @@ if (interactive()) { ``` Now, an application user can see the text and `data.frame` added inside the `teal_card` in the `Report previewer` module. -You can also add other objects, like ggplot2, rtables, rlistings, etc. +You can also add other objects, like `ggplot2`, `rtables`, `rlistings`, etc. ```{r shinylive_iframe_4, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} code <- paste0(c( @@ -238,8 +239,8 @@ tm_simple_regression <- function(label = "Simple Regression") { report_data <- reactive({ obj <- data() - teal.reporter::teal_card(obj) <- - c(teal.reporter::teal_card(obj), "# Module's computation") + teal_card(obj) <- + c(teal_card(obj), "# Module's computation") eval_code( obj, sprintf( From 370b400611e05818136234209cc03cd1b722614e Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 14:57:50 +0200 Subject: [PATCH 09/23] add todo to managing-reproducible report documents --- ...-reproducible-report-documents-in-teal.rmd | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 45a2b141f5..ef4e449c97 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -34,6 +34,8 @@ app_default <- init( example_module("Analysis 2") ) ) +# Start app with +# if (interactive()) shinyApp(app$ui, app$server) ``` With default reporting enabled: @@ -54,6 +56,8 @@ app_no_reporting <- init( ), reporter = NULL ) +# Start app with +# if (interactive()) shinyApp(app_no_reporting$ui, app_no_reporting$server) ``` When `reporter = NULL`: @@ -68,7 +72,9 @@ For advanced use cases, you can provide a custom initial reporter object: library(teal.reporter) # Create a custom reporter with specific configuration -custom_reporter <- teal.reporter::Reporter$new() +custom_reporter <- Reporter$new() +custom_card <- teal_card("## Welome", "Welcome message", head(iris)) +custom_reporter$append_cards(list(WelcomeCard = custom_card)) # Use the custom reporter in your app app_custom <- init( @@ -77,8 +83,34 @@ app_custom <- init( example_module("Analysis 1"), example_module("Analysis 2") ), - reporter = custom_reporter + reporter = custom_reporter # TODO: doesn't work yet, app do not start with a predefined card ) +# Start app with +# if (interactive()) shinyApp(app_custom$ui, app_custom$server) +``` + +##### 4. Custom Reporter with a template + +Custom initial reporter can also include a template function that will be applied to every card: + +```{r custom_reporter_template} +library(teal.reporter) + +# Create a custom reporter with specific configuration +custom_reporter_template <- Reporter$new() +custom_reporter_template$set_template() # TODO: set the template function + +# Use the custom reporter in your app +app_custom <- init( + data = teal_data(IRIS = iris, MTCARS = mtcars), + modules = modules( + example_module("Analysis 1"), + example_module("Analysis 2") + ), + reporter = custom_reporter_template +) +# Start app with +# if (interactive()) shinyApp(custom_reporter_template$ui, custom_reporter_template$server) ``` #### Module-Level Reporting Control @@ -95,6 +127,8 @@ app_selective <- init( example_module("Analysis 3") # Reporting enabled ) ) +# Start app with +# if (interactive()) shinyApp(app_selective$ui, app_selective$server) ``` In this example: @@ -142,10 +176,16 @@ app_after <- init( data = teal_data(IRIS = iris, MTCARS = mtcars), modules = modules( example_module("Analysis 1") |> - after(server = function(input, output, session, data) { - teal_card(data()) <- teal_card(data(), "## Custom Analysis Summary", head(iris)) + after(server = function(input, output, session, data) { # TODO: after does not work this? + + rdata <- reactive({ + obj <- data() + teal_card(obj) <- c(teal_card(obj), "## Custom Analysis Summary", head(iris)) + }) return(data) }) ) ) -``` \ No newline at end of file +# Start app with +# if (interactive()) shinyApp(app_after$ui, app_after$server) +``` From c8b53a48000d6f056cdc1d1c25bac5d020519a30 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 16:22:25 +0200 Subject: [PATCH 10/23] fix after example --- .../managing-reproducible-report-documents-in-teal.rmd | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index ef4e449c97..29aba5d0b6 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -176,12 +176,8 @@ app_after <- init( data = teal_data(IRIS = iris, MTCARS = mtcars), modules = modules( example_module("Analysis 1") |> - after(server = function(input, output, session, data) { # TODO: after does not work this? - - rdata <- reactive({ - obj <- data() - teal_card(obj) <- c(teal_card(obj), "## Custom Analysis Summary", head(iris)) - }) + after(server = function(data) { + teal_card(data) <- c(teal_card(data), "## Custom Analysis Summary", head(iris)) return(data) }) ) From bf08341a4c7b71878e4414714fa4e2110d59282b Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 16:35:33 +0200 Subject: [PATCH 11/23] fix template example --- ...managing-reproducible-report-documents-in-teal.rmd | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 29aba5d0b6..120be230fc 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -98,7 +98,14 @@ library(teal.reporter) # Create a custom reporter with specific configuration custom_reporter_template <- Reporter$new() -custom_reporter_template$set_template() # TODO: set the template function +custom_reporter_template$set_template( + # Need to return named `teal_card` + function(card) { + tcard <- c("Templated information", card) + attributes(tcard) <- attributes(card) + tcard + } +) # Use the custom reporter in your app app_custom <- init( @@ -110,7 +117,7 @@ app_custom <- init( reporter = custom_reporter_template ) # Start app with -# if (interactive()) shinyApp(custom_reporter_template$ui, custom_reporter_template$server) +# if (interactive()) shinyApp(app_custom$ui, app_custom$server) ``` #### Module-Level Reporting Control From 54cc06b409530a6e8d0c592af77d3b19852a30ee Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 9 Jun 2025 16:42:08 +0200 Subject: [PATCH 12/23] add metadata title to the card --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 1 + 1 file changed, 1 insertion(+) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 120be230fc..e30b8b4d26 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -74,6 +74,7 @@ library(teal.reporter) # Create a custom reporter with specific configuration custom_reporter <- Reporter$new() custom_card <- teal_card("## Welome", "Welcome message", head(iris)) +metadata(custom_card, "title") <- "The title" custom_reporter$append_cards(list(WelcomeCard = custom_card)) # Use the custom reporter in your app From 9610897f0b66aa0c7d4411877b6744b0434d7276 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:49:21 +0200 Subject: [PATCH 13/23] Update vignettes/adding-support-for-reporting.Rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/adding-support-for-reporting.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index 212c7dbdca..ed984a50b7 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -95,7 +95,7 @@ knitr::include_url(url, height = "800px") ### Modify the body of the server function -To inform `teal` that the module requires reporting, return interactive `teal_data` from the `server` function. +To inform `teal` that the module requires reporting, return `reactive` containing `teal_report` from the `server` function. Outputs of the module will be included in the report when the module is called. See below: From 56dbc327107f615c5100475c086d9969cdd60b6d Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:49:51 +0200 Subject: [PATCH 14/23] Update vignettes/adding-support-for-reporting.Rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/adding-support-for-reporting.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index ed984a50b7..0614c16f9f 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -96,7 +96,7 @@ knitr::include_url(url, height = "800px") ### Modify the body of the server function To inform `teal` that the module requires reporting, return `reactive` containing `teal_report` from the `server` function. -Outputs of the module will be included in the report when the module is called. +Current outputs of the modules and a reproducible code will be included in the module when "add to report" button is clicked. See below: ```{r module_2} From 03544374321259cdf57729ea334dd1c760e6dac3 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:50:30 +0200 Subject: [PATCH 15/23] Update vignettes/getting-started-with-teal.Rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/getting-started-with-teal.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/getting-started-with-teal.Rmd b/vignettes/getting-started-with-teal.Rmd index 722bc095b6..96c8c73d6a 100644 --- a/vignettes/getting-started-with-teal.Rmd +++ b/vignettes/getting-started-with-teal.Rmd @@ -132,7 +132,7 @@ The `reporter` parameter in `init` accepts three types of values: * `parameter is omitted`: reporting is enabled by default globally. * `NULL`: reporting is disabled globally. -* `teal.reporter::Report$new()`: predefined reporter object. +* `teal.reporter::Report$new()`: predefined reporter object, possibly containing some initial cards. For more details on reporting functionality and how to implement it in your modules, see: - [adding support for reporting](adding-support-for-reporting.html), From 885a6c226b58cb6b6a1346aab801edcf54835000 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:51:08 +0200 Subject: [PATCH 16/23] Update vignettes/managing-reproducible-report-documents-in-teal.rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index e30b8b4d26..260826336b 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -10,7 +10,7 @@ vignette: > ## Introduction -`teal` provides comprehensive reporting capabilities that allow users to generate reproducible documents from their analysis modules. This vignette covers the key components for managing report documents in `teal` applications. +`teal` provides reporting capabilities that allow app users to compose reproducible documents from their analysis modules. This vignette covers the key components for managing report documents in `teal` applications. The reporting system offers three levels of control: From ecd8aec349e0c0b3e61e93b0e7fedc73baf5808b Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:51:45 +0200 Subject: [PATCH 17/23] Update vignettes/managing-reproducible-report-documents-in-teal.rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 260826336b..1a5b099c81 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -12,11 +12,10 @@ vignette: > `teal` provides reporting capabilities that allow app users to compose reproducible documents from their analysis modules. This vignette covers the key components for managing report documents in `teal` applications. -The reporting system offers three levels of control: +The reporting system offers two types of control: 1. **Global reporting control** via the `reporter` parameter in `init()` -2. **Module-level control** using `disable_report()` to exclude specific modules -3. **Report customization** with the `after` function to enhance report content +2. **Module-level control** via `after()` and `disable_report()` This vignette demonstrates how to use these features effectively to create flexible and customized reporting workflows. From ddfc2e4b12ce547279350b551131994610a3bbc3 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:20:35 +0200 Subject: [PATCH 18/23] Update vignettes/managing-reproducible-report-documents-in-teal.rmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 1a5b099c81..3258c334c5 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -19,7 +19,7 @@ The reporting system offers two types of control: This vignette demonstrates how to use these features effectively to create flexible and customized reporting workflows. -## Global and Local Reporting Control +## Global Reporting Control ##### 1. Default Reporting (parameter omitted) When you don't specify the `reporter` parameter, `teal` automatically enables default reporting functionality: From d0951f6efbd67af5886b38c7d912a856ea142ae1 Mon Sep 17 00:00:00 2001 From: m7pr Date: Tue, 10 Jun 2025 12:28:00 +0200 Subject: [PATCH 19/23] setnence about templated approach --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 3258c334c5..e5dfa1ab06 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -91,7 +91,8 @@ app_custom <- init( ##### 4. Custom Reporter with a template -Custom initial reporter can also include a template function that will be applied to every card: +Custom initial reporter can also include a template function that will be applied to every card. +With templated approach you can included disclaimers, data sources, data privacy information, etc. ```{r custom_reporter_template} library(teal.reporter) From 2cca04bca1ab9d0f40034ae193ed6b68ad2ac124 Mon Sep 17 00:00:00 2001 From: m7pr Date: Tue, 10 Jun 2025 14:02:49 +0200 Subject: [PATCH 20/23] simplify adding support for reporting vignette --- vignettes/adding-support-for-reporting.Rmd | 203 ++------------------- 1 file changed, 13 insertions(+), 190 deletions(-) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index 0614c16f9f..c754f2ef22 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -26,211 +26,34 @@ The responsibilities of a module developer include: The entire life cycle of objects involved in creating the report and configuring the module to preview the report is handled by `teal`. -## Custom module - -```{r setup, include=FALSE} -library(teal) -library(teal.reporter) -``` -```{r as_interactive, eval=FALSE, echo=FALSE} -interactive <- function() TRUE -``` - -Let us consider an example module, based on the example module from `teal`: -```{r module_1} -library(teal) -library(teal.reporter) - -my_module <- function(label = "example teal module") { - module( - label = label, - server = function(id, data) { - checkmate::assert_class(isolate(data()), "teal_data") - - moduleServer(id, function(input, output, session) { - updateSelectInput(session, "dataname", choices = isolate(names(data()))) - output$dataset <- renderPrint({ - req(input$dataname) - data()[[input$dataname]] - }) - }) - }, - ui = function(id) { - ns <- NS(id) - sidebarLayout( - sidebarPanel(selectInput(ns("dataname"), "Choose a dataset", choices = NULL)), - mainPanel(verbatimTextOutput(ns("dataset"))) - ) - } - ) -} -``` - -Using `teal`, you can launch this example module with the following: - -```{r app_1} -app <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = my_module() -) - -if (interactive()) { - shinyApp(app$ui, app$server) -} -``` - -```{r shinylive_iframe_1, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} -code <- paste0(c( - knitr::knit_code$get("as_interactive"), - knitr::knit_code$get("module_1"), - knitr::knit_code$get("app_1") -), collapse = "\n") - -url <- roxy.shinylive::create_shinylive_url(code) -knitr::include_url(url, height = "800px") -``` - - ## Add support for reporting -### Modify the body of the server function +To inform `teal` that the module requires reporting, return a `reactive` containing `teal_report` from the `server` function. +Current outputs of the modules and reproducible code will be included in the module when "add to report" button is clicked. -To inform `teal` that the module requires reporting, return `reactive` containing `teal_report` from the `server` function. -Current outputs of the modules and a reproducible code will be included in the module when "add to report" button is clicked. -See below: +Every input `teal_data` object in `teal` gets converted to a `teal_report` object, which you can then enhance with additional content. -```{r module_2} -my_module_with_reporting <- function(label = "example teal module") { - module( - label = label, - server = function(id, data) { - moduleServer(id, function(input, output, session) { - updateSelectInput(session, "dataname", choices = isolate(names(data()))) - output$dataset <- renderPrint({ - req(input$dataname) - data()[[input$dataname]] - }) - return(data) - }) - }, - ui = function(id) { - ns <- NS(id) - sidebarLayout( - sidebarPanel(selectInput(ns("dataname"), "Choose a dataset", choices = NULL)), - mainPanel(verbatimTextOutput(ns("dataset"))) - ) - } - ) -} -``` - -With these modifications, the module is now ready to be launched with `teal`: - -```{r app_2} -app <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = my_module_with_reporting() -) - -if (interactive()) { - shinyApp(app$ui, app$server) -} -``` - -```{r shinylive_iframe_2, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} -code <- paste0(c( - knitr::knit_code$get("as_interactive"), - knitr::knit_code$get("setup"), - knitr::knit_code$get("module_2"), - knitr::knit_code$get("app_2") -), collapse = "\n") - -url <- roxy.shinylive::create_shinylive_url(code) -knitr::include_url(url, height = "800px") -``` - -### Add content to the report card - -To add content to a report card, we will utilize the `teal_report` class and its convenience function `teal_card`. -You can read about it [here](https://insightsengineering.github.io/teal.reporter/latest-tag/articles/teal-report-class.html). - -Every input `teal_data` object in `teal` gets converted to a `teal_report` object. -This means that we can use the `teal_report` class to add content to the report card. - -```{r module_4} -my_module_with_reporting <- function(label = "example teal module") { - module( - label = label, - server = function(id, data, reporter) { - moduleServer(id, function(input, output, session) { - updateSelectInput(session, "dataname", choices = isolate(names(data()))) - output$dataset <- renderPrint({ - req(input$dataname) - data()[[input$dataname]] - }) - - rdata <- reactive({ - obj <- data() - teal_card(obj) <- c(teal_card(obj), "## Example heading", head(iris)) - }) - return(rdata) - }) - }, - ui = function(id) { - ns <- NS(id) - sidebarLayout( - sidebarPanel( - selectInput(ns("dataname"), "Choose a dataset", choices = NULL) - ), - mainPanel(verbatimTextOutput(ns("dataset"))) - ) - } - ) -} -``` - -```{r app_4} -app <- init( - data = teal_data(IRIS = iris, MTCARS = mtcars), - modules = my_module_with_reporting() -) - -if (interactive()) { - shinyApp(app$ui, app$server) -} -``` - -Now, an application user can see the text and `data.frame` added inside the `teal_card` in the `Report previewer` module. -You can also add other objects, like `ggplot2`, `rtables`, `rlistings`, etc. - -```{r shinylive_iframe_4, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} -code <- paste0(c( - knitr::knit_code$get("as_interactive"), - knitr::knit_code$get("setup"), - knitr::knit_code$get("module_4"), - knitr::knit_code$get("app_4") -), collapse = "\n") - -url <- roxy.shinylive::create_shinylive_url(code) -knitr::include_url(url, height = "800px") -``` +For detailed information about the `teal_report` class and its capabilities, see the [teal_report Class vignette](https://insightsengineering.github.io/teal.reporter/latest-tag/articles/teal-report-class.html). ## Example -In conclusion, we have demonstrated how to build a standard `teal` app with code reproducibility and reporter functionalities. +Below is an example demonstrating how to build a `teal` module with reporting functionality. + +The key aspects of this implementation are: -In the final example, we have incorporated `teal.code` snippets. -`teal.code` is an `R` library that offers utilities for storing code and associating it with an execution environment. -This allows `teal_report` to store the code necessary to generate the table along with the table itself. -To learn more about `teal.code` see the vignette _`qenv`_ in `teal.code`. +1. **Return a reactive `teal_report`**: The module's server function returns a reactive containing an enhanced `teal_report` object +2. **Add content with `teal_card()`**: Commentary and section headers are added using `teal_card()` +3. **Capture computations with `eval_code()`**: Code execution and results are captured for reproducibility ```{r app_5} +library(teal) +library(teal.reporter) + tm_simple_regression <- function(label = "Simple Regression") { module( label = label, server = function(input, output, session, data, reporter, ...) { - # Create the plot output$plot <- renderPlot({ req(input$x_var, input$y_var) dataset <- data()[["iris"]] From 958b486bb4e329014908e6f4ab72e992888341fb Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:02:07 +0200 Subject: [PATCH 21/23] Update vignettes/managing-reproducible-report-documents-in-teal.rmd Co-authored-by: Pawel Rucki <12943682+pawelru@users.noreply.github.com> Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index e5dfa1ab06..79c17fd5c5 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -72,7 +72,7 @@ library(teal.reporter) # Create a custom reporter with specific configuration custom_reporter <- Reporter$new() -custom_card <- teal_card("## Welome", "Welcome message", head(iris)) +custom_card <- teal_card("## Welcome", "Welcome message", head(iris)) metadata(custom_card, "title") <- "The title" custom_reporter$append_cards(list(WelcomeCard = custom_card)) From 4b314da96ec609b8bed0e20750f7fabd99ea7543 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Wed, 11 Jun 2025 09:02:19 +0200 Subject: [PATCH 22/23] Update vignettes/managing-reproducible-report-documents-in-teal.rmd Co-authored-by: Pawel Rucki <12943682+pawelru@users.noreply.github.com> Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- vignettes/managing-reproducible-report-documents-in-teal.rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/managing-reproducible-report-documents-in-teal.rmd b/vignettes/managing-reproducible-report-documents-in-teal.rmd index 79c17fd5c5..075f33a241 100644 --- a/vignettes/managing-reproducible-report-documents-in-teal.rmd +++ b/vignettes/managing-reproducible-report-documents-in-teal.rmd @@ -92,7 +92,7 @@ app_custom <- init( ##### 4. Custom Reporter with a template Custom initial reporter can also include a template function that will be applied to every card. -With templated approach you can included disclaimers, data sources, data privacy information, etc. +With the templated approach, you can included disclaimers, data sources, data privacy information, etc. ```{r custom_reporter_template} library(teal.reporter) From 548bb23d74a2b917e67cdacb8fd835ac821de99c Mon Sep 17 00:00:00 2001 From: m7pr Date: Fri, 13 Jun 2025 10:55:57 +0200 Subject: [PATCH 23/23] move reporting section to teal::example_module --- R/dummy_functions.R | 10 ++++++++++ man/example_module.Rd | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/R/dummy_functions.R b/R/dummy_functions.R index becb2706de..872786d9df 100644 --- a/R/dummy_functions.R +++ b/R/dummy_functions.R @@ -11,6 +11,16 @@ #' @inheritParams teal_modules #' @param decorators `r lifecycle::badge("experimental")` (`list` of `teal_transform_module`) optional, #' decorator for `object` included in the module. +#' +#' @section Reporting: +#' +#' This module returns an object of class `teal_module`, that contains a `server` function. +#' Since the server function returns a `teal_report` object, this makes this module reportable, which means that +#' the reporting functionality will be turned on automatically by the `teal` framework. +#' +#' For more information on reporting in `teal`, see the vignettes: +#' - `vignette("managing-reproducible-report-documents-in-teal", package = "teal")` +#' - `vignette("adding-support-for-reporting-to-custom-modules", package = "teal")` #' #' @return A `teal` module which can be included in the `modules` argument to [init()]. #' diff --git a/man/example_module.Rd b/man/example_module.Rd index 7e5251a87a..797d3bf60a 100644 --- a/man/example_module.Rd +++ b/man/example_module.Rd @@ -43,6 +43,20 @@ The object can be anything that can be handled by \code{renderPrint()}. See the \code{vignette("transform-module-output", package = "teal")} or \code{\link{teal_transform_module}} to read more about decorators. } +\section{Reporting}{ + + +This module returns an object of class \code{teal_module}, that contains a \code{server} function. +Since the server function returns a \code{teal_report} object, this makes this module reportable, which means that +the reporting functionality will be turned on automatically by the \code{teal} framework. + +For more information on reporting in \code{teal}, see the vignettes: +\itemize{ +\item \code{vignette("managing-reproducible-report-documents-in-teal", package = "teal")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} +} + \examples{ app <- init( data = teal_data(IRIS = iris, MTCARS = mtcars), @@ -56,8 +70,8 @@ if (interactive()) { \describe{ \item{example-1}{ \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIFpUcxUNql2A6dIAmUUlGkBeaV2oB9Z6-YASSxAgGUPaVpGWgBnXGkAWV0AYQBBLHDPGFICFhieXHtpGCJHFWo4GIi4AA9YVAqfErKK7QF+QSVpdiFyUXEpbR0QIpiACyFWVPR2cwASFVp4+ZiRKUYOgF8wTYBdIA}{Open in Shinylive} - \if{html}{\out{}} - \if{html}{\out{}} + \if{html}{\out{}} + \if{html}{\out{}} } } }