diff --git a/.lintr b/.lintr index 113ca30c1..87688e231 100644 --- a/.lintr +++ b/.lintr @@ -1,6 +1,5 @@ linters: linters_with_defaults( line_length_linter = line_length_linter(120), - cyclocomp_linter = NULL, object_usage_linter = NULL, object_name_linter = object_name_linter(styles = c("snake_case", "symbols"), regexes = c(ANL = "^ANL_?[0-9A-Z_]*$", ADaM = "^r?AD[A-Z]{2,3}_?[0-9]*$")), indentation_linter = NULL diff --git a/DESCRIPTION b/DESCRIPTION index 28bcccd67..d08f98f88 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -85,10 +85,10 @@ VignetteBuilder: rmarkdown Remotes: insightsengineering/teal.logger@main, - insightsengineering/teal.reporter@main, + insightsengineering/teal.reporter@teal_reportable, insightsengineering/teal.transform@main, insightsengineering/teal.widgets@main, - insightsengineering/teal@main + insightsengineering/teal@teal_reportable, Config/Needs/verdepcheck: haleyjeppson/ggmosaic, tidyverse/ggplot2, rstudio/shiny, insightsengineering/teal, insightsengineering/teal.slice, insightsengineering/teal.transform, diff --git a/R/tm_a_pca.R b/R/tm_a_pca.R index 8e4111cb5..0a52134f6 100644 --- a/R/tm_a_pca.R +++ b/R/tm_a_pca.R @@ -47,6 +47,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -235,9 +237,6 @@ ui_a_pca <- function(id, ...) { uiOutput(ns("all_plots")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args["dat"]), teal.transform::data_extract_ui( @@ -353,9 +352,7 @@ ui_a_pca <- function(id, ...) { } # Server function for the PCA module -srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") +srv_a_pca <- function(id, data, dat, plot_height, plot_width, ggplot2_args, decorators) { checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -436,9 +433,16 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl selector_list = selector_list, datasets = data ) - qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr");library("tidyr")') # nolint quotes - ) + qenv <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Principal Component Analysis"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr");library("tidyr")') # nolint: quotes. + }) anl_merged_q <- reactive({ req(anl_merged_input()) qenv() %>% @@ -514,6 +518,8 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl ) ) + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Principal Components Table") + qenv <- teal.code::eval_code( qenv, quote({ @@ -522,6 +528,8 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl }) ) + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Eigenvectors Table") + teal.code::eval_code( qenv, quote({ @@ -602,7 +610,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl ), ggtheme = ggtheme ) - + teal.reporter::teal_card(base_q) <- c(teal.reporter::teal_card(base_q), "## Elbow plot") teal.code::eval_code( base_q, substitute( @@ -679,6 +687,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl ggtheme = ggtheme ) + teal.reporter::teal_card(base_q) <- c(teal.reporter::teal_card(base_q), "## Circle plot") teal.code::eval_code( base_q, substitute( @@ -737,6 +746,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl size <- input$size font_size <- input$font_size + teal.reporter::teal_card(base_q) <- c(teal.reporter::teal_card(base_q), "## Biplot") qenv <- teal.code::eval_code( qenv, substitute( @@ -997,6 +1007,7 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl parsed_ggplot2_args$theme ) + teal.reporter::teal_card(base_q) <- c(teal.reporter::teal_card(base_q), "## Eigenvector plot") teal.code::eval_code( base_q, substitute( @@ -1038,9 +1049,8 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl data = q, decorators = select_decorators(decorators, obj_name), expr = reactive({ - substitute(print(.plot), env = list(.plot = as.name(obj_name))) - }), - expr_is_reactive = TRUE + substitute(.plot, env = list(.plot = as.name(obj_name))) + }) ) }, names(output_q), @@ -1132,31 +1142,6 @@ srv_a_pca <- function(id, data, reporter, filter_panel_api, dat, plot_height, pl verbatim_content = source_code_r, title = "R Code for PCA" ) - - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Principal Component Analysis Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Principal Components Table", "header3") - card$append_table(computation()[["tbl_importance"]]) - card$append_text("Eigenvectors Table", "header3") - card$append_table(computation()[["tbl_eigenvector"]]) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + decorated_output_q }) } diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 1c9347523..bcd03a582 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -67,6 +67,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -285,9 +287,6 @@ ui_a_regression <- function(id, ...) { tags$div(verbatimTextOutput(ns("text"))) )), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), tags$br(), teal.transform::datanames_input(args[c("response", "regressor")]), teal.transform::data_extract_ui( @@ -386,8 +385,6 @@ ui_a_regression <- function(id, ...) { # Server function for the regression module srv_a_regression <- function(id, data, - reporter, - filter_panel_api, response, regressor, plot_height, @@ -395,8 +392,6 @@ srv_a_regression <- function(id, ggplot2_args, default_outlier_label, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -462,9 +457,16 @@ srv_a_regression <- function(id, ) }) - qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes - ) + qenv <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Linear Regression Plot"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes. + }) anl_merged_q <- reactive({ req(anl_merged_input()) @@ -526,7 +528,7 @@ srv_a_regression <- function(id, ) } - anl_merged_q() %>% + anl_fit <- anl_merged_q() %>% teal.code::eval_code(substitute(fit <- stats::lm(form, data = ANL), env = list(form = form))) %>% teal.code::eval_code(quote({ for (regressor in names(fit$contrasts)) { @@ -536,7 +538,12 @@ srv_a_regression <- function(id, ) } })) %>% - teal.code::eval_code(quote(summary(fit))) + teal.code::eval_code(quote({ + fit_summary <- summary(fit) + fit_summary + })) + teal.reporter::teal_card(anl_fit) <- c(teal.reporter::teal_card(anl_fit), "## Plot") + anl_fit }) label_col <- reactive({ @@ -982,7 +989,7 @@ srv_a_regression <- function(id, output_q <- reactive({ teal::validate_inputs(iv_r()) - switch(input$plot_type, + obj <- switch(input$plot_type, "Response vs Regressor" = output_plot_0(), "Residuals vs Fitted" = output_plot_1(), "Normal Q-Q" = output_plot_2(), @@ -991,21 +998,22 @@ srv_a_regression <- function(id, "Residuals vs Leverage" = output_plot_5(), "Cook's dist vs Leverage" = output_plot_6() ) + obj }) decorated_output_q <- srv_decorate_teal_data( "decorator", data = output_q, decorators = select_decorators(decorators, "plot"), - expr = plot + expr = quote(plot) ) fitted <- reactive({ - req(output_q()) + req(decorated_output_q()) decorated_output_q()[["fit"]] }) plot_r <- reactive({ - req(output_q()) + req(decorated_output_q()) decorated_output_q()[["plot"]] }) @@ -1032,26 +1040,6 @@ srv_a_regression <- function(id, title = "R code for the regression plot", ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Linear Regression Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + decorated_output_q }) } diff --git a/R/tm_data_table.R b/R/tm_data_table.R index 603f41c3f..7f1fb7068 100644 --- a/R/tm_data_table.R +++ b/R/tm_data_table.R @@ -310,7 +310,7 @@ srv_data_table <- function(id, teal::validate_has_data(df, min_nrow = 1L, msg = paste("data", dataname, "is empty")) qenv <- teal.code::eval_code( data(), - 'library("dplyr");library("DT")' # nolint quotes + 'library("dplyr");library("DT")' # nolint: quotes. ) teal.code::eval_code( qenv, diff --git a/R/tm_g_association.R b/R/tm_g_association.R index f64e9adb4..f8d16112b 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -48,6 +48,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -232,9 +234,6 @@ ui_tm_g_association <- function(id, ...) { teal.widgets::plot_with_settings_ui(id = ns("myplot")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("ref", "vars")]), teal.transform::data_extract_ui( @@ -301,16 +300,12 @@ ui_tm_g_association <- function(id, ...) { # Server function for the association module srv_tm_g_association <- function(id, data, - reporter, - filter_panel_api, ref, vars, plot_height, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") @@ -346,9 +341,16 @@ srv_tm_g_association <- function(id, selector_list = selector_list ) - qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr");library("tern");library("ggmosaic")') # nolint quotes - ) + qenv <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Association Plot"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr");library("ggmosaic")') # nolint: quotes. + }) anl_merged_q <- reactive({ req(anl_merged_input()) qenv() %>% teal.code::eval_code(as.expression(anl_merged_input()$expr)) @@ -495,8 +497,10 @@ srv_tm_g_association <- function(id, ) ) } + obj <- merged$anl_q_r() + teal.reporter::teal_card(obj) <- c(teal.reporter::teal_card(obj), "## Plot") teal.code::eval_code( - merged$anl_q_r(), + obj, substitute( expr = title <- new_title, env = list(new_title = new_title) @@ -506,9 +510,7 @@ srv_tm_g_association <- function(id, substitute( expr = { plots <- plot_calls - plot_top <- plots[[1]] - plot_bottom <- plots[[2]] - plot <- tern::stack_grobs(grobs = lapply(list(plot_top, plot_bottom), ggplot2::ggplotGrob)) + plot <- gridExtra::arrangeGrob(plots[[1]], plots[[2]], ncol = 1) }, env = list( plot_calls = do.call( @@ -525,10 +527,7 @@ srv_tm_g_association <- function(id, id = "decorator", data = output_q, decorators = select_decorators(decorators, "plot"), - expr = { - grid::grid.newpage() - grid::grid.draw(plot) - } + expr = quote(plot) ) plot_r <- reactive({ @@ -554,26 +553,6 @@ srv_tm_g_association <- function(id, title = "Association Plot" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Association Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + decorated_output_grob_q }) } diff --git a/R/tm_g_bivariate.R b/R/tm_g_bivariate.R index bf43cc86e..109b7382f 100644 --- a/R/tm_g_bivariate.R +++ b/R/tm_g_bivariate.R @@ -70,6 +70,7 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting #' #' @examplesShinylive #' library(teal.modules.general) @@ -339,9 +340,6 @@ ui_g_bivariate <- function(id, ...) { tags$div(teal.widgets::plot_with_settings_ui(id = ns("myplot"))) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("x", "y", "row_facet", "col_facet", "color", "fill", "size")]), teal.transform::data_extract_ui( @@ -479,8 +477,6 @@ ui_g_bivariate <- function(id, ...) { # Server function for the bivariate module srv_g_bivariate <- function(id, data, - reporter, - filter_panel_api, x, y, row_facet, @@ -493,8 +489,6 @@ srv_g_bivariate <- function(id, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -559,14 +553,22 @@ srv_g_bivariate <- function(id, selector_list = selector_list, datasets = data ) - qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr");library("teal.modules.general")') # nolint quotes - ) anl_merged_q <- reactive({ - req(anl_merged_input()) - qenv() %>% - teal.code::eval_code(as.expression(anl_merged_input()$expr)) + obj <- data() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Bivariate Plot"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + obj %>% + teal.code::eval_code( + c( + expression(library(ggplot2), library(dplyr)), + as.expression(anl_merged_input()$expr) + ) + ) }) merged <- list( @@ -692,7 +694,9 @@ srv_g_bivariate <- function(id, } } - teal.code::eval_code(merged$anl_q_r(), substitute(expr = plot <- cl, env = list(cl = cl))) + obj <- merged$anl_q_r() + teal.reporter::teal_card(obj) <- c(teal.reporter::teal_card(obj), "## Plot") + teal.code::eval_code(obj, substitute(expr = plot <- cl, env = list(cl = cl))) }) decorated_output_q_facets <- srv_decorate_teal_data( @@ -730,8 +734,7 @@ srv_g_bivariate <- function(id, ) } print_call - }), - expr_is_reactive = TRUE + }) ) plot_r <- reactive(req(decorated_output_q_facets())[["plot"]]) @@ -753,27 +756,9 @@ srv_g_bivariate <- function(id, title = "Bivariate Plot" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Bivariate Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + + decorated_output_q_facets }) } diff --git a/R/tm_g_distribution.R b/R/tm_g_distribution.R index 46d77137b..437a81b67 100644 --- a/R/tm_g_distribution.R +++ b/R/tm_g_distribution.R @@ -56,6 +56,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -258,9 +260,6 @@ ui_distribution <- function(id, ...) { ) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("dist_var", "strata_var")]), teal.transform::data_extract_ui( @@ -402,8 +401,6 @@ ui_distribution <- function(id, ...) { # Server function for the distribution module srv_distribution <- function(id, data, - reporter, - filter_panel_api, dist_var, strata_var, group_var, @@ -411,8 +408,6 @@ srv_distribution <- function(id, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -542,7 +537,7 @@ srv_distribution <- function(id, ) qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes + teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint: quotes. ) anl_merged_q <- reactive({ @@ -640,7 +635,15 @@ srv_distribution <- function(id, common_q <- reactive({ # Create a private stack for this function only. - ANL <- merged$anl_q_r()[["ANL"]] + obj <- merged$anl_q_r() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Distribution Plot"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + + ANL <- obj[["ANL"]] dist_var <- merge_vars()$dist_var s_var <- merge_vars()$s_var g_var <- merge_vars()$g_var @@ -655,7 +658,7 @@ srv_distribution <- function(id, # isolated as dist_param1/dist_param2 already triggered the reactivity t_dist <- isolate(input$t_dist) - qenv <- merged$anl_q_r() + qenv <- obj if (length(g_var) > 0) { validate( @@ -664,7 +667,7 @@ srv_distribution <- function(id, "Group by variable must be `factor`, `character`, or `integer`" ) ) - qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -682,7 +685,7 @@ srv_distribution <- function(id, ) ) - qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -892,7 +895,7 @@ srv_distribution <- function(id, } if (length(t_dist) != 0 && main_type_var == "Density" && length(g_var) == 0 && length(s_var) == 0) { - qenv <- teal.code::eval_code(qenv, 'library("ggpp")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("ggpp")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -954,6 +957,7 @@ srv_distribution <- function(id, ggtheme = ggtheme ) + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Histogram Plot") teal.code::eval_code( qenv, substitute( @@ -1037,7 +1041,7 @@ srv_distribution <- function(id, ) if (length(t_dist) != 0 && length(g_var) == 0 && length(s_var) == 0) { - qenv <- teal.code::eval_code(qenv, 'library("ggpp")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("ggpp")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -1084,6 +1088,7 @@ srv_distribution <- function(id, ggtheme = ggtheme ) + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## QQ Plot") teal.code::eval_code( qenv, substitute( @@ -1232,7 +1237,7 @@ srv_distribution <- function(id, qenv <- common_q() if (length(s_var) == 0 && length(g_var) == 0) { - qenv <- teal.code::eval_code(qenv, 'library("generics")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("generics")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -1246,7 +1251,7 @@ srv_distribution <- function(id, ) ) } else { - qenv <- teal.code::eval_code(qenv, 'library("tidyr")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("tidyr")') # nolint: quotes. qenv <- teal.code::eval_code( qenv, substitute( @@ -1297,28 +1302,28 @@ srv_distribution <- function(id, "d_density", data = output_dist_q, decorators = select_decorators(decorators, "histogram_plot"), - expr = print(histogram_plot) + expr = quote(histogram_plot) ) decorated_output_qq_q <- srv_decorate_teal_data( "d_qq", data = output_qq_q, decorators = select_decorators(decorators, "qq_plot"), - expr = print(qq_plot) + expr = quote(qq_plot) ) decorated_output_summary_q <- srv_decorate_teal_data( "d_summary", data = output_summary_q, decorators = select_decorators(decorators, "summary_table"), - expr = summary_table + expr = quote(summary_table) ) decorated_output_test_q <- srv_decorate_teal_data( "d_test", data = output_test_q, decorators = select_decorators(decorators, "test_table"), - expr = test_table + expr = quote(test_table) ) decorated_output_q <- reactive({ @@ -1384,38 +1389,13 @@ srv_distribution <- function(id, title = "R Code for distribution" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Distribution Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - if (input$tabs == "Histogram") { - card$append_plot(dist_r(), dim = pws1$dim()) - } else if (input$tabs == "QQplot") { - card$append_plot(qq_r(), dim = pws2$dim()) - } - card$append_text("Statistics table", "header3") - card$append_table(decorated_output_summary_q()[["summary_table"]]) - tests_error <- tryCatch(expr = tests_r(), error = function(e) "error") - if (inherits(tests_error, "data.frame")) { - card$append_text("Tests table", "header3") - card$append_table(tests_r()) - } - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card + reactive( + if (input$tabs == "Histogram") { + decorated_output_dist_q() + } else if (input$tabs == "QQplot") { + decorated_output_qq_q() } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + ) }) } diff --git a/R/tm_g_response.R b/R/tm_g_response.R index a2b62aecb..c760e6bae 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -63,6 +63,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -263,9 +265,6 @@ ui_g_response <- function(id, ...) { teal.widgets::plot_with_settings_ui(id = ns("myplot")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("response", "x", "row_facet", "col_facet")]), teal.transform::data_extract_ui( @@ -332,8 +331,6 @@ ui_g_response <- function(id, ...) { # Server function for the response module srv_g_response <- function(id, data, - reporter, - filter_panel_api, response, x, row_facet, @@ -342,8 +339,6 @@ srv_g_response <- function(id, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -395,7 +390,7 @@ srv_g_response <- function(id, ) qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes + teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint: quotes. ) anl_merged_q <- reactive({ @@ -413,6 +408,12 @@ srv_g_response <- function(id, teal::validate_inputs(iv_r()) qenv <- merged$anl_q_r() + teal.reporter::teal_card(qenv) <- + c( + teal.reporter::teal_card("# Response Plot"), + teal.reporter::teal_card(qenv), + teal.reporter::teal_card("## Module's code") + ) ANL <- qenv[["ANL"]] resp_var <- as.vector(merged$anl_input_r()$columns_source$response) x <- as.vector(merged$anl_input_r()$columns_source$x) @@ -572,6 +573,7 @@ srv_g_response <- function(id, ggthemes = parsed_ggplot2_args$ggtheme )) + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Plot") teal.code::eval_code(qenv, plot_call) }) @@ -579,7 +581,7 @@ srv_g_response <- function(id, id = "decorator", data = output_q, decorators = select_decorators(decorators, "plot"), - expr = plot + expr = quote(plot) ) plot_r <- reactive(req(decorated_output_plot_q())[["plot"]]) @@ -601,26 +603,8 @@ srv_g_response <- function(id, title = "Show R Code for Response" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Response Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + + decorated_output_plot_q }) } diff --git a/R/tm_g_scatterplot.R b/R/tm_g_scatterplot.R index 0c108a350..a74e953e5 100644 --- a/R/tm_g_scatterplot.R +++ b/R/tm_g_scatterplot.R @@ -54,6 +54,7 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting #' #' @examplesShinylive #' library(teal.modules.general) @@ -371,9 +372,6 @@ ui_g_scatterplot <- function(id, ...) { DT::dataTableOutput(ns("data_table"), width = "100%") ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("x", "y", "color_by", "size_by", "row_facet", "col_facet")]), teal.transform::data_extract_ui( @@ -509,8 +507,6 @@ ui_g_scatterplot <- function(id, ...) { # Server function for the scatterplot module srv_g_scatterplot <- function(id, data, - reporter, - filter_panel_api, x, y, color_by, @@ -522,8 +518,6 @@ srv_g_scatterplot <- function(id, table_dec, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -590,9 +584,15 @@ srv_g_scatterplot <- function(id, datasets = data, merge_function = "dplyr::inner_join" ) - qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes - ) + qenv <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- c( + teal.reporter::teal_card("# Scatter Plot"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes. + }) anl_merged_q <- reactive({ req(anl_merged_input()) @@ -1016,6 +1016,7 @@ srv_g_scatterplot <- function(id, plot_call <- substitute(expr = plot <- plot_call, env = list(plot_call = plot_call)) + teal.reporter::teal_card(plot_q) <- c(teal.reporter::teal_card(plot_q), "## Plot") teal.code::eval_code(plot_q, plot_call) }) @@ -1023,7 +1024,7 @@ srv_g_scatterplot <- function(id, id = "decorator", data = output_q, decorators = select_decorators(decorators, "plot"), - expr = print(plot) + expr = quote(plot) ) plot_r <- reactive(req(decorated_output_plot_q())[["plot"]]) @@ -1074,26 +1075,8 @@ srv_g_scatterplot <- function(id, title = "R Code for scatterplot" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Scatter Plot", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + + decorated_output_plot_q }) } diff --git a/R/tm_g_scatterplotmatrix.R b/R/tm_g_scatterplotmatrix.R index 673c850a6..c3cae54b1 100644 --- a/R/tm_g_scatterplotmatrix.R +++ b/R/tm_g_scatterplotmatrix.R @@ -42,6 +42,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -251,9 +253,6 @@ ui_g_scatterplotmatrix <- function(id, ...) { teal.widgets::plot_with_settings_ui(id = ns("myplot")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args$variables), teal.transform::data_extract_ui( @@ -300,14 +299,10 @@ ui_g_scatterplotmatrix <- function(id, ...) { # Server function for the scatterplot matrix module srv_g_scatterplotmatrix <- function(id, data, - reporter, - filter_panel_api, variables, plot_height, plot_width, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -333,7 +328,13 @@ srv_g_scatterplotmatrix <- function(id, anl_merged_q <- reactive({ req(anl_merged_input()) - qenv <- teal.code::eval_code(data(), 'library("dplyr");library("lattice")') # nolint quotes + obj <- data() + teal.reporter::teal_card(obj) <- c( + teal.reporter::teal_card("# Scatter Plot Matrix"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + qenv <- teal.code::eval_code(obj, 'library("dplyr");library("lattice")') # nolint: quotes. teal.code::eval_code(qenv, as.expression(anl_merged_input()$expr)) }) @@ -370,7 +371,7 @@ srv_g_scatterplotmatrix <- function(id, # check character columns. If any, then those are converted to factors check_char <- vapply(ANL[, cols_names], is.character, logical(1)) - qenv <- teal.code::eval_code(qenv, 'library("dplyr")') # nolint quotes + qenv <- teal.code::eval_code(qenv, 'library("dplyr")') # nolint: quotes. if (any(check_char)) { qenv <- teal.code::eval_code( qenv, @@ -394,6 +395,8 @@ srv_g_scatterplotmatrix <- function(id, # create plot + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Plot") + if (add_cor) { shinyjs::show("cor_method") shinyjs::show("cor_use") @@ -464,7 +467,7 @@ srv_g_scatterplotmatrix <- function(id, id = "decorator", data = output_q, decorators = select_decorators(decorators, "plot"), - expr = plot + expr = quote(plot) ) plot_r <- reactive(req(decorated_output_q())[["plot"]]) @@ -508,27 +511,8 @@ srv_g_scatterplotmatrix <- function(id, title = "Show R Code for Scatterplotmatrix" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Scatter Plot Matrix", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Plot", "header3") - card$append_plot(plot_r(), dim = pws$dim()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + decorated_output_q }) } diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 0e1cd859e..7ca520475 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -20,7 +20,7 @@ #' @section Decorating Module: #' #' This module generates the following objects, which can be modified in place using decorators: -#' - `summary_plot` (`grob` created with [ggplot2::ggplotGrob()]) +#' - `summary_plot` (`ggplot`) #' - `combination_plot` (`grob` created with [ggplot2::ggplotGrob()]) #' - `by_subject_plot` (`ggplot`) #' - `table` (`datatables` created with [DT::datatable()]) @@ -47,6 +47,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -199,10 +201,9 @@ ui_page_missing_data <- function(id, pre_output = NULL, post_output = NULL) { } # Server function for the missing data module (all datasets) -srv_page_missing_data <- function(id, data, reporter, filter_panel_api, datanames, parent_dataname, +srv_page_missing_data <- function(id, data, reporter, datanames, parent_dataname, plot_height, plot_width, ggplot2_args, ggtheme, decorators) { with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") moduleServer(id, function(input, output, session) { teal.logger::log_shiny_input_changes(input, namespace = "teal.modules.general") @@ -265,14 +266,13 @@ srv_page_missing_data <- function(id, data, reporter, filter_panel_api, dataname }) }) - lapply( + result <- sapply( datanames, function(x) { srv_missing_data( id = x, data = data, reporter = if (with_reporter) reporter, - filter_panel_api = if (with_filter) filter_panel_api, dataname = x, parent_dataname = parent_dataname, plot_height = plot_height, @@ -280,8 +280,18 @@ srv_page_missing_data <- function(id, data, reporter, filter_panel_api, dataname ggplot2_args = ggplot2_args, decorators = decorators ) - } + }, + USE.NAMES = TRUE, + simplify = FALSE ) + + reactive({ + if (is.null(input$dataname_tab)) { + teal.data::teal_data() + } else { + result[[input$dataname_tab]]() + } + }) }) } @@ -360,9 +370,6 @@ encoding_missing_data <- function(id, summary_per_patient = FALSE, ggtheme, data ns <- NS(id) tagList( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), helpText( paste0("Dataset", `if`(length(datanames) > 1, "s", ""), ":"), @@ -451,7 +458,6 @@ encoding_missing_data <- function(id, summary_per_patient = FALSE, ggtheme, data srv_missing_data <- function(id, data, reporter, - filter_panel_api, dataname, parent_dataname, plot_height, @@ -459,7 +465,6 @@ srv_missing_data <- function(id, ggplot2_args, decorators) { with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -521,8 +526,15 @@ srv_missing_data <- function(id, group_var <- input$group_by_var anl <- data_r() - qenv <- teal.code::eval_code(data(), { - 'library("dplyr");library("ggplot2");library("tidyr");library("gridExtra")' # nolint quotes + obj <- data() + teal.reporter::teal_card(obj) <- c( + teal.reporter::teal_card("# Missing Data"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + + qenv <- teal.code::eval_code(obj, { + 'library("dplyr");library("ggplot2");library("tidyr");library("gridExtra")' # nolint: quotes. }) qenv <- if (!is.null(selected_vars()) && length(selected_vars()) != ncol(anl)) { @@ -687,8 +699,10 @@ srv_missing_data <- function(id, combination_cutoff_q <- reactive({ req(common_code_q()) + qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Combination Plot") teal.code::eval_code( - common_code_q(), + qenv, quote( combination_cutoff <- ANL %>% dplyr::mutate_all(is.na) %>% @@ -743,22 +757,26 @@ srv_missing_data <- function(id, expr = analysis_vars <- setdiff(colnames(ANL), data_keys), env = list(data_keys = data_keys()) ) + ) + + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Summary Plot") + + qenv <- teal.code::eval_code( + qenv, + substitute( + expr = summary_plot_obs <- data_frame_call[, analysis_vars] %>% + dplyr::summarise_all(list(function(x) sum(is.na(x)))) %>% + tidyr::pivot_longer(dplyr::everything(), names_to = "col", values_to = "n_na") %>% + dplyr::mutate(n_not_na = nrow(ANL) - n_na) %>% + tidyr::pivot_longer(-col, names_to = "isna", values_to = "n") %>% + dplyr::mutate(isna = isna == "n_na", n_pct = n / nrow(ANL) * 100), + env = list(data_frame_call = if (!inherits(data_r(), "tbl_df")) { + quote(tibble::as_tibble(ANL)) + } else { + quote(ANL) + }) + ) ) %>% - teal.code::eval_code( - substitute( - expr = summary_plot_obs <- data_frame_call[, analysis_vars] %>% - dplyr::summarise_all(list(function(x) sum(is.na(x)))) %>% - tidyr::pivot_longer(dplyr::everything(), names_to = "col", values_to = "n_na") %>% - dplyr::mutate(n_not_na = nrow(ANL) - n_na) %>% - tidyr::pivot_longer(-col, names_to = "isna", values_to = "n") %>% - dplyr::mutate(isna = isna == "n_na", n_pct = n / nrow(ANL) * 100), - env = list(data_frame_call = if (!inherits(data_r(), "tbl_df")) { - quote(tibble::as_tibble(ANL)) - } else { - quote(ANL) - }) - ) - ) %>% # x axis ordering according to number of missing values and alphabet teal.code::eval_code( quote( @@ -916,15 +934,11 @@ srv_missing_data <- function(id, if (isTRUE(input$if_patients_plot)) { within(qenv, { - g1 <- ggplot2::ggplotGrob(summary_plot_top) - g2 <- ggplot2::ggplotGrob(summary_plot_bottom) - summary_plot <- gridExtra::gtable_cbind(g1, g2, size = "first") - summary_plot$heights <- grid::unit.pmax(g1$heights, g2$heights) + summary_plot <- gridExtra::grid.arrange(summary_plot_top, summary_plot_bottom, ncol = 2) }) } else { within(qenv, { - g1 <- ggplot2::ggplotGrob(summary_plot_top) - summary_plot <- g1 + summary_plot <- summary_plot_top }) } }) @@ -1100,10 +1114,13 @@ srv_missing_data <- function(id, function(x) round(sum(is.na(x)) / length(x), 4) } + qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Summary Table") + qenv <- if (!is.null(group_var)) { common_code_libraries_q <- teal.code::eval_code( - common_code_q(), - 'library("forcats");library("glue");' # nolint quotes + qenv, + 'library("forcats");library("glue");' # nolint: quotes. ) teal.code::eval_code( common_code_libraries_q, @@ -1129,7 +1146,7 @@ srv_missing_data <- function(id, ) } else { teal.code::eval_code( - common_code_q(), + qenv, substitute( expr = summary_data <- ANL %>% dplyr::summarise_all(summ_fn) %>% @@ -1143,7 +1160,7 @@ srv_missing_data <- function(id, ) } - within(qenv, table <- DT::datatable(summary_data)) + within(qenv, table <- summary_data) }) by_subject_plot_q <- reactive({ @@ -1175,8 +1192,11 @@ srv_missing_data <- function(id, function(x) paste(as.integer(x), collapse = "") } - teal.code::eval_code( - common_code_q(), + qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## By Subject Plot") + + qenv <- teal.code::eval_code( + qenv, substitute( expr = parent_keys <- keys, env = list(keys = data_parent_keys()) @@ -1227,39 +1247,41 @@ srv_missing_data <- function(id, }, env = list(hashing_function = hashing_function) ) - ) %>% - teal.code::eval_code( - substitute( - expr = { - by_subject_plot <- ggplot2::ggplot(summary_plot_patients, ggplot2::aes( - x = factor(id, levels = order_subjects), - y = factor(col, levels = ordered_columns[["column"]]), - fill = isna - )) + - ggplot2::geom_raster() + - ggplot2::annotate( - "text", - x = length(order_subjects), - y = seq_len(nrow(ordered_columns)), - hjust = 1, - label = sprintf("%d [%.02f%%]", ordered_columns[["na_count"]], ordered_columns[["na_percent"]]) - ) + - ggplot2::scale_fill_manual( - name = "", - values = c("grey90", c(getOption("ggplot2.discrete.colour")[2], "#ff2951ff")[1]), - labels = c("Present", "Missing (at least one)") - ) + - labs + - ggthemes + - themes - }, - env = list( - labs = parsed_ggplot2_args$labs, - themes = parsed_ggplot2_args$theme, - ggthemes = parsed_ggplot2_args$ggtheme - ) + ) + + qenv <- teal.code::eval_code( + qenv, + substitute( + expr = { + by_subject_plot <- ggplot2::ggplot(summary_plot_patients, ggplot2::aes( + x = factor(id, levels = order_subjects), + y = factor(col, levels = ordered_columns[["column"]]), + fill = isna + )) + + ggplot2::geom_raster() + + ggplot2::annotate( + "text", + x = length(order_subjects), + y = seq_len(nrow(ordered_columns)), + hjust = 1, + label = sprintf("%d [%.02f%%]", ordered_columns[["na_count"]], ordered_columns[["na_percent"]]) + ) + + ggplot2::scale_fill_manual( + name = "", + values = c("grey90", c(getOption("ggplot2.discrete.colour")[2], "#ff2951ff")[1]), + labels = c("Present", "Missing (at least one)") + ) + + labs + + ggthemes + + themes + }, + env = list( + labs = parsed_ggplot2_args$labs, + themes = parsed_ggplot2_args$theme, + ggthemes = parsed_ggplot2_args$ggtheme ) ) + ) }) # Decorated outputs @@ -1269,34 +1291,33 @@ srv_missing_data <- function(id, id = "dec_summary_plot", data = summary_plot_q, decorators = select_decorators(decorators, "summary_plot"), - expr = { - grid::grid.newpage() - grid::grid.draw(summary_plot) - } + expr = quote({ + summary_plot + }) ) decorated_combination_plot_q <- srv_decorate_teal_data( id = "dec_combination_plot", data = combination_plot_q, decorators = select_decorators(decorators, "combination_plot"), - expr = { + expr = quote({ grid::grid.newpage() grid::grid.draw(combination_plot) - } + }) ) decorated_summary_table_q <- srv_decorate_teal_data( id = "dec_summary_table", data = summary_table_q, decorators = select_decorators(decorators, "table"), - expr = table + expr = quote(table) ) decorated_by_subject_plot_q <- srv_decorate_teal_data( id = "dec_by_subject_plot", data = by_subject_plot_q, decorators = select_decorators(decorators, "by_subject_plot"), - expr = print(by_subject_plot) + expr = quote(by_subject_plot) ) # Plots & tables reactives @@ -1320,7 +1341,7 @@ srv_missing_data <- function(id, options = list(language = list(zeroRecords = "No variable selected."), pageLength = input$levels_table_rows) ) } else { - decorated_summary_table_q()[["table"]] + DT::datatable(decorated_summary_table_q()[["table"]]) } }) @@ -1374,48 +1395,8 @@ srv_missing_data <- function(id, title = "Show R Code for Missing Data" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::TealReportCard$new() - sum_type <- input$summary_type - title <- if (sum_type == "By Variable Levels") paste0(sum_type, " Table") else paste0(sum_type, " Plot") - title_dataname <- paste(title, dataname, sep = " - ") - label <- if (label == "") { - paste("Missing Data", sum_type, dataname, sep = " - ") - } else { - label - } - card$set_name(label) - card$append_text(title_dataname, "header2") - if (with_filter) card$append_fs(filter_panel_api$get_filter_state()) - if (sum_type == "Summary") { - card$append_text("Plot", "header3") - card$append_plot(summary_plot_r(), dim = pws1$dim()) - } else if (sum_type == "Combinations") { - card$append_text("Plot", "header3") - card$append_plot(combination_plot_r(), dim = pws2$dim()) - } else if (sum_type == "By Variable Levels") { - card$append_text("Table", "header3") - table <- decorated_summary_table_q()[["table"]] - if (nrow(table) == 0L) { - card$append_text("No data available for table.") - } else { - card$append_table(table) - } - } else if (sum_type == "Grouped by Subject") { - card$append_text("Plot", "header3") - card$append_plot(by_subject_plot_r(), dim = pws3$dim()) - } - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + + decorated_final_q }) } diff --git a/R/tm_outliers.R b/R/tm_outliers.R index e15ba7635..c8fd2c3e5 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -45,6 +45,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -264,9 +266,6 @@ ui_outliers <- function(id, ...) { DT::dataTableOutput(ns("table_ui")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(args[c("outlier_var", "categorical_var")]), teal.transform::data_extract_ui( @@ -389,10 +388,8 @@ ui_outliers <- function(id, ...) { # Server function for the outliers module # Server function for the outliers module -srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, +srv_outliers <- function(id, data, outlier_var, categorical_var, plot_height, plot_width, ggplot2_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -449,10 +446,10 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, teal.code::eval_code( data(), paste0( - 'library("dplyr");library("tidyr");', # nolint quotes + 'library("dplyr");library("tidyr");', # nolint: quotes. 'library("tibble");library("ggplot2");' ) - ) %>% # nolint quotes + ) %>% # nolint: quotes. teal.code::eval_code(as.expression(anl_merged_input()$expr)) }) @@ -476,6 +473,12 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, ANL <- merged$anl_q_r()[["ANL"]] qenv <- merged$anl_q_r() + teal.reporter::teal_card(qenv) <- + c( + teal.reporter::teal_card("# Outliers Analysis"), + teal.reporter::teal_card(qenv), + teal.reporter::teal_card("## Module's code") + ) outlier_var <- as.vector(merged$anl_input_r()$columns_source$outlier_var) categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var) @@ -637,6 +640,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, ) qenv <- if (length(categorical_var) > 0) { + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Summary Table") qenv <- teal.code::eval_code( qenv, substitute( @@ -733,14 +737,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, # Generate decoratable object from data qenv <- within(qenv, { - table <- DT::datatable( - summary_table, - options = list( - dom = "t", - autoWidth = TRUE, - columnDefs = list(list(width = "200px", targets = "_all")) - ) - ) + table <- summary_table }) if (length(categorical_var) > 0 && nrow(qenv[["ANL_OUTLIER"]]) > 0) { @@ -755,8 +752,11 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, # boxplot/violinplot # nolint commented_code box_plot_q <- reactive({ req(common_code_q()) - ANL <- common_code_q()[["ANL"]] - ANL_OUTLIER <- common_code_q()[["ANL_OUTLIER"]] + qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Box Plot") + + ANL <- qenv[["ANL"]] + ANL_OUTLIER <- qenv[["ANL_OUTLIER"]] outlier_var <- as.vector(merged$anl_input_r()$columns_source$outlier_var) categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var) @@ -829,7 +829,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, ) teal.code::eval_code( - common_code_q(), + qenv, substitute( expr = box_plot <- plot_call + ggplot2::scale_color_manual(values = c("TRUE" = "red", "FALSE" = "black")) + @@ -846,8 +846,11 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, # density plot density_plot_q <- reactive({ - ANL <- common_code_q()[["ANL"]] - ANL_OUTLIER <- common_code_q()[["ANL_OUTLIER"]] + qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Density Plot") + + ANL <- qenv[["ANL"]] + ANL_OUTLIER <- qenv[["ANL_OUTLIER"]] outlier_var <- as.vector(merged$anl_input_r()$columns_source$outlier_var) categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var) @@ -890,7 +893,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, ) teal.code::eval_code( - common_code_q(), + qenv, substitute( expr = density_plot <- plot_call + labs + ggthemes + themes, env = list( @@ -906,6 +909,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, # Cumulative distribution plot cumulative_plot_q <- reactive({ qenv <- common_code_q() + teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "## Cumulative Distribution Plot") ANL <- qenv[["ANL"]] ANL_OUTLIER <- qenv[["ANL_OUTLIER"]] @@ -1037,8 +1041,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, }, env = list(table_columns = input$table_ui_columns, .plot = as.name(obj_name)) ) - }), - expr_is_reactive = TRUE + }) ) }, stats::setNames(nm = c("box_plot", "density_plot", "cumulative_plot")), @@ -1051,7 +1054,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, "d_table", data = decorated_final_q_no_table, decorators = select_decorators(decorators, "table"), - expr = table + expr = quote(table) ) output$summary_table <- DT::renderDataTable( @@ -1059,7 +1062,14 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, if (iv_r()$is_valid()) { categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var) if (!is.null(categorical_var)) { - decorated_final_q()[["table"]] + DT::datatable( + decorated_final_q()[["table"]], + options = list( + dom = "t", + autoWidth = TRUE, + columnDefs = list(list(width = "200px", targets = "_all")) + ) + ) } } } @@ -1322,39 +1332,7 @@ srv_outliers <- function(id, data, reporter, filter_panel_api, outlier_var, title = "Show R Code for Outlier" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - tab_type <- input$tabs - card <- teal::report_card_template( - title = paste0("Outliers - ", tab_type), - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - categorical_var <- as.vector(merged$anl_input_r()$columns_source$categorical_var) - if (length(categorical_var) > 0) { - summary_table <- decorated_final_q()[["table"]] - card$append_text("Summary Table", "header3") - card$append_table(summary_table) - } - card$append_text("Plot", "header3") - if (tab_type == "Boxplot") { - card$append_plot(box_plot_r(), dim = box_pws$dim()) - } else if (tab_type == "Density Plot") { - card$append_plot(density_plot_r(), dim = density_pws$dim()) - } else if (tab_type == "Cumulative Distribution Plot") { - card$append_plot(cumulative_plot_r(), dim = cum_density_pws$dim()) - } - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + + decorated_final_q }) } diff --git a/R/tm_t_crosstable.R b/R/tm_t_crosstable.R index f0708e9a1..59d6a634a 100644 --- a/R/tm_t_crosstable.R +++ b/R/tm_t_crosstable.R @@ -59,6 +59,8 @@ #' To learn more please refer to the vignette #' `vignette("transform-module-output", package = "teal")` or the [`teal::teal_transform_module()`] documentation. #' +#' @inheritSection teal::example_module Reporting +#' #' @examplesShinylive #' library(teal.modules.general) #' interactive <- function() TRUE @@ -239,9 +241,6 @@ ui_t_crosstable <- function(id, x, y, show_percentage, show_total, remove_zero_c teal.widgets::table_with_settings_ui(ns("table")) ), encoding = tags$div( - ### Reporter - teal.reporter::simple_reporter_ui(ns("simple_reporter")), - ### tags$label("Encodings", class = "text-primary"), teal.transform::datanames_input(list(x, y)), teal.transform::data_extract_ui(ns("x"), label = "Row values", x, is_single_dataset = is_single_dataset), @@ -274,9 +273,7 @@ ui_t_crosstable <- function(id, x, y, show_percentage, show_total, remove_zero_c } # Server function for the cross-table module -srv_t_crosstable <- function(id, data, reporter, filter_panel_api, label, x, y, remove_zero_columns, basic_table_args, decorators) { - with_reporter <- !missing(reporter) && inherits(reporter, "Reporter") - with_filter <- !missing(filter_panel_api) && inherits(filter_panel_api, "FilterPanelAPI") +srv_t_crosstable <- function(id, data, label, x, y, remove_zero_columns, basic_table_args, decorators) { checkmate::assert_class(data, "reactive") checkmate::assert_class(isolate(data()), "teal_data") moduleServer(id, function(input, output, session) { @@ -330,9 +327,16 @@ srv_t_crosstable <- function(id, data, reporter, filter_panel_api, label, x, y, selector_list = selector_list, merge_function = merge_function ) - qenv <- reactive( - teal.code::eval_code(data(), 'library("rtables");library("tern");library("dplyr")') # nolint quotes - ) + qenv <- reactive({ + obj <- data() + teal.reporter::teal_card(obj) <- + c( + teal.reporter::teal_card("# Cross Table"), + teal.reporter::teal_card(obj), + teal.reporter::teal_card("## Module's code") + ) + teal.code::eval_code(obj, 'library("rtables");library("tern");library("dplyr")') # nolint: quotes. + }) anl_merged_q <- reactive({ req(anl_merged_input()) qenv() %>% @@ -384,8 +388,10 @@ srv_t_crosstable <- function(id, data, reporter, filter_panel_api, label, x, y, ANL ) + obj <- merged$anl_q_r() + teal.reporter::teal_card(obj) <- c(teal.reporter::teal_card(obj), "# Table") obj <- teal.code::eval_code( - merged$anl_q_r(), + obj, substitute( expr = { title <- plot_title @@ -461,7 +467,7 @@ srv_t_crosstable <- function(id, data, reporter, filter_panel_api, label, x, y, id = "decorator", data = output_q, decorators = select_decorators(decorators, "table"), - expr = table + expr = quote(table) ) output$title <- renderText(req(decorated_output_q())[["title"]]) @@ -485,26 +491,6 @@ srv_t_crosstable <- function(id, data, reporter, filter_panel_api, label, x, y, title = "Show R Code for Cross-Table" ) - ### REPORTER - if (with_reporter) { - card_fun <- function(comment, label) { - card <- teal::report_card_template( - title = "Cross Table", - label = label, - with_filter = with_filter, - filter_panel_api = filter_panel_api - ) - card$append_text("Table", "header3") - card$append_table(table_r()) - if (!comment == "") { - card$append_text("Comment", "header3") - card$append_text(comment) - } - card$append_src(source_code_r()) - card - } - teal.reporter::simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun) - } - ### + decorated_output_q }) } diff --git a/R/utils.R b/R/utils.R index 5eb3609fd..dc4e0571b 100644 --- a/R/utils.R +++ b/R/utils.R @@ -286,11 +286,10 @@ assert_single_selection <- function(x, #' Wrappers around `srv_transform_teal_data` that allows to decorate the data #' @inheritParams teal::srv_transform_teal_data -#' @param expr (`expression` or `reactive`) to evaluate on the output of the decoration. -#' When an expression it must be inline code. See [within()] +#' @inheritParams teal.reporter::`eval_code,teal_report-method` +#' @param expr (`reactive`) with expression to evaluate on the output of the +#' decoration. It must be compatible with `code` argument of [teal.code::eval_code()]. #' Default is `NULL` which won't evaluate any appending code. -#' @param expr_is_reactive (`logical(1)`) whether `expr` is a reactive expression -#' that skips defusing the argument. #' @details #' `srv_decorate_teal_data` is a wrapper around `srv_transform_teal_data` that #' allows to decorate the data with additional expressions. @@ -298,33 +297,23 @@ assert_single_selection <- function(x, #' first. #' #' @keywords internal -srv_decorate_teal_data <- function(id, data, decorators, expr, expr_is_reactive = FALSE) { +srv_decorate_teal_data <- function(id, data, decorators, expr) { checkmate::assert_class(data, classes = "reactive") checkmate::assert_list(decorators, "teal_transform_module") - checkmate::assert_flag(expr_is_reactive) - missing_expr <- missing(expr) - if (!missing_expr && !expr_is_reactive) { - expr <- dplyr::enexpr(expr) # Using dplyr re-export to avoid adding rlang to Imports - } + no_expr <- missing(expr) moduleServer(id, function(input, output, session) { decorated_output <- srv_transform_teal_data("inner", data = data, transformators = decorators) + expr_r <- if (is.reactive(expr)) expr else reactive(expr) + reactive({ - data_out <- try(data(), silent = TRUE) - if (inherits(data_out, "qenv.error")) { - data() + req(decorated_output()) + if (no_expr) { + decorated_output() } else { - # ensure original errors are displayed and `eval_code` is never executed with NULL - req(data(), decorated_output()) - if (missing_expr) { - decorated_output() - } else if (expr_is_reactive) { - teal.code::eval_code(decorated_output(), expr()) - } else { - teal.code::eval_code(decorated_output(), expr) - } + teal.code::eval_code(decorated_output(), expr_r()) } }) }) diff --git a/man/srv_decorate_teal_data.Rd b/man/srv_decorate_teal_data.Rd index 91977f9b9..d5321072e 100644 --- a/man/srv_decorate_teal_data.Rd +++ b/man/srv_decorate_teal_data.Rd @@ -5,7 +5,7 @@ \alias{ui_decorate_teal_data} \title{Wrappers around \code{srv_transform_teal_data} that allows to decorate the data} \usage{ -srv_decorate_teal_data(id, data, decorators, expr, expr_is_reactive = FALSE) +srv_decorate_teal_data(id, data, decorators, expr) ui_decorate_teal_data(id, decorators, ...) } @@ -14,12 +14,11 @@ ui_decorate_teal_data(id, decorators, ...) \item{data}{(\code{reactive} returning \code{teal_data})} -\item{expr}{(\code{expression} or \code{reactive}) to evaluate on the output of the decoration. -When an expression it must be inline code. See \code{\link[=within]{within()}} +\item{expr}{(\code{reactive}) with expression to evaluate on the output of the +decoration. It must be compatible with \code{code} argument of \code{\link[teal.code:eval_code]{teal.code::eval_code()}}. Default is \code{NULL} which won't evaluate any appending code.} -\item{expr_is_reactive}{(\code{logical(1)}) whether \code{expr} is a reactive expression -that skips defusing the argument.} +\item{...}{(\code{\link{dots}}) additional arguments passed to future methods.} } \description{ Wrappers around \code{srv_transform_teal_data} that allows to decorate the data diff --git a/man/tm_missing_data.Rd b/man/tm_missing_data.Rd index 6d2f03824..04fca9147 100644 --- a/man/tm_missing_data.Rd +++ b/man/tm_missing_data.Rd @@ -82,7 +82,7 @@ adaptable for general data analysis purposes. This module generates the following objects, which can be modified in place using decorators: \itemize{ -\item \code{summary_plot} (\code{grob} created with \code{\link[ggplot2:ggplotGrob]{ggplot2::ggplotGrob()}}) +\item \code{summary_plot} (\code{ggplot}) \item \code{combination_plot} (\code{grob} created with \code{\link[ggplot2:ggplotGrob]{ggplot2::ggplotGrob()}}) \item \code{by_subject_plot} (\code{ggplot}) \item \code{table} (\code{datatables} created with \code{\link[DT:datatable]{DT::datatable()}})