Skip to contents

These are the canonical safety and efficacy tables a programmer builds from the shell — each one rendered live below from the bundled demo data, so what you see is exactly what the code produces. They mirror the package’s cross-backend qualification (inst/qualification/), which rebuilds the same displays from the real PHUSE Test Data Factory ADaM and checks them across every backend.

Each recipe ends on the spec (the live HTML you see); the closing line shows how to ship the same spec to a submission backend — just change the extension.

Demographics and baseline characteristics

The reference safety table: a usage = "group" parameter stub, indented statistic rows, decimal-aligned arm columns, and the population BigN folded into each header from cdisc_saf_n.

n <- stats::setNames(cdisc_saf_n$n, cdisc_saf_n$arm_short)

demo_tbl <- tabular(
  cdisc_saf_demo,
  titles = c(
    "Table 14.1.1",
    "Demographic and Baseline Characteristics",
    "Safety Population"
  ),
  footnotes = "Percentages are based on the number of subjects per treatment group."
) |>
  cols(
    variable = col_spec(usage = "group", label = "Parameter"),
    stat_label = col_spec(label = "Statistic"),
    placebo = col_spec(
      label = "Placebo\nN={n['placebo']}",
      align = "decimal"
    ),
    drug_50 = col_spec(
      label = "Drug 50\nN={n['drug_50']}",
      align = "decimal"
    ),
    drug_100 = col_spec(
      label = "Drug 100\nN={n['drug_100']}",
      align = "decimal"
    ),
    Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal")
  )

demo_tbl

 

Table 14.1.1

Demographic and Baseline Characteristics

Safety Population

 

Statistic Placebo
N=86
Drug 50
N=96
Drug 100
N=72
Total
N=254
Age (years)
n 86          96          72          254         
Mean (SD) 75.2 (8.59) 76.0 (8.11) 73.8 (7.94)  75.1 (8.25)
Median 76.0        78.0        75.5         77.0       
Q1, Q3 69.2, 81.8  71.0, 82.0  70.5, 79.0   70.0, 81.0 
Min, Max 52  , 89    51  , 88    56  , 88     51  , 89   
 
Sex, n (%)
F 53 (61.6)   55 (57.3)   35 (48.6)   143 (56.3)  
M 33 (38.4)   41 (42.7)   37 (51.4)   111 (43.7)  
 
Race, n (%)
WHITE 78 (90.7)   90 (93.8)   62 (86.1)   230 (90.6)  
BLACK OR AFRICAN AMERICAN  8 ( 9.3)    6 ( 6.2)    9 (12.5)    23 ( 9.1)  
ASIAN  0           0           0            0         
AMERICAN INDIAN OR ALASKA NATIVE  0           0           1 ( 1.4)     1 ( 0.4)  

Percentages are based on the number of subjects per treatment group.

emit(demo_tbl, "t_14_1_1.rtf") # ship: or .pdf / .docx / .html / .md

Adverse-event overview

A flat overview: stat_label is a plain display column carrying both the high-level flag rows and the two-space-indented maximum-severity detail rows (the indent is baked into the label strings), so each category sits on one line with its counts.

ae_tbl <- tabular(
  cdisc_saf_ae,
  titles = c(
    "Table 14.3.0",
    "Overview of Treatment-Emergent Adverse Events",
    "Safety Population"
  )
) |>
  cols(
    stat_label = col_spec(label = ""),
    placebo = col_spec(
      label = "Placebo\nN={n['placebo']}",
      align = "decimal"
    ),
    drug_50 = col_spec(
      label = "Drug 50\nN={n['drug_50']}",
      align = "decimal"
    ),
    drug_100 = col_spec(
      label = "Drug 100\nN={n['drug_100']}",
      align = "decimal"
    ),
    Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal")
  )

ae_tbl

 

Table 14.3.0

Overview of Treatment-Emergent Adverse Events

Safety Population

 

