Author: Laure Cougnaud
Date: 2025-09-24

# Advanced user in-text tables

#### Laure Cougnaud

#### September 24, 2025

In this vignette we focus on providing more explanation on how the `inTextSummaryTable` package actually works. We would describe some of the functionalities less exposed to the users.

We assume you are already familiar on how to create and export tables, otherwise we advise to first check out the dedicated vignettes for creating and exporting tables. The vignettes are accessible with the commands below.

    vignette("inTextSummaryTable-createTables", "inTextSummaryTable")
    vignette("inTextSummaryTable-exportTables", "inTextSummaryTable")

We will first create example data sets to show how the exporting functionalities work. The data sets used are available in the `clinUtils` package.

    library(inTextSummaryTable)
    library(clinUtils)
    library(tools) # toTitleCase

    # load example data
    data(dataADaMCDISCP01)

    dataAll <- dataADaMCDISCP01
    labelVars <- attr(dataAll, "labelVars")

    dataADSL <- dataADaMCDISCP01$ADSL

    dataAE <-  subset(dataAll$ADAE, SAFFL == "Y" & TRTEMFL == "Y")
    dataAEInterest <- subset(dataAE, AESOC %in% c(
            "INFECTIONS AND INFESTATIONS",
            "GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS"
        )
    )

    # ensure that order of elements is the one specified in
    # the corresponding numeric variable
    dataAEInterest$TRTA <- reorder(dataAEInterest$TRTA, dataAEInterest$TRTAN)
    dataAEInterest$AESEV <- factor(dataAEInterest$AESEV, levels = c("MILD", "MODERATE"))

    dataTotalAE <- subset(dataAll$ADSL, TRT01A != "Placebo")
    # should contain columns specified in 'colVar'
    dataTotalAE$TRTA <- dataTotalAE$TRT01A

# 1 Detailed framework of the creation of the in-text table

The `getSummaryStatisticsTable` consists of the following framework:

- computation of the summary statistics table with the `computeSummaryStatisticsTable` function
- export of the table to the required format with the `outputType` parameter

## 1.1 Computation of the summary statistics

The supporting data for the summary statistics table, is accessed via the `computeSummaryStatisticsTable`. This includes the entire set of statistics (as numeric) and combined statistic set.

The output from the `computeSummaryStatisticsTable` is equivalent of the table output by the `getSummaryStatisticsTable` function when the `outputType` is set to ‘data.frame-base’.

    summaryTable <- computeSummaryStatisticsTable(
        data = dataAEInterest,
        rowVar = c("AESOC", "AEDECOD"),
        rowVarTotalInclude = c("AESOC", "AEDECOD"),
        colVar = "TRTA",
        stats = getStats("n (%)"),
        dataTotal = dataTotalAE,
        labelVars = labelVars,
        rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)")
    )

    print(head(summaryTable, 3))

    ##                                                  AESOC                     AEDECOD                TRTA isTotal statN statm statPercTotalN statPercN    n (%)
    ## 1 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE DERMATITIS Xanomeline Low Dose   FALSE     0     0              2         0        0
    ## 2 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS   APPLICATION SITE ERYTHEMA Xanomeline Low Dose   FALSE     2     2              2       100  2 (100)
    ## 3 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE IRRITATION Xanomeline Low Dose   FALSE     1     2              2        50 1 (50.0)

Please note the presence of the `isTotal` column, which flags the records containing the number of subjects reported in the table header.

    print(subset(summaryTable, isTotal))

    ##    AESOC AEDECOD                 TRTA isTotal statN statm statPercTotalN statPercN   n (%)
    ## 13  <NA>    <NA>  Xanomeline Low Dose    TRUE     2     2              2       100 2 (100)
    ## 26  <NA>    <NA> Xanomeline High Dose    TRUE     3     3              3       100 3 (100)

## 1.2 Export table to the requested format

The summary table is exported to the format of interest with:

    export(
        summaryTable = summaryTable,
        outputType = "flextable"
    )

