arframe TFL Gallery
  1. Tables
  2. Prior Medication
  • Getting Started
    • Installation

  • Tables
    • Study Conduct
    • Enrollment by Country and Site

    • Study Population
    • Demographics Summary
    • Medical History
    • Prior Medication
    • Disposition Summary
    • Analysis Populations

    • Extent of Exposure
    • Concomitant Medications
    • Extent of Exposure

    • Safety
    • Adverse Events by System Organ Class and Preferred Term
    • AEs Related to Study Drug
    • Common Adverse Events
    • Adverse Events by Grade / Intensity
    • Overall Safety Summary
    • Adverse Events with Event Counts
    • Exposure-Adjusted Adverse Events
    • Adverse Events by Subgroup
    • Serious Adverse Events by SOC and PT
    • AEs Leading to Study Drug Discontinuation
    • Death Summary
    • Vital Signs
    • Laboratory Results - Chemistry
    • Laboratory Shift Table
    • Laboratory Worst Toxicity Grade
    • Laboratory Marked Abnormalities
    • Electrocardiogram Summary

    • Efficacy
    • Time to Event Summary
    • Best Overall Response

  • Listings
    • Adverse Event Listing
    • Demographic Characteristics Listing
    • Medical History Listing
    • Vital Signs Listing
    • Laboratory Test Results Listing
    • Concomitant Medications Listing

  • Figures
    • Kaplan-Meier Plot
    • Swimmer Plot
    • Waterfall Plot

On this page

  • Setup
  • Data Preparation
  • arframe Pipeline
  • Rendered Table
  1. Tables
  2. Prior Medication

Prior Medication

Summary of Prior Medications by Medication Class and Preferred Name

Setup

See Prerequisites for installation instructions.

library(arframe)
library(pharmaverseadam)
library(dplyr, warn.conflicts = FALSE)
library(tidyr)
library(cards)

adsl_saf <- pharmaverseadam::adsl |>
  blank_to_na() |>
  filter(SAFFL == "Y", TRT01A != "Screen Failure")

# Prior medications: PREFL == "Y", exclude UNCODED
adcm_prior <- pharmaverseadam::adcm |>
  blank_to_na() |>
  filter(SAFFL == "Y", PREFL == "Y", !is.na(CMCLAS), CMCLAS != "UNCODED")

arm_levels <- c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose")
arm_n <- adsl_saf |>
  filter(TRT01A %in% arm_levels) |>
  count(TRT01A) |> pull(n, name = TRT01A)
arm_n <- arm_n[arm_levels]
N_total <- nrow(adsl_saf)
n_vec <- c(arm_n, Total = N_total)

Data Preparation

  • dplyr
  • cards
n_pct <- function(n, denom) sprintf("%d (%.1f)", n, n / denom * 100)

# ── Overall row ──
any_prior_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A) |>
  count(TRT01A) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

any_prior_total <- n_distinct(adcm_prior$USUBJID)

any_prior_row <- bind_cols(
  tibble(cls = "ANY PRIOR MEDICATION", drug = "ANY PRIOR MEDICATION",
         row_type = "overall"),
  any_prior_arm,
  tibble(Total = n_pct(any_prior_total, N_total))
)

# ── Class-level (CMCLAS) ──
cls_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A, CMCLAS) |>
  count(TRT01A, CMCLAS) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, CMCLAS, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

cls_total <- adcm_prior |>
  distinct(USUBJID, CMCLAS) |>
  count(CMCLAS) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(CMCLAS, Total)

cls_wide <- left_join(cls_arm, cls_total, by = "CMCLAS") |>
  mutate(cls = CMCLAS, drug = CMCLAS, row_type = "class", .before = 1) |>
  select(-CMCLAS)

# ── Drug-level (CMDECOD) ──
drug_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A, CMCLAS, CMDECOD) |>
  count(TRT01A, CMCLAS, CMDECOD) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, CMCLAS, CMDECOD, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

drug_total <- adcm_prior |>
  distinct(USUBJID, CMCLAS, CMDECOD) |>
  count(CMCLAS, CMDECOD) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(CMCLAS, CMDECOD, Total)

drug_wide <- left_join(drug_arm, drug_total, by = c("CMCLAS", "CMDECOD")) |>
  mutate(cls = CMCLAS, drug = CMDECOD, row_type = "drug", .before = 1) |>
  select(-CMCLAS, -CMDECOD)

