Professional Documents
Culture Documents
psp412797 Sup 0001 Supinfo
psp412797 Sup 0001 Supinfo
Title: Finding the right hazard function for time to event modelling: a tutorial
Corresponding author: Ulrika S H Simonsson, Box 591, 75124 Uppsala, Sweden. Tel: +46 18 471
Keywords: time to event, survival analysis, hazard function, kernel based visual
##################################################################################
# Version: 1.0
# Reference: Rob C van Wijk, Ulrika S H Simonsson, Finding the right hazard function
##################################################################################
#####################
#####################
library(tidyverse) #version 1.3.0 which includes ggplot2 (version 3.3.3) purrr (version 0.3.4) tibble
#(version 3.1.0) dplyr (version 1.0.5) tidyr (version 1.1.3) stringr (version 1.4.0) readr (version 1.4.0)
theme_set(theme_bw())
theme_update(panel.grid = element_blank())
##################################################################################
# set minimum and maximum as variables to facilitate updating the slider/manual input combination
##################################################################################
# Time
time = 180
time_min = 0
time_max = 365
# Drug effect on hazard functions (exponential, Gompertz, Weibull, lognormal, log-logistic, circadian)
#as a whole under the proportional hazard assumption (coefficients, can be calculated to hazard
drug_exp =0
drug_gompertz = 0
drug_weibull = 0
drug_lognormal = 0
drug_logl =0
drug_circadian = 0
hr_min = -2
hr_max =2
# Drug effect on individual parameters of the hazard functions, in relative term (%, will multiply the
#parameter)
drug_lambda = 0
drug_gamma = 0
drug_mu =0
drug_sigma = 0
drug_amp = 0
drug_period = 0
drug_phase = 0
drug_min = -100
drug_max = 100
lambda_constant = 0.05
lambda_constant_min = 0
lambda_constant_max = 1
lambda_gompertz = 0.02
lambda_gompertz_min = 0
lambda_gompertz_max = 1
gamma_gompertz = -0.001
gamma_gompertz_min = -0.1
gamma_gompertz_max = 0.1
lambda_weibull = 0.02
lambda_weibull_min = 0
lambda_weibull_max = 1
gamma_weibull = 0.8
gamma_weibull_min = -2
gamma_weibull_max = 2
# Parameters of the log-normal hazard function
mu =5
mu_min = 0
mu_max = 10
sigma =2
sigma_min = 0
sigma_max = 5
lambda_logl = 0.02
lambda_logl_min = 0
lambda_logl_max = 1
gamma_logl = 1.1
gamma_logl_min = 0
gamma_logl_max = 2
lambda_circadian_min = 0
lambda_circadian_max = 1
amp = 0.1
amp_min =0
amp_max =1
period = 180
period_min =0
period_max = 365
phase =0
phase_min = -150
phase_max = 150
####################################
####################################
ui <- fluidPage(
# formatting of the sliders in different colours
border: black}")),
border: orange}")),
border: orange}")),
border: orange}")),
border: orange}")),
border: orange}")),
border: orange}")),
border: red}")),
border: red}")),
border: red}")),
tags$style(HTML(".js-irs-23 .irs-single, .js-irs-23 .irs-bar-edge, .js-irs-23 .irs-bar {background: red;
border: red}")),
border: red}")),
border: red}")),
border: red}")),
border: red}")),
# Instruction and reference panel at the top of the page (across the max of 12 columns)
fluidRow(
column(12, p(strong('Instructions'))),
column(12, p('Graphical exploration of different hazard functions for time to event analysis. These
functions can be compared with an non-parametric estimation of the hazard in the time to event
data based on the kernel based visual hazard comparison (',a('Goulooze et al, AAPS 20: 5, 2018', href
= 'http://dx.doi.org/10.1208/s12248-017-0162-9', target="_blank" ),') or hazard based visual
predictive check (',a('Huh & Hutmacher, J Pharmacokinet Pharmacodyn, 43:57-71, 2016', href =
'http://dx.doi.org/10.1007/s10928-015-9454-9', target="_blank"),').')),
column(12, p("Time and hazard function parameters can be set using the sliders. Alternatively,
they can be set in the input box below the slider which has no lower or upper constraint. Effects of
covariates/treatment on function as a whole (proportional hazard with hazard ratio output) or on the
function's individual parameters on the relative scale can be selected in the same manner. Graphs
can be downloaded in tiff format using the provided link, with all relevant parameter values
column(12, ),
column(12, p(em('Reference: Rob C van Wijk, Ulrika S H Simonsson, Finding the right hazard
function for time to event modelling: a tutorial and Shiny app (2022, manuscript under review)'))),
# Middle part of the application divided into 4 columns (parameter sliders) and hazard functions
#(graphical element)
fluidRow(
column(2,
sliderInput('TIME',
p('Time duration'),
min = time_min,
max = time_max,
value = time,
step = 1),
numericInput('TIME_NUM',
'',
value = time,
step = 1),
sliderInput('LAMBDA_GOMPERTZ',
min = lambda_gompertz_min,
max = lambda_gompertz_max,
value = lambda_gompertz,
step = 0.001),
numericInput('LAMBDA_GOMPERTZ_NUM',
'',
value = lambda_gompertz,
step = 0.001),
sliderInput('LAMBDA_WEIBULL',
min = lambda_weibull_min,
max = lambda_weibull_max,
value = lambda_weibull,
step = 0.001),
numericInput('LAMBDA_WEIBULL_NUM',
'',
value = lambda_weibull,
step = 0.001),
sliderInput('MU',
min = mu_min,
max = mu_max,
value = mu,
step = 0.01),
numericInput('MU_NUM',
'',
value = mu,
step = 0.01),
sliderInput('LAMBDA_LOGL',
min = lambda_logl_min,
max = lambda_logl_max,
value = lambda_logl,
step = 0.001),
numericInput('LAMBDA_LOGL_NUM',
'',
value = lambda_logl,
step = 0.001),
sliderInput('LAMBDA_CIRCADIAN',
min = lambda_circadian_min,
max = lambda_circadian_max,
value = lambda_circadian,
step = 0.001),
numericInput('LAMBDA_CIRCADIAN_NUM',
'',
value = lambda_circadian,
step = 0.001),
sliderInput('PERIOD',
min = period_min,
max = period_max,
value = period,
step = 1),
numericInput('PERIOD_NUM',
'',
value = period,
step = 1)
),
column(2,
sliderInput('LAMBDA_CONSTANT',
min = lambda_constant_min,
max = lambda_constant_max,
value = lambda_constant,
step = 0.001),
numericInput('LAMBDA_CONSTANT_NUM',
'',
value = lambda_constant,
step = 0.001),
sliderInput('GAMMA_GOMPERTZ',
min = gamma_gompertz_min,
max = gamma_gompertz_max,
value = gamma_gompertz,
numericInput('GAMMA_GOMPERTZ_NUM',
'',
value = gamma_gompertz,
sliderInput('GAMMA_WEIBULL',
min = gamma_weibull_min,
max = gamma_weibull_max,
value = gamma_weibull,
step = 0.01),
numericInput('GAMMA_WEIBULL_NUM',
'',
value = gamma_weibull,
step = 0.01),
sliderInput('SIGMA',
min = sigma_min,
max = sigma_max,
value = sigma,
step = 0.01),
numericInput('SIGMA_NUM',
'',
value = sigma,
step = 0.01),
sliderInput('GAMMA_LOGL',
min = gamma_logl_min,
max = gamma_logl_max,
value = gamma_logl,
step = 0.01),
numericInput('GAMMA_LOGL_NUM',
'',
value = gamma_logl,
step = 0.01),
sliderInput('AMP',
min = amp_min,
max = amp_max,
value = amp,
step = 0.01),
numericInput('AMP_NUM',
'',
value = amp,
step = 0.01),
sliderInput('PHASE',
min = phase_min,
max = phase_max,
value = phase,
step = 1),
numericInput('PHASE_NUM',
'',
value = phase,
step = 1)
),
# Right hand side of the middle panel with graphical hazard functions and the download button to
column(4,
plotOutput("CONSTANT"),
plotOutput("WEIBULL"),
plotOutput("LOGLOGISTIC")
),
column(4,
plotOutput("GOMPERTZ"),
plotOutput("LOGNORMAL"),
plotOutput("CIRCADIAN")
),
# Bottom panel with the covariate/treatment effect on the hazard function as a whole
fluidRow(
column(12,
hr(),
significant digits.')),
hr())),
fluidRow(
column(2,
sliderInput('DRUG_EXP',
min = hr_min,
max = hr_max,
value = drug_exp,
step = 0.1),
numericInput('DRUG_EXP_NUM',
'',
value = drug_exp,
step = 0.1),
textOutput('HR_EXP')
),
column(2,
sliderInput('DRUG_GOMPERTZ',
max = hr_max,
value = drug_gompertz,
step = 0.1),
numericInput('DRUG_GOMPERTZ_NUM',
'',
value = drug_gompertz,
step = 0.1),
textOutput('HR_GOMPERTZ')
),
column(2,
sliderInput('DRUG_WEIBULL',
min = hr_min,
max = hr_max,
value = drug_weibull,
step = 0.1),
numericInput('DRUG_WEIBULL_NUM',
'',
value = drug_weibull,
step = 0.1),
textOutput('HR_WEIBULL')
),
column(2,
sliderInput('DRUG_LOGNORMAL',
min = hr_min,
max = hr_max,
value = drug_lognormal,
step = 0.1),
numericInput('DRUG_LOGNORMAL_NUM',
'',
value = drug_lognormal,
step = 0.1),
textOutput('HR_LOGNORMAL')
),
column(2,
sliderInput('DRUG_LOGL',
min = hr_min,
max = hr_max,
value = drug_logl,
step = 0.1),
numericInput('DRUG_LOGL_NUM',
'',
value = drug_logl,
step = 0.1),
textOutput('HR_LOGL')
),
column(2,
sliderInput('DRUG_CIRCADIAN',
min = hr_min,
max = hr_max,
value = drug_circadian,
step = 0.1),
numericInput('DRUG_CIRCADIAN_NUM',
'',
value = drug_circadian,
step = 0.1),
textOutput('HR_CIRCADIAN')
),
# Bottom panel with the covariate/treatment effect on the hazard function's individual parameters
fluidRow(
hr())),
fluidRow(
column(2,
sliderInput('DRUG_LAMBDA',
max = drug_max,
value = drug_lambda,
step = 1,
post = '%'),
numericInput('DRUG_LAMBDA_NUM',
'',
value = drug_lambda,
step = 1),
sliderInput('DRUG_PHASE',
min = drug_min,
max = drug_max,
value = drug_phase,
step = 1,
post = '%'),
numericInput('DRUG_PHASE_NUM',
'',
value = drug_phase,
step = 1),
p(em('In case of phase=0, set phase equal to period to study the relative drug effect.'))
),
column(2,
sliderInput('DRUG_GAMMA',
min = drug_min,
max = drug_max,
value = drug_gamma,
step = 1,
post = '%'),
numericInput('DRUG_GAMMA_NUM',
'',
value = drug_gamma,
step = 1)
),
column(2,
sliderInput('DRUG_MU',
p('Effect on mu (%)'),
min = drug_min,
max = drug_max,
value = drug_mu,
step = 1,
post = '%'),
numericInput('DRUG_MU_NUM',
'',
value = drug_mu,
step = 1)
),
column(2,
sliderInput('DRUG_SIGMA',
min = drug_min,
max = drug_max,
value = drug_sigma,
step = 1,
post = '%'),
numericInput('DRUG_SIGMA_NUM',
'',
value = drug_sigma,
step = 1)
),
column(2,
sliderInput('DRUG_AMP',
min = drug_min,
max = drug_max,
value = drug_amp,
step = 1,
post = '%'),
numericInput('DRUG_AMP_NUM',
'',
value = drug_amp,
step = 1)
),
column(2,
sliderInput('DRUG_PERIOD',
min = drug_min,
max = drug_max,
value = drug_period,
step = 1,
post = '%'),
numericInput('DRUG_PERIOD_NUM',
'',
value = drug_period,
step = 1)
)
)
##########
# Server
##########
#Refresh and synchronize numeric and slider for the same input, so that when the slider is changed,
#the manual input also changes accordingly, and vice versa (including the minimum and maximum
observeEvent(input$TIME, {
})
observeEvent(input$TIME_NUM, {
input$TIME_NUM))
})
observeEvent(input$LAMBDA_CONSTANT, {
lambda_constant_max, input$LAMBDA_CONSTANT))
})
observeEvent(input$LAMBDA_CONSTANT_NUM, {
})
observeEvent(input$LAMBDA_GOMPERTZ, {
lambda_gompertz_max, input$LAMBDA_GOMPERTZ))
})
observeEvent(input$LAMBDA_GOMPERTZ_NUM, {
})
observeEvent(input$GAMMA_GOMPERTZ, {
gamma_gompertz_max, input$GAMMA_GOMPERTZ))
})
observeEvent(input$GAMMA_GOMPERTZ_NUM, {
})
observeEvent(input$LAMBDA_WEIBULL, {
lambda_weibull_max, input$LAMBDA_WEIBULL))
})
observeEvent(input$LAMBDA_WEIBULL_NUM, {
})
observeEvent(input$GAMMA_WEIBULL, {
gamma_weibull_max, input$GAMMA_WEIBULL))
})
observeEvent(input$GAMMA_WEIBULL_NUM, {
})
observeEvent(input$MU, {
observeEvent(input$MU_NUM, {
})
observeEvent(input$SIGMA, {
input$SIGMA))
})
observeEvent(input$SIGMA_NUM, {
sigma_max, input$SIGMA_NUM))
})
observeEvent(input$LAMBDA_LOGL, {
})
observeEvent(input$LAMBDA_LOGL_NUM, {
lambda_logl_max, input$LAMBDA_LOGL_NUM))
})
observeEvent(input$GAMMA_LOGL, {
})
observeEvent(input$GAMMA_LOGL_NUM, {
gamma_logl_max, input$GAMMA_LOGL_NUM))
})
observeEvent(input$GAMMA_WEIBULL, {
gamma_weibull_max, input$GAMMA_WEIBULL))
})
observeEvent(input$GAMMA_WEIBULL_NUM, {
})
observeEvent(input$LAMBDA_CIRCADIAN, {
lambda_circadian_max, input$LAMBDA_CIRCADIAN))
})
observeEvent(input$LAMBDA_CIRCADIAN_NUM, {
})
observeEvent(input$AMP, {
})
observeEvent(input$AMP_NUM, {
input$AMP_NUM))
})
observeEvent(input$PERIOD, {
input$PERIOD))
})
observeEvent(input$PERIOD_NUM, {
})
observeEvent(input$PHASE, {
updateNumericInput(session, 'PHASE_NUM', value = input$PHASE, min = ifelse(input$PHASE >
input$PHASE))
})
observeEvent(input$PHASE_NUM, {
phase_max, input$PHASE_NUM))
})
observeEvent(input$DRUG_LAMBDA, {
})
observeEvent(input$DRUG_LAMBDA_NUM, {
})
observeEvent(input$DRUG_GAMMA, {
updateNumericInput(session, 'DRUG_GAMMA_NUM', value = input$DRUG_GAMMA, min =
})
observeEvent(input$DRUG_GAMMA_NUM, {
})
observeEvent(input$DRUG_MU, {
})
observeEvent(input$DRUG_MU_NUM, {
})
observeEvent(input$DRUG_SIGMA, {
updateNumericInput(session, 'DRUG_SIGMA_NUM', value = input$DRUG_SIGMA, min =
})
observeEvent(input$DRUG_SIGMA_NUM, {
})
observeEvent(input$DRUG_AMP, {
})
observeEvent(input$DRUG_AMP_NUM, {
})
observeEvent(input$DRUG_PERIOD, {
updateNumericInput(session, 'DRUG_PERIOD_NUM', value = input$DRUG_PERIOD, min =
})
observeEvent(input$DRUG_PERIOD_NUM, {
})
observeEvent(input$DRUG_PHASE, {
})
observeEvent(input$DRUG_PHASE_NUM, {
})
observeEvent(input$DRUG_EXP, {
updateNumericInput(session, 'DRUG_EXP_NUM', value = input$DRUG_EXP, min =
})
observeEvent(input$DRUG_EXP_NUM, {
})
observeEvent(input$DRUG_GOMPERTZ, {
})
observeEvent(input$DRUG_GOMPERTZ_NUM, {
})
observeEvent(input$DRUG_WEIBULL, {
updateNumericInput(session, 'DRUG_WEIBULL_NUM', value = input$DRUG_WEIBULL, min =
})
observeEvent(input$DRUG_WEIBULL_NUM, {
})
observeEvent(input$DRUG_LOGNORMAL, {
})
observeEvent(input$DRUG_LOGNORMAL_NUM, {
})
observeEvent(input$DRUG_LOGL, {
updateNumericInput(session, 'DRUG_LOGL_NUM', value = input$DRUG_LOGL, min =
})
observeEvent(input$DRUG_LOGL_NUM, {
})
observeEvent(input$DRUG_CIRCADIAN, {
})
observeEvent(input$DRUG_CIRCADIAN_NUM, {
})
#Calculating the hazard ratio based on the coefficient input with 3 significant digits
output$HR_EXP <- reactive({
})
})
})
})
})
})
#Create simulation dataset
req(input$TIME,
input$LAMBDA_CONSTANT,
input$LAMBDA_GOMPERTZ,
input$GAMMA_GOMPERTZ,
input$LAMBDA_WEIBULL,
input$GAMMA_WEIBULL,
input$MU,
input$SIGMA,
input$LAMBDA_LOGL,
input$GAMMA_LOGL,
input$LAMBDA_CIRCADIAN,
input$AMP,
input$PERIOD,
input$PHASE,
input$DRUG_LAMBDA,
input$DRUG_GAMMA,
input$DRUG_MU,
input$DRUG_SIGMA,
input$DRUG_AMP,
input$DRUG_PERIOD,
input$DRUG_PHASE,
input$DRUG_EXP,
input$DRUG_GOMPERTZ,
input$DRUG_WEIBULL,
input$DRUG_LOGNORMAL,
input$DRUG_LOGL,
input$DRUG_CIRCADIAN
%>%
1)) %>%
input$DRUG_GAMMA/100)))) %>%
#Create plots including covariate/treatment effect in orange (hazard ratio) or red (individual
#parameter effects)
geom_line() +
scale_x_continuous(name = 'Time') +
3), sep = ''), ''), ifelse(input$DRUG_LAMBDA != 0, paste('\ndrug effect (red) on lambda = ',
print(plotCONSTANT())
geom_line() +
scale_x_continuous(name = 'Time') +
paste('\ndrug effect (red) on lambda = ', input$DRUG_LAMBDA, '%', sep = ''), ''),
ifelse(input$DRUG_GAMMA != 0, paste('\ndrug effect (red) on gamma = ', input$DRUG_GAMMA, '%',
print(plotGOMPERTZ())
geom_line() +
scale_x_continuous(name = 'Time') +
paste('\nhazard ratio (orange) = ', signif(exp(input$DRUG_WEIBULL), digits = 3), sep = ''), ''),
'%', sep = ''), ''), ifelse(input$DRUG_GAMMA != 0, paste('\ndrug effect (red) on gamma = ',
print(plotWEIBULL())
geom_line() +
scale_x_continuous(name = 'Time') +
ndrug effect (red) on mu = ', input$DRUG_MU, '%', sep = ''), ''), ifelse(input$DRUG_SIGMA != 0,
paste('\ndrug effect (red) on sigma = ', input$DRUG_SIGMA, '%', sep = ''), ''), sep = ''))
print(plotLOGNORMAL())
geom_line() +
scale_x_continuous(name = 'Time') +
nhazard ratio (orange) = ', signif(exp(input$DRUG_LOGL), digits = 3), sep = ''), ''),
'%', sep = ''), ''), ifelse(input$DRUG_GAMMA != 0, paste('\ndrug effect (red) on gamma = ',
print(plotLOGLOGISTIC())
}
)
geom_line() +
scale_x_continuous(name = 'Time') +
sep = ''))
print(plotCIRCADIAN())
#Create downloadable to download the plot with the filename reflecting the selected parameter
#and covariate/treatment effect values, where relevant (with none selected, the ifelse statement will
filename = function() {
paste("HazardTool_Exponential_lambda_",
input$LAMBDA_CONSTANT,
ifelse(input$DRUG_EXP != 0, paste('_hr_', signif(exp(input$DRUG_EXP), digits = 3), sep = ''), ''),
".tiff", sep="")
},
content = function(file) {
print(plotCONSTANT())
dev.off()
filename = function() {
input$GAMMA_GOMPERTZ,
".tiff", sep="")
},
content = function(file) {
print(plotGOMPERTZ())
dev.off()
filename = function() {
input$GAMMA_WEIBULL,
".tiff", sep="")
},
content = function(file) {
print(plotWEIBULL())
dev.off()
}
filename = function() {
".tiff", sep="")
},
content = function(file) {
print(plotLOGNORMAL())
dev.off()
input$GAMMA_LOGL,
''),
".tiff", sep="")
},
content = function(file) {
print(plotLOGLOGISTIC())
dev.off()
filename = function() {
".tiff", sep="")
},
content = function(file) {
print(plotCIRCADIAN())
dev.off()
###############
# Run the app
###############