Creating a Shift Table in R

Here is a workflow to create a Shift Table in R, using the {tidyverse} suite for data processing, and {gt} to build the desired table layout.

Required Packages

Code
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(tidyr))
suppressPackageStartupMessages(library(rlang))
suppressPackageStartupMessages(library(purrr))
suppressPackageStartupMessages(library(stringr))
suppressPackageStartupMessages(library(gt))
suppressPackageStartupMessages(library(here))

# list all files
files <- list.files(here("R"), pattern = ".R", full.names = TRUE)
# Read all files
walk(files, source)

Data used for Analysis

We will make use of the adsl and adlb test ADaM datasets from the {pharmaverseadam} R package for analysis.

ADSL is the subject level analysis dataset

Code
adsl <- pharmaverseadam::adsl

ADLB is the analysis dataset for Laboratory Records

Code
adlb <- pharmaverseadam::adlb

Variables used for Analysis

  • USUBJID - Unique Subject Identifier
  • SAFFL - Safety Population Flag
  • TRT01A - Actual Treatment Arm for Period 01
  • PARAM - Parameter
  • PARAMCD - Parameter Code
  • AVISIT - Analysis Visit
  • AVISITN - Analysis Visit (Numeric)
  • AVAL - Analysis Value
  • ANL01FL - Analysis Flag 01
  • BNRIND - Baseline Reference Range Indicator
  • ANRIND - Analysis Reference Range Indicator

Programming Flow

1. Calculating BIG N

  • Keep only safety subjects (SAFFL == 'Y') in adsl
  • Count number of subjects in the full safety analysis set within each treatment arm (TRT01A)
Code
adsl_bign <- adsl |>
  na_to_missing() |>
  filter(.data$SAFFL == "Y") |>
  select(all_of(c("USUBJID", "TRT01A"))) |>
  add_count(.data$TRT01A, name = "TRT_N")

2. Preprocessing Lab Records

  • Merge adsl_bign to adlb to add TRT_N
  • Filter out missing values in Baseline Reference Range Indicator (BNRIND), Analysis Reference Range Indicator (ANRIND) and Analysis Value (AVAL)
  • Subset the resulting data for subjects with post-does records where analysis flag (ANL01FL) is equal to 'Y'
  • Subset data to keep records within the time period (eg. Week 2, Week 4, Week 6) we want to see the shifts in Laboratory Tests
  • Add BIG N to treatment labels by concatenating TRT_N with TRT01A
Code
adlb_prep <- adlb |>
  na_to_missing() |>
  mutate(across(all_of(c("BNRIND", "ANRIND")), str_to_title)) |>
  left_join(adsl_bign, by = c("USUBJID", "TRT01A")) |>
  filter(
    .data$BNRIND != "<Missing>",
    .data$ANRIND != "<Missing>",
    !is.na(.data$AVAL),
    .data$ANL01FL == "Y",
    .data$AVISIT %in% c("Week 2", "Week 4", "Week 6")
  ) |>
  mutate(TRT_VAR = paste0(.data$TRT01A, "<br>(N=", .data$TRT_N, ")")) |>
  select(-TRT_N)


Subset adlb_prep to keep only Hemoglobin records

Code
adlb_hgb <- adlb_prep |>
  filter(.data$PARAMCD == "HGB")

3. Get all combinations of Range Indicator values

Create a dummy dataset that contains all possible combination of BNRIND and ANRIND values by Treatment and Visit.

Code
comb_base_pbase <- expand_grid(
  TRT_VAR = unique(adlb_hgb[["TRT_VAR"]]),
  AVISIT = unique(adlb_hgb[["AVISIT"]]),
  BNRIND = c("Low", "Normal", "High", "Total")
) |>
  cross_join(tibble(ANRIND = c("Low", "Normal", "High")))

4. Performing Counts by Analysis Visit

