cardinal
  • Home
  • Template Library
    • FDA Table 2
    • FDA Table 3
    • FDA Table 4
    • FDA Table 5
    • FDA Table 6
    • FDA Table 7
    • FDA Table 8
    • FDA Table 9
    • FDA Table 10
    • FDA Table 11
    • FDA Table 12
    • FDA Table 13
    • FDA Table 14
    • FDA Table 15
    • FDA Table 16
    • FDA Table 17
    • FDA Table 18
    • FDA Table 20
    • FDA Table 21
    • FDA Table 22
    • FDA Table 32
    • FDA Table 33
    • FDA Table 34
    • FDA Table 35
    • FDA Table 36
    • FDA Figure 1
    • FDA Figure 2
    • FDA Figure 3
    • FDA Figure 14
  • About
  • Resources
  • Help
    • Getting Started
    • Report a Bug
    • FAQ

On this page

  • Environment Setup and Package Installation
    • Environment Setup
    • Installing Package Dependencies
    • Installing the cardinal Package
  • Loading Data
  • Template Navigation
  • Creating Tables
    • Using the Table Functions
    • Table Customization
  • Feature Requests
  • Additional Resources

Getting Started

Environment Setup and Package Installation

Environment Setup

Please ensure that R version 3.6 or higher is installed on your computer. This is required to install the cardinal package and its dependencies. You can check your current version of R by running sessionInfo() within the R console.

Installing Package Dependencies

The cardinal package requires several packages available on CRAN.

To use the cardinal package, ensure you have these necessary package dependencies installed by running the following code:

if (!require("gtsummary")) install.packages("gtsummary")
if (!require("cards")) install.packages("cards")
if (!require("cardx")) install.packages("cardx")
if (!require("formatters")) install.packages("formatters")
if (!require("rtables")) install.packages("rtables")
if (!require("rlistings")) install.packages("rlistings")
if (!require("tern")) install.packages("tern")

Optionally, to run the examples provided within the cardinal package and on this site you can also install the random CDISC data package, which contains example datasets, by running the following:

if (!require("random.cdisc.data")) install.packages("random.cdisc.data")

For more information on these packages, see the Additional Resources section below.

Installing the cardinal Package

To install the cardinal package, run the following line of code:

if (!require("cardinal")) remotes::install_github("pharmaverse/cardinal")

Loading Data

The table functions provided by cardinal are designed to work with any datasets which adhere to CDISC standards. If you have access to CDISC data, load this into your R environment as usual to use when generating tables.

If you do not have access to CDISC data, or want to run the examples provided within the package, you can use the random.cdisc.data package to load a selection of datasets containing example synthetic randomized CDISC data. Datasets are stored in the package by name, prefixed by the letter "c" (for “cached”). For example, after loading the random.cdisc.data package you can access an ADSL dataset by running cadsl, or ADAE with cadae. This data is loaded in where necessary as part of the provided examples.

Template Navigation

A list of all templates currently available in cardinal is provided in the Template Library Index, with tables designed based on the FDA Standard Safety Tables and Figures: Integrated Guide.

Each template provided is associated with a function available within the cardinal package, and contains 4 sections:

  • Spec. Screenshot: This tab provides a screenshot of the given table coming from the FDA Standard Safety Table and Figures document.

  • Table: This tab displays the output table corresponding to the screenshot in the previous tab, generated using the associated cardinal table function. You can expect a similar output table when using the table function with your own data, depending on pre-processing and the customizations that you apply via the table function parameters.

  • Table Setup: This tab provides the code used to generate the example table displayed in the previous tab, including the loading of necessary libraries and example datasets, and any pre-processing steps applied prior to generating the table.

  • Function Details: This tab includes details on the table-generating function used for this template. Table functions use the naming convention make_table_XX() where XX is the table number taken from the FDA Standard Safety Table and Figures document (preceded by a 0 if the number is a single digit). Any required variables for the input datasets are listed along with a description of all function arguments. This information is mirrored by the function’s help page accessible within R (i.e. ?make_table_XX). By default, all table generating functions use the {gtsummary} package - though we do support rtables functionality. To specify the use of which table engine is being used, engine specific functions can be called (make_table_02_rtables, for example).

          A link to the function’s source code can be found at the bottom of the page in this tab:

Creating Tables

