## ----setup, include = FALSE-----------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

options( width = 58 )


## -------------------------------------------------------
# median control time-to-event
median <- 12
# exponential dropout rate per unit of time
eta <- .001
# hypothesized experimental/control hazard ratio 
# (alternate hypothesis)
hr <- .75
# null hazard ratio (1 for superiority, >1 for non-inferiority)
hr0 <- 1
# Type I error (1-sided)
alpha <- .025
# Type II error (1-power)
beta <- .1

## ----message=FALSE--------------------------------------
# study duration
T <- 36 
# follow-up duration of last patient enrolled
minfup <- 12
# enrollment period durations
R <- c(1,2,3,4)
# relative enrollment rates during above periods
gamma <- c(1,1.5,2.5,4)
# randomization ratio, experimental/control
ratio <- 1

## ----tidy=FALSE,warning=FALSE---------------------------
library(gsDesign)
x <- nSurv(R = R,
           gamma = gamma,
           eta = eta,
           minfup = minfup,
           T = T,
           lambdaC = log(2)/median,
           hr = hr,
           hr0 = hr0,
           beta = beta,
           alpha = alpha)

## -------------------------------------------------------
x

## ----eval=FALSE-----------------------------------------
#  # THIS CODE IS EXAMPLE ONLY; NOT EXECUTED HERE
#  nSurv(R = R,
#     gamma = gamma,
#     eta = eta,
#     minfup = minfup,
#     T = NULL, # this was changed
#     lambdaC = log(2)/median,
#     hr = hr,
#     hr0 = hr0,
#     beta = beta,
#     alpha = alpha)

## -------------------------------------------------------
# number of analyses (interim + final)
k <- 3
# timing of interim analyses (k-1 increasing numbers >0 and <1)
# proportion of final events at each interim
timing <- c(.25,.75)
# efficacy bound spending function
# We use Lan-DeMets spending function approximating O'Brien-Fleming bound
# no parameter required for this spending function
sfu <- sfLDOF
sfupar <- NULL
# futility bound spending function
sfl <- sfHSD 
# futility bound spending parameter specification
sflpar <- -7

## -------------------------------------------------------
# Type II error = 1-Power
beta <- .15

## ----tidy=FALSE-----------------------------------------
# generate design
x <- gsSurv(k = k, timing = timing, R = R, gamma = gamma, eta = eta,
            minfup = minfup,T = T, lambdaC = log(2) / median,
            hr = hr, hr0 = hr0 , beta = beta, alpha = alpha,
            sfu = sfu, sfupar = sfupar, sfl = sfl, sflpar = sflpar)

## ----results='asis'-------------------------------------
cat(summary(x))

## ----warning=FALSE--------------------------------------
library(gt)
library(tibble)
tibble(Period = paste("Month",rownames(x$gamma)),
       Rate = as.numeric(x$gamma)) %>% 
  gt() %>% tab_header(title = "Enrollment rate requirements")

## -------------------------------------------------------
# footnote text for table
footnote1 <- "P{Cross} is the probability of crossing the given bound (efficacy or futility) at or before the given analysis under the assumed hazard ratio (HR)."
footnote2 <- " Design assumes futility bound is discretionary (non-binding); upper boundary crossing probabilities shown here assume trial stops at first boundary crossed and thus total less than the design Type I error."
footnoteHR <- "HR presented is not a requirement, but an estimate of approximately what HR would be required to cross each bound."
footnoteM <- "Month is approximated given enrollment and event rate assumptions under alternate hypothesis."
# spending function footnotes
footnoteUS <-"Efficacy bound set using Lan-DeMets spending function approximating an O'Brien-Fleming bound."
footnoteLS <- paste("Futility bound set using ",x$lower$name," beta-spending function with ", 
                    x$lower$parname,"=",x$lower$param,".",sep = "")
# caption text for table
caption <- paste("Overall survival trial design with HR=",hr,", ",100*(1-beta),"% power and ",100*alpha,"% Type 1 error",sep = "")

