Many standard tables call for a set of difference columns to be added alongside the main tabulation; this, combined with the spanning column labels favored by Johnson&Johnson shells, results in a complex final column structure.
To ease the creation of these structures, particularly in the
presence of virtual combination arms, we provide the
grouped_cols_w_diffs function. It provides the flexibility
to be used in standard template scripts, as we will see below.
At it’s most basic, grouped_cols_w_diffs takes a
column-span treatment map, as created by
create_colspan_map. This creates a column structure with
spanning labels over active and non-active treatment groups, as well as
difference columns comparing each active treatments individually against
each non-active treatment:
library(junco)
adsl <- create_colspan_var(pharmaverseadamjnj::adsl)
adae <- create_colspan_var(pharmaverseadamjnj::adae)
adlb <- create_colspan_var(pharmaverseadamjnj::adlb)
trt_map <- create_colspan_map(adsl)
print(trt_map)
#> colspan_trt TRT01A
#> 1 Active Study Agent Xanomeline Low Dose
#> 2 Active Study Agent Xanomeline High Dose
#> 3 Placebolyt <- basic_table() |>
grouped_cols_w_diffs(trt_map)
build_table(lyt, adsl)
#> Active Study Agent Risk Differences
#> Xanomeline Low Dose Xanomeline High Dose Placebo Xanomeline Low Dose vs Placebo Xanomeline High Dose vs Placebo
#> ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————grouped_cols_w_diffs creates only the column
structure; the contents of the difference columns are calculated by the
analysis function used in the layout. The structure for the
various types of difference columns (risk, mean, eair, etc) differs only
in the spanning label for the difference columns.
grouped_cols_w_diffs accepts diffs_label for
this purpose:
lyt2 <- basic_table() |>
grouped_cols_w_diffs(trt_map, diffs_label = "Mean Differences")
build_table(lyt2, adsl)
#> Active Study Agent Mean Differences
#> Xanomeline Low Dose Xanomeline High Dose Placebo Xanomeline Low Dose vs Placebo Xanomeline High Dose vs Placebo
#> ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————Care should be taken to choose the correct analysis function to create the types of differences required by your shell.
Despite the function’s name, we can turn off difference columns when
using grouped_cols_w_diffs via the diff_cols
argument. This allows us to use the function unconditionally in our
layouts while retaining the ability to turn off difference columns ,
e.g., in shells where they are optional.
Beyond the basic usage, grouped_cols_w_diffs offers
fine-grained control over both the arms (notably the addition of
combination arms) and comparisons between arms displayed in your
table.
Combination levels are declared via a “combo data.frame” similar to
those accepted by rtables::add_combo_levels. In particular,
we use a data.frame with the following columns:
valname - (character)
Name of the combination level (as it will appear in paths)label - (character) Label
for the combination level (as it will appear in the table)levelcombo - (list of
characters) The levels which should be combined into the
combination levelexargs - (list) Extra
arguments to be passed to a/cfuns associated with the combination
levelis_control Optional
(logical) When TRUE, the combination level
will be added to the second (non-active) group of treatments. Assumed
FALSE if not specified.compare_against Optional
(list of characters) The levels the
combination level should be compared against (as the first/active
element). Assumed to be select_all_levels if not
specified.Thus at its most basic, we use this argument like so:
library(tibble)
#> Warning: package 'tibble' was built under R version 4.5.2
combodf1 <- tribble(
~valname, ~label, ~levelcombo, ~exargs,
"all_active", "All Xanomeline", c("Xanomeline High Dose", "Xanomeline Low Dose"), list()
)
lyt3 <- basic_table() |>
grouped_cols_w_diffs(trt_map, combo_map_df = combodf1)
#> none of the combination levels appeared in the colspan treatment map; adding them automatically.
build_table(lyt3, adsl)
#> Active Study Agent Risk Differences
#> Xanomeline Low Dose Xanomeline High Dose All Xanomeline Placebo Xanomeline Low Dose vs Placebo Xanomeline High Dose vs Placebo All Xanomeline vs Placebo
#> ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————We can instead add a second virtual control or referene group by
including the is_control column and setting it to
TRUE for some or all of our combination levels:
combodf2 <- tribble(
~valname, ~label, ~levelcombo, ~exargs, ~is_control,
"all_active", "All Xanomeline", c("Xanomeline High Dose", "Xanomeline Low Dose"), list(), FALSE,
"placebo_redux", "Double Placebo!!", c("Placebo"), list(), TRUE
)
lyt4 <- basic_table() |>
grouped_cols_w_diffs(trt_map, combo_map_df = combodf2)
#> none of the combination levels appeared in the colspan treatment map; adding them automatically.
build_table(lyt4, adsl)
#> Active Study Agent Risk Differences
#> Xanomeline Low Dose Xanomeline High Dose All Xanomeline Placebo Double Placebo!! Xanomeline Low Dose vs Placebo Xanomeline High Dose vs Placebo All Xanomeline vs Placebo Xanomeline Low Dose vs Double Placebo!! Xanomeline High Dose vs Double Placebo!! All Xanomeline vs Double Placebo!!
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————As we can see, this allows us full flexibility to include combination levels as both active and non-active virtual arms, including using them in both sides of comparisons (even simultaneously).
Finally, we have complete control over which comparisons appear in
our table via the comp_map argument. When non-null, the
exact set of comparisons specified in comp_map will appear
in our table.
comp_map accepts a data.frame with the columns
active, and comparator, as well optional
active_is_combo and comparator_is_combo
columns. The values in active and comparator
should be the names (as opposed to labels) of the respective
arms:
comp_map1 <- tribble(
~active, ~comparator,
"Xanomeline High Dose", "Placebo",
"Xanomeline Low Dose", "placebo_redux",
"all_active", "placebo_redux"
)
lyt5 <- basic_table() |>
grouped_cols_w_diffs(trt_map, combo_map_df = combodf2, comp_map = comp_map1)
#> none of the combination levels appeared in the colspan treatment map; adding them automatically.
build_table(lyt5, adsl)
#> Active Study Agent Risk Differences
#> Xanomeline Low Dose Xanomeline High Dose All Xanomeline Placebo Double Placebo!! Xanomeline High Dose vs Placebo Xanomeline Low Dose vs Double Placebo!! All Xanomeline vs Double Placebo!!
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————We can also use comp_map to compare one active treatment
to another:
comp_map2 <- tribble(
~active, ~comparator,
"Xanomeline High Dose", "Xanomeline Low Dose",
"Xanomeline High Dose", "Placebo",
"Xanomeline Low Dose", "Placebo"
)
lyt6 <- basic_table() |>
grouped_cols_w_diffs(trt_map, comp_map = comp_map2)
build_table(lyt6, adsl)
#> Active Study Agent Risk Differences
#> Xanomeline Low Dose Xanomeline High Dose Placebo Xanomeline High Dose vs Xanomeline Low Dose Xanomeline High Dose vs Placebo Xanomeline Low Dose vs Placebo
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————The grouped_cols_w_subgrps function generates columns
structures, with or without overarching spanning column headers, wherein
treatment arms are further split by the values of a subgrouping
variable.
By default, a Total column is added to the left of the subgroups within each treatment, though this can be disabled.
Similar to grouped_cols_w_diffs, we can specify a
colspan_trt_map, which will define both the spanning labels
and the treatment variable:
lyt_subgrp <- basic_table() |>
grouped_cols_w_subgrps(trt_map, subgrp_var = "SEX")
build_table(lyt_subgrp, adsl)
#> Active Study Agent
#> Xanomeline Low Dose Xanomeline High Dose Placebo
#> (N=96) (N=72) (N=86)
#> SEX SEX SEX
#> Total F M Total F M Total F M
#> —————————————————————————————————————————————————————————————————————————Similar to grouped_cols_w_diffs, we can get a structure
without spanning labels by specifying trtvar instead of
colspan_trt_map, though this does make the name of the
function something of a misnomer, as the treatments are no longer
grouped:
lyt_subgrp2 <- basic_table() |>
grouped_cols_w_subgrps(trtvar = "TRT01A", subgrp_var = "SEX")
build_table(lyt_subgrp2, adsl)
#> Xanomeline Low Dose Xanomeline High Dose Placebo
#> (N=96) (N=72) (N=86)
#> SEX SEX SEX
#> Total F M Total F M Total F M
#> —————————————————————————————————————————————————————————————————————————grouped_cols_w_subgrps also accepts
combo_map_df, with usage similar to that explored for
grouped_cols_w_diffs above.
For pre-computed quartile (or any other binning) groups, we can
simply use grouped_cols_w_subgrps with
total_facet = FALSE:
lyt_ageqrtls <- basic_table() |>
grouped_cols_w_subgrps(colspan_trt_map = trt_map,
subgrp_var = "AGEGR1",
subgrp_lbl = "Age Quartiles",
total_facet = FALSE)
build_table(lyt_ageqrtls, adsl)
#> Active Study Agent
#> Xanomeline Low Dose Xanomeline High Dose Placebo
#> (N=96) (N=72) (N=86)
#> Age Quartiles Age Quartiles Age Quartiles
#> >=18 to <65 >=65 to <75 >=75 >=18 to <65 >=65 to <75 >=75 >=18 to <65 >=65 to <75 >=75
#> —————————————————————————————————————————————————————————————————————————————————————————————————————————We can create the column structure for a standard Shift Table via the
shift_tbl_col_struct function (assuming BNRIND
is a classification at baseline and ANRIND is the same
classification applied at analysis date):
The “some vs all” case, motivated by comparing counts of AEs to counts of treatment-related AEs, is similar to the subgroup column structures, with the exception that the groups being compared are not mutually exclusive.
In light of this, some_v_all_col_struct creates two
subgroup facets within each treatment group, one containing one or more
levels of a specified subgrouping variable, the other being all levels
of the subgrouping variable. We control this behavior by the combination
of subgrp_var, declaring the variable, and
subgrp_lvls defining which levels should be included in the
smaller group.
lyt <- basic_table() |>
some_v_all_col_struct(trt_map,
subgrp_var = "AETOXGR",
subgrp_lvls = c("4", "5"),
all_lbl = "All Grades",
subgrp_lbl = "High Toxicity")
build_table(lyt, adae)
#> Active Study Agent
#> Xanomeline Low Dose Xanomeline High Dose Placebo
#> (N=454) (N=436) (N=301)
#> All Grades High Toxicity All Grades High Toxicity All Grades High Toxicity
#> ———————————————————————————————————————————————————————————————————————————————————————