Code
shift_counts <- adlb_hgb |>
  bind_rows(mutate(adlb_hgb, BNRIND = "Total")) |>
  group_by(!!!syms(c("TRT_VAR", "AVISITN", "ANRIND", "BNRIND"))) |>
  count(.data[["AVISIT"]], name = "CNT") |>
  ungroup() |>
  # merge dummy dataset to get all combinations of `ANRIND` and `BNRIND` values
  full_join(comb_base_pbase, by = c("TRT_VAR", "AVISIT", "BNRIND", "ANRIND")) |>
  mutate(across("CNT", ~ replace_na(.x, 0))) |>
  arrange(
    .data[["TRT_VAR"]],
    factor(.data[["BNRIND"]], levels = c("Low", "Normal", "High", "Total"))
  )

5. Reshaping Data

  • Reshaping data to wide format to get the final Shift Table layout
  • Adding Post-Baseline Grade Totals
Code
shift_wide <- shift_counts |>
  pivot_wider(
    id_cols = all_of(c("AVISIT", "ANRIND")),
    names_from = all_of(c("TRT_VAR", "BNRIND")),
    values_from = "CNT",
    names_sep = "^"
  )

post_base_grade_totals <- shift_wide |>
  summarize(across(where(is.numeric), sum), .by = all_of("AVISIT")) |>
  mutate(ANRIND = "Total")

visit_levels <-
  arrange(filter(shift_counts, !is.na(.data$AVISITN)), by = .data$AVISITN) |>
  pull(.data$AVISIT) |>
  unique()

shift_final <- shift_wide |>
  bind_rows(post_base_grade_totals) |>
  arrange(
    factor(.data$AVISIT, levels = visit_levels),
    factor(.data$ANRIND, levels = c("Low", "Normal", "High", "Total"))
  )

An alternate and tidier approach would be to create a function say count_shifts_by_visit() to cover Steps 3-5

Code
shift_final <-
  count_shifts_by_visit(
    bds_dataset = adlb_hgb,
    trt_var = exprs(TRT_VAR),
    analysis_grade_var = exprs(ANRIND),
    base_grade_var = exprs(BNRIND),
    grade_var_order = exprs(Low, Normal, High),
    visit_var = exprs(AVISIT, AVISITN)
  )

6. Adding Percentages

Code
trt_bign <-
  map(
    set_names(unique(adsl_bign[["TRT01A"]])),
    \(trt_val) get_trt_total(adsl_bign, exprs(TRT01A, TRT_N), trt_val)
  )

shift_final <- shift_final |>
  add_pct2cols(
    exclude_cols = exprs(AVISIT, ANRIND),
    trt_bign = trt_bign
  )

7. Displaying the Final Table with {gt}

Code
out <-
  shift_final |>
  gt(groupname_col = "AVISIT", row_group_as_column = TRUE) |>
  cols_label_with(
    columns = contains("ANRIND"), \(x) md("Reference<br>Range")
  ) |>
  tab_spanner_delim(delim = "^") |>
  text_transform(
    fn = \(x) map(x, \(y) md(paste0(y, "<br>Baseline<br>n (%)"))),
    locations = cells_column_spanners()
  ) |>
  # headers and footers
  tab_stubhead(md("Analysis Visit")) |>
  tab_footnote(footnote = md("N: Number of subjects in the full safety analysis set, within each treatment group<br>n: Subjects with at least one baseline and post-baseline records")) |>
  tab_header(
    preheader = c("Protocol: CDISCPILOT01", "Cutoff date: DDMMYYYY"), # for rtf
    title = md(
      "Table x.x<br>Shift Table of Lab Hematology<br>(Full Safety Analysis Set)"
    ),
    subtitle = paste0("Parameter = ", unique(pull(adlb_hgb, "PARAM")))
  ) |>
  tab_source_note(
    "Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY"
  ) |>
  # cell styling
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_body(columns = 2)
  ) |>
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_body(columns = -c(1, 2))
  ) |>
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_column_labels(columns = -c(1, 2))
  ) |>
  # other options
  tab_options(
    # rtf options
    page.orientation = "landscape",
    page.numbering = TRUE,
    page.header.use_tbl_headings = TRUE,
    page.footer.use_tbl_notes = TRUE,
    # page.height = "18in", uncomment to modify page dimensions while saving as rtf
    # other styling
    table.background.color = "white",
    table.font.names = "monospace-slab-serif",
    row_group.font.weight = "bold",
    column_labels.font.weight = "bold",
    heading.title.font.weight = "bold",
    heading.title.font.size = "20px",
    heading.padding = "10px",
    heading.subtitle.font.size = "14px"
  ) |>
  opt_css(
    css = "
    .gt_heading {
      border-top-style: hidden !important;
    }
    .gt_sourcenote {
      border-bottom-style: hidden !important;
    }
    .gt_table {
      width: max-content !important;
    }
    .gt_subtitle, .gt_footnotes, .gt_sourcenote {
      text-align: left !important;
      font-weight: bold !important;
      color: gray !important;
    }
    "
  )