## ---- echo=TRUE,message=FALSE,tidy=FALSE----------------
gsBoundSummary(x) %>% 
  gt() %>%
  tab_header(title = "Time-to-event group sequential design") %>% 
  cols_align("left") %>%
  tab_footnote(footnoteUS,locations = cells_column_labels(columns = 3)) %>% 
  tab_footnote(footnoteLS,locations = cells_column_labels(columns = 4)) %>% 
  tab_footnote(footnoteHR,locations = cells_data(columns = 2,rows = c(3,8,13))) %>% 
  tab_footnote(footnoteM,locations = cells_data(columns = 1,rows = c(4,9,14))) %>% 
  tab_footnote(footnote1,locations = cells_data(columns = 2,rows = c(4,5,9,10,14,15))) %>% 
  tab_footnote(footnote2,locations = cells_data(columns = 2,rows = c(4,9,14)))

## ---- fig.height=3.5,fig.width=7,warning=FALSE,message=FALSE----
library(ggplot2)
library(scales)
plot(x,plottype = "power",cex = .8,xlab = "HR") + 
  scale_y_continuous(labels = scales::percent)

## -------------------------------------------------------
# number of events (final is still planned number)
n.I <- c(115, 364, ceiling(x$n.I[x$k]))

## -------------------------------------------------------
xu <- gsDesign(alpha = x$alpha, beta = x$beta,
               maxn.IPlan = x$n.I[x$k], n.I = n.I,
               sfu = sfu, sfupar = sfupar, sfl = sfl, sflpar = sflpar,
               delta = x$delta, delta1 = x$delta1, delta0 = x$delta0)

## -------------------------------------------------------
gsBoundSummary(xu,
               deltaname="HR",
               logdelta=TRUE,
               Nname="Events",
               exclude = c("Spending", "B-value", "CP", "CP H1", 
                           "PP", "P(Cross) if HR=1","P(Cross) if HR=0.75")) %>%
  gt() %>% 
  cols_align("left") %>%
  tab_header(title = "Time-to-event group sequential bound guidance",
             subtitle = "Bounds updated based on event counts through IA2") %>% 
  tab_footnote("Nominal p-value required to establish statistical significance.",
               locations=cells_data(columns = 3, rows = c(2, 5, 8))) %>% 
  tab_footnote("Interim futility guidance based on observed HR is non-binding.",
               locations=cells_data(columns = 4, rows = c(3, 6))) %>%
  tab_footnote("HR bounds are approximations; decisions on crossing are based solely on p-values.",
               locations=cells_data(column= 2, rows = c(3, 6, 9)))

## -------------------------------------------------------
Z <- c(0.25, 2)

## -------------------------------------------------------
gsCP(x = xu, # updated design
     i = 2,  # interim analysis 2
     zi = Z[2] # observed Z-value for testing
)$upper$prob

## -------------------------------------------------------
prior <- normalGrid(mu = x$delta/2,
                    sigma = sqrt(20/max(x$n.I)))
cat(paste(" Prior mean:", round(x$delta/2, 3), 
          "\n Prior standard deviation", round(sqrt(20/x$n.fix), 3), "\n"))

## -------------------------------------------------------
gsPP(x = xu, # updated design
     i = 2,  # interim analysis 2
     zi = Z[2], # observed Z-value for testing
     theta = prior$z, # grid points for above prior
     wgts = prior$wgts # weights for averaging over grid
)

## ----fig.width=6.5, fig.height=5------------------------
maxx <- 450 # max for x-axis specified by user  
ylim <- c(-1,3) # user-specified y-axis limits
analysis <- 2  # current analysis specified by user
# Following code should require no further changes
plot(xu, plottype="B", base=TRUE, xlim=c(0,maxx), ylim=ylim, main="B-value projection",
     lty=1, col=1:2, xlab="Events")
N <- c(0, xu$n.I[1:analysis])
B <- c(0, Z * sqrt(xu$timing[1:analysis]))
points(x = N, y = B, col = 4)
lines(x = N, y = B, col = 4)
slope <- B[analysis+1] / N[analysis + 1]
Nvals <- c(N[analysis+1], max(xu$n.I))
lines(x = Nvals,
      y = B[analysis + 1] + c(0, slope * (Nvals[2] - Nvals[1])),
      col = 4,
      lty = 2)

