Exporting in-text tables

In this vignette we focus on exporting tables created with the inTextSummaryTable package.

In particular, we will cover

  • how to export tables for specific formats as Word/Powerpoint/Html/R object
  • how to make your custom aesthetics
  • how to save tables into separated documents
  • how to set specific text formatting (e.g. superscripts/subscripts)
  • how to create multiple tables at once based on a variable of interest
  • how to create a listing
  • how to filter and split exported tables

We assume you are already familiar on how to create tables, otherwise we advise to first check out the dedicated vignette on how to make tables, available here) or accessible with the commands below.

vignette("inTextSummaryTable-createTables", "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.

Load packages and data

library(inTextSummaryTable)
library(clinUtils)
library(pander)
library(tools) # toTitleCase
# load example data
data(dataADaMCDISCP01)

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

This section creates example data sets used below.

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 

Output formats

The default exported format is flextable, which is suitable for Word/PowerPoint documents.

Alternatively, a table can be exported as datatable interactive table for html reports, or as a data frame in R.

The outputType parameter specifies the output format of the summary statistics table.

Static table for Word/Powerpoint

General format

To get the table in a format suitable for Word/Powerpoint documents, the outputType parameter should be set to ‘flextable’ (the default).

summaryTableFt <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects in the data; n = number of subjects with observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    outputType = "flextable"
)
class(summaryTableFt)
## [1] "flextable"
summaryTableFt

Table: Adverse Events by System Organ Class and Preferred Term

TEAE by SOC and Preferred Term
n (%)

Xanomeline Low Dose
(N=2)

Xanomeline High Dose
(N=3)

Dictionary-Derived Term

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

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

LOWER RESPIRATORY TRACT INFECTION

0

1 (33.3)

PNEUMONIA

1 (50.0)

0

N = number of subjects in the data; n = number of subjects with observation

Denominator for percentage calculations is the total number of subjects per treatment group in the safety population

The object summaryTableFt is a flextable object.

This is available through the flextable R package (see ?flextable).

When printed into the R console, a flextable object is displayed in the internet browser. However, the summaryTableFt object can be inserted within a rmarkdown document by printing it in the specified document chunk, providing that the following system requirement are satisfied:

A rmarkdown chunk can contains only one flextable object. To include a list of flextable in a rmarkdown document, the function knitPrintListObjects of the clinUtils package can be used.

Style: report or presentation

The table can be styled via the style parameter. This parameter affects the fontsize, font family, color of the text and background, dimensions of the table.

Other specific parameters can be used to export the table as landscape (landscape), specify custom margins (margin), row indent (rowVarPadBase), font size and family (fontsize and font).

By default, the table is styled for a CSR report.

getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects with data; n = number of subjects with this observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)")
)

Table: Adverse Events by System Organ Class and Preferred Term

TEAE by SOC and Preferred Term
n (%)

Xanomeline Low Dose
(N=2)

Xanomeline High Dose
(N=3)

Dictionary-Derived Term

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

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

LOWER RESPIRATORY TRACT INFECTION

0

1 (33.3)

PNEUMONIA

1 (50.0)

0

N = number of subjects with data; n = number of subjects with this observation

Denominator for percentage calculations is the total number of subjects per treatment group in the safety population

The table can also be styled for a presentation.

Note that the default dimension of a table printed in a Powerpoint document follows the standard 4:3 size (7.5 x 10 inches).

If you wish to set the dimension for a Widescreen document, it is possible to set a global option for this. Please, check out the section “Custom aesthetics”.

getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects with data; n = number of subjects with this observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    style = "presentation"
)

Table: Adverse Events by System Organ Class and Preferred Term

TEAE by SOC and Preferred Term
n (%)

Xanomeline Low Dose
(N=2)

Xanomeline High Dose
(N=3)

Dictionary-Derived Term

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

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

LOWER RESPIRATORY TRACT INFECTION

0

1 (33.3)

PNEUMONIA

1 (50.0)

0

N = number of subjects with data; n = number of subjects with this observation

Denominator for percentage calculations is the total number of subjects per treatment group in the safety population

Interactive table for html

The summary statistics table is exported as an interactive table by setting the parameter: outputType to ‘DT’.