TEAE by SOC and Preferred Term n (%) | Xanomeline Low Dose (N=2) | Xanomeline High Dose (N=3)
--- | --- | ---
Dictionary-Derived Term
Any TEAE by SOC and Preferred Term n (%), Dictionary-Derived Term | 2 (100) | 3 (100)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS | 2 (100) | 3 (100)
APPLICATION SITE DERMATITIS | 0 | 1 (33.3)
APPLICATION SITE ERYTHEMA | 2 (100) | 1 (33.3)
APPLICATION SITE IRRITATION | 1 (50.0) | 1 (33.3)
APPLICATION SITE PRURITUS | 2 (100) | 2 (66.7)
FATIGUE | 0 | 1 (33.3)
SECRETION DISCHARGE | 1 (50.0) | 0
SUDDEN DEATH | 1 (50.0) | 0
INFECTIONS AND INFESTATIONS | 1 (50.0) | 1 (33.3)
LOWER RESPIRATORY TRACT INFECTION | 0 | 1 (33.3)
PNEUMONIA | 1 (50.0) | 0

Please see the vignette: `inTextSummaryTable-exportTables` for more information on the different export types available.

# 2 Combine summary statistics table

## 2.1 Via the `combine` function

Summary statistics tables can be combined with the `combine` function.

    tableDemoCat <- computeSummaryStatisticsTable(
        data = dataADSL,
        var = c("SEX", "AGE"), varInclude0 = TRUE,
        colVar = "TRT01P",
        stats = getStats("n (%)", includeName = FALSE),
        labelVars = labelVars
    )
    tableDemoCont <- computeSummaryStatisticsTable(
        data = dataADSL,
        var = c("HEIGHTBL", "WEIGHTBL"),
        colVar = "TRT01P",
        stats = getStats(c("n", "Mean")),
        labelVars = labelVars
    )
    tableDemo <- combine(tableDemoCat, tableDemoCont)
    export(tableDemo)

| Placebo (N=2) | Xanomeline High Dose (N=3) | Xanomeline Low Dose (N=2)
--- | --- | --- | ---
Sex |  |  |
F | 1 (50.0) | 2 (66.7) | 2 (100)
M | 1 (50.0) | 1 (33.3) | 0
Age | 2 (100) | 3 (100) | 2 (100)
Baseline Height (cm) |  |  |
n | 2 | 3 | 2
Mean | 167.7 | 163 | 155.6
Baseline Weight (kg) |  |  |
n | 2 | 3 | 2
Mean | 59.65 | 68.5 | 54.45

## 2.2 Manually

The tables created via the `inTextSummaryTable` are simple R `data.frame` objects, so these can be combined/update to include extra statistics of interest.

The general workflow is to:

- create a table of descriptive statistics with the package (via the `computeSummaryStatisticsTable` function)
- create a `data.frame` with your statistics of relevance - in a similar format
- combine your table with a table created by the package
- export it (via the `exportSummaryStatisticsTable` function)

For example, we combine the descriptive statistics table created above with a set of pre-computed statistics (e.g. p-values of the difference between the treatment groups).

    dataADSL$TRT01P <- with(dataADSL, reorder(TRT01P, TRT01PN))

    # check format of table created with the package:
    descTable <- tableDemoCont
    descTable[, c("variable", "TRT01P", "isTotal", "n", "Mean")]

    ##               variable               TRT01P isTotal n  Mean
    ## 1 Baseline Height (cm)              Placebo   FALSE 2 167.7
    ## 2 Baseline Weight (kg)              Placebo   FALSE 2 59.65
    ## 3                 <NA>              Placebo    TRUE 2    NA
    ## 4 Baseline Height (cm) Xanomeline High Dose   FALSE 3   163
    ## 5 Baseline Weight (kg) Xanomeline High Dose   FALSE 3  68.5
    ## 6                 <NA> Xanomeline High Dose    TRUE 3    NA
    ## 7 Baseline Height (cm)  Xanomeline Low Dose   FALSE 2 155.6
    ## 8 Baseline Weight (kg)  Xanomeline Low Dose   FALSE 2 54.45
    ## 9                 <NA>  Xanomeline Low Dose    TRUE 2    NA

