From 0a027b1419e9025fac7b175c248dbc7c9133a01b Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:45:37 +0100 Subject: [PATCH 01/21] Push for question --- R/fda-table_35.R | 64 +++++++++++++++++++++++++++++++++++++++----- man/make_table_35.Rd | 17 +++++++----- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index 2da4201b..cda78558 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -2,23 +2,75 @@ #' Safety Population, Pooled Analysis (or Trial X) #' #' @details -#' * `adae` must contain the variables specified by +#' * `df` must contain the variables specified by #' `arm_var`, `id_var`, `soc_var` and `saffl_var`. -#' * If specified, `alt_counts_df` must contain the variables specified by `arm_var`, `id_var`, and `saffl_var`. -#' * Columns are split by arm. Overall population column is excluded by default (see `lbl_overall` argument). -#' * All-zero rows are removed by default (see `prune_0` argument). +#' * `return_ard` set to `TRUE` or `FALSE`; whether the intermediate ARD object should be returned. #' #' @inheritParams argument_convention +#' @param soc_var (`character`)\cr Name of the variable that contains the SOC to describe. +#' +#' @return A `gtsummary` table and, if `return_ard = TRUE`, an ARD. +#' If `return_ard = TRUE`, they will be returned as a list with named elements `table` and `ard`. +#' +#' @seealso [`tbl_make_table_35`] #' #' @examples #' adsl <- random.cdisc.data::cadsl #' adae <- random.cdisc.data::cadae #' -#' tbl <- make_table_35(adae = adae, alt_counts_df = adsl) +#' tbl <- make_table_35(df = adae, denominator = adsl) #' tbl #' #' @export -make_table_35 <- function(adae, +make_table_35 <- function(df, + denominator, + return_ard = TRUE, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AESOC", + lbl_overall = NULL) { + +assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) +assert_flag_variables(df, saffl_var) +assert_subset(c(arm_var, id_var, saffl_var), names(denominator)) +assert_flag_variables(denominator, saffl_var) + +df <- df %>% + filter(.data[[saffl_var]] == "Y") %>% + arrange(soc_var) %>% + df_explicit_na() + +df_denom <- denominator %>% filter(.data[[saffl_var]] == "Y") + +tbl_gts <- + tbl_hierarchical( + data = df, + variables = soc_var, + by = arm_var, + denominator = df_denom, + id = id_var + ) + + if (!is.null(lbl_overall)) { + tbl_gts <- tbl_gts %>% + add_overall(last = TRUE, col_label = paste0("**", lbl_overall, "** \n N = {n}")) + } +} + + + + + + + + + + + + + +make_table_35_rtables <- function(adae, alt_counts_df = NULL, show_colcounts = TRUE, id_var = "USUBJID", diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index 6556f6d6..0b787cc6 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -33,7 +33,7 @@ make_table_35( \item{saffl_var}{(\code{character})\cr flag variable used to indicate inclusion in safety population.} -\item{soc_var}{(\code{character})\cr Name of the system organ class variable from \code{adae} to include in the table.} +\item{soc_var}{(\code{character})\cr Name of the variable that contains the SOC to describe.} \item{lbl_soc_var}{(\code{character})\cr label corresponding to system organ class variable \code{soc_var} to print in the table.} @@ -60,24 +60,29 @@ be included in the column labels by default. The length of \code{col_label} must annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should use the annotation type as name and the desired string as value.} } +\value{ +A \code{gtsummary} table and, if \code{return_ard = TRUE}, an ARD. +If \code{return_ard = TRUE}, they will be returned as a list with named elements \code{table} and \code{ard}. +} \description{ Table 35. Patients With Adverse Events by System Organ Class, Safety Population, Pooled Analysis (or Trial X) } \details{ \itemize{ -\item \code{adae} must contain the variables specified by +\item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{soc_var} and \code{saffl_var}. -\item If specified, \code{alt_counts_df} must contain the variables specified by \code{arm_var}, \code{id_var}, and \code{saffl_var}. -\item Columns are split by arm. Overall population column is excluded by default (see \code{lbl_overall} argument). -\item All-zero rows are removed by default (see \code{prune_0} argument). +\item \code{return_ard} set to \code{TRUE} or \code{FALSE}; whether the intermediate ARD object should be returned. } } \examples{ adsl <- random.cdisc.data::cadsl adae <- random.cdisc.data::cadae -tbl <- make_table_35(adae = adae, alt_counts_df = adsl) +tbl <- make_table_35(df = adae, denominator = adsl) tbl } +\seealso{ +\code{\link{tbl_make_table_35}} +} From 838a98a670e782b2c4fe8412e6e8a46333b4edb4 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 25 Nov 2024 16:28:36 +0100 Subject: [PATCH 02/21] Add tests --- NAMESPACE | 2 + R/alex_draft_0.R | 65 +++++++ R/alex_draft_1.R | 51 +++++ R/alex_draft_ard.R | 63 ++++++ R/fda-table_35.R | 264 +++++++++++++++++++++----- R/fda-table_35_draft.R | 166 ++++++++++++++++ man/ard_make_table_35.Rd | 32 ++++ man/make_table_35.Rd | 41 +--- man/preproc_df_table_35.Rd | 19 ++ man/tbl_make_table_35.Rd | 116 +++++++++++ tests/testthat/_snaps/fda-table_35.md | 112 ++--------- tests/testthat/test-fda-table_35.R | 47 ++++- 12 files changed, 799 insertions(+), 179 deletions(-) create mode 100644 R/alex_draft_0.R create mode 100644 R/alex_draft_1.R create mode 100644 R/alex_draft_ard.R create mode 100644 R/fda-table_35_draft.R create mode 100644 man/ard_make_table_35.Rd create mode 100644 man/preproc_df_table_35.Rd create mode 100644 man/tbl_make_table_35.Rd diff --git a/NAMESPACE b/NAMESPACE index c0d69c5b..b08af1da 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -36,6 +36,8 @@ export(make_table_33) export(make_table_33_gtsum) export(make_table_34) export(make_table_35) +export(make_table_35_gtsummary) +export(make_table_35_rtables) export(make_table_36) export(make_table_38) export(split_cols_by_arm) diff --git a/R/alex_draft_0.R b/R/alex_draft_0.R new file mode 100644 index 00000000..2adedb8d --- /dev/null +++ b/R/alex_draft_0.R @@ -0,0 +1,65 @@ +# source("R/utils.R") +# source("R/fda-table_35.R") +# +# # adsl <- random.cdisc.data::cadsl +# # adae <- random.cdisc.data::cadae +# # +# # tblo <- make_table_35(df = adae, denominator = adsl, lbl_overall = "abc") +# # tblo +# +# +# adsl <- random.cdisc.data::cadsl +# adae <- random.cdisc.data::cadae +# +# tbl <- make_table_35(df = adae, denominator = adsl) +# tbl +# +# tbl_overall <- +# tbl_hierarchical( +# data = adae, +# variables = "AESOC", +# # by = arm_var, +# denominator = adsl, +# id = "USUBJID" +# ) %>% +# modify_header(all_stat_cols() ~ "**Overall** \nN = {n}") +# +# tbl_overall +# +# tbl_df <- as.data.frame(tbl) +# tbl_overall_df <- as.data.frame(tbl_overall) +# +# tbl_all <- +# left_join( +# x = tbl_df, +# y = tbl_overall_df, +# by = "**Primary System Organ Class**" +# ) +# +# tbl_all_gt <- gt(tbl_all) +# tbl_all_gt +# +# tbl_all_gt2 <- gtsummary::with_gtsummary_theme( +# x = gtsummary::theme_gtsummary_compact(), +# expr = tbl_all_gt +# ) +# +# tbl_all_gt2 +# +# cols_names <- colnames(tbl_all) +# cols_names +# tbl_all_gt2_md <- +# tbl_all %>% +# gt() %>% +# cols_label( +# .list = setNames(lapply(cols_names, md), cols_names) +# ) +# +# tbl_all_gt2_md +# +# tbl_final <- gtsummary::with_gtsummary_theme( +# x = gtsummary::theme_gtsummary_compact(), +# expr = tbl_all_gt2_md +# ) +# +# tbl_final diff --git a/R/alex_draft_1.R b/R/alex_draft_1.R new file mode 100644 index 00000000..3b4b5484 --- /dev/null +++ b/R/alex_draft_1.R @@ -0,0 +1,51 @@ +# # Load ----- +# source("R/utils.R") +# source("R/fda-table_35.R") +# +# # No lbl_overall ----- +# adsl <- random.cdisc.data::cadsl +# adae <- random.cdisc.data::cadae +# +# tbl <- make_table_35(df = adae, denominator = adsl) +# +# tbl_ovrl <- +# tbl_hierarchical( +# data = adae, +# variables = "AESOC", +# # by = arm_var, +# denominator = adsl, +# id = "USUBJID" +# ) %>% +# modify_header(label ~ paste0("**System Organ Class**")) %>% +# modify_header(all_stat_cols() ~ "**Overall** \nN = {n}") %>% +# gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") +# +# +# tbl <- as.data.frame(tbl) +# tbl_ovrl <- as.data.frame(tbl_ovrl) +# +# tbl_all <- left_join(x = tbl, y = tbl_ovrl, by = "**System Organ Class**") +# +# cols_names <- colnames(tbl_all) +# cols_names +# tbl_all_gt2_md <- +# tbl_all %>% +# gt() %>% +# cols_label( +# .list = setNames(lapply(cols_names, md), cols_names) +# ) +# +# tbl_all_gt2_md +# +# # lbl_overall ----- +# +# adsl <- random.cdisc.data::cadsl +# adae <- random.cdisc.data::cadae +# +# tbl <- +# make_table_35( +# df = adae, +# denominator = adsl, +# lbl_overall = "def" +# ) +# tbl diff --git a/R/alex_draft_ard.R b/R/alex_draft_ard.R new file mode 100644 index 00000000..9fbbfe19 --- /dev/null +++ b/R/alex_draft_ard.R @@ -0,0 +1,63 @@ +# source("R/utils.R") +# source("R/fda-table_35.R") +# +# adsl <- random.cdisc.data::cadsl +# adae <- random.cdisc.data::cadae +# +# tbl <- make_table_35(df = adae, denominator = adsl, lbl_overall = "def") +# tbl +# +# ard <- +# cards::ard_stack_hierarchical( +# data = adae %>% filter(SAFFL == "Y"), +# variables = c(AESOC), +# by = TRT01A, +# denominator = adsl %>% filter(SAFFL == "Y"), +# id = USUBJID, +# overall = TRUE +# ) +# +# ard <- +# cards::ard_stack_hierarchical( +# data = adae %>% filter(SAFFL == "Y"), +# variables = c(AESOC), +# by = TRT01A, +# denominator = adsl %>% filter(SAFFL == "Y"), +# id = USUBJID, +# overall = TRUE +# ) +# +# +# +# +# AESOC +# +# +# +# +# +# +# ADAE_subset <- cards::ADAE |> +# dplyr::filter( +# AESOC %in% unique(cards::ADAE$AESOC)[1:5], +# AETERM %in% unique(cards::ADAE$AETERM)[1:5] +# ) +# +# # Example 1: Event Rates -------------------- +# # First, build the ARD +# ard <- +# cards::ard_stack_hierarchical( +# data = ADAE_subset, +# variables = c(AESOC, AETERM), +# by = TRTA, +# denominator = cards::ADSL |> mutate(TRTA = ARM), +# id = USUBJID, +# overall = TRUE +# ) +# +# # Second, build table from the ARD +# tbl_ard_hierarchical( +# cards = ard, +# variables = c(AESOC, AETERM), +# by = TRTA +# ) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index cda78558..d932af27 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -28,81 +28,251 @@ make_table_35 <- function(df, id_var = "USUBJID", arm_var = "ARM", saffl_var = "SAFFL", - soc_var = "AESOC", - lbl_overall = NULL) { - -assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) -assert_flag_variables(df, saffl_var) -assert_subset(c(arm_var, id_var, saffl_var), names(denominator)) -assert_flag_variables(denominator, saffl_var) - -df <- df %>% - filter(.data[[saffl_var]] == "Y") %>% - arrange(soc_var) %>% - df_explicit_na() - -df_denom <- denominator %>% filter(.data[[saffl_var]] == "Y") - -tbl_gts <- - tbl_hierarchical( - data = df, - variables = soc_var, - by = arm_var, - denominator = df_denom, - id = id_var + soc_var = "AEBODSYS", + lbl_overall = NULL, + na_level = "") { + + ard <- ard_table_35( + df = df, + denominator = denominator, + id_var = id_var, + arm_var = arm_var, + saffl_var = saffl_var, + soc_var = soc_var, + na_level = na_level ) - if (!is.null(lbl_overall)) { - tbl_gts <- tbl_gts %>% - add_overall(last = TRUE, col_label = paste0("**", lbl_overall, "** \n N = {n}")) + tbl <- make_table_35_gtsummary( + df = df, + denominator = denominator, + id_var = id_var, + arm_var = arm_var, + saffl_var = saffl_var, + soc_var = soc_var, + na_level = na_level + ) + + if (return_ard) { + return(list(table = tbl, ard = ard)) + } else { + return(tbl) # nocov } + } +#' Pre-Process Data for Table 35 Creation +#' +#' @keywords internal +preproc_df_table_35 <- function(df, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + na_level = "") { + assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) + assert_flag_variables(df, saffl_var) + df <- df |> + filter(.data[[saffl_var]] == "Y") |> + arrange(soc_var) |> + df_explicit_na(na_level = na_level) + df +} +#' Make ARD: Table 35 +#' +#' @examples +#' library(dplyr) +#' +#' adsl <- random.cdisc.data::cadsl +#' adae <- random.cdisc.data::cadae +#' +#' ard <- cardinal:::ard_table_35(adae, adsl) +#' ard +#' +#' @keywords internal +#' @name ard_make_table_35 +ard_table_35 <- function(df, + denominator = NULL, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_overall = NULL, + na_level = "") { + df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) + if (is.null(denominator)) { + denominator <- df # nocov + } + else { + denominator <- + alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) + } + ard <- + cards::ard_stack_hierarchical( + data = df, + variables = all_of(soc_var), + by = all_of(arm_var), + denominator = denominator, + id = all_of(id_var), + overall = !is.null(lbl_overall) + ) + ard +} +#' Engine-Specific Functions: Table 35 +#' +#' The table engine used by each engine-specific function is identified by its suffix. +#' +#' @inheritParams argument_convention +#' +#' @details +#' * `df` must contain the variables the variables specified by +#' `arm_var`, `id_var`, `saffl_var`, and `soc_var`. +#' * If specified, `denominator` (or `alt_counts_df`) must contain `USUBJID` and the variables specified by `arm_var` +#' and `saffl_var`. +#' * Flag variables (i.e. `XXXFL`) are expected to have two levels: `"Y"` (true) and `"N"` (false). Missing values in +#' flag variables are treated as `"N"`. +#' * Numbers in table represent the absolute numbers of patients and fraction of `N`. +#' * All-zero rows are removed by default by `make_table_35_rtables()` (see `prune_0` argument). +#' +#' @return +#' * `make_table_35_gtsummary()` returns a `gtsummary` object. +#' * `make_table_35_rtables()` returns an `rtable` object. +#' +#' @seealso [make_table_35()] +#' +#' @examples +#' library(dplyr) +#' +#' adsl <- random.cdisc.data::cadsl +#' adae <- random.cdisc.data::cadae +#' +#' # gtsummary table -------------- +#' tbl_gtsummary <- cardinal:::make_table_35_gtsummary(df = adae, denominator = adsl) +#' tbl_gtsummary +#' +#' # rtables table ---------------- +#' tbl_rtables <- cardinal:::make_table_35_rtables(df = adae, alt_counts_df = adsl) +#' tbl_rtables +#' +#' @export +#' @name tbl_make_table_35 +make_table_35_gtsummary <- function(df, + denominator = NULL, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_overall = NULL, + na_level = "") { + df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) + if (is.null(denominator)) { + denominator <- df # nocov + } + else { + denominator <- + alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) + } -make_table_35_rtables <- function(adae, - alt_counts_df = NULL, - show_colcounts = TRUE, - id_var = "USUBJID", - arm_var = "ARM", - saffl_var = "SAFFL", - soc_var = "AESOC", - lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], - lbl_overall = NULL, - risk_diff = NULL, - prune_0 = FALSE, - annotations = NULL) { - assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(adae)) - assert_flag_variables(adae, saffl_var) + tbl_gts <- + tbl_hierarchical( + data = df, + variables = soc_var, + by = arm_var, + denominator = denominator, + id = id_var + ) |> + modify_header(label ~ paste0("**System Organ Class**")) |> + modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> + gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") - adae <- adae %>% - filter(.data[[saffl_var]] == "Y") %>% - arrange(soc_var) %>% - df_explicit_na() + if (!is.null(lbl_overall)) { + tbl_gts_ovrl <- + tbl_hierarchical( + data = df, + variables = soc_var, + denominator = df_denom, + id = id_var + ) |> + modify_header(label ~ paste0("**System Organ Class**")) |> + modify_header( + all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") + ) |> + gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") + tbl_gts_df <- as.data.frame(tbl_gts) + tbl_gts_ovrl_df <- as.data.frame(tbl_gts_ovrl) + + tbl_gts_all_df <- + left_join( + x = tbl_gts_df, + y = tbl_gts_ovrl_df, + by = "**System Organ Class**" + ) + + cols_names <- colnames(tbl_gts_all_df) + + tbl_gts <- + tbl_gts_all_df |> + gt() |> + cols_label( + .list = setNames(lapply(cols_names, md), cols_names) + ) + + tbl <- gtsummary::with_gtsummary_theme( + x = gtsummary::theme_gtsummary_compact(), + expr = tbl_gts + ) + } + + else { + tbl_gts <- tbl_gts + + tbl <- gtsummary::with_gtsummary_theme( + x = gtsummary::theme_gtsummary_compact(), + expr = as_gt(tbl_gts) + ) + } +} + +#' @export +#' @rdname tbl_make_table_35 +make_table_35_rtables <- function(df, + alt_counts_df = NULL, + show_colcounts = TRUE, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], + lbl_overall = NULL, + risk_diff = NULL, + prune_0 = FALSE, + na_level = "", + annotations = NULL) { + df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) alt_counts_df <- alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) - lyt <- basic_table_annot(show_colcounts, annotations) %>% - split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% + lyt <- basic_table_annot(show_colcounts, annotations) |> + split_cols_by_arm(arm_var, lbl_overall, risk_diff) |> count_occurrences( vars = soc_var, drop = FALSE, riskdiff = !is.null(risk_diff) - ) %>% + ) |> append_topleft(c("", lbl_soc_var)) - tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) %>% + tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) |> sort_at_path( path = c(soc_var), scorefun = score_occurrences_cols(col_names = levels(adae[[arm_var]])) diff --git a/R/fda-table_35_draft.R b/R/fda-table_35_draft.R new file mode 100644 index 00000000..6e3bc73c --- /dev/null +++ b/R/fda-table_35_draft.R @@ -0,0 +1,166 @@ +#' #' Table 35. Patients With Adverse Events by System Organ Class, +#' #' Safety Population, Pooled Analysis (or Trial X) +#' #' +#' #' @details +#' #' * `df` must contain the variables specified by +#' #' `arm_var`, `id_var`, `soc_var` and `saffl_var`. +#' #' * `return_ard` set to `TRUE` or `FALSE`; whether the intermediate ARD object should be returned. +#' #' +#' #' @inheritParams argument_convention +#' #' @param soc_var (`character`)\cr Name of the variable that contains the SOC to describe. +#' #' +#' #' @return A `gtsummary` table and, if `return_ard = TRUE`, an ARD. +#' #' If `return_ard = TRUE`, they will be returned as a list with named elements `table` and `ard`. +#' #' +#' #' @seealso [`tbl_make_table_35`] +#' #' +#' #' @examples +#' #' adsl <- random.cdisc.data::cadsl +#' #' adae <- random.cdisc.data::cadae +#' #' +#' #' tbl <- make_table_35(df = adae, denominator = adsl) +#' #' tbl +#' #' +#' #' @export +#' make_table_35 <- function(df, +#' denominator, +#' return_ard = TRUE, +#' id_var = "USUBJID", +#' arm_var = "ARM", +#' saffl_var = "SAFFL", +#' soc_var = "AESOC", +#' lbl_overall = NULL) { +#' +#' assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) +#' assert_flag_variables(df, saffl_var) +#' assert_subset(c(arm_var, id_var, saffl_var), names(denominator)) +#' assert_flag_variables(denominator, saffl_var) +#' +#' df <- df %>% +#' filter(.data[[saffl_var]] == "Y") %>% +#' arrange(soc_var) %>% +#' df_explicit_na() +#' +#' df_denom <- denominator %>% filter(.data[[saffl_var]] == "Y") +#' +#' tbl_gts <- +#' tbl_hierarchical( +#' data = df, +#' variables = soc_var, +#' by = arm_var, +#' denominator = df_denom, +#' id = id_var +#' ) %>% +#' modify_header(label ~ paste0("**System Organ Class**")) %>% +#' modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") %>% +#' gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") +#' +#' if (!is.null(lbl_overall)) { +#' tbl_gts_ovrl <- +#' tbl_hierarchical( +#' data = df, +#' variables = soc_var, +#' denominator = df_denom, +#' id = id_var +#' ) %>% +#' modify_header(label ~ paste0("**System Organ Class**")) %>% +#' modify_header( +#' all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") +#' ) %>% +#' gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") +#' +#' tbl_gts_df <- as.data.frame(tbl_gts) +#' tbl_gts_ovrl_df <- as.data.frame(tbl_gts_ovrl) +#' +#' tbl_gts_all_df <- +#' left_join( +#' x = tbl_gts_df, +#' y = tbl_gts_ovrl_df, +#' by = "**System Organ Class**" +#' ) +#' +#' cols_names <- colnames(tbl_gts_all_df) +#' +#' tbl_gts <- +#' tbl_gts_all_df %>% +#' gt() %>% +#' cols_label( +#' .list = setNames(lapply(cols_names, md), cols_names) +#' ) +#' +#' tbl <- gtsummary::with_gtsummary_theme( +#' x = gtsummary::theme_gtsummary_compact(), +#' expr = tbl_gts +#' ) +#' } +#' +#' else { +#' tbl_gts <- tbl_gts +#' +#' tbl <- gtsummary::with_gtsummary_theme( +#' x = gtsummary::theme_gtsummary_compact(), +#' expr = as_gt(tbl_gts) +#' ) +#' } +#' +#' if (return_ard) { +#' +#' } +#' +#' +#' return(tbl) +#' } +#' +#' +#' +#' +#' +#' +#' +#' +#' +#' +#' +#' +#' +#' make_table_35_rtables <- function(adae, +#' alt_counts_df = NULL, +#' show_colcounts = TRUE, +#' id_var = "USUBJID", +#' arm_var = "ARM", +#' saffl_var = "SAFFL", +#' soc_var = "AESOC", +#' lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], +#' lbl_overall = NULL, +#' risk_diff = NULL, +#' prune_0 = FALSE, +#' annotations = NULL) { +#' assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(adae)) +#' assert_flag_variables(adae, saffl_var) +#' +#' adae <- adae %>% +#' filter(.data[[saffl_var]] == "Y") %>% +#' arrange(soc_var) %>% +#' df_explicit_na() +#' +#' alt_counts_df <- +#' alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) +#' +#' lyt <- basic_table_annot(show_colcounts, annotations) %>% +#' split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% +#' count_occurrences( +#' vars = soc_var, +#' drop = FALSE, +#' riskdiff = !is.null(risk_diff) +#' ) %>% +#' append_topleft(c("", lbl_soc_var)) +#' +#' tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) %>% +#' sort_at_path( +#' path = c(soc_var), +#' scorefun = score_occurrences_cols(col_names = levels(adae[[arm_var]])) +#' ) +#' if (prune_0) tbl <- prune_table(tbl) +#' +#' tbl +#' } diff --git a/man/ard_make_table_35.Rd b/man/ard_make_table_35.Rd new file mode 100644 index 00000000..ba4b38e6 --- /dev/null +++ b/man/ard_make_table_35.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fda-table_35.R +\name{ard_make_table_35} +\alias{ard_make_table_35} +\alias{ard_table_35} +\title{Make ARD: Table 35} +\usage{ +ard_table_35( + df, + denominator = NULL, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_overall = NULL, + na_level = "" +) +} +\description{ +Make ARD: Table 35 +} +\examples{ +library(dplyr) + +adsl <- random.cdisc.data::cadsl +adae <- random.cdisc.data::cadae + +ard <- cardinal:::ard_table_35(adae, adsl) +ard + +} +\keyword{internal} diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index 0b787cc6..694561c0 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -6,26 +6,19 @@ Safety Population, Pooled Analysis (or Trial X)} \usage{ make_table_35( - adae, - alt_counts_df = NULL, - show_colcounts = TRUE, + df, + denominator, + return_ard = TRUE, id_var = "USUBJID", arm_var = "ARM", saffl_var = "SAFFL", - soc_var = "AESOC", - lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], + soc_var = "AEBODSYS", lbl_overall = NULL, - risk_diff = NULL, - prune_0 = FALSE, - annotations = NULL + na_level = "" ) } \arguments{ -\item{adae}{(\code{data.frame})\cr dataset (typically ADAE) required to build table.} - -\item{alt_counts_df}{(\code{character})\cr alternative dataset (typically ADSL) used only to calculate column counts.} - -\item{show_colcounts}{(\code{flag})\cr Whether column counts should be printed. Boolean.} +\item{df}{(\code{data.frame})\cr dataset required to build table.} \item{id_var}{(\code{character})\cr variable used as unique subject identifier.} @@ -35,30 +28,10 @@ make_table_35( \item{soc_var}{(\code{character})\cr Name of the variable that contains the SOC to describe.} -\item{lbl_soc_var}{(\code{character})\cr label corresponding to system organ class variable \code{soc_var} to print in the -table.} - \item{lbl_overall}{(\code{character})\cr if specified, an overall column will be added to the table with the given value as the column label.} -\item{risk_diff}{(named \code{list})\cr list of settings to apply to add one or more risk difference columns to the table. -Defaults to \code{NULL} (no risk difference column added). See \code{\link[tern:add_riskdiff]{tern::add_riskdiff()}} for more details. List should -contain the following elements: -\itemize{ -\item \code{arm_x}: (required) the name of reference arm. -\item \code{arm_y}: (required) the names of the arms to compare to the reference arm. A new column will be added for each -element of \code{arm_y}. -\item \code{col_label}: (optional) labels to use for the risk difference columns. Defaults to -\code{"Risk Difference (\%) (95\% CI)"}. For more than one risk difference column, \code{"arm x vs. arm y"} text will also -be included in the column labels by default. The length of \code{col_label} must be equal to the length of \code{arm_y}. -\item \code{pct}: (optional) whether the output should be returned as percentages. Defaults to \code{TRUE}. -}} - -\item{prune_0}{(\code{flag})\cr Whether all-zero rows should be removed from the table. Boolean.} - -\item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid -annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should -use the annotation type as name and the desired string as value.} +\item{na_level}{(\code{character})\cr string to represent missing values.} } \value{ A \code{gtsummary} table and, if \code{return_ard = TRUE}, an ARD. diff --git a/man/preproc_df_table_35.Rd b/man/preproc_df_table_35.Rd new file mode 100644 index 00000000..f5d3fa51 --- /dev/null +++ b/man/preproc_df_table_35.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fda-table_35.R +\name{preproc_df_table_35} +\alias{preproc_df_table_35} +\title{Pre-Process Data for Table 35 Creation} +\usage{ +preproc_df_table_35( + df, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + na_level = "" +) +} +\description{ +Pre-Process Data for Table 35 Creation +} +\keyword{internal} diff --git a/man/tbl_make_table_35.Rd b/man/tbl_make_table_35.Rd new file mode 100644 index 00000000..2e73080b --- /dev/null +++ b/man/tbl_make_table_35.Rd @@ -0,0 +1,116 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fda-table_35.R +\name{tbl_make_table_35} +\alias{tbl_make_table_35} +\alias{make_table_35_gtsummary} +\alias{make_table_35_rtables} +\title{Engine-Specific Functions: Table 35} +\usage{ +make_table_35_gtsummary( + df, + denominator = NULL, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_overall = NULL, + na_level = "" +) + +make_table_35_rtables( + df, + alt_counts_df = NULL, + show_colcounts = TRUE, + id_var = "USUBJID", + arm_var = "ARM", + saffl_var = "SAFFL", + soc_var = "AEBODSYS", + lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], + lbl_overall = NULL, + risk_diff = NULL, + prune_0 = FALSE, + na_level = "", + annotations = NULL +) +} +\arguments{ +\item{df}{(\code{data.frame})\cr dataset required to build table.} + +\item{id_var}{(\code{character})\cr variable used as unique subject identifier.} + +\item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} + +\item{saffl_var}{(\code{character})\cr flag variable used to indicate inclusion in safety population.} + +\item{soc_var}{(\code{character})\cr Name of the system organ class variable from \code{adae} to include in the table.} + +\item{lbl_overall}{(\code{character})\cr if specified, an overall column will be added to the table with +the given value as the column label.} + +\item{na_level}{(\code{character})\cr string to represent missing values.} + +\item{alt_counts_df}{(\code{character})\cr alternative dataset (typically ADSL) used only to calculate column counts.} + +\item{show_colcounts}{(\code{flag})\cr Whether column counts should be printed. Boolean.} + +\item{lbl_soc_var}{(\code{character})\cr label corresponding to system organ class variable \code{soc_var} to print in the +table.} + +\item{risk_diff}{(named \code{list})\cr list of settings to apply to add one or more risk difference columns to the table. +Defaults to \code{NULL} (no risk difference column added). See \code{\link[tern:add_riskdiff]{tern::add_riskdiff()}} for more details. List should +contain the following elements: +\itemize{ +\item \code{arm_x}: (required) the name of reference arm. +\item \code{arm_y}: (required) the names of the arms to compare to the reference arm. A new column will be added for each +element of \code{arm_y}. +\item \code{col_label}: (optional) labels to use for the risk difference columns. Defaults to +\code{"Risk Difference (\%) (95\% CI)"}. For more than one risk difference column, \code{"arm x vs. arm y"} text will also +be included in the column labels by default. The length of \code{col_label} must be equal to the length of \code{arm_y}. +\item \code{pct}: (optional) whether the output should be returned as percentages. Defaults to \code{TRUE}. +}} + +\item{prune_0}{(\code{flag})\cr Whether all-zero rows should be removed from the table. Boolean.} + +\item{annotations}{(named \code{list} of \code{character})\cr list of annotations to add to the table. Valid +annotation types are \code{title}, \code{subtitles}, \code{main_footer}, and \code{prov_footer}. Each name-value pair should +use the annotation type as name and the desired string as value.} +} +\value{ +\itemize{ +\item \code{make_table_35_gtsummary()} returns a \code{gtsummary} object. +\item \code{make_table_35_rtables()} returns an \code{rtable} object. +} +} +\description{ +The table engine used by each engine-specific function is identified by its suffix. +} +\details{ +\itemize{ +\item \code{df} must contain the variables the variables specified by +\code{arm_var}, \code{id_var}, \code{saffl_var}, and \code{soc_var}. +\item If specified, \code{denominator} (or \code{alt_counts_df}) must contain \code{USUBJID} and the variables specified by \code{arm_var} +and \code{saffl_var}. +\item Flag variables (i.e. \code{XXXFL}) are expected to have two levels: \code{"Y"} (true) and \code{"N"} (false). Missing values in +flag variables are treated as \code{"N"}. +\item Numbers in table represent the absolute numbers of patients and fraction of \code{N}. +\item All-zero rows are removed by default by \code{make_table_35_rtables()} (see \code{prune_0} argument). +} +} +\examples{ +library(dplyr) + +adsl <- random.cdisc.data::cadsl +adae <- random.cdisc.data::cadae + +# gtsummary table -------------- +tbl_gtsummary <- cardinal:::make_table_35_gtsummary(df = adae, denominator = adsl) +tbl_gtsummary + +# rtables table ---------------- +tbl_rtables <- cardinal:::make_table_35_rtables(df = adae, alt_counts_df = adsl) +tbl_rtables + +} +\seealso{ +\code{\link[=make_table_35]{make_table_35()}} +} diff --git a/tests/testthat/_snaps/fda-table_35.md b/tests/testthat/_snaps/fda-table_35.md index 2633781c..81044a0f 100644 --- a/tests/testthat/_snaps/fda-table_35.md +++ b/tests/testthat/_snaps/fda-table_35.md @@ -1,99 +1,29 @@ -# Table 35 generation works with default values +# Table 35 generation works with gtsummary with custom values Code - res + as.data.frame(res) Output - A: Drug X B: Placebo C: Combination - Primary System Organ Class (N=134) (N=134) (N=132) - ————————————————————————————————————————————————————————————————————— - cl D 96 (71.6%) 90 (67.2%) 98 (74.2%) - cl B 96 (71.6%) 89 (66.4%) 97 (73.5%) - cl A 78 (58.2%) 75 (56.0%) 89 (67.4%) - cl C 67 (50.0%) 75 (56.0%) 79 (59.8%) + row_type var_label variable label stat_1 stat_2 stat_3 + 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) + 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) + 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 85 (64.4) + 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 43 (32.6) + 5 level
AEBODSYS cl C.2 35 (26.1) 48 (35.8) 55 (41.7) + 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 80 (60.6) + 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) -# Table 35 generation works with custom values +# Table 35 generation works with gtsummary missing values Code - res + as.data.frame(res) Output - Table 35. Patients With Adverse Events1 by System Organ Class, - Safety Population, Pooled Analysis - - ——————————————————————————————————————————————————————————————————————————————————— - Total - A: Drug X B: Placebo C: Combination Population - Primary System Organ Class (N=134) (N=134) (N=132) (N=400) - ——————————————————————————————————————————————————————————————————————————————————— - cl D 96 (71.6%) 90 (67.2%) 98 (74.2%) 284 (71.0%) - cl B 96 (71.6%) 89 (66.4%) 97 (73.5%) 282 (70.5%) - cl A 78 (58.2%) 75 (56.0%) 89 (67.4%) 242 (60.5%) - cl C 67 (50.0%) 75 (56.0%) 79 (59.8%) 221 (55.2%) - ——————————————————————————————————————————————————————————————————————————————————— - - Source: [include Applicant source, datasets and/or software tools used]. - (1) Treatment-emergent adverse event defined as [definition]. - (2) Duration = [e.g., X week double-blind treatment period or median - and a range indicating pooled trial durations]. - (3) Difference is shown between [treatment arms] (e.g., difference - is shown between Drug Name dosage X vs. placebo). - (4) Table display is ordered by the risk difference. - - Abbreviations: CI, confidence interval; - N, number of patients in treatment arm; - n, number of patients with at least one event - -# Table 35 generation works with risk difference column - - Code - res - Output - A: Drug X B: Placebo C: Combination Risk Difference (%) (95% CI) - Primary System Organ Class (N=134) (N=134) (N=132) (N=268) - ———————————————————————————————————————————————————————————————————————————————————————————————————— - cl D 96 (71.6%) 90 (67.2%) 98 (74.2%) -4.5 (-15.5 - 6.5) - cl B 96 (71.6%) 89 (66.4%) 97 (73.5%) -5.2 (-16.3 - 5.8) - cl A 78 (58.2%) 75 (56.0%) 89 (67.4%) -2.2 (-14.1 - 9.6) - cl C 67 (50.0%) 75 (56.0%) 79 (59.8%) 6.0 (-6.0 - 17.9) - -# Table 35 generation works with some NA values - - Code - res - Output - A: Drug X B: Placebo C: Combination - Primary System Organ Class (N=134) (N=134) (N=132) - ————————————————————————————————————————————————————————————————————— - cl D 96 (71.6%) 90 (67.2%) 98 (74.2%) - cl B 96 (71.6%) 89 (66.4%) 97 (73.5%) - cl A 78 (58.2%) 75 (56.0%) 89 (67.4%) - cl C 67 (50.0%) 75 (56.0%) 79 (59.8%) - -# Table 35 generation works with custom values (SOC variable and label) - - Code - res - Output - Total - A: Drug X B: Placebo C: Combination Population - AEBODSYS var used (N=134) (N=134) (N=132) (N=400) - —————————————————————————————————————————————————————————————————————————— - cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) 242 (60.5%) - cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) 238 (59.5%) - cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) 226 (56.5%) - cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) 162 (40.5%) - cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 139 (34.8%) - cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) 138 (34.5%) - cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) 132 (33.0%) - -# Table 35 generation works with pruning - - Code - res - Output - A: Drug X B: Placebo C: Combination - Primary System Organ Class (N=134) (N=134) (N=132) - ————————————————————————————————————————————————————————————————————— - cl A 95 (70.9%) 99 (73.9%) 109 (82.6%) - cl D 96 (71.6%) 90 (67.2%) 98 (74.2%) - cl B 96 (71.6%) 89 (66.4%) 97 (73.5%) + row_type var_label variable label stat_1 stat_2 stat_3 + 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) + 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) + 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 84 (63.6) + 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 42 (31.8) + 5 level
AEBODSYS cl C.2 34 (25.4) 48 (35.8) 55 (41.7) + 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 79 (59.8) + 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) + 8 level
AEBODSYS <Missing> 2 (1.5) 2 (1.5) 6 (4.5) diff --git a/tests/testthat/test-fda-table_35.R b/tests/testthat/test-fda-table_35.R index 5001130a..c1f5c336 100644 --- a/tests/testthat/test-fda-table_35.R +++ b/tests/testthat/test-fda-table_35.R @@ -2,14 +2,47 @@ adsl <- adsl_raw adae <- adae_raw test_that("Table 35 generation works with default values", { - result <- make_table_35(adae, adsl) + withr::local_options(list(width = 150)) + expect_warning(result <- make_table_35(adae)) res <- expect_silent(result) - expect_snapshot(res) + expect_snapshot(res$table |> as.data.frame()) + expect_snapshot(res$ard) + + # no ARD + expect_warning(result2 <- make_table_35(adae, adsl, return_ard = FALSE)) + res2 <- expect_silent(result2) + + # tables the same + expect_identical(res$table, res2) +}) + +# gtsummary ---- + +test_that("Table 35 generation works with gtsummary with custom values", { + withr::local_options(list(width = 150)) + + result <- make_table_35_gtsummary(df = adae, denominator = adsl) + + res <- expect_silent(result) + expect_snapshot(res |> as.data.frame()) }) +test_that("Table 35 generation works with gtsummary missing values", { + withr::local_options(list(width = 150)) + + set.seed(5) + adae[sample(seq_len(nrow(adae)), 10), "AEBODSYS"] <- NA + + result <- make_table_35_gtsummary(df = adae, denominator = adsl) + res <- expect_silent(result) + expect_snapshot(res |> as.data.frame()) +}) + +# rtables ----- + test_that("Table 35 generation works with custom values", { - result <- make_table_35( + result <- make_table_35_rtables( adae, adsl, lbl_overall = "Total\nPopulation", @@ -41,7 +74,7 @@ test_that("Table 35 generation works with custom values", { test_that("Table 35 generation works with risk difference column", { risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") - result <- make_table_35(adae, adsl, risk_diff = risk_diff) + result <- make_table_35_rtables(adae, adsl, risk_diff = risk_diff) res <- expect_silent(result) expect_snapshot(res) @@ -52,14 +85,14 @@ test_that("Table 35 generation works with some NA values", { adae[sample(seq_len(nrow(adae)), 10), "AEBODSYS"] <- NA adae <- adae %>% df_explicit_na() - result <- make_table_35(adae, adsl) + result <- make_table_35_rtables(adae, adsl) res <- expect_silent(result) expect_snapshot(res) }) test_that("Table 35 generation works with custom values (SOC variable and label)", { - result <- make_table_35( + result <- make_table_35_rtables( adae, adsl, lbl_overall = "Total\nPopulation", @@ -73,7 +106,7 @@ test_that("Table 35 generation works with custom values (SOC variable and label) test_that("Table 35 generation works with pruning", { adae$AESOC[adae$AESOC == "cl C"] <- "cl A" - result <- make_table_35(adae, adsl, prune_0 = TRUE) + result <- make_table_35_rtables(adae, adsl, prune_0 = TRUE) res <- expect_silent(result) expect_snapshot(res) From 039aca96a636257a27063a12f278f225b02bd407 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:45:15 +0100 Subject: [PATCH 03/21] Update template-table_35.qmd --- quarto/table-templates/template-table_35.qmd | 108 +++++++++++++++++-- 1 file changed, 101 insertions(+), 7 deletions(-) diff --git a/quarto/table-templates/template-table_35.qmd b/quarto/table-templates/template-table_35.qmd index 9b59fb81..4de12bd1 100644 --- a/quarto/table-templates/template-table_35.qmd +++ b/quarto/table-templates/template-table_35.qmd @@ -1,17 +1,108 @@ --- title: FDA Table 35 subtitle: Patients With Adverse Events by System Organ Class, Safety Population, Pooled Analysis (or Trial X) -format: html --- +```{r setup, echo=FALSE} +``` + ::: panel-tabset + ## Spec. Screenshot ![](../assets/images/screenshots/table_35.png){fig-align="center" width="70%"} -## Table +## gtsummary Table + +
+ +gtsummary Table Setup + +```{r tbl1, eval=FALSE, echo=TRUE} +# Load Libraries & Data +library(cardinal) + +adsl <- random.cdisc.data::cadsl +adae <- random.cdisc.data::cadae + +# Output Table +make_table_35(df = adae, denominator = adsl, return_ard = FALSE) +``` + +
+ +
+ +Function Details + +### `make_table_35()` + +------------------------------------------------------------------------ + +Required variables: + +- **`df`**: The variables specified by `id_var`, `arm_var`, `saffl_var`, and `soc_var`. +- **`denominator`** (if specified): `USUBJID` and the variables specified by `arm_var` and `saffl_var` +- If both the ARD (`return_ard = "Y"`) and an overall column (`lbl_overall` not missing) are requested, a list of two ARDs will be returned: `ard$tbl_summary` for the table by groups, and `ard$add_overall` for the overal column. + ++---------------+------------------------------------------------------------------------------------+---------------+ +| **Argument** | **Description** | **Default** | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `df` | (`data.frame`) Dataset (typically ADSL) required to build table. | *No default* | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `return_ard` | (`flag`) Whether an ARD should be returned. | `TRUE` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `denominator` | (`character`) Alternative dataset used only to calculate column counts. | `NULL` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `id_var` | (`character`) Identifier variable used to count the participants within each flag. | `"USUBJID"` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `arm_var` | (`character`) Arm variable used to split table into columns. | `"ARM"` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `saffl_var` | (`character`) Flag variable used to indicate inclusion in safety population. | `"SAFFL"` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `soc_var` | (`character`) SOC variable from `adae` to include in the table. | `"ARBODSYS"` | ++---------------+------------------------------------------------------------------------------------+---------------+ +| `na_level` | (`character`) String to represent missing values. | `""` | ++---------------+------------------------------------------------------------------------------------+---------------+ + +Source code for this function is available [here](https://github.com/pharmaverse/cardinal/blob/main/R/fda-table_11.R). + +
+ +## ARD + +
-```{r tbl, message=FALSE, warning=FALSE} +ARD Setup + +```{r tbl2, echo=TRUE, message=FALSE, warning=FALSE, results='hide'} +# Load Libraries & Data +library(cardinal) + +adsl <- random.cdisc.data::cadsl +adae <- random.cdisc.data::cadae + +# Create Table and ARD +result <- make_table_35(df = adae, denominator = adsl) + +# Output ARD +result$ard +``` + +```{r tbl2-print, echo=FALSE} +withr::local_options(width = 9999) +print(result$ard, columns = "all", n = Inf) +``` + +
+ +## rtables Table + +
+ +rtables Table Setup + +```{r tbl3, eval=FALSE, echo=TRUE} # Load Libraries & Data library(random.cdisc.data) library(cardinal) @@ -21,15 +112,17 @@ adae <- random.cdisc.data::cadae # Output Table risk_diff <- list(arm_x = "B: Placebo", arm_y = "A: Drug X") # optional -make_table_35(adae = adae, alt_counts_df = adsl, risk_diff = risk_diff) +make_table_35_rtables(df = adae, alt_counts_df = adsl, risk_diff = risk_diff) ``` -## Table Setup +
-```{r tbl, eval=FALSE, echo=TRUE} +```{r tbl3, message=FALSE, warning=FALSE, eval=TRUE} ``` -## Function Details +
+ +Function Details ### `make_table_35()` @@ -75,4 +168,5 @@ Required variables: +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ Source code for this function is available [here](https://github.com/pharmaverse/cardinal/blob/main/R/fda-table_35.R). +
::: From 442e0ef11d7ff482636d119de2241a63b71350a8 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:01:25 +0100 Subject: [PATCH 04/21] Delete fda-table_35.md --- tests/testthat/_snaps/fda-table_35.md | 29 --------------------------- 1 file changed, 29 deletions(-) delete mode 100644 tests/testthat/_snaps/fda-table_35.md diff --git a/tests/testthat/_snaps/fda-table_35.md b/tests/testthat/_snaps/fda-table_35.md deleted file mode 100644 index 81044a0f..00000000 --- a/tests/testthat/_snaps/fda-table_35.md +++ /dev/null @@ -1,29 +0,0 @@ -# Table 35 generation works with gtsummary with custom values - - Code - as.data.frame(res) - Output - row_type var_label variable label stat_1 stat_2 stat_3 - 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) - 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) - 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 85 (64.4) - 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 43 (32.6) - 5 level
AEBODSYS cl C.2 35 (26.1) 48 (35.8) 55 (41.7) - 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 80 (60.6) - 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) - -# Table 35 generation works with gtsummary missing values - - Code - as.data.frame(res) - Output - row_type var_label variable label stat_1 stat_2 stat_3 - 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) - 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) - 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 84 (63.6) - 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 42 (31.8) - 5 level
AEBODSYS cl C.2 34 (25.4) 48 (35.8) 55 (41.7) - 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 79 (59.8) - 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) - 8 level
AEBODSYS <Missing> 2 (1.5) 2 (1.5) 6 (4.5) - From aec9bf753aaa1fbc5ec31dfca44454cb74fc9071 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:03:50 +0100 Subject: [PATCH 05/21] delete drafts --- R/alex_draft_0.R | 65 ---------------- R/alex_draft_1.R | 51 ------------- R/alex_draft_ard.R | 63 ---------------- R/fda-table_35_draft.R | 166 ----------------------------------------- 4 files changed, 345 deletions(-) delete mode 100644 R/alex_draft_0.R delete mode 100644 R/alex_draft_1.R delete mode 100644 R/alex_draft_ard.R delete mode 100644 R/fda-table_35_draft.R diff --git a/R/alex_draft_0.R b/R/alex_draft_0.R deleted file mode 100644 index 2adedb8d..00000000 --- a/R/alex_draft_0.R +++ /dev/null @@ -1,65 +0,0 @@ -# source("R/utils.R") -# source("R/fda-table_35.R") -# -# # adsl <- random.cdisc.data::cadsl -# # adae <- random.cdisc.data::cadae -# # -# # tblo <- make_table_35(df = adae, denominator = adsl, lbl_overall = "abc") -# # tblo -# -# -# adsl <- random.cdisc.data::cadsl -# adae <- random.cdisc.data::cadae -# -# tbl <- make_table_35(df = adae, denominator = adsl) -# tbl -# -# tbl_overall <- -# tbl_hierarchical( -# data = adae, -# variables = "AESOC", -# # by = arm_var, -# denominator = adsl, -# id = "USUBJID" -# ) %>% -# modify_header(all_stat_cols() ~ "**Overall** \nN = {n}") -# -# tbl_overall -# -# tbl_df <- as.data.frame(tbl) -# tbl_overall_df <- as.data.frame(tbl_overall) -# -# tbl_all <- -# left_join( -# x = tbl_df, -# y = tbl_overall_df, -# by = "**Primary System Organ Class**" -# ) -# -# tbl_all_gt <- gt(tbl_all) -# tbl_all_gt -# -# tbl_all_gt2 <- gtsummary::with_gtsummary_theme( -# x = gtsummary::theme_gtsummary_compact(), -# expr = tbl_all_gt -# ) -# -# tbl_all_gt2 -# -# cols_names <- colnames(tbl_all) -# cols_names -# tbl_all_gt2_md <- -# tbl_all %>% -# gt() %>% -# cols_label( -# .list = setNames(lapply(cols_names, md), cols_names) -# ) -# -# tbl_all_gt2_md -# -# tbl_final <- gtsummary::with_gtsummary_theme( -# x = gtsummary::theme_gtsummary_compact(), -# expr = tbl_all_gt2_md -# ) -# -# tbl_final diff --git a/R/alex_draft_1.R b/R/alex_draft_1.R deleted file mode 100644 index 3b4b5484..00000000 --- a/R/alex_draft_1.R +++ /dev/null @@ -1,51 +0,0 @@ -# # Load ----- -# source("R/utils.R") -# source("R/fda-table_35.R") -# -# # No lbl_overall ----- -# adsl <- random.cdisc.data::cadsl -# adae <- random.cdisc.data::cadae -# -# tbl <- make_table_35(df = adae, denominator = adsl) -# -# tbl_ovrl <- -# tbl_hierarchical( -# data = adae, -# variables = "AESOC", -# # by = arm_var, -# denominator = adsl, -# id = "USUBJID" -# ) %>% -# modify_header(label ~ paste0("**System Organ Class**")) %>% -# modify_header(all_stat_cols() ~ "**Overall** \nN = {n}") %>% -# gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") -# -# -# tbl <- as.data.frame(tbl) -# tbl_ovrl <- as.data.frame(tbl_ovrl) -# -# tbl_all <- left_join(x = tbl, y = tbl_ovrl, by = "**System Organ Class**") -# -# cols_names <- colnames(tbl_all) -# cols_names -# tbl_all_gt2_md <- -# tbl_all %>% -# gt() %>% -# cols_label( -# .list = setNames(lapply(cols_names, md), cols_names) -# ) -# -# tbl_all_gt2_md -# -# # lbl_overall ----- -# -# adsl <- random.cdisc.data::cadsl -# adae <- random.cdisc.data::cadae -# -# tbl <- -# make_table_35( -# df = adae, -# denominator = adsl, -# lbl_overall = "def" -# ) -# tbl diff --git a/R/alex_draft_ard.R b/R/alex_draft_ard.R deleted file mode 100644 index 9fbbfe19..00000000 --- a/R/alex_draft_ard.R +++ /dev/null @@ -1,63 +0,0 @@ -# source("R/utils.R") -# source("R/fda-table_35.R") -# -# adsl <- random.cdisc.data::cadsl -# adae <- random.cdisc.data::cadae -# -# tbl <- make_table_35(df = adae, denominator = adsl, lbl_overall = "def") -# tbl -# -# ard <- -# cards::ard_stack_hierarchical( -# data = adae %>% filter(SAFFL == "Y"), -# variables = c(AESOC), -# by = TRT01A, -# denominator = adsl %>% filter(SAFFL == "Y"), -# id = USUBJID, -# overall = TRUE -# ) -# -# ard <- -# cards::ard_stack_hierarchical( -# data = adae %>% filter(SAFFL == "Y"), -# variables = c(AESOC), -# by = TRT01A, -# denominator = adsl %>% filter(SAFFL == "Y"), -# id = USUBJID, -# overall = TRUE -# ) -# -# -# -# -# AESOC -# -# -# -# -# -# -# ADAE_subset <- cards::ADAE |> -# dplyr::filter( -# AESOC %in% unique(cards::ADAE$AESOC)[1:5], -# AETERM %in% unique(cards::ADAE$AETERM)[1:5] -# ) -# -# # Example 1: Event Rates -------------------- -# # First, build the ARD -# ard <- -# cards::ard_stack_hierarchical( -# data = ADAE_subset, -# variables = c(AESOC, AETERM), -# by = TRTA, -# denominator = cards::ADSL |> mutate(TRTA = ARM), -# id = USUBJID, -# overall = TRUE -# ) -# -# # Second, build table from the ARD -# tbl_ard_hierarchical( -# cards = ard, -# variables = c(AESOC, AETERM), -# by = TRTA -# ) diff --git a/R/fda-table_35_draft.R b/R/fda-table_35_draft.R deleted file mode 100644 index 6e3bc73c..00000000 --- a/R/fda-table_35_draft.R +++ /dev/null @@ -1,166 +0,0 @@ -#' #' Table 35. Patients With Adverse Events by System Organ Class, -#' #' Safety Population, Pooled Analysis (or Trial X) -#' #' -#' #' @details -#' #' * `df` must contain the variables specified by -#' #' `arm_var`, `id_var`, `soc_var` and `saffl_var`. -#' #' * `return_ard` set to `TRUE` or `FALSE`; whether the intermediate ARD object should be returned. -#' #' -#' #' @inheritParams argument_convention -#' #' @param soc_var (`character`)\cr Name of the variable that contains the SOC to describe. -#' #' -#' #' @return A `gtsummary` table and, if `return_ard = TRUE`, an ARD. -#' #' If `return_ard = TRUE`, they will be returned as a list with named elements `table` and `ard`. -#' #' -#' #' @seealso [`tbl_make_table_35`] -#' #' -#' #' @examples -#' #' adsl <- random.cdisc.data::cadsl -#' #' adae <- random.cdisc.data::cadae -#' #' -#' #' tbl <- make_table_35(df = adae, denominator = adsl) -#' #' tbl -#' #' -#' #' @export -#' make_table_35 <- function(df, -#' denominator, -#' return_ard = TRUE, -#' id_var = "USUBJID", -#' arm_var = "ARM", -#' saffl_var = "SAFFL", -#' soc_var = "AESOC", -#' lbl_overall = NULL) { -#' -#' assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) -#' assert_flag_variables(df, saffl_var) -#' assert_subset(c(arm_var, id_var, saffl_var), names(denominator)) -#' assert_flag_variables(denominator, saffl_var) -#' -#' df <- df %>% -#' filter(.data[[saffl_var]] == "Y") %>% -#' arrange(soc_var) %>% -#' df_explicit_na() -#' -#' df_denom <- denominator %>% filter(.data[[saffl_var]] == "Y") -#' -#' tbl_gts <- -#' tbl_hierarchical( -#' data = df, -#' variables = soc_var, -#' by = arm_var, -#' denominator = df_denom, -#' id = id_var -#' ) %>% -#' modify_header(label ~ paste0("**System Organ Class**")) %>% -#' modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") %>% -#' gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") -#' -#' if (!is.null(lbl_overall)) { -#' tbl_gts_ovrl <- -#' tbl_hierarchical( -#' data = df, -#' variables = soc_var, -#' denominator = df_denom, -#' id = id_var -#' ) %>% -#' modify_header(label ~ paste0("**System Organ Class**")) %>% -#' modify_header( -#' all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") -#' ) %>% -#' gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") -#' -#' tbl_gts_df <- as.data.frame(tbl_gts) -#' tbl_gts_ovrl_df <- as.data.frame(tbl_gts_ovrl) -#' -#' tbl_gts_all_df <- -#' left_join( -#' x = tbl_gts_df, -#' y = tbl_gts_ovrl_df, -#' by = "**System Organ Class**" -#' ) -#' -#' cols_names <- colnames(tbl_gts_all_df) -#' -#' tbl_gts <- -#' tbl_gts_all_df %>% -#' gt() %>% -#' cols_label( -#' .list = setNames(lapply(cols_names, md), cols_names) -#' ) -#' -#' tbl <- gtsummary::with_gtsummary_theme( -#' x = gtsummary::theme_gtsummary_compact(), -#' expr = tbl_gts -#' ) -#' } -#' -#' else { -#' tbl_gts <- tbl_gts -#' -#' tbl <- gtsummary::with_gtsummary_theme( -#' x = gtsummary::theme_gtsummary_compact(), -#' expr = as_gt(tbl_gts) -#' ) -#' } -#' -#' if (return_ard) { -#' -#' } -#' -#' -#' return(tbl) -#' } -#' -#' -#' -#' -#' -#' -#' -#' -#' -#' -#' -#' -#' -#' make_table_35_rtables <- function(adae, -#' alt_counts_df = NULL, -#' show_colcounts = TRUE, -#' id_var = "USUBJID", -#' arm_var = "ARM", -#' saffl_var = "SAFFL", -#' soc_var = "AESOC", -#' lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], -#' lbl_overall = NULL, -#' risk_diff = NULL, -#' prune_0 = FALSE, -#' annotations = NULL) { -#' assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(adae)) -#' assert_flag_variables(adae, saffl_var) -#' -#' adae <- adae %>% -#' filter(.data[[saffl_var]] == "Y") %>% -#' arrange(soc_var) %>% -#' df_explicit_na() -#' -#' alt_counts_df <- -#' alt_counts_df_preproc(alt_counts_df, id_var, arm_var, saffl_var) -#' -#' lyt <- basic_table_annot(show_colcounts, annotations) %>% -#' split_cols_by_arm(arm_var, lbl_overall, risk_diff) %>% -#' count_occurrences( -#' vars = soc_var, -#' drop = FALSE, -#' riskdiff = !is.null(risk_diff) -#' ) %>% -#' append_topleft(c("", lbl_soc_var)) -#' -#' tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) %>% -#' sort_at_path( -#' path = c(soc_var), -#' scorefun = score_occurrences_cols(col_names = levels(adae[[arm_var]])) -#' ) -#' if (prune_0) tbl <- prune_table(tbl) -#' -#' tbl -#' } From 48b4be262a7f978d93ca660fc7d234cebde018c5 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:23:15 +0100 Subject: [PATCH 06/21] update --- R/fda-table_35.R | 2 +- tests/testthat/_snaps/fda-table_35.md | 165 ++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/testthat/_snaps/fda-table_35.md diff --git a/R/fda-table_35.R b/R/fda-table_35.R index d932af27..cda84a86 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -23,7 +23,7 @@ #' #' @export make_table_35 <- function(df, - denominator, + denominator = NULL, return_ard = TRUE, id_var = "USUBJID", arm_var = "ARM", diff --git a/tests/testthat/_snaps/fda-table_35.md b/tests/testthat/_snaps/fda-table_35.md new file mode 100644 index 00000000..021e5a15 --- /dev/null +++ b/tests/testthat/_snaps/fda-table_35.md @@ -0,0 +1,165 @@ +# Table 35 generation works with default values + + Code + as.data.frame(res$table) + Output + row_type var_label variable label stat_1 stat_2 stat_3 + 1 level
AEBODSYS cl A.1 78 (59.1) 75 (57.7) 89 (55.6) + 2 level
AEBODSYS cl B.1 47 (83.9) 49 (81.7) 43 (69.4) + 3 level
AEBODSYS cl B.2 79 (61.2) 74 (53.6) 85 (59.4) + 4 level
AEBODSYS cl C.1 43 (78.2) 46 (73.0) 43 (67.2) + 5 level
AEBODSYS cl C.2 35 (72.9) 48 (90.6) 55 (84.6) + 6 level
AEBODSYS cl D.1 79 (62.2) 67 (63.2) 80 (59.3) + 7 level
AEBODSYS cl D.2 47 (75.8) 58 (80.6) 57 (77.0) + +--- + + Code + res$ard + Message + {cards} data frame: 72 x 11 + Output + group1 group1_level variable variable_level stat_name stat_label stat + 1 ARM A: Drug X AEBODSYS cl A.1 n n 78 + 2 ARM A: Drug X AEBODSYS cl A.1 N N 132 + 3 ARM A: Drug X AEBODSYS cl A.1 p % 0.591 + 4 ARM A: Drug X AEBODSYS cl B.1 n n 47 + 5 ARM A: Drug X AEBODSYS cl B.1 N N 56 + 6 ARM A: Drug X AEBODSYS cl B.1 p % 0.839 + 7 ARM A: Drug X AEBODSYS cl B.2 n n 79 + 8 ARM A: Drug X AEBODSYS cl B.2 N N 129 + 9 ARM A: Drug X AEBODSYS cl B.2 p % 0.612 + 10 ARM A: Drug X AEBODSYS cl C.1 n n 43 + Message + i 62 more rows + i Use `print(n = ...)` to see more rows + i 4 more variables: context, fmt_fn, warning, error + +# Table 35 generation works with gtsummary with custom values + + Code + as.data.frame(res) + Output + row_type var_label variable label stat_1 stat_2 stat_3 + 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) + 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) + 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 85 (64.4) + 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 43 (32.6) + 5 level
AEBODSYS cl C.2 35 (26.1) 48 (35.8) 55 (41.7) + 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 80 (60.6) + 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) + +# Table 35 generation works with gtsummary missing values + + Code + as.data.frame(res) + Output + row_type var_label variable label stat_1 stat_2 stat_3 + 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) + 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) + 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 84 (63.6) + 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 42 (31.8) + 5 level
AEBODSYS cl C.2 34 (25.4) 48 (35.8) 55 (41.7) + 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 79 (59.8) + 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) + 8 level
AEBODSYS <Missing> 2 (1.5) 2 (1.5) 6 (4.5) + +# Table 35 generation works with custom values + + Code + res + Output + Table 35. Patients With Adverse Events1 by System Organ Class, + Safety Population, Pooled Analysis + + ——————————————————————————————————————————————————————————————————————————————————— + Total + A: Drug X B: Placebo C: Combination Population + Body System or Organ Class (N=134) (N=134) (N=132) (N=400) + ——————————————————————————————————————————————————————————————————————————————————— + cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) 242 (60.5%) + cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) 238 (59.5%) + cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) 226 (56.5%) + cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) 162 (40.5%) + cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 139 (34.8%) + cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) 138 (34.5%) + cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) 132 (33.0%) + ——————————————————————————————————————————————————————————————————————————————————— + + Source: [include Applicant source, datasets and/or software tools used]. + (1) Treatment-emergent adverse event defined as [definition]. + (2) Duration = [e.g., X week double-blind treatment period or median + and a range indicating pooled trial durations]. + (3) Difference is shown between [treatment arms] (e.g., difference + is shown between Drug Name dosage X vs. placebo). + (4) Table display is ordered by the risk difference. + + Abbreviations: CI, confidence interval; + N, number of patients in treatment arm; + n, number of patients with at least one event + +# Table 35 generation works with risk difference column + + Code + res + Output + A: Drug X B: Placebo C: Combination Risk Difference (%) (95% CI) + Body System or Organ Class (N=134) (N=134) (N=132) (N=268) + ———————————————————————————————————————————————————————————————————————————————————————————————————— + cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) -2.2 (-14.1 - 9.6) + cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) -3.7 (-15.6 - 8.1) + cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) -9.0 (-20.8 - 2.9) + cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) 8.2 (-3.4 - 19.9) + cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 1.5 (-10.0 - 13.0) + cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) 9.7 (-1.3 - 20.7) + cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) 2.2 (-9.0 - 13.5) + +# Table 35 generation works with some NA values + + Code + res + Output + A: Drug X B: Placebo C: Combination + Body System or Organ Class (N=134) (N=134) (N=132) + ————————————————————————————————————————————————————————————————————— + cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) + cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) + cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) + cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) + cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) + cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) + cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) + +# Table 35 generation works with custom values (SOC variable and label) + + Code + res + Output + Total + A: Drug X B: Placebo C: Combination Population + AEBODSYS var used (N=134) (N=134) (N=132) (N=400) + —————————————————————————————————————————————————————————————————————————— + cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) 242 (60.5%) + cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) 238 (59.5%) + cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) 226 (56.5%) + cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) 162 (40.5%) + cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 139 (34.8%) + cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) 138 (34.5%) + cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) 132 (33.0%) + +# Table 35 generation works with pruning + + Code + res + Output + A: Drug X B: Placebo C: Combination + Body System or Organ Class (N=134) (N=134) (N=132) + ————————————————————————————————————————————————————————————————————— + cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) + cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) + cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) + cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) + cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) + cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) + cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) + From b1e490f316405210cade6c27aeceaca2b3bb96fc Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:10:34 +0100 Subject: [PATCH 07/21] Update make_table_35.Rd --- man/make_table_35.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index 694561c0..cdd85da0 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -7,7 +7,7 @@ Safety Population, Pooled Analysis (or Trial X)} \usage{ make_table_35( df, - denominator, + denominator = NULL, return_ard = TRUE, id_var = "USUBJID", arm_var = "ARM", From 52b3776317edc389e17344b0ae4e19f1c7b3f6d0 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 07:51:35 +0000 Subject: [PATCH 08/21] [skip style] [skip vbump] Restyle files --- R/fda-table_35.R | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index cda84a86..bf8160a2 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -31,7 +31,6 @@ make_table_35 <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - ard <- ard_table_35( df = df, denominator = denominator, @@ -57,7 +56,6 @@ make_table_35 <- function(df, } else { return(tbl) # nocov } - } #' Pre-Process Data for Table 35 Creation @@ -69,7 +67,6 @@ preproc_df_table_35 <- function(df, saffl_var = "SAFFL", soc_var = "AEBODSYS", na_level = "") { - assert_subset(c(soc_var, arm_var, id_var, saffl_var), names(df)) assert_flag_variables(df, saffl_var) @@ -102,13 +99,11 @@ ard_table_35 <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) if (is.null(denominator)) { denominator <- df # nocov - } - else { + } else { denominator <- alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) } @@ -172,13 +167,11 @@ make_table_35_gtsummary <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) if (is.null(denominator)) { denominator <- df # nocov - } - else { + } else { denominator <- alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) } @@ -232,9 +225,7 @@ make_table_35_gtsummary <- function(df, x = gtsummary::theme_gtsummary_compact(), expr = tbl_gts ) - } - - else { + } else { tbl_gts <- tbl_gts tbl <- gtsummary::with_gtsummary_theme( From 9a0137aefe29f111e40dca5b17b338433aa59270 Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:13:40 +0100 Subject: [PATCH 09/21] Update test-fda-table_35.R --- tests/testthat/test-fda-table_35.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-fda-table_35.R b/tests/testthat/test-fda-table_35.R index c1f5c336..ed53b0d9 100644 --- a/tests/testthat/test-fda-table_35.R +++ b/tests/testthat/test-fda-table_35.R @@ -4,17 +4,17 @@ adae <- adae_raw test_that("Table 35 generation works with default values", { withr::local_options(list(width = 150)) - expect_warning(result <- make_table_35(adae)) + result <- make_table_35(adae) res <- expect_silent(result) expect_snapshot(res$table |> as.data.frame()) expect_snapshot(res$ard) # no ARD - expect_warning(result2 <- make_table_35(adae, adsl, return_ard = FALSE)) + result2 <- make_table_35(adae, adsl, return_ard = FALSE) res2 <- expect_silent(result2) # tables the same - expect_identical(res$table, res2) + expect_error(expect_identical(res$table, res2)) }) # gtsummary ---- From efc531fa0c0735bcdedee93424334a821bc1c31d Mon Sep 17 00:00:00 2001 From: aassuied-ps <123543888+aassuied-ps@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:43:15 +0100 Subject: [PATCH 10/21] typo in fda-table_36.R --- R/fda-table_36.R | 2 +- man/make_table_36.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/fda-table_36.R b/R/fda-table_36.R index 3d1a4da0..44e08bce 100644 --- a/R/fda-table_36.R +++ b/R/fda-table_36.R @@ -18,7 +18,7 @@ #' adsl <- random.cdisc.data::cadsl #' adae <- random.cdisc.data::cadae #' -#' tbl <- make_table_35(adae = adae, alt_counts_df = adsl) +#' tbl <- make_table_36(adae = adae, alt_counts_df = adsl) #' tbl #' #' @export diff --git a/man/make_table_36.Rd b/man/make_table_36.Rd index dd74cfa9..e8cb5ce6 100644 --- a/man/make_table_36.Rd +++ b/man/make_table_36.Rd @@ -86,7 +86,7 @@ and \code{pref_var}. adsl <- random.cdisc.data::cadsl adae <- random.cdisc.data::cadae -tbl <- make_table_35(adae = adae, alt_counts_df = adsl) +tbl <- make_table_36(adae = adae, alt_counts_df = adsl) tbl } From fa3844a5e1b2081986defc4c93a9600d527146b8 Mon Sep 17 00:00:00 2001 From: "27856297+dependabot-preview[bot]@users.noreply.github.com" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 13:04:51 +0000 Subject: [PATCH 11/21] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/make_table_35.Rd | 4 ++++ man/tbl_make_table_35.Rd | 2 ++ 2 files changed, 6 insertions(+) diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index cdd85da0..b2d5d868 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -20,6 +20,10 @@ make_table_35( \arguments{ \item{df}{(\code{data.frame})\cr dataset required to build table.} +\item{denominator}{(\code{data.frame})\cr alternative dataset (typically ADSL) used only to calculate denominator counts.} + +\item{return_ard}{(\code{flag})\cr whether an ARD should be returned. Defaults to \code{TRUE}.} + \item{id_var}{(\code{character})\cr variable used as unique subject identifier.} \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} diff --git a/man/tbl_make_table_35.Rd b/man/tbl_make_table_35.Rd index 2e73080b..5405f3a8 100644 --- a/man/tbl_make_table_35.Rd +++ b/man/tbl_make_table_35.Rd @@ -36,6 +36,8 @@ make_table_35_rtables( \arguments{ \item{df}{(\code{data.frame})\cr dataset required to build table.} +\item{denominator}{(\code{data.frame})\cr alternative dataset (typically ADSL) used only to calculate denominator counts.} + \item{id_var}{(\code{character})\cr variable used as unique subject identifier.} \item{arm_var}{(\code{character})\cr Name of the treatment arm variable used to split table into columns.} From 93b9ebfcb7f60b0aaaa53ac6d9915022cc8e9839 Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Tue, 11 Mar 2025 15:08:46 +0100 Subject: [PATCH 12/21] Remove ARD generating function and extract ARD from gtsummary object instead --- R/fda-table_35.R | 104 ++++++++++------------------------------------- 1 file changed, 21 insertions(+), 83 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index bf8160a2..c4013553 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -31,15 +31,6 @@ make_table_35 <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - ard <- ard_table_35( - df = df, - denominator = denominator, - id_var = id_var, - arm_var = arm_var, - saffl_var = saffl_var, - soc_var = soc_var, - na_level = na_level - ) tbl <- make_table_35_gtsummary( df = df, @@ -48,10 +39,12 @@ make_table_35 <- function(df, arm_var = arm_var, saffl_var = saffl_var, soc_var = soc_var, + lbl_overall = lbl_overall, na_level = na_level ) if (return_ard) { + ard <- gather_ard(tbl) return(list(table = tbl, ard = ard)) } else { return(tbl) # nocov @@ -78,48 +71,6 @@ preproc_df_table_35 <- function(df, df } -#' Make ARD: Table 35 -#' -#' @examples -#' library(dplyr) -#' -#' adsl <- random.cdisc.data::cadsl -#' adae <- random.cdisc.data::cadae -#' -#' ard <- cardinal:::ard_table_35(adae, adsl) -#' ard -#' -#' @keywords internal -#' @name ard_make_table_35 -ard_table_35 <- function(df, - denominator = NULL, - id_var = "USUBJID", - arm_var = "ARM", - saffl_var = "SAFFL", - soc_var = "AEBODSYS", - lbl_overall = NULL, - na_level = "") { - df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) - - if (is.null(denominator)) { - denominator <- df # nocov - } else { - denominator <- - alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) - } - - ard <- - cards::ard_stack_hierarchical( - data = df, - variables = all_of(soc_var), - by = all_of(arm_var), - denominator = denominator, - id = all_of(id_var), - overall = !is.null(lbl_overall) - ) - - ard -} #' Engine-Specific Functions: Table 35 #' @@ -167,17 +118,21 @@ make_table_35_gtsummary <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { + df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) if (is.null(denominator)) { denominator <- df # nocov } else { - denominator <- - alt_counts_df_preproc(denominator, id_var, arm_var, saffl_var) + denominator <- alt_counts_df_preproc( + denominator, + id_var, + arm_var, + saffl_var + ) } - tbl_gts <- - tbl_hierarchical( + tbl_gts <- tbl_hierarchical( data = df, variables = soc_var, by = arm_var, @@ -186,53 +141,36 @@ make_table_35_gtsummary <- function(df, ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> - gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") + modify_column_alignment(columns = all_stat_cols(), align = "right") if (!is.null(lbl_overall)) { - tbl_gts_ovrl <- - tbl_hierarchical( + tbl_gts_ovrl <- tbl_hierarchical( data = df, variables = soc_var, - denominator = df_denom, + denominator = denominator, id = id_var ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header( all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") ) |> - gtsummary::modify_column_alignment(columns = all_stat_cols(), align = "right") - - tbl_gts_df <- as.data.frame(tbl_gts) - tbl_gts_ovrl_df <- as.data.frame(tbl_gts_ovrl) - - tbl_gts_all_df <- - left_join( - x = tbl_gts_df, - y = tbl_gts_ovrl_df, - by = "**System Organ Class**" - ) + modify_column_alignment(columns = all_stat_cols(), align = "right") - cols_names <- colnames(tbl_gts_all_df) - - tbl_gts <- - tbl_gts_all_df |> - gt() |> - cols_label( - .list = setNames(lapply(cols_names, md), cols_names) - ) + tbl_merged <- tbl_merge(list(tbl_gts, tbl_gts_ovrl), tab_spanner = FALSE) tbl <- gtsummary::with_gtsummary_theme( x = gtsummary::theme_gtsummary_compact(), - expr = tbl_gts + expr = tbl_merged ) } else { - tbl_gts <- tbl_gts - tbl <- gtsummary::with_gtsummary_theme( - x = gtsummary::theme_gtsummary_compact(), - expr = as_gt(tbl_gts) + tbl <- with_gtsummary_theme( + x = theme_gtsummary_compact(), + expr = tbl_gts ) } + + return(tbl) } #' @export From bcc001bce36dc076316ceb2a1ef0ed62611017e7 Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Tue, 11 Mar 2025 15:28:55 +0100 Subject: [PATCH 13/21] Simplify documentation --- R/fda-table_35.R | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index c4013553..dce7bed2 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -4,7 +4,7 @@ #' @details #' * `df` must contain the variables specified by #' `arm_var`, `id_var`, `soc_var` and `saffl_var`. -#' * `return_ard` set to `TRUE` or `FALSE`; whether the intermediate ARD object should be returned. +#' * `return_ard` set to `TRUE` (default) or `FALSE`; whether the intermediate ARD object should be returned. #' #' @inheritParams argument_convention #' @param soc_var (`character`)\cr Name of the variable that contains the SOC to describe. @@ -95,17 +95,16 @@ preproc_df_table_35 <- function(df, #' @seealso [make_table_35()] #' #' @examples -#' library(dplyr) #' #' adsl <- random.cdisc.data::cadsl #' adae <- random.cdisc.data::cadae #' #' # gtsummary table -------------- -#' tbl_gtsummary <- cardinal:::make_table_35_gtsummary(df = adae, denominator = adsl) +#' tbl_gtsummary <- make_table_35_gtsummary(df = adae, denominator = adsl) #' tbl_gtsummary #' #' # rtables table ---------------- -#' tbl_rtables <- cardinal:::make_table_35_rtables(df = adae, alt_counts_df = adsl) +#' tbl_rtables <- make_table_35_rtables(df = adae, alt_counts_df = adsl) #' tbl_rtables #' #' @export From a2f4efd65e45b0200a2696bb353d6640074133ab Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:41:26 +0000 Subject: [PATCH 14/21] [skip style] [skip vbump] Restyle files --- R/fda-table_35.R | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index dce7bed2..750ae554 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -31,7 +31,6 @@ make_table_35 <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - tbl <- make_table_35_gtsummary( df = df, denominator = denominator, @@ -117,7 +116,6 @@ make_table_35_gtsummary <- function(df, soc_var = "AEBODSYS", lbl_overall = NULL, na_level = "") { - df <- preproc_df_table_35(df, id_var, arm_var, saffl_var, soc_var, na_level) if (is.null(denominator)) { @@ -132,23 +130,23 @@ make_table_35_gtsummary <- function(df, } tbl_gts <- tbl_hierarchical( - data = df, - variables = soc_var, - by = arm_var, - denominator = denominator, - id = id_var - ) |> + data = df, + variables = soc_var, + by = arm_var, + denominator = denominator, + id = id_var + ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> modify_column_alignment(columns = all_stat_cols(), align = "right") if (!is.null(lbl_overall)) { tbl_gts_ovrl <- tbl_hierarchical( - data = df, - variables = soc_var, - denominator = denominator, - id = id_var - ) |> + data = df, + variables = soc_var, + denominator = denominator, + id = id_var + ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header( all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") @@ -162,7 +160,6 @@ make_table_35_gtsummary <- function(df, expr = tbl_merged ) } else { - tbl <- with_gtsummary_theme( x = theme_gtsummary_compact(), expr = tbl_gts From 1fe6ca2ce6b809fc3b2b7efedefbe387135e830f Mon Sep 17 00:00:00 2001 From: "27856297+dependabot-preview[bot]@users.noreply.github.com" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:41:42 +0000 Subject: [PATCH 15/21] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/ard_make_table_35.Rd | 32 -------------------------------- man/make_table_35.Rd | 2 +- man/tbl_make_table_35.Rd | 5 ++--- 3 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 man/ard_make_table_35.Rd diff --git a/man/ard_make_table_35.Rd b/man/ard_make_table_35.Rd deleted file mode 100644 index ba4b38e6..00000000 --- a/man/ard_make_table_35.Rd +++ /dev/null @@ -1,32 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/fda-table_35.R -\name{ard_make_table_35} -\alias{ard_make_table_35} -\alias{ard_table_35} -\title{Make ARD: Table 35} -\usage{ -ard_table_35( - df, - denominator = NULL, - id_var = "USUBJID", - arm_var = "ARM", - saffl_var = "SAFFL", - soc_var = "AEBODSYS", - lbl_overall = NULL, - na_level = "" -) -} -\description{ -Make ARD: Table 35 -} -\examples{ -library(dplyr) - -adsl <- random.cdisc.data::cadsl -adae <- random.cdisc.data::cadae - -ard <- cardinal:::ard_table_35(adae, adsl) -ard - -} -\keyword{internal} diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index b2d5d868..c2902461 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -49,7 +49,7 @@ Safety Population, Pooled Analysis (or Trial X) \itemize{ \item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{soc_var} and \code{saffl_var}. -\item \code{return_ard} set to \code{TRUE} or \code{FALSE}; whether the intermediate ARD object should be returned. +\item \code{return_ard} set to \code{TRUE} (default) or \code{FALSE}; whether the intermediate ARD object should be returned. } } \examples{ diff --git a/man/tbl_make_table_35.Rd b/man/tbl_make_table_35.Rd index 5405f3a8..7b257b2b 100644 --- a/man/tbl_make_table_35.Rd +++ b/man/tbl_make_table_35.Rd @@ -99,17 +99,16 @@ flag variables are treated as \code{"N"}. } } \examples{ -library(dplyr) adsl <- random.cdisc.data::cadsl adae <- random.cdisc.data::cadae # gtsummary table -------------- -tbl_gtsummary <- cardinal:::make_table_35_gtsummary(df = adae, denominator = adsl) +tbl_gtsummary <- make_table_35_gtsummary(df = adae, denominator = adsl) tbl_gtsummary # rtables table ---------------- -tbl_rtables <- cardinal:::make_table_35_rtables(df = adae, alt_counts_df = adsl) +tbl_rtables <- make_table_35_rtables(df = adae, alt_counts_df = adsl) tbl_rtables } From 19e6dcb487451c3efdc71e68acb04fe4a5097b4a Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Tue, 11 Mar 2025 15:42:27 +0100 Subject: [PATCH 16/21] Update documentation --- man/ard_make_table_35.Rd | 32 -------------------------------- man/make_table_35.Rd | 2 +- man/tbl_make_table_35.Rd | 5 ++--- 3 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 man/ard_make_table_35.Rd diff --git a/man/ard_make_table_35.Rd b/man/ard_make_table_35.Rd deleted file mode 100644 index ba4b38e6..00000000 --- a/man/ard_make_table_35.Rd +++ /dev/null @@ -1,32 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/fda-table_35.R -\name{ard_make_table_35} -\alias{ard_make_table_35} -\alias{ard_table_35} -\title{Make ARD: Table 35} -\usage{ -ard_table_35( - df, - denominator = NULL, - id_var = "USUBJID", - arm_var = "ARM", - saffl_var = "SAFFL", - soc_var = "AEBODSYS", - lbl_overall = NULL, - na_level = "" -) -} -\description{ -Make ARD: Table 35 -} -\examples{ -library(dplyr) - -adsl <- random.cdisc.data::cadsl -adae <- random.cdisc.data::cadae - -ard <- cardinal:::ard_table_35(adae, adsl) -ard - -} -\keyword{internal} diff --git a/man/make_table_35.Rd b/man/make_table_35.Rd index b2d5d868..c2902461 100644 --- a/man/make_table_35.Rd +++ b/man/make_table_35.Rd @@ -49,7 +49,7 @@ Safety Population, Pooled Analysis (or Trial X) \itemize{ \item \code{df} must contain the variables specified by \code{arm_var}, \code{id_var}, \code{soc_var} and \code{saffl_var}. -\item \code{return_ard} set to \code{TRUE} or \code{FALSE}; whether the intermediate ARD object should be returned. +\item \code{return_ard} set to \code{TRUE} (default) or \code{FALSE}; whether the intermediate ARD object should be returned. } } \examples{ diff --git a/man/tbl_make_table_35.Rd b/man/tbl_make_table_35.Rd index 5405f3a8..7b257b2b 100644 --- a/man/tbl_make_table_35.Rd +++ b/man/tbl_make_table_35.Rd @@ -99,17 +99,16 @@ flag variables are treated as \code{"N"}. } } \examples{ -library(dplyr) adsl <- random.cdisc.data::cadsl adae <- random.cdisc.data::cadae # gtsummary table -------------- -tbl_gtsummary <- cardinal:::make_table_35_gtsummary(df = adae, denominator = adsl) +tbl_gtsummary <- make_table_35_gtsummary(df = adae, denominator = adsl) tbl_gtsummary # rtables table ---------------- -tbl_rtables <- cardinal:::make_table_35_rtables(df = adae, alt_counts_df = adsl) +tbl_rtables <- make_table_35_rtables(df = adae, alt_counts_df = adsl) tbl_rtables } From d0e866afe84c7b972b078ddcdf6a0e93d0fddccc Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Tue, 11 Mar 2025 15:47:24 +0100 Subject: [PATCH 17/21] Correct minor lintr findings --- R/fda-table_35.R | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index dce7bed2..fe292d78 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -132,23 +132,23 @@ make_table_35_gtsummary <- function(df, } tbl_gts <- tbl_hierarchical( - data = df, - variables = soc_var, - by = arm_var, - denominator = denominator, - id = id_var - ) |> + data = df, + variables = soc_var, + by = arm_var, + denominator = denominator, + id = id_var + ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> modify_column_alignment(columns = all_stat_cols(), align = "right") if (!is.null(lbl_overall)) { tbl_gts_ovrl <- tbl_hierarchical( - data = df, - variables = soc_var, - denominator = denominator, - id = id_var - ) |> + data = df, + variables = soc_var, + denominator = denominator, + id = id_var + ) |> modify_header(label ~ paste0("**System Organ Class**")) |> modify_header( all_stat_cols() ~ paste0("**", lbl_overall, "** \nN = {n}") From a9e5dd2e3d910e35e6e6ab47781da07bf434693b Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Tue, 11 Mar 2025 16:19:34 +0100 Subject: [PATCH 18/21] Update quarto document --- R/fda-table_35.R | 2 +- quarto/table-templates/template-table_35.qmd | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index fe292d78..22c6f1b4 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -181,7 +181,7 @@ make_table_35_rtables <- function(df, arm_var = "ARM", saffl_var = "SAFFL", soc_var = "AEBODSYS", - lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], + lbl_soc_var = formatters::var_labels(df, fill = TRUE)[soc_var], lbl_overall = NULL, risk_diff = NULL, prune_0 = FALSE, diff --git a/quarto/table-templates/template-table_35.qmd b/quarto/table-templates/template-table_35.qmd index 4de12bd1..807433e7 100644 --- a/quarto/table-templates/template-table_35.qmd +++ b/quarto/table-templates/template-table_35.qmd @@ -43,7 +43,7 @@ Required variables: - **`df`**: The variables specified by `id_var`, `arm_var`, `saffl_var`, and `soc_var`. - **`denominator`** (if specified): `USUBJID` and the variables specified by `arm_var` and `saffl_var` -- If both the ARD (`return_ard = "Y"`) and an overall column (`lbl_overall` not missing) are requested, a list of two ARDs will be returned: `ard$tbl_summary` for the table by groups, and `ard$add_overall` for the overal column. +- If both the ARD (`return_ard = TRUE`) and an overall column (`lbl_overall` not missing) are requested, a list of two ARDs will be returned: one for the table by groups, and the other for the overall column. +---------------+------------------------------------------------------------------------------------+---------------+ | **Argument** | **Description** | **Default** | @@ -64,8 +64,10 @@ Required variables: +---------------+------------------------------------------------------------------------------------+---------------+ | `na_level` | (`character`) String to represent missing values. | `""` | +---------------+------------------------------------------------------------------------------------+---------------+ +| `lbl_overall` | (`character`) String to represent the label of an overall column. | `NULL` | ++---------------+------------------------------------------------------------------------------------+---------------+ -Source code for this function is available [here](https://github.com/pharmaverse/cardinal/blob/main/R/fda-table_11.R). +Source code for this function is available [here](https://github.com/pharmaverse/cardinal/blob/main/R/fda-table_35.R). @@ -91,7 +93,7 @@ result$ard ```{r tbl2-print, echo=FALSE} withr::local_options(width = 9999) -print(result$ard, columns = "all", n = Inf) +print(result$ard, columns = "all") ``` @@ -124,24 +126,26 @@ make_table_35_rtables(df = adae, alt_counts_df = adsl, risk_diff = risk_diff) Function Details -### `make_table_35()` +### `make_table_35_rtables()` ------------------------------------------------------------------------ Required variables: -- **`adae`**: `USUBJID` and the variables specified by `arm_var`, `saffl_var` and `soc_var`. +- **`df`**: `USUBJID` and the variables specified by `arm_var`, `saffl_var` and `soc_var`. - **`alt_counts_df`** (if specified): `USUBJID` and the variables specified by `arm_var` and `saffl_var`. +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ | **Argument** | **Description** | **Default** | +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ -| `adae` | (`data.frame`) Dataset (typically ADAE) required to build table. | *No default* | +| `df` | (`data.frame`) Dataset (typically ADAE) required to build table. | *No default* | +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ | `alt_counts_df` | (`character`) Alternative dataset (typically ADSL) used only to calculate column counts. | `NULL` | +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ | `show_colcounts` | (`flag`) Whether column counts should be printed. | `TRUE` | +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ +| `id_var` | (`character`) Subject identifier variable . | `USUBJID` | ++------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ | `arm_var` | (`character`) Arm variable used to split table into columns. | `"ARM"` | +------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------+ | `saffl_var` | (`character`) Flag variable used to indicate inclusion in safety population. | `"SAFFL"` | From 3a7486e368a6e4f59314e01c68b48ac0e608bffc Mon Sep 17 00:00:00 2001 From: "27856297+dependabot-preview[bot]@users.noreply.github.com" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:22:29 +0000 Subject: [PATCH 19/21] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/tbl_make_table_35.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/tbl_make_table_35.Rd b/man/tbl_make_table_35.Rd index 7b257b2b..68494945 100644 --- a/man/tbl_make_table_35.Rd +++ b/man/tbl_make_table_35.Rd @@ -25,7 +25,7 @@ make_table_35_rtables( arm_var = "ARM", saffl_var = "SAFFL", soc_var = "AEBODSYS", - lbl_soc_var = formatters::var_labels(adae, fill = TRUE)[soc_var], + lbl_soc_var = formatters::var_labels(df, fill = TRUE)[soc_var], lbl_overall = NULL, risk_diff = NULL, prune_0 = FALSE, From ab1c64675779738a532665a66e7f785d1a2a7e23 Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Wed, 12 Mar 2025 08:52:05 +0100 Subject: [PATCH 20/21] Upload upload-artifact action version number from v3 to v4 --- .github/workflows/docs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 8aa3f577..8436c233 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -68,7 +68,7 @@ jobs: - name: Upload Docs ⬆️ if: github.event_name != 'push' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: site path: ./_site From 16121b39403efa537a791468f3b3f830ecb9212c Mon Sep 17 00:00:00 2001 From: "Knizia,Jessica (MED BDS) BIP-DE-B" Date: Wed, 12 Mar 2025 09:29:30 +0100 Subject: [PATCH 21/21] Fix test --- R/fda-table_35.R | 4 +- tests/testthat/_snaps/fda-table_35.md | 89 ++++++++++++++------------- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/R/fda-table_35.R b/R/fda-table_35.R index 814a597c..defe0161 100644 --- a/R/fda-table_35.R +++ b/R/fda-table_35.R @@ -197,10 +197,10 @@ make_table_35_rtables <- function(df, ) |> append_topleft(c("", lbl_soc_var)) - tbl <- build_table(lyt, df = adae, alt_counts_df = alt_counts_df) |> + tbl <- build_table(lyt, df = df, alt_counts_df = alt_counts_df) |> sort_at_path( path = c(soc_var), - scorefun = score_occurrences_cols(col_names = levels(adae[[arm_var]])) + scorefun = score_occurrences_cols(col_names = levels(df[[arm_var]])) ) if (prune_0) tbl <- prune_table(tbl) diff --git a/tests/testthat/_snaps/fda-table_35.md b/tests/testthat/_snaps/fda-table_35.md index 021e5a15..f3f3853e 100644 --- a/tests/testthat/_snaps/fda-table_35.md +++ b/tests/testthat/_snaps/fda-table_35.md @@ -3,66 +3,70 @@ Code as.data.frame(res$table) Output - row_type var_label variable label stat_1 stat_2 stat_3 - 1 level
AEBODSYS cl A.1 78 (59.1) 75 (57.7) 89 (55.6) - 2 level
AEBODSYS cl B.1 47 (83.9) 49 (81.7) 43 (69.4) - 3 level
AEBODSYS cl B.2 79 (61.2) 74 (53.6) 85 (59.4) - 4 level
AEBODSYS cl C.1 43 (78.2) 46 (73.0) 43 (67.2) - 5 level
AEBODSYS cl C.2 35 (72.9) 48 (90.6) 55 (84.6) - 6 level
AEBODSYS cl D.1 79 (62.2) 67 (63.2) 80 (59.3) - 7 level
AEBODSYS cl D.2 47 (75.8) 58 (80.6) 57 (77.0) + **System Organ Class** **A: Drug X** \nN = 609 **B: Placebo** \nN = 622 **C: Combination** \nN = 703 + 1 cl A.1 78 (59%) 75 (58%) 89 (56%) + 2 cl B.1 47 (84%) 49 (82%) 43 (69%) + 3 cl B.2 79 (61%) 74 (54%) 85 (59%) + 4 cl C.1 43 (78%) 46 (73%) 43 (67%) + 5 cl C.2 35 (73%) 48 (91%) 55 (85%) + 6 cl D.1 79 (62%) 67 (63%) 80 (59%) + 7 cl D.2 47 (76%) 58 (81%) 57 (77%) --- Code res$ard + Output + $tbl_hierarchical Message - {cards} data frame: 72 x 11 + {cards} data frame: 72 x 13 Output - group1 group1_level variable variable_level stat_name stat_label stat - 1 ARM A: Drug X AEBODSYS cl A.1 n n 78 - 2 ARM A: Drug X AEBODSYS cl A.1 N N 132 - 3 ARM A: Drug X AEBODSYS cl A.1 p % 0.591 - 4 ARM A: Drug X AEBODSYS cl B.1 n n 47 - 5 ARM A: Drug X AEBODSYS cl B.1 N N 56 - 6 ARM A: Drug X AEBODSYS cl B.1 p % 0.839 - 7 ARM A: Drug X AEBODSYS cl B.2 n n 79 - 8 ARM A: Drug X AEBODSYS cl B.2 N N 129 - 9 ARM A: Drug X AEBODSYS cl B.2 p % 0.612 - 10 ARM A: Drug X AEBODSYS cl C.1 n n 43 + group1 group1_level variable variable_level stat_name stat_label stat stat_fmt + 1 ARM A: Drug X AEBODSYS cl A.1 n n 78 78 + 2 ARM A: Drug X AEBODSYS cl A.1 N N 132 132 + 3 ARM A: Drug X AEBODSYS cl A.1 p % 0.591 59 + 4 ARM A: Drug X AEBODSYS cl B.1 n n 47 47 + 5 ARM A: Drug X AEBODSYS cl B.1 N N 56 56 + 6 ARM A: Drug X AEBODSYS cl B.1 p % 0.839 84 + 7 ARM A: Drug X AEBODSYS cl B.2 n n 79 79 + 8 ARM A: Drug X AEBODSYS cl B.2 N N 129 129 + 9 ARM A: Drug X AEBODSYS cl B.2 p % 0.612 61 + 10 ARM A: Drug X AEBODSYS cl C.1 n n 43 43 Message i 62 more rows i Use `print(n = ...)` to see more rows - i 4 more variables: context, fmt_fn, warning, error + i 5 more variables: context, fmt_fn, warning, error, gts_column + Output + # Table 35 generation works with gtsummary with custom values Code as.data.frame(res) Output - row_type var_label variable label stat_1 stat_2 stat_3 - 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) - 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) - 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 85 (64.4) - 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 43 (32.6) - 5 level
AEBODSYS cl C.2 35 (26.1) 48 (35.8) 55 (41.7) - 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 80 (60.6) - 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) + **System Organ Class** **A: Drug X** \nN = 134 **B: Placebo** \nN = 134 **C: Combination** \nN = 132 + 1 cl A.1 78 (58%) 75 (56%) 89 (67%) + 2 cl B.1 47 (35%) 49 (37%) 43 (33%) + 3 cl B.2 79 (59%) 74 (55%) 85 (64%) + 4 cl C.1 43 (32%) 46 (34%) 43 (33%) + 5 cl C.2 35 (26%) 48 (36%) 55 (42%) + 6 cl D.1 79 (59%) 67 (50%) 80 (61%) + 7 cl D.2 47 (35%) 58 (43%) 57 (43%) # Table 35 generation works with gtsummary missing values Code as.data.frame(res) Output - row_type var_label variable label stat_1 stat_2 stat_3 - 1 level
AEBODSYS cl A.1 78 (58.2) 75 (56.0) 89 (67.4) - 2 level
AEBODSYS cl B.1 47 (35.1) 49 (36.6) 43 (32.6) - 3 level
AEBODSYS cl B.2 79 (59.0) 74 (55.2) 84 (63.6) - 4 level
AEBODSYS cl C.1 43 (32.1) 46 (34.3) 42 (31.8) - 5 level
AEBODSYS cl C.2 34 (25.4) 48 (35.8) 55 (41.7) - 6 level
AEBODSYS cl D.1 79 (59.0) 67 (50.0) 79 (59.8) - 7 level
AEBODSYS cl D.2 47 (35.1) 58 (43.3) 57 (43.2) - 8 level
AEBODSYS <Missing> 2 (1.5) 2 (1.5) 6 (4.5) + **System Organ Class** **A: Drug X** \nN = 134 **B: Placebo** \nN = 134 **C: Combination** \nN = 132 + 1 cl A.1 78 (58%) 75 (56%) 89 (67%) + 2 cl B.1 47 (35%) 49 (37%) 43 (33%) + 3 cl B.2 79 (59%) 74 (55%) 84 (64%) + 4 cl C.1 43 (32%) 46 (34%) 42 (32%) + 5 cl C.2 34 (25%) 48 (36%) 55 (42%) + 6 cl D.1 79 (59%) 67 (50%) 79 (60%) + 7 cl D.2 47 (35%) 58 (43%) 57 (43%) + 8 2 (1.5%) 2 (1.5%) 6 (4.5%) # Table 35 generation works with custom values @@ -123,12 +127,13 @@ Body System or Organ Class (N=134) (N=134) (N=132) ————————————————————————————————————————————————————————————————————— cl A.1 78 (58.2%) 75 (56.0%) 89 (67.4%) - cl B.2 79 (59.0%) 74 (55.2%) 85 (64.4%) - cl D.1 79 (59.0%) 67 (50.0%) 80 (60.6%) + cl B.2 79 (59.0%) 74 (55.2%) 84 (63.6%) + cl D.1 79 (59.0%) 67 (50.0%) 79 (59.8%) cl D.2 47 (35.1%) 58 (43.3%) 57 (43.2%) cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) - cl C.2 35 (26.1%) 48 (35.8%) 55 (41.7%) - cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) + cl C.2 34 (25.4%) 48 (35.8%) 55 (41.7%) + cl C.1 43 (32.1%) 46 (34.3%) 42 (31.8%) + 2 (1.5%) 2 (1.5%) 6 (4.5%) # Table 35 generation works with custom values (SOC variable and label)