My Main Pipeline

How everything runs in main.R

Published

March 13, 2026

The entire internship workflow can be launched from a single file, main.R, which executes the full pipeline.
In this article, I walk through how the pipeline is structured and how each component contributes to the final sample size comparison results.

Code
# Initialisation ----
source("R/init.R")

cli::boxx(
  "SSC",
  float = "center",
  col = "blue",
  border_style = "double",
  padding = c(0, 15, 0, 15)
)

# Survival sample size comparison ----
cli::cli_h1("SSC Survival")
source("R/comp_surv_fixed.R")
source("R/lakatos_n_lan.R")
source("R/comp_surv_gs.R")
source("R/comp_surv_one_arm.R")

# Binary sample size comparison ----
cli::cli_h1("SSC Binary")
source("R/comp_bin_fixed_pooled.R")
source("R/comp_bin_fixed_exact.R")
source("R/comp_bin_gs.R")
source("R/comp_bin_one_arm.R")
source("R/comp_bin_one_arm_exact.R")

# Write results
write_rds(ssc, "ssc.rds")

Initialisation

The init.R file is the first script that runs. It prepares everything needed for the rest of the pipeline:

Code
# load packages
suppressPackageStartupMessages(suppressWarnings({
  library(S7)
  library(gt)
  library(cli)
  library(rlang)
  library(tidyverse)
}))

# Error rate 
er_rate <- 0.1 # error rate 10%

# List to export
ssc <- lst()
wrapper <- lst()

# Source functions
## Intermediate functions
source("R/functions/checks.R")
source("R/functions/n_ratio.R")
source("R/functions/e_ratio.R")
source("R/functions/helpers.R")
source("R/functions/evaluate_relevancy.R")

# Wrappers
source("R/wrappers/oa2s_wrapper.R")
source("R/wrappers/rpact_wrapper.R")
source("R/wrappers/bbssr_wrapper.R")
source("R/wrappers/sssas_wrapper.R")
source("R/wrappers/ahern_wrapper.R")
source("R/wrappers/rashnu_wrapper.R")
source("R/wrappers/gsdesign2_wrapper.R")

# Memoise wrappers
wrapper = map(
  wrapper,
  ~ memoise::memoise(.x, cache = cachem::cache_disk("the_cache_of_the_memoise"))
)

# Source S7 classes and methods
source("R/S7/generics.R")
source("R/S7/ssc_design.R")
source("R/S7/ssc_results.R")

# BOXX
boxx(
  "SSC",
  float = "center",
  col = "blue",
  border_style = "double",
  padding = c(0, 15, 0, 15)
) |> print()

This script:

  • loads all required packages,
  • initializes global objects (ssc, wrapper, error rate, etc.),
  • loads helper functions,
  • loads wrapper functions for sample size calculations (see the Wrapper post),
  • loads all S7 classes and methods (see the S7 post).

It ensures that the environment is clean and that all downstream scripts can run consistently.

Comparison scripts

Each comparison script corresponds to a specific design, such as Two‑Arm Survival Fixed Design.
All scripts are independent and follow the same structure.

Parameters & Design

We start by defining the parameter grid used to compare different software and R packages:

Code
# Params ----
params <- lst()
# List of parameters for grid search
params$list = list(
  alpha = c(0.01, 0.05, 0.1, 0.20, 0.49),
  power = c(0.51, 0.8, 0.9, 0.99),
  hr = c(0.1, 0.5, 0.7, 0.9, 0.99),
  surv_t = c(0.1, 0.3, 0.6, 0.9)
)
params$additional <- list(
  event_time = 3,
  accrual_time = 3,
  follow_up_time = 3,
  sided = 2,
  allocation_ratio = 1
)
# Get all combinations of params
params$table <- params$list |> expand.grid() |> as_tibble()
1
Initialize the parameters object
2
Define all varying parameters used in the grid
3
Define fixed parameters shared across all runs
4
Create the full parameter grid

We then instantiate a design object using ssc_design:

Code
design_surv_fixed <- ssc_design(
  endpoint = "survival",
  type = "fixed",
  params = params
)

Results by method

For every software package or method, we compute sample sizes and wrap the results into an ssc_results object:

Code
rpact_wrapper <- partial(wrapper$rpact_surv_fixed, !!!params$additional)
rpact <-
  params$table |>
  mutate(
    nested_res = pmap_vec(params$table, rpact_wrapper, .progress = TRUE)
  ) |>
  unnest(nested_res) |>
  ssc_results(design = design_surv_fixed, method = "rpact")
1
partial() passes all non‑varying parameters to the wrapper
2
We compute the sample size for each parameter combination in the grid

(See the Wrappers post for details on how package-specific functions are wrapped.)

Comparison

Next, we join all method-specific results into a single combined table:

