Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ec44372
Explore heatmap and tile map
llrs-roche Sep 23, 2025
4593c88
Fix lintr names
llrs-roche Oct 3, 2025
586b960
Replace table by a plot
llrs-roche Oct 3, 2025
c4a13cc
Fix lint comments
llrs-roche Oct 3, 2025
dda7615
[skip style] [skip vbump] Restyle files
github-actions[bot] Oct 3, 2025
ea38ac1
Fix lintr issues
llrs-roche Oct 3, 2025
ee7f4b6
Merge branch '495_plot_missing@main' of github.com:insightsengineerin…
llrs-roche Oct 3, 2025
1159a49
Merge branch 'main' into 495_plot_missing@main
llrs-roche Oct 3, 2025
c296936
Split evaluation to load libraries
llrs-roche Oct 3, 2025
56020d4
Merge branch 'main' into 495_plot_missing@main
m7pr Oct 8, 2025
5e3080d
Use "library(pkg)" instead of 'library("pkg")' #nolint
llrs-roche Oct 9, 2025
484b91c
Use dot at the end of lint comment
llrs-roche Oct 9, 2025
d2673e6
Simplify code branch
llrs-roche Oct 13, 2025
558f666
[skip style] [skip vbump] Restyle files
github-actions[bot] Oct 13, 2025
5c4b580
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
github-actions[bot] Oct 13, 2025
d2a903f
Merge branch 'main' into 495_plot_missing@main
llrs-roche Oct 15, 2025
08951f5
Merge branch 'main' into 495_plot_missing@main
llrs-roche Oct 16, 2025
bcf8803
Merge branch 'main' into 495_plot_missing@main
m7pr Oct 17, 2025
ef399e0
Fix logic
llrs-roche Oct 17, 2025
f383cc7
Avoid ggplot2 warnings
llrs-roche Oct 17, 2025
fed8c46
Check feedback from copilot
llrs-roche Oct 17, 2025
6d71798
[skip style] [skip vbump] Restyle files
github-actions[bot] Oct 17, 2025
22faabd
Fix misspelling on linters
llrs-roche Oct 20, 2025
3cb8e61
Fix style
llrs-roche Oct 20, 2025
463f61e
Do not reduce the timeout from the default 4s
llrs-roche Oct 20, 2025
b576f8e
[skip style] [skip vbump] Restyle files
github-actions[bot] Oct 20, 2025
3696675
Fix typo
llrs-roche Oct 20, 2025
949a35b
Avoid skipping tests
llrs-roche Oct 20, 2025
ed17c6b
Update code based on https://github.com/insightsengineering/teal.modu…
llrs-roche Oct 20, 2025
188fa05
Add req to resolve the app faster
llrs-roche Oct 21, 2025
f1a180b
[skip style] [skip vbump] Restyle files
github-actions[bot] Oct 21, 2025
1006fa9
Prefix functions with their packages
llrs-roche Oct 21, 2025
8a311f1
Fix typo
llrs-roche Oct 21, 2025
5b4226a
Fix package
llrs-roche Oct 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Imports:
tools,
utils
Suggests:
formatters (>= 0.5.11),
knitr (>= 1.42),
logger (>= 0.4.0),
nestcolor (>= 0.1.0),
Expand Down
4 changes: 2 additions & 2 deletions R/teal.modules.general.R
Original file line number Diff line number Diff line change
Expand Up @@ -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")
2 changes: 1 addition & 1 deletion R/tm_a_pca.R
Original file line number Diff line number Diff line change
Expand Up @@ -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 output(s)")
)
teal.code::eval_code(obj, 'library("ggplot2");library("dplyr");library("tidyr")') # nolint: quotes
teal.code::eval_code(obj, "library(ggplot2);library(dplyr);library(tidyr)")
})
anl_merged_q <- reactive({
req(anl_merged_input())
Expand Down
2 changes: 1 addition & 1 deletion R/tm_a_regression.R
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ srv_a_regression <- function(id,
teal.reporter::teal_card(obj),
teal.reporter::teal_card("## Module's output(s)")
)
teal.code::eval_code(obj, 'library("ggplot2");library("dplyr")') # nolint: quotes
teal.code::eval_code(obj, "library(ggplot2);library(dplyr)")
})