### 2.2.1 Statistics in rows

    # add p-values in an extra row
    infTable <- unique(subset(descTable, !isTotal)[, c("variable", "TRT01P"), drop = FALSE])
    infTable[which(infTable$variable == "Baseline Height (cm)"), "pValue"] <- 1e-10
    infTable[which(infTable$variable == "Baseline Weight (kg)"), "pValue"] <- 1e-9
    summaryTable <- plyr::rbind.fill(descTable, infTable)

    exportSummaryStatisticsTable(
        summaryTable = summaryTable,
        rowVar = "variable",
        colVar = "TRT01P",
        statsVar = c("n", "Mean", "pValue")
    )

variable | Placebo (N=2) | Xanomeline High Dose (N=3) | Xanomeline Low Dose (N=2)
--- | --- | --- | ---
Baseline Height (cm) |  |  |
n | 2 | 3 | 2
Mean | 167.7 | 163 | 155.6
pValue | 1e-10 | 1e-10 | 1e-10
Baseline Weight (kg) |  |  |
n | 2 | 3 | 2
Mean | 59.65 | 68.5 | 54.45
pValue | 1e-09 | 1e-09 | 1e-09

### 2.2.2 Statistics in rows, in an extra column

    compLab <- "Comparison between treatments (p-value)"

    # add p-values in a new column - in an extra row
    infTable <- unique(subset(descTable, !isTotal)[, "variable", drop = FALSE])
    infTable$TRT01P <- compLab
    infTable[which(infTable$variable == "Baseline Height (cm)"), "pValue"] <- 1e-10
    infTable[which(infTable$variable == "Baseline Weight (kg)"), "pValue"] <- 1e-9
    summaryTable <- plyr::rbind.fill(descTable, infTable)

    # order columns to have comparison column as last
    summaryTable$TRT01P <- factor(summaryTable$TRT01P, levels = c(levels(dataADSL$TRT01P), compLab))
    exportSummaryStatisticsTable(
        summaryTable = summaryTable,
        rowVar = "variable",
        colVar = "TRT01P",
        statsVar = c("n", "Mean", "pValue")
    )

variable | Placebo (N=2) | Xanomeline Low Dose (N=2) | Xanomeline High Dose (N=3) | Comparison between treatments (p-value)
--- | --- | --- | --- | ---
Baseline Height (cm) |  |  |  |
n | 2 | 2 | 3 | -
Mean | 167.7 | 155.6 | 163 | -
pValue | - | - | - | 1e-10
Baseline Weight (kg) |  |  |  |
n | 2 | 2 | 3 | -
Mean | 59.65 | 54.45 | 68.5 | -
pValue | - | - | - | 1e-09

### 2.2.3 Statistics in an extra column

    infTable <- unique(subset(descTable, !isTotal)[, "variable", drop = FALSE])
    infTable$TRT01P <- compLab
    infTable[which(infTable$variable == "Baseline Height (cm)"), "Mean"] <- 1e-10
    infTable[which(infTable$variable == "Baseline Weight (kg)"), "Mean"] <- 1e-9

    summaryTable <- plyr::rbind.fill(descTable, infTable)

    # order columns to have comparison column as last
    summaryTable$TRT01P <- factor(summaryTable$TRT01P, levels = c(levels(dataADSL$TRT01P), compLab))

    exportSummaryStatisticsTable(
        summaryTable = summaryTable,
        rowVar = "variable",
        colVar = "TRT01P",
        statsVar = c("n", "Mean")
    )

variable | Placebo (N=2) | Xanomeline Low Dose (N=2) | Xanomeline High Dose (N=3) | Comparison between treatments (p-value)
--- | --- | --- | --- | ---
Baseline Height (cm) |  |  |  |
n | 2 | 2 | 3 | -
Mean | 167.7 | 155.6 | 163 | 1e-10
Baseline Weight (kg) |  |  |  |
n | 2 | 2 | 3 | -
Mean | 59.65 | 54.45 | 68.5 | 1e-09

# 3 Data pre-processing

The variables used for the row and columns of the summary statistics tables should be present in a long format in the input data for the `getSummaryStatisticsTable` function.

