-
Notifications
You must be signed in to change notification settings - Fork 33
/
tlf-overview.qmd
372 lines (304 loc) · 14.9 KB
/
tlf-overview.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# Overview {#tlf-overview}
```{r, include=FALSE}
source("_common.R")
```
## Background
Submitting clinical trial results to regulatory agencies is a crucial aspect
of clinical development.
The [Electronic Common Technical Document (eCTD)](https://en.wikipedia.org/wiki/Electronic_common_technical_document)
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](https://www.fda.gov/drugs/electronic-regulatory-submission-and-review/electronic-common-technical-document-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](https://github.com/cdisc-org/sdtm-adam-pilot-project/blob/master/updated-pilot-submission-package/900172/m5/53-clin-stud-rep/535-rep-effic-safety-stud/5351-stud-rep-contr/cdiscpilot01/cdiscpilot01.pdf)
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](https://clinicaldata.ema.europa.eu/web/cdp/home).
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](https://database.ich.org/sites/default/files/E3_Guideline.pdf)
and the [FDA's PDF Specifications](https://www.fda.gov/media/76797/download).
::: {.callout-note}
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
## Datasets
The dataset structure follows
[CDISC Analysis Data Model (ADaM)](https://www.cdisc.org/standards/foundational/adam).
In this project, we used publicly available CDISC pilot study data, which is
accessible through the
[CDISC GitHub repository](https://github.com/cdisc-org/sdtm-adam-pilot-project/tree/master/updated-pilot-submission-package/900172/m5/datasets/cdiscpilot01/analysis/adam/datasets).
To streamline the process, we have downloaded all the datasets from the
repository and stored them in the
[`data-adam/` folder](https://github.com/elong0527/r4csr/tree/main/data-adam)
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)](https://www.cdisc.org/standards/foundational/adam)
standard.
## Tools
To exemplify the generation of TLFs in RTF format, we rely on the functionality
provided by two R packages:
- [tidyverse](https://www.tidyverse.org/): 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](https://merck.github.io/r2rtf/): creation RTF files.
The r2rtf package offers functions specifically designed for generating
RTF files, allowing us to produce TLFs in the desired format.
::: {.callout-note}
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.
:::
### 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](https://tidyverse.tidyverse.org/articles/manifesto.html)
and offer user-friendly interfaces for interactive data analysis.
The creators of the tidyverse, Posit, have provided exceptional
[cheatsheets](https://posit.co/resources/cheatsheets/)
and [tutorials](https://github.com/rstudio-education/remaster-the-tidyverse)
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:
- [The tidyverse cookbook](https://rstudio-education.github.io/tidyverse-cookbook/)
- [R for Data Science](https://r4ds.had.co.nz/)
::: {.callout-note}
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.
:::
### 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](https://merck.github.io/r2rtf/articles/index.html).
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:
```{r, message=FALSE}
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.
::: {.callout-note}
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.
:::
```{r}
r2rtf_adae |> select(USUBJID, TRTA, AEDECOD)
```
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.
```{r}
tbl <- r2rtf_adae %>%
count(TRTA, AEDECOD) %>%
pivot_wider(names_from = TRTA, values_from = n, values_fill = 0)
tbl
```
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:
- `rtf_page()`: RTF page information
- `rtf_title()`: RTF title information
- `rtf_colheader()`: RTF column header information
- `rtf_body()`: RTF table body information
- `rtf_footnote()`: RTF footnote information
- `rtf_source()`: RTF data source information
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](https://merck.github.io/r2rtf/reference/index.html).
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`.
```{r}
tbl |>
head() |>
rtf_body() |>
rtf_encode() |>
write_rtf("tlf/intro-ae1.rtf")
```
```{r, out.width = "100%", out.height = if (knitr::is_html_output()) "400px", echo = FALSE, fig.align = "center"}
rtf2pdf("tlf/intro-ae1.rtf")
knitr::include_graphics("tlf/intro-ae1.pdf")
```
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.
::: {.callout-note}
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.
:::
```{r}
tbl |>
head() |>
rtf_body(col_rel_width = c(3, 2, 2, 2)) |>
rtf_encode() |>
write_rtf("tlf/intro-ae2.rtf")
```
```{r, out.width = "100%", out.height = if (knitr::is_html_output()) "400px", echo = FALSE, fig.align = "center"}
rtf2pdf("tlf/intro-ae2.rtf")
knitr::include_graphics("tlf/intro-ae2.pdf")
```
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:
```{r}
tbl |>
head() |>
rtf_colheader(
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() %>%
write_rtf("tlf/intro-ae3.rtf")
```
```{r, out.width = "100%", out.height = if (knitr::is_html_output()) "400px", echo = FALSE, fig.align = "center"}
rtf2pdf("tlf/intro-ae3.rtf")
knitr::include_graphics("tlf/intro-ae3.pdf")
```
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:
```{r, echo = FALSE}
r2rtf:::justification() |>
select(1:2) |>
knitr::kable()
```
Below is an example to make the first column left-aligned and the rest columns
center-aligned.
```{r}
tbl |>
head() |>
rtf_body(text_justification = c("l", "c", "c", "c")) |>
rtf_encode() |>
write_rtf("tlf/intro-ae5.rtf")
```
```{r, out.width = "100%", out.height = if (knitr::is_html_output()) "400px", echo = FALSE, fig.align = "center"}
rtf2pdf("tlf/intro-ae5.rtf")
knitr::include_graphics("tlf/intro-ae5.pdf")
```
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.
::: {.callout-note}
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](https://merck.github.io/r2rtf/articles/rtf-row.html#border-type).
:::
```{r}
tbl |>
head() |>
rtf_colheader(
colheader = " | Treatment",
col_rel_width = c(3, 6)
) |>
rtf_colheader(
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() |>
write_rtf("tlf/intro-ae7.rtf")
```
```{r, out.width = "100%", out.height = if (knitr::is_html_output()) "400px", echo = FALSE, fig.align = "center"}
rtf2pdf("tlf/intro-ae7.rtf")
knitr::include_graphics("tlf/intro-ae7.pdf")
```
The r2rtf R [package website](https://merck.github.io/r2rtf/articles/index.html)
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.