Table x.x
Shift Table of Lab Hematology
(Full Safety Analysis Set)
Parameter = Hemoglobin (mmol/L)
Analysis Visit Reference
Range
Placebo
(N=86)
Baseline
n (%)
Xanomeline High Dose
(N=72)
Baseline
n (%)
Xanomeline Low Dose
(N=96)
Baseline
n (%)
Low Normal High Total Low Normal High Total Low Normal High Total
Week 2 Low 4 (4.7%) 2 (2.3%) 0 6 (7%) 1 (1.4%) 3 (4.2%) 0 4 (5.6%) 4 (4.2%) 0 0 4 (4.2%)
Normal 3 (3.5%) 73 (84.9%) 0 76 (88.4%) 0 65 (90.3%) 2 (2.8%) 67 (93.1%) 1 (1%) 67 (69.8%) 1 (1%) 69 (71.9%)
High 0 0 0 0 0 0 0 0 0 0 0 0
Total 7 (8.1%) 75 (87.2%) 0 82 (95.3%) 1 (1.4%) 68 (94.4%) 2 (2.8%) 71 (98.6%) 5 (5.2%) 67 (69.8%) 1 (1%) 73 (76%)
Week 4 Low 4 (4.7%) 2 (2.3%) 0 6 (7%) 1 (1.4%) 0 0 1 (1.4%) 4 (4.2%) 2 (2.1%) 0 6 (6.2%)
Normal 1 (1.2%) 68 (79.1%) 0 69 (80.2%) 0 63 (87.5%) 1 (1.4%) 64 (88.9%) 1 (1%) 57 (59.4%) 0 58 (60.4%)
High 0 0 0 0 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 5 (5.8%) 70 (81.4%) 0 75 (87.2%) 1 (1.4%) 64 (88.9%) 1 (1.4%) 66 (91.7%) 5 (5.2%) 59 (61.5%) 0 64 (66.7%)
Week 6 Low 3 (3.5%) 1 (1.2%) 0 4 (4.7%) 0 1 (1.4%) 0 1 (1.4%) 4 (4.2%) 3 (3.1%) 0 7 (7.3%)
Normal 2 (2.3%) 64 (74.4%) 0 66 (76.7%) 0 51 (70.8%) 1 (1.4%) 52 (72.2%) 1 (1%) 50 (52.1%) 0 51 (53.1%)
High 0 1 (1.2%) 0 1 (1.2%) 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 5 (5.8%) 66 (76.7%) 0 71 (82.6%) 0 53 (73.6%) 1 (1.4%) 54 (75%) 5 (5.2%) 53 (55.2%) 0 58 (60.4%)
Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY
N: Number of subjects in the full safety analysis set, within each treatment group
n: Subjects with at least one baseline and post-baseline records
  • Split adlb_prep by multiple parameters.
  • Map over count_shifts_by_visit() on the data split by parameters
  • Add percentages to numeric columns within each resulting data.frame from count_shifts_by_visit()
  • Create a function std_shift_display() to combine the {gt} table display steps and map it over on the list output retrieved from the previous step
Code
adlb_multi <- adlb_prep |>
  filter(toupper(.data$PARAMCD) %in% c("PLAT", "HCT", "MCH")) |>
  group_nest(.data$PARAM)

shift_out <- map(adlb_multi$data, \(x) {
  count_shifts_by_visit(
    bds_dataset = x,
    trt_var = exprs(TRT_VAR),
    analysis_grade_var = exprs(ANRIND),
    base_grade_var = exprs(BNRIND),
    grade_var_order = exprs(Low, Normal, High),
    visit_var = exprs(AVISIT, AVISITN)
  )
}) |>
  set_names(adlb_multi$PARAM)

