arframe TFL Gallery
  1. Tables
  2. Enrollment by Country and Site
  • 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. Enrollment by Country and Site

Enrollment by Country and Site

Summary of Enrollment by Country and Investigative Site

Setup

See Prerequisites for installation instructions.

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

# All enrolled subjects (no safety filter — enrollment includes screen failures)
adsl_all <- pharmaverseadam::adsl |>
  blank_to_na() |>
  filter(TRT01A != "Screen Failure")

arm_levels <- c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose")

arm_n <- adsl_all |>
  filter(TRT01A %in% arm_levels) |>
  count(TRT01A) |>
  pull(n, name = TRT01A)
arm_n <- arm_n[arm_levels]

N_total <- sum(arm_n)
n_vec <- c(arm_n, Total = N_total)

Data Preparation

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

# Assign country (CDISCPILOT01 is all USA — use COUNTRY column)
# Group sites under their country for the hierarchical display
adsl_enroll <- adsl_all |>
  filter(TRT01A %in% arm_levels) |>
  mutate(
    COUNTRY = if_else(is.na(COUNTRY) | COUNTRY == "", "USA", COUNTRY),
    site_label = paste0("Site ", SITEID)
  )

# ── Country-level counts ──
country_arm <- adsl_enroll |>
  count(TRT01A, COUNTRY) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, COUNTRY, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

country_total <- adsl_enroll |>
  count(COUNTRY) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(COUNTRY, Total)

country_wide <- left_join(country_arm, country_total, by = "COUNTRY") |>
  mutate(
    country  = COUNTRY,
    site     = COUNTRY,
    row_type = "country",
    .before  = 1
  ) |>
  select(-COUNTRY)

# ── Site-level counts ──
site_arm <- adsl_enroll |>
  count(TRT01A, COUNTRY, site_label) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, COUNTRY, site_label, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

site_total <- adsl_enroll |>
  count(COUNTRY, site_label) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(COUNTRY, site_label, Total)

site_wide <- left_join(site_arm, site_total, by = c("COUNTRY", "site_label")) |>
  mutate(
    country  = COUNTRY,
    site     = site_label,
    row_type = "site",
    .before  = 1
  ) |>
  select(-COUNTRY, -site_label)

# ── Sort: country alphabetical, sites by descending enrollment ──
site_order <- adsl_enroll |>
  count(COUNTRY, site_label, name = "n") |>
  arrange(COUNTRY, desc(n)) |>
  select(country = COUNTRY, site = site_label)

site_wide <- site_order |>
  left_join(site_wide, by = c("country", "site"))

# ── Interleave country + site rows ──
enroll_wide <- bind_rows(
  lapply(sort(unique(adsl_enroll$COUNTRY)), function(cntry) {
    bind_rows(
      filter(country_wide, country == cntry),
      filter(site_wide, country == cntry)
    )
  })
) |>
  mutate(across(all_of(c(arm_levels, "Total")), ~ replace_na(.x, "0 (0.0)")))

arframe Pipeline

The fr_table() pipeline:

enroll_wide |>
  fr_table() |>
  fr_titles(
    "Table 14.1.2",
    "Summary of Enrollment by Country and Investigative Site",
    "Randomized Subjects"
  ) |>
  fr_cols(
    country  = fr_col(visible = FALSE),
    site     = fr_col("Country\n  Site", width = 2.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  = "country",
    indent_by = "site"
  ) |>
  fr_styles(
    fr_row_style(rows = fr_rows_matches("row_type", value = "country"), bold = TRUE)
  ) |>
  fr_footnotes(
    "Percentages based on total number of randomized subjects.",
    "Subjects who were screen failures are excluded.",
    "Sites sorted by descending enrollment count within each country."
  )

Rendered Table

Table 14.1.2
Summary of Enrollment by Country and Investigative Site
Randomized Subjects
Country
Site
Placebo
(N=86)
Xanomeline High Dose
(N=72)
Xanomeline Low Dose
(N=96)
Total
(N=254)
USA86 (100.0)72 (100.0)96 (100.0)254 (100.0)
Site 70114 ( 16.3)12 ( 16.7)15 ( 15.6) 41 ( 16.1)
Site 71011 ( 12.8)10 ( 13.9)10 ( 10.4) 31 ( 12.2)
Site 704 9 ( 10.5) 8 ( 11.1) 8 ( 8.3) 25 ( 9.8)
Site 708 9 ( 10.5) 5 ( 6.9)11 ( 11.5) 25 ( 9.8)
Site 716 8 ( 9.3) 7 ( 9.7) 9 ( 9.4) 24 ( 9.4)
Site 709 7 ( 8.1) 5 ( 6.9) 9 ( 9.4) 21 ( 8.3)
Site 703 6 ( 7.0) 5 ( 6.9) 7 ( 7.3) 18 ( 7.1)
Site 705 5 ( 5.8) 5 ( 6.9) 6 ( 6.2) 16 ( 6.3)
Site 718 4 ( 4.7) 4 ( 5.6) 5 ( 5.2) 13 ( 5.1)
Site 713 3 ( 3.5) 3 ( 4.2) 3 ( 3.1) 9 ( 3.5)
Site 715 3 ( 3.5) 2 ( 2.8) 3 ( 3.1) 8 ( 3.1)
Site 717 2 ( 2.3) 3 ( 4.2) 2 ( 2.1) 7 ( 2.8)
Site 714 2 ( 2.3) 1 ( 1.4) 3 ( 3.1) 6 ( 2.4)
Site 711 1 ( 1.2) 1 ( 1.4) 2 ( 2.1) 4 ( 1.6)
Site 706 1 ( 1.2) 1 ( 1.4) 1 ( 1.0) 3 ( 1.2)
Site 707 1 ( 1.2) 0 1 ( 1.0) 2 ( 0.8)
Site 702 0 0 1 ( 1.0) 1 ( 0.4)
Percentages based on total number of randomized subjects.
Subjects who were screen failures are excluded.
Sites sorted by descending enrollment count within each country.
/opt/quarto/share/rmd/rmd.R 01APR2026 09:53:04
Source Code
---
title: "Enrollment by Country and Site"
subtitle: "Summary of Enrollment by Country and Investigative Site"
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)