Placebo
N=86
Drug 50
N=96
Drug 100
N=72
Total
N=254
Any TEAE 65 (75.6) 84 (87.5) 68 (94.4) 217 (85.4)
Any Serious AE (SAE)  0         2 ( 2.1)  1 ( 1.4)   3 ( 1.2)
Any AE Related to Study Drug 43 (50.0) 77 (80.2) 64 (88.9) 184 (72.4)
Any AE Leading to Death  2 ( 2.3)  1 ( 1.0)  0          3 ( 1.2)
Any AE Recovered / Resolved 47 (54.7) 61 (63.5) 49 (68.1) 157 (61.8)
  Maximum severity: Mild 36 (41.9) 21 (21.9) 20 (27.8)  77 (30.3)
  Maximum severity: Moderate 24 (27.9) 47 (49.0) 40 (55.6) 111 (43.7)
  Maximum severity: Severe  5 ( 5.8) 16 (16.7)  8 (11.1)  29 (11.4)
emit(ae_tbl, "t_14_3_0.rtf") # ship: or .pdf / .docx / .html / .md

Adverse events by SOC and preferred term

The two-level hierarchy: label holds SOC text on SOC rows and PT text on PT rows, indented by indent_level; the hidden soc / row_type / n_total / soc_n columns ride along as partition and sort keys. sort_rows() clusters PTs under their parent SOC and orders both levels by descending frequency.

aesocpt_tbl <- tabular(
  cdisc_saf_aesocpt,
  titles = c(
    "Table 14.3.1",
    "Adverse Events by System Organ Class and Preferred Term",
    "Safety Population"
  )
) |>
  cols(
    label = col_spec(
      label = "SOC / Preferred Term",
      indent = "indent_level"
    ),
    soc = col_spec(visible = FALSE),
    row_type = col_spec(visible = FALSE),
    n_total = col_spec(visible = FALSE),
    soc_n = col_spec(visible = FALSE),
    placebo = col_spec(
      label = "Placebo\nN={n['placebo']}",
      align = "decimal"
    ),
    drug_50 = col_spec(
      label = "Drug 50\nN={n['drug_50']}",
      align = "decimal"
    ),
    drug_100 = col_spec(
      label = "Drug 100\nN={n['drug_100']}",
      align = "decimal"
    ),
    Total = col_spec(label = "Total\nN={n['Total']}", align = "decimal")
  ) |>
  sort_rows(by = c("soc_n", "n_total"), descending = c(TRUE, TRUE))

aesocpt_tbl

 

Table 14.3.1

Adverse Events by System Organ Class and Preferred Term

Safety Population

 