# add percentages
shift_out <- map(shift_out, \(df) {
  df |>
    add_pct2cols(
      exclude_cols = exprs(AVISIT, ANRIND),
      trt_bign = trt_bign
    )
})

list_out <-
  map(names(shift_out), \(x) {
    shift_out[[x]] |>
      std_shift_display(
        param = x,
        group_col = "AVISIT",
        stub_header = "Analysis Visit",
        rtf_preheader = "Protocol: CDISCPILOT01",
        title = "Table x.x<br>Shift Table of Lab
        Hematology<br>(Full Safety Analysis Set)",
        footnote = "N: Number of subjects in the full safety analysis set, within each treatment group<br>n: Subjects with at least one baseline and post-baseline records",
        sourcenote =
          "Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY"
      )
  })

gt_group(.list = list_out)
Table x.x
Shift Table of Lab Hematology
(Full Safety Analysis Set)
Parameter = Ery. Mean Corpuscular Hemoglobin (fmol(Fe))
Analysis Visit Reference
Range
Placebo
(N=86)
Baseline
n (%)
Xanomeline High Dose
(N=72)
Baseline
n (%)
Xanomeline Low Dose
(N=96)
Baseline
n (%)
Low Normal High Total Low Normal High Total Low Normal High Total
Week 2 Low 0 0 0 0 1 (1.4%) 0 0 1 (1.4%) 0 0 0 0
Normal 0 78 (90.7%) 2 (2.3%) 80 (93%) 0 63 (87.5%) 2 (2.8%) 65 (90.3%) 0 68 (70.8%) 2 (2.1%) 70 (72.9%)
High 0 0 2 (2.3%) 2 (2.3%) 0 0 5 (6.9%) 5 (6.9%) 0 2 (2.1%) 1 (1%) 3 (3.1%)
Total 0 78 (90.7%) 4 (4.7%) 82 (95.3%) 1 (1.4%) 63 (87.5%) 7 (9.7%) 71 (98.6%) 0 70 (72.9%) 3 (3.1%) 73 (76%)
Week 4 Low 0 0 0 0 1 (1.4%) 0 0 1 (1.4%) 0 0 0 0
Normal 0 70 (81.4%) 1 (1.2%) 71 (82.6%) 0 58 (80.6%) 1 (1.4%) 59 (81.9%) 0 60 (62.5%) 2 (2.1%) 62 (64.6%)
High 0 2 (2.3%) 2 (2.3%) 4 (4.7%) 0 0 6 (8.3%) 6 (8.3%) 0 1 (1%) 1 (1%) 2 (2.1%)
Total 0 72 (83.7%) 3 (3.5%) 75 (87.2%) 1 (1.4%) 58 (80.6%) 7 (9.7%) 66 (91.7%) 0 61 (63.5%) 3 (3.1%) 64 (66.7%)
Week 6 Low 0 0 0 0 0 0 0 0 0 0 0 0
Normal 0 65 (75.6%) 2 (2.3%) 67 (77.9%) 0 47 (65.3%) 1 (1.4%) 48 (66.7%) 0 55 (57.3%) 2 (2.1%) 57 (59.4%)
High 0 2 (2.3%) 2 (2.3%) 4 (4.7%) 0 0 6 (8.3%) 6 (8.3%) 0 0 1 (1%) 1 (1%)
Total 0 67 (77.9%) 4 (4.7%) 71 (82.6%) 0 47 (65.3%) 7 (9.7%) 54 (75%) 0 55 (57.3%) 3 (3.1%) 58 (60.4%)
Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY
N: Number of subjects in the full safety analysis set, within each treatment group
n: Subjects with at least one baseline and post-baseline records
Table x.x
Shift Table of Lab Hematology
(Full Safety Analysis Set)
Parameter = Hematocrit (1)
Analysis Visit Reference
Range
Placebo
(N=86)
Baseline
n (%)
Xanomeline High Dose
(N=72)
Baseline
n (%)
Xanomeline Low Dose
(N=96)
Baseline
n (%)
Low Normal High Total Low Normal High Total Low Normal High Total
Week 2 Low 0 0 0 0 1 (1.4%) 0 0 1 (1.4%) 1 (1%) 2 (2.1%) 0 3 (3.1%)
Normal 3 (3.5%) 79 (91.9%) 0 82 (95.3%) 0 66 (91.7%) 2 (2.8%) 68 (94.4%) 0 67 (69.8%) 1 (1%) 68 (70.8%)
High 0 0 0 0 0 1 (1.4%) 0 1 (1.4%) 0 0 1 (1%) 1 (1%)
Total 3 (3.5%) 79 (91.9%) 0 82 (95.3%) 1 (1.4%) 67 (93.1%) 2 (2.8%) 70 (97.2%) 1 (1%) 69 (71.9%) 2 (2.1%) 72 (75%)
Week 4 Low 3 (3.5%) 0 0 3 (3.5%) 0 0 0 0 1 (1%) 2 (2.1%) 0 3 (3.1%)
Normal 0 71 (82.6%) 0 71 (82.6%) 1 (1.4%) 61 (84.7%) 2 (2.8%) 64 (88.9%) 1 (1%) 58 (60.4%) 1 (1%) 60 (62.5%)
High 0 0 0 0 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 3 (3.5%) 71 (82.6%) 0 74 (86%) 1 (1.4%) 62 (86.1%) 2 (2.8%) 65 (90.3%) 2 (2.1%) 60 (62.5%) 1 (1%) 63 (65.6%)
Week 6 Low 2 (2.3%) 1 (1.2%) 0 3 (3.5%) 1 (1.4%) 0 0 1 (1.4%) 1 (1%) 1 (1%) 0 2 (2.1%)
Normal 0 66 (76.7%) 0 66 (76.7%) 0 50 (69.4%) 2 (2.8%) 52 (72.2%) 1 (1%) 52 (54.2%) 1 (1%) 54 (56.2%)
High 0 1 (1.2%) 0 1 (1.2%) 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 2 (2.3%) 68 (79.1%) 0 70 (81.4%) 1 (1.4%) 51 (70.8%) 2 (2.8%) 54 (75%) 2 (2.1%) 53 (55.2%) 1 (1%) 56 (58.3%)
Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY
N: Number of subjects in the full safety analysis set, within each treatment group
n: Subjects with at least one baseline and post-baseline records
Table x.x
Shift Table of Lab Hematology
(Full Safety Analysis Set)
Parameter = Platelet (10^9/L)
Analysis Visit Reference
Range
Placebo
(N=86)
Baseline
n (%)
Xanomeline High Dose
(N=72)
Baseline
n (%)
Xanomeline Low Dose
(N=96)
Baseline
n (%)
Low Normal High Total Low Normal High Total Low Normal High Total
Week 2 Low 0 0 0 0 1 (1.4%) 0 0 1 (1.4%) 0 0 0 0
Normal 0 80 (93%) 1 (1.2%) 81 (94.2%) 0 70 (97.2%) 0 70 (97.2%) 1 (1%) 66 (68.8%) 1 (1%) 68 (70.8%)
High 0 0 1 (1.2%) 1 (1.2%) 0 0 0 0 0 2 (2.1%) 0 2 (2.1%)
Total 0 80 (93%) 2 (2.3%) 82 (95.3%) 1 (1.4%) 70 (97.2%) 0 71 (98.6%) 1 (1%) 68 (70.8%) 1 (1%) 70 (72.9%)
Week 4 Low 0 0 0 0 0 0 0 0 1 (1%) 0 0 1 (1%)
Normal 0 72 (83.7%) 0 72 (83.7%) 0 65 (90.3%) 0 65 (90.3%) 0 61 (63.5%) 1 (1%) 62 (64.6%)
High 0 0 2 (2.3%) 2 (2.3%) 0 0 0 0 0 0 0 0
Total 0 72 (83.7%) 2 (2.3%) 74 (86%) 0 65 (90.3%) 0 65 (90.3%) 1 (1%) 61 (63.5%) 1 (1%) 63 (65.6%)
Week 6 Low 0 0 0 0 0 0 0 0 1 (1%) 0 0 1 (1%)
Normal 0 69 (80.2%) 1 (1.2%) 70 (81.4%) 0 53 (73.6%) 0 53 (73.6%) 0 56 (58.3%) 1 (1%) 57 (59.4%)
High 0 0 1 (1.2%) 1 (1.2%) 0 0 0 0 0 0 0 0
Total 0 69 (80.2%) 2 (2.3%) 71 (82.6%) 0 53 (73.6%) 0 53 (73.6%) 1 (1%) 56 (58.3%) 1 (1%) 58 (60.4%)
Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY
N: Number of subjects in the full safety analysis set, within each treatment group
n: Subjects with at least one baseline and post-baseline records