There are many table-generating functions available within the cardinal package, each of which is used to generate a different FDA standard safety table using R. These functions create rtables table objects which can then be further customized, paginated, etc. if required using functions from the rtables package.

Using the Table Functions

To use the table functions you will need to load the cardinal package and then call the appropriate table function. For example, to create FDA Safety Table 2, you can run the following code:

library(dplyr)
library(cardinal)

# Data pre-processing - ensure all necessary variables are present in the data
adsl <- random.cdisc.data::cadsl %>%
  mutate(AGEGR1 = as.factor(case_when(
    AGE >= 17 & AGE < 65 ~ ">=17 to <65",
    AGE >= 65 ~ ">=65",
    AGE >= 65 & AGE < 75 ~ ">=65 to <75",
    AGE >= 75 ~ ">=75"
  )))

# Create table
tbl <- make_table_02(df = adsl)
tbl
$table
<div id="sqqikskhyr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  <style>#sqqikskhyr table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#sqqikskhyr thead, #sqqikskhyr tbody, #sqqikskhyr tfoot, #sqqikskhyr tr, #sqqikskhyr td, #sqqikskhyr th {
  border-style: none;
}

#sqqikskhyr p {
  margin: 0;
  padding: 0;
}

#sqqikskhyr .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: auto;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#sqqikskhyr .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#sqqikskhyr .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#sqqikskhyr .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#sqqikskhyr .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#sqqikskhyr .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#sqqikskhyr .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#sqqikskhyr .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#sqqikskhyr .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#sqqikskhyr .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#sqqikskhyr .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#sqqikskhyr .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#sqqikskhyr .gt_spanner_row {
  border-bottom-style: hidden;
}

#sqqikskhyr .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#sqqikskhyr .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#sqqikskhyr .gt_from_md > :first-child {
  margin-top: 0;
}

#sqqikskhyr .gt_from_md > :last-child {
  margin-bottom: 0;
}

#sqqikskhyr .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#sqqikskhyr .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#sqqikskhyr .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#sqqikskhyr .gt_row_group_first td {
  border-top-width: 2px;
}

#sqqikskhyr .gt_row_group_first th {
  border-top-width: 2px;
}

#sqqikskhyr .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#sqqikskhyr .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#sqqikskhyr .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#sqqikskhyr .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#sqqikskhyr .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#sqqikskhyr .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#sqqikskhyr .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#sqqikskhyr .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#sqqikskhyr .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#sqqikskhyr .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#sqqikskhyr .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#sqqikskhyr .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#sqqikskhyr .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#sqqikskhyr .gt_left {
  text-align: left;
}

#sqqikskhyr .gt_center {
  text-align: center;
}

#sqqikskhyr .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#sqqikskhyr .gt_font_normal {
  font-weight: normal;
}

#sqqikskhyr .gt_font_bold {
  font-weight: bold;
}

#sqqikskhyr .gt_font_italic {
  font-style: italic;
}

#sqqikskhyr .gt_super {
  font-size: 65%;
}

#sqqikskhyr .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#sqqikskhyr .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#sqqikskhyr .gt_indent_1 {
  text-indent: 5px;
}

#sqqikskhyr .gt_indent_2 {
  text-indent: 10px;
}

#sqqikskhyr .gt_indent_3 {
  text-indent: 15px;
}

#sqqikskhyr .gt_indent_4 {
  text-indent: 20px;
}

#sqqikskhyr .gt_indent_5 {
  text-indent: 25px;
}

#sqqikskhyr .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#sqqikskhyr div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
  <table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="label"><span data-qmd-base64="KipDaGFyYWN0ZXJpc3RpYyoq"><span class='gt_from_md'><strong>Characteristic</strong></span></span></th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="stat_1"><span data-qmd-base64="KipBOiBEcnVnIFgqKiAgCk4gPSAxMzQ="><span class='gt_from_md'><strong>A: Drug X</strong><br />
