From 90ada6880fede63e5c3b49d760495947f69149be Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:19:42 +0000 Subject: [PATCH 01/11] Initial plan From 2e3811ed39387f6d39977c53351dd4c1c19fbd97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:26:17 +0000 Subject: [PATCH 02/11] Separate CARDs section from TLG section Co-authored-by: jeffreyad <112705781+jeffreyad@users.noreply.github.com> --- _quarto.yml | 1 + cards/demographic.qmd | 101 ++++++++++++++++++++++++++++++++++++++++++ cards/index.qmd | 3 ++ tlg/demographic.qmd | 57 +----------------------- 4 files changed, 106 insertions(+), 56 deletions(-) create mode 100644 cards/demographic.qmd create mode 100644 cards/index.qmd diff --git a/_quarto.yml b/_quarto.yml index d6a95cd0..a3cb3e82 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -51,6 +51,7 @@ website: - auto: sdtm - auto: adam - auto: tlg + - auto: cards - auto: digit_files - auto: interactive - auto: logging diff --git a/cards/demographic.qmd b/cards/demographic.qmd new file mode 100644 index 00000000..aa4714ce --- /dev/null +++ b/cards/demographic.qmd @@ -0,0 +1,101 @@ +--- +title: "Demographic Table" +order: 1 +--- + +```{r setup script, include=FALSE, purl=FALSE} +invisible_hook_purl <- function(before, options, ...) { + knitr::hook_purl(before, options, ...) + NULL +} +knitr::knit_hooks$set(purl = invisible_hook_purl) +knitr::opts_chunk$set(echo = TRUE) +``` + +## Introduction + +This guide will show you how pharmaverse packages, along with some from tidyverse, can be used to create a Demographic table, using the `{pharmaverseadam}` `ADSL` data as an input. + +In the examples below, we illustrate how to create demographics tables using Analysis Results Datasets---part of the emerging [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard). + +## Data preprocessing + +Now we will add some pre-processing to create some extra formatted variables ready for display in the table. + +```{r preproc} +#| message: false +library(dplyr) + +# Create categorical variables, remove screen failures, and assign column labels +adsl <- pharmaverseadam::adsl |> + filter(!ACTARM %in% "Screen Failure") |> + mutate( + SEX = case_match(SEX, "M" ~ "MALE", "F" ~ "FEMALE"), + AGEGR1 = + case_when( + between(AGE, 18, 40) ~ "18-40", + between(AGE, 41, 64) ~ "41-64", + AGE > 64 ~ ">=65" + ) |> + factor(levels = c("18-40", "41-64", ">=65")) + ) |> + labelled::set_variable_labels( + AGE = "Age (yr)", + AGEGR1 = "Age group", + SEX = "Sex", + RACE = "Race" + ) +``` + +## {gtsummary} & {cards} + +In the example below, we will use the [{gtsummary}](https://www.danieldsjoberg.com/gtsummary/) and [{cards}](https://insightsengineering.github.io/cards/) packages to create a demographics tables. + +- The {cards} package creates Analysis Results Datasets (ARDs, which are a part of the [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard)). +- The {gtsummary} utilizes ARDs to create tables. + +#### ARD ➡ Table + +In the example below, we first build an ARD with the needed summary statistics using {cards}. +Then, we use the ARD to build the demographics table with {gtsummary}. + +```{r gtsummary-table} +#| message: false +library(cards) +library(gtsummary) +theme_gtsummary_compact() # reduce default padding and font size for a gt table + +# build the ARD with the needed summary statistics using {cards} +ard <- + ard_stack( + adsl, + ard_continuous(variables = AGE), + ard_categorical(variables = c(AGEGR1, SEX, RACE)), + .by = ACTARM, # split results by treatment arm + .attributes = TRUE # optionally include column labels in the ARD + ) + +# use the ARD to create a demographics table using {gtsummary} +tbl_ard_summary( + cards = ard, + by = ACTARM, + include = c(AGE, AGEGR1, SEX, RACE), + type = AGE ~ "continuous2", + statistic = AGE ~ c("{N}", "{mean} ({sd})", "{median} ({p25}, {p75})", "{min}, {max}") +) |> + bold_labels() |> + modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> # add Ns to header + modify_footnote(everything() ~ NA) # remove default footnote +``` + +#### Table ➡ ARD + +One may also build the demographics in the classic way using `gtsummary::tbl_summary()` from a data frame, then extract the ARD from the table object. + +```{r gtsummary-ard} +# build demographics table directly from a data frame +tbl <- adsl |> tbl_summary(by = ACTARM, include = c(AGE, AGEGR1, SEX, RACE)) + +# extract ARD from table object +gather_ard(tbl)[[1]] |> select(-gts_column) # removing column so ARD fits on page +``` diff --git a/cards/index.qmd b/cards/index.qmd new file mode 100644 index 00000000..b3f13a7d --- /dev/null +++ b/cards/index.qmd @@ -0,0 +1,3 @@ +--- +title: "CARDs" +--- diff --git a/tlg/demographic.qmd b/tlg/demographic.qmd index 4af3b9cc..c8e7c775 100644 --- a/tlg/demographic.qmd +++ b/tlg/demographic.qmd @@ -16,9 +16,7 @@ knitr::opts_chunk$set(echo = TRUE) This guide will show you how pharmaverse packages, along with some from tidyverse, can be used to create a Demographic table, using the `{pharmaverseadam}` `ADSL` data as an input. -In the examples below, we illustrate two general approaches for creating a demographics table. -The first utilizes Analysis Results Datasets---part of the emerging [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard). -The second is the classic method of creating summary tables directly from a data set. +In the example below, we illustrate creating summary tables directly from a data set. ## Data preprocessing @@ -49,59 +47,6 @@ adsl <- pharmaverseadam::adsl |> ) ``` -## {gtsummary} & {cards} - -In the example below, we will use the [{gtsummary}](https://www.danieldsjoberg.com/gtsummary/) and [{cards}](https://insightsengineering.github.io/cards/) packages to create a demographics tables. - -- The {cards} package creates Analysis Results Datasets (ARDs, which are a part of the [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard)). -- The {gtsummary} utilizes ARDs to create tables. - -#### ARD ➡ Table - -In the example below, we first build an ARD with the needed summary statistics using {cards}. -Then, we use the ARD to build the demographics table with {gtsummary}. - -```{r gtsummary-table} -#| message: false -library(cards) -library(gtsummary) -theme_gtsummary_compact() # reduce default padding and font size for a gt table - -# build the ARD with the needed summary statistics using {cards} -ard <- - ard_stack( - adsl, - ard_continuous(variables = AGE), - ard_categorical(variables = c(AGEGR1, SEX, RACE)), - .by = ACTARM, # split results by treatment arm - .attributes = TRUE # optionally include column labels in the ARD - ) - -# use the ARD to create a demographics table using {gtsummary} -tbl_ard_summary( - cards = ard, - by = ACTARM, - include = c(AGE, AGEGR1, SEX, RACE), - type = AGE ~ "continuous2", - statistic = AGE ~ c("{N}", "{mean} ({sd})", "{median} ({p25}, {p75})", "{min}, {max}") -) |> - bold_labels() |> - modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> # add Ns to header - modify_footnote(everything() ~ NA) # remove default footnote -``` - -#### Table ➡ ARD - -One may also build the demographics in the classic way using `gtsummary::tbl_summary()` from a data frame, then extract the ARD from the table object. - -```{r gtsummary-ard} -# build demographics table directly from a data frame -tbl <- adsl |> tbl_summary(by = ACTARM, include = c(AGE, AGEGR1, SEX, RACE)) - -# extract ARD from table object -gather_ard(tbl)[[1]] |> select(-gts_column) # removing column so ARD fits on page -``` - ## {rtables} & {tern} The packages used with a brief description of their purpose are as follows: From 13ef99a7eb7acf5a261648b0508a0f2b84ed629e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:29:47 +0000 Subject: [PATCH 03/11] Add 'cards' to WORDLIST for spell checking Co-authored-by: jeffreyad <112705781+jeffreyad@users.noreply.github.com> --- inst/WORDLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/WORDLIST b/inst/WORDLIST index 7b81871a..5f478ef1 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -185,6 +185,7 @@ cachem cairo cairoFT callr +cards categorizationvars cdisc CDISC From 74925437f850cf391e4fb243219b01fde312f370 Mon Sep 17 00:00:00 2001 From: Jeff Dickinson Date: Thu, 13 Nov 2025 18:01:21 -0600 Subject: [PATCH 04/11] Add rendered R script --- cards/demographic.R | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 cards/demographic.R diff --git a/cards/demographic.R b/cards/demographic.R new file mode 100644 index 00000000..d9e02b68 --- /dev/null +++ b/cards/demographic.R @@ -0,0 +1,57 @@ +## ----r preproc---------------------------------------------------------------- +library(dplyr) + +# Create categorical variables, remove screen failures, and assign column labels +adsl <- pharmaverseadam::adsl |> + filter(!ACTARM %in% "Screen Failure") |> + mutate( + SEX = case_match(SEX, "M" ~ "MALE", "F" ~ "FEMALE"), + AGEGR1 = + case_when( + between(AGE, 18, 40) ~ "18-40", + between(AGE, 41, 64) ~ "41-64", + AGE > 64 ~ ">=65" + ) |> + factor(levels = c("18-40", "41-64", ">=65")) + ) |> + labelled::set_variable_labels( + AGE = "Age (yr)", + AGEGR1 = "Age group", + SEX = "Sex", + RACE = "Race" + ) + +## ----r gtsummary-table-------------------------------------------------------- +library(cards) +library(gtsummary) +theme_gtsummary_compact() # reduce default padding and font size for a gt table + +# build the ARD with the needed summary statistics using {cards} +ard <- + ard_stack( + adsl, + ard_continuous(variables = AGE), + ard_categorical(variables = c(AGEGR1, SEX, RACE)), + .by = ACTARM, # split results by treatment arm + .attributes = TRUE # optionally include column labels in the ARD + ) + +# use the ARD to create a demographics table using {gtsummary} +tbl_ard_summary( + cards = ard, + by = ACTARM, + include = c(AGE, AGEGR1, SEX, RACE), + type = AGE ~ "continuous2", + statistic = AGE ~ c("{N}", "{mean} ({sd})", "{median} ({p25}, {p75})", "{min}, {max}") +) |> + bold_labels() |> + modify_header(all_stat_cols() ~ "**{level}** \nN = {n}") |> # add Ns to header + modify_footnote(everything() ~ NA) # remove default footnote + +## ----r gtsummary-ard---------------------------------------------------------- +# build demographics table directly from a data frame +tbl <- adsl |> tbl_summary(by = ACTARM, include = c(AGE, AGEGR1, SEX, RACE)) + +# extract ARD from table object +gather_ard(tbl)[[1]] |> select(-gts_column) # removing column so ARD fits on page + From 2b25a947360e8221da5cba07f15d5c0d9cee32f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:49:05 +0000 Subject: [PATCH 05/11] Enhance introduction with detailed CDISC ARD and cards package information Co-authored-by: jeffreyad <112705781+jeffreyad@users.noreply.github.com> --- cards/demographic.qmd | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cards/demographic.qmd b/cards/demographic.qmd index aa4714ce..0a5bc093 100644 --- a/cards/demographic.qmd +++ b/cards/demographic.qmd @@ -16,7 +16,26 @@ knitr::opts_chunk$set(echo = TRUE) This guide will show you how pharmaverse packages, along with some from tidyverse, can be used to create a Demographic table, using the `{pharmaverseadam}` `ADSL` data as an input. -In the examples below, we illustrate how to create demographics tables using Analysis Results Datasets---part of the emerging [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard). +### About CDISC Analysis Results Data (ARD) + +Analysis Results Datasets (ARDs) are a core component of the emerging [CDISC Analysis Results Standard](https://www.cdisc.org/standards/foundational/analysis-results-standard). ARDs provide a standardized, machine-readable format for representing statistical analysis results, enabling: + +- **Reproducibility**: ARDs capture the complete analysis metadata, making results reproducible and traceable +- **Automation**: Machine-readable formats allow automated generation of tables, listings, and graphs +- **Interoperability**: Standardized structures facilitate data exchange between systems and organizations +- **Regulatory Submissions**: ARDs support modern regulatory requirements for transparent and auditable analyses + +### About the {cards} Package + +The [{cards}](https://insightsengineering.github.io/cards/) package is a powerful R package designed to create Analysis Results Datasets that conform to the CDISC ARD standard. Key features include: + +- Creates ARDs with summary statistics for continuous and categorical variables +- Supports stratified analyses (e.g., by treatment arm) +- Integrates seamlessly with table-making packages like {gtsummary} +- Captures metadata such as variable labels and analysis context +- Provides a consistent data structure for downstream reporting + +In the examples below, we illustrate how to create demographics tables using ARDs generated with {cards}, demonstrating the modern workflow for creating analysis results that are both human-readable and machine-actionable. ## Data preprocessing From 07b682d782b09e3a4e055a0836710a0bfddf4fcc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:53:13 +0000 Subject: [PATCH 06/11] Rename cards demographic files to cards_demographic to avoid name conflicts Co-authored-by: jeffreyad <112705781+jeffreyad@users.noreply.github.com> --- cards/{demographic.R => cards_demographic.R} | 0 cards/{demographic.qmd => cards_demographic.qmd} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cards/{demographic.R => cards_demographic.R} (100%) rename cards/{demographic.qmd => cards_demographic.qmd} (100%) diff --git a/cards/demographic.R b/cards/cards_demographic.R similarity index 100% rename from cards/demographic.R rename to cards/cards_demographic.R diff --git a/cards/demographic.qmd b/cards/cards_demographic.qmd similarity index 100% rename from cards/demographic.qmd rename to cards/cards_demographic.qmd From 23165bcd51aaf504bf30c61a9e7cc2f780a05636 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:57:07 +0000 Subject: [PATCH 07/11] Add 'See also' section in TLG demographic linking to CARDs example Co-authored-by: jeffreyad <112705781+jeffreyad@users.noreply.github.com> --- tlg/demographic.qmd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tlg/demographic.qmd b/tlg/demographic.qmd index c8e7c775..774f95aa 100644 --- a/tlg/demographic.qmd +++ b/tlg/demographic.qmd @@ -88,3 +88,7 @@ result <- build_table(lyt, adsl2) result ``` + +## See also + +For an alternative approach using Analysis Results Datasets (ARDs) and the [{cards}](https://insightsengineering.github.io/cards/) package, see the [CARDs Demographic Table example](../cards/cards_demographic.qmd). From 963509a4476244f7e28147ec7ed71e890dea3359 Mon Sep 17 00:00:00 2001 From: Jeffrey Dickinson Date: Fri, 14 Nov 2025 18:55:21 +0000 Subject: [PATCH 08/11] #104 run styler and update wordlist --- cards/cards_demographic.R | 1 - inst/WORDLIST | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cards/cards_demographic.R b/cards/cards_demographic.R index d9e02b68..5092c848 100644 --- a/cards/cards_demographic.R +++ b/cards/cards_demographic.R @@ -54,4 +54,3 @@ tbl <- adsl |> tbl_summary(by = ACTARM, include = c(AGE, AGEGR1, SEX, RACE)) # extract ARD from table object gather_ard(tbl)[[1]] |> select(-gts_column) # removing column so ARD fits on page - diff --git a/inst/WORDLIST b/inst/WORDLIST index 5f478ef1..4d25702e 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -136,6 +136,7 @@ ATPT ATPTN ATPTREF attr +auditable autofit autolog autoslider @@ -186,6 +187,7 @@ cairo cairoFT callr cards +CARDs categorizationvars cdisc CDISC From ec576ffc14362b0a8e4b0898914d0cd7582a1384 Mon Sep 17 00:00:00 2001 From: Jeff Dickinson Date: Thu, 4 Dec 2025 11:03:45 -0600 Subject: [PATCH 09/11] Update cards/cards_demographic.qmd Co-authored-by: Daniel Sjoberg --- cards/cards_demographic.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cards/cards_demographic.qmd b/cards/cards_demographic.qmd index 0a5bc093..4db790db 100644 --- a/cards/cards_demographic.qmd +++ b/cards/cards_demographic.qmd @@ -89,7 +89,7 @@ ard <- ard_stack( adsl, ard_continuous(variables = AGE), - ard_categorical(variables = c(AGEGR1, SEX, RACE)), + ard_tabulate(variables = c(AGEGR1, SEX, RACE)), .by = ACTARM, # split results by treatment arm .attributes = TRUE # optionally include column labels in the ARD ) From 5fc12608459e1b398301ec3005822f5bed780074 Mon Sep 17 00:00:00 2001 From: Jeff Dickinson Date: Thu, 4 Dec 2025 11:04:17 -0600 Subject: [PATCH 10/11] Update cards/cards_demographic.qmd Co-authored-by: Daniel Sjoberg --- cards/cards_demographic.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cards/cards_demographic.qmd b/cards/cards_demographic.qmd index 4db790db..97c8d2a1 100644 --- a/cards/cards_demographic.qmd +++ b/cards/cards_demographic.qmd @@ -88,7 +88,7 @@ theme_gtsummary_compact() # reduce default padding and font size for a gt table ard <- ard_stack( adsl, - ard_continuous(variables = AGE), + ard_summary(variables = AGE), ard_tabulate(variables = c(AGEGR1, SEX, RACE)), .by = ACTARM, # split results by treatment arm .attributes = TRUE # optionally include column labels in the ARD From 1ede229af7743e6da076710ea6c09857288d6810 Mon Sep 17 00:00:00 2001 From: Jeff Dickinson Date: Thu, 4 Dec 2025 11:04:34 -0600 Subject: [PATCH 11/11] Update cards/cards_demographic.qmd Co-authored-by: Daniel Sjoberg --- cards/cards_demographic.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cards/cards_demographic.qmd b/cards/cards_demographic.qmd index 97c8d2a1..021f6bdb 100644 --- a/cards/cards_demographic.qmd +++ b/cards/cards_demographic.qmd @@ -27,7 +27,7 @@ Analysis Results Datasets (ARDs) are a core component of the emerging [CDISC Ana ### About the {cards} Package -The [{cards}](https://insightsengineering.github.io/cards/) package is a powerful R package designed to create Analysis Results Datasets that conform to the CDISC ARD standard. Key features include: +The [{cards}](https://insightsengineering.github.io/cards/) package is a powerful R package designed to create Analysis Results Datasets (ARDs). Key features include: - Creates ARDs with summary statistics for continuous and categorical variables - Supports stratified analyses (e.g., by treatment arm)