Colorize cells (Optional)

Suppose we want to highlight values which are Normal in Baseline but Low or High in post-baseline

Code
out |>
  data_color(
    columns = contains("Normal"),
    rows = ANRIND %in% c("High", "Low"),
    palette = c("white", "lightpink")
  )
Table x.x
Shift Table of Lab Hematology
(Full Safety Analysis Set)
Parameter = Hemoglobin (mmol/L)
Analysis Visit Reference
Range
Placebo
(N=86)
Baseline
n (%)
Xanomeline High Dose
(N=72)
Baseline
n (%)
Xanomeline Low Dose
(N=96)
Baseline
n (%)
Low Normal High Total Low Normal High Total Low Normal High Total
Week 2 Low 4 (4.7%) 2 (2.3%) 0 6 (7%) 1 (1.4%) 3 (4.2%) 0 4 (5.6%) 4 (4.2%) 0 0 4 (4.2%)
Normal 3 (3.5%) 73 (84.9%) 0 76 (88.4%) 0 65 (90.3%) 2 (2.8%) 67 (93.1%) 1 (1%) 67 (69.8%) 1 (1%) 69 (71.9%)
High 0 0 0 0 0 0 0 0 0 0 0 0
Total 7 (8.1%) 75 (87.2%) 0 82 (95.3%) 1 (1.4%) 68 (94.4%) 2 (2.8%) 71 (98.6%) 5 (5.2%) 67 (69.8%) 1 (1%) 73 (76%)
Week 4 Low 4 (4.7%) 2 (2.3%) 0 6 (7%) 1 (1.4%) 0 0 1 (1.4%) 4 (4.2%) 2 (2.1%) 0 6 (6.2%)
Normal 1 (1.2%) 68 (79.1%) 0 69 (80.2%) 0 63 (87.5%) 1 (1.4%) 64 (88.9%) 1 (1%) 57 (59.4%) 0 58 (60.4%)
High 0 0 0 0 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 5 (5.8%) 70 (81.4%) 0 75 (87.2%) 1 (1.4%) 64 (88.9%) 1 (1.4%) 66 (91.7%) 5 (5.2%) 59 (61.5%) 0 64 (66.7%)
Week 6 Low 3 (3.5%) 1 (1.2%) 0 4 (4.7%) 0 1 (1.4%) 0 1 (1.4%) 4 (4.2%) 3 (3.1%) 0 7 (7.3%)
Normal 2 (2.3%) 64 (74.4%) 0 66 (76.7%) 0 51 (70.8%) 1 (1.4%) 52 (72.2%) 1 (1%) 50 (52.1%) 0 51 (53.1%)
High 0 1 (1.2%) 0 1 (1.2%) 0 1 (1.4%) 0 1 (1.4%) 0 0 0 0
Total 5 (5.8%) 66 (76.7%) 0 71 (82.6%) 0 53 (73.6%) 1 (1.4%) 54 (75%) 5 (5.2%) 53 (55.2%) 0 58 (60.4%)
Source: ADLB DDMMYYYY hh:mm; Listing x.xx; SDTM package: DDMMYYYY
N: Number of subjects in the full safety analysis set, within each treatment group
n: Subjects with at least one baseline and post-baseline records

Saving the Table

Code
# as rtf
gtsave(out, "adlb_rxxxx_20240428.rtf", "path to the output directory")
# as pdf
gtsave(out, "adlb_rxxxx_20240428.pdf", "path to the output directory")
# as word
gtsave(out, "adlb_rxxxx_20240428.docx", "path to the output directory")
# as html
gtsave(out, "adlb_rxxxx_20240428.html", "path to the output directory")
Back to top