anl_merged_q <- reactive({
Expand Down
2 changes: 1 addition & 1 deletion R/tm_data_table.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
)
teal.code::eval_code(
qenv,
Expand Down
6 changes: 3 additions & 3 deletions R/tm_g_association.R
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -346,7 +346,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")') # nolint: quotes
teal.code::eval_code(obj, "library(ggplot2);library(dplyr);library(ggmosaic)")
})
anl_merged_q <- reactive({
req(anl_merged_input())
Expand Down
10 changes: 3 additions & 7 deletions R/tm_g_bivariate.R
Original file line number Diff line number Diff line change
Expand Up @@ -559,13 +559,9 @@ srv_g_bivariate <- function(id,
teal.reporter::teal_card(obj),
teal.reporter::teal_card("## Module's output(s)")
)
obj %>%
teal.code::eval_code(
c(
'library("ggplot2");library("dplyr")', # nolint: quotes
as.expression(anl_merged_input()$expr)
)
)
obj |>
teal.code::eval_code("library(ggplot2);library(dplyr)") |>
teal.code::eval_code(as.expression(anl_merged_input()$expr))
})

merged <- list(
Expand Down
14 changes: 7 additions & 7 deletions R/tm_g_distribution.R
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,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)")
)

anl_merged_q <- reactive({
Expand Down Expand Up @@ -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
qenv <- teal.code::eval_code(qenv, "library(forcats)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand All @@ -680,7 +680,7 @@ srv_distribution <- function(id,
)
)

qenv <- teal.code::eval_code(qenv, 'library("forcats")') # nolint quotes
qenv <- teal.code::eval_code(qenv, "library(forcats)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand Down Expand Up @@ -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
qenv <- teal.code::eval_code(qenv, "library(ggpp)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand Down Expand Up @@ -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
qenv <- teal.code::eval_code(qenv, "library(ggpp)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand Down Expand Up @@ -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
qenv <- teal.code::eval_code(qenv, "library(generics)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand All @@ -1246,7 +1246,7 @@ srv_distribution <- function(id,
)
)
} else {
qenv <- teal.code::eval_code(qenv, 'library("tidyr")') # nolint quotes
qenv <- teal.code::eval_code(qenv, "library(tidyr)")
qenv <- teal.code::eval_code(
qenv,
substitute(
Expand Down
4 changes: 2 additions & 2 deletions R/tm_g_response.R
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,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)")
)

anl_merged_q <- reactive({
Expand Down Expand Up @@ -521,7 +521,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"
)
Expand Down
2 changes: 1 addition & 1 deletion R/tm_g_scatterplot.R
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ srv_g_scatterplot <- function(id,
teal.reporter::teal_card(obj),
teal.reporter::teal_card("## Module's output(s)")
)
teal.code::eval_code(data(), 'library("ggplot2");library("dplyr")') # nolint quotes
teal.code::eval_code(data(), "library(ggplot2);library(dplyr)")
})

anl_merged_q <- reactive({
Expand Down
2 changes: 1 addition & 1 deletion R/tm_g_scatterplotmatrix.R
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ srv_g_scatterplotmatrix <- function(id,
teal.reporter::teal_card(obj),
teal.reporter::teal_card("## Module's output(s)")
)
qenv <- teal.code::eval_code(obj, 'library("dplyr");library("lattice")') # nolint quotes
qenv <- teal.code::eval_code(obj, "library(dplyr);library(lattice)")
teal.code::eval_code(qenv, as.expression(anl_merged_input()$expr))
})

Expand Down
122 changes: 87 additions & 35 deletions R/tm_missing_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
#' )
#' )
Expand Down Expand Up @@ -314,8 +316,7 @@ 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")),
)
)
if (isTRUE(by_subject_plot)) {
Expand Down Expand Up @@ -511,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)) {
Expand Down Expand Up @@ -1055,7 +1056,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 update on tab change
common_code_q()
Expand All @@ -1065,7 +1066,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) ||
Expand Down Expand Up @@ -1097,7 +1098,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,
Expand Down Expand Up @@ -1137,10 +1138,67 @@ srv_missing_data <- function(id,
)
}

within(qenv, {
table <- rtables::df_to_tt(summary_data)
table
})
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
)

# 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
)

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
})

by_subject_plot_q <- reactive({
Expand Down Expand Up @@ -1286,11 +1344,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(
Expand All @@ -1310,22 +1368,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({
Expand All @@ -1347,9 +1391,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,
Expand All @@ -1361,8 +1410,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)
Expand All @@ -1371,7 +1423,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()
}
Expand Down
Loading
Loading