Timer: Track timed events and apply condition-triggered analyses
Timer.RdA class to collect and query timepoints, time-based events, across arms.
Timer class also supports conditions that filter data using dplyr::filter()
and apply custom analyses.
Use add_timepoint() to append timepoints, get_timepoint() for a lookup,
and check_conditions() to filter a data frame based on a trigger condition
and return either analysis results or the filtered data.
Details
Helper functions trigger_by_calendar() and trigger_by_fraction() provide
convenient shortcuts for common trigger patterns.
See also
Trial to coordinate simulations with populations, add_timepoints()
to attach multiple timepoints, dplyr::filter() for condition syntax.
Public fields
namecharacterUnique identifier for theTimerinstance.timelistlistA list of timepoints. Each timepoint is a list with keys:timenumericCalendar timearmcharacterUnique identifier of the armdropperinteger# of subjects dropper attimeenrollerinteger# of subjects enrolled attime
conditionslistA list of condition entries. Each entry is a list with keys:whereexprfilter conditions indplyr::filter()styleanalysisfunctionorNULLanalysis applied to filtered datanamecharacterorNULLunique key for the condition
Methods
Method new()
Create a new Timer instance.
Usage
Timer$new(name, timelist = NULL, conditions = NULL)Arguments
namecharacterUnique identifier.timelistlistOptional list of timepoints.conditionslistOptional list of condition entries.
Examples
t <- Timer$new(name = "Timer")Method add_timepoint()
Add a timepoint to a timer.
Arguments
timenumericCalendar time.armcharacterArm identifier.dropperintegerCount of subjects to drop.enrollerintegerCount of subjects to enroll.
Examples
t <- Timer$new(name = "Timer")
t$add_timepoint(
time = 1,
arm = "A",
dropper = 1L,
enroller = 3L
)Method add_condition()
Add a trigger condition to a timer.
Arguments
...expressionBoolean expression(s) fordplyr::filter().analysisfunctionorNULLOptional function to apply.namecharacterUnique condition identifier.
Examples
#' t <- Timer$new(name = "Timer")
# Add timepoints
t$add_timepoint(time = 1, arm = "A", dropper = 2L, enroller = 10L)
# Add conditions using `dplyr` style
# Suppose you have a data.frame:
df <- data.frame(
id = 1:6,
arm = c("A","A","B","B","A","B"),
status = c("active","inactive","active","active","inactive","active"),
visit = c(1,2,1,3,3,2)
)
# Analysis function: count rows at/after a given visit, per arm
my_analysis <- function(dat, current_time) {
out <- aggregate(id ~ arm, dat, length)
out$current_time <- current_time
out
}
# Condition 1: active only
t$add_condition(
status == "active",
analysis = my_analysis,
name = "active_only"
)Method get_end_timepoint()
Determine the last timepoint for a given instance of Timer class.
Examples
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$get_end_timepoint()Method get_n_arms()
Get number of unique arms.
Examples
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_n_arms()Method get_unique_times()
Get unique timepoints.
Examples
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_unique_times()Method get_timepoint()
Get a timepoint by arm and index.
Examples
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_timepoint("A", 1)Method check_conditions()
Check conditions and return filtered data or analysis results.
Examples
#' t <- Timer$new(name = "Timer")
# Add timepoints
t$add_timepoint(time = 1, arm = "A", dropper = 2L, enroller = 10L)
t$add_timepoint(time = 2, arm = "A", dropper = 1L, enroller = 12L)
t$add_timepoint(time = 1, arm = "B", dropper = 0L, enroller = 8L)
# Query
t$get_end_timepoint() # max time => 2
t$get_n_arms() # unique arms => 2
t$get_unique_times() # unique times => c(1, 2)
t$get_timepoint("A", 1) # returns a single timepoint
# Add conditions using dplyr style
# Suppose you have a data.frame:
df <- data.frame(
id = 1:6,
arm = c("A","A","B","B","A","B"),
status = c("active", "inactive", "active", "active", "inactive", "active"),
visit = c(1,2,1,3,3,2)
)
# Analysis function: count rows at/after a given visit, per arm
my_analysis <- function(dat, current_time) {
out <- aggregate(id ~ arm, dat, length)
out$current_time <- current_time
out
}
# Condition: active only
t$add_condition(
status == "active",
analysis = my_analysis,
name = "active_only"
)Examples
# Basic construction
t <- Timer$new(name = "Timer")
# Add timepoints
t$add_timepoint(time = 1, arm = "A", dropper = 2L, enroller = 10L)
t$add_timepoint(time = 2, arm = "A", dropper = 1L, enroller = 12L)
t$add_timepoint(time = 1, arm = "B", dropper = 0L, enroller = 8L)
# Query
t$get_end_timepoint() # max time => 2
#> [1] 2
t$get_n_arms() # unique arms => 2
#> [1] 2
t$get_unique_times() # unique times => c(1, 2)
#> [1] 1 2
t$get_timepoint("A", 1) # returns a single timepoint
#> $time
#> [1] 1
#>
#> $arm
#> [1] "A"
#>
#> $dropper
#> [1] 2
#>
#> $enroller
#> [1] 10
#>
# Add conditions using trigger helpers or dplyr style
# Suppose you have a data.frame:
df <- data.frame(
id = 1:6,
arm = c("A", "A", "B", "B", "A", "B"),
status = c("active", "inactive", "active", "active", "inactive", "active"),
visit = c(1, 2, 1, 3, 3, 2)
)
# Analysis function: count rows at/after a given visit, per arm
my_analysis <- function(dat, current_time) {
out <- aggregate(id ~ arm, dat, length)
out$current_time <- current_time
out
}
# Or add conditions manually with dplyr style
# Condition: arm A, visit >= 2, no analysis -> returns filtered df
t$add_condition(
arm == "A", visit >= 2,
name = "armA_visit2plus"
)
# Run checks
res <- t$check_conditions(locked_data = df, current_time = 3)
#> Warning: returning filtered data as is because condition 'armA_visit2plus' has no applicable analysis
names(res)
#> [1] "armA_visit2plus"
## ------------------------------------------------
## Method `Timer$new`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
## ------------------------------------------------
## Method `Timer$add_timepoint`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
t$add_timepoint(
time = 1,
arm = "A",
dropper = 1L,
enroller = 3L
)
## ------------------------------------------------
## Method `Timer$add_condition`
## ------------------------------------------------
#' t <- Timer$new(name = "Timer")
# Add timepoints
t$add_timepoint(time = 1, arm = "A", dropper = 2L, enroller = 10L)
# Add conditions using `dplyr` style
# Suppose you have a data.frame:
df <- data.frame(
id = 1:6,
arm = c("A","A","B","B","A","B"),
status = c("active","inactive","active","active","inactive","active"),
visit = c(1,2,1,3,3,2)
)
# Analysis function: count rows at/after a given visit, per arm
my_analysis <- function(dat, current_time) {
out <- aggregate(id ~ arm, dat, length)
out$current_time <- current_time
out
}
# Condition 1: active only
t$add_condition(
status == "active",
analysis = my_analysis,
name = "active_only"
)
## ------------------------------------------------
## Method `Timer$get_end_timepoint`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$get_end_timepoint()
#> [1] 3.14
## ------------------------------------------------
## Method `Timer$get_n_arms`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_n_arms()
#> [1] 2
## ------------------------------------------------
## Method `Timer$get_unique_times`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_unique_times()
#> [1] 3.14 3.28
## ------------------------------------------------
## Method `Timer$get_timepoint`
## ------------------------------------------------
t <- Timer$new(name = "Timer")
t$add_timepoint(time = 3.14, arm = "A", dropper = 7L, enroller = 22L)
t$add_timepoint(time = 3.28, arm = "B", dropper = 6L, enroller = 23L)
t$get_timepoint("A", 1)
#> NULL
## ------------------------------------------------
## Method `Timer$check_conditions`
## ------------------------------------------------
#' t <- Timer$new(name = "Timer")
# Add timepoints
t$add_timepoint(time = 1, arm = "A", dropper = 2L, enroller = 10L)
t$add_timepoint(time = 2, arm = "A", dropper = 1L, enroller = 12L)
t$add_timepoint(time = 1, arm = "B", dropper = 0L, enroller = 8L)
# Query
t$get_end_timepoint() # max time => 2
#> [1] 3.28
t$get_n_arms() # unique arms => 2
#> [1] 2
t$get_unique_times() # unique times => c(1, 2)
#> [1] 3.14 3.28 1.00 2.00
t$get_timepoint("A", 1) # returns a single timepoint
#> $time
#> [1] 1
#>
#> $arm
#> [1] "A"
#>
#> $dropper
#> [1] 2
#>
#> $enroller
#> [1] 10
#>
# Add conditions using dplyr style
# Suppose you have a data.frame:
df <- data.frame(
id = 1:6,
arm = c("A","A","B","B","A","B"),
status = c("active", "inactive", "active", "active", "inactive", "active"),
visit = c(1,2,1,3,3,2)
)
# Analysis function: count rows at/after a given visit, per arm
my_analysis <- function(dat, current_time) {
out <- aggregate(id ~ arm, dat, length)
out$current_time <- current_time
out
}
# Condition: active only
t$add_condition(
status == "active",
analysis = my_analysis,
name = "active_only"
)