From ec4437231bc7d89ca089d16a32c326557f3f95ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Tue, 23 Sep 2025 16:45:20 +0200 Subject: [PATCH 01/60] Explore heatmap and tile map --- R/tm_missing_data.R | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 0778b4e0e..b11339dac 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1107,11 +1107,11 @@ srv_missing_data <- function(id, 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( qenv, 'library("forcats");library("glue")' # nolint + ) teal.code::eval_code( common_code_libraries_q, @@ -1150,7 +1150,34 @@ srv_missing_data <- function(id, ) ) } - + #convert to ggplot + browser() + tile <- within(qenv, { + keep_columns <- intersect(c(keys, "SUBJID", "SITEID"), colnames(ANL)) + labels <- vapply(ANL, formatters::obj_label, character(1L)) + ANL %>% + pivot_longer(-keep_columns, values_transform = is.na) |> + summarise(.by = c(SUBJID, name), value = value, perc = sum(value)/n()) |> + mutate(label = labels[name]) |> + ggplot() + + geom_tile(aes(SUBJID, label, fill = value)) + + geom_text(aes(SUBJID, label, label = scales::label_percent()(perc)), data = . %>% filter(value)) + + scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "gray"), + labels = c("TRUE" = "Missing", "FALSE" = "Present"), + name = "Value") + + scale_x_discrete(expand = expansion()) + }, + keys = join_keys(qenv) |> unlist() |> unique()) + + heatmap <- within(qenv, { + ANL2 <- ANL[, setdiff(colnames(ANL), c(keys, "SUBJID", "SITEID"))] + labels <- vapply(ANL2, formatters::obj_label, character(1L)) + ANL2 <- is.na(ANL2) + rownames(ANL2) <- ANL$SUBJID + ANL2[] <- as.numeric(ANL2) + heatmap(t(ANL2), Rowv = NA, Colv = NA, scale = "none", + labRow = labels) + }, keys = join_keys(qenv) |> unlist() |> unique()) within(qenv, { table <- rtables::df_to_tt(summary_data) table From 4593c886d7ae5be9bb5518086748ce3bb0cf3e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 3 Oct 2025 08:41:02 +0200 Subject: [PATCH 02/60] Fix lintr names --- R/tm_a_pca.R | 2 +- R/tm_a_regression.R | 6 ++--- R/tm_data_table.R | 2 +- R/tm_g_association.R | 6 ++--- R/tm_g_bivariate.R | 2 +- R/tm_g_distribution.R | 14 +++++----- R/tm_g_response.R | 4 +-- R/tm_g_scatterplot.R | 2 +- R/tm_g_scatterplotmatrix.R | 2 +- R/tm_missing_data.R | 52 ++++++++++++++++++++++++++------------ 10 files changed, 56 insertions(+), 36 deletions(-) diff --git a/R/tm_a_pca.R b/R/tm_a_pca.R index 1cf0d40d4..07eea120a 100644 --- a/R/tm_a_pca.R +++ b/R/tm_a_pca.R @@ -440,7 +440,7 @@ srv_a_pca <- function(id, data, dat, plot_height, plot_width, ggplot2_args, deco 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 + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr");library("tidyr")') # nolint: quotes_lintr }) anl_merged_q <- reactive({ req(anl_merged_input()) diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 3ed9f29d6..5221616fe 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -37,9 +37,9 @@ #' It takes the form of `c(value, min, max)` and it is passed to the `value_min_max` #' argument in `teal.widgets::optionalSliderInputValMinMax`. #' -# nolint start: line_length. +# nolint start: line_length_lintr. #' @param ggplot2_args `r roxygen_ggplot2_args_param("Response vs Regressor", "Residuals vs Fitted", "Scale-Location", "Cook's distance", "Residuals vs Leverage", "Cook's dist vs Leverage")` -# nolint end: line_length. +# nolint end: line_length_lintr. #' #' @inherit shared_params return #' @@ -465,7 +465,7 @@ srv_a_regression <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes_lintr }) anl_merged_q <- reactive({ diff --git a/R/tm_data_table.R b/R/tm_data_table.R index 6fcfe4325..df77687b6 100644 --- a/R/tm_data_table.R +++ b/R/tm_data_table.R @@ -309,7 +309,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_lintr. ) teal.code::eval_code( qenv, diff --git a/R/tm_g_association.R b/R/tm_g_association.R index 5016472ba..94d70d613 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -151,8 +151,8 @@ tm_g_association <- function(label = "Association", show_association = TRUE, plot_height = c(600, 400, 5000), plot_width = NULL, - distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length. - association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length. + distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length_lintr. + association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length_lintr. pre_output = NULL, post_output = NULL, ggplot2_args = teal.widgets::ggplot2_args(), @@ -349,7 +349,7 @@ srv_tm_g_association <- function(id, 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 + teal.code::eval_code(obj, 'library("ggplot2");library("dplyr");library("ggmosaic")') # nolint: quotes_lintr }) anl_merged_q <- reactive({ req(anl_merged_input()) diff --git a/R/tm_g_bivariate.R b/R/tm_g_bivariate.R index a2099ae36..440d1d4f9 100644 --- a/R/tm_g_bivariate.R +++ b/R/tm_g_bivariate.R @@ -565,7 +565,7 @@ srv_g_bivariate <- function(id, obj %>% teal.code::eval_code( c( - 'library("ggplot2");library("dplyr")', # nolint: quotes + 'library("ggplot2");library("dplyr")', # nolint: quotes_lintr as.expression(anl_merged_input()$expr) ) ) diff --git a/R/tm_g_distribution.R b/R/tm_g_distribution.R index 1e8ae5a61..932d381f8 100644 --- a/R/tm_g_distribution.R +++ b/R/tm_g_distribution.R @@ -524,7 +524,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_lintr ) anl_merged_q <- reactive({ @@ -665,7 +665,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_lintr qenv <- teal.code::eval_code( qenv, substitute( @@ -683,7 +683,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_lintr qenv <- teal.code::eval_code( qenv, substitute( @@ -893,7 +893,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_lintr qenv <- teal.code::eval_code( qenv, substitute( @@ -1039,7 +1039,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_lintr qenv <- teal.code::eval_code( qenv, substitute( @@ -1235,7 +1235,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_lintr qenv <- teal.code::eval_code( qenv, substitute( @@ -1249,7 +1249,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_lintr qenv <- teal.code::eval_code( qenv, substitute( diff --git a/R/tm_g_response.R b/R/tm_g_response.R index 7f22bacb5..901dfcaa2 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -390,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_lintr ) anl_merged_q <- reactive({ @@ -524,7 +524,7 @@ srv_g_response <- function(id, resp_cl = resp_cl, hjust_value = if (swap_axes) "left" else "middle", vjust_value = if (swap_axes) "middle" else -1, - position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint: line_length. + position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint: line_length_lintr. anl3_y = if (!freq) 1.1 else as.name("ns"), position_anl3_value = if (!freq) "fill" else "stack" ) diff --git a/R/tm_g_scatterplot.R b/R/tm_g_scatterplot.R index 1c0a38ab3..7d27c9ddf 100644 --- a/R/tm_g_scatterplot.R +++ b/R/tm_g_scatterplot.R @@ -591,7 +591,7 @@ srv_g_scatterplot <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes + teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes_lintr }) anl_merged_q <- reactive({ diff --git a/R/tm_g_scatterplotmatrix.R b/R/tm_g_scatterplotmatrix.R index 25187f35f..168b77c58 100644 --- a/R/tm_g_scatterplotmatrix.R +++ b/R/tm_g_scatterplotmatrix.R @@ -334,7 +334,7 @@ srv_g_scatterplotmatrix <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - qenv <- teal.code::eval_code(obj, 'library("dplyr");library("lattice")') # nolint quotes + qenv <- teal.code::eval_code(obj, 'library("dplyr");library("lattice")') # nolint quotes_lintr teal.code::eval_code(qenv, as.expression(anl_merged_input()$expr)) }) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index b11339dac..a7a205780 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1150,34 +1150,54 @@ srv_missing_data <- function(id, ) ) } - #convert to ggplot - browser() + # convert to ggplot + # browser() tile <- within(qenv, { - keep_columns <- intersect(c(keys, "SUBJID", "SITEID"), colnames(ANL)) + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(ANL, formatters::obj_label, character(1L)) - ANL %>% - pivot_longer(-keep_columns, values_transform = is.na) |> - summarise(.by = c(SUBJID, name), value = value, perc = sum(value)/n()) |> - mutate(label = labels[name]) |> - ggplot() + - geom_tile(aes(SUBJID, label, fill = value)) + - geom_text(aes(SUBJID, label, label = scales::label_percent()(perc)), data = . %>% filter(value)) + - scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "gray"), - labels = c("TRUE" = "Missing", "FALSE" = "Present"), - name = "Value") + + plot <- ANL %>% + filter(group_vals %in% group_var_name) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise(.by = c(group_var_name, name), + value = sum(value), perc = value/n()) %>% + mutate(label = labels[name]) %>% + ggplot(aes(group_var_name, label)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white") + + labs(fill = label_column, ylab = element_blank()) + scale_x_discrete(expand = expansion()) + # scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "gray", "0" = "gray"), + # labels = c("TRUE" = "Missing", "FALSE" = "Present", "0" = "Present"), + # name = "Value") + }, - keys = join_keys(qenv) |> unlist() |> unique()) + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals, + column = if (input$count_type == "counts") { as.name("value")} else {as.name("perc")}, + label_column = if (input$count_type == "counts") "Missing counts" else "Missing percentage" + ) + # convert to heatmap + browser() + tile$plot heatmap <- within(qenv, { - ANL2 <- ANL[, setdiff(colnames(ANL), c(keys, "SUBJID", "SITEID"))] + ANL2 <- select(ANL, setdiff(colnames(ANL), c(group_var, keys, "SUBJID", "SITEID"))) labels <- vapply(ANL2, formatters::obj_label, character(1L)) ANL2 <- is.na(ANL2) rownames(ANL2) <- ANL$SUBJID ANL2[] <- as.numeric(ANL2) heatmap(t(ANL2), Rowv = NA, Colv = NA, scale = "none", labRow = labels) - }, keys = join_keys(qenv) |> unlist() |> unique()) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var = group_var, + group_vals = group_vals, + summ_fn = summ_fn) + + + within(qenv, { table <- rtables::df_to_tt(summary_data) table From 586b960b47bc7250946139e69a81a6eaed93558c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 3 Oct 2025 12:21:56 +0200 Subject: [PATCH 03/60] Replace table by a plot --- DESCRIPTION | 1 + R/tm_missing_data.R | 183 +++++++++++++++++++++++------------------ man/tm_missing_data.Rd | 2 + 3 files changed, 108 insertions(+), 78 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5d8ea763b..40ec18fbc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -69,6 +69,7 @@ Imports: tools, utils Suggests: + formatters (>= 0.5.11), knitr (>= 1.42), logger (>= 0.4.0), nestcolor (>= 0.1.0), diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index a7a205780..edfc1a045 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -22,6 +22,7 @@ #' This module generates the following objects, which can be modified in place using decorators: #' - `summary_plot` (`ggplot`) #' - `combination_plot` (`grob` created with [ggplot2::ggplotGrob()]) +#' - `by_variable_plot` (`ggplot`) #' - `by_subject_plot` (`ggplot`) #' #' A Decorator is applied to the specific output using a named list of `teal_transform_module` objects. @@ -34,6 +35,7 @@ #' decorators = list( #' summary_plot = teal_transform_module(...), # applied only to `summary_plot` output #' combination_plot = teal_transform_module(...), # applied only to `combination_plot` output +#' by_variable_plot = teal_transform_module(...) # applied only to `by_variable_plot` output #' by_subject_plot = teal_transform_module(...) # applied only to `by_subject_plot` output #' ) #' ) @@ -328,8 +330,9 @@ ui_missing_data <- function(id, by_subject_plot = FALSE) { ), tabPanel( "By Variable Levels", - teal.widgets::get_dt_rows(ns("levels_table"), ns("levels_table_rows")), - DT::dataTableOutput(ns("levels_table")) + # teal.widgets::get_dt_rows(ns("levels_table"), ns("levels_table_rows")), + # DT::dataTableOutput(ns("levels_table")) + teal.widgets::plot_with_settings_ui(id = ns("by_variable_plot")), ) ) if (isTRUE(by_subject_plot)) { @@ -1069,7 +1072,7 @@ srv_missing_data <- function(id, }) }) - summary_table_q <- reactive({ + by_variable_plot_q <- reactive({ req( input$summary_type == "By Variable Levels", # needed to trigger show r code update on tab change common_code_q() @@ -1079,7 +1082,7 @@ srv_missing_data <- function(id, # extract the ANL dataset for use in further validation anl <- common_code_q()[["ANL"]] - group_var <- input$group_by_var + group_var <- req(input$group_by_var) validate( need( is.null(group_var) || @@ -1111,7 +1114,6 @@ srv_missing_data <- function(id, common_code_libraries_q <- teal.code::eval_code( qenv, 'library("forcats");library("glue")' # nolint - ) teal.code::eval_code( common_code_libraries_q, @@ -1150,58 +1152,89 @@ srv_missing_data <- function(id, ) ) } - # convert to ggplot - # browser() - tile <- within(qenv, { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(ANL, formatters::obj_label, character(1L)) - plot <- ANL %>% - filter(group_vals %in% group_var_name) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise(.by = c(group_var_name, name), - value = sum(value), perc = value/n()) %>% - mutate(label = labels[name]) %>% - ggplot(aes(group_var_name, label)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white") + - labs(fill = label_column, ylab = element_blank()) + - scale_x_discrete(expand = expansion()) - # scale_fill_manual(values = c("TRUE" = "red", "FALSE" = "gray", "0" = "gray"), - # labels = c("TRUE" = "Missing", "FALSE" = "Present", "0" = "Present"), - # name = "Value") + - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals, - column = if (input$count_type == "counts") { as.name("value")} else {as.name("perc")}, - label_column = if (input$count_type == "counts") "Missing counts" else "Missing percentage" - ) - # convert to heatmap - browser() - tile$plot - heatmap <- within(qenv, { - ANL2 <- select(ANL, setdiff(colnames(ANL), c(group_var, keys, "SUBJID", "SITEID"))) - labels <- vapply(ANL2, formatters::obj_label, character(1L)) - ANL2 <- is.na(ANL2) - rownames(ANL2) <- ANL$SUBJID - ANL2[] <- as.numeric(ANL2) - heatmap(t(ANL2), Rowv = NA, Colv = NA, scale = "none", - labRow = labels) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var = group_var, - group_vals = group_vals, - summ_fn = summ_fn) + dev_ggplot2_args <- teal.widgets::ggplot2_args( + labs = list( + fill = if (input$count_type == "counts") "Missing counts" else "Missing percentage", + y = quote(ggplot2::element_blank()) + ) + ) + all_ggplot2_args <- teal.widgets::resolve_ggplot2_args( + user_plot = ggplot2_args[["By Variable Levels"]], + user_default = ggplot2_args$default, + module_plot = dev_ggplot2_args + ) + parsed_ggplot2_args <- teal.widgets::parse_ggplot2_args( + all_ggplot2_args, + ggtheme = input$ggtheme + ) - within(qenv, { - table <- rtables::df_to_tt(summary_data) - table - }) + # convert to ggplot + if (!is.null(group_vals)) { + ANL_q <- within(qenv, + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(ANL, formatters::obj_label, character(1L)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals + ) + } else { + ANL_q <- within(qenv, + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(ANL, formatters::obj_label, character(1L)) + ANL <- ANL %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var + ) + } + req(NROW(ANL_q$ANL) > 0) + browser(expr = group_var == "RACE") + tile <- within(ANL_q, + { + by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white" + ) + + scale_x_discrete(expand = expansion()) + + scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + labs + + ggthemes + }, + group_var_name = as.name(group_var), + column = if (input$count_type == "counts") { + as.name("value") + } else { + as.name("perc") + }, + labs = parsed_ggplot2_args$labs, + labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), + # low = if (input$count_type == "counts") "grey90" else "#ff2951ff", + ggthemes = parsed_ggplot2_args$ggtheme + ) + tile }) by_subject_plot_q <- reactive({ @@ -1347,11 +1380,11 @@ srv_missing_data <- function(id, }) ) - decorated_summary_table_q <- srv_decorate_teal_data( - id = "dec_summary_table", - data = summary_table_q, - decorators = select_decorators(decorators, "table"), - expr = quote(table) + decorated_by_variable_plot_q <- srv_decorate_teal_data( + id = "dec_by_variable_plot", + data = by_variable_plot_q, + decorators = select_decorators(decorators, "by_variable_plot"), + expr = quote(by_variable_plot) ) decorated_by_subject_plot_q <- srv_decorate_teal_data( @@ -1371,22 +1404,8 @@ srv_missing_data <- function(id, req(decorated_combination_plot_q())[["combination_plot"]] }) - summary_table_r <- reactive({ - q <- req(decorated_summary_table_q()) - - if (length(input$variables_select) == 0) { - # so that zeroRecords message gets printed - # using tibble as it supports weird column names, such as " " - DT::datatable( - tibble::tibble(` ` = logical(0)), - options = list( - language = list(zeroRecords = "No variable selected."), - pageLength = input$levels_table_rows - ) - ) - } else { - DT::datatable(q[["summary_data"]]) - } + by_variable_plot_r <- reactive({ + req(decorated_by_variable_plot_q())[["by_variable_plot"]] }) by_subject_plot_r <- reactive({ @@ -1408,9 +1427,14 @@ srv_missing_data <- function(id, width = plot_width ) - output$levels_table <- DT::renderDataTable(summary_table_r()) - pws3 <- teal.widgets::plot_with_settings_srv( + id = "by_variable_plot", + plot_r = by_variable_plot_r, + height = plot_height, + width = plot_width + ) + + pws4 <- teal.widgets::plot_with_settings_srv( id = "by_subject_plot", plot_r = by_subject_plot_r, height = plot_height, @@ -1422,8 +1446,11 @@ srv_missing_data <- function(id, decorated_combination_plot_dims_q <- # nolint: object_length_linter. set_chunk_dims(pws2, decorated_combination_plot_q) + decorated_by_variable_plot_dims_q <- # nolint: object_length_linter. + set_chunk_dims(pws3, decorated_by_variable_plot_q) + decorated_by_subject_plot_dims_q <- # nolint: object_length_linter. - set_chunk_dims(pws3, decorated_by_subject_plot_q) + set_chunk_dims(pws4, decorated_by_subject_plot_q) decorated_final_q <- reactive({ sum_type <- req(input$summary_type) @@ -1432,7 +1459,7 @@ srv_missing_data <- function(id, } else if (sum_type == "Combinations") { decorated_combination_plot_dims_q() } else if (sum_type == "By Variable Levels") { - decorated_summary_table_q() + decorated_by_variable_plot_dims_q() } else if (sum_type == "Grouped by Subject") { decorated_by_subject_plot_dims_q() } diff --git a/man/tm_missing_data.Rd b/man/tm_missing_data.Rd index 25244f9c6..1b9543d2f 100644 --- a/man/tm_missing_data.Rd +++ b/man/tm_missing_data.Rd @@ -84,6 +84,7 @@ This module generates the following objects, which can be modified in place usin \itemize{ \item \code{summary_plot} (\code{ggplot}) \item \code{combination_plot} (\code{grob} created with \code{\link[ggplot2:ggplotGrob]{ggplot2::ggplotGrob()}}) +\item \code{by_variable_plot} (\code{ggplot}) \item \code{by_subject_plot} (\code{ggplot}) } @@ -96,6 +97,7 @@ See code snippet below: decorators = list( summary_plot = teal_transform_module(...), # applied only to `summary_plot` output combination_plot = teal_transform_module(...), # applied only to `combination_plot` output + by_variable_plot = teal_transform_module(...) # applied only to `by_variable_plot` output by_subject_plot = teal_transform_module(...) # applied only to `by_subject_plot` output ) ) From c4a13ccf1faacaee2f53047fb0549adabd2b53b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 3 Oct 2025 12:23:08 +0200 Subject: [PATCH 04/60] Fix lint comments --- R/tm_missing_data.R | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index edfc1a045..2fc847b1c 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -330,8 +330,6 @@ ui_missing_data <- function(id, by_subject_plot = FALSE) { ), tabPanel( "By Variable Levels", - # teal.widgets::get_dt_rows(ns("levels_table"), ns("levels_table_rows")), - # DT::dataTableOutput(ns("levels_table")) teal.widgets::plot_with_settings_ui(id = ns("by_variable_plot")), ) ) @@ -1173,7 +1171,7 @@ srv_missing_data <- function(id, # convert to ggplot if (!is.null(group_vals)) { - ANL_q <- within(qenv, + ANL_q <- within(qenv, #nolint object_name_linter { keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(ANL, formatters::obj_label, character(1L)) @@ -1192,7 +1190,7 @@ srv_missing_data <- function(id, group_vals = group_vals ) } else { - ANL_q <- within(qenv, + ANL_q <- within(qenv, #nolint object_name_linter { keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(ANL, formatters::obj_label, character(1L)) @@ -1231,7 +1229,6 @@ srv_missing_data <- function(id, }, labs = parsed_ggplot2_args$labs, labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), - # low = if (input$count_type == "counts") "grey90" else "#ff2951ff", ggthemes = parsed_ggplot2_args$ggtheme ) tile From dda7615e3fbc4510be6179a058115e76648dbd9c Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:36:30 +0000 Subject: [PATCH 05/60] [skip style] [skip vbump] Restyle files --- R/tm_missing_data.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 2fc847b1c..b30ab5e1d 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1171,7 +1171,7 @@ srv_missing_data <- function(id, # convert to ggplot if (!is.null(group_vals)) { - ANL_q <- within(qenv, #nolint object_name_linter + ANL_q <- within(qenv, # nolint object_name_linter { keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(ANL, formatters::obj_label, character(1L)) @@ -1190,7 +1190,7 @@ srv_missing_data <- function(id, group_vals = group_vals ) } else { - ANL_q <- within(qenv, #nolint object_name_linter + ANL_q <- within(qenv, # nolint object_name_linter { keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(ANL, formatters::obj_label, character(1L)) From ea38ac1fb4eab68b43788c8b9cde52ef9b6ed9b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 3 Oct 2025 13:37:51 +0200 Subject: [PATCH 06/60] Fix lintr issues --- R/tm_a_regression.R | 4 ++-- R/tm_g_association.R | 4 ++-- R/tm_g_response.R | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 5221616fe..145f5bc22 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -37,9 +37,9 @@ #' It takes the form of `c(value, min, max)` and it is passed to the `value_min_max` #' argument in `teal.widgets::optionalSliderInputValMinMax`. #' -# nolint start: line_length_lintr. +# nolint start: line_length #' @param ggplot2_args `r roxygen_ggplot2_args_param("Response vs Regressor", "Residuals vs Fitted", "Scale-Location", "Cook's distance", "Residuals vs Leverage", "Cook's dist vs Leverage")` -# nolint end: line_length_lintr. +# nolint end: line_length #' #' @inherit shared_params return #' diff --git a/R/tm_g_association.R b/R/tm_g_association.R index 94d70d613..0d28abb21 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -151,8 +151,8 @@ tm_g_association <- function(label = "Association", show_association = TRUE, plot_height = c(600, 400, 5000), plot_width = NULL, - distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length_lintr. - association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint: line_length_lintr. + distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_lintr. + association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_lintr. pre_output = NULL, post_output = NULL, ggplot2_args = teal.widgets::ggplot2_args(), diff --git a/R/tm_g_response.R b/R/tm_g_response.R index 901dfcaa2..d633cdcca 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -524,7 +524,7 @@ srv_g_response <- function(id, resp_cl = resp_cl, hjust_value = if (swap_axes) "left" else "middle", vjust_value = if (swap_axes) "middle" else -1, - position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint: line_length_lintr. + position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint line_length_lintr anl3_y = if (!freq) 1.1 else as.name("ns"), position_anl3_value = if (!freq) "fill" else "stack" ) From c2969368b9aaa1e6fd9e139d97e151510bdd8d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 3 Oct 2025 16:22:33 +0200 Subject: [PATCH 07/60] Split evaluation to load libraries --- R/tm_g_bivariate.R | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/R/tm_g_bivariate.R b/R/tm_g_bivariate.R index 440d1d4f9..0cab36238 100644 --- a/R/tm_g_bivariate.R +++ b/R/tm_g_bivariate.R @@ -562,13 +562,9 @@ srv_g_bivariate <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - obj %>% - teal.code::eval_code( - c( - 'library("ggplot2");library("dplyr")', # nolint: quotes_lintr - as.expression(anl_merged_input()$expr) - ) - ) + obj |> + teal.code::eval_code('library("ggplot2");library("dplyr")') |> # nolint: quotes_lintr + teal.code::eval_code(as.expression(anl_merged_input()$expr)) }) merged <- list( From 5e3080d50b73c0616975c2aaad658fc9d5b2dc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Thu, 9 Oct 2025 11:59:18 +0200 Subject: [PATCH 08/60] Use "library(pkg)" instead of 'library("pkg")' #nolint --- R/tm_a_pca.R | 2 +- R/tm_a_regression.R | 2 +- R/tm_data_table.R | 2 +- R/tm_g_association.R | 2 +- R/tm_g_bivariate.R | 2 +- R/tm_g_distribution.R | 14 +++++++------- R/tm_g_response.R | 2 +- R/tm_g_scatterplot.R | 2 +- R/tm_g_scatterplotmatrix.R | 2 +- R/tm_missing_data.R | 4 ++-- R/tm_outliers.R | 2 +- R/tm_t_crosstable.R | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/R/tm_a_pca.R b/R/tm_a_pca.R index d448c7b3b..1a3f00216 100644 --- a/R/tm_a_pca.R +++ b/R/tm_a_pca.R @@ -437,7 +437,7 @@ srv_a_pca <- function(id, data, dat, plot_height, plot_width, ggplot2_args, deco 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_lintr + teal.code::eval_code(obj, "library(ggplot2);library(dplyr);library(tidyr)") }) anl_merged_q <- reactive({ req(anl_merged_input()) diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 5df2f43e0..2717b7943 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -462,7 +462,7 @@ srv_a_regression <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes_lintr + teal.code::eval_code(obj, "library(ggplot2);library(dplyr)") }) anl_merged_q <- reactive({ diff --git a/R/tm_data_table.R b/R/tm_data_table.R index df77687b6..47d21cbfc 100644 --- a/R/tm_data_table.R +++ b/R/tm_data_table.R @@ -309,7 +309,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_lintr. + "library(dplyr);library(DT)" ) teal.code::eval_code( qenv, diff --git a/R/tm_g_association.R b/R/tm_g_association.R index 75adaf7a0..662c044bc 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -346,7 +346,7 @@ srv_tm_g_association <- function(id, 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_lintr + teal.code::eval_code(obj, "library(ggplot2);library(dplyr);library(ggmosaic)") }) anl_merged_q <- reactive({ req(anl_merged_input()) diff --git a/R/tm_g_bivariate.R b/R/tm_g_bivariate.R index ab027dd2d..6ece4d991 100644 --- a/R/tm_g_bivariate.R +++ b/R/tm_g_bivariate.R @@ -560,7 +560,7 @@ srv_g_bivariate <- function(id, teal.reporter::teal_card("## Module's code") ) obj |> - teal.code::eval_code('library("ggplot2");library("dplyr")') |> # nolint: quotes_lintr + teal.code::eval_code("library(ggplot2);library(dplyr)") |> teal.code::eval_code(as.expression(anl_merged_input()$expr)) }) diff --git a/R/tm_g_distribution.R b/R/tm_g_distribution.R index 8e988e42c..29ccd4175 100644 --- a/R/tm_g_distribution.R +++ b/R/tm_g_distribution.R @@ -521,7 +521,7 @@ srv_distribution <- function(id, ) qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes_lintr + teal.code::eval_code(data(), "library(ggplot2);library(dplyr)") ) anl_merged_q <- reactive({ @@ -662,7 +662,7 @@ srv_distribution <- function(id, "Group by variable must be `factor`, `character`, or `integer`" ) ) - qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint quotes_lintr + qenv <- teal.code::eval_code(qenv, "library(forcats)") qenv <- teal.code::eval_code( qenv, substitute( @@ -680,7 +680,7 @@ srv_distribution <- function(id, ) ) - qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint quotes_lintr + qenv <- teal.code::eval_code(qenv, "library(forcats)") qenv <- teal.code::eval_code( qenv, substitute( @@ -890,7 +890,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_lintr + qenv <- teal.code::eval_code(qenv, "library(ggpp)") qenv <- teal.code::eval_code( qenv, substitute( @@ -1036,7 +1036,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_lintr + qenv <- teal.code::eval_code(qenv, "library(ggpp)") qenv <- teal.code::eval_code( qenv, substitute( @@ -1232,7 +1232,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_lintr + qenv <- teal.code::eval_code(qenv, "library(generics)") qenv <- teal.code::eval_code( qenv, substitute( @@ -1246,7 +1246,7 @@ srv_distribution <- function(id, ) ) } else { - qenv <- teal.code::eval_code(qenv, 'library("tidyr")') # nolint quotes_lintr + qenv <- teal.code::eval_code(qenv, "library(tidyr)") qenv <- teal.code::eval_code( qenv, substitute( diff --git a/R/tm_g_response.R b/R/tm_g_response.R index ad6d412ca..6a204e40f 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -387,7 +387,7 @@ srv_g_response <- function(id, ) qenv <- reactive( - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes_lintr + teal.code::eval_code(data(), "library(ggplot2);library(dplyr)") ) anl_merged_q <- reactive({ diff --git a/R/tm_g_scatterplot.R b/R/tm_g_scatterplot.R index 9207c241a..78696efc4 100644 --- a/R/tm_g_scatterplot.R +++ b/R/tm_g_scatterplot.R @@ -588,7 +588,7 @@ srv_g_scatterplot <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes_lintr + teal.code::eval_code(data(), "library(ggplot2);library(dplyr)") }) anl_merged_q <- reactive({ diff --git a/R/tm_g_scatterplotmatrix.R b/R/tm_g_scatterplotmatrix.R index 07a8bb1e5..d35541130 100644 --- a/R/tm_g_scatterplotmatrix.R +++ b/R/tm_g_scatterplotmatrix.R @@ -331,7 +331,7 @@ srv_g_scatterplotmatrix <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's code") ) - qenv <- teal.code::eval_code(obj, 'library("dplyr");library("lattice")') # nolint quotes_lintr + qenv <- teal.code::eval_code(obj, "library(dplyr);library(lattice)") teal.code::eval_code(qenv, as.expression(anl_merged_input()$expr)) }) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 2ca62dad5..f41b0ed50 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -512,7 +512,7 @@ srv_missing_data <- function(id, ) qenv <- teal.code::eval_code(obj, { - 'library("dplyr");library("ggplot2");library("tidyr");library("gridExtra")' # nolint quotes + "library(dplyr);library(ggplot2);library(tidyr);library(gridExtra)" }) qenv <- if (!is.null(selected_vars()) && length(selected_vars()) != ncol(anl)) { @@ -1097,7 +1097,7 @@ srv_missing_data <- function(id, qenv <- if (!is.null(group_var)) { common_code_libraries_q <- teal.code::eval_code( qenv, - 'library("forcats");library("glue")' # nolint + "library(forcats);library(glue)" ) teal.code::eval_code( common_code_libraries_q, diff --git a/R/tm_outliers.R b/R/tm_outliers.R index f8a552322..1cf9130e9 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -453,7 +453,7 @@ srv_outliers <- function(id, data, outlier_var, req(anl_merged_input()) teal.code::eval_code( data_obj(), - 'library("dplyr");library("tidyr");library("tibble");library("ggplot2")' # nolint quotes + "library(dplyr);library(tidyr);library(tibble);library(ggplot2)" ) %>% teal.code::eval_code(as.expression(anl_merged_input()$expr)) }) diff --git a/R/tm_t_crosstable.R b/R/tm_t_crosstable.R index 0fa64c90a..032ff6f81 100644 --- a/R/tm_t_crosstable.R +++ b/R/tm_t_crosstable.R @@ -332,7 +332,7 @@ srv_t_crosstable <- function(id, data, label, x, y, remove_zero_columns, basic_t 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 + teal.code::eval_code(obj, "library(rtables);library(tern);library(dplyr)") }) anl_merged_q <- reactive({ req(anl_merged_input()) From 484b91c37da59ea08afa0f8bcebf167b3dc78c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Thu, 9 Oct 2025 12:32:45 +0200 Subject: [PATCH 09/60] Use dot at the end of lint comment --- R/teal.modules.general.R | 4 ++-- R/tm_a_regression.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/teal.modules.general.R b/R/teal.modules.general.R index 82f61a562..62c385d91 100644 --- a/R/teal.modules.general.R +++ b/R/teal.modules.general.R @@ -15,11 +15,11 @@ #' @keywords internal "_PACKAGE" -# nolint start +# nolint start. # Note ggmosaic (version <= 0.3.3) needs to be in DEPENDS as the following does not work if it is imported # df <- data.frame(x = c("A", "B", "C", "A"), y = c("Z", "Z", "W", "W")) # ggplot(df) + ggmosaic::geom_mosaic(aes(x = ggmosaic::product(x), fill = y)) -# nolint end +# nolint end. # Needed to avoid R CMD note on no visible binding utils::globalVariables("count") diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 2717b7943..8cde5714e 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -37,9 +37,9 @@ #' It takes the form of `c(value, min, max)` and it is passed to the `value_min_max` #' argument in `teal.widgets::optionalSliderInputValMinMax`. #' -# nolint start: line_length +# nolint start: line_length. #' @param ggplot2_args `r roxygen_ggplot2_args_param("Response vs Regressor", "Residuals vs Fitted", "Scale-Location", "Cook's distance", "Residuals vs Leverage", "Cook's dist vs Leverage")` -# nolint end: line_length +# nolint end: line_length. #' #' @inherit shared_params return #' From d2673e6d95423895215c217a80dae0aa01838e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 13 Oct 2025 12:23:03 +0200 Subject: [PATCH 10/60] Simplify code branch --- R/tm_missing_data.R | 60 +++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index f41b0ed50..e5b3b4599 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1156,47 +1156,27 @@ srv_missing_data <- function(id, ) # convert to ggplot - if (!is.null(group_vals)) { - ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(ANL, formatters::obj_label, character(1L)) - ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% - mutate(label = labels[name]) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals - ) - } else { - ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(ANL, formatters::obj_label, character(1L)) - ANL <- ANL %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% - mutate(label = labels[name]) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var - ) - } - req(NROW(ANL_q$ANL) > 0) - browser(expr = group_var == "RACE") + ANL_q <- within(qenv, # nolint object_name_linter + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(ANL, formatters::obj_label, character(1L)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals + ) + tile <- within(ANL_q, - { + { by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + geom_tile(aes(fill = column)) + geom_text(aes(label = scales::percent(perc)), From 558f66661b852bc74340d277bf230318f9d6f4f6 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:33:36 +0000 Subject: [PATCH 11/60] [skip style] [skip vbump] Restyle files --- R/tm_missing_data.R | 34 +++++++++++++++++----------------- R/tm_outliers.R | 1 - 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index e5b3b4599..299b90d35 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1157,26 +1157,26 @@ srv_missing_data <- function(id, # convert to ggplot ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(ANL, formatters::obj_label, character(1L)) - ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% - mutate(label = labels[name]) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(ANL, formatters::obj_label, character(1L)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals ) tile <- within(ANL_q, - { + { by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + geom_tile(aes(fill = column)) + geom_text(aes(label = scales::percent(perc)), diff --git a/R/tm_outliers.R b/R/tm_outliers.R index 1cf9130e9..f78c4986a 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -112,7 +112,6 @@ #' vars <- choices_selected(variable_choices(data[["ADSL"]], fact_vars_adsl)) #' #' -#' #' app <- init( #' data = data, #' modules = modules( From 5c4b580ca54f0423376ecbb297c89783fc5b3348 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:40:37 +0000 Subject: [PATCH 12/60] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/tm_outliers.Rd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/man/tm_outliers.Rd b/man/tm_outliers.Rd index 2a4120b2b..a355b1d97 100644 --- a/man/tm_outliers.Rd +++ b/man/tm_outliers.Rd @@ -156,7 +156,6 @@ fact_vars_adsl <- names(Filter(isTRUE, sapply(data[["ADSL"]], is.factor))) vars <- choices_selected(variable_choices(data[["ADSL"]], fact_vars_adsl)) - app <- init( data = data, modules = modules( @@ -200,8 +199,8 @@ if (interactive()) { \if{html}{\out{}} } \item{example-2}{ - \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqajGIgEwCu1OAGcMAcwpxm1AJQAdCLTIyoBUrQBucAAQAeALS6AZoIgbaJdnN0AVLAFUAokrcQAxLoDCAEQCSAMreuvxQpFC6cAAesKgiSmERBsZc1AD6SVA2ieGRRroA7rSkABYq7Fm4uiBKuroAgr6BADIpumkYWYiIjE2tSgC+ihAAVkQq6QDWcKyilXm2BfxwJlDCpOkE-LSiBOnjkzNzwNDw81lyALruaxrpWiyi6VD8otTtZ2LsAGK01ORGOxdg4XNVRGh4hwssBgAowP0WvCrldqrsMHdSERGHJcUpHoxRO0CKUJgQxOlRHARBo4Px2ATaFB6CItqTaOSLnlYfDEcjUaZ1JsCc9Xu88RB3EpIe0VCV2HVQnldABeJURXCKvhCEREtXa4TfRX1UgwdJEQSkOgyebG+q6C1W2gyB4sVW6OiiUgKiD2v3qqDpGKkZj3USoOAEH3+-1ZL7u3nNJF4O0xqk00ju9ORzbhyPRmP+6jM6kJsCBak53SM5kiRDwzW+wt+klksTumssuBsttciI8hFJ-nVKO8gDirjwunhACEALJYADSWAAjPDcY3m37s7T+GWGhOG6nCzANrR4no1T8Gi1As5N1v6iZaNE6e7r7fXE3myMf8e5A+LbhHAEjYhy3Cuow7qet6x71FkQbRCGQqUhGo7foWcawJe06DgMKYYTGz4AjI7rEYCqH5nB-oih2TyAVurYcu2aqPNQgjdkxnILP2cJ4cmKLVCKAAkO7kPwAHUdula7nR7Gcey3EwnxfJgIJ1ZPKJMniZJhEnmeF7uqCX6Pr+hZmX6Fm6GZIwjLQJi6MCqihpoOg2LYtRNqI5QQKwDToOwkLCYItDVEFVKMDoOJDEoYCDFcQA}{Open in Shinylive} - \if{html}{\out{}} + \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqajGIgEwCu1OAGcMAcwpxm1AJQAdCLTIyoBUrQBucAAQAeALS6AZoIgbaJdnN0AVLAFUAokrcQAxLoDCAEQCSAMreuvxQpFC6cAAesKgiSmERBsZc1AD6SVA2ieGRRroA7rSkABYq7Fm4uiBKuroAgr6BADIpumkYWYiIjE2tSgC+ihAAVkQq6QDWcKyilXm2BfxwJlDCpOkE-LSiBOnjkzNzwNDw81lyALruaxrpWiyi6VD8otTtZ2LsAGK01ORGOxdg4XNVRGh4hwssBgAowP0WvCrldqrsMHdSERGHJcUpHoxRO0CKUJgQxOlRHARBo4Px2ATaFB6CItqTaOSLnlYfDEcjUaZ1JsCc9Xu88RB3JD2ioSuw6qE8roALyKiK4BV8IQiImqrXCb4K+qkGDpIiCUh0GTzI31XTmy20GQPFgq3R0USkeUQO2+tVQdIxUjMe6iVBwAjev1+rJfN285pIvC26NUmmkN1piObMMRqPRv3UZnU+NgQLU7O6RnMkSIeEan0F30ksliN3VllwNmtrkRHkIxP86qR3kAcVceF08IAQgBZLAAaSwAEZ4biG03fVnafxSw1x-WUwWYBtaPE9Kqfg0WoFnBvN-UTLRonS3Veb65G02Rt+j3J7824RwBI2IctwLqMG6Hpeke9RZIG0TBkKlLhiOX4FrGsAXlOA4DMm6HRk+AIyG6RGAiheawX6Irtk8AGbi2HJtqqjzUIIXaMZyCx9nCuFJii1QigAJNu5D8P+VFbhWO60WxHHslxMK8XyYACVWTwidJYkSQRx6nuebqgp+D4-gWpm+uZuimSMIy0CYujAqoIaaDoNi2LUjaiOUECsA06DsJCQmCLQ1SBVSjA6DiQxKGAgxXEAA}{Open in Shinylive} + \if{html}{\out{}} \if{html}{\out{}} } } From ef399e0c7af9150b43cb9140d00d3adae047e624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 17 Oct 2025 16:40:22 +0200 Subject: [PATCH 13/60] Fix logic --- R/tm_missing_data.R | 128 +++++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 42 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index eb6859b52..99ae13a81 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1156,47 +1156,91 @@ srv_missing_data <- function(id, ) # convert to ggplot - ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(ANL, formatters::obj_label, character(1L)) - ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% - mutate(label = labels[name]) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals - ) + labels <- lapply(qenv$ANL, attr, which = "label") + if (!any(lengths(labels))) { + ANL_q <- within(qenv, # nolint object_name_linter + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals + ) + tile <- within(ANL_q, + { + by_variable_plot <- ggplot(ANL, aes(group_var_name, name)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white" + ) + + scale_x_discrete(expand = expansion()) + + scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + labs + + ggthemes + }, + group_var_name = as.name(group_var), + column = if (input$count_type == "counts") { + as.name("value") + } else { + as.name("perc") + }, + labs = parsed_ggplot2_args$labs, + labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), + ggthemes = parsed_ggplot2_args$ggtheme + ) + + } else { + ANL_q <- within(qenv, # nolint object_name_linter + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals + ) + + tile <- within(ANL_q, + { + by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white" + ) + + scale_x_discrete(expand = expansion()) + + scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + labs + + ggthemes + }, + group_var_name = as.name(group_var), + column = if (input$count_type == "counts") { + as.name("value") + } else { + as.name("perc") + }, + labs = parsed_ggplot2_args$labs, + labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), + ggthemes = parsed_ggplot2_args$ggtheme + ) + } - tile <- within(ANL_q, - { - by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white" - ) + - scale_x_discrete(expand = expansion()) + - scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + - labs + - ggthemes - }, - group_var_name = as.name(group_var), - column = if (input$count_type == "counts") { - as.name("value") - } else { - as.name("perc") - }, - labs = parsed_ggplot2_args$labs, - labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), - ggthemes = parsed_ggplot2_args$ggtheme - ) tile }) @@ -1207,8 +1251,8 @@ srv_missing_data <- function(id, teal::validate_has_data(data_r(), 1) dev_ggplot2_args <- teal.widgets::ggplot2_args( - labs = list(x = "", y = ""), - theme = list(legend.position = "bottom", axis.text.x = quote(ggplot2::element_blank())) + labs = list(x = NULL, y = NULL), + theme = list(legend.position = "bottom", axis.text.x =NULL) ) all_ggplot2_args <- teal.widgets::resolve_ggplot2_args( From f383cc73b6a7a5c43a18fb85f47fd19606558a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 17 Oct 2025 16:40:50 +0200 Subject: [PATCH 14/60] Avoid ggplot2 warnings --- R/tm_missing_data.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 99ae13a81..11f008c76 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1140,7 +1140,7 @@ srv_missing_data <- function(id, dev_ggplot2_args <- teal.widgets::ggplot2_args( labs = list( fill = if (input$count_type == "counts") "Missing counts" else "Missing percentage", - y = quote(ggplot2::element_blank()) + y = NULL ) ) @@ -1252,7 +1252,7 @@ srv_missing_data <- function(id, dev_ggplot2_args <- teal.widgets::ggplot2_args( labs = list(x = NULL, y = NULL), - theme = list(legend.position = "bottom", axis.text.x =NULL) + theme = list(legend.position = "bottom", axis.text.x = NULL) ) all_ggplot2_args <- teal.widgets::resolve_ggplot2_args( From fed8c46c0fb797fc0f6fe69bdeac3e3bf1188306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Fri, 17 Oct 2025 16:57:56 +0200 Subject: [PATCH 15/60] Check feedback from copilot --- R/tm_missing_data.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 11f008c76..b316bae63 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -316,7 +316,7 @@ ui_missing_data <- function(id, by_subject_plot = FALSE) { ), tabPanel( "By Variable Levels", - teal.widgets::plot_with_settings_ui(id = ns("by_variable_plot")), + teal.widgets::plot_with_settings_ui(id = ns("by_variable_plot")) ) ) if (isTRUE(by_subject_plot)) { @@ -1065,7 +1065,7 @@ srv_missing_data <- function(id, # extract the ANL dataset for use in further validation anl <- common_code_q()[["ANL"]] - group_var <- req(input$group_by_var) + group_var <- input$group_by_var validate( need( is.null(group_var) || From 6d71798fa9b0de0b6912d77924a5acc9a07c7b13 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:44:20 +0000 Subject: [PATCH 16/60] [skip style] [skip vbump] Restyle files --- R/tm_missing_data.R | 141 ++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index b316bae63..52c86ccf4 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1159,85 +1159,84 @@ srv_missing_data <- function(id, labels <- lapply(qenv$ANL, attr, which = "label") if (!any(lengths(labels))) { ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals ) tile <- within(ANL_q, - { - by_variable_plot <- ggplot(ANL, aes(group_var_name, name)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white" - ) + - scale_x_discrete(expand = expansion()) + - scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + - labs + - ggthemes - }, - group_var_name = as.name(group_var), - column = if (input$count_type == "counts") { - as.name("value") - } else { - as.name("perc") - }, - labs = parsed_ggplot2_args$labs, - labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), - ggthemes = parsed_ggplot2_args$ggtheme + { + by_variable_plot <- ggplot(ANL, aes(group_var_name, name)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white" + ) + + scale_x_discrete(expand = expansion()) + + scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + labs + + ggthemes + }, + group_var_name = as.name(group_var), + column = if (input$count_type == "counts") { + as.name("value") + } else { + as.name("perc") + }, + labs = parsed_ggplot2_args$labs, + labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), + ggthemes = parsed_ggplot2_args$ggtheme ) - } else { ANL_q <- within(qenv, # nolint object_name_linter - { - keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) - ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% - mutate(label = labels[name]) - }, - keys = join_keys(qenv) |> unlist() |> unique(), - group_var_name = as.name(group_var), - group_var = group_var, - group_vals = group_vals + { + keep_columns <- intersect(c(keys, group_var), colnames(ANL)) + labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) + ANL <- ANL %>% + filter(group_var_name %in% group_vals) %>% + pivot_longer(-keep_columns, values_transform = is.na) %>% + summarise( + .by = c(group_var_name, name), + value = sum(value), perc = value / n() + ) %>% + mutate(label = labels[name]) + }, + keys = join_keys(qenv) |> unlist() |> unique(), + group_var_name = as.name(group_var), + group_var = group_var, + group_vals = group_vals ) tile <- within(ANL_q, - { - by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white" - ) + - scale_x_discrete(expand = expansion()) + - scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + - labs + - ggthemes - }, - group_var_name = as.name(group_var), - column = if (input$count_type == "counts") { - as.name("value") - } else { - as.name("perc") - }, - labs = parsed_ggplot2_args$labs, - labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), - ggthemes = parsed_ggplot2_args$ggtheme + { + by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + + geom_tile(aes(fill = column)) + + geom_text(aes(label = scales::percent(perc)), + data = . %>% filter(perc > 0), color = "white" + ) + + scale_x_discrete(expand = expansion()) + + scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + labs + + ggthemes + }, + group_var_name = as.name(group_var), + column = if (input$count_type == "counts") { + as.name("value") + } else { + as.name("perc") + }, + labs = parsed_ggplot2_args$labs, + labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), + ggthemes = parsed_ggplot2_args$ggtheme ) } From 22faabd501becd320bf20992d205dffafe5c1f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 10:55:23 +0200 Subject: [PATCH 17/60] Fix misspelling on linters --- R/tm_g_association.R | 4 ++-- R/tm_g_response.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/tm_g_association.R b/R/tm_g_association.R index e088f42c4..67e5c5c4b 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -151,8 +151,8 @@ tm_g_association <- function(label = "Association", show_association = TRUE, plot_height = c(600, 400, 5000), plot_width = NULL, - distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_lintr. - association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_lintr. + distribution_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_linter. + association_theme = c("gray", "bw", "linedraw", "light", "dark", "minimal", "classic", "void"), # nolint line_length_linter. pre_output = NULL, post_output = NULL, ggplot2_args = teal.widgets::ggplot2_args(), diff --git a/R/tm_g_response.R b/R/tm_g_response.R index 6ec1650f4..6871565ac 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -520,7 +520,7 @@ srv_g_response <- function(id, resp_cl = resp_cl, hjust_value = if (swap_axes) "left" else "middle", vjust_value = if (swap_axes) "middle" else -1, - position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint line_length_lintr + position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint line_length_linter anl3_y = if (!freq) 1.1 else as.name("ns"), position_anl3_value = if (!freq) "fill" else "stack" ) From 3cb8e61b28127bfe7415c10ed63deb078e23b4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 10:56:04 +0200 Subject: [PATCH 18/60] Fix style --- R/tm_outliers.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/R/tm_outliers.R b/R/tm_outliers.R index 235b93d89..2d75ba0fd 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -738,9 +738,10 @@ srv_outliers <- function(id, data, outlier_var, categorical_var_name = as.name(categorical_var) ) ) - ) |> within({ - table <- rtables::df_to_tt(summary_data) - table + ) |> + within({ + table <- rtables::df_to_tt(summary_data) + table }) } else { msg <- "No categorical variable selected, summary table cannot be created." From 463f61e88eff2db38ae42a83e623386e2b44d52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 11:54:30 +0200 Subject: [PATCH 19/60] Do not reduce the timeout from the default 4s --- tests/testthat/test-shinytest2-tm_misssing_data.R | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testthat/test-shinytest2-tm_misssing_data.R b/tests/testthat/test-shinytest2-tm_misssing_data.R index 73d602f2b..a8b1628b0 100644 --- a/tests/testthat/test-shinytest2-tm_misssing_data.R +++ b/tests/testthat/test-shinytest2-tm_misssing_data.R @@ -32,7 +32,6 @@ app_driver_tm_missing_data <- function() { post_output = NULL ) ), - timeout = 3000, seed = 1 ) } From b576f8eab93bec2a9806bebb1331df0209eaa615 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:57:42 +0000 Subject: [PATCH 20/60] [skip style] [skip vbump] Restyle files --- R/tm_outliers.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_outliers.R b/R/tm_outliers.R index 2d75ba0fd..e53f021f4 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -742,7 +742,7 @@ srv_outliers <- function(id, data, outlier_var, within({ table <- rtables::df_to_tt(summary_data) table - }) + }) } else { msg <- "No categorical variable selected, summary table cannot be created." showNotification(msg, From 3696675ce155af39f6b8ea9321aff3ea2ecb8fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 13:01:58 +0200 Subject: [PATCH 21/60] Fix typo --- ...ta.R => test-shinytest2-tm_missing_data.R} | 72 ++++++++++++------- 1 file changed, 45 insertions(+), 27 deletions(-) rename tests/testthat/{test-shinytest2-tm_misssing_data.R => test-shinytest2-tm_missing_data.R} (67%) diff --git a/tests/testthat/test-shinytest2-tm_misssing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R similarity index 67% rename from tests/testthat/test-shinytest2-tm_misssing_data.R rename to tests/testthat/test-shinytest2-tm_missing_data.R index a8b1628b0..58f61a88c 100644 --- a/tests/testthat/test-shinytest2-tm_misssing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -14,37 +14,43 @@ app_driver_tm_missing_data <- function() { }) init_teal_app_driver( - teal::init( - data = data, - modules = tm_missing_data( - label = "Missing data", - plot_height = c(600, 400, 5000), - plot_width = NULL, - datanames = "all", - ggtheme = "gray", - ggplot2_args = list( - "Combinations Hist" = teal.widgets::ggplot2_args( - labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) - ), - "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) + data = data, + modules = tm_missing_data( + label = "Missing data", + plot_height = c(600, 400, 5000), + plot_width = NULL, + datanames = "all", + ggtheme = "gray", + ggplot2_args = list( + "Combinations Hist" = teal.widgets::ggplot2_args( + labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) ), - pre_output = NULL, - post_output = NULL - ) + "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) + ), + pre_output = NULL, + post_output = NULL ), + timeout = 3000, seed = 1 ) } test_that("e2e - tm_missing_data: Initializes without errors", { + testthat::skip("chromium") skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() app_driver$expect_no_shiny_error() - testthat::expect_equal(app_driver$get_text(".teal-modules-tree .active"), "Missing data") + testthat::expect_equal( + app_driver$get_text("#teal-teal_modules-active_tab .active"), + "Missing data" + ) + + encoding_dataset <- app_driver$get_text( + app_driver$active_module_element("dataset_encodings .help-block") + ) - encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) @@ -52,6 +58,7 @@ test_that("e2e - tm_missing_data: Initializes without errors", { }) test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { + testthat::skip("chromium") skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # default summary tab @@ -65,15 +72,18 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary c("Petal.Length", "Sepal.Length", "Petal.Width", "Species", "Sepal.Width") ) - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-filter_na")) + app_driver$click(selector = app_driver$active_module_element("iris-filter_na")) app_driver$expect_no_validation_error() - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) + app_driver$click(selector = app_driver$active_module_element("iris-any_na")) app_driver$expect_no_validation_error() testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") + sprintf( + "%s .shiny-plot-output", + app_driver$active_module_element("iris-summary_plot-plot_out_main") + ) ) ) @@ -81,6 +91,7 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary }) test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { + testthat::skip("chromium") skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() @@ -92,7 +103,10 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c app_driver$expect_no_validation_error() testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") + sprintf( + "%s .shiny-plot-output", + app_driver$active_module_element("iris-combination_plot-plot_out_main") + ) ) ) @@ -100,19 +114,22 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") + sprintf( + "%s .shiny-input-container", + app_driver$active_module_element("iris-cutoff") + ) ) ) - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) + testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 2L) app_driver$set_active_module_input("iris-combination_cutoff", 10L) - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) app_driver$expect_no_validation_error() app_driver$stop() }) test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { + testthat::skip("chromium") skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # By variable levels @@ -137,17 +154,18 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By "counts" ) app_driver$set_active_module_input("iris-count_type", "proportions") - testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) + testthat::expect_true(app_driver$is_visible(app_driver$active_module_element("iris-levels_table"))) app_driver$stop() }) test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { + testthat::skip("chromium") skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% + levels_table <- app_driver$active_module_element("iris-levels_table") %>% app_driver$get_html_rvest() %>% rvest::html_table(fill = TRUE) %>% .[[1]] From 949a35b0754f8cf28436ff2cbf5020fcec596073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 14:40:04 +0200 Subject: [PATCH 22/60] Avoid skipping tests --- .../test-shinytest2-tm_missing_data.R | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index 58f61a88c..605151cf2 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -14,21 +14,23 @@ app_driver_tm_missing_data <- function() { }) init_teal_app_driver( - data = data, - modules = tm_missing_data( - label = "Missing data", - plot_height = c(600, 400, 5000), - plot_width = NULL, - datanames = "all", - ggtheme = "gray", - ggplot2_args = list( - "Combinations Hist" = teal.widgets::ggplot2_args( - labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) + app = init( + data = data, + modules = tm_missing_data( + label = "Missing data", + plot_height = c(600, 400, 5000), + plot_width = NULL, + datanames = "all", + ggtheme = "gray", + ggplot2_args = list( + "Combinations Hist" = teal.widgets::ggplot2_args( + labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) + ), + "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) ), - "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) - ), - pre_output = NULL, - post_output = NULL + pre_output = NULL, + post_output = NULL + ) ), timeout = 3000, seed = 1 @@ -36,14 +38,15 @@ app_driver_tm_missing_data <- function() { } test_that("e2e - tm_missing_data: Initializes without errors", { - testthat::skip("chromium") + skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() app_driver$expect_no_shiny_error() + testthat::expect_equal( - app_driver$get_text("#teal-teal_modules-active_tab .active"), + app_driver$get_text(selector = "#teal-teal_modules-active_module_id > div.dropdown.nav-item-custom > div > ul > li > ul > li > a"), "Missing data" ) @@ -58,7 +61,7 @@ test_that("e2e - tm_missing_data: Initializes without errors", { }) test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { - testthat::skip("chromium") + skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # default summary tab @@ -91,7 +94,7 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary }) test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { - testthat::skip("chromium") + skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() @@ -129,7 +132,7 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c }) test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { - testthat::skip("chromium") + skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # By variable levels @@ -160,7 +163,7 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By }) test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { - testthat::skip("chromium") + skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() From ed17c6b427602f7dfb9568dd70736d39cf651989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Mon, 20 Oct 2025 14:53:23 +0200 Subject: [PATCH 23/60] Update code based on https://github.com/insightsengineering/teal.modules.general/pull/927 --- .../test-shinytest2-tm_missing_data.R | 43 +++++-------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index 605151cf2..4847feeb3 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -38,22 +38,13 @@ app_driver_tm_missing_data <- function() { } test_that("e2e - tm_missing_data: Initializes without errors", { - skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() app_driver$expect_no_shiny_error() + testthat::expect_equal(app_driver$get_text(".teal-modules-tree .active"), "Missing data") - - testthat::expect_equal( - app_driver$get_text(selector = "#teal-teal_modules-active_module_id > div.dropdown.nav-item-custom > div > ul > li > ul > li > a"), - "Missing data" - ) - - encoding_dataset <- app_driver$get_text( - app_driver$active_module_element("dataset_encodings .help-block") - ) - + encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) @@ -61,7 +52,6 @@ test_that("e2e - tm_missing_data: Initializes without errors", { }) test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { - skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # default summary tab @@ -75,18 +65,15 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary c("Petal.Length", "Sepal.Length", "Petal.Width", "Species", "Sepal.Width") ) - app_driver$click(selector = app_driver$active_module_element("iris-filter_na")) + app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-filter_na")) app_driver$expect_no_validation_error() - app_driver$click(selector = app_driver$active_module_element("iris-any_na")) + app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) app_driver$expect_no_validation_error() testthat::expect_true( app_driver$is_visible( - sprintf( - "%s .shiny-plot-output", - app_driver$active_module_element("iris-summary_plot-plot_out_main") - ) + app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") ) ) @@ -94,7 +81,6 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary }) test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { - skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() @@ -106,10 +92,7 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c app_driver$expect_no_validation_error() testthat::expect_true( app_driver$is_visible( - sprintf( - "%s .shiny-plot-output", - app_driver$active_module_element("iris-combination_plot-plot_out_main") - ) + app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") ) ) @@ -117,22 +100,19 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c testthat::expect_true( app_driver$is_visible( - sprintf( - "%s .shiny-input-container", - app_driver$active_module_element("iris-cutoff") - ) + app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") ) ) - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 2L) + testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) app_driver$set_active_module_input("iris-combination_cutoff", 10L) + testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) app_driver$expect_no_validation_error() app_driver$stop() }) test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { - skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() # By variable levels @@ -157,18 +137,17 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By "counts" ) app_driver$set_active_module_input("iris-count_type", "proportions") - testthat::expect_true(app_driver$is_visible(app_driver$active_module_element("iris-levels_table"))) + testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) app_driver$stop() }) test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { - skip_if_too_deep(5) app_driver <- app_driver_tm_missing_data() app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - levels_table <- app_driver$active_module_element("iris-levels_table") %>% + levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% app_driver$get_html_rvest() %>% rvest::html_table(fill = TRUE) %>% .[[1]] From 188fa05db5b5e7e0db1bb2b6d2b2fe31c7000059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Tue, 21 Oct 2025 10:01:59 +0200 Subject: [PATCH 24/60] Add req to resolve the app faster --- R/tm_missing_data.R | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 52c86ccf4..7771054e3 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -230,6 +230,7 @@ srv_page_missing_data <- function(id, data, datanames, parent_dataname, }) output$dataset_encodings <- renderUI({ + req(ggtheme, datanames, is.logical(if_subject_plot)) tagList( lapply( datanames, @@ -453,6 +454,7 @@ srv_missing_data <- function(id, data_keys <- reactive(unlist(teal.data::join_keys(data())[[dataname]])) iv_r <- reactive({ + iv <- shinyvalidate::InputValidator$new() iv$add_rule( "variables_select", @@ -487,6 +489,7 @@ srv_missing_data <- function(id, }) data_parent_keys <- reactive({ + req(data(), parent_dataname) if (length(parent_dataname) > 0 && parent_dataname %in% names(data())) { keys <- teal.data::join_keys(data())[[dataname]] if (parent_dataname %in% names(keys)) { @@ -501,7 +504,7 @@ srv_missing_data <- function(id, common_code_q <- reactive({ teal::validate_inputs(iv_r()) - + req(data(), data_r(), input$summary_type) group_var <- input$group_by_var anl <- data_r() obj <- data() @@ -567,13 +570,14 @@ srv_missing_data <- function(id, }) selected_vars <- reactive({ - req(input$variables_select) + req(data_keys(), input$variables_select) keys <- data_keys() vars <- unique(c(keys, input$variables_select)) vars }) vars_summary <- reactive({ + req(data_r()) na_count <- data_r() %>% sapply(function(x) mean(is.na(x)), USE.NAMES = TRUE) %>% sort(decreasing = TRUE) @@ -587,6 +591,7 @@ srv_missing_data <- function(id, # Keep encoding panel up-to-date output$variables <- renderUI({ + req(vars_summary(), data_r()) choices <- split(x = vars_summary()$key, f = vars_summary()$label, drop = TRUE) %>% rev() selected <- choices <- unname(unlist(choices)) @@ -601,6 +606,7 @@ srv_missing_data <- function(id, }) observeEvent(input$filter_na, { + req(vars_summary(), data_r()) choices <- vars_summary() %>% dplyr::select(!!as.name("key")) %>% getElement(name = 1) @@ -619,6 +625,7 @@ srv_missing_data <- function(id, }) output$group_by_var_ui <- renderUI({ + req(data_r()) all_choices <- teal.transform::variable_choices(data_r()) cat_choices <- all_choices[!sapply(data_r(), function(x) is.numeric(x) || inherits(x, "POSIXct"))] validate( @@ -639,10 +646,10 @@ srv_missing_data <- function(id, }) output$group_by_vals_ui <- renderUI({ - req(input$group_by_var) + req(isolate(prev_group_by_var()), input$group_by_var, data_r()) choices <- teal.transform::value_choices(data_r(), input$group_by_var, input$group_by_var) - prev_choices <- isolate(input$group_by_vals) + prev_choices <- req(isolate(input$group_by_vals)) # determine selected value based on filtered data # display those previously selected values that are still available @@ -675,8 +682,8 @@ srv_missing_data <- function(id, }) combination_cutoff_q <- reactive({ - req(common_code_q()) - qenv <- common_code_q() + + qenv <- req(common_code_q()) teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "### Combination Plot") teal.code::eval_code( qenv, @@ -691,6 +698,7 @@ srv_missing_data <- function(id, }) output$cutoff <- renderUI({ + req(combination_cutoff_q()) x <- combination_cutoff_q()[["combination_cutoff"]]$n # select 10-th from the top @@ -714,9 +722,9 @@ srv_missing_data <- function(id, summary_plot_q <- reactive({ req(input$summary_type == "Summary") # needed to trigger update on tab change - teal::validate_has_data(data_r(), 1) - - qenv <- common_code_q() + teal::validate_has_data(req(data_r()), 1) + req(data_keys(), input$ggtheme) + qenv <- req(common_code_q()) if (input$any_na) { new_col_name <- "**anyna**" qenv <- teal.code::eval_code( @@ -765,7 +773,7 @@ srv_missing_data <- function(id, ) # always set "**anyna**" level as the last one - if (isolate(input$any_na)) { + if (req(isolate(input$any_na))) { qenv <- teal.code::eval_code( qenv, quote(x_levels <- c(setdiff(x_levels, "**anyna**"), "**anyna**")) @@ -921,8 +929,9 @@ srv_missing_data <- function(id, }) combination_plot_q <- reactive({ - req(input$summary_type == "Combinations", input$combination_cutoff, combination_cutoff_q()) - teal::validate_has_data(data_r(), 1) + req(input$summary_type == "Combinations", input$combination_cutoff, + combination_cutoff_q(), data_keys(), input$ggtheme) + teal::validate_has_data(req(data_r()), 1) qenv <- teal.code::eval_code( combination_cutoff_q(), @@ -1060,7 +1069,7 @@ srv_missing_data <- function(id, input$summary_type == "By Variable Levels", # needed to trigger update on tab change common_code_q() ) - teal::validate_has_data(data_r(), 1) + teal::validate_has_data(req(data_r()), 1) # extract the ANL dataset for use in further validation anl <- common_code_q()[["ANL"]] @@ -1091,7 +1100,7 @@ srv_missing_data <- function(id, function(x) round(sum(is.na(x)) / length(x), 4) } - qenv <- common_code_q() + qenv <- req(common_code_q()) teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "### Summary Table") qenv <- if (!is.null(group_var)) { @@ -1245,9 +1254,10 @@ srv_missing_data <- function(id, by_subject_plot_q <- reactive({ # needed to trigger update on tab change - req(input$summary_type == "Grouped by Subject", common_code_q()) + req(input$summary_type == "Grouped by Subject", common_code_q(), + input$ggtheme) - teal::validate_has_data(data_r(), 1) + teal::validate_has_data(req(data_r()), 1) dev_ggplot2_args <- teal.widgets::ggplot2_args( labs = list(x = NULL, y = NULL), @@ -1272,7 +1282,7 @@ srv_missing_data <- function(id, function(x) paste(as.integer(x), collapse = "") } - qenv <- common_code_q() + qenv <- req(common_code_q()) teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "### By Subject Plot") qenv <- teal.code::eval_code( From f1a180bff568638bc36e21b5c550c5f8ee414cc6 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 08:05:23 +0000 Subject: [PATCH 25/60] [skip style] [skip vbump] Restyle files --- R/tm_missing_data.R | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 7771054e3..00008cad8 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -454,7 +454,6 @@ srv_missing_data <- function(id, data_keys <- reactive(unlist(teal.data::join_keys(data())[[dataname]])) iv_r <- reactive({ - iv <- shinyvalidate::InputValidator$new() iv$add_rule( "variables_select", @@ -682,7 +681,6 @@ srv_missing_data <- function(id, }) combination_cutoff_q <- reactive({ - qenv <- req(common_code_q()) teal.reporter::teal_card(qenv) <- c(teal.reporter::teal_card(qenv), "### Combination Plot") teal.code::eval_code( @@ -929,8 +927,10 @@ srv_missing_data <- function(id, }) combination_plot_q <- reactive({ - req(input$summary_type == "Combinations", input$combination_cutoff, - combination_cutoff_q(), data_keys(), input$ggtheme) + req( + input$summary_type == "Combinations", input$combination_cutoff, + combination_cutoff_q(), data_keys(), input$ggtheme + ) teal::validate_has_data(req(data_r()), 1) qenv <- teal.code::eval_code( @@ -1254,8 +1254,10 @@ srv_missing_data <- function(id, by_subject_plot_q <- reactive({ # needed to trigger update on tab change - req(input$summary_type == "Grouped by Subject", common_code_q(), - input$ggtheme) + req( + input$summary_type == "Grouped by Subject", common_code_q(), + input$ggtheme + ) teal::validate_has_data(req(data_r()), 1) From 1006fa9660eb65a62680c3408909650b6e987ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Tue, 21 Oct 2025 11:20:06 +0200 Subject: [PATCH 26/60] Prefix functions with their packages --- R/tm_missing_data.R | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 00008cad8..b5ab5a012 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1185,13 +1185,13 @@ srv_missing_data <- function(id, ) tile <- within(ANL_q, { - by_variable_plot <- ggplot(ANL, aes(group_var_name, name)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white" + by_variable_plot <- ggplo2::ggplot(ANL, ggplo2::aes(group_var_name, name)) + + ggplo2::geom_tile(ggplo2::aes(fill = column)) + + ggplo2::geom_text(ggplo2::aes(label = scales::percent(perc)), + data = . %>% dplyr::filter(perc > 0), color = "white" ) + - scale_x_discrete(expand = expansion()) + - scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + ggplo2::scale_x_discrete(expand = ggplo2::expansion()) + + ggplo2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + labs + ggthemes }, @@ -1211,13 +1211,13 @@ srv_missing_data <- function(id, keep_columns <- intersect(c(keys, group_var), colnames(ANL)) labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) ANL <- ANL %>% - filter(group_var_name %in% group_vals) %>% - pivot_longer(-keep_columns, values_transform = is.na) %>% - summarise( + dplyr::filter(group_var_name %in% group_vals) %>% + dplyr::pivot_longer(-keep_columns, values_transform = is.na) %>% + dplyr::summarise( .by = c(group_var_name, name), value = sum(value), perc = value / n() ) %>% - mutate(label = labels[name]) + dplyr::mutate(label = labels[name]) }, keys = join_keys(qenv) |> unlist() |> unique(), group_var_name = as.name(group_var), @@ -1227,13 +1227,13 @@ srv_missing_data <- function(id, tile <- within(ANL_q, { - by_variable_plot <- ggplot(ANL, aes(group_var_name, label)) + - geom_tile(aes(fill = column)) + - geom_text(aes(label = scales::percent(perc)), - data = . %>% filter(perc > 0), color = "white" + by_variable_plot <- ggplo2::ggplot(ANL, ggplo2::aes(group_var_name, label)) + + ggplo2::geom_tile(ggplo2::aes(fill = column)) + + ggplo2::geom_text(ggplo2::aes(label = scales::percent(perc)), + data = . %>% dplyr::filter(perc > 0), color = "white" ) + - scale_x_discrete(expand = expansion()) + - scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + ggplo2::scale_x_discrete(expand = ggplo2::expansion()) + + ggplo2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + labs + ggthemes }, From 8a311f1b551a1f802894040df5ff9d19cf443b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Tue, 21 Oct 2025 12:02:26 +0200 Subject: [PATCH 27/60] Fix typo --- R/tm_missing_data.R | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index b5ab5a012..8c84409af 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1185,13 +1185,13 @@ srv_missing_data <- function(id, ) tile <- within(ANL_q, { - by_variable_plot <- ggplo2::ggplot(ANL, ggplo2::aes(group_var_name, name)) + - ggplo2::geom_tile(ggplo2::aes(fill = column)) + - ggplo2::geom_text(ggplo2::aes(label = scales::percent(perc)), + by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, name)) + + ggplot2::geom_tile(ggplot2::aes(fill = column)) + + ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), data = . %>% dplyr::filter(perc > 0), color = "white" ) + - ggplo2::scale_x_discrete(expand = ggplo2::expansion()) + - ggplo2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + + ggplot2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + labs + ggthemes }, @@ -1227,13 +1227,13 @@ srv_missing_data <- function(id, tile <- within(ANL_q, { - by_variable_plot <- ggplo2::ggplot(ANL, ggplo2::aes(group_var_name, label)) + - ggplo2::geom_tile(ggplo2::aes(fill = column)) + - ggplo2::geom_text(ggplo2::aes(label = scales::percent(perc)), + by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, label)) + + ggplot2::geom_tile(ggplot2::aes(fill = column)) + + ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), data = . %>% dplyr::filter(perc > 0), color = "white" ) + - ggplo2::scale_x_discrete(expand = ggplo2::expansion()) + - ggplo2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + + ggplot2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + labs + ggthemes }, From 5b4226a77bb90c53eef178f358d576cc543bbaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= Date: Tue, 21 Oct 2025 12:55:43 +0200 Subject: [PATCH 28/60] Fix package --- R/tm_missing_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 8c84409af..0de1fdb05 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1212,7 +1212,7 @@ srv_missing_data <- function(id, labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) ANL <- ANL %>% dplyr::filter(group_var_name %in% group_vals) %>% - dplyr::pivot_longer(-keep_columns, values_transform = is.na) %>% + tidyr::pivot_longer(-keep_columns, values_transform = is.na) %>% dplyr::summarise( .by = c(group_var_name, name), value = sum(value), perc = value / n() From 4b6e86797ff5e65f12de28611a43c436496166d9 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 12:31:24 +0000 Subject: [PATCH 29/60] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/tm_a_pca.Rd | 16 ++++++++++++++++ man/tm_a_regression.Rd | 16 ++++++++++++++++ man/tm_g_association.Rd | 16 ++++++++++++++++ man/tm_g_bivariate.Rd | 16 ++++++++++++++++ man/tm_g_distribution.Rd | 16 ++++++++++++++++ man/tm_g_response.Rd | 16 ++++++++++++++++ man/tm_g_scatterplot.Rd | 16 ++++++++++++++++ man/tm_g_scatterplotmatrix.Rd | 16 ++++++++++++++++ man/tm_missing_data.Rd | 16 ++++++++++++++++ man/tm_outliers.Rd | 16 ++++++++++++++++ man/tm_t_crosstable.Rd | 16 ++++++++++++++++ 11 files changed, 176 insertions(+) diff --git a/man/tm_a_pca.Rd b/man/tm_a_pca.Rd index 2fdfdf650..eae1bd9c0 100644 --- a/man/tm_a_pca.Rd +++ b/man/tm_a_pca.Rd @@ -125,6 +125,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example diff --git a/man/tm_a_regression.Rd b/man/tm_a_regression.Rd index 37a215e71..1afc5260d 100644 --- a/man/tm_a_regression.Rd +++ b/man/tm_a_regression.Rd @@ -147,6 +147,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example diff --git a/man/tm_g_association.Rd b/man/tm_g_association.Rd index 9e651dc70..86ae13618 100644 --- a/man/tm_g_association.Rd +++ b/man/tm_g_association.Rd @@ -107,6 +107,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_g_bivariate.Rd b/man/tm_g_bivariate.Rd index 09fd2e2d2..3eea66e7f 100644 --- a/man/tm_g_bivariate.Rd +++ b/man/tm_g_bivariate.Rd @@ -154,6 +154,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_g_distribution.Rd b/man/tm_g_distribution.Rd index 5f5058bf2..798ef0a2a 100644 --- a/man/tm_g_distribution.Rd +++ b/man/tm_g_distribution.Rd @@ -112,6 +112,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_g_response.Rd b/man/tm_g_response.Rd index 2a617112a..b25330676 100644 --- a/man/tm_g_response.Rd +++ b/man/tm_g_response.Rd @@ -135,6 +135,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_g_scatterplot.Rd b/man/tm_g_scatterplot.Rd index 556c87b34..13b41566e 100644 --- a/man/tm_g_scatterplot.Rd +++ b/man/tm_g_scatterplot.Rd @@ -146,6 +146,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_g_scatterplotmatrix.Rd b/man/tm_g_scatterplotmatrix.Rd index f90d7cf52..ba9c4c3d9 100644 --- a/man/tm_g_scatterplotmatrix.Rd +++ b/man/tm_g_scatterplotmatrix.Rd @@ -86,6 +86,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() diff --git a/man/tm_missing_data.Rd b/man/tm_missing_data.Rd index 1b9543d2f..cbb7b82fa 100644 --- a/man/tm_missing_data.Rd +++ b/man/tm_missing_data.Rd @@ -110,6 +110,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general example data data <- teal_data() diff --git a/man/tm_outliers.Rd b/man/tm_outliers.Rd index a355b1d97..2699a457f 100644 --- a/man/tm_outliers.Rd +++ b/man/tm_outliers.Rd @@ -98,6 +98,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example diff --git a/man/tm_t_crosstable.Rd b/man/tm_t_crosstable.Rd index 0682c348b..6c2b051be 100644 --- a/man/tm_t_crosstable.Rd +++ b/man/tm_t_crosstable.Rd @@ -115,6 +115,22 @@ To learn more please refer to the vignette \code{vignette("transform-module-output", package = "teal")} or the \code{\link[teal:teal_transform_module]{teal::teal_transform_module()}} documentation. } +\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("reportable-shiny-application", package = "teal.reporter")} +\item \code{vignette("adding-support-for-reporting-to-custom-modules", package = "teal")} +} + +} + \examples{ # general data example data <- teal_data() From 8845ead768e53b4404aa52239f7014f0d01de4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Fri, 21 Nov 2025 12:57:39 +0100 Subject: [PATCH 30/60] Test CI changes --- .github/workflows/check.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index c4cda93c0..b940fce25 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -21,7 +21,7 @@ jobs: uses: insightsengineering/r.pkg.template/.github/workflows/audit.yaml@main r-cmd: name: R CMD Check 🧬 - uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main + uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@skip_missing_files secrets: REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} with: @@ -46,7 +46,7 @@ jobs: selected-shinytests: true r-cmd-non-cran: name: R CMD Check (non-CRAN) 🧬 - uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main + uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@skip_missing_files secrets: REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} with: From ef5997189e275ce34e60bb7a52195293022164e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:35:44 +0000 Subject: [PATCH 31/60] ci: test ci and revert in the next commit --- ...ata.R => test-shinytest2-tm_missing_data_remove_this_suffix.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-shinytest2-tm_missing_data.R => test-shinytest2-tm_missing_data_remove_this_suffix.R} (100%) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R similarity index 100% rename from tests/testthat/test-shinytest2-tm_missing_data.R rename to tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R From 1732dfd84d2d46da6d4cb6c86f9af015252837bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:47:42 +0100 Subject: [PATCH 32/60] Update R/tm_g_association.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_g_association.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_g_association.R b/R/tm_g_association.R index 67e5c5c4b..aadaee5e2 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -345,7 +345,7 @@ srv_tm_g_association <- function(id, teal.reporter::teal_card(obj), teal.reporter::teal_card("## Module's output(s)") ) - teal.code::eval_code(obj, "library(ggplot2);library(dplyr);library(ggmosaic)") + teal.code::eval_code(obj, "library(ggplot2);library(dplyr)") }) anl_merged_q <- reactive({ req(anl_merged_input()) From 7329984edca8fbed286542ccb804659d757aa2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:00:14 +0000 Subject: [PATCH 33/60] adds new file to remove later --- tests/testthat/test-shinytest2-yada.R | 161 ++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 tests/testthat/test-shinytest2-yada.R diff --git a/tests/testthat/test-shinytest2-yada.R b/tests/testthat/test-shinytest2-yada.R new file mode 100644 index 000000000..4847feeb3 --- /dev/null +++ b/tests/testthat/test-shinytest2-yada.R @@ -0,0 +1,161 @@ +app_driver_tm_missing_data <- function() { + data <- within(simple_teal_data(), { + set.seed(123) + + add_nas <- function(x) { + x[sample(seq_along(x), floor(length(x) * runif(1, .05, .17)))] <- NA + x + } + + iris[] <- lapply(iris, add_nas) + mtcars[] <- lapply(mtcars, add_nas) + mtcars[["cyl"]] <- as.factor(mtcars[["cyl"]]) + mtcars[["gear"]] <- as.factor(mtcars[["gear"]]) + }) + + init_teal_app_driver( + app = init( + data = data, + modules = tm_missing_data( + label = "Missing data", + plot_height = c(600, 400, 5000), + plot_width = NULL, + datanames = "all", + ggtheme = "gray", + ggplot2_args = list( + "Combinations Hist" = teal.widgets::ggplot2_args( + labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) + ), + "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) + ), + pre_output = NULL, + post_output = NULL + ) + ), + timeout = 3000, + seed = 1 + ) +} + +test_that("e2e - tm_missing_data: Initializes without errors", { + skip_if_too_deep(5) + app_driver <- app_driver_tm_missing_data() + + app_driver$expect_no_shiny_error() + testthat::expect_equal(app_driver$get_text(".teal-modules-tree .active"), "Missing data") + + encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) + testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) + + + app_driver$stop() +}) + +test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { + skip_if_too_deep(5) + app_driver <- app_driver_tm_missing_data() + # default summary tab + testthat::expect_equal( + app_driver$get_active_module_input("iris-summary_type"), + "Summary" + ) + + testthat::expect_setequal( + app_driver$get_active_module_input("iris-variables_select"), + c("Petal.Length", "Sepal.Length", "Petal.Width", "Species", "Sepal.Width") + ) + + app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-filter_na")) + app_driver$expect_no_validation_error() + + app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) + app_driver$expect_no_validation_error() + + testthat::expect_true( + app_driver$is_visible( + app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") + ) + ) + + app_driver$stop() +}) + +test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { + skip_if_too_deep(5) + app_driver <- app_driver_tm_missing_data() + + app_driver$expect_no_shiny_error() + + # combination graph + + app_driver$set_active_module_input("iris-summary_type", "Combinations") + app_driver$expect_no_validation_error() + testthat::expect_true( + app_driver$is_visible( + app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") + ) + ) + + # combination encoding + + testthat::expect_true( + app_driver$is_visible( + app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") + ) + ) + + testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) + app_driver$set_active_module_input("iris-combination_cutoff", 10L) + testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) + app_driver$expect_no_validation_error() + + app_driver$stop() +}) + +test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { + skip_if_too_deep(5) + app_driver <- app_driver_tm_missing_data() + # By variable levels + app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") + app_driver$expect_no_validation_error() + + + testthat::expect_equal( + app_driver$get_active_module_input("iris-group_by_var"), + "Species" + ) + testthat::expect_setequal( + app_driver$get_active_module_input("iris-group_by_vals"), + c("NA", "setosa", "versicolor", "virginica") + ) + + app_driver$set_active_module_input("iris-group_by_vals", c("versicolor", "virginica")) + app_driver$expect_no_validation_error() + + testthat::expect_equal( + app_driver$get_active_module_input("iris-count_type"), + "counts" + ) + app_driver$set_active_module_input("iris-count_type", "proportions") + testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) + + app_driver$stop() +}) + +test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { + skip_if_too_deep(5) + app_driver <- app_driver_tm_missing_data() + + app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") + levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% + app_driver$get_html_rvest() %>% + rvest::html_table(fill = TRUE) %>% + .[[1]] + + testthat::expect_setequal( + levels_table$Variable, + c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") + ) + + app_driver$stop() +}) From c13063f33d85adde3381dce788aa9d2837f26ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:03:58 +0000 Subject: [PATCH 34/60] chore: cleanup extra files and fix name --- ...ta.R => test-shinytest2-tm_missing_data.R} | 0 ...test2-tm_missing_data_remove_this_suffix.R | 161 ------------------ 2 files changed, 161 deletions(-) rename tests/testthat/{test-shinytest2-tm_misssing_data.R => test-shinytest2-tm_missing_data.R} (100%) delete mode 100644 tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R diff --git a/tests/testthat/test-shinytest2-tm_misssing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R similarity index 100% rename from tests/testthat/test-shinytest2-tm_misssing_data.R rename to tests/testthat/test-shinytest2-tm_missing_data.R diff --git a/tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R b/tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R deleted file mode 100644 index 4847feeb3..000000000 --- a/tests/testthat/test-shinytest2-tm_missing_data_remove_this_suffix.R +++ /dev/null @@ -1,161 +0,0 @@ -app_driver_tm_missing_data <- function() { - data <- within(simple_teal_data(), { - set.seed(123) - - add_nas <- function(x) { - x[sample(seq_along(x), floor(length(x) * runif(1, .05, .17)))] <- NA - x - } - - iris[] <- lapply(iris, add_nas) - mtcars[] <- lapply(mtcars, add_nas) - mtcars[["cyl"]] <- as.factor(mtcars[["cyl"]]) - mtcars[["gear"]] <- as.factor(mtcars[["gear"]]) - }) - - init_teal_app_driver( - app = init( - data = data, - modules = tm_missing_data( - label = "Missing data", - plot_height = c(600, 400, 5000), - plot_width = NULL, - datanames = "all", - ggtheme = "gray", - ggplot2_args = list( - "Combinations Hist" = teal.widgets::ggplot2_args( - labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) - ), - "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) - ), - pre_output = NULL, - post_output = NULL - ) - ), - timeout = 3000, - seed = 1 - ) -} - -test_that("e2e - tm_missing_data: Initializes without errors", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$expect_no_shiny_error() - testthat::expect_equal(app_driver$get_text(".teal-modules-tree .active"), "Missing data") - - encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) - testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) - - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - # default summary tab - testthat::expect_equal( - app_driver$get_active_module_input("iris-summary_type"), - "Summary" - ) - - testthat::expect_setequal( - app_driver$get_active_module_input("iris-variables_select"), - c("Petal.Length", "Sepal.Length", "Petal.Width", "Species", "Sepal.Width") - ) - - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-filter_na")) - app_driver$expect_no_validation_error() - - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) - app_driver$expect_no_validation_error() - - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") - ) - ) - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$expect_no_shiny_error() - - # combination graph - - app_driver$set_active_module_input("iris-summary_type", "Combinations") - app_driver$expect_no_validation_error() - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") - ) - ) - - # combination encoding - - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") - ) - ) - - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) - app_driver$set_active_module_input("iris-combination_cutoff", 10L) - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) - app_driver$expect_no_validation_error() - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - # By variable levels - app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - app_driver$expect_no_validation_error() - - - testthat::expect_equal( - app_driver$get_active_module_input("iris-group_by_var"), - "Species" - ) - testthat::expect_setequal( - app_driver$get_active_module_input("iris-group_by_vals"), - c("NA", "setosa", "versicolor", "virginica") - ) - - app_driver$set_active_module_input("iris-group_by_vals", c("versicolor", "virginica")) - app_driver$expect_no_validation_error() - - testthat::expect_equal( - app_driver$get_active_module_input("iris-count_type"), - "counts" - ) - app_driver$set_active_module_input("iris-count_type", "proportions") - testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% - app_driver$get_html_rvest() %>% - rvest::html_table(fill = TRUE) %>% - .[[1]] - - testthat::expect_setequal( - levels_table$Variable, - c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") - ) - - app_driver$stop() -}) From ad5c396a54215b6f5dacbcd29a92cd8b160cf0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 21 Nov 2025 18:31:56 +0000 Subject: [PATCH 35/60] chore: remove added file --- tests/testthat/test-shinytest2-yada.R | 161 -------------------------- 1 file changed, 161 deletions(-) delete mode 100644 tests/testthat/test-shinytest2-yada.R diff --git a/tests/testthat/test-shinytest2-yada.R b/tests/testthat/test-shinytest2-yada.R deleted file mode 100644 index 4847feeb3..000000000 --- a/tests/testthat/test-shinytest2-yada.R +++ /dev/null @@ -1,161 +0,0 @@ -app_driver_tm_missing_data <- function() { - data <- within(simple_teal_data(), { - set.seed(123) - - add_nas <- function(x) { - x[sample(seq_along(x), floor(length(x) * runif(1, .05, .17)))] <- NA - x - } - - iris[] <- lapply(iris, add_nas) - mtcars[] <- lapply(mtcars, add_nas) - mtcars[["cyl"]] <- as.factor(mtcars[["cyl"]]) - mtcars[["gear"]] <- as.factor(mtcars[["gear"]]) - }) - - init_teal_app_driver( - app = init( - data = data, - modules = tm_missing_data( - label = "Missing data", - plot_height = c(600, 400, 5000), - plot_width = NULL, - datanames = "all", - ggtheme = "gray", - ggplot2_args = list( - "Combinations Hist" = teal.widgets::ggplot2_args( - labs = list(subtitle = "Plot produced by Missing Data Module", caption = NULL) - ), - "Combinations Main" = teal.widgets::ggplot2_args(labs = list(title = NULL)) - ), - pre_output = NULL, - post_output = NULL - ) - ), - timeout = 3000, - seed = 1 - ) -} - -test_that("e2e - tm_missing_data: Initializes without errors", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$expect_no_shiny_error() - testthat::expect_equal(app_driver$get_text(".teal-modules-tree .active"), "Missing data") - - encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) - testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) - - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Default settings and visibility of the summary graph", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - # default summary tab - testthat::expect_equal( - app_driver$get_active_module_input("iris-summary_type"), - "Summary" - ) - - testthat::expect_setequal( - app_driver$get_active_module_input("iris-variables_select"), - c("Petal.Length", "Sepal.Length", "Petal.Width", "Species", "Sepal.Width") - ) - - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-filter_na")) - app_driver$expect_no_validation_error() - - app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) - app_driver$expect_no_validation_error() - - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") - ) - ) - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Check default settings and visibility of the combinations graph and encodings", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$expect_no_shiny_error() - - # combination graph - - app_driver$set_active_module_input("iris-summary_type", "Combinations") - app_driver$expect_no_validation_error() - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") - ) - ) - - # combination encoding - - testthat::expect_true( - app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") - ) - ) - - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) - app_driver$set_active_module_input("iris-combination_cutoff", 10L) - testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) - app_driver$expect_no_validation_error() - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By Variable Levels'", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - # By variable levels - app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - app_driver$expect_no_validation_error() - - - testthat::expect_equal( - app_driver$get_active_module_input("iris-group_by_var"), - "Species" - ) - testthat::expect_setequal( - app_driver$get_active_module_input("iris-group_by_vals"), - c("NA", "setosa", "versicolor", "virginica") - ) - - app_driver$set_active_module_input("iris-group_by_vals", c("versicolor", "virginica")) - app_driver$expect_no_validation_error() - - testthat::expect_equal( - app_driver$get_active_module_input("iris-count_type"), - "counts" - ) - app_driver$set_active_module_input("iris-count_type", "proportions") - testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) - - app_driver$stop() -}) - -test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% - app_driver$get_html_rvest() %>% - rvest::html_table(fill = TRUE) %>% - .[[1]] - - testthat::expect_setequal( - levels_table$Variable, - c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") - ) - - app_driver$stop() -}) From 31957c579d9bd333735352b32ed1223cf879c810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 24 Nov 2025 10:03:45 +0100 Subject: [PATCH 36/60] Remove mention to ggmosaic --- R/teal.modules.general.R | 6 ------ 1 file changed, 6 deletions(-) diff --git a/R/teal.modules.general.R b/R/teal.modules.general.R index 93de04c70..07e7cf03c 100644 --- a/R/teal.modules.general.R +++ b/R/teal.modules.general.R @@ -14,11 +14,5 @@ #' @keywords internal "_PACKAGE" -# nolint start. -# Note ggmosaic (version <= 0.3.3) needs to be in DEPENDS as the following does not work if it is imported -# df <- data.frame(x = c("A", "B", "C", "A"), y = c("Z", "Z", "W", "W")) -# ggplot(df) + ggmosaic::geom_mosaic(aes(x = ggmosaic::product(x), fill = y)) -# nolint end. - # Needed to avoid R CMD note on no visible binding utils::globalVariables("count") From d17b93bffdf2bd872e6d8443534eb69895014416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 24 Nov 2025 10:05:25 +0100 Subject: [PATCH 37/60] Remove extra dependency --- DESCRIPTION | 1 - 1 file changed, 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7497837c8..e8b381922 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -68,7 +68,6 @@ Imports: tools, utils Suggests: - formatters (>= 0.5.11), knitr (>= 1.42), logger (>= 0.4.0), nestcolor (>= 0.1.0), From 5626cc3f757dca8cf8f25339f0def7364b8747d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:08:51 +0100 Subject: [PATCH 38/60] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_g_response.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_g_response.R b/R/tm_g_response.R index 6871565ac..b5b2aef53 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -520,7 +520,7 @@ srv_g_response <- function(id, resp_cl = resp_cl, hjust_value = if (swap_axes) "left" else "middle", vjust_value = if (swap_axes) "middle" else -1, - position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint line_length_linter + position_anl2_value = if (!freq) quote(position_fill(0.5)) else quote(position_stack(0.5)), # nolint: line_length_linter. anl3_y = if (!freq) 1.1 else as.name("ns"), position_anl3_value = if (!freq) "fill" else "stack" ) From cd0880ac4ff3c1002244305c4ac394f867c1b0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 24 Nov 2025 10:58:30 +0100 Subject: [PATCH 39/60] Use main now that https://github.com/insightsengineering/r.pkg.template/pull/290/ was merged --- .github/workflows/check.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index b940fce25..c4cda93c0 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -21,7 +21,7 @@ jobs: uses: insightsengineering/r.pkg.template/.github/workflows/audit.yaml@main r-cmd: name: R CMD Check 🧬 - uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@skip_missing_files + uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main secrets: REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} with: @@ -46,7 +46,7 @@ jobs: selected-shinytests: true r-cmd-non-cran: name: R CMD Check (non-CRAN) 🧬 - uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@skip_missing_files + uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main secrets: REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} with: From 4bedaa30d350de15ba69a3ad128a5ae3bc8476b6 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:33:33 +0100 Subject: [PATCH 40/60] update insightsengineering/teal@bring_tests Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9ba78ad5d..ea814326c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -83,7 +83,7 @@ VignetteBuilder: knitr, rmarkdown Remotes: - insightsengineering/teal, + insightsengineering/teal@bring_tests, insightsengineering/teal.reporter Config/Needs/verdepcheck: haleyjeppson/ggmosaic, tidyverse/ggplot2, rstudio/shiny, insightsengineering/teal, From e65605feccaf7b30393cfe62d67ac927783bf05e Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Thu, 27 Nov 2025 15:27:41 +0100 Subject: [PATCH 41/60] Update DESCRIPTION Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ea814326c..9ba78ad5d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -83,7 +83,7 @@ VignetteBuilder: knitr, rmarkdown Remotes: - insightsengineering/teal@bring_tests, + insightsengineering/teal, insightsengineering/teal.reporter Config/Needs/verdepcheck: haleyjeppson/ggmosaic, tidyverse/ggplot2, rstudio/shiny, insightsengineering/teal, From 5eed0feb070b3eb2a228d659572f9f1da6373f4a Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Thu, 27 Nov 2025 15:28:06 +0100 Subject: [PATCH 42/60] Update check.yaml to allow PR events on any branch Remove branch restriction for pull request events Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- .github/workflows/check.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index c4cda93c0..403fb722c 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -8,8 +8,6 @@ on: - synchronize - reopened - ready_for_review - branches: - - main push: branches: - main From 1a5e9345e28b4faca3f8dcd01b31f61ff54cdaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Fri, 28 Nov 2025 15:13:19 +0100 Subject: [PATCH 43/60] Add lintr issue --- .lintr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.lintr b/.lintr index 87688e231..896713e73 100644 --- a/.lintr +++ b/.lintr @@ -2,5 +2,6 @@ linters: linters_with_defaults( line_length_linter = line_length_linter(120), 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 + indentation_linter = NULL, + pipe_consistency_linter = NULL ) From b46d233f0289964a115b03503252b1337a923d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Fri, 28 Nov 2025 15:18:30 +0100 Subject: [PATCH 44/60] Fix summary plot from anyna --- R/tm_missing_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 0de1fdb05..933721f40 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -771,7 +771,7 @@ srv_missing_data <- function(id, ) # always set "**anyna**" level as the last one - if (req(isolate(input$any_na))) { + if (input$any_na) { qenv <- teal.code::eval_code( qenv, quote(x_levels <- c(setdiff(x_levels, "**anyna**"), "**anyna**")) From 3d60bc4bb366fb97fb88c6fc3a5971a1d90d6399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 10:11:37 +0100 Subject: [PATCH 45/60] Update id --- tests/testthat/test-shinytest2-tm_file_viewer.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-shinytest2-tm_file_viewer.R b/tests/testthat/test-shinytest2-tm_file_viewer.R index a681f1a8b..14ae07a9a 100644 --- a/tests/testthat/test-shinytest2-tm_file_viewer.R +++ b/tests/testthat/test-shinytest2-tm_file_viewer.R @@ -44,7 +44,7 @@ test_that("e2e - tm_file_viewer: Shows selected image file", { skip_if_too_deep(5) app_driver <- app_driver_tm_file_viewer() - app_driver$click(selector = "[id= '4_anchor']") + app_driver$click(selector = "[id= '5_anchor']") # [id = 'x'] instead of #x to avoid a DOM error testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output img"))) img_src <- app_driver$get_html_rvest(app_driver$namespaces(TRUE)$module("output")) %>% From e183a3c5f4490cfe9d631712b931b659c11fd1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 11:47:03 +0100 Subject: [PATCH 46/60] Fix module so plot is shown --- R/tm_missing_data.R | 94 +++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 55 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 933721f40..6c433332a 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -468,7 +468,9 @@ srv_missing_data <- function(id, iv_summary_table$add_rule("count_type", shinyvalidate::sv_required("Please select type of counts")) iv_summary_table$add_rule( "group_by_vals", - shinyvalidate::sv_required("Please select both group-by variable and values") + ~ if (length(input$group_by_vals) == 0L && length(.) == 1 && (.) == input$group_by_vals) { + "Please select both group-by variable and values" + } ) iv_summary_table$add_rule( "group_by_var", @@ -645,10 +647,10 @@ srv_missing_data <- function(id, }) output$group_by_vals_ui <- renderUI({ - req(isolate(prev_group_by_var()), input$group_by_var, data_r()) + req(input$group_by_var, data_r()) choices <- teal.transform::value_choices(data_r(), input$group_by_var, input$group_by_var) - prev_choices <- req(isolate(input$group_by_vals)) + prev_choices <- isolate(input$group_by_vals) # determine selected value based on filtered data # display those previously selected values that are still available @@ -915,7 +917,7 @@ srv_missing_data <- function(id, ) } - if (isTRUE(input$if_patients_plot)) { + qenv <- if (isTRUE(input$if_patients_plot)) { within(qenv, { summary_plot <- gridExtra::grid.arrange(summary_plot_top, summary_plot_bottom, ncol = 2) }) @@ -924,6 +926,7 @@ srv_missing_data <- function(id, summary_plot <- summary_plot_top }) } + qenv }) combination_plot_q <- reactive({ @@ -1074,15 +1077,14 @@ srv_missing_data <- function(id, # extract the ANL dataset for use in further validation anl <- common_code_q()[["ANL"]] + req(input$group_by_var, input$group_by_vals) group_var <- input$group_by_var validate( need( - is.null(group_var) || - length(unique(anl[[group_var]])) < 100, + length(unique(anl[[group_var]])) < 100, "Please select group-by variable with fewer than 100 unique values" ) ) - group_vals <- input$group_by_vals variables_select <- input$variables_select vars <- unique(variables_select, group_var) @@ -1103,48 +1105,33 @@ srv_missing_data <- function(id, qenv <- req(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( - qenv, - "library(forcats);library(glue)" - ) - teal.code::eval_code( - common_code_libraries_q, - substitute( - expr = { - summary_data <- ANL %>% - dplyr::mutate(group_var_name := forcats::fct_na_value_to_level(as.factor(group_var_name), "NA")) %>% - dplyr::group_by_at(group_var) %>% - dplyr::filter(group_var_name %in% group_vals) - - count_data <- dplyr::summarise(summary_data, n = dplyr::n()) - - summary_data <- dplyr::summarise_all(summary_data, summ_fn) %>% - dplyr::mutate(group_var_name := paste0(group_var, ":", group_var_name, "(N=", count_data$n, ")")) %>% - tidyr::pivot_longer(!dplyr::all_of(group_var), names_to = "Variable", values_to = "out") %>% - tidyr::pivot_wider(names_from = group_var, values_from = "out") %>% - dplyr::mutate(`Variable label` = create_cols_labels(Variable, just_label = TRUE), .after = Variable) - }, - env = list( - group_var = group_var, group_var_name = as.name(group_var), group_vals = group_vals, summ_fn = summ_fn - ) - ) - ) - } else { - teal.code::eval_code( - qenv, - substitute( - expr = summary_data <- ANL %>% - dplyr::summarise_all(summ_fn) %>% - tidyr::pivot_longer(dplyr::everything(), - names_to = "Variable", - values_to = paste0("Missing (N=", nrow(ANL), ")") - ) %>% - dplyr::mutate(`Variable label` = create_cols_labels(Variable), .after = Variable), - env = list(summ_fn = summ_fn) + + common_code_libraries_q <- teal.code::eval_code( + qenv, + "library(forcats);library(glue)" + ) + qenv <- teal.code::eval_code( + common_code_libraries_q, + substitute( + expr = { + summary_data <- ANL %>% + dplyr::mutate(group_var_name := forcats::fct_na_value_to_level(as.factor(group_var_name), "NA")) %>% + dplyr::group_by_at(group_var) %>% + dplyr::filter(group_var_name %in% group_vals) + + count_data <- dplyr::summarise(summary_data, n = dplyr::n()) + + summary_data <- dplyr::summarise_all(summary_data, summ_fn) %>% + dplyr::mutate(group_var_name := paste0(group_var, ":", group_var_name, "(N=", count_data$n, ")")) %>% + tidyr::pivot_longer(!dplyr::all_of(group_var), names_to = "Variable", values_to = "out") %>% + tidyr::pivot_wider(names_from = group_var, values_from = "out") %>% + dplyr::mutate(`Variable label` = create_cols_labels(Variable, just_label = TRUE), .after = Variable) + }, + env = list( + group_var = group_var, group_var_name = as.name(group_var), group_vals = group_vals, summ_fn = summ_fn ) ) - } + ) dev_ggplot2_args <- teal.widgets::ggplot2_args( labs = list( @@ -1181,7 +1168,7 @@ srv_missing_data <- function(id, keys = join_keys(qenv) |> unlist() |> unique(), group_var_name = as.name(group_var), group_var = group_var, - group_vals = group_vals + group_vals = req(group_vals) ) tile <- within(ANL_q, { @@ -1209,20 +1196,18 @@ srv_missing_data <- function(id, ANL_q <- within(qenv, # nolint object_name_linter { keep_columns <- intersect(c(keys, group_var), colnames(ANL)) - labels <- vapply(qenv$ANL, attr, which = "label", FUN.VALUE = character(1L)) + labels <- vapply(ANL, attr, which = "label", FUN.VALUE = character(1L)) ANL <- ANL %>% dplyr::filter(group_var_name %in% group_vals) %>% tidyr::pivot_longer(-keep_columns, values_transform = is.na) %>% - dplyr::summarise( - .by = c(group_var_name, name), - value = sum(value), perc = value / n() - ) %>% + dplyr::group_by(group_var_name, name) %>% + dplyr::summarise(value = sum(value), perc = value / n()) %>% dplyr::mutate(label = labels[name]) }, keys = join_keys(qenv) |> unlist() |> unique(), group_var_name = as.name(group_var), group_var = group_var, - group_vals = group_vals + group_vals = req(group_vals) ) tile <- within(ANL_q, @@ -1248,7 +1233,6 @@ srv_missing_data <- function(id, ggthemes = parsed_ggplot2_args$ggtheme ) } - tile }) From 6d7b42f8144440f3fbd1e61f56126f6b192f3198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 12:08:18 +0100 Subject: [PATCH 47/60] Fix file_viewer tests --- tests/testthat/test-shinytest2-tm_file_viewer.R | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_file_viewer.R b/tests/testthat/test-shinytest2-tm_file_viewer.R index 14ae07a9a..1770a8a29 100644 --- a/tests/testthat/test-shinytest2-tm_file_viewer.R +++ b/tests/testthat/test-shinytest2-tm_file_viewer.R @@ -44,6 +44,11 @@ test_that("e2e - tm_file_viewer: Shows selected image file", { skip_if_too_deep(5) app_driver <- app_driver_tm_file_viewer() + selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") + type <- app_driver$get_text(selector = selector) + names(type) <- app_driver$get_attr(selector = selector, "id") + app_driver$click(selector = paste0("[id='", names(type)[type == "png"], "']")) # Avoids issue with DOM id starting with number + app_driver$click(selector = "[id= '5_anchor']") # [id = 'x'] instead of #x to avoid a DOM error testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output img"))) @@ -60,7 +65,11 @@ test_that("e2e - tm_file_viewer: Shows selected text file", { skip_if_too_deep(5) app_driver <- app_driver_tm_file_viewer() - app_driver$click(selector = "[id= '5_anchor']") + selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") + type <- app_driver$get_text(selector = selector) + names(type) <- app_driver$get_attr(selector = selector, "id") + app_driver$click(selector = paste0("[id='", names(type)[type == "txt"], "']")) # Avoids issue with DOM id starting with number + testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output pre"))) pre_text <- app_driver$get_html_rvest(app_driver$namespaces(TRUE)$module("output")) %>% @@ -82,7 +91,10 @@ test_that("e2e - tm_file_viewer: Shows selected url", { skip_if_too_deep(5) app_driver <- app_driver_tm_file_viewer() - app_driver$click(selector = "[id= '6_anchor']") + selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") + type <- app_driver$get_text(selector = selector) + names(type) <- app_driver$get_attr(selector = selector, "id") + app_driver$click(selector = paste0("[id='", names(type)[type == "url"], "']")) # Avoids issue with DOM id starting with number testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output img"))) testthat::expect_equal( From 466d5e77b0deec0d24b0da8317d105c21e3f6a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 14:43:46 +0100 Subject: [PATCH 48/60] Simplify selectors (and lintr notes) --- tests/testthat/test-shinytest2-tm_file_viewer.R | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_file_viewer.R b/tests/testthat/test-shinytest2-tm_file_viewer.R index 1770a8a29..89b772b8c 100644 --- a/tests/testthat/test-shinytest2-tm_file_viewer.R +++ b/tests/testthat/test-shinytest2-tm_file_viewer.R @@ -27,9 +27,10 @@ test_that("e2e - tm_file_viewer: Initializes without errors and shows files tree app_driver$expect_validation_error() # encoding are visible testthat::expect_true(app_driver$is_visible(selector = app_driver$namespaces(TRUE)$module("tree"))) - list_files <- app_driver$get_html_rvest(selector = app_driver$namespaces(TRUE)$module("tree")) %>% - rvest::html_nodes("a") %>% - rvest::html_text() + selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") + list_files <- app_driver$get_text(selector = selector) + # Avoids issue with DOM id starting with number + testthat::expect_setequal( list_files, c("folder", "png", "txt", "url") @@ -47,9 +48,9 @@ test_that("e2e - tm_file_viewer: Shows selected image file", { selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") type <- app_driver$get_text(selector = selector) names(type) <- app_driver$get_attr(selector = selector, "id") - app_driver$click(selector = paste0("[id='", names(type)[type == "png"], "']")) # Avoids issue with DOM id starting with number + # Avoids issue with DOM id starting with number + app_driver$click(selector = paste0("[id='", names(type)[type == "png"], "']")) - app_driver$click(selector = "[id= '5_anchor']") # [id = 'x'] instead of #x to avoid a DOM error testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output img"))) img_src <- app_driver$get_html_rvest(app_driver$namespaces(TRUE)$module("output")) %>% @@ -68,7 +69,8 @@ test_that("e2e - tm_file_viewer: Shows selected text file", { selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") type <- app_driver$get_text(selector = selector) names(type) <- app_driver$get_attr(selector = selector, "id") - app_driver$click(selector = paste0("[id='", names(type)[type == "txt"], "']")) # Avoids issue with DOM id starting with number + # Avoids issue with DOM id starting with number + app_driver$click(selector = paste0("[id='", names(type)[type == "txt"], "']")) testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output pre"))) @@ -94,7 +96,8 @@ test_that("e2e - tm_file_viewer: Shows selected url", { selector <- paste0(app_driver$namespaces(TRUE)$module("tree"), " * a") type <- app_driver$get_text(selector = selector) names(type) <- app_driver$get_attr(selector = selector, "id") - app_driver$click(selector = paste0("[id='", names(type)[type == "url"], "']")) # Avoids issue with DOM id starting with number + # Avoids issue with DOM id starting with number + app_driver$click(selector = paste0("[id='", names(type)[type == "url"], "']")) testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("output img"))) testthat::expect_equal( From 70bbaf0e7a7a5d6e833d2a8867ce7c46cc7c5902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 14:44:07 +0100 Subject: [PATCH 49/60] Add more pause to ensure the checks are when the app is ready --- tests/testthat/test-shinytest2-tm_missing_data.R | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index 11c7e1d98..17a370d11 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -48,7 +48,6 @@ test_that("e2e - tm_missing_data: Initializes without errors", { encoding_dataset <- app_driver$get_text(paste(app_driver$namespaces(TRUE)$wrapper(NULL), ".help-block")) testthat::expect_match(encoding_dataset, "Datasets.*iris.*mtcars", all = FALSE) - app_driver$stop() }) @@ -71,6 +70,7 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary app_driver$click(selector = app_driver$namespaces(TRUE)$module("iris-any_na")) app_driver$expect_no_validation_error() + app_driver$wait_for_idle() testthat::expect_true( app_driver$is_visible( @@ -86,11 +86,13 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c app_driver <- app_driver_tm_missing_data() app_driver$expect_no_shiny_error() + app_driver$wait_for_idle() # combination graph - app_driver$set_active_module_input("iris-summary_type", "Combinations") app_driver$expect_no_validation_error() + app_driver$wait_for_idle() + testthat::expect_true( app_driver$is_visible( app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") @@ -107,6 +109,7 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 1L) app_driver$set_active_module_input("iris-combination_cutoff", 10L) + app_driver$wait_for_idle() testthat::expect_equal(app_driver$get_active_module_input("iris-combination_cutoff"), 10L) app_driver$expect_no_validation_error() @@ -119,7 +122,7 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By # By variable levels app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") app_driver$expect_no_validation_error() - + app_driver$wait_for_idle() testthat::expect_equal( app_driver$get_active_module_input("iris-group_by_var"), @@ -132,12 +135,14 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By app_driver$set_active_module_input("iris-group_by_vals", c("versicolor", "virginica")) app_driver$expect_no_validation_error() + app_driver$wait_for_idle() testthat::expect_equal( app_driver$get_active_module_input("iris-count_type"), "counts" ) app_driver$set_active_module_input("iris-count_type", "proportions") + app_driver$wait_for_idle() testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) app_driver$stop() @@ -148,6 +153,7 @@ test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { app_driver <- app_driver_tm_missing_data() app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") + app_driver$wait_for_idle() levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% app_driver$get_html_rvest() %>% rvest::html_table(fill = TRUE) %>% From d480e4ae8b6874a136ee9d1f8919b984ef6f11fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Mon, 1 Dec 2025 15:46:14 +0100 Subject: [PATCH 50/60] Update ids --- tests/testthat/test-shinytest2-tm_missing_data.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index 17a370d11..9250dbeaa 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -74,7 +74,7 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_out_main .shiny-plot-output") + app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_main") ) ) @@ -95,12 +95,11 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_out_main .shiny-plot-output") + app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_main") ) ) # combination encoding - testthat::expect_true( app_driver$is_visible( app_driver$namespaces(TRUE)$module("iris-cutoff .shiny-input-container") From ddc10dbe6d4245eae68e12e4fff18d0d9dbb532a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Tue, 2 Dec 2025 10:13:25 +0100 Subject: [PATCH 51/60] Remove test about a table no longer present --- .../test-shinytest2-tm_missing_data.R | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index 9250dbeaa..e689ffa18 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -146,22 +146,3 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By app_driver$stop() }) - -test_that("e2e - tm_missing_data: Validate 'By Variable Levels' table values", { - skip_if_too_deep(5) - app_driver <- app_driver_tm_missing_data() - - app_driver$set_active_module_input("iris-summary_type", "By Variable Levels") - app_driver$wait_for_idle() - levels_table <- app_driver$namespaces(TRUE)$module("iris-levels_table") %>% - app_driver$get_html_rvest() %>% - rvest::html_table(fill = TRUE) %>% - .[[1]] - - testthat::expect_setequal( - levels_table$Variable, - c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") - ) - - app_driver$stop() -}) From b72941c8b7d8b338c8c5eff5a0841b6834ccd4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Tue, 2 Dec 2025 11:39:24 +0100 Subject: [PATCH 52/60] Remove requirements that prevented displaying the output --- R/tm_missing_data.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 6c433332a..370f9c36e 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -571,7 +571,7 @@ srv_missing_data <- function(id, }) selected_vars <- reactive({ - req(data_keys(), input$variables_select) + req(input$variables_select) keys <- data_keys() vars <- unique(c(keys, input$variables_select)) vars @@ -723,7 +723,7 @@ srv_missing_data <- function(id, summary_plot_q <- reactive({ req(input$summary_type == "Summary") # needed to trigger update on tab change teal::validate_has_data(req(data_r()), 1) - req(data_keys(), input$ggtheme) + req(input$ggtheme) qenv <- req(common_code_q()) if (input$any_na) { new_col_name <- "**anyna**" @@ -932,7 +932,7 @@ srv_missing_data <- function(id, combination_plot_q <- reactive({ req( input$summary_type == "Combinations", input$combination_cutoff, - combination_cutoff_q(), data_keys(), input$ggtheme + combination_cutoff_q(), input$ggtheme ) teal::validate_has_data(req(data_r()), 1) @@ -1077,7 +1077,7 @@ srv_missing_data <- function(id, # extract the ANL dataset for use in further validation anl <- common_code_q()[["ANL"]] - req(input$group_by_var, input$group_by_vals) + req(input$group_by_var) group_var <- input$group_by_var validate( need( From 9c17dd9c822b5c927db98b5eede8837d9c4d3655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Tue, 2 Dec 2025 12:13:43 +0100 Subject: [PATCH 53/60] Update the ids of the plots --- tests/testthat/test-shinytest2-tm_missing_data.R | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-shinytest2-tm_missing_data.R b/tests/testthat/test-shinytest2-tm_missing_data.R index e689ffa18..86b8a5244 100644 --- a/tests/testthat/test-shinytest2-tm_missing_data.R +++ b/tests/testthat/test-shinytest2-tm_missing_data.R @@ -74,7 +74,7 @@ test_that("e2e - tm_missing_data: Default settings and visibility of the summary testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-summary_plot-plot_main") + app_driver$namespaces(TRUE)$module("iris-summary_plot-plot-with-settings") ) ) @@ -95,7 +95,7 @@ test_that("e2e - tm_missing_data: Check default settings and visibility of the c testthat::expect_true( app_driver$is_visible( - app_driver$namespaces(TRUE)$module("iris-combination_plot-plot_main") + app_driver$namespaces(TRUE)$module("iris-combination_plot-plot-with-settings") ) ) @@ -142,7 +142,11 @@ test_that("e2e - tm_missing_data: Validate functionality and UI response for 'By ) app_driver$set_active_module_input("iris-count_type", "proportions") app_driver$wait_for_idle() - testthat::expect_true(app_driver$is_visible(app_driver$namespaces(TRUE)$module("iris-levels_table"))) + testthat::expect_true( + app_driver$is_visible( + app_driver$namespaces(TRUE)$module("iris-by_variable_plot-plot-with-settings") + ) + ) app_driver$stop() }) From d1f46c9c7db7289528b37f31060104372236fc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:20:28 +0100 Subject: [PATCH 54/60] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_missing_data.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 370f9c36e..7c27711cd 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1173,9 +1173,9 @@ srv_missing_data <- function(id, tile <- within(ANL_q, { by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, name)) + - ggplot2::geom_tile(ggplot2::aes(fill = column)) + + ggplot2::geom_tile(ggplot2::aes(fill = column), color = "gray90") + ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), - data = . %>% dplyr::filter(perc > 0), color = "white" + data = ~ dplyr::filter(.x, perc > 0), ) + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + ggplot2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + From 605abe2d017fc9750e38d15c09e68b31a65a7488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:23:04 +0100 Subject: [PATCH 55/60] Update R/tm_missing_data.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_missing_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 7c27711cd..0708ccfe0 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1213,7 +1213,7 @@ srv_missing_data <- function(id, tile <- within(ANL_q, { by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, label)) + - ggplot2::geom_tile(ggplot2::aes(fill = column)) + + ggplot2::geom_tile(ggplot2::aes(fill = column), color = "gray90") + ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), data = . %>% dplyr::filter(perc > 0), color = "white" ) + From 78021ce76305edfa3c3f8585617d8a84fe656706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:23:15 +0100 Subject: [PATCH 56/60] Update R/tm_missing_data.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_missing_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 0708ccfe0..2e5d9088c 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1215,7 +1215,7 @@ srv_missing_data <- function(id, by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, label)) + ggplot2::geom_tile(ggplot2::aes(fill = column), color = "gray90") + ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), - data = . %>% dplyr::filter(perc > 0), color = "white" + data = ~ dplyr::filter(.x, perc > 0) ) + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + ggplot2::scale_fill_gradient(high = "#ff2951ff", low = "grey90", labels = labels) + From 5677cc22dd3137a8ba96c980e8c29654a75eb4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Tue, 2 Dec 2025 15:56:00 +0100 Subject: [PATCH 57/60] Fix logic for validation error --- R/tm_missing_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 2e5d9088c..17c2b4fb0 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -468,7 +468,7 @@ srv_missing_data <- function(id, iv_summary_table$add_rule("count_type", shinyvalidate::sv_required("Please select type of counts")) iv_summary_table$add_rule( "group_by_vals", - ~ if (length(input$group_by_vals) == 0L && length(.) == 1 && (.) == input$group_by_vals) { + ~ if (length(input$group_by_vals) == 0L) { "Please select both group-by variable and values" } ) From a95713e59810b0141eeeb6e8ff77193129a250fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla?= <185338939+llrs-roche@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:30:54 +0100 Subject: [PATCH 58/60] Update R/tm_missing_data.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> Signed-off-by: Lluís Revilla <185338939+llrs-roche@users.noreply.github.com> --- R/tm_missing_data.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 17c2b4fb0..c900744a4 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -468,9 +468,11 @@ srv_missing_data <- function(id, iv_summary_table$add_rule("count_type", shinyvalidate::sv_required("Please select type of counts")) iv_summary_table$add_rule( "group_by_vals", - ~ if (length(input$group_by_vals) == 0L) { - "Please select both group-by variable and values" - } + ~ if (length(input$group_by_var) >= 1L && length(.) == 0L) "Please select filter values" + ) + iv_summary_table$add_rule( + "group_by_var", + ~ if (length(.) == 0L) "Please select group-by variable" ) iv_summary_table$add_rule( "group_by_var", From d3d5737e43983dde1d28b01e308e6810fa290b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Wed, 3 Dec 2025 09:08:32 +0100 Subject: [PATCH 59/60] Change label according to user selection --- R/tm_missing_data.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 17c2b4fb0..116b62350 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -1174,7 +1174,7 @@ srv_missing_data <- function(id, { by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, name)) + ggplot2::geom_tile(ggplot2::aes(fill = column), color = "gray90") + - ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), + ggplot2::geom_text(ggplot2::aes(label = text_label), data = ~ dplyr::filter(.x, perc > 0), ) + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + @@ -1188,6 +1188,7 @@ srv_missing_data <- function(id, } else { as.name("perc") }, + text_label = if (input$count_type == "counts") as.name("value") else quote(scales::percent(perc)), labs = parsed_ggplot2_args$labs, labels = if (input$count_type == "counts") quote(ggplot2::waiver()) else quote(scales::label_percent()), ggthemes = parsed_ggplot2_args$ggtheme @@ -1214,7 +1215,7 @@ srv_missing_data <- function(id, { by_variable_plot <- ggplot2::ggplot(ANL, ggplot2::aes(group_var_name, label)) + ggplot2::geom_tile(ggplot2::aes(fill = column), color = "gray90") + - ggplot2::geom_text(ggplot2::aes(label = scales::percent(perc)), + ggplot2::geom_text(ggplot2::aes(label = text_label), data = ~ dplyr::filter(.x, perc > 0) ) + ggplot2::scale_x_discrete(expand = ggplot2::expansion()) + @@ -1222,6 +1223,7 @@ srv_missing_data <- function(id, labs + ggthemes }, + text_label = if (input$count_type == "counts") as.name("value") else quote(scales::percent(perc)), group_var_name = as.name(group_var), column = if (input$count_type == "counts") { as.name("value") From 01d9758db6f26d48518537204ac76d6066ae5970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Revilla=20Sancho?= Date: Wed, 3 Dec 2025 11:43:08 +0100 Subject: [PATCH 60/60] Add back the branch --- .github/workflows/check.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 403fb722c..c4cda93c0 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -8,6 +8,8 @@ on: - synchronize - reopened - ready_for_review + branches: + - main push: branches: - main