# ── Sort: class alphabetical, drugs within class by frequency ──
cls_order <- sort(unique(cls_wide$cls))

prior_med_wide <- bind_rows(
  any_prior_row,
  bind_rows(lapply(cls_order, function(c) {
    bind_rows(
      filter(cls_wide, cls == c),
      filter(drug_wide, cls == c) |>
        left_join(
          adcm_prior |> distinct(USUBJID, CMCLAS, CMDECOD) |>
            count(CMCLAS, CMDECOD, name = "drug_n"),
          by = c("cls" = "CMCLAS", "drug" = "CMDECOD")
        ) |> arrange(desc(drug_n)) |> select(-drug_n)
    )
  }))
) |>
  mutate(across(where(is.character) & !c(cls, drug, row_type),
                ~ replace_na(.x, "0 (0.0)")))
prior_ard <- ard_stack_hierarchical(
  data        = adcm_prior,
  variables   = c(CMCLAS, CMDECOD),
  by          = TRT01A,
  denominator = adsl_saf,
  id          = USUBJID,
  overall     = TRUE,
  over_variables = TRUE
) |>
  sort_ard_hierarchical(sort = "descending")

prior_med_cards <- fr_wide_ard(
  prior_ard,
  statistic = "{n} ({p}%)",
  decimals  = c(p = 1),
  label     = c(
    "..ard_hierarchical_overall.." = "ANY PRIOR MEDICATION",
    CMCLAS  = "Medication Class",
    CMDECOD = "Preferred Name"
  )
)

arframe Pipeline

prior_med_wide |>
  fr_table() |>
  fr_titles(
    "Table 14.1.8",
    "Summary of Prior Medications",
    "by Medication Class and Preferred Name",
    "Safety Population"
  ) |>
  fr_cols(
    cls      = fr_col(visible = FALSE),
    drug     = fr_col("Medication Class\n  Preferred Name", width = 3.5),
    row_type = fr_col(visible = FALSE),
    !!!setNames(
      lapply(arm_levels, function(a) fr_col(a, align = "decimal")),
      arm_levels
    ),
    Total = fr_col("Total", align = "decimal"),
    .n = n_vec
  ) |>
  fr_header(bold = TRUE, align = "center") |>
  fr_rows(group_by = "cls", indent_by = "drug") |>
  fr_styles(
    fr_row_style(rows = fr_rows_matches("row_type", value = "class"), bold = TRUE),
    fr_row_style(rows = fr_rows_matches("row_type", value = "overall"), bold = TRUE)
  ) |>
  fr_footnotes(
    "Prior medication: any medication started before first dose of study drug.",
    "Subjects counted once per medication class and once per preferred name.",
    "Percentages based on N per treatment arm (Safety Population).",
    "UNCODED medications excluded."
  )

Rendered Table

