Introduction to the Analysis Results Standard and {cards}
Introduction to the {cardx} Package and ARD Extras
ARD to Tables with {gtsummary}
ARD to Tables with {tfrmt}
Metadata-driven table formatting
Easily create new and modify existing tables
Input: ARD with raw, numeric values ({cards}!)
Output: Formatted table via {gt}
Demographics Table | |||
---|---|---|---|
Placebo N = xx |
Low Dose N = xx |
High Dose N = xx |
|
Age (y) | |||
Mean | xxx.x | xxx.x | xxx.x |
SD | xxx.xx | xxx.xx | xxx.xx |
Median | xxx.x | xxx.x | xxx.x |
Min | xxx.x | xxx.x | xxx.x |
Max | xxx.x | xxx.x | xxx.x |
<65 yrs | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
65-80 yrs | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
>80 yrs | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
Sex | |||
Male | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
Female | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
Baseline BMI | |||
Mean | xxx.x | xxx.x | xxx.x |
SD | xxx.xx | xxx.xx | xxx.xx |
Median | xxx.x | xxx.x | xxx.x |
Min | xxx.x | xxx.x | xxx.x |
Max | xxx.x | xxx.x | xxx.x |
<25 | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
25-<30 | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
>=30 | xxx (xx.x %) | xxx (xx.x %) | xxx (xx.x %) |
Demographics Table | |||
---|---|---|---|
Placebo N = 86 |
Low Dose N = 84 |
High Dose N = 84 |
|
Age (y) | |||
Mean | 75.2 | 75.7 | 74.4 |
SD | 8.59 | 8.29 | 7.89 |
Median | 76.0 | 77.5 | 76.0 |
Min | 52.0 | 51.0 | 56.0 |
Max | 89.0 | 88.0 | 88.0 |
<65 yrs | 14 (16.3 %) | 8 ( 9.5 %) | 11 (13.1 %) |
65-80 yrs | 42 (48.8 %) | 47 (56.0 %) | 55 (65.5 %) |
>80 yrs | 30 (34.9 %) | 29 (34.5 %) | 18 (21.4 %) |
Sex | |||
Male | 33 (38.4 %) | 34 (40.5 %) | 44 (52.4 %) |
Female | 53 (61.6 %) | 50 (59.5 %) | 40 (47.6 %) |
Baseline BMI | |||
Mean | 23.6 | 25.1 | 25.3 |
SD | 3.67 | 4.27 | 4.16 |
Median | 23.4 | 24.3 | 24.8 |
Min | 15.1 | 17.7 | 13.7 |
Max | 33.3 | 40.1 | 34.5 |
<25 | 59 (68.6 %) | 47 (56.0 %) | 44 (52.4 %) |
25-<30 | 21 (24.4 %) | 27 (32.1 %) | 28 (33.3 %) |
>=30 | 6 ( 7.0 %) | 10 (11.9 %) | 12 (14.3 %) |
Demographics Table | |||
---|---|---|---|
Safety Population | |||
High Dose (N = 84) |
Low Dose (N = 84) |
Placebo (N = 86) |
|
Age (y) | |||
Mean | 74.4 | 75.7 | 75.2 |
SD | 7.89 | 8.29 | 8.59 |
Median | 76.0 | 77.5 | 76.0 |
Min | 56.0 | 51.0 | 52.0 |
Max | 88.0 | 88.0 | 89.0 |
<65 yrs | 11 (13.1 %) | 8 ( 9.5 %) | 14 (16.3 %) |
65-80 yrs | 55 (65.5 %) | 47 (56.0 %) | 42 (48.8 %) |
>80 yrs | 18 (21.4 %) | 29 (34.5 %) | 30 (34.9 %) |
Sex | |||
Male | 44 (52.4 %) | 34 (40.5 %) | 33 (38.4 %) |
Female | 40 (47.6 %) | 50 (59.5 %) | 53 (61.6 %) |
Data collected at Screening Visit |
Organization standards can be capture as templates
With layering, teams can customize only the bits that need changing
# create a template as a function
tfrmt_demog_ta <- function(tfrmt_obj){
tfrmt_demog_ta <- tfrmt(
# define the formatting specific to the therapeutic area
)
layer_tfrmt(x = tfrmt_obj, y = tfrmt_demog_ta)
}
# Layering multiple templates
tfrmt_demog_org() |>
tfrmt_demog_ta() |>
print_to_gt(
.data = demog_data
)
Organization standards can be capture as templates
With layering, teams can customize only the bits that need changing
# create a template as a function
tfrmt_demog_study <- function(tfrmt_obj){
tfrmt_demog_study <- tfrmt(
# define the formatting specific to the study
)
layer_tfrmt(x = tfrmt_obj, y = tfrmt_demog_study)
}
# Layering multiple templates
tfrmt_demog_org() |>
tfrmt_demog_ta() |>
tfrmt_demog_study() |>
print_to_gt(
.data = demog_data
)
{
"group": ["rowlbl1", "grp"],
"label": ["rowlbl2"],
"param": ["param"],
"value": ["value"],
"column": ["column"],
"title": ["Demographics Table"],
"body_plan": [
{
"group_val": [".default"],
"label_val": [".default"],
"param_val": ["n", "pct"],
"frmt_combine": {
"expression": ["{n} {pct}"],
"frmt_ls": {
"n": {
"frmt": {
"expression": ["xxx"],
"missing": {},
"scientific": {},
"transform": {}
}
},
"pct": {
"frmt_when": {
"frmt_ls": {
"==100": [""],
"==0": [""],
"TRUE": {
"frmt": {
"expression": ["(xx.x %)"],
"missing": {},
"scientific": {},
"transform": {}
}
}
},
"missing": {}
}
}
},
"missing": {}
}
},
{
"group_val": [".default"],
"label_val": ["n"],
"param_val": [".default"],
"frmt": {
"expression": ["xxx"],
"missing": {},
"scientific": {},
"transform": {}
}
},
{
"group_val": [".default"],
"label_val": ["Mean", "Median", "Min", "Max"],
"param_val": [".default"],
"frmt": {
"expression": ["xxx.x"],
"missing": {},
"scientific": {},
"transform": {}
}
},
{
"group_val": [".default"],
"label_val": ["SD"],
"param_val": [".default"],
"frmt": {
"expression": ["xxx.xx"],
"missing": {},
"scientific": {},
"transform": {}
}
}
],
"col_style_plan": [
{
"cols": [
["Placebo"],
["Low Dose"],
["High Dose"]
],
"align": [".", ",", " "],
"type": ["char"],
"width": {}
},
{
"cols": [
["rowlbl1"],
["rowlbl2"]
],
"align": ["left"],
"type": ["char"],
"width": {}
}
],
"col_plan": {
"col_plan": {
"dots": [
["-grp"],
["-starts_with(\"ord\")"]
],
".drop": [false]
}
},
"sorting_cols": ["ord1", "ord2"],
"big_n": {
"param_val": ["bigN"],
"n_frmt": {
"expression": ["<br>N = xx"],
"missing": {},
"scientific": {},
"transform": {}
},
"by_page": [false]
}
}
Create a language-agnostic JSON file
Load JSON back into R and recreate the table with json_to_tfrmt()
tfrmt::print_to_gt()
creates a {gt} object under the hood
You can export the table to a variety of formats using gt::gt_save()
# A tibble: 6 × 7
TRT01A variable label stat_name stat ord1 ord2
<chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
1 Active Age (years) Median median 77 1 NA
2 Active Age (years) [Q1, Q3] p25 71 1 NA
3 Active Age (years) [Q1, Q3] p75 81 1 NA
4 Placebo Age (years) Median median 76 1 NA
5 Placebo Age (years) [Q1, Q3] p25 69 1 NA
6 Placebo Age (years) [Q1, Q3] p75 82 1 NA
ord1 | ord2 | Active | Placebo | |
---|---|---|---|---|
Age (years) | ||||
Median | 1 | NA | 77 | 76 |
[Q1, Q3] | 1 | NA | 71, 81 | 69, 82 |
Age Group | ||||
18-64 | 2 | 1 | 19, 11.3095238095238 | 14, 16.2790697674419 |
>64 | 2 | 2 | 149, 88.6904761904762 | 72, 83.7209302325581 |
TRT01A | ||||
Active | NA | NA | 168 | |
Placebo | NA | NA | 86 |
ord1 | ord2 | Active N = 168 |
Placebo N = 86 |
|
---|---|---|---|---|
Age (years) | ||||
Median | 1 | NA | 77 | 76 |
[Q1, Q3] | 1 | NA | 71, 81 | 69, 82 |
Age Group | ||||
18-64 | 2 | 1 | 19, 11.3095238095238 | 14, 16.2790697674419 |
>64 | 2 | 2 | 149, 88.6904761904762 | 72, 83.7209302325581 |
Placebo N = 86 |
Active N = 168 |
|
---|---|---|
Age (years) | ||
Median | 76 | 77 |
[Q1, Q3] | 69, 82 | 71, 81 |
Age Group | ||
18-64 | 14, 16.2790697674419 | 19, 11.3095238095238 |
>64 | 72, 83.7209302325581 | 149, 88.6904761904762 |
Placebo N = 86 |
Active N = 168 |
|
---|---|---|
Age (years) | ||
Median | 76.00 | 77.00 |
[Q1, Q3] | 69.00, 82.00 | 71.00, 81.00 |
Age Group | ||
18-64 | 14.00, 16.28 | 19.00, 11.31 |
>64 | 72.00, 83.72 | 149.00, 88.69 |
Placebo N = 86 |
Active N = 168 |
|
---|---|---|
Age (years) | ||
Median | 76.00 | 77.00 |
[Q1, Q3] | 69.00, 82.00 | 71.00, 81.00 |
Age Group | ||
18-64 | 14 (16.3%) | 19 (11.3%) |
>64 | 72 (83.7%) | 149 (88.7%) |
tfrmt_demog <- tfrmt_demog |>
tfrmt(
body_plan = body_plan(
frmt_structure(
group_val = ".default",
label_val = "Median",
frmt("xx.x")
),
frmt_structure(
group_val = ".default",
label_val = ".default",
frmt_combine(
expression = "[{p25}, {p75}]",
p25 = frmt("xx.x"),
p75 = frmt("xx.x")
)
)
)
)
print_to_gt(
tfrmt = tfrmt_demog,
.data = ard_demog
) |>
gt_style_slides()
Placebo N = 86 |
Active N = 168 |
|
---|---|---|
Age (years) | ||
Median | 76.0 | 77.0 |
[Q1, Q3] | [69.0, 82.0] | [71.0, 81.0] |
Age Group | ||
18-64 | 14 (16.3%) | 19 (11.3%) |
>64 | 72 (83.7%) | 149 (88.7%) |
Placebo N = 86 |
Active N = 168 |
|
---|---|---|
Age (years) | ||
Median | 76.0 | 77.0 |
[Q1, Q3] | [69.0, 82.0] | [71.0, 81.0] |
Age Group | ||
18-64 | 14 (16.3%) | 19 (11.3%) |
>64 | 72 (83.7%) | 149 (88.7%) |
Placebo N = 86 |
Active N = 1681 |
|
---|---|---|
Age (years) | ||
Median | 76.0 | 77.0 |
[Q1, Q3] | [69.0, 82.0] | [71.0, 81.0] |
Age Group | ||
18-64 | 14 (16.3%) | 19 (11.3%) |
>64 | 72 (83.7%) | 149 (88.7%) |
1 Pooled High and Low Dose |
Demographic Table | ||
---|---|---|
Safety Population | ||
Placebo N = 86 |
Active N = 1681 |
|
Age (years) | ||
Median | 76.0 | 77.0 |
[Q1, Q3] | [69.0, 82.0] | [71.0, 81.0] |
Age Group | ||
18-64 | 14 (16.3%) | 19 (11.3%) |
>64 | 72 (83.7%) | 149 (88.7%) |
1 Pooled High and Low Dose |
Transform values in the formatting
Row group formatting
Pagination
Multi-positional column alignment
Templating
{cards} includes a helper function shuffle_ard()
to transform native {cards} output to display-ready data
This is also available as an argument .shuffle
in ard_stack()
library(cards)
pharmaverseadam::adsl |>
ard_categorical(
by = TRT01A,
variables = c("AGEGR1","SEX")
)
group1 group1_level variable variable_level stat_name stat_label stat
1 TRT01A Placebo AGEGR1 >64 n n 72
2 TRT01A Placebo AGEGR1 >64 N N 86
3 TRT01A Placebo AGEGR1 >64 p % 0.837
4 TRT01A Screen F… AGEGR1 >64 n n 43
5 TRT01A Screen F… AGEGR1 >64 N N 52
6 TRT01A Screen F… AGEGR1 >64 p % 0.827
7 TRT01A Xanomeli… AGEGR1 >64 n n 61
8 TRT01A Xanomeli… AGEGR1 >64 N N 72
9 TRT01A Xanomeli… AGEGR1 >64 p % 0.847
10 TRT01A Xanomeli… AGEGR1 >64 n n 88
{cards} includes a helper function shuffle_ard()
to transform native {cards} output to display-ready data
This is also available as an argument .shuffle
in ard_stack()
library(cards)
pharmaverseadam::adsl |>
ard_categorical(
by = TRT01A,
variables = c("AGEGR1","SEX")
) |>
shuffle_ard()
# A tibble: 48 × 6
TRT01A variable label context stat_name stat
<chr> <chr> <chr> <chr> <chr> <dbl>
1 Placebo AGEGR1 >64 categorical n 72
2 Placebo AGEGR1 >64 categorical N 86
3 Placebo AGEGR1 >64 categorical p 0.837
4 Placebo AGEGR1 18-64 categorical n 14
5 Placebo AGEGR1 18-64 categorical N 86
6 Placebo AGEGR1 18-64 categorical p 0.163
7 Screen Failure AGEGR1 >64 categorical n 43
8 Screen Failure AGEGR1 >64 categorical N 52
9 Screen Failure AGEGR1 >64 categorical p 0.827
10 Screen Failure AGEGR1 18-64 categorical n 9
# ℹ 38 more rows
{cards} includes a helper function shuffle_ard()
to transform native {cards} output to display-ready data
This is also available as an argument .shuffle
in ard_stack()
library(cards)
library(tfrmt)
my_ard <- pharmaverseadam::adsl |>
ard_categorical(
by = TRT01A,
variables = c("AGEGR1","SEX")
) |>
shuffle_ard() |>
dplyr::filter(stat_name %in% c("n","p")) |>
dplyr::select(-context)
tfrmt(
group = variable,
label = label,
column = TRT01A,
param = stat_name,
value = stat,
body_plan = body_plan(
frmt_structure(group_val = ".default",
label_val = ".default",
frmt_combine("{n} ({p}%)",
n = frmt("xx"),
p = frmt("xx",
transform = ~.*100)))
)
) |>
print_to_gt(my_ard)|>
gt_style_slides()|>
gt::tab_options(
table.font.size = 15
)
Placebo | Screen Failure | Xanomeline High Dose | Xanomeline Low Dose | |
---|---|---|---|---|
AGEGR1 | ||||
>64 | 72 (84%) | 43 (83%) | 61 (85%) | 88 (92%) |
18-64 | 14 (16%) | 9 (17%) | 11 (15%) | 8 ( 8%) |
SEX | ||||
F | 53 (62%) | 36 (69%) | 35 (49%) | 55 (57%) |
M | 33 (38%) | 16 (31%) | 37 (51%) | 41 (43%) |
Point-and-click interface for {tfrmt}
Ability to create new or modify existing display
Eases learning curve for new users
Empowers non-programmers
Open R file exercises/04-tables-tfrmt.R
Run the provided code, which will open the app in your browser
Complete the steps to further customize the table (hint: Edit tab):
Switch the order of treatment columns so Active is first (hint: Column Plan)
Change the footnote marks to letters instead of numbers (hint: Footnote Plan)
Split the table into 2 parts by setting a maximum of 3 rows (hint: Page Plan)
Export the table (hint: Export Tab)
Introduction to the Analysis Results Standard and {cards}
Introduction to the {cardx} Package and ARD Extras
ARD to Tables with {gtsummary}
ARD to Tables with {tfrmt}
Wrap-up slido quiz
{gtsummary}: https://www.danieldsjoberg.com/gtsummary/
{tfrmtbuilder}: https://gsk-biostatistics.github.io/tfrmtbuilder/