In case the grouping of the rows/columns is more complex and no grouping variable is yet available in the data, the function `combineVariables` offers simpler functionalities to create the input data.

The label for the grouping is extracted from the SAS dataset labels if `labelVars` is specified, or can be customized (`label` parameter).

For example, the adverse events are counted for different population set: screened population, completer population, only events with high severity, or related to the treatment and with high severity.

    # prepare the data: create grouping of interest
    dataAEGroup <- combineVariables(
        data = dataAEInterest,
        newVar = "AEGRP",
        paramsList = list(
            # for all screened patients
            list(var = "TRTA", value = "Xanomeline High Dose"),
            # for moderate severity
            list(var = "AESEV", value = "MODERATE", labelExtra = "Moderate"),
            list(var = "AENDY", label = paste("With adverse events ending date"))
        ),
        # include also counts for all records
        includeAll = TRUE,
        labelAll = "All Adverse events",
        labelVars = labelVars
    )
    labelVars["AEGRP"] <- "Patient groups of interest"

    # create the table
    getSummaryStatisticsTable(
        data = dataAEGroup,
        colVar = "TRTA",
        rowVar = "AEGRP",
        labelVars = labelVars,
        dataTotal = dataTotalAE,
        stats = list(expression(paste0(statN, " (", round(statPercN, 1), ")"))),
        title = "Table: Adverse events: counts for groups of interest",
        footer = "Statistics: n (%)"
    )

Table: Adverse events: counts for groups of interest
Patient groups of interest | Xanomeline Low Dose (N=2) | Xanomeline High Dose (N=3) |
--- | --- | --- | ---
All Adverse events | 2 (100) | 3 (100) | 0 (NA)
Actual Treatment | 0 (0) | 3 (100) | 0 (NA)
Severity/Intensity Moderate | 1 (50) | 3 (100) | 0 (NA)
With adverse events ending date | 2 (100) | 3 (100) | 0 (NA)
Statistics: n (%)

# 4 Appendix

## 4.1 Session information

R version 4.5.1 (2025-06-13) Platform: x86_64-pc-linux-gnu Running under: Ubuntu 24.04.2 LTS

Matrix products: default BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0

locale: [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=C LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C

time zone: Etc/UTC tzcode source: system (glibc)

attached base packages: [1] tools stats graphics grDevices utils datasets methods base

other attached packages: [1] clinUtils_0.2.0 inTextSummaryTable_3.3.5 knitr_1.50

loaded via a namespace (and not attached): [1] sass_0.4.10 fontLiberation_0.1.0 xml2_1.4.0 stringi_1.8.7 hms_1.1.3 digest_0.6.37
[7] magrittr_2.0.3 evaluate_1.0.5 grid_4.5.1 RColorBrewer_1.1-3 flextable_0.9.10 fastmap_1.2.0
[13] plyr_1.8.9 jsonlite_2.0.0 ggrepel_0.9.6 zip_2.3.3 crosstalk_1.2.2 viridisLite_0.4.2
[19] scales_1.4.0 fontBitstreamVera_0.1.1 textshaping_1.0.1 jquerylib_0.1.4 cli_3.6.5 rlang_1.1.6
[25] fontquiver_0.2.1 cowplot_1.2.0 cachem_1.1.0 yaml_2.3.10 gdtools_0.4.3 officer_0.6.10
[31] reshape2_1.4.4 uuid_1.2-1 ggplot2_4.0.0 DT_0.33 forcats_1.0.0 vctrs_0.6.5
[37] R6_2.6.1 lifecycle_1.0.4 stringr_1.5.1 htmlwidgets_1.6.4 ragg_1.4.0 pkgconfig_2.0.3
[43] bslib_0.9.0 pillar_1.11.0 gtable_0.3.6 data.table_1.17.8 glue_1.8.0 Rcpp_1.1.0
[49] systemfonts_1.2.3 haven_2.5.5 xfun_0.53 tibble_3.3.0 farver_2.1.2 htmltools_0.5.8.1
[55] rmarkdown_2.29 compiler_4.5.1 S7_0.2.0 askpass_1.2.1 openssl_2.3.3