1  Overview

1.1 Background

Submitting clinical trial results to regulatory agencies is a crucial aspect of clinical development. The Electronic Common Technical Document (eCTD) has emerged as the global standard format for regulatory submissions. For instance, the United States Food and Drug Administration (US FDA) mandates the use of eCTD for new drug applications and biologics license applications.

A CSR provides comprehensive information about the methods and results of an individual clinical study. To support the statistical analysis, numerous tables, listings, and figures are included within the main text and appendices. As part of the CDISC pilot project, an example CSR is also available for reference. If you seek additional examples of CSR, you can visit the clinical data website of the European Medicines Agency (EMA) clinical data website.

The creation of CSR is a collaborative effort that involves various professionals such as clinicians, medical writers, statisticians, statistical programmers. In this context, we will focus on the specific deliverables provided by statisticians and statistical programmers.

Within an organization, these professionals typically collaborate to define, develop, validate, and deliver the necessary tables, listings, and figures (TLFs) for a CSR. These TLFs serve to summarize the efficacy and/or safety of the pharmaceutical product under study. In the pharmaceutical industry, Microsoft Word is widely utilized for CSR preparation. As a result, the deliverables from statisticians and statistical programmers are commonly provided in formats such as .rtf, .doc, .docx to align with industry standards and requirements.

Our focus is to demonstrate the process of generating TLFs in RTF format, which is commonly employed in CSRs. The examples provided in this chapter adhere to the ICH E3 guidance and the FDA’s PDF Specifications.


FDA’s PDF specification is a general reference. Each organization can define more specific TLF format requirements that can be different from the examples in this book. The FDA’s PDF specification serves as a general reference for formatting requirements. Each organization has the flexibility to define its own specific requirements for TLFs. These specific format requirements may differ from the examples provided in this book. It is advisable to consult and adhere to the guidelines and specifications set by your respective organization when preparing TLFs for submission.

By following the ICH E3 guidance, most of TLFs in a CSR are located at

  • Section 10: Study participants
  • Section 11: Efficacy evaluation
  • Section 12: Safety evaluation
  • Section 14: Tables, listings, and figures referrals but not included in the text
  • Section 16: Appendices

1.2 Datasets

The dataset structure follows CDISC Analysis Data Model (ADaM).

In this project, we used publicly available CDISC pilot study data, which is accessible through the CDISC GitHub repository.

To streamline the process, we have downloaded all the datasets from the repository and stored them in the data-adam/ folder within this project. Additionally, we converted these datasets from the .xpt format to the .sas7bdat format for ease of use and compatibility. The dataset structure adheres to the CDISC Analysis Data Model (ADaM) standard.

1.3 Tools

To exemplify the generation of TLFs in RTF format, we rely on the functionality provided by two R packages:

  • tidyverse: preparation of datasets in a format suitable for reporting purposes. The tidyverse package offers a comprehensive suite of tools and functions for data manipulation and transformation, ensuring that the data is structured appropriately.
  • r2rtf: creation RTF files. The r2rtf package offers functions specifically designed for generating RTF files, allowing us to produce TLFs in the desired format.

There are indeed several other R packages available that can assist in creating TLFs in ASCII, RTF, and Word formats such as rtables, huxtable, pharmaRTF, gt, officer, and flextable. However, in this particular context, we will concentrate on demonstrating the concept using the r2rtf package. It is highly recommended for readers to explore and experiment with various R packages to identify the most suitable tools that align with their specific needs and objectives.

1.3.1 tidyverse

The tidyverse is a comprehensive collection of R packages that aim to simplify the workflow of manipulating, visualizing, and analyzing data in R. These packages adhere to the principles outlined in the the tidy tools manifesto and offer user-friendly interfaces for interactive data analysis.

The creators of the tidyverse, Posit, have provided exceptional cheatsheets and tutorials that serve as valuable resources for learning and mastering the functionalities of these packages.

Furthermore, there are several books available that serve as introductions to the tidyverse. For example:


In this book, we assume that the reader already has experience in using the tidyverse. This prior knowledge and familiarity with the tidyverse tools enable a more efficient and focused exploration of the concepts presented throughout the book.

1.3.2 r2rtf

r2rtf is an R package specifically designed to create production-ready tables and figures in RTF format.

  • Provide simple “verb” functions that correspond to each component of a table, to help you translate a data frame to a table in an RTF file.
  • Enable pipes (|>).
  • Focus on the table format only. Data manipulation and analysis tasks can be handled by other R packages like the tidyverse.

Before generating an RTF table using r2rtf, there are a few steps to follow:

  • Determine the desired layout of the table.
  • Break down the layout into smaller tasks, which can be programmed.
  • Execute the program to generate the table.

We provide a brief introduction of r2rtf and show how to transfer data frames into table, listing, and figures (TLFs).

We provide a concise introduction to r2rtf and demonstrate how to convert data frames into TLFs. For more comprehensive examples and additional features, we encourage readers to explore the r2rtf package website.

To illustrate the basic usage of the r2rtf package, we will work with the “r2rtf_adae” dataset, available within the r2rtf package. This dataset contains information on adverse events (AEs) from a clinical trial, which will serve as a practical example for generating RTF tables using r2rtf.

To begin, let’s load the required packages:

library(tidyverse) # Manipulate data
library(r2rtf) # Reporting in RTF format

In this example, we will focus on three variables from the r2rtf_adae dataset:

  • USUBJID: unique subject identifier.
  • TRTA: actual treatment group.
  • AEDECOD: dictionary-derived derm.