A datatable object, created with the DT R package is created.

Interactivity includes the functionalities to:

  • filter the table
  • order columns
  • export the table (or a subset of this)
  • include custom interactivity e.g. the possibility to have expandable rows/columns, see patient profiles inclusion in the medical monitoring report

Such table can be included in a html rmarkdown report.

The interactive table can be further customized by setting options specific to this output (see clinUtils::getClinDT).

Please note that the interactive table is only created if Pandoc is available.

getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects in the data; n = number of subjects with observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    outputType = "DT",
    ## DT-specific options
    buttons = c() # remove all export buttons
)

Data frames for R

The summary statistics table can be stored as a R object.

Note that the exported data.frames contains attributes that indicate which statistics are used, which row variables/column variables are to be shown and how etc.

Final table

The summary statistics data displayed in the final table object can be exported as an R data.frame.

In this case the outputType should be set to data.frame.

summaryTable <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects in the data; n = number of subjects with observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    style = "presentation",
    outputType = "data.frame"
)
pander(summaryTable, split.table = Inf)
AESOC AEDECOD Xanomeline Low Dose (N=2) Xanomeline High Dose (N=3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE DERMATITIS 0 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE ERYTHEMA 2 (100) 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE IRRITATION 1 (50.0) 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE PRURITUS 2 (100) 2 (66.7)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS FATIGUE 0 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SECRETION DISCHARGE 1 (50.0) 0
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SUDDEN DEATH 1 (50.0) 0
INFECTIONS AND INFESTATIONS LOWER RESPIRATORY TRACT INFECTION 0 1 (33.3)
INFECTIONS AND INFESTATIONS PNEUMONIA 1 (50.0) 0

Full table in long format

The table with all the computed summary statistics, the specified set of statistics of interest and all row/column variables stored in a long format is available by using the outputType parameter to ‘data.frame-base’.

This format is typically of interest to run quality checks of the computed summary statistics in comparison with e.g. Table/Listing/Figures, or to compare the statistics computed between batches of the data.

summaryTableAll <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term",
    footer = c(
        "N = number of subjects in the data; n = number of subjects with observation",
        paste("Denominator for percentage calculations is the total number of subjects",
            "per treatment group in the safety population"
        )
    ),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    style = "presentation",
    outputType = "data.frame-base"
)
pander(summaryTableAll, split.table = Inf)
AESOC AEDECOD TRTA isTotal statN statm statPercTotalN statPercN n (%)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE DERMATITIS Xanomeline Low Dose FALSE 0 0 2 0 0
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE ERYTHEMA Xanomeline Low Dose FALSE 2 2 2 100 2 (100)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE IRRITATION Xanomeline Low Dose FALSE 1 2 2 50 1 (50.0)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE PRURITUS Xanomeline Low Dose FALSE 2 2 2 100 2 (100)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS FATIGUE Xanomeline Low Dose FALSE 0 0 2 0 0
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SECRETION DISCHARGE Xanomeline Low Dose FALSE 1 2 2 50 1 (50.0)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SUDDEN DEATH Xanomeline Low Dose FALSE 1 1 2 50 1 (50.0)
INFECTIONS AND INFESTATIONS LOWER RESPIRATORY TRACT INFECTION Xanomeline Low Dose FALSE 0 0 2 0 0
INFECTIONS AND INFESTATIONS PNEUMONIA Xanomeline Low Dose FALSE 1 2 2 50 1 (50.0)
NA NA Xanomeline Low Dose TRUE 2 2 2 100 2 (100)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE DERMATITIS Xanomeline High Dose FALSE 1 2 3 33.33 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE ERYTHEMA Xanomeline High Dose FALSE 1 1 3 33.33 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE IRRITATION Xanomeline High Dose FALSE 1 2 3 33.33 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE PRURITUS Xanomeline High Dose FALSE 2 3 3 66.67 2 (66.7)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS FATIGUE Xanomeline High Dose FALSE 1 1 3 33.33 1 (33.3)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SECRETION DISCHARGE Xanomeline High Dose FALSE 0 0 3 0 0
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS SUDDEN DEATH Xanomeline High Dose FALSE 0 0 3 0 0
INFECTIONS AND INFESTATIONS LOWER RESPIRATORY TRACT INFECTION Xanomeline High Dose FALSE 1 2 3 33.33 1 (33.3)
INFECTIONS AND INFESTATIONS PNEUMONIA Xanomeline High Dose FALSE 0 0 3 0 0
NA NA Xanomeline High Dose TRUE 3 3 3 100 3 (100)

