diff --git a/DESCRIPTION b/DESCRIPTION index f92b511d..9aa3157f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,6 +44,7 @@ Imports: doFuture, foreach, future, + lt, methods, mvtnorm, stats, diff --git a/NAMESPACE b/NAMESPACE index f016fa3c..10127f35 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ S3method(as_gt,fixed_design) S3method(as_gt,gs_design) S3method(as_gt,simtrial_gs_wlr) +S3method(lt::lt,simtrial_gs_wlr) S3method(summary,simtrial_gs_wlr) S3method(wlr,counting_process) S3method(wlr,default) @@ -18,6 +19,7 @@ export(fh) export(fit_pwexp) export(get_analysis_date) export(get_cut_date_by_event) +export(lt) export(maxcombo) export(mb) export(milestone) @@ -56,6 +58,7 @@ importFrom(future, nbrOfWorkers, plan ) +importFrom(lt,lt) importFrom(methods,is) importFrom(mvtnorm, GenzBretz, diff --git a/NEWS.md b/NEWS.md index 27439205..e737ffbd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # simtrial 1.0.2 +## Major changes + +- The heavy **gt** dependency is replaced by the lightweight **lt** package for rendering summary tables (#371). The `lt()` generic is re-exported so `summary()` output can be rendered with `lt()` after only loading simtrial. `as_gt()` is deprecated but kept for one release; it still returns a `gt_tbl` object and now requires the suggested **gt** package to be installed. + ## Bug fixes - `sim_gs_n()` is updated to provide updated efficacy bound when it is one-sided design (#348, thanks to @LittleBeannie). diff --git a/R/as_gt.R b/R/as_gt.R index ccaeba5d..a8674f83 100644 --- a/R/as_gt.R +++ b/R/as_gt.R @@ -18,23 +18,48 @@ #' Convert summary table to a gt object #' +#' `as_gt()` is deprecated in favor of [lt()], which produces a lightweight +#' HTML table without the heavy \pkg{gt} dependency. `as_gt()` is kept for one +#' release so existing code that customizes the output with \pkg{gt} functions +#' keeps working; it still returns a `gt_tbl` object and requires \pkg{gt} to be +#' installed. New code should use [lt()]; see [lt-methods] for details. +#' #' @param x A summary object of a fixed or group sequential design. #' @param ... Additional arguments (not used). #' #' @return A gt table. #' +#' @seealso [lt()], [lt-methods] +#' #' @export as_gt <- function(x, ...) { + .Deprecated("lt", package = "simtrial", + msg = paste( + "as_gt() is deprecated and will be removed in a future release;", + "please use lt() instead." + )) UseMethod("as_gt", x) } +# stop with an informative message when gt is not installed, since it is only +# a suggested (optional) dependency now that as_gt() is deprecated +assert_gt_installed <- function() { + if (!requireNamespace("gt", quietly = TRUE)) stop( + "The 'gt' package is required by the deprecated as_gt(); ", + "install it with install.packages('gt'), or use lt() instead.", + call. = FALSE + ) +} + #' @param x A object returned by [summary()]. #' @param title Title of the gt table. #' @param subtitle Subtitle of the gt table. #' @param ... Additional parameters (not used). #' -#' @return A gt table summarizing the simulation results. +#' @return A gt table summarizing the simulation results. This method is +#' deprecated; use [lt()] instead. It still returns a `gt_tbl` object for one +#' release and requires \pkg{gt} to be installed. #' @export #' @rdname as_gt #' @@ -101,6 +126,8 @@ as_gt <- function(x, ...) { as_gt.simtrial_gs_wlr <- function(x, title = "Summary of simulation results by WLR tests", subtitle = NULL, ...){ + assert_gt_installed() + # get the default subtitle if (is.null(subtitle)) { subtitle <- paste0("Weighted by ", attributes(x)$method) diff --git a/R/lt.R b/R/lt.R new file mode 100644 index 00000000..9fa8dedf --- /dev/null +++ b/R/lt.R @@ -0,0 +1,188 @@ +# Copyright (c) 2026 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. +# All rights reserved. +# +# This file is part of the simtrial program. +# +# simtrial is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Re-export the lt() generic so users can call lt() on a simulation summary after +# only loading simtrial (without also attaching lt or qualifying with lt::). +# This also makes S3 dispatch robust regardless of package load order. +# See https://github.com/yihui/lt/issues/4. + +#' @importFrom lt lt +#' @export +lt::lt + +#' Create an lt table from a simulation summary +#' +#' S3 method for [lt()] that converts a group sequential simulation summary +#' (a `simtrial_gs_wlr` object returned by [summary()]) into a formatted lt +#' table. This is the lightweight replacement for the deprecated [as_gt()]. +#' +#' @param data A summary object returned by [summary()]. +#' @param title Title of the lt table. +#' @param subtitle Subtitle of the lt table. +#' @param ... Additional arguments (not used). +#' +#' @return An `lt_tbl` object summarizing the simulation results. +#' +#' @name lt-methods +#' +#' @seealso [as_gt()] +#' +#' @exportS3Method lt::lt +#' +#' @examples +#' +#' # Parameters for enrollment +#' enroll_rampup_duration <- 4 # Duration for enrollment ramp up +#' enroll_duration <- 16 # Total enrollment duration +#' enroll_rate <- gsDesign2::define_enroll_rate( +#' duration = c( +#' enroll_rampup_duration, enroll_duration - enroll_rampup_duration), +#' rate = c(10, 30)) +#' +#' # Parameters for treatment effect +#' delay_effect_duration <- 3 # Delay treatment effect in months +#' median_ctrl <- 9 # Survival median of the control arm +#' median_exp <- c(9, 14) # Survival median of the experimental arm +#' dropout_rate <- 0.001 +#' fail_rate <- gsDesign2::define_fail_rate( +#' duration = c(delay_effect_duration, 100), +#' fail_rate = log(2) / median_ctrl, +#' hr = median_ctrl / median_exp, +#' dropout_rate = dropout_rate) +#' +#' # Other related parameters +#' alpha <- 0.025 # Type I error +#' beta <- 0.1 # Type II error +#' ratio <- 1 # Randomization ratio (experimental:control) +#' +#' # Build a one-sided group sequential design +#' design <- gsDesign2::gs_design_ahr( +#' enroll_rate = enroll_rate, fail_rate = fail_rate, +#' ratio = ratio, alpha = alpha, beta = beta, +#' analysis_time = c(12, 24, 36), +#' upper = gsDesign2::gs_spending_bound, +#' upar = list(sf = gsDesign::sfLDOF, total_spend = alpha), +#' lower = gsDesign2::gs_b, +#' lpar = rep(-Inf, 3)) +#' +#' # Define cuttings of 2 IAs and 1 FA +#' ia1_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[1])) +#' ia2_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[2])) +#' fa_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[3])) +#' +#' # Run simulations +#' simulation <- sim_gs_n( +#' n_sim = 3, +#' sample_size = ceiling(design$analysis$n[3]), +#' enroll_rate = design$enroll_rate, +#' fail_rate = design$fail_rate, +#' test = wlr, +#' cut = list(ia1 = ia1_cut, ia2 = ia2_cut, fa = fa_cut), +#' weight = fh(rho = 0, gamma = 0.5)) +#' +#' # Summarize simulations +#' simulation |> +#' summary(bound = gsDesign::gsDesign(k = 3, test.type = 1, sfu = gsDesign::sfLDOF)$upper$bound) |> +#' lt() +#' +#' # Summarize simulations and compare with the planned design +#' simulation |> +#' summary(design = design) |> +#' lt() +lt.simtrial_gs_wlr <- function(data, + title = "Summary of simulation results by WLR tests", + subtitle = NULL, ...){ + x <- data + + # The raw output of sim_gs_n() also carries the "simtrial_gs_wlr" class but is + # not a summary (it lacks the attributes added by summary()). In that case fall + # back to a plain lt table, mirroring how bare gt() used to render it. + if (is.null(attributes(x)$compare_with_design)) { + return(lt::lt(as.data.frame(x), ...)) + } + + # get the default subtitle + if (is.null(subtitle)) { + subtitle <- paste0("Weighted by ", attributes(x)$method) + } + + # if it is not compared with the design + if (attributes(x)$compare_with_design == "no") { + as.data.frame(x) |> + lt::lt() |> + lt::lt_label(sim_time = "Time", sim_n = "N", sim_event = "Event", sim_upper_prob = "Crossing probability") |> + lt::lt_move(columns = c("sim_time", "sim_n", "sim_event"), after = "analysis") |> + lt::lt_header(title = title, subtitle = subtitle) + } else { + # get the design type, either one-sided or two-sided + design_type <- attributes(x)$design_type + + # lt has no tidyselect, so enumerate the columns of each spanner explicitly. + # The columns must be listed in the same paired order (asymptotic before + # simulated) that lt_move() lays them out below, because lt matches a + # spanner to the visual position of its first column and then spans the + # next length(columns) columns; listing them in any other order would + # misalign the spanners (and silently drop later ones). + time_cols <- c("asy_time", "sim_time") + n_cols <- c("asy_n", "sim_n") + event_cols <- c("asy_event", "sim_event") + upper_cols <- c("asy_upper_prob", "sim_upper_prob") + lower_cols <- c("asy_lower_prob", "sim_lower_prob") + + # build an lt table as return, moving the paired asymptotic/simulated columns + # right after `analysis` so each spanner covers a contiguous block + ans <- as.data.frame(x) |> + lt::lt() |> + lt::lt_move( + columns = c(time_cols, n_cols, event_cols), + after = "analysis") + + # for a two-sided design, keep the efficacy (upper) and futility (lower) + # probability columns contiguous within their own spanners + if (design_type == "two-sided") { + ans <- ans |> + lt::lt_move( + columns = c(upper_cols, lower_cols), + after = "sim_event") + } + + ans <- ans |> + lt::lt_spanner(label = "Time", columns = time_cols) |> + lt::lt_spanner(label = "Events", columns = event_cols) |> + lt::lt_spanner(label = "N", columns = n_cols) |> + lt::lt_spanner( + label = "Probability of crossing efficacy bounds under H1", + columns = upper_cols) + + if (design_type == "two-sided") { + ans <- ans |> lt::lt_spanner( + label = "Probability of crossing futility bounds under H1", + columns = lower_cols) + } + + # label the asymptotic/simulated/analysis columns, mirroring the + # starts_with()/matches() rules used by gt::cols_label() in as_gt() + labels <- ifelse( + startsWith(names(x), "asy"), "Asymptotic", + ifelse(startsWith(names(x), "sim"), "Simulated", "Analysis")) + labels <- stats::setNames(as.list(labels), names(x)) + + do.call(lt::lt_label, c(list(ans), labels)) |> + lt::lt_header(title = title, subtitle = subtitle) + } +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 2a4fc697..e4fd5146 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -59,6 +59,7 @@ reference: - title: "Summarize simulations" contents: - summary.simtrial_gs_wlr + - lt.simtrial_gs_wlr - as_gt.simtrial_gs_wlr - title: "Randomization algorithms" diff --git a/man/as_gt.Rd b/man/as_gt.Rd index 8917196b..2270a58c 100644 --- a/man/as_gt.Rd +++ b/man/as_gt.Rd @@ -26,10 +26,16 @@ as_gt(x, ...) \value{ A gt table. -A gt table summarizing the simulation results. +A gt table summarizing the simulation results. This method is +deprecated; use \code{\link[=lt]{lt()}} instead. It still returns a \code{gt_tbl} object for one +release and requires \pkg{gt} to be installed. } \description{ -Convert summary table to a gt object +\code{as_gt()} is deprecated in favor of \code{\link[=lt]{lt()}}, which produces a lightweight +HTML table without the heavy \pkg{gt} dependency. \code{as_gt()} is kept for one +release so existing code that customizes the output with \pkg{gt} functions +keeps working; it still returns a \code{gt_tbl} object and requires \pkg{gt} to be +installed. New code should use \code{\link[=lt]{lt()}}; see \link{lt-methods} for details. } \examples{ @@ -92,3 +98,6 @@ simulation |> summary(design = design) |> simtrial::as_gt() } +\seealso{ +\code{\link[=lt]{lt()}}, \link{lt-methods} +} diff --git a/man/lt-methods.Rd b/man/lt-methods.Rd new file mode 100644 index 00000000..bf88e130 --- /dev/null +++ b/man/lt-methods.Rd @@ -0,0 +1,95 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lt.R +\name{lt-methods} +\alias{lt-methods} +\alias{lt.simtrial_gs_wlr} +\title{Create an lt table from a simulation summary} +\usage{ +\method{lt}{simtrial_gs_wlr}( + data, + title = "Summary of simulation results by WLR tests", + subtitle = NULL, + ... +) +} +\arguments{ +\item{data}{A summary object returned by \code{\link[=summary]{summary()}}.} + +\item{title}{Title of the lt table.} + +\item{subtitle}{Subtitle of the lt table.} + +\item{...}{Additional arguments (not used).} +} +\value{ +An \code{lt_tbl} object summarizing the simulation results. +} +\description{ +S3 method for \code{\link[=lt]{lt()}} that converts a group sequential simulation summary +(a \code{simtrial_gs_wlr} object returned by \code{\link[=summary]{summary()}}) into a formatted lt +table. This is the lightweight replacement for the deprecated \code{\link[=as_gt]{as_gt()}}. +} +\examples{ + +# Parameters for enrollment +enroll_rampup_duration <- 4 # Duration for enrollment ramp up +enroll_duration <- 16 # Total enrollment duration +enroll_rate <- gsDesign2::define_enroll_rate( + duration = c( + enroll_rampup_duration, enroll_duration - enroll_rampup_duration), + rate = c(10, 30)) + +# Parameters for treatment effect +delay_effect_duration <- 3 # Delay treatment effect in months +median_ctrl <- 9 # Survival median of the control arm +median_exp <- c(9, 14) # Survival median of the experimental arm +dropout_rate <- 0.001 +fail_rate <- gsDesign2::define_fail_rate( + duration = c(delay_effect_duration, 100), + fail_rate = log(2) / median_ctrl, + hr = median_ctrl / median_exp, + dropout_rate = dropout_rate) + +# Other related parameters +alpha <- 0.025 # Type I error +beta <- 0.1 # Type II error +ratio <- 1 # Randomization ratio (experimental:control) + +# Build a one-sided group sequential design +design <- gsDesign2::gs_design_ahr( + enroll_rate = enroll_rate, fail_rate = fail_rate, + ratio = ratio, alpha = alpha, beta = beta, + analysis_time = c(12, 24, 36), + upper = gsDesign2::gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = alpha), + lower = gsDesign2::gs_b, + lpar = rep(-Inf, 3)) + +# Define cuttings of 2 IAs and 1 FA +ia1_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[1])) +ia2_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[2])) +fa_cut <- create_cut(target_event_overall = ceiling(design$analysis$event[3])) + +# Run simulations +simulation <- sim_gs_n( + n_sim = 3, + sample_size = ceiling(design$analysis$n[3]), + enroll_rate = design$enroll_rate, + fail_rate = design$fail_rate, + test = wlr, + cut = list(ia1 = ia1_cut, ia2 = ia2_cut, fa = fa_cut), + weight = fh(rho = 0, gamma = 0.5)) + +# Summarize simulations +simulation |> + summary(bound = gsDesign::gsDesign(k = 3, test.type = 1, sfu = gsDesign::sfLDOF)$upper$bound) |> + lt() + +# Summarize simulations and compare with the planned design +simulation |> + summary(design = design) |> + lt() +} +\seealso{ +\code{\link[=as_gt]{as_gt()}} +} diff --git a/man/reexports.Rd b/man/reexports.Rd new file mode 100644 index 00000000..0e579bcf --- /dev/null +++ b/man/reexports.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lt.R +\docType{import} +\name{reexports} +\alias{reexports} +\alias{lt} +\title{Objects exported from other packages} +\keyword{internal} +\description{ +These objects are imported from other packages. Follow the links +below to see their documentation. + +\describe{ + \item{lt}{\code{\link[lt:lt]{lt()}}} +}} + diff --git a/vignettes/discrepancy-between-simtrial-and-survival.Rmd b/vignettes/discrepancy-between-simtrial-and-survival.Rmd index 0c46e35c..19019cdc 100644 --- a/vignettes/discrepancy-between-simtrial-and-survival.Rmd +++ b/vignettes/discrepancy-between-simtrial-and-survival.Rmd @@ -13,7 +13,6 @@ vignette: > library(gsDesign) library(gsDesign2) library(dplyr) -library(gt) library(simtrial) library(tidyr) library(survival) @@ -86,7 +85,7 @@ scenarios <- tribble( 6, "Strong null", 3, 18, .25, 6, "Strong null", 4, 12, .2, ) -# scenarios |> gt() +scenarios |> lt() ``` ```{r} @@ -103,7 +102,7 @@ fr <- scenarios |> select(-x_rate) |> filter(Period > 0, Scenario > 0) |> ungroup() -# fr |> gt() |> fmt_number(columns = everything(), decimals = 2) +fr |> lt() fr <- fr |> mutate(fail_rate = rate, dropout_rate = 0.001, stratum = "All") diff --git a/vignettes/maxcombo.Rmd b/vignettes/maxcombo.Rmd index 626dbf8f..02c4bf81 100644 --- a/vignettes/maxcombo.Rmd +++ b/vignettes/maxcombo.Rmd @@ -51,7 +51,7 @@ When more than one test is chosen the correlation between tests is computed as s library(simtrial) library(knitr) library(dplyr) -library(gt) +library(lt) ``` ```{r} @@ -64,8 +64,8 @@ x <- sim_fixed_n( ) x |> - gt() |> - fmt_number(columns = c("ln_hr", "z", "duration", "v1", "v2", "v3"), decimals = 2) + lt() |> + lt_format(columns = c("ln_hr", "z", "duration", "v1", "v2", "v3"), decimals = 2) ``` ### Generating data with `sim_pw_surv()` @@ -80,8 +80,8 @@ s <- sim_pw_surv(n = 100) s |> head() |> - gt() |> - fmt_number(columns = c("enroll_time", "fail_time", "dropout_time", "cte"), decimals = 2) + lt() |> + lt_format(columns = c("enroll_time", "fail_time", "dropout_time", "cte"), decimals = 2) ``` Once generated, we need to cut the data for analysis. Here we cut after 75 events. @@ -91,8 +91,8 @@ x <- s |> cut_data_by_event(75) x |> head() |> - gt() |> - fmt_number(columns = "tte", decimals = 2) + lt() |> + lt_format(columns = "tte", decimals = 2) ``` Now we can analyze this data. We begin with `s` to show how this can be done in a single line. @@ -127,7 +127,7 @@ In this case we use the small `aml` dataset from the survival package. library(survival) aml |> head() |> - gt() + lt() ``` We rename variables and create a stratum variable as follows: @@ -145,7 +145,7 @@ x <- aml |> transmute( x |> head() |> - gt() + lt() ``` Now we analyze the data with a MaxCombo with the logrank and FH(0, 1) and compute a $p$-value. diff --git a/vignettes/rmst.Rmd b/vignettes/rmst.Rmd index 8e10c822..09afd1fc 100644 --- a/vignettes/rmst.Rmd +++ b/vignettes/rmst.Rmd @@ -14,8 +14,7 @@ knitr::opts_chunk$set( comment = "#>" ) -run <- requireNamespace("gt", quietly = TRUE) && - requireNamespace("survRM2", quietly = TRUE) +run <- requireNamespace("survRM2", quietly = TRUE) knitr::opts_chunk$set(eval = run) ``` @@ -94,8 +93,6 @@ where $\alpha$ is a predefined significant level, and $z_{\alpha/2}$ is the uppe ```{r, message=FALSE, warning=FALSE} # Simulate NPH data from the piecewise model library(simtrial) -# Table display -library(gt) ``` ```{r} @@ -105,7 +102,7 @@ simtrial:::rmst_single_arm( time_var = data_single_arm$month, event_var = data_single_arm$evntd, tau = 10 -) |> gt() +) |> lt() ``` ## Estimation of RMST differences in 2 arms at a single time point diff --git a/vignettes/routines.Rmd b/vignettes/routines.Rmd index 07951bfb..cf495e9d 100644 --- a/vignettes/routines.Rmd +++ b/vignettes/routines.Rmd @@ -14,8 +14,7 @@ knitr::opts_chunk$set( comment = "#>" ) -run <- requireNamespace("dplyr", quietly = TRUE) && - requireNamespace("gt", quietly = TRUE) +run <- requireNamespace("dplyr", quietly = TRUE) knitr::opts_chunk$set(eval = run) ``` @@ -48,7 +47,7 @@ The package could be extended in many ways in the future, including: ```{r, message=FALSE, warning=FALSE} library(simtrial) -library(gt) +library(lt) library(dplyr) ``` @@ -143,8 +142,8 @@ x <- sim_pw_surv( ) head(x) |> - gt() |> - fmt_number(columns = c("enroll_time", "fail_time", "dropout_time", "cte"), decimals = 2) + lt() |> + lt_format(columns = c("enroll_time", "fail_time", "dropout_time", "cte"), decimals = 2) ``` ## Cutting data for analysis @@ -157,8 +156,8 @@ Observations enrolled after the input `cut_date` are deleted and events and cens y <- cut_data_by_date(x, cut_date = 5) head(y) |> - gt() |> - fmt_number(columns = "tte", decimals = 2) + lt() |> + lt_format(columns = "tte", decimals = 2) ``` For instance, if we wish to cut the entire dataset when 50 events are observed in the Positive stratum we can use the `get_cut_date_by_event` function as follows: @@ -186,8 +185,8 @@ The counting process format is further discussed in the next section where we co ten150 <- counting_process(y150, arm = "experimental") head(ten150) |> - gt() |> - fmt_number(columns = c("tte", "o_minus_e", "var_o_minus_e"), decimals = 2) + lt() |> + lt_format(columns = c("tte", "o_minus_e", "var_o_minus_e"), decimals = 2) ``` ## Logrank and weighted logrank testing @@ -282,8 +281,8 @@ sim_fixed_n( timing_type = 1:5, # Use all possible data cutoff methods rho_gamma = rho_gamma # FH test(s) to use; in this case, logrank ) |> - gt() |> - fmt_number(columns = c("ln_hr", "z", "duration")) + lt() |> + lt_format(columns = c("ln_hr", "z", "duration")) ``` If you look carefully, you should be asking why the cutoff with the planned number of events is so different than the other data cutoff methods. diff --git a/vignettes/sim_fixed_design_custom.Rmd b/vignettes/sim_fixed_design_custom.Rmd index 45223bcf..1ab3587a 100644 --- a/vignettes/sim_fixed_design_custom.Rmd +++ b/vignettes/sim_fixed_design_custom.Rmd @@ -12,7 +12,7 @@ vignette: > library(gsDesign2) library(simtrial) library(dplyr) -library(gt) +library(lt) library(doFuture) library(tibble) set.seed(2025) @@ -64,7 +64,7 @@ uncut_data_a <- sim_pw_surv(n = n, stratum = stratum, block = block, The output of `sim_pw_surv()` is subject-level observations, including stratum, enrollment time for the observation, treatment group the observation is randomized to, failure time, dropout time, calendar time of enrollment plot the minimum of failure time and dropout time ( `cte`), and an failure and dropout indicator (`fail = 1` is a failure, `fail = 0` is a dropout). ```{r} -uncut_data_a |> head() |> gt() |> tab_header("An Overview of Simulated TTE data") +uncut_data_a |> head() |> lt() |> lt_header("An Overview of Simulated TTE data") ``` ## Scenario b) Differential dropout rates @@ -208,7 +208,7 @@ cut_date <- cut_date_d cat("The cutoff date is ", round(cut_date, 2)) cut_data <- uncut_data |> cut_data_by_date(cut_date) -cut_data |> head() |> gt() |> tab_header(paste0("An Overview of TTE data Cut at ", round(cut_date, 2), "Months")) +cut_data |> head() |> lt() |> lt_header(paste0("An Overview of TTE data Cut at ", round(cut_date, 2), "Months")) ``` # Step 3: Run tests @@ -258,7 +258,7 @@ sim_res <- tribble( sim_res_mc$method, sim_res_mc$parameter, NA, NA, NA, sim_res_mc$p_value ) -sim_res |> gt() |> tab_header("One Simulation Results") +sim_res |> lt() |> lt_header("One Simulation Results") ``` @@ -354,7 +354,7 @@ plan("sequential") The output from the parallel computation resembles the output of `sim_fix_n()` described in the vignette [Simulate Fixed Designs with Ease via sim_fixed_n](https://merck.github.io/simtrial/articles/sim_fixed_design_simple.html). Each row in the output corresponds to the simulation results for each testing method per each repeation. ```{r} -ans |> head() |> gt() |> tab_header("Overview Each Simulation results") +ans |> head() |> lt() |> lt_header("Overview Each Simulation results") ``` # Step 5: Summarize simulations @@ -374,8 +374,8 @@ ans_mc <- ans |> ans_non_mc |> union(ans_mc) |> - gt() |> - tab_header("Summary from 100 simulations") + lt() |> + lt_header("Summary from 100 simulations") ``` diff --git a/vignettes/sim_fixed_design_simple.Rmd b/vignettes/sim_fixed_design_simple.Rmd index 532f4f6e..34b82682 100644 --- a/vignettes/sim_fixed_design_simple.Rmd +++ b/vignettes/sim_fixed_design_simple.Rmd @@ -12,7 +12,7 @@ vignette: > library(gsDesign2) library(simtrial) library(dplyr) -library(gt) +library(lt) set.seed(2027) ``` @@ -59,10 +59,10 @@ In this approach, users can obtain the sample size and targeted events from the x <- fixed_design_ahr(enroll_rate = enroll_rate, fail_rate = fail_rate, alpha = 0.025, power = 0.85, ratio = 1, study_duration = total_duration) |> to_integer() -x |> summary() |> gt() |> - tab_header(title = "Sample Size and Targeted Events Based on AHR Method", +x |> summary() |> lt() |> + lt_header(title = "Sample Size and Targeted Events Based on AHR Method", subtitle = "Fixed Design with 85% Power, One-sided 2.5% Type I error") |> - fmt_number(columns = c(4, 5, 7), decimals = 2) + lt_format(columns = c(4, 5, 7), decimals = 2) ``` Now we set the derived targeted sample size, enrollment rate, and event count from the above. @@ -109,9 +109,9 @@ Here we have just run 2 simulated trials and see how the different cutoffs vary ```{r} sim_res |> - gt() |> - tab_header("Tests for Each Simulation Result", subtitle = "Logrank Test for Different Analysis Cutoffs") |> - fmt_number(columns = c(4, 5, 7), decimals = 2) + lt() |> + lt_header("Tests for Each Simulation Result", subtitle = "Logrank Test for Different Analysis Cutoffs") |> + lt_format(columns = c(4, 5, 7), decimals = 2) ``` # Step 3: Summarize simulations @@ -142,10 +142,10 @@ sim_res |> `Mean duration` = mean(duration)) |> mutate(`Sample size` = sample_size, `Targeted events` = target_event) |> - gt() |> - tab_header(title = "Summary of 100 simulations by 5 different analysis cutoff methods", + lt() |> + lt_header(title = "Summary of 100 simulations by 5 different analysis cutoff methods", subtitle = "Tested by logrank") |> - fmt_number(columns = c(2:4), decimals = 2) + lt_format(columns = c(2:4), decimals = 2) ``` We can also do things like summarize distribution of event counts at the planned study duration. diff --git a/vignettes/sim_gs_design_simple.Rmd b/vignettes/sim_gs_design_simple.Rmd index a3712f50..d0c4a3b5 100644 --- a/vignettes/sim_gs_design_simple.Rmd +++ b/vignettes/sim_gs_design_simple.Rmd @@ -12,7 +12,7 @@ vignette: > library(gsDesign2) library(simtrial) library(dplyr) -library(gt) +library(lt) set.seed(2025) ``` @@ -165,8 +165,8 @@ The `z` column is the test statistic for the logrank test (estimate / se). The `info` and `info0` columns are the information at the current analysis under the alternate and null hypotheses, respectively. ```{r} -sim_res |> head(n = 6) |> gt() |> tab_header("Overview Each Simulation results") |> - fmt_number(columns = c(5, 8:12), decimals = 2) +sim_res |> head(n = 6) |> lt() |> lt_header("Overview Each Simulation results") |> + lt_format(columns = c(5, 8:12), decimals = 2) ``` # Step 3: Summarize simulations @@ -180,10 +180,10 @@ sim_res |> summarize(`Mean time` = mean(cut_date), `sd(time)` = sd(cut_date), `Simulated power` = mean(z >= eff_bound)) |> ungroup() |> mutate(`Asymptotic power` = x$bound$probability[x$bound$bound == "upper"]) |> - gt() |> - tab_header("Summary of 100 simulations") |> - fmt_number(columns = 2, decimals = 1) |> - fmt_number(columns = 3:5, decimals = 2) + lt() |> + lt_header("Summary of 100 simulations") |> + lt_format(columns = 2, decimals = 1) |> + lt_format(columns = 3:5, decimals = 2) ``` ## References