library(arframe)
library(ggplot2)
library(survival)
library(pharmaverseadam)
library(dplyr, warn.conflicts = FALSE)
arm_levels <- c("Placebo", "Xanomeline Low Dose", "Xanomeline High Dose")
arm_colors <- c("#1b9e77", "#d95f02", "#7570b3")
pfs <- pharmaverseadam::adtte_onco |>
filter(PARAMCD == "PFS", ARM != "Screen Failure") |>
mutate(
ARM = factor(ARM, levels = arm_levels),
AVAL_MONTHS = AVAL / 30.4375,
EVENT = 1 - CNSR
)Kaplan-Meier Plot
Progression-Free Survival
Setup
See Prerequisites for installation instructions.
Plot Construction
# Fit survival curves
fit <- survfit(Surv(AVAL_MONTHS, EVENT) ~ ARM, data = pfs)
# Build plot data for ggplot2
surv_df <- broom::tidy(fit) |>
mutate(strata = gsub("ARM=", "", strata))
# Number at risk
nar_times <- seq(0, 6, by = 1)
s <- summary(fit, times = nar_times, extend = TRUE)
nar_df <- data.frame(
time = s$time,
strata = gsub("ARM=", "", s$strata),
n.risk = s$n.risk,
stringsAsFactors = FALSE
) |>
mutate(strata = factor(strata, levels = rev(arm_levels)))
# KM curves
p_km <- ggplot(surv_df, aes(x = time, y = estimate, color = strata)) +
geom_step(linewidth = 0.8) +
geom_point(
data = surv_df |> filter(n.censor > 0),
aes(x = time, y = estimate),
shape = 3, size = 2
) +
scale_color_manual(values = setNames(arm_colors, arm_levels)) +
scale_x_continuous(breaks = nar_times, limits = c(0, 6)) +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
labs(x = "Time (Months)", y = "Survival Probability", color = "Treatment") +
theme_minimal(base_size = 11) +
theme(
legend.position = "bottom",
panel.grid.minor = element_blank()
)
# Number at risk table
p_nar <- ggplot(nar_df, aes(x = time, y = strata, label = n.risk)) +
geom_text(size = 3.2) +
scale_x_continuous(breaks = nar_times, limits = c(-0.1, 6.1)) +
labs(x = NULL, y = NULL, title = "Number at Risk") +
theme_minimal(base_size = 10) +
theme(
panel.grid = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_text(size = 8),
plot.title = element_text(size = 10, face = "bold")
)
# Combine with patchwork
km_combined <- patchwork::wrap_plots(p_km, p_nar, ncol = 1, heights = c(4, 1))arframe Pipeline
km_combined |>
fr_figure(width = 7, height = 5.5) |>
fr_titles(
"Figure 14.2.1",
"Kaplan-Meier Plot for Progression-Free Survival",
"Efficacy Population"
) |>
fr_footnotes(
"PFS is calculated from date of first dose to date of disease progression or death.",
"Patients without progression or death are censored at date of last assessment.",
"Censored observations are indicated by + marks."
)Rendered Figure
Figure 14.2.1
Kaplan-Meier Plot for Progression-Free Survival
Efficacy Population
PFS is calculated from date of first dose to date of disease progression or death.
Patients without progression or death are censored at date of last assessment.
Censored observations are indicated by + marks.
/opt/quarto/share/rmd/rmd.R
01APR2026 09:50:26