Converts Analysis Results Data (ARD) from packages like
cards into a wide summary
data frame suitable for fr_table(). ARD stores one row per statistic;
fr_wide_ard() combines statistics using format strings, pivots treatment
arms to columns, and returns a display-ready data frame.
This function has no dependency on cards — it accepts any data frame
with the standard ARD columns (variable, stat_name, stat).
Handles all common post-ard_stack() pipeline shapes:
Raw
ard_stack()output (list columns)After
unlist_ard_columns()(atomic columns)After
rename_ard_columns(columns = all_ard_groups("names"))(group columns renamed to e.g.ARM)After default
rename_ard_columns()(both groups and variables renamed)Multi-group
.by = c(ARM, SEX)— extra groups preserved in outputNo
.byat all (ungrouped)
Usage
fr_wide_ard(
data,
statistic = list(continuous = "{mean} ({sd})", categorical = "{n} ({p}%)"),
column = NULL,
label = NULL,
overall = "Total",
decimals = NULL,
fmt = NULL,
big_n = NULL,
pct_display = NULL
)Arguments
- data
A data frame with ARD columns. At minimum, requires
stat_nameandstat. Standard ARD also hasvariable,group1/group1_level,variable_level, andcontext. Renamed ARD (afterrename_ard_columns()) is also accepted. Typically produced bycards::ard_stack().- statistic
Format strings for combining statistics into display cells. Accepts three forms:
Form 1: Named list by context (most common)
list( categorical = "{n} ({p}%)", continuous = c("Mean (SD)" = "{mean} ({sd})", Median = "{median}") )Categorical: one format string produces one row per category level. Continuous: a named character vector produces one row per entry, with names becoming row labels (e.g., "Mean (SD)", "Median").
Form 2: Named list by variable (per-variable override)
list( AGE = c(n = "{N}", "Mean (SD)" = "{mean} ({sd})"), SEX = "{n} ({p}%)", default = "{n} ({p}%)" )Form 3: Single string (applied to everything)
"{n} ({p}%)"Default:
list(continuous = "{mean} ({sd})", categorical = "{n} ({p}%)").- column
Character scalar. The grouping variable that becomes the display columns (e.g.,
"ARM","DOSGRP"). For raw ARD, this is the value ingroup1(auto-detected ifNULL). For renamed ARD, this is the column name in the data frame. IfNULL(default), auto-detected from the data.- label
Named character vector mapping variable names to display labels. E.g.,
c(AGE = "Age (years)", SEX = "Sex, n (%)"). For hierarchical ARD, also renames sentinel variables:c("..ard_hierarchical_overall.." = "Patients with Any TEAE"). IfNULL, usesvariablevalues as-is.- overall
Character scalar. Column header for overall/total rows (where
group1isNA). Default"Total". Set toNULLto exclude overall rows.- decimals
Decimal precision for stat formatting. Accepts two forms:
Global defaults — a named integer vector:
c(mean = 1, sd = 2, p = 0, median = 1)Per-variable overrides — a named list:
list( AGE = c(mean = 1, sd = 2), BMIBL = c(mean = 2, sd = 3), .default = c(mean = 1, sd = 2, p = 0) )Overrides built-in defaults. Default:
NULL.- fmt
Named list of custom format functions keyed by
stat_name. Each function takes a numeric value and returns a character string. E.g.,list(p.value = function(x) if (x < 0.001) "<0.001" else sprintf("%.3f", x)). Default:NULL.- big_n
Character scalar. The
stat_namevalue used for population counts (BigN) in the ARD (e.g.,"BigN","bigN","popn"). When specified, rows with thisstat_nameare extracted from the body and attached asattr(result, "n_counts")— a named numeric vector suitable forfr_cols(.n =). Default:NULL(no extraction).- pct_display
Named list controlling percentage display rules. Partial overrides supported — only supplied keys change, others keep defaults. Keys:
zero (logical): Display percentage when count is zero?
FALSE(default): n=0 shows "0" only.TRUE: n=0 shows full format e.g. "0 (0.0%)".threshold (logical): Apply pharma threshold rules?
TRUE(default): extreme percentages display as "<0.1" / ">99.9" (dynamic based on decimals precision).FALSE: show exact rounded value.
Default:
NULL(useslist(zero = FALSE, threshold = TRUE)).
Value
A data frame with columns:
- Extra group columns (if multi-group)
e.g.,
SEX,PARAMCDvariableGrouping variable (for use with
fr_rows(group_by =))stat_labelRow label (statistic name or category level)
- One column per treatment arm
Formatted display values
Total(if overall present)Overall column
For hierarchical ARD (SOC/PT), additional columns:
socSystem organ class value
ptPreferred term value
row_type"soc"or"pt"
If big_n is specified, attr(result, "n_counts") contains a named
numeric vector of population counts per arm.
Pipe directly to fr_table():
ard |> fr_wide_ard() |> fr_table() |> fr_cols(...) |> fr_render("out.pdf")See also
fr_table() for the pipeline entry point.
Examples
if (requireNamespace("cards", quietly = TRUE)) {
ard <- cards::ard_stack(
data = arframe::adsl[arframe::adsl$SAFFL == "Y", ],
.by = "ARM",
cards::ard_continuous(variables = "AGE"),
cards::ard_categorical(variables = "SEX"),
.overall = TRUE
)
# --- Scenario 1: Multi-row continuous output ---
wide <- fr_wide_ard(ard,
statistic = list(
continuous = c(
n = "{N}",
"Mean (SD)" = "{mean} ({sd})",
Median = "{median}",
"Min, Max" = "{min}, {max}"
),
categorical = "{n} ({p}%)"
),
label = c(AGE = "Age (years)", SEX = "Sex"),
decimals = c(mean = 1, sd = 2, p = 0)
)
print(wide)
# --- Scenario 2: Per-variable decimals ---
wide2 <- fr_wide_ard(ard,
statistic = list(
continuous = c("Mean (SD)" = "{mean} ({sd})"),
categorical = "{n} ({p}%)"
),
decimals = list(AGE = c(mean = 2, sd = 3), .default = c(p = 1))
)
# --- Scenario 3: Single string statistic ---
cat_ard <- cards::ard_stack(
data = arframe::adsl[arframe::adsl$SAFFL == "Y", ],
.by = "ARM",
cards::ard_categorical(variables = "SEX")
)
wide3 <- fr_wide_ard(cat_ard, statistic = "{n} ({p}%)")
# --- Scenario 4: Pipe into arframe ---
wide |>
fr_table() |>
fr_cols(
variable = fr_col(visible = FALSE),
stat_label = fr_col("", width = 2.5),
.align = "decimal"
) |>
fr_rows(group_by = list(cols = "variable", label = "stat_label"))
}
#> variable stat_label Placebo Zomerane 100mg Zomerane 50mg Total
#> 1 Age (years) n 45 45 45 135
#> 2 Age (years) Mean (SD) 75.0 (6.75) 75.3 (7.09) 73.1 (8.43) 74.4 (7.46)
#> 3 Age (years) Median 74.0 73.0 74.0 74.0
#> 4 Age (years) Min, Max 65.0, 88.0 55.0, 88.0 55.0, 88.0 55.0, 88.0
#> 5 Sex F 27 (60%) 20 (44%) 28 (62%) 75 (56%)
#> 6 Sex M 18 (40%) 25 (56%) 17 (38%) 60 (44%)
#>
#> ── fr_spec: Table
#> Data: 6 rows x 6 columns
#> Page: landscape letter, 9pt Times New Roman
#> Columns (5 visible of 6):
#> stat_label "" 2.50in decimal
#> Placebo "Placebo" 0.61in decimal
#> Zomerane 100mg "Zomerane 100mg" 1.00in decimal
#> Zomerane 50mg "Zomerane 50mg" 0.93in decimal
#> Total "Total" 0.61in decimal
#> Header: valign=bottom
#> Rows: group_by=variable (label=stat_label), indent_by=stat_label