Table 14.1.8
Summary of Prior Medications
by Medication Class and Preferred Name
Safety Population
Medication Class
Preferred Name
Placebo
(N=86)
Xanomeline High Dose
(N=72)
Xanomeline Low Dose
(N=96)
Total
(N=254)
ANY PRIOR MEDICATION38 (44.2)18 (25.0)35 (36.5)91 (35.8)
ALIMENTARY TRACT AND METABOLISM10 (11.6) 8 (11.1)10 (10.4)28 (11.0)
CALCIUM 7 ( 8.1) 3 ( 4.2) 6 ( 6.2)16 ( 6.3)
NIZATIDINE 1 ( 1.2) 4 ( 5.6) 0 5 ( 2.0)
METFORMIN HYDROCHLORIDE 1 ( 1.2) 0 1 ( 1.0) 2 ( 0.8)
SIMETICONE 0 0 2 ( 2.1) 2 ( 0.8)
ALGELDRATE 1 ( 1.2) 0 0 1 ( 0.4)
CALCIUM CARBONATE 0 1 ( 1.4) 0 1 ( 0.4)
LOPERAMIDE HYDROCHLORIDE 0 0 1 ( 1.0) 1 ( 0.4)
ANTINEOPLASTIC AND IMMUNOMODULATING AGENTS 1 ( 1.2) 0 0 1 ( 0.4)
LEUPRORELIN ACETATE 1 ( 1.2) 0 0 1 ( 0.4)
BLOOD AND BLOOD FORMING ORGANS 0 0 1 ( 1.0) 1 ( 0.4)
FERROUS SULFATE 0 0 1 ( 1.0) 1 ( 0.4)
CARDIOVASCULAR SYSTEM 9 (10.5) 3 ( 4.2)11 (11.5)23 ( 9.1)
AMLODIPINE 5 ( 5.8) 2 ( 2.8) 1 ( 1.0) 8 ( 3.1)
DIGOXIN 0 1 ( 1.4) 4 ( 4.2) 5 ( 2.0)
FUROSEMIDE 1 ( 1.2) 0 2 ( 2.1) 3 ( 1.2)
DOXAZOSIN MESILATE 1 ( 1.2) 0 1 ( 1.0) 2 ( 0.8)
NIFEDIPINE 2 ( 2.3) 0 0 2 ( 0.8)
FLUVASTATIN 0 0 2 ( 2.1) 2 ( 0.8)
FELODIPINE 0 0 1 ( 1.0) 1 ( 0.4)
LOSARTAN POTASSIUM 0 0 1 ( 1.0) 1 ( 0.4)
GENITO URINARY SYSTEM AND SEX HORMONES 6 ( 7.0) 4 ( 5.6)10 (10.4)20 ( 7.9)
ESTROGENS CONJUGATED 6 ( 7.0) 4 ( 5.6)10 (10.4)20 ( 7.9)
NERVOUS SYSTEM20 (23.3) 5 ( 6.9)10 (10.4)35 (13.8)
ACETYLSALICYLIC ACID19 (22.1) 5 ( 6.9)10 (10.4)34 (13.4)
ALPRAZOLAM 1 ( 1.2) 0 0 1 ( 0.4)
SUMATRIPTAN 1 ( 1.2) 0 0 1 ( 0.4)
RESPIRATORY SYSTEM 3 ( 3.5) 3 ( 4.2) 0 6 ( 2.4)
NAPROXEN SODIUM 1 ( 1.2) 3 ( 4.2) 0 4 ( 1.6)
SALBUTAMOL SULFATE 2 ( 2.3) 0 0 2 ( 0.8)
IPRATROPIUM BROMIDE 1 ( 1.2) 0 0 1 ( 0.4)
Prior medication: any medication started before first dose of study drug.
Subjects counted once per medication class and once per preferred name.
Percentages based on N per treatment arm (Safety Population).
UNCODED medications excluded.
/opt/quarto/share/rmd/rmd.R 01APR2026 09:54:23
Source Code
---
title: "Prior Medication"
subtitle: "Summary of Prior Medications by Medication Class and Preferred Name"
execute:
  echo: true
  eval: true
---


```{r}
#| label: prereqs
#| include: false
library(arframe)
fr_theme(hlines = "header", font_family = "Courier New")

blank_to_na <- function(df) {
  df[] <- lapply(df, function(x) {
    if (is.character(x)) x[x == ""] <- NA_character_
    x
  })
  df
}
```

## Setup

See [Prerequisites](../install.qmd) for installation instructions.

```{r}
#| label: setup
library(arframe)
library(pharmaverseadam)
library(dplyr, warn.conflicts = FALSE)
library(tidyr)
library(cards)

adsl_saf <- pharmaverseadam::adsl |>
  blank_to_na() |>
  filter(SAFFL == "Y", TRT01A != "Screen Failure")

# Prior medications: PREFL == "Y", exclude UNCODED
adcm_prior <- pharmaverseadam::adcm |>
  blank_to_na() |>
  filter(SAFFL == "Y", PREFL == "Y", !is.na(CMCLAS), CMCLAS != "UNCODED")

arm_levels <- c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose")
arm_n <- adsl_saf |>
  filter(TRT01A %in% arm_levels) |>
  count(TRT01A) |> pull(n, name = TRT01A)
arm_n <- arm_n[arm_levels]
N_total <- nrow(adsl_saf)
n_vec <- c(arm_n, Total = N_total)
```


## Data Preparation

::: {.panel-tabset}

### dplyr