Code
combined <-
  lst(rpact, east, nquery, rashnu, gsdesign2) |>
  map(get_tbl) |>
  add_name_as_suffix(c("e", "n")) |>
  reduce(
    \(x, y) {
      full_join(x, y, by = join_by(alpha, power, hr, surv_t))
    }
  ) |>
  mutate(relevancy = evaluate_relevancy_surv(alpha, power, hr)) |>
  mutate(relevancy = fct_relevel(relevancy, c("high", "medium", "low"))) |>
  ssc_results(design = design_surv_fixed, method = "combined")

Then we compute the N‑Ratio using a chosen reference method (e.g., "east"):

Code
n_ratio <- 
  combined |>
  get_tbl() |> 
  get_n_ratio(ref = "east")

Tables & Figures

To communicate results, each comparison script generates both tables and figures.

Tables are built using gt and saved in a tables list:

Code
# Tables and figures ----
title <- "N-Ratio 2-Arms Survival"
## Tables ----
table_n_ratio <- 
  n_ratio |> 
  gt_n_ratio(title = title, ref_name = "East")

tables <- lst(table_n_ratio)

Figures are built with ggplot2 and saved in a plots list:

Code
## Figures ----
p_n_ratio <- 
  n_ratio |> 
  plot_n_ratio(title = title, ref_name = "East")

plots <- lst(p_n_ratio)

Exporting results

Each script stores its results in the global ssc object:

Code
# Export results ----
ssc$surv$fixed$res <- lst(rpact, rashnu, gsdesign2, east, nquery)
ssc$surv$fixed$raw <- lst("east" = east_raw, "nquery" = nquery_raw)
ssc$surv$fixed$params <- params
ssc$surv$fixed$combined <- combined
ssc$bin$fixed$tables <- tables
ssc$bin$fixed$plots <- plots

We also store a standalone object for exporting script‑specific results:

Code
comp_surv_fixed <- lst(
  params,
  combined,
  n_ratio,
  tables,
  plots
)

Execution

By using the cli package, the script outputs a series of messages (and eventually warnings and errors) that allow following the execution.

> # Initialisation ----
> source("R/init.R")
                          ╔═════════════════════════════════╗
                          ║               SSC               ║
                          ╚═════════════════════════════════╝

> # Binary sample size comparison ----
> cli_h1("SSC-Binary")

── SSC-Binary ────────────────────────────────────────────────────────────────────────

> source("R/comparison/comp_bin_fixed_pooled.R")
─────────────────────── Binary fixed design, pooled computation ──────────────────────
✔ Params & design
✔ Rpact results                                   
✔ East results
✔ nQuery results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_bin_fixed_exact.R")
─────────────────────── Binary fixed design, exact computation ───────────────────────
✔ Params & design
✔ bbssr results                                   
✔ East results
✔ nQuery results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_bin_gs.R")
─────────────────────────── Binary group-sequential design ───────────────────────────
✔ Params & design
✔ Rpact results                                   
✔ East results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_bin_one_arm.R")
─────────────────────────────── One-armed binary design ──────────────────────────────
✔ Params & design
✔ Rpact results                                   
✔ East results
✔ nQuery results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_bin_one_arm_exact.R")
──────────────────────────── One-armed binary design exact ───────────────────────────
✔ Params & design
✔ A'Hern results                                  
✔ East results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> # Survival sample size comparison ----
> cli_h1("SSC-Survival")

── SSC-Survival ──────────────────────────────────────────────────────────────────────

> source("R/comparison/comp_surv_fixed.R")
──────────────────────────────── Survival fixed design ───────────────────────────────
✔ Params & design
✔ Rpact results                                   
✔ Rashnu results                                  
✔ GsDesign2 results                               
✔ East results
✔ nQuery results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_surv_gs.R")
────────────────────────── Survival group-sequential design ──────────────────────────
✔ Params & design
✔ Rpact results
✔ Gsdesign2 results
✔ East results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> source("R/comparison/comp_surv_one_arm.R")
─────────────────────────────── Survival One-arm design ──────────────────────────────
✔ Params & design
✔ OneArm2stage results                            
✔ SampleSizeSingleArmSurvival results             
✔ Rashnu results                                  
✔ nQuery results
✔ Combined results
`summarise()` has grouped output by 'relevancy'. You can override using the `.groups`
argument.
✔ Tables & figures

> # Additional analysis ----
> cli_h1("SSC-side-analysis")

── SSC-side-analysis ─────────────────────────────────────────────────────────────────

> source("R/side-analysis/lakatos_n_lan.R")
───────────────────────── Survival fixed Lakatos & Lan (1992) ────────────────────────
✔ Params & design
✔ Rpact results
✔ Rashnu results
✔ GsDesign2 results
✔ East results
✔ nQuery results
✔ Combined results
✔ Tables & figures

> source("R/side-analysis/bin2arms_exact.R")
──────────────────────── Exact computations for Binary Two-Arm ───────────────────────
✔ Params
✔ bbssr exact results
✔ East results
✔ nQuery results
✔ Combined results
✔ Tables & figures

> # Export results ----
> # write_rds(ssc, "outputs/ssc.rds")