SOC / Preferred Term Placebo
N=86
Drug 50
N=96
Drug 100
N=72
Total
N=254
TOTAL SUBJECTS WITH AN EVENT 52 (60.5) 81 (84.4) 66 (91.7) 199 (78.3)
SKIN AND SUBCUTANEOUS TISSUE DISORDERS 19 (22.1) 36 (37.5) 35 (48.6)  90 (35.4)
PRURITUS  8 ( 9.3) 21 (21.9) 25 (34.7)  54 (21.3)
ERYTHEMA  8 ( 9.3) 14 (14.6) 14 (19.4)  36 (14.2)
RASH  5 ( 5.8) 13 (13.5)  8 (11.1)  26 (10.2)
HYPERHIDROSIS  2 ( 2.3)  4 ( 4.2)  8 (11.1)  14 ( 5.5)
SKIN IRRITATION  3 ( 3.5)  6 ( 6.2)  5 ( 6.9)  14 ( 5.5)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS 15 (17.4) 36 (37.5) 30 (41.7)  81 (31.9)
APPLICATION SITE PRURITUS  6 ( 7.0) 23 (24.0) 21 (29.2)  50 (19.7)
APPLICATION SITE ERYTHEMA  3 ( 3.5) 13 (13.5) 14 (19.4)  30 (11.8)
APPLICATION SITE DERMATITIS  5 ( 5.8)  9 ( 9.4)  7 ( 9.7)  21 ( 8.3)
APPLICATION SITE IRRITATION  3 ( 3.5)  9 ( 9.4)  9 (12.5)  21 ( 8.3)
APPLICATION SITE VESICLES  1 ( 1.2)  5 ( 5.2)  5 ( 6.9)  11 ( 4.3)
GASTROINTESTINAL DISORDERS 13 (15.1) 12 (12.5) 17 (23.6)  42 (16.5)
DIARRHOEA  9 (10.5)  5 ( 5.2)  3 ( 4.2)  17 ( 6.7)
VOMITING  3 ( 3.5)  4 ( 4.2)  6 ( 8.3)  13 ( 5.1)
NAUSEA  3 ( 3.5)  3 ( 3.1)  6 ( 8.3)  12 ( 4.7)
ABDOMINAL PAIN  1 ( 1.2)  3 ( 3.1)  1 ( 1.4)   5 ( 2.0)
SALIVARY HYPERSECRETION  0         0         4 ( 5.6)   4 ( 1.6)
NERVOUS SYSTEM DISORDERS  6 ( 7.0) 18 (18.8) 17 (23.6)  41 (16.1)
DIZZINESS  2 ( 2.3)  9 ( 9.4) 10 (13.9)  21 ( 8.3)
HEADACHE  3 ( 3.5)  3 ( 3.1)  5 ( 6.9)  11 ( 4.3)
SYNCOPE  0         5 ( 5.2)  2 ( 2.8)   7 ( 2.8)
SOMNOLENCE  2 ( 2.3)  3 ( 3.1)  1 ( 1.4)   6 ( 2.4)
TRANSIENT ISCHAEMIC ATTACK  0         2 ( 2.1)  1 ( 1.4)   3 ( 1.2)
CARDIAC DISORDERS  7 ( 8.1) 12 (12.5) 14 (19.4)  33 (13.0)
SINUS BRADYCARDIA  2 ( 2.3)  7 ( 7.3)  8 (11.1)  17 ( 6.7)
MYOCARDIAL INFARCTION  4 ( 4.7)  2 ( 2.1)  4 ( 5.6)  10 ( 3.9)
ATRIAL FIBRILLATION  1 ( 1.2)  2 ( 2.1)  2 ( 2.8)   5 ( 2.0)
SUPRAVENTRICULAR EXTRASYSTOLES  1 ( 1.2)  1 ( 1.0)  1 ( 1.4)   3 ( 1.2)
VENTRICULAR EXTRASYSTOLES  0         2 ( 2.1)  1 ( 1.4)   3 ( 1.2)
INFECTIONS AND INFESTATIONS 12 (14.0)  6 ( 6.2) 11 (15.3)  29 (11.4)
NASOPHARYNGITIS  2 ( 2.3)  4 ( 4.2)  6 ( 8.3)  12 ( 4.7)
UPPER RESPIRATORY TRACT INFECTION  6 ( 7.0)  1 ( 1.0)  3 ( 4.2)  10 ( 3.9)
INFLUENZA  1 ( 1.2)  1 ( 1.0)  1 ( 1.4)   3 ( 1.2)
URINARY TRACT INFECTION  2 ( 2.3)  0         1 ( 1.4)   3 ( 1.2)
CYSTITIS  1 ( 1.2)  0         1 ( 1.4)   2 ( 0.8)
RESPIRATORY, THORACIC AND MEDIASTINAL DISORDERS  5 ( 5.8)  8 ( 8.3)  9 (12.5)  22 ( 8.7)
COUGH  1 ( 1.2)  5 ( 5.2)  5 ( 6.9)  11 ( 4.3)
NASAL CONGESTION  3 ( 3.5)  1 ( 1.0)  3 ( 4.2)   7 ( 2.8)
DYSPNOEA  1 ( 1.2)  1 ( 1.0)  1 ( 1.4)   3 ( 1.2)
EPISTAXIS  0         1 ( 1.0)  2 ( 2.8)   3 ( 1.2)
PHARYNGOLARYNGEAL PAIN  0         1 ( 1.0)  1 ( 1.4)   2 ( 0.8)
PSYCHIATRIC DISORDERS  7 ( 8.1)  9 ( 9.4)  3 ( 4.2)  19 ( 7.5)
CONFUSIONAL STATE  2 ( 2.3)  3 ( 3.1)  1 ( 1.4)   6 ( 2.4)
AGITATION  2 ( 2.3)  3 ( 3.1)  0          5 ( 2.0)
INSOMNIA  2 ( 2.3)  0         2 ( 2.8)   4 ( 1.6)
ANXIETY  0         3 ( 3.1)  0          3 ( 1.2)
DELUSION  1 ( 1.2)  0         1 ( 1.4)   2 ( 0.8)
MUSCULOSKELETAL AND CONNECTIVE TISSUE DISORDERS  3 ( 3.5)  6 ( 6.2)  5 ( 6.9)  14 ( 5.5)
BACK PAIN  1 ( 1.2)  1 ( 1.0)  3 ( 4.2)   5 ( 2.0)
ARTHRALGIA  1 ( 1.2)  2 ( 2.1)  1 ( 1.4)   4 ( 1.6)
SHOULDER PAIN  1 ( 1.2)  2 ( 2.1)  0          3 ( 1.2)
MUSCLE SPASMS  0         1 ( 1.0)  1 ( 1.4)   2 ( 0.8)
ARTHRITIS  0         0         1 ( 1.4)   1 ( 0.4)
INVESTIGATIONS  5 ( 5.8)  4 ( 4.2)  3 ( 4.2)  12 ( 4.7)
ELECTROCARDIOGRAM ST SEGMENT DEPRESSION  4 ( 4.7)  1 ( 1.0)  0          5 ( 2.0)
ELECTROCARDIOGRAM T WAVE INVERSION  2 ( 2.3)  1 ( 1.0)  1 ( 1.4)   4 ( 1.6)
BLOOD GLUCOSE INCREASED  0         1 ( 1.0)  1 ( 1.4)   2 ( 0.8)
ELECTROCARDIOGRAM T WAVE AMPLITUDE DECREASED  1 ( 1.2)  1 ( 1.0)  0          2 ( 0.8)
BIOPSY  0         0         1 ( 1.4)   1 ( 0.4)

