From 48dfaa1d264919ca33f0784d07f003c8ba92ab26 Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 13:22:24 -0500 Subject: [PATCH 1/9] Fix summarize_*() function indentation --- R/count_occurrences.R | 14 +++++++++++--- R/count_occurrences_by_grade.R | 20 ++++++++++++++------ R/summarize_num_patients.R | 14 +++++++++++--- man/count_occurrences.Rd | 2 +- man/count_occurrences_by_grade.Rd | 12 ++++++------ man/summarize_num_patients.Rd | 2 +- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/R/count_occurrences.R b/R/count_occurrences.R index 4a03604c26..a8daf84821 100644 --- a/R/count_occurrences.R +++ b/R/count_occurrences.R @@ -320,7 +320,7 @@ summarize_occurrences <- function(lyt, .stats = "count_fraction_fixed_dp", .stat_names = NULL, .formats = NULL, - .indent_mods = NULL, + .indent_mods = 0L, .labels = NULL) { checkmate::assert_flag(riskdiff) afun <- if (isFALSE(riskdiff)) a_count_occurrences else afun_riskdiff @@ -330,7 +330,14 @@ summarize_occurrences <- function(lyt, if (!is.null(.stat_names)) extra_args[[".stat_names"]] <- .stat_names if (!is.null(.formats)) extra_args[[".formats"]] <- .formats if (!is.null(.labels)) extra_args[[".labels"]] <- .labels - if (!is.null(.indent_mods)) extra_args[[".indent_mods"]] <- .indent_mods + if (is.null(.indent_mods)) { + indent_mod <- 0L + } else if (length(.indent_mods) == 1) { + indent_mod <- .indent_mods + } else { + indent_mod <- 0L + extra_args[[".indent_mods"]] <- .indent_mods + } # Process additional arguments to the statistic function extra_args <- c( @@ -349,6 +356,7 @@ summarize_occurrences <- function(lyt, var = var, cfun = afun, na_str = na_str, - extra_args = extra_args + extra_args = extra_args, + indent_mod = indent_mod ) } diff --git a/R/count_occurrences_by_grade.R b/R/count_occurrences_by_grade.R index a006e1a958..0947bb40cb 100644 --- a/R/count_occurrences_by_grade.R +++ b/R/count_occurrences_by_grade.R @@ -376,8 +376,8 @@ count_occurrences_by_grade <- function(lyt, .stats = "count_fraction", .stat_names = NULL, .formats = list(count_fraction = format_count_fraction_fixed_dp), - .indent_mods = NULL, - .labels = NULL) { + .labels = NULL, + .indent_mods = NULL) { checkmate::assert_flag(riskdiff) afun <- if (isFALSE(riskdiff)) a_count_occurrences_by_grade else afun_riskdiff @@ -455,8 +455,8 @@ summarize_occurrences_by_grade <- function(lyt, .stats = "count_fraction", .stat_names = NULL, .formats = list(count_fraction = format_count_fraction_fixed_dp), - .indent_mods = NULL, - .labels = NULL) { + .labels = NULL, + .indent_mods = 0L) { checkmate::assert_flag(riskdiff) afun <- if (isFALSE(riskdiff)) a_count_occurrences_by_grade else afun_riskdiff @@ -465,7 +465,14 @@ summarize_occurrences_by_grade <- function(lyt, if (!is.null(.stat_names)) extra_args[[".stat_names"]] <- .stat_names if (!is.null(.formats)) extra_args[[".formats"]] <- .formats if (!is.null(.labels)) extra_args[[".labels"]] <- .labels - if (!is.null(.indent_mods)) extra_args[[".indent_mods"]] <- .indent_mods + if (is.null(.indent_mods)) { + indent_mod <- 0L + } else if (length(.indent_mods) == 1) { + indent_mod <- .indent_mods + } else { + indent_mod <- 0L + extra_args[[".indent_mods"]] <- .indent_mods + } # Process additional arguments to the statistic function extra_args <- c( @@ -484,6 +491,7 @@ summarize_occurrences_by_grade <- function(lyt, var = var, cfun = afun, na_str = na_str, - extra_args = extra_args + extra_args = extra_args, + indent_mod = indent_mod ) } diff --git a/R/summarize_num_patients.R b/R/summarize_num_patients.R index 5d8b48ef20..b39454a120 100644 --- a/R/summarize_num_patients.R +++ b/R/summarize_num_patients.R @@ -235,7 +235,7 @@ summarize_num_patients <- function(lyt, unique = "Number of patients with at least one event", nonunique = "Number of events" ), - .indent_mods = NULL) { + .indent_mods = 0L) { checkmate::assert_flag(riskdiff) afun <- if (isFALSE(riskdiff)) a_num_patients else afun_riskdiff @@ -244,7 +244,14 @@ summarize_num_patients <- function(lyt, if (!is.null(.stat_names)) extra_args[[".stat_names"]] <- .stat_names if (!is.null(.formats)) extra_args[[".formats"]] <- .formats if (!is.null(.labels)) extra_args[[".labels"]] <- .labels - if (!is.null(.indent_mods)) extra_args[[".indent_mods"]] <- .indent_mods + if (is.null(.indent_mods)) { + indent_mod <- 0L + } else if (length(.indent_mods) == 1) { + indent_mod <- .indent_mods + } else { + indent_mod <- 0L + extra_args[[".indent_mods"]] <- .indent_mods + } # Process additional arguments to the statistic function extra_args <- c( @@ -263,7 +270,8 @@ summarize_num_patients <- function(lyt, var = var, cfun = afun, na_str = na_str, - extra_args = extra_args + extra_args = extra_args, + indent_mod = indent_mod ) } diff --git a/man/count_occurrences.Rd b/man/count_occurrences.Rd index 75c1ce7695..04b5444999 100644 --- a/man/count_occurrences.Rd +++ b/man/count_occurrences.Rd @@ -37,7 +37,7 @@ summarize_occurrences( .stats = "count_fraction_fixed_dp", .stat_names = NULL, .formats = NULL, - .indent_mods = NULL, + .indent_mods = 0L, .labels = NULL ) diff --git a/man/count_occurrences_by_grade.Rd b/man/count_occurrences_by_grade.Rd index ebde413fbc..88853d69d4 100644 --- a/man/count_occurrences_by_grade.Rd +++ b/man/count_occurrences_by_grade.Rd @@ -24,8 +24,8 @@ count_occurrences_by_grade( .stats = "count_fraction", .stat_names = NULL, .formats = list(count_fraction = format_count_fraction_fixed_dp), - .indent_mods = NULL, - .labels = NULL + .labels = NULL, + .indent_mods = NULL ) summarize_occurrences_by_grade( @@ -41,8 +41,8 @@ summarize_occurrences_by_grade( .stats = "count_fraction", .stat_names = NULL, .formats = list(count_fraction = format_count_fraction_fixed_dp), - .indent_mods = NULL, - .labels = NULL + .labels = NULL, + .indent_mods = 0L ) s_count_occurrences_by_grade( @@ -114,11 +114,11 @@ Options are: \verb{'count_fraction', 'count_fraction_fixed_dp'}} \item{.formats}{(named \code{character} or \code{list})\cr formats for the statistics. See Details in \code{analyze_vars} for more information on the \code{"auto"} setting.} +\item{.labels}{(named \code{character})\cr labels for the statistics (without indent).} + \item{.indent_mods}{(named \code{integer})\cr indent modifiers for the labels. Defaults to 0, which corresponds to the unmodified default behavior. Can be negative.} -\item{.labels}{(named \code{character})\cr labels for the statistics (without indent).} - \item{df}{(\code{data.frame})\cr data set containing all analysis variables.} \item{labelstr}{(\code{string})\cr label of the level of the parent split currently being summarized diff --git a/man/summarize_num_patients.Rd b/man/summarize_num_patients.Rd index a9f9201f50..e3f9b209d9 100644 --- a/man/summarize_num_patients.Rd +++ b/man/summarize_num_patients.Rd @@ -41,7 +41,7 @@ summarize_num_patients( .formats = NULL, .labels = list(unique = "Number of patients with at least one event", nonunique = "Number of events"), - .indent_mods = NULL + .indent_mods = 0L ) s_num_patients( From 9968aa170f3380631a4fa7c42b1bddc327de112a Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 13:22:42 -0500 Subject: [PATCH 2/9] Remove count_occurrences() default for empty data frames - not needed --- R/count_occurrences.R | 5 ----- 1 file changed, 5 deletions(-) diff --git a/R/count_occurrences.R b/R/count_occurrences.R index a8daf84821..babf113982 100644 --- a/R/count_occurrences.R +++ b/R/count_occurrences.R @@ -170,11 +170,6 @@ a_count_occurrences <- function(df, .stats <- default_and_custom_stats_list$all_stats custom_stat_functions <- default_and_custom_stats_list$custom_stats - # if empty, return NA - if (nrow(df) == 0) { - return(in_rows(.list = as.list(rep(NA, length(.stats))) %>% stats::setNames(.stats))) - } - # Apply statistics function x_stats <- .apply_stat_functions( default_stat_fnc = s_count_occurrences, From 3bf6a12b794c4ab15b515bf667fda1eac6934ac7 Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 13:23:08 -0500 Subject: [PATCH 3/9] Add processing for unnamed labels/formats for backwards compatibility --- R/utils_default_stats_formats_labels.R | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R index 667d163668..72b0054a72 100644 --- a/R/utils_default_stats_formats_labels.R +++ b/R/utils_default_stats_formats_labels.R @@ -271,6 +271,15 @@ get_formats_from_stats <- function(stats, } checkmate::assert_list(levels_per_stats, null.ok = TRUE) + # If unnamed formats given as formats_in and same number of stats, use one format per stat + if ( + !is.null(formats_in) && length(formats_in) == length(stats) && + is.null(names(formats_in)) && is.null(levels_per_stats) # nolint + ) { + out <- as.list(formats_in) %>% setNames(stats) + return(out) + } + # If levels_per_stats not given, assume one row per statistic if (is.null(levels_per_stats)) levels_per_stats <- as.list(stats) %>% setNames(stats) @@ -318,6 +327,15 @@ get_labels_from_stats <- function(stats, } checkmate::assert_list(levels_per_stats, null.ok = TRUE) + # If unnamed labels given as labels_in and same number of stats, use one label per stat + if ( + !is.null(labels_in) && length(labels_in) == length(stats) && + is.null(names(labels_in)) && is.null(levels_per_stats) # nolint + ) { + out <- as.list(labels_in) %>% setNames(stats) + return(out) + } + # If levels_per_stats not given, assume one row per statistic if (is.null(levels_per_stats)) levels_per_stats <- as.list(stats) %>% setNames(stats) From 925ec179273fb98d63b42d70e8265028dadc8130 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:26:43 +0000 Subject: [PATCH 4/9] [skip style] [skip vbump] Restyle files --- R/utils_default_stats_formats_labels.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R index 72b0054a72..f644fef376 100644 --- a/R/utils_default_stats_formats_labels.R +++ b/R/utils_default_stats_formats_labels.R @@ -274,7 +274,7 @@ get_formats_from_stats <- function(stats, # If unnamed formats given as formats_in and same number of stats, use one format per stat if ( !is.null(formats_in) && length(formats_in) == length(stats) && - is.null(names(formats_in)) && is.null(levels_per_stats) # nolint + is.null(names(formats_in)) && is.null(levels_per_stats) # nolint ) { out <- as.list(formats_in) %>% setNames(stats) return(out) @@ -330,7 +330,7 @@ get_labels_from_stats <- function(stats, # If unnamed labels given as labels_in and same number of stats, use one label per stat if ( !is.null(labels_in) && length(labels_in) == length(stats) && - is.null(names(labels_in)) && is.null(levels_per_stats) # nolint + is.null(names(labels_in)) && is.null(levels_per_stats) # nolint ) { out <- as.list(labels_in) %>% setNames(stats) return(out) From 1f8538f0d868e90ea6a2030989bec7d2902bc318 Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 13:34:06 -0500 Subject: [PATCH 5/9] Fix lint --- R/utils_default_stats_formats_labels.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/utils_default_stats_formats_labels.R b/R/utils_default_stats_formats_labels.R index f644fef376..19bc8f8989 100644 --- a/R/utils_default_stats_formats_labels.R +++ b/R/utils_default_stats_formats_labels.R @@ -274,7 +274,7 @@ get_formats_from_stats <- function(stats, # If unnamed formats given as formats_in and same number of stats, use one format per stat if ( !is.null(formats_in) && length(formats_in) == length(stats) && - is.null(names(formats_in)) && is.null(levels_per_stats) # nolint + is.null(names(formats_in)) && is.null(levels_per_stats) ) { out <- as.list(formats_in) %>% setNames(stats) return(out) @@ -330,7 +330,7 @@ get_labels_from_stats <- function(stats, # If unnamed labels given as labels_in and same number of stats, use one label per stat if ( !is.null(labels_in) && length(labels_in) == length(stats) && - is.null(names(labels_in)) && is.null(levels_per_stats) # nolint + is.null(names(labels_in)) && is.null(levels_per_stats) ) { out <- as.list(labels_in) %>% setNames(stats) return(out) From 9ba4661ea07f2fc3982e4c7a5c5410e63a781eba Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 13:46:45 -0500 Subject: [PATCH 6/9] Update test --- .../_snaps/count_occurrences_by_grade.md | 26 +++++++++---------- .../test-count_occurrences_by_grade.R | 1 - 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/testthat/_snaps/count_occurrences_by_grade.md b/tests/testthat/_snaps/count_occurrences_by_grade.md index 9f2e657c22..d849cedc3c 100644 --- a/tests/testthat/_snaps/count_occurrences_by_grade.md +++ b/tests/testthat/_snaps/count_occurrences_by_grade.md @@ -602,17 +602,17 @@ Code res Output - A: Drug X B: Placebo C: Combination Risk Difference (%) (95% CI) - (N=202) (N=177) (N=162) (N=379) - ————————————————————————————————————————————————————————————————————————————————————— - F - -Any- 20 (9.9%) 19 (10.7%) 19 (11.7%) -0.8 (-7.0 - 5.3) - MILD 2 (1.0%) 2 (1.1%) 0 -0.1 (-2.2 - 1.9) - MODERATE 4 (2.0%) 3 (1.7%) 3 (1.9%) 0.3 (-2.4 - 3.0) - SEVERE 14 (6.9%) 14 (7.9%) 16 (9.9%) -1.0 (-6.3 - 4.3) - M - -Any- 14 (6.9%) 21 (11.9%) 17 (10.5%) -4.9 (-10.8 - 1.0) - MILD 1 (0.5%) 0 1 (0.6%) 0.5 (-0.5 - 1.5) - MODERATE 4 (2.0%) 7 (4.0%) 5 (3.1%) -2.0 (-5.4 - 1.5) - SEVERE 9 (4.5%) 14 (7.9%) 11 (6.8%) -3.5 (-8.3 - 1.4) + A: Drug X B: Placebo C: Combination Risk Difference (%) (95% CI) + (N=202) (N=177) (N=162) (N=379) + ——————————————————————————————————————————————————————————————————————————————————— + F + -Any- 20 (9.9%) 19 (10.7%) 19 (11.7%) -0.8 (-7.0 - 5.3) + MILD 2 (1.0%) 2 (1.1%) 0 -0.1 (-2.2 - 1.9) + MODERATE 4 (2.0%) 3 (1.7%) 3 (1.9%) 0.3 (-2.4 - 3.0) + SEVERE 14 (6.9%) 14 (7.9%) 16 (9.9%) -1.0 (-6.3 - 4.3) + M + -Any- 14 (6.9%) 21 (11.9%) 17 (10.5%) -4.9 (-10.8 - 1.0) + MILD 1 (0.5%) 0 1 (0.6%) 0.5 (-0.5 - 1.5) + MODERATE 4 (2.0%) 7 (4.0%) 5 (3.1%) -2.0 (-5.4 - 1.5) + SEVERE 9 (4.5%) 14 (7.9%) 11 (6.8%) -3.5 (-8.3 - 1.4) diff --git a/tests/testthat/test-count_occurrences_by_grade.R b/tests/testthat/test-count_occurrences_by_grade.R index b60cf99373..d3bf1cf4bc 100644 --- a/tests/testthat/test-count_occurrences_by_grade.R +++ b/tests/testthat/test-count_occurrences_by_grade.R @@ -483,7 +483,6 @@ testthat::test_that("summarize_occurrences works as expected with risk differenc summarize_occurrences_by_grade( var = "AESEV", riskdiff = TRUE, - .indent_mods = 1L, grade_groups = grade_groups, id = "SITEID" ) %>% From 266d9656acf3e65a8c0e9515550c52188eb86c94 Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Thu, 6 Mar 2025 14:06:02 -0500 Subject: [PATCH 7/9] Change condition for empty return --- R/count_occurrences.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/R/count_occurrences.R b/R/count_occurrences.R index babf113982..c5887c8150 100644 --- a/R/count_occurrences.R +++ b/R/count_occurrences.R @@ -181,6 +181,11 @@ a_count_occurrences <- function(df, ) ) + # if empty, return NA + if (is.null(unlist(x_stats))) { + return(in_rows(.list = as.list(rep(NA, length(.stats))) %>% stats::setNames(.stats))) + } + # Fill in formatting defaults .stats <- get_stats("count_occurrences", stats_in = .stats, custom_stats_in = names(custom_stat_functions)) x_stats <- x_stats[.stats] From af45aeb1c54724a8e5872c0608f4f4d07dee3913 Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Fri, 7 Mar 2025 16:39:23 -0500 Subject: [PATCH 8/9] Add test --- tests/testthat/_snaps/summarize_num_patients.md | 10 ++++++++++ tests/testthat/test-summarize_num_patients.R | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/tests/testthat/_snaps/summarize_num_patients.md b/tests/testthat/_snaps/summarize_num_patients.md index 2a3cc0c5a8..4eb52dabbf 100644 --- a/tests/testthat/_snaps/summarize_num_patients.md +++ b/tests/testthat/_snaps/summarize_num_patients.md @@ -304,6 +304,16 @@ Number of events 4 3 (n) 3 3 +# summarize_num_patients works with single unnamed .labels/.formats values + + Code + res + Output + A B + (N=5) (N=4) + ——————————————————————————— + - Overall - 3.00 3.00 + # analyze_num_patients works well for pagination Code diff --git a/tests/testthat/test-summarize_num_patients.R b/tests/testthat/test-summarize_num_patients.R index f0360224ba..402f774582 100644 --- a/tests/testthat/test-summarize_num_patients.R +++ b/tests/testthat/test-summarize_num_patients.R @@ -209,6 +209,22 @@ testthat::test_that( testthat::expect_snapshot(res) } ) +testthat::test_that("summarize_num_patients works with single unnamed .labels/.formats values", { + df <- data.frame( + USUBJID = as.character(c(1, 2, 1, 4, NA, 6, 6, 8, 9)), + ARM = c("A", "A", "A", "A", "A", "B", "B", "B", "B"), + AGE = c(10, 15, 10, 17, 8, 11, 11, 19, 17) + ) + + result <- basic_table() %>% + split_cols_by("ARM") %>% + add_colcounts() %>% + summarize_num_patients("USUBJID", .stats = "unique_count", .labels = "- Overall -", .formats = "xx.xx") %>% + build_table(df) + + res <- testthat::expect_silent(result) + testthat::expect_snapshot(res) +}) testthat::test_that("analyze_num_patients works well for pagination", { set.seed(1) From 557046ad6ebd06b3cf408b969975b8023bef2acc Mon Sep 17 00:00:00 2001 From: Emily de la Rua Date: Mon, 10 Mar 2025 16:37:12 -0400 Subject: [PATCH 9/9] Send na_rm to afun --- R/summarize_change.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/summarize_change.R b/R/summarize_change.R index 7cc73614a2..bc3ebb89ff 100644 --- a/R/summarize_change.R +++ b/R/summarize_change.R @@ -181,6 +181,7 @@ summarize_change <- function(lyt, extra_args <- c( extra_args, variables = list(variables), + na_rm = na_rm, ... )