# All enrolled subjects (no safety filter — enrollment includes screen failures)
adsl_all <- pharmaverseadam::adsl |>
  blank_to_na() |>
  filter(TRT01A != "Screen Failure")

arm_levels <- c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose")

arm_n <- adsl_all |>
  filter(TRT01A %in% arm_levels) |>
  count(TRT01A) |>
  pull(n, name = TRT01A)
arm_n <- arm_n[arm_levels]

N_total <- sum(arm_n)
n_vec <- c(arm_n, Total = N_total)
```


## Data Preparation

```{r}
#| label: data-prep

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

# Assign country (CDISCPILOT01 is all USA — use COUNTRY column)
# Group sites under their country for the hierarchical display
adsl_enroll <- adsl_all |>
  filter(TRT01A %in% arm_levels) |>
  mutate(
    COUNTRY = if_else(is.na(COUNTRY) | COUNTRY == "", "USA", COUNTRY),
    site_label = paste0("Site ", SITEID)
  )

# ── Country-level counts ──
country_arm <- adsl_enroll |>
  count(TRT01A, COUNTRY) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, COUNTRY, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

country_total <- adsl_enroll |>
  count(COUNTRY) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(COUNTRY, Total)

country_wide <- left_join(country_arm, country_total, by = "COUNTRY") |>
  mutate(
    country  = COUNTRY,
    site     = COUNTRY,
    row_type = "country",
    .before  = 1
  ) |>
  select(-COUNTRY)

# ── Site-level counts ──
site_arm <- adsl_enroll |>
  count(TRT01A, COUNTRY, site_label) |>
  mutate(value = mapply(n_pct, n, arm_n[TRT01A])) |>
  select(TRT01A, COUNTRY, site_label, value) |>
  pivot_wider(names_from = TRT01A, values_from = value)

site_total <- adsl_enroll |>
  count(COUNTRY, site_label) |>
  mutate(Total = n_pct(n, N_total)) |>
  select(COUNTRY, site_label, Total)

site_wide <- left_join(site_arm, site_total, by = c("COUNTRY", "site_label")) |>
  mutate(
    country  = COUNTRY,
    site     = site_label,
    row_type = "site",
    .before  = 1
  ) |>
  select(-COUNTRY, -site_label)

# ── Sort: country alphabetical, sites by descending enrollment ──
site_order <- adsl_enroll |>
  count(COUNTRY, site_label, name = "n") |>
  arrange(COUNTRY, desc(n)) |>
  select(country = COUNTRY, site = site_label)

site_wide <- site_order |>
  left_join(site_wide, by = c("country", "site"))

# ── Interleave country + site rows ──
enroll_wide <- bind_rows(
  lapply(sort(unique(adsl_enroll$COUNTRY)), function(cntry) {
    bind_rows(
      filter(country_wide, country == cntry),
      filter(site_wide, country == cntry)
    )
  })
) |>
  mutate(across(all_of(c(arm_levels, "Total")), ~ replace_na(.x, "0 (0.0)")))
```


## arframe Pipeline

The `fr_table()` pipeline:

```{r}
#| label: pipeline
#| eval: false
enroll_wide |>
  fr_table() |>
  fr_titles(
    "Table 14.1.2",
    "Summary of Enrollment by Country and Investigative Site",
    "Randomized Subjects"
  ) |>
  fr_cols(
    country  = fr_col(visible = FALSE),
    site     = fr_col("Country\n  Site", width = 2.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  = "country",
    indent_by = "site"
  ) |>
  fr_styles(
    fr_row_style(rows = fr_rows_matches("row_type", value = "country"), bold = TRUE)
  ) |>
  fr_footnotes(
    "Percentages based on total number of randomized subjects.",
    "Subjects who were screen failures are excluded.",
    "Sites sorted by descending enrollment count within each country."
  )
```


## Rendered Table

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

Open-source TFL reference collection

 

CDISC Pilot Study (CDISCPILOT01) • pharmaverseadam datasets