This table is long, so a real deliverable paginates it — keeping each SOC and its preferred terms together. Pagination materialises in the paged backends (RTF, PDF, DOCX), so add paginate() and emit to one of those:

aesocpt_tbl |>
  paginate(keep_together = "soc", continuation = "(continued)") |>
  emit("t_14_3_1.pdf")

Best overall response and response rates

The efficacy companion: group_label synthesises one bold section band per analysis block (best overall response, ORR, CBR, DCR) via header_row, with indented response rows beneath. Denominators come from cdisc_eff_n.

ne <- stats::setNames(cdisc_eff_n$n, cdisc_eff_n$arm_short)

resp_tbl <- tabular(
  cdisc_eff_resp,
  titles = c(
    "Table 14.2.1",
    "Best Overall Response and Response Rates",
    "Efficacy Evaluable Population"
  )
) |>
  cols(
    group_label = col_spec(usage = "group", group_display = "header_row"),
    stat_label = col_spec(label = "Response"),
    groupid = col_spec(visible = FALSE),
    row_type = col_spec(visible = FALSE),
    placebo = col_spec(
      label = "Placebo\nN={ne['placebo']}",
      align = "decimal"
    ),
    drug_50 = col_spec(
      label = "Drug 50\nN={ne['drug_50']}",
      align = "decimal"
    ),
    drug_100 = col_spec(
      label = "Drug 100\nN={ne['drug_100']}",
      align = "decimal"
    )
  )

resp_tbl

 

Table 14.2.1

Best Overall Response and Response Rates

Efficacy Evaluable Population

 

Response Placebo
N=86
Drug 50
N=84
Drug 100
N=84
Best Overall Response
CR  1 ( 1.2)    1 ( 1.2)    1 ( 1.2)  
PR  1 ( 1.2)    0           0         
SD  1 ( 1.2)    0           0         
NON-CR/NON-PD  0           0           1 ( 1.2)  
PD  0           0           1 ( 1.2)  
NE  0           1 ( 1.2)    0         
MISSING 83 (96.5)   82 (97.6)   81 (96.4)  
 
Objective Response Rate
ORR (CR + PR)  2   (2.3)   1   (1.2)   1   (1.2) 
95% CI (Clopper-Pearson) ( 0.3, 8.1) ( 0.0, 6.5) ( 0.0, 6.5)
 
Clinical Benefit Rate
CBR (CR + PR + SD)  3   (3.5)   1   (1.2)   1   (1.2) 
95% CI (Clopper-Pearson) ( 0.7, 9.9) ( 0.0, 6.5) ( 0.0, 6.5)
 
Disease Control Rate
DCR (CR + PR + SD + NON-CR/NON-PD)  3   (3.5)   1   (1.2)   2   (2.4) 
95% CI (Clopper-Pearson) ( 0.7, 9.9) ( 0.0, 6.5) ( 0.3, 8.3)
emit(resp_tbl, "t_14_2_1.rtf") # ship: or .pdf / .docx / .html / .md

See also