Displaying subject totals (“Big N’s”) at the top of a table is a very
common and necessary part of building tables for clinical trials.
{tfrmt} allows you to do this via the big_n
argument, which
allows you to use a big_n_structure
object to specify which
values in the ARD should be added to the columns and how they should be
formatted.
Overall Big Ns
To dynamically add big N’s to column labels, the information needs to be included in the ARD. As a simple example, let’s take a small demographics table that just has Age and Sex for Placebo, Treatment and Total. Below is our ARD prior to incorporating the big Ns:
data <- tibble(Group = rep(c("Age (y)", "Sex", "Age (y)", "Sex"), c(3, 3, 6,12)),
Label = rep(c("n", "Mean (SD)", "Male","Female"), c(6, 6,6,6)),
Column = rep(c("Placebo", "Treatment", "Total"), times = 8),
Param = rep(c("n", "mean", "sd", "n", "pct", "n", "pct"), c(6, 3, 3, 3,3,3,3)),
Value = c(15,13,28,14,13,27,73.56, 74.231,71.84,9.347,7.234,8.293,8,7,15,8/14,7/13,15/27,6,6,12,6/14,6/13,12/27
)
) %>%
# Note because tfrmt only does rounding we will need to have the percents multiplied by 100
mutate(Value = case_when(Param == "pct" ~ Value * 100,
TRUE ~ Value),
ord1 = if_else(Group == "Age (y)", 1, 2),
ord2 = if_else(Label == "n", 1, 2))
data
#> # A tibble: 24 × 7
#> Group Label Column Param Value ord1 ord2
#> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
#> 1 Age (y) n Placebo n 15 1 1
#> 2 Age (y) n Treatment n 13 1 1
#> 3 Age (y) n Total n 28 1 1
#> 4 Sex n Placebo n 14 2 1
#> 5 Sex n Treatment n 13 2 1
#> 6 Sex n Total n 27 2 1
#> 7 Age (y) Mean (SD) Placebo mean 73.6 1 2
#> 8 Age (y) Mean (SD) Treatment mean 74.2 1 2
#> 9 Age (y) Mean (SD) Total mean 71.8 1 2
#> 10 Age (y) Mean (SD) Placebo sd 9.35 1 2
#> # ℹ 14 more rows
In this study we have 30 subjects per treatment arm for a total of 60
subjects. Because the ARD is 1 row per unique value, our Ns will
contribute 3 rows to the ARD. To make the N’s go to the right place, we
need to supply information about the column
column values.
The column
column values should map to those already
available in the ARD. Then we can combine this information with the data
above to make the full ARD for this table.
big_ns <- tibble(Column = c("Placebo", "Treatment", "Total"),
Param = "bigN",
Value = c(30,30,60))
data <- bind_rows(data, big_ns)
Now we can make our tfrmt
as normal, but this time we
are going to add a big_n_structure
to big_n
.
Here we will specify that values with the parameter of
"bigN"
should be appended to the column labels and they
should be formatted as "N = XX"
and on a separate line.
tfrmt(
group = Group,
label = Label,
column = Column,
value = Value,
param = Param,
sorting_cols = c(ord1, ord2),
body_plan = body_plan(
frmt_structure(group_val = ".default",
label_val = ".default",
frmt_combine("{n} {pct}",
n = frmt("X"),
pct = frmt("(xx.x%)", missing = " ")
)
),
frmt_structure(group_val = "Age (y)", label_val = "Mean (SD)",
frmt_combine("{mean} ({sd})",
mean = frmt("XX.X"),
sd = frmt("x.xx")
)
),
frmt_structure(group_val = ".default", label_val = "n", frmt("xx"))
),
col_plan = col_plan(everything(), -starts_with("ord"), "Total"),
row_grp_plan = row_grp_plan(
row_grp_structure(group_val = ".default", element_block(post_space = " "))
),
big_n = big_n_structure(param_val = "bigN", n_frmt = frmt("\nN = xx"))
) %>%
print_to_gt(data)
Placebo N = 30 | Treatment N = 30 | Total N = 60 | |
---|---|---|---|
Age (y) | |||
n | 15 | 13 | 28 |
Mean (SD) | 73.6 (9.35) | 74.2 (7.23) | 71.8 (8.29) |
Sex | |||
n | 14 | 13 | 27 |
Male | 8 (57.1%) | 7 (53.8%) | 15 (55.6%) |
Female | 6 (42.9%) | 6 (46.2%) | 12 (44.4%) |
No matter how complicated the table, this feature will work as long
as the ARD is set up appropriately with the correct column
column values on the big N rows. For tables with spanning columns
(i.e. multiple column
columns), the big N will be appended
to the lowest level column
column value that is supplied
(based on the order of the column variables supplied to the
tfrmt
). Let’s look at this table, which has 3 layers of
column spanning:
data <- tribble(
~group, ~label, ~span2, ~span1, ~my_col, ~parm, ~val,
"g1", "rowlabel1", "column cols", "cols 1,2", "col1" , "value", 1,
"g1", "rowlabel1", "column cols", "cols 1,2", "col2" , "value", 1,
"g1", "rowlabel1", NA, NA, "mycol3", "value", 1,
"g1", "rowlabel1", "column cols", "col 4" , "col4" , "value", 1,
"g1", "rowlabel1", NA, NA, "mycol5", "value", 1,
"g1", "rowlabel2", "column cols", "cols 1,2", "col1" , "value", 2,
"g1", "rowlabel2", "column cols", "cols 1,2", "col2" , "value", 2,
"g1", "rowlabel2", NA, NA , "mycol3", "value", 2,
"g1", "rowlabel2", "column cols", "col 4" , "col4" , "value", 2,
"g1", "rowlabel2", NA, NA, "mycol5", "value", 2,
"g2", "rowlabel3", "column cols", "cols 1,2", "col1" , "value", 3,
"g2", "rowlabel3", "column cols", "cols 1,2", "col2" , "value", 3,
"g2", "rowlabel3", NA, NA, "mycol3", "value", 3,
"g2", "rowlabel3", "column cols", "col 4" , "col4" , "value", 3,
"g2", "rowlabel3", NA, NA, "mycol5", "value", 3,
)
spanning_tfrmt<- tfrmt(
group = group,
label = label,
param = parm,
value = val,
column = c(span2, span1, my_col),
body_plan = body_plan(
frmt_structure(group_val = ".default", label_val = ".default", frmt("x"))
),
col_plan = col_plan(
group,
label,
starts_with("col")
)
)
print_to_gt(spanning_tfrmt, data)
column cols
|
|||||
---|---|---|---|---|---|
cols 1,2
|
col 4
|
mycol3 | mycol5 | ||
col1 | col2 | col4 | |||
g1 | |||||
rowlabel1 | 1 | 1 | 1 | 1 | 1 |
rowlabel2 | 2 | 2 | 2 | 2 | 2 |
g2 | |||||
rowlabel3 | 3 | 3 | 3 | 3 | 3 |
If we just want to put the big N on the highest “column cols”, we
need to add a row to the ARD where span2
equals
"column cols"
and all other column
columns are
missing.
with_big_n_data <- tribble(
~group, ~label, ~span2, ~span1, ~my_col, ~parm, ~val,
NA, NA, "column cols", NA, NA , "bigN", 18,
) %>%
bind_rows(data)
#Now we can add the big_n to the tfrmt from before
n_span_tfrmt <- spanning_tfrmt %>%
tfrmt(big_n = big_n_structure(param_val = "bigN", n_frmt = frmt("\nN = xx")))
print_to_gt(n_span_tfrmt, .data = with_big_n_data)
column cols
N = 18
|
|||||
---|---|---|---|---|---|
cols 1,2
|
col 4
|
mycol3 | mycol5 | ||
col1 | col2 | col4 | |||
g1 | |||||
rowlabel1 | 1 | 1 | 1 | 1 | 1 |
rowlabel2 | 2 | 2 | 2 | 2 | 2 |
g2 | |||||
rowlabel3 | 3 | 3 | 3 | 3 | 3 |
If we also want big N’s on col 1,2
, col4
,
and mycol3
, we will need Add 3 more rows to our ARD. One
that goes down to the span1
level of specificity and two
that go all the way down to my_col
level of specificity.
(Note: because we are keeping the parm
values the same we
can use the same tfrmt)
with_more_big_n_data <- tribble(
~group, ~label, ~span2, ~span1, ~my_col, ~parm, ~val,
NA, NA, "column cols", "cols 1,2", NA , "bigN", 12,
NA, NA, "column cols", "col 4" , "col4" , "bigN", 6,
NA, NA, NA, NA, "mycol3", "bigN", 6
) %>%
bind_rows(with_big_n_data)
print_to_gt(n_span_tfrmt, .data = with_more_big_n_data)
column cols
N = 18
|
|||||
---|---|---|---|---|---|
cols 1,2
N = 12
|
col 4
|
mycol3 N = 6 | mycol5 | ||
col1 | col2 | col4 N = 6 | |||
g1 | |||||
rowlabel1 | 1 | 1 | 1 | 1 | 1 |
rowlabel2 | 2 | 2 | 2 | 2 | 2 |
g2 | |||||
rowlabel3 | 3 | 3 | 3 | 3 | 3 |
Page-Level Big Ns
The page_plan
allows users to split up large tables in
many ways. Let’s suppose our page_plan
splits our table so
that each subtable represents a different subpopulation defined by the
group
variable in the ARD.
In this case, our page_plan looks something like this:
page_structure(group_val = ".default")
Because our subtables contain different populations, we want the big
Ns displayed in the headers to be table-specific. To achieve this, we
can supply multiple sets of big Ns in the ARD. We just need to specify
the specific values of the group
parameter that each big N
belongs to. This functionality can be enabled via the
by_page
argument in big_n_structure
.
For example, let’s take the following data, where we have calculated
big Ns for each level of the grouping variable grp
:
dat <- crossing(
grp = c("A","B"),
lbl = c("a","b"),
col = c("Placebo","Treatment"),
param = "mean"
) %>%
mutate(val = c(1.254, 3.483, 5.123, 4.239,4.364, 8.435, 7.645, 2.312))
big_ns <- tibble(col = c("Placebo","Placebo","Treatment","Treatment"),
grp = c("A", "B", "A", "B"),
param = "bigN",
val = c(34, 36, 42, 39))
dat <- bind_rows(dat, big_ns)
tail(dat)
#> # A tibble: 6 × 5
#> grp lbl col param val
#> <chr> <chr> <chr> <chr> <dbl>
#> 1 B b Placebo mean 7.64
#> 2 B b Treatment mean 2.31
#> 3 A NA Placebo bigN 34
#> 4 B NA Placebo bigN 36
#> 5 A NA Treatment bigN 42
#> 6 B NA Treatment bigN 39
Now that we have all big Ns represented in the ARD, we can make sure
of the by_page
argument in the big_n_structure
to ensure the various big Ns are assigned to the relevant pages defined
by the page_plan
.
gts <- tfrmt(
group = grp,
label = lbl,
column = col,
param = param,
value = val,
body_plan = body_plan(
frmt_structure(group_val = ".default", label_val = ".default", frmt("x.x"))
),
page_plan = page_plan(
page_structure(group_val = ".default")
),
big_n = big_n_structure(param_val = "bigN", n_frmt = frmt("\nN = xx"), by_page = TRUE)
) %>%
print_to_gt(dat)
Placebo N = 34 | Treatment N = 42 | |
---|---|---|
A | ||
a | 1.3 | 3.5 |
b | 5.1 | 4.2 |
Placebo N = 36 | Treatment N = 39 | |
---|---|---|
B | ||
a | 4.4 | 8.4 |
b | 7.6 | 2.3 |
## Final note
As a final note, column names for the big N's should match the ARD column names, rather than any future names. Regardless of any renaming that happens in the `col_plan`, the column name for the big N's should be consistent with column values in the ARD. The big N's will still be added if names do get updated in the `col_plan`.
``` r
n_span_tfrmt %>%
tfrmt(col_plan = col_plan(
group,
label,
starts_with("col"),
new_col_3 = mycol3,
-mycol5
)) %>%
print_to_gt(.data = with_more_big_n_data)
column cols
N = 18
|
||||
---|---|---|---|---|
cols 1,2
N = 12
|
col 4
|
new_col_3 N = 6 | ||
col1 | col2 | col4 N = 6 | ||
g1 | ||||
rowlabel1 | 1 | 1 | 1 | 1 |
rowlabel2 | 2 | 2 | 2 | 2 |
g2 | ||||
rowlabel3 | 3 | 3 | 3 | 3 |
big_n_structure
s provide a straightforward way of adding
big N’s from the ARD into the column labels. The functionality allows
for big N’s at any level of column spanning depending on how it is
parameterized in the ARD.