Exporting in-text tables

library(knitr)
opts_chunk$set(
    echo = TRUE, results = 'markup', warning = FALSE, 
    # stop document execution if error (not the default)
    error = FALSE, 
    message = FALSE, cache = FALSE,
    fig.width = 8, fig.height = 7,
    fig.path = "./figures_vignette/",
    fig.align = 'center')
options(width = 170)
# instead of warn = 0 by default
# include warnings when they occur in the document
options(warn = 1)

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

In particular, we will cover

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 {#outputFormat}

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

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 (%)")
)

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

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:

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)

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)

Differences between the format

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

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:

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

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

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:

# 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

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

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

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:

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

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) 

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
)

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

# 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"
)

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)

# for specific AEDECOD
xTerm <- subset(x, AEDECOD == "MYOCARDIAL INFARCTION")
# identify the record for treated patient:
subset(xTerm, grepl("Placebo", TRTA))
# 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
# across all AE terms:
ddply(x, "AEDECOD", function(xTerm)
      if(subset(xTerm, grepl("Placebo", TRTA))$statPercN >= 20) xTerm
)

# format it as a function and pass it to the 'filterFct' parameter

Appendix

Session information

pander(sessionInfo())


Try the inTextSummaryTable package in your browser

Any scripts or data that you put into this service are public.

inTextSummaryTable documentation built on Sept. 12, 2023, 5:06 p.m.