N = 134</span></span></th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="stat_2"><span data-qmd-base64="KipCOiBQbGFjZWJvKiogIApOID0gMTM0"><span class='gt_from_md'><strong>B: Placebo</strong><br />
N = 134</span></span></th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="stat_3"><span data-qmd-base64="KipDOiBDb21iaW5hdGlvbioqICAKTiA9IDEzMg=="><span class='gt_from_md'><strong>C: Combination</strong><br />
N = 132</span></span></th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="stat_0"><span data-qmd-base64="KipUb3RhbCBQb3B1bGF0aW9uKiogIApOID0gNDAw"><span class='gt_from_md'><strong>Total Population</strong><br />
N = 400</span></span></th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">Sex, n (%)</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    F</td>
<td headers="stat_1" class="gt_row gt_right">79 (59%)</td>
<td headers="stat_2" class="gt_row gt_right">82 (61%)</td>
<td headers="stat_3" class="gt_row gt_right">70 (53%)</td>
<td headers="stat_0" class="gt_row gt_right">231 (58%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    M</td>
<td headers="stat_1" class="gt_row gt_right">55 (41%)</td>
<td headers="stat_2" class="gt_row gt_right">52 (39%)</td>
<td headers="stat_3" class="gt_row gt_right">62 (47%)</td>
<td headers="stat_0" class="gt_row gt_right">169 (42%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">Age</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    Mean (SD)</td>
<td headers="stat_1" class="gt_row gt_right">33.77 (6.55)</td>
<td headers="stat_2" class="gt_row gt_right">35.43 (7.90)</td>
<td headers="stat_3" class="gt_row gt_right">35.43 (7.72)</td>
<td headers="stat_0" class="gt_row gt_right">34.88 (7.44)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    Median (min - max)</td>
<td headers="stat_1" class="gt_row gt_right">33.00 (21.00 - 50.00)</td>
<td headers="stat_2" class="gt_row gt_right">35.00 (21.00 - 62.00)</td>
<td headers="stat_3" class="gt_row gt_right">35.00 (20.00 - 69.00)</td>
<td headers="stat_0" class="gt_row gt_right">34.00 (20.00 - 69.00)</td></tr>
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">AGEGR1, n (%)</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    &gt;=17 to &lt;65</td>
<td headers="stat_1" class="gt_row gt_right">134 (100%)</td>
<td headers="stat_2" class="gt_row gt_right">134 (100%)</td>
<td headers="stat_3" class="gt_row gt_right">131 (99%)</td>
<td headers="stat_0" class="gt_row gt_right">399 (100%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    &gt;=65</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_3" class="gt_row gt_right">1 (0.8%)</td>
<td headers="stat_0" class="gt_row gt_right">1 (0.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">Race, n (%)</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    ASIAN</td>
<td headers="stat_1" class="gt_row gt_right">68 (51%)</td>
<td headers="stat_2" class="gt_row gt_right">67 (50%)</td>
<td headers="stat_3" class="gt_row gt_right">73 (55%)</td>
<td headers="stat_0" class="gt_row gt_right">208 (52%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    BLACK OR AFRICAN AMERICAN</td>
<td headers="stat_1" class="gt_row gt_right">31 (23%)</td>
<td headers="stat_2" class="gt_row gt_right">28 (21%)</td>
<td headers="stat_3" class="gt_row gt_right">32 (24%)</td>
<td headers="stat_0" class="gt_row gt_right">91 (23%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    WHITE</td>
<td headers="stat_1" class="gt_row gt_right">27 (20%)</td>
<td headers="stat_2" class="gt_row gt_right">26 (19%)</td>
<td headers="stat_3" class="gt_row gt_right">21 (16%)</td>
<td headers="stat_0" class="gt_row gt_right">74 (19%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    AMERICAN INDIAN OR ALASKA NATIVE</td>
<td headers="stat_1" class="gt_row gt_right">8 (6.0%)</td>
<td headers="stat_2" class="gt_row gt_right">11 (8.2%)</td>
<td headers="stat_3" class="gt_row gt_right">6 (4.5%)</td>
<td headers="stat_0" class="gt_row gt_right">25 (6.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    MULTIPLE</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">1 (0.7%)</td>
<td headers="stat_3" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_0" class="gt_row gt_right">1 (0.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">1 (0.7%)</td>
<td headers="stat_3" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_0" class="gt_row gt_right">1 (0.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    OTHER</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_3" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_0" class="gt_row gt_right">0 (0%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    UNKNOWN</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_3" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_0" class="gt_row gt_right">0 (0%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">Ethnicity, n (%)</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    HISPANIC OR LATINO</td>
<td headers="stat_1" class="gt_row gt_right">15 (11%)</td>
<td headers="stat_2" class="gt_row gt_right">18 (13%)</td>
<td headers="stat_3" class="gt_row gt_right">15 (11%)</td>
<td headers="stat_0" class="gt_row gt_right">48 (12%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    NOT HISPANIC OR LATINO</td>
<td headers="stat_1" class="gt_row gt_right">104 (78%)</td>
<td headers="stat_2" class="gt_row gt_right">103 (77%)</td>
<td headers="stat_3" class="gt_row gt_right">101 (77%)</td>
<td headers="stat_0" class="gt_row gt_right">308 (77%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    NOT REPORTED</td>
<td headers="stat_1" class="gt_row gt_right">6 (4.5%)</td>
<td headers="stat_2" class="gt_row gt_right">10 (7.5%)</td>
<td headers="stat_3" class="gt_row gt_right">11 (8.3%)</td>
<td headers="stat_0" class="gt_row gt_right">27 (6.8%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    UNKNOWN</td>
<td headers="stat_1" class="gt_row gt_right">9 (6.7%)</td>
<td headers="stat_2" class="gt_row gt_right">3 (2.2%)</td>
<td headers="stat_3" class="gt_row gt_right">5 (3.8%)</td>
<td headers="stat_0" class="gt_row gt_right">17 (4.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left" style="font-weight: bold;">Country, n (%)</td>
<td headers="stat_1" class="gt_row gt_right"><br /></td>
<td headers="stat_2" class="gt_row gt_right"><br /></td>
<td headers="stat_3" class="gt_row gt_right"><br /></td>
<td headers="stat_0" class="gt_row gt_right"><br /></td></tr>
    <tr><td headers="label" class="gt_row gt_left">    CHN</td>
<td headers="stat_1" class="gt_row gt_right">74 (55%)</td>
<td headers="stat_2" class="gt_row gt_right">81 (60%)</td>
<td headers="stat_3" class="gt_row gt_right">64 (48%)</td>
<td headers="stat_0" class="gt_row gt_right">219 (55%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    USA</td>
<td headers="stat_1" class="gt_row gt_right">10 (7.5%)</td>
<td headers="stat_2" class="gt_row gt_right">13 (9.7%)</td>
<td headers="stat_3" class="gt_row gt_right">17 (13%)</td>
<td headers="stat_0" class="gt_row gt_right">40 (10%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    BRA</td>
<td headers="stat_1" class="gt_row gt_right">13 (9.7%)</td>
<td headers="stat_2" class="gt_row gt_right">7 (5.2%)</td>
<td headers="stat_3" class="gt_row gt_right">10 (7.6%)</td>
<td headers="stat_0" class="gt_row gt_right">30 (7.5%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    PAK</td>
<td headers="stat_1" class="gt_row gt_right">12 (9.0%)</td>
<td headers="stat_2" class="gt_row gt_right">9 (6.7%)</td>
<td headers="stat_3" class="gt_row gt_right">10 (7.6%)</td>
<td headers="stat_0" class="gt_row gt_right">31 (7.8%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    NGA</td>
<td headers="stat_1" class="gt_row gt_right">8 (6.0%)</td>
<td headers="stat_2" class="gt_row gt_right">7 (5.2%)</td>
<td headers="stat_3" class="gt_row gt_right">11 (8.3%)</td>
<td headers="stat_0" class="gt_row gt_right">26 (6.5%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    RUS</td>
<td headers="stat_1" class="gt_row gt_right">5 (3.7%)</td>
<td headers="stat_2" class="gt_row gt_right">8 (6.0%)</td>
<td headers="stat_3" class="gt_row gt_right">6 (4.5%)</td>
<td headers="stat_0" class="gt_row gt_right">19 (4.8%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    JPN</td>
<td headers="stat_1" class="gt_row gt_right">5 (3.7%)</td>
<td headers="stat_2" class="gt_row gt_right">4 (3.0%)</td>
<td headers="stat_3" class="gt_row gt_right">9 (6.8%)</td>
<td headers="stat_0" class="gt_row gt_right">18 (4.5%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    GBR</td>
<td headers="stat_1" class="gt_row gt_right">4 (3.0%)</td>
<td headers="stat_2" class="gt_row gt_right">3 (2.2%)</td>
<td headers="stat_3" class="gt_row gt_right">2 (1.5%)</td>
<td headers="stat_0" class="gt_row gt_right">9 (2.3%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    CAN</td>
<td headers="stat_1" class="gt_row gt_right">3 (2.2%)</td>
<td headers="stat_2" class="gt_row gt_right">2 (1.5%)</td>
<td headers="stat_3" class="gt_row gt_right">3 (2.3%)</td>
<td headers="stat_0" class="gt_row gt_right">8 (2.0%)</td></tr>
    <tr><td headers="label" class="gt_row gt_left">    CHE</td>
<td headers="stat_1" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_2" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_3" class="gt_row gt_right">0 (0%)</td>
<td headers="stat_0" class="gt_row gt_right">0 (0%)</td></tr>
  </tbody>
  
  
</table>
</div>

$ard
$ard$tbl_summary
   group1 group1_level variable variable_level stat_name stat_label stat
1     ARM    A: Drug X      SEX              F         n          n   79
2     ARM    A: Drug X      SEX              F         N          N  134
3     ARM    A: Drug X      SEX              F         p          % 0.59
4     ARM    A: Drug X      SEX              M         n          n   55
5     ARM    A: Drug X      SEX              M         N          N  134
6     ARM    A: Drug X      SEX              M         p          % 0.41
7     ARM    A: Drug X   AGEGR1      >=17 to …         n          n  134
8     ARM    A: Drug X   AGEGR1      >=17 to …         N          N  134
9     ARM    A: Drug X   AGEGR1      >=17 to …         p          %    1
10    ARM    A: Drug X   AGEGR1           >=65         n          n    0

$ard$add_overall
   variable variable_level   context stat_name stat_label  stat
1       SEX              F categori…         n          n   231
2       SEX              F categori…         N          N   400
3       SEX              F categori…         p          % 0.578
4       SEX              M categori…         n          n   169
5       SEX              M categori…         N          N   400
6       SEX              M categori…         p          % 0.423
7    AGEGR1      >=17 to … categori…         n          n   399
8    AGEGR1      >=17 to … categori…         N          N   400
9    AGEGR1      >=17 to … categori…         p          % 0.998
10   AGEGR1           >=65 categori…         n          n     1

The above table is created using the default settings. You can customize tables by specifying function parameter values to set input data, variables to include in the table, table annotations, etc.

Table Customization

Each template takes several arguments that can be set to generate a table that meets your requirements. A brief overview of the parameters for each template is provided in the Function Details section of each table template page (see the Function Details section above) and the function’s help page within R (i.e. ?make_table_XX), with many of these parameters being standard across table functions.

To customize the output table, you can modify the values of these arguments as per your requirements. For example, table 2 can be customized as follows:

advs <- random.cdisc.data::cadvs %>%
  filter(AVISIT == "BASELINE", VSTESTCD == "TEMP") %>%
  select("USUBJID", "AVAL")

anl <- left_join(adsl, advs, by = "USUBJID") %>% tern::df_explicit_na()

tbl <- make_table_02(
  df = anl,
  vars = c("SEX", "AGE", "RACE", "COUNTRY", "AVAL")
)
tbl$tbl
NULL

Note that the prune_0 argument can be set to specify whether all-zero rows should be included in a table. For example, see that the demographics table below includes rows for OTHER and UNKNOWN for which all values are zero, whereas these two rows were excluded from the previous tables (prune_0 defaults to TRUE in make_table_02()).

make_table_02_rtables(df = anl, vars = "RACE", prune_0 = FALSE)
                                              A: Drug X    B: Placebo   C: Combination   Total Population
Characteristic                                 (N=134)      (N=134)        (N=132)           (N=400)     
—————————————————————————————————————————————————————————————————————————————————————————————————————————
Race                                                                                                     
  ASIAN                                       68 (50.7%)    67 (50%)      73 (55.3%)        208 (52%)    
  BLACK OR AFRICAN AMERICAN                   31 (23.1%)   28 (20.9%)     32 (24.2%)        91 (22.8%)   
  WHITE                                       27 (20.1%)   26 (19.4%)     21 (15.9%)        74 (18.5%)   
  AMERICAN INDIAN OR ALASKA NATIVE              8 (6%)     11 (8.2%)       6 (4.5%)         25 (6.2%)    
  MULTIPLE                                        0         1 (0.7%)          0              1 (0.2%)    
  NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER       0         1 (0.7%)          0              1 (0.2%)    
  OTHER                                           0            0              0                 0        
  UNKNOWN                                         0            0              0                 0        

Feature Requests

If you would like to request the addition of a new feature to a pre-existing function within cardinal, or would like a specific table template to be added, please file an issue on GitHub here or reach out to the cardinal team directly via our Slack channel here.

You can access the source code for all currently available functions in the cardinal GitHub repository here.

Additional Resources

See the following packages used by cardinal for more information:

  • tern: Clinical trials analysis functions
  • rtables: Table creation
  • rlistings: Listing creation
  • formatters: Additional rendering formatting
  • random.cdisc.data: Example synthetic randomized CDISC datasets (required for examples only)
Source Code
---
title: "Getting Started"
toc: true
toc-depth: 4
---

### Environment Setup and Package Installation

#### Environment Setup

Please ensure that R version 3.6 or higher is installed on your computer. This is required to install the `cardinal` package and its dependencies. You can check your current version of R by running `sessionInfo()` within the R console.

#### Installing Package Dependencies

The `cardinal` package requires several packages available on CRAN.

To use the `cardinal` package, ensure you have these necessary package dependencies installed by running the following code:

```{r, echo=TRUE, eval=FALSE}
if (!require("gtsummary")) install.packages("gtsummary")
if (!require("cards")) install.packages("cards")
if (!require("cardx")) install.packages("cardx")
if (!require("formatters")) install.packages("formatters")
if (!require("rtables")) install.packages("rtables")
if (!require("rlistings")) install.packages("rlistings")
if (!require("tern")) install.packages("tern")
```

Optionally, to run the examples provided within the `cardinal` package and on this site you can also install the random CDISC data package, which contains example datasets, by running the following:

```{r, echo=TRUE, eval=FALSE}
if (!require("random.cdisc.data")) install.packages("random.cdisc.data")
```

For more information on these packages, see the [Additional Resources](#additional-resources) section below.

#### Installing the cardinal Package

To install the `cardinal` package, run the following line of code:

```{r, echo=TRUE, eval=FALSE}
if (!require("cardinal")) remotes::install_github("pharmaverse/cardinal")
```

### Loading Data

The table functions provided by `cardinal` are designed to work with any datasets which adhere to CDISC standards. If you have access to CDISC data, load this into your R environment as usual to use when generating tables.

If you do not have access to CDISC data, or want to run the examples provided within the package, you can use the `random.cdisc.data` package to load a selection of datasets containing example synthetic randomized CDISC data. Datasets are stored in the package by name, prefixed by the letter `"c"` (for "cached"). For example, after loading the `random.cdisc.data` package you can access an ADSL dataset by running `cadsl`, or ADAE with `cadae`. This data is loaded in where necessary as part of the provided examples.

### Template Navigation

A list of all templates currently available in `cardinal` is provided in the [Template Library Index](index-templates.qmd), with tables designed based on the [FDA Standard Safety Tables and Figures: Integrated Guide](https://downloads.regulations.gov/FDA-2022-N-1961-0046/attachment_1.pdf).

Each template provided is associated with a function available within the `cardinal` package, and contains 4 sections:

-   **Spec. Screenshot**: This tab provides a screenshot of the given table coming from the FDA Standard Safety Table and Figures document.

![](./assets/images/getting-started/gs-pan1.png){fig-align="center" width="90%"}

-   **Table**: This tab displays the output table corresponding to the screenshot in the previous tab, generated using the associated `cardinal` table function. You can expect a similar output table when using the table function with your own data, depending on pre-processing and the customizations that you apply via the table function parameters.

![](./assets/images/getting-started/gs-pan2.png){fig-align="center" width="90%"}

-   **Table Setup**: This tab provides the code used to generate the example table displayed in the previous tab, including the loading of necessary libraries and example datasets, and any pre-processing steps applied prior to generating the table.

![](./assets/images/getting-started/gs-pan3.png){fig-align="center" width="90%"}

-   **Function Details**: This tab includes details on the table-generating function used for this template. Table functions use the naming convention `make_table_XX()` where `XX` is the table number taken from the FDA Standard Safety Table and Figures document (preceded by a 0 if the number is a single digit). Any required variables for the input datasets are listed along with a description of all function arguments. This information is mirrored by the function's help page accessible within R (i.e. `?make_table_XX`). By default, all table generating functions use the {gtsummary} package - though we do support rtables functionality. To specify the use of which table engine is being used, engine specific functions can be called (`make_table_02_rtables`, for example).

![](./assets/images/getting-started/gs-pan4.png){fig-align="center" width="90%"}

|           A link to the function's source code can be found at the bottom of the page in this tab:

![](./assets/images/getting-started/gs-pan4b.png){fig-align="center" width="90%"}

### Creating Tables

There are many table-generating functions available within the `cardinal` package, each of which is used to generate a different FDA standard safety table using R. These functions create `rtables` table objects which can then be further customized, paginated, etc. if required using functions from the [`rtables`](https://insightsengineering.github.io/rtables/) package.

#### Using the Table Functions

To use the table functions you will need to load the `cardinal` package and then call the appropriate table function. For example, to create FDA Safety Table 2, you can run the following code:

```{r, echo=TRUE, warning=FALSE, message=FALSE}
library(dplyr)
library(cardinal)

# Data pre-processing - ensure all necessary variables are present in the data
adsl <- random.cdisc.data::cadsl %>%
  mutate(AGEGR1 = as.factor(case_when(
    AGE >= 17 & AGE < 65 ~ ">=17 to <65",
    AGE >= 65 ~ ">=65",
    AGE >= 65 & AGE < 75 ~ ">=65 to <75",
    AGE >= 75 ~ ">=75"
  )))

# Create table
tbl <- make_table_02(df = adsl)
tbl
```

The above table is created using the default settings. You can customize tables by specifying function parameter values to set input data, variables to include in the table, table annotations, etc.

#### Table Customization

Each template takes several arguments that can be set to generate a table that meets your requirements. A brief overview of the parameters for each template is provided in the **Function Details** section of each table template page (see the Function Details section above) and the function's help page within R (i.e. `?make_table_XX`), with many of these parameters being standard across table functions.

To customize the output table, you can modify the values of these arguments as per your requirements. For example, table 2 can be customized as follows:

```{r, echo=TRUE, warning=FALSE, message=FALSE}
advs <- random.cdisc.data::cadvs %>%
  filter(AVISIT == "BASELINE", VSTESTCD == "TEMP") %>%
  select("USUBJID", "AVAL")

anl <- left_join(adsl, advs, by = "USUBJID") %>% tern::df_explicit_na()

tbl <- make_table_02(
  df = anl,
  vars = c("SEX", "AGE", "RACE", "COUNTRY", "AVAL")
)
tbl$tbl
```

Note that the `prune_0` argument can be set to specify whether all-zero rows should be included in a table. For example, see that the demographics table below includes rows for `OTHER` and `UNKNOWN` for which all values are zero, whereas these two rows were excluded from the previous tables (`prune_0` defaults to `TRUE` in `make_table_02()`).

```{r, echo=TRUE}
make_table_02_rtables(df = anl, vars = "RACE", prune_0 = FALSE)
```

### Feature Requests

If you would like to request the addition of a new feature to a pre-existing function within `cardinal`, or would like a specific table template to be added, please file an issue on GitHub [here](https://github.com/pharmaverse/cardinal/issues) or reach out to the cardinal team directly via our Slack channel [here](https://app.slack.com/client/T028PB489D3/C04MQS12MND).

You can access the source code for all currently available functions in the `cardinal` GitHub repository [here](https://github.com/pharmaverse/cardinal/tree/main/R).

### Additional Resources {#additional-resources}

See the following packages used by `cardinal` for more information:

-   [`tern`](https://insightsengineering.github.io/tern): Clinical trials analysis functions
-   [`rtables`](https://insightsengineering.github.io/rtables): Table creation
-   [`rlistings`](https://insightsengineering.github.io/rlistings): Listing creation
-   [`formatters`](https://insightsengineering.github.io/formatters): Additional rendering formatting
-   [`random.cdisc.data`](https://insightsengineering.github.io/random.cdisc.data): Example synthetic randomized CDISC datasets (required for examples only)
 
  • This website as well as code examples are licensed under the Apache License, Version 2.0.
Cookie Preferences