Additional information about these variables can be found on the help page of the dataset, which can be accessed by using the command ?r2rtf_adae in R.

r2rtf_adae |> select(USUBJID, TRTA, AEDECOD)
#>       USUBJID    TRTA                   AEDECOD
#> 1 01-701-1015 Placebo APPLICATION SITE ERYTHEMA
#> 2 01-701-1015 Placebo APPLICATION SITE PRURITUS
#> 3 01-701-1015 Placebo                 DIARRHOEA
#> 4 01-701-1023 Placebo                  ERYTHEMA
#> # ℹ 1187 more rows

To manipulate the data and create a data frame containing the necessary information for the RTF table, we can use the dplyr and tidyr packages within the tidyverse.

tbl <- r2rtf_adae %>%
  count(TRTA, AEDECOD) %>%
  pivot_wider(names_from = TRTA, values_from = n, values_fill = 0)

#> # A tibble: 242 × 4
#>   AEDECOD        Placebo `Xanomeline High Dose` `Xanomeline Low Dose`
#>   <chr>            <int>                  <int>                 <int>
#> 1 ABDOMINAL PAIN       1                      2                     3
#> 2 AGITATION            2                      1                     2
#> 3 ALOPECIA             1                      0                     0
#> 4 ANXIETY              2                      0                     4
#> # ℹ 238 more rows

Having prepared the dataset tbl, we can now proceed with constructing the final RTF table using the r2rtf package. The r2rtf package has various functions, each designed for a specific type of table layout. Some commonly used verbs include:

Functions provided by the r2rtf package are designed to work seamlessly with the pipe operator (|>). This allows for a more concise and readable code structure, enhancing the efficiency of table creation in RTF format. A full list of functions in the r2rtf package can be found in the package reference page.

Here is a minimal example that demonstrates how to combine functions using pipes to create an RTF table.

  • rtf_body() is used to define table body layout.
  • rtf_encode() transfers table layout information into RTF syntax.
  • write_rtf() save RTF encoding into a file with file extension .rtf.
tbl |>
  head() |>
  rtf_body() |>
  rtf_encode() |>

In the previous example, we may want to add more column space to the first column. We can achieve the goal by updating the col_rel_width argument in the rtf_body() function.

In the example below, the col_rel_width argument expects a vector with the same length as the number of columns in the table tbl. This vector defines the relative width of each column within a predetermined total column width. Here, the relative width is defined as 3:2:2:2 that allow us to allocate more space to specific columns.


Only the ratio of the col_rel_width values is considered. Therefore, using col_rel_width = c(6, 4, 4, 4) or col_rel_width = c(1.5, 1, 1, 1) would yield equivalent results, as they maintain the same ratio.

tbl |>
  head() |>
  rtf_body(col_rel_width = c(3, 2, 2, 2)) |>
  rtf_encode() |>

In the previous example, we encountered a misalignment issue with the column header. To address this, we can use the rtf_colheader() function to adjust column header width and provide more informative column headers.

Within the rtf_colheader() function, the colheader argument is used to specify the content of the column header. The columns are separated using the | symbol. In the following example, we define the column header as "Adverse Events | Placebo | Xanomeline High Dose | Xanomeline Low Dose", representing the four columns in the table:

tbl |>
  head() |>
    colheader = "Adverse Events | Placebo | Xanomeline High Dose | Xanomeline Low Dose",
    col_rel_width = c(3, 2, 2, 2)
  ) |>
  rtf_body(col_rel_width = c(3, 2, 2, 2)) |>
  rtf_encode() %>%

In rtf_body() and rtf_colheader(), the text_justification argument is used to align text within the generated RTF table. The default value is "c", representing center justification. However, you can customize the text justification by column using a character vector with a length equal to the number of displayed columns. Here is a table displaying the possible inputs for the text_justification argument:

type name
l left
c center
r right
d decimal
j justified

Below is an example to make the first column left-aligned and the rest columns center-aligned.

tbl |>
  head() |>
  rtf_body(text_justification = c("l", "c", "c", "c")) |>
  rtf_encode() |>

The border_left, border_right, border_top, and border_bottom arguments in the rtf_body() and rtf_colheader() functions are used to control the cell borders in the RTF table. If we want to remove the top border of "Adverse Events" in the header, we can change the default value "single" to "" in the border_top argument. Below is an example to demonstrate the possibility of adding multiple column headers with proper border lines.


the r2rtf package supports 26 different border types, each offering unique border styles. For more details and examples regarding these border types, you can refer to the r2rtf package website.

tbl |>
  head() |>
    colheader = " | Treatment",
    col_rel_width = c(3, 6)
  ) |>
    colheader = "Adverse Events | Placebo | Xanomeline High Dose | Xanomeline Low Dose",
    border_top = c("", "single", "single", "single"),
    col_rel_width = c(3, 2, 2, 2)
  ) |>
  rtf_body(col_rel_width = c(3, 2, 2, 2)) %>%
  rtf_encode() |>

The r2rtf R package website provides additional examples that demonstrate how to customize various aspects of the generated RTF tables. These examples cover topics such as customizing the title, subtitle, footnote, data source, and handling special characters within the table content.

In the upcoming chapters of this book, we will introduce and explore these features as they become relevant to the specific use cases and scenarios discussed. By following along with the chapters, readers will gradually learn how to leverage these features to customize and enhance their RTF tables in real examples.