```{r}
#| label: dplyr-code

n_pct <- function(n, denom) sprintf("%d (%.1f)", n, n / denom * 100)

# ── Overall row ──
any_prior_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A) |>
  count(TRT01A) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

any_prior_total <- n_distinct(adcm_prior$USUBJID)

any_prior_row <- bind_cols(
  tibble(cls = "ANY PRIOR MEDICATION", drug = "ANY PRIOR MEDICATION",
         row_type = "overall"),
  any_prior_arm,
  tibble(Total = n_pct(any_prior_total, N_total))
)

# ── Class-level (CMCLAS) ──
cls_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A, CMCLAS) |>
  count(TRT01A, CMCLAS) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, CMCLAS, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

cls_total <- adcm_prior |>
  distinct(USUBJID, CMCLAS) |>
  count(CMCLAS) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(CMCLAS, Total)

cls_wide <- left_join(cls_arm, cls_total, by = "CMCLAS") |>
  mutate(cls = CMCLAS, drug = CMCLAS, row_type = "class", .before = 1) |>
  select(-CMCLAS)

# ── Drug-level (CMDECOD) ──
drug_arm <- adcm_prior |>
  distinct(USUBJID, TRT01A, CMCLAS, CMDECOD) |>
  count(TRT01A, CMCLAS, CMDECOD) |>
  filter(TRT01A %in% arm_levels) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, CMCLAS, CMDECOD, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

drug_total <- adcm_prior |>
  distinct(USUBJID, CMCLAS, CMDECOD) |>
  count(CMCLAS, CMDECOD) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(CMCLAS, CMDECOD, Total)

drug_wide <- left_join(drug_arm, drug_total, by = c("CMCLAS", "CMDECOD")) |>
  mutate(cls = CMCLAS, drug = CMDECOD, row_type = "drug", .before = 1) |>
  select(-CMCLAS, -CMDECOD)

# ── Sort: class alphabetical, drugs within class by frequency ──
cls_order <- sort(unique(cls_wide$cls))

prior_med_wide <- bind_rows(
  any_prior_row,
  bind_rows(lapply(cls_order, function(c) {
    bind_rows(
      filter(cls_wide, cls == c),
      filter(drug_wide, cls == c) |>
        left_join(
          adcm_prior |> distinct(USUBJID, CMCLAS, CMDECOD) |>
            count(CMCLAS, CMDECOD, name = "drug_n"),
          by = c("cls" = "CMCLAS", "drug" = "CMDECOD")
        ) |> arrange(desc(drug_n)) |> select(-drug_n)
    )
  }))
) |>
  mutate(across(where(is.character) & !c(cls, drug, row_type),
                ~ replace_na(.x, "0 (0.0)")))
```

### cards

```{r}
#| label: cards-code
prior_ard <- ard_stack_hierarchical(
  data        = adcm_prior,
  variables   = c(CMCLAS, CMDECOD),
  by          = TRT01A,
  denominator = adsl_saf,
  id          = USUBJID,
  overall     = TRUE,
  over_variables = TRUE
) |>
  sort_ard_hierarchical(sort = "descending")

prior_med_cards <- fr_wide_ard(
  prior_ard,
  statistic = "{n} ({p}%)",
  decimals  = c(p = 1),
  label     = c(
    "..ard_hierarchical_overall.." = "ANY PRIOR MEDICATION",
    CMCLAS  = "Medication Class",
    CMDECOD = "Preferred Name"
  )
)
```

:::


## arframe Pipeline

```{r}
#| label: pipeline
#| eval: false
prior_med_wide |>
  fr_table() |>
  fr_titles(
    "Table 14.1.8",
    "Summary of Prior Medications",
    "by Medication Class and Preferred Name",
    "Safety Population"
  ) |>
  fr_cols(
    cls      = fr_col(visible = FALSE),
    drug     = fr_col("Medication Class\n  Preferred Name", width = 3.5),
    row_type = fr_col(visible = FALSE),
    !!!setNames(
      lapply(arm_levels, function(a) fr_col(a, align = "decimal")),
      arm_levels
    ),
    Total = fr_col("Total", align = "decimal"),
    .n = n_vec
  ) |>
  fr_header(bold = TRUE, align = "center") |>
  fr_rows(group_by = "cls", indent_by = "drug") |>
  fr_styles(
    fr_row_style(rows = fr_rows_matches("row_type", value = "class"), bold = TRUE),
    fr_row_style(rows = fr_rows_matches("row_type", value = "overall"), bold = TRUE)
  ) |>
  fr_footnotes(
    "Prior medication: any medication started before first dose of study drug.",
    "Subjects counted once per medication class and once per preferred name.",
    "Percentages based on N per treatment arm (Safety Population).",
    "UNCODED medications excluded."
  )
```


## Rendered Table

```{r}
#| label: table
#| echo: false
#| ref.label: pipeline
```

Open-source TFL reference collection

 

CDISC Pilot Study (CDISCPILOT01) • pharmaverseadam datasets