Differences between the format

Most of the functionalities and default parameters are the same between the flextable and DT format, at the exception of:

  • for the DT format, by default the variables and statistics are included in different columns: rowVarInSepCol is rowVar and statsLayout is set to ‘col’
  • for the flextable format, by default the row variables and statistics are nested: rowVarInSepCol is set to: ‘NULL’ and the statsLayout is set to ‘row’

Custom aesthetics

The inTextSummaryTable contains functionalities to set the aesthetics of the tables.

Those aesthetics are set through global options.

This has the main advantage that if you wish to change the default color scheme, it is possible to set your preferences only once at the beginning of the R script or Rmd document.

When loading the package, the global options for palettes get automatically defined into the R session. If you wish to change the default colors, you can apply your preferences by changing the global options.

The inTextSummaryTable package has the following options for table aesthetics:

  • inTextSummaryTable.colors.table.presentation

  • inTextSummaryTable.pageDim.presentation

The first option sets custom colors for a table in a presentation mode, the last one defines the page dimension of a Powerpoint when exporting a table.

Note that the options have to be defined after loading the package. This because when loading the package, the default global options for palettes will overwrite the custom palettes.

Colors

As you may have already noticed if you have read the vignette till here, by default, the reporting format makes tables with a black text on a white background. On the contrary, the presentation format creates tables with a blue header and white text, whereas the body is grey with black text.

If you wish to define a personal color scheme, a named vector can be created and passed to the options, as shown below.

Colors can be provided in hexadecimals or in rgb specification. In the example we use hexadecimals just for convenience.

Note that the bodyBackground1 and bodyBackground2 allow to have alternating row colors.

# create named vector
customColorTable <- c(
    # black text in the header
    'header' = "#000000",
    # green background in the header
    'headerBackground' = "#74D055FF",
    # black text in the body
    'body' = "#000000", 
    # yellow background for all rows
    'bodyBackground1' = "#FDE725FF",
    'bodyBackground2' = "#FDE725FF",
    # black footer
    'footer' = "#000000",
    # white footer background
    'footerBackground' = "#FFFFFF",
    # black line for footer
    'line' = "#000000"
)
# set options
options(inTextSummaryTable.colors.table.presentation = customColorTable)
# create the table on a dummy data set
getSummaryStatisticsTable(
    data = data.frame(USUBJID = c(1, 2)),
    style = "presentation" 
)

Statistic

StatisticValue
(N=2)

statN

2

statm

2

statPercTotalN

2

statPercN

100

Dimension of the page

By default, the inTextSummaryTable ships with a default PowerPoint in the standard 4:3 size (7.5 x 10 inches).

However, it is often common to create a PowerPoint template with Widescreen size of 16:9 which consistts of 7.50 x 13.32 inches.

Therefore, it possible to accomodate such widescreen size by providing

# set custom dimension of page for presentation
# in this example, the dimension is the widescreen size
pageDimCustom <- c(7.5, 13.32)
options(inTextSummaryTable.pageDim.presentation = pageDimCustom)
getOption("inTextSummaryTable.pageDim.presentation")
## [1]  7.50 13.32

Further info on asthetics

For further information about the aesthetics settings of the package, a dedicated vignette is available at

vignette("inTextSummaryTable-aesthetics", "inTextSummaryTable")

Set back default palettes

There is always to possibility to switch back to the default palettes of the package:

options(inTextSummaryTable.colors.table.presentation = tableColorsPresentation)

Export table to a separated file

The table can be exported to a different file by specifying a file name in the file parameter.

Possible formats are:

  • txt: the raw base table is exported to a text file. This format can be used e.g. to run quality checks with reference Table/Listings/Figures.
  • docx: the formatted table is exported to a Word document. Such format is typically of interest to share the tables to medical writers, to be imported directly into a Statistical Analysis Plan (if style = 'report').
  • html: an interactive table is exported to the specified html file
# export table to a Word document
summaryTableFt <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    file = file.path("tables_CSR", "summaryTable-AEs.docx")
)

# export interactive table to a html document
summaryTableFt <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    file = file.path("tables_CSR", "summaryTable-AEs.html")
)

# export table in raw format to a text file
summaryTableFt <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    file = file.path("tables_CSR", "summaryTable-AEs.txt")
)

# export to multiple formats at once
summaryTableFt <- getSummaryStatisticsTable(
    data = dataAEInterest,
    rowVar = c("AESOC", "AEDECOD"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    dataTotal = dataTotalAE,
    labelVars = labelVars,
    file = file.path("tables_CSR",
        c("summaryTable.txt", "summaryTable.docx", "summaryTable.html")
    )
)

Export table of pre-computed summary statistics

To create a table in a similar format as the in-text tables created by the package, from pre-computed summary statistics (e.g. from CRO or from a different software as SAS) the function exportSummaryStatisticsTable can be used.

This function takes as input a data.frame in long format that should contain the summary statistics.

The long format should be such that the

  • statistic value (statsVar)
  • statistic type (if multiple), grouping row and columns (rowVar and colVar)

are both stored as different columns in the data.frame.

If the column headers should contain total number of subjects, the corresponding counts should be stored in records with the column isTotal set to TRUE.

dataDIABP <- subset(
    dataAll$ADVS, 
    SAFFL == "Y" & ANL01FL == "Y" &
    PARAMCD == "DIABP" & 
    AVISIT %in% c("Baseline", "Week 6") &
    ATPT == "AFTER LYING DOWN FOR 5 MINUTES"
)

# create example of data.frame containing statistics of interest
statsEff <- sapply(c("AVAL", "CHG"), function(var) {
      
      getStats(
          type = c("n", "mean (se)", "median (range)"),
          x = dataDIABP[[var]]
      )
      
    }, simplify = FALSE)

summaryTable <- computeSummaryStatisticsTable(
    data = dataDIABP,
    colVar = c("TRTP", "AVISIT"),
    var = c("AVAL", "CHG"), varGeneralLab = "",
    stats = statsEff,
    labelVars = labelVars
)

# format df with statistics to in-text table format
export(
    summaryTable = summaryTable,
    statsVar = c("n", "Mean (SE)", "Median (range)"),
    rowVar = "variable", rowVarLab = "Statistic",
    colVar = c("TRTP", "AVISIT"),
    colHeaderTotalInclude = TRUE,
    labelVars = simpleCap(tolower(labelVars[c("AVAL", "CHG")])),
    title = toTitleCase(
        "Table: Diastolic Blood Pressure (mmHg) statistics"
    )
)

Table: Diastolic Blood Pressure (mmHg) Statistics

Placebo

Xanomeline High Dose

Xanomeline Low Dose

Baseline
(N=2)

Week 6
(N=1)

Baseline
(N=3)

Week 6
(N=3)

Baseline
(N=2)

Week 6
(N=2)

Analysis Value

n

2

1

3

3

2

2

Mean (SE)

71.0 (1.00)

70.0 ( NA)

68.3 (6.69)

72.0 (10.02)

74.0 (10.00)

65.0 (5.00)

Median (range)

71.0 (70,72)

70.0 (70,70)

70.0 (56,79)

76.0 (53,87)

74.0 (64,84)

65.0 (60,70)

Change from Baseline

n

2

1

3

3

2

2

Mean (SE)

0.0 (0.00)

-2.0 ( NA)

0.0 (0.00)

3.7 (3.38)

0.0 (0.00)

-9.0 (5.00)

Median (range)

0.0 (0,0)

-2.0 (-2,-2)

0.0 (0,0)

6.0 (-3,8)

0.0 (0,0)

-9.0 (-14,-4)

Text formatting

Specific formatted text can be specified for the flextable output type only.

Superscript/subscript

Superscript and subscript are specified via the special text pattern as a^{b} and a_{b} respectively.

To use a superscript or a subscript in the table, the text should be formatted as: text^{superscript} or text_{subscript}.

This is for example useful to reference additional informations in a specific footnote or specify custom variable labels.

dataSL <- subset(dataAll$ADSL, SAFFL == "Y")

varsSL <- c("AGE", "WEIGHTBL", "BMIBL")
labelVars[varsSL] <- c(
    "Age",
    "Weight_{t}",
    "BMI (kg/m^{2})"
)

getSummaryStatisticsTable(
    data = dataSL, 
    var = varsSL,  
    stats = getStats("n (%"),
    labelVars = labelVars,
    fontsize = 16,
    title = toTitleCase("Demographic data (Safety Analysis Set)")
)

Demographic Data (Safety Analysis Set)

Variable

n (%)
(N=7)

Age

7 (100)

Weightt

7 (100)

BMI (kg/m2)

7 (100)

Bold and greek letters

Specific cells of the table can be highlight in bold by using the syntax: bold{} in the stats or statsExtra function.

This highlighting may depend:

  • on a additional variable via the statsExtra parameter:
    for example: statsExtra <- function(data) with(data, ifelse(ANRIND != "N", paste0("bold{", toString(AVAL), "}"), toString(AVAL))
  • on the values of computed statistics, via the stats parameter

Greek letters are included as they are in the table.

getSummaryStatisticsTable(
    data = dataSL, 
    var = varsSL,  
    stats = list(
        expression(paste0(
            ifelse(statMean > statMedian, 
                paste0("bold{", roundHalfUpTextFormat(statMean, 1), "}"), 
                roundHalfUpTextFormat(statMean, 1)
            ), 
            "\n(", 
                roundHalfUpTextFormat(statSE, 2),")")
        )
    ),
    labelVars = labelVars,
    fontsize = 12,
    title = toTitleCase("Demographic data (Safety Analysis Set)")
)

Demographic Data (Safety Analysis Set)

Variable

StatisticValue
(N=7)

Age

74.3
(3.71)

Weightt

62.0
(5.68)

BMI (kg/m2)

23.4
(1.71)

Create multiple tables by a variable

Multiple tables can be created for each element of a variable in the dataset by specifying the name of the variable in the argument byVar.

A list of final summary table can be included into a rmarkdown document with the knitPrintListObjects.

Please note that the following chunk option should be used: results = 'asis'.

For example, AE tables are created for each treatment:

summaryTableList <- getSummaryStatisticsTable(
    data = subset(dataAE, TRTEMFL == "Y"),
    rowVar = c("AESOC", "AEDECOD"),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    colVar = "TRTA",
    byVar = "TRTA",
    stats = getStats("n (%)"),
    labelVars = labelVars,
    title = "Table: Treatment-Emergent adverse events"
)

# print the list of tables in the rmarkdown document
clinUtils::knitPrintListObjects(summaryTableList) 

Table: Treatment-Emergent adverse events

Actual Treatment: Placebo

TEAE by SOC and Preferred Term
n (%)

Placebo
(N=2)

Dictionary-Derived Term

CARDIAC DISORDERS

MYOCARDIAL INFARCTION

1 (50.0)

PSYCHIATRIC DISORDERS

COMPLETED SUICIDE

1 (50.0)

Table: Treatment-Emergent adverse events

Actual Treatment: Xanomeline High Dose

TEAE by SOC and Preferred Term
n (%)

Xanomeline High Dose
(N=3)

Dictionary-Derived Term

GASTROINTESTINAL DISORDERS

NAUSEA

2 (66.7)

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

APPLICATION SITE DERMATITIS

1 (33.3)

APPLICATION SITE ERYTHEMA

1 (33.3)

APPLICATION SITE IRRITATION

1 (33.3)

APPLICATION SITE PRURITUS

2 (66.7)

FATIGUE

1 (33.3)

INFECTIONS AND INFESTATIONS

LOWER RESPIRATORY TRACT INFECTION

1 (33.3)

METABOLISM AND NUTRITION DISORDERS

DECREASED APPETITE

1 (33.3)

MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS

BACK PAIN

1 (33.3)

FLANK PAIN

1 (33.3)

NERVOUS SYSTEM DISORDERS

AMNESIA

1 (33.3)

LETHARGY

1 (33.3)

PARTIAL SEIZURES WITH SECONDARY GENERALISATION

1 (33.3)

PSYCHIATRIC DISORDERS

HALLUCINATION, VISUAL

1 (33.3)

RENAL AND URINARY DISORDERS

CALCULUS URETHRAL

1 (33.3)

RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS

EPISTAXIS

1 (33.3)

SKIN AND SUBCUTANEOUS TISSUE DISORDERS

ACTINIC KERATOSIS

1 (33.3)

Table: Treatment-Emergent adverse events

Actual Treatment: Xanomeline Low Dose

TEAE by SOC and Preferred Term
n (%)

Xanomeline Low Dose
(N=2)

Dictionary-Derived Term

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

APPLICATION SITE ERYTHEMA

2 (100)

APPLICATION SITE IRRITATION

1 (50.0)

APPLICATION SITE PRURITUS

2 (100)

SECRETION DISCHARGE

1 (50.0)

SUDDEN DEATH

1 (50.0)

INFECTIONS AND INFESTATIONS

PNEUMONIA

1 (50.0)

INJURY, POISONING AND PROCEDURAL COMPLICATIONS

JOINT DISLOCATION

1 (50.0)

SKIN LACERATION

1 (50.0)

INVESTIGATIONS

NASAL MUCOSA BIOPSY

1 (50.0)

MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS

MUSCULAR WEAKNESS

1 (50.0)

SHOULDER PAIN

1 (50.0)

PSYCHIATRIC DISORDERS

CONFUSIONAL STATE

1 (50.0)

RENAL AND URINARY DISORDERS

INCONTINENCE

1 (50.0)

RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS

DYSPNOEA

1 (50.0)

SKIN AND SUBCUTANEOUS TISSUE DISORDERS

ERYTHEMA

1 (50.0)

Listing

Listing in a similar format as the in-text summary table is created via the getListing function.

varsListing <- c(
    "USUBJID", "AEBODSYS", "AEDECOD", "TRTA", 
    "AESEV", "AESER", "ASTDY", "AENDY"
)

dataListing <- subset(dataAE, TRTEMFL == "Y" & AESEV == "SEVERE")
dataListing <- dataListing[, varsListing]
colnames(dataListing) <- getLabelVar(var = varsListing, labelVars = labelVars)

getListing(
    data = dataListing, 
    title = "Listing of treatment-emergent severe adverse events",
    includeRownames = FALSE
)

Listing of treatment-emergent severe adverse events

Unique Subject Identifier

Body System or Organ Class

Dictionary-Derived Term

Actual Treatment

Severity/Intensity

Serious Event

Analysis Start Relative Day

Analysis End Relative Day

01-701-1211

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

SUDDEN DEATH

Xanomeline Low Dose

SEVERE

N

61

61

01-704-1445

PSYCHIATRIC DISORDERS

COMPLETED SUICIDE

Placebo

SEVERE

N

174

174

01-710-1083

CARDIAC DISORDERS

MYOCARDIAL INFARCTION

Placebo

SEVERE

N

12

12

01-718-1371

NERVOUS SYSTEM DISORDERS

PARTIAL SEIZURES WITH SECONDARY GENERALISATION

Xanomeline High Dose

SEVERE

Y

38

41

01-718-1427

GASTROINTESTINAL DISORDERS

NAUSEA

Xanomeline High Dose

SEVERE

N

36

39

Filter records in a table

If only a subset of the records should be displayed in the final table, a custom filtering functions is specified via the filterFct parameter.

library(plyr)

# SOC with AE terms with at least 2 subjects
getSummaryStatisticsTable(
    data = subset(dataAE, TRTEMFL == "Y"),
    rowVar = c("AESOC", "AEDECOD"),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    filterFct = function(x)
      ddply(x, "AESOC", function(y)
            if(any(y$statN >= 2))   y           
      ),
    labelVars = labelVars,
    title = paste(
        "Table: Adverse Events by System Organ Class and",
        "Preferred Term with at least 2 patients in System Organ Class"
    )
)

Table: Adverse Events by System Organ Class and Preferred Term with at least 2 patients in System Organ Class

TEAE by SOC and Preferred Term
n (%)

Placebo
(N=2)

Xanomeline High Dose
(N=3)

Xanomeline Low Dose
(N=2)

Dictionary-Derived Term

GASTROINTESTINAL DISORDERS

NAUSEA

0

2 (66.7)

0

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

APPLICATION SITE DERMATITIS

0

1 (33.3)

0

APPLICATION SITE ERYTHEMA

0

1 (33.3)

2 (100)

APPLICATION SITE IRRITATION

0

1 (33.3)

1 (50.0)

APPLICATION SITE PRURITUS

0

2 (66.7)

2 (100)

FATIGUE

0

1 (33.3)

0

SECRETION DISCHARGE

0

0

1 (50.0)

SUDDEN DEATH

0

0

1 (50.0)

# AE term with at least one term with more than 70% in the treatment
getSummaryStatisticsTable(
    data = subset(dataAE, TRTEMFL == "Y"),
    rowVar = c("AESOC", "AEDECOD"),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    filterFct = function(x)
      ddply(x, "AEDECOD", function(xTerm) {
            if(any(xTerm$statPercN >= 70))  xTerm       
          }),
    labelVars = labelVars,
    title = "Table: Adverse Events by System Organ Class and Preferred Term with at least 70% patients"
)

Table: Adverse Events by System Organ Class and Preferred Term with at least 70% patients

TEAE by SOC and Preferred Term
n (%)

Placebo
(N=2)

Xanomeline High Dose
(N=3)

Xanomeline Low Dose
(N=2)

Dictionary-Derived Term

GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS

APPLICATION SITE ERYTHEMA

0

1 (33.3)

2 (100)

APPLICATION SITE PRURITUS

0

2 (66.7)

2 (100)

Note: to help the creation of this filtering function, the displaying data could be extracted first via the computeSummaryStatisticsTable function (instead of creating directly the in-text table via the getSummaryStatisticsTable), and then used to define the filterFct parameter.

x <- computeSummaryStatisticsTable(
    data = subset(dataAE, TRTEMFL == "Y"),
    rowVar = c("AESOC", "AEDECOD"),
    rowVarLab = c('AESOC' = "TEAE by SOC and Preferred Term\nn (%)"),
    colVar = "TRTA",
    stats = getStats("n (%)"),
    labelVars = labelVars
)
head(x)
##                                                  AESOC                     AEDECOD    TRTA isTotal statN statm statPercTotalN statPercN    n (%)
## 1                                    CARDIAC DISORDERS       MYOCARDIAL INFARCTION Placebo   FALSE     1     1              2        50 1 (50.0)
## 2                           GASTROINTESTINAL DISORDERS                      NAUSEA Placebo   FALSE     0     0              2         0        0
## 3 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE DERMATITIS Placebo   FALSE     0     0              2         0        0
## 4 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS   APPLICATION SITE ERYTHEMA Placebo   FALSE     0     0              2         0        0
## 5 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS APPLICATION SITE IRRITATION Placebo   FALSE     0     0              2         0        0
## 6 GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS   APPLICATION SITE PRURITUS Placebo   FALSE     0     0              2         0        0
# for specific AEDECOD
xTerm <- subset(x, AEDECOD == "MYOCARDIAL INFARCTION")
# identify the record for treated patient:
subset(xTerm, grepl("Placebo", TRTA))
##               AESOC               AEDECOD    TRTA isTotal statN statm statPercTotalN statPercN    n (%)
## 1 CARDIAC DISORDERS MYOCARDIAL INFARCTION Placebo   FALSE     1     1              2        50 1 (50.0)
# keep all records (placebo + treatment) if percentage if higher than 20%:
# if no 'else' condition, nothing (NULL) is returned:
if(subset(xTerm, grepl("Placebo", TRTA))$statPercN >= 20)   xTerm
##                AESOC               AEDECOD                 TRTA isTotal statN statm statPercTotalN statPercN    n (%)
## 1  CARDIAC DISORDERS MYOCARDIAL INFARCTION              Placebo   FALSE     1     1              2        50 1 (50.0)
## 33 CARDIAC DISORDERS MYOCARDIAL INFARCTION Xanomeline High Dose   FALSE     0     0              3         0        0
## 65 CARDIAC DISORDERS MYOCARDIAL INFARCTION  Xanomeline Low Dose   FALSE     0     0              2         0        0
# across all AE terms:
ddply(x, "AEDECOD", function(xTerm)
      if(subset(xTerm, grepl("Placebo", TRTA))$statPercN >= 20) xTerm
)
##                   AESOC               AEDECOD                 TRTA isTotal statN statm statPercTotalN statPercN    n (%)
## 1 PSYCHIATRIC DISORDERS     COMPLETED SUICIDE              Placebo   FALSE     1     1              2        50 1 (50.0)
## 2 PSYCHIATRIC DISORDERS     COMPLETED SUICIDE Xanomeline High Dose   FALSE     0     0              3         0        0
## 3 PSYCHIATRIC DISORDERS     COMPLETED SUICIDE  Xanomeline Low Dose   FALSE     0     0              2         0        0
## 4     CARDIAC DISORDERS MYOCARDIAL INFARCTION              Placebo   FALSE     1     1              2        50 1 (50.0)
## 5     CARDIAC DISORDERS MYOCARDIAL INFARCTION Xanomeline High Dose   FALSE     0     0              3         0        0
## 6     CARDIAC DISORDERS MYOCARDIAL INFARCTION  Xanomeline Low Dose   FALSE     0     0              2         0        0
## 7                  <NA>                  <NA>              Placebo    TRUE     2     2              2       100  2 (100)
## 8                  <NA>                  <NA> Xanomeline High Dose    TRUE     3    30              3       100  3 (100)
## 9                  <NA>                  <NA>  Xanomeline Low Dose    TRUE     2    22              2       100  2 (100)
# format it as a function and pass it to the 'filterFct' parameter

Appendix

Session information

R version 4.4.2 (2024-10-31)

Platform: x86_64-pc-linux-gnu

locale: 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, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C

attached base packages: tools, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: plyr(v.1.8.9), pander(v.0.6.5), clinUtils(v.0.2.0), inTextSummaryTable(v.3.3.3), knitr(v.1.49) and rmarkdown(v.2.29)

loaded via a namespace (and not attached): gtable(v.0.3.6), xfun(v.0.49), bslib(v.0.8.0), ggplot2(v.3.5.1), htmlwidgets(v.1.6.4), ggrepel(v.0.9.6), vctrs(v.0.6.5), crosstalk(v.1.2.1), generics(v.0.1.3), tibble(v.3.2.1), fansi(v.1.0.6), pkgconfig(v.2.0.3), data.table(v.1.16.2), uuid(v.1.2-1), lifecycle(v.1.0.4), flextable(v.0.9.7), farver(v.2.1.2), compiler(v.4.4.2), stringr(v.1.5.1), textshaping(v.0.4.0), munsell(v.0.5.1), fontquiver(v.0.2.1), fontLiberation(v.0.1.0), htmltools(v.0.5.8.1), sys(v.3.4.3), buildtools(v.1.0.0), sass(v.0.4.9), yaml(v.2.3.10), pillar(v.1.9.0), jquerylib(v.0.1.4), openssl(v.2.2.2), DT(v.0.33), cachem(v.1.1.0), fontBitstreamVera(v.0.1.1), tidyselect(v.1.2.1), zip(v.2.3.1), digest(v.0.6.37), stringi(v.1.8.4), dplyr(v.1.1.4), reshape2(v.1.4.4), maketools(v.1.3.1), labeling(v.0.4.3), forcats(v.1.0.0), cowplot(v.1.1.3), fastmap(v.1.2.0), grid(v.4.4.2), colorspace(v.2.1-1), cli(v.3.6.3), magrittr(v.2.0.3), utf8(v.1.2.4), withr(v.3.0.2), gdtools(v.0.4.1), scales(v.1.3.0), officer(v.0.6.7), askpass(v.1.2.1), ragg(v.1.3.3), hms(v.1.1.3), evaluate(v.1.0.1), haven(v.2.5.4), viridisLite(v.0.4.2), rlang(v.1.1.4), Rcpp(v.1.0.13-1), glue(v.1.8.0), xml2(v.1.3.6), jsonlite(v.1.8.9), R6(v.2.5.1) and systemfonts(v.1.1.0)