---
title: "Standard Column Structures"
date: "2026-05-04"
output:
    rmarkdown::html_document:
        theme: "spacelab"
        highlight: "kate"
        toc: true
        toc_float: true
vignette: >
  %\VignetteIndexEntry{Standard Column Structures}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
editor_options:
  markdown:
      wrap: 72
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  echo = TRUE,
  collapse = TRUE,
  comment = "#>"
)
```

# Structures With Difference Columns

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.

## Basic Usage

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:

```{r}
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)
```

```{r}
lyt <- basic_table() |>
  grouped_cols_w_diffs(trt_map)


build_table(lyt, adsl)
```

### A Note About Types Of Differences
`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:

```{r}
lyt2 <- basic_table() |>
  grouped_cols_w_diffs(trt_map, diffs_label = "Mean Differences")


build_table(lyt2, adsl)
```

Care should be taken to choose the correct analysis function to create
the types of differences required by your shell.

### Turning Off The Difference Columns

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.


```{r}
lyt_nodiff <- basic_table() |>
  grouped_cols_w_diffs(trt_map, diff_cols = FALSE)


build_table(lyt_nodiff, adsl)
```


## Advanced Usage

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.

### Including Virtual Combination Arms

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 `character`s) The levels which should
  be combined into the combination level
- **`exargs`** - (`list`) Extra arguments to be passed to a/cfuns
  associated with the combination level
- **`is_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 `character`s) 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:

```{r}
library(tibble)
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)

build_table(lyt3, adsl)
```

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:

```{r}
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)

build_table(lyt4, adsl)
```

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).

### Direct Control Of Comparisons

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:



```{r}
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)

build_table(lyt5, adsl)
```

We can also use `comp_map` to compare one active treatment to another:


```{r}
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)

```

# Other Standard Column Structures

## Subgroup Column Structures

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:

```{r}
lyt_subgrp <- basic_table() |>
  grouped_cols_w_subgrps(trt_map, subgrp_var = "SEX")


build_table(lyt_subgrp, adsl)
```

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:


```{r}
lyt_subgrp2 <- basic_table() |>
  grouped_cols_w_subgrps(trtvar = "TRT01A", subgrp_var = "SEX")


build_table(lyt_subgrp2, adsl)
```

`grouped_cols_w_subgrps` also accepts `combo_map_df`, with usage
similar to that explored for `grouped_cols_w_diffs` above.

### Quartiles As A Special Case Of Subgrouping

For pre-computed quartile (or any other binning) groups, we can simply use `grouped_cols_w_subgrps` with `total_facet = FALSE`:


```{r}
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)
```

## Shift Table Column Structure

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):

```{r}
param <- levels(adlb$PARAMCD)[1]
lyt_shift <- basic_table() |>
  shift_tbl_col_struct(var = "BNRIND",
                       span_lbl = paste("Baseline", param))

build_table(lyt_shift, adlb)
```

## Some Vs All Column Structure

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.

```{r}
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)
```
