From cc714fd3c894151a027e4bcd134bc1602bdbf8ad Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 21 May 2026 14:05:05 -0400 Subject: [PATCH 01/12] Replace gt dependency with lt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the gt package dependency entirely and use the lightweight lt package for table rendering. This reduces install weight and aligns with the project's move toward minimal dependencies. Changes: - New as_lt() generic + methods replacing as_gt() - All vignettes updated: gt() → lt(), tab_header() → lt_header(), fmt_number() → lt_format(), tab_spanner() → lt_spanner(), tab_footnote() → lt_footnote()/lt_note(), cols_label() → lt_cols_label() - README.Rmd: use knitr::kable() for GitHub rendering - DESCRIPTION: gt removed from Imports, lt added - Tests updated for lt_tbl assertions Co-Authored-By: Claude Opus 4.6 --- DESCRIPTION | 2 +- NAMESPACE | 7 +- R/as_gt.R | 263 +------ R/as_lt.R | 260 +++++++ R/globals.R | 2 +- R/summary.R | 2 +- R/utility_tidy_tbl.R | 17 +- README.Rmd | 37 +- inst/achieved_vignettes/style.Rmd | 4 +- man/as_gt.Rd | 193 ----- tests/testit/helper.R | 2 - tests/testit/test-developer-as_gt.R | 22 - tests/testit/test-developer-as_lt.R | 26 + tests/testit/test-independent-gs_update_ahr.R | 1 - tests/testit/test-independent_as_gt.md | 693 ------------------ vignettes/articles/story-ahr-under-nph.Rmd | 32 +- .../story-compare-power-delay-effect.Rmd | 38 +- vignettes/articles/story-cp.Rmd | 6 +- vignettes/articles/story-design-with-ahr.Rmd | 38 +- .../articles/story-design-with-spending.Rmd | 11 +- vignettes/articles/story-integer-design.Rmd | 20 +- vignettes/articles/story-nph-futility.Rmd | 16 +- .../articles/story-package-architecture.Rmd | 6 +- ...y-power-evaluation-with-spending-bound.Rmd | 12 +- vignettes/articles/story-risk-difference.Rmd | 154 ++-- vignettes/articles/story-seven-test-types.Rmd | 18 +- .../articles/story-spending-time-example.Rmd | 74 +- vignettes/articles/story-update-boundary.Rmd | 18 +- vignettes/gsDesign2.Rmd | 16 +- 29 files changed, 518 insertions(+), 1472 deletions(-) create mode 100644 R/as_lt.R delete mode 100644 man/as_gt.Rd delete mode 100644 tests/testit/test-developer-as_gt.R create mode 100644 tests/testit/test-developer-as_lt.R delete mode 100644 tests/testit/test-independent_as_gt.md diff --git a/DESCRIPTION b/DESCRIPTION index 0f18853b1..b95ec4496 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,7 +43,7 @@ Imports: data.table, dplyr, gsDesign, - gt, + lt, methods, mvtnorm, npsurvSS (>= 1.1.0), diff --git a/NAMESPACE b/NAMESPACE index 3c12c9f04..dba88e9dc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,7 @@ # Generated by roxygen2: do not edit by hand -S3method(as_gt,fixed_design_summary) -S3method(as_gt,gs_design_summary) -S3method(as_gt,simtrial_gs_wlr) +S3method(as_lt,fixed_design_summary) +S3method(as_lt,gs_design_summary) S3method(as_rtf,fixed_design_summary) S3method(as_rtf,gs_design_summary) S3method(print,fixed_design) @@ -13,7 +12,7 @@ S3method(to_integer,fixed_design) S3method(to_integer,gs_design) export(ahr) export(ahr_blinded) -export(as_gt) +export(as_lt) export(as_rtf) export(define_enroll_rate) export(define_fail_rate) diff --git a/R/as_gt.R b/R/as_gt.R index c7a2b8bb0..6c97f2727 100644 --- a/R/as_gt.R +++ b/R/as_gt.R @@ -16,258 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -#' Convert summary table of a fixed or group sequential design object to a gt object -#' -#' @param x A summary object of a fixed or group sequential design. -#' @param ... Additional arguments (not used). -#' -#' @return A `gt_tbl` object. -#' -#' @export -as_gt <- function(x, ...) { - UseMethod("as_gt", x) -} - -#' @rdname as_gt -#' -#' @export -#' -#' @examples -#' # Fixed design examples ---- -#' -#' # Enrollment rate -#' enroll_rate <- define_enroll_rate( -#' duration = 18, -#' rate = 20 -#' ) -#' -#' # Failure rates -#' fail_rate <- define_fail_rate( -#' duration = c(4, 100), -#' fail_rate = log(2) / 12, -#' dropout_rate = .001, -#' hr = c(1, .6) -#' ) -#' -#' # Study duration in months -#' study_duration <- 36 -#' -#' # Experimental / Control randomization ratio -#' ratio <- 1 -#' -#' # 1-sided Type I error -#' alpha <- 0.025 -#' -#' # Type II error (1 - power) -#' beta <- 0.1 -#' -#' # Example 1 ---- -#' fixed_design_ahr( -#' alpha = alpha, power = 1 - beta, -#' enroll_rate = enroll_rate, fail_rate = fail_rate, -#' study_duration = study_duration, ratio = ratio -#' ) |> -#' summary() |> -#' as_gt() -#' -#' # Example 2 ---- -#' fixed_design_fh( -#' alpha = alpha, power = 1 - beta, -#' enroll_rate = enroll_rate, fail_rate = fail_rate, -#' study_duration = study_duration, ratio = ratio -#' ) |> -#' summary() |> -#' as_gt() -as_gt.fixed_design_summary <- function(x, title = NULL, footnote = NULL, ...) { - if (is.null(title)) title <- attr(x, "title") - if (is.null(footnote)) footnote <- attr(x, "footnote") - - ans <- gt::gt(x) |> - gt::tab_header(title = title) - - if (!isFALSE(footnote)) { - ans <- ans |> - gt::tab_footnote( - footnote = footnote, - locations = gt::cells_title(group = "title") - ) - } - - return(ans) -} - -#' @rdname as_gt -#' -#' @param title A string to specify the title of the gt table. -#' @param subtitle A string to specify the subtitle of the gt table. -#' @param colname_spanner A string to specify the spanner of the gt table. -#' @param colname_spannersub A vector of strings to specify the spanner details -#' of the gt table. -#' @param footnote A list containing `content`, `location`, and `attr`. -#' `content` is a vector of string to specify the footnote text; `location` is -#' a vector of string to specify the locations to put the superscript of the -#' footnote index; `attr` is a vector of string to specify the attributes of -#' the footnotes, for example, `c("colname", "title", "subtitle", "analysis", -#' "spanner")`; users can use the functions in the `gt` package to customize -#' the table. To disable footnotes, use `footnote = FALSE`. -#' @param display_bound A vector of strings specifying the label of the bounds. -#' The default is `c("Efficacy", "Futility")`. -#' @param display_columns A vector of strings specifying the variables to be -#' displayed in the summary table. -#' @param display_inf_bound Logical, whether to display the +/-inf bound. -#' -#' @export -#' -#' @examples -#' \donttest{ -#' # Group sequential design examples --- -#' -#' # Example 1 ---- -#' # The default output -#' -#' gs_design_ahr() |> -#' summary() |> -#' as_gt() -#' -#' gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt() -#' -#' gs_design_wlr() |> -#' summary() |> -#' as_gt() -#' -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt() -#' -#' gs_power_combo() |> -#' summary() |> -#' as_gt() -#' -#' gs_design_rd() |> -#' summary() |> -#' as_gt() -#' -#' gs_power_rd() |> -#' summary() |> -#' as_gt() -#' -#' # Example 2 ---- -#' # Usage of title = ..., subtitle = ... -#' # to edit the title/subtitle -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt( -#' title = "Bound Summary", -#' subtitle = "from gs_power_wlr" -#' ) -#' -#' # Example 3 ---- -#' # Usage of colname_spanner = ..., colname_spannersub = ... -#' # to edit the spanner and its sub-spanner -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt( -#' colname_spanner = "Cumulative probability to cross boundaries", -#' colname_spannersub = c("under H1", "under H0") -#' ) -#' -#' # Example 4 ---- -#' # Usage of footnote = ... -#' # to edit the footnote -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt( -#' footnote = list( -#' content = c( -#' "approximate weighted hazard ratio to cross bound.", -#' "wAHR is the weighted AHR.", -#' "the crossing probability.", -#' "this table is generated by gs_power_wlr." -#' ), -#' location = c("~wHR at bound", NA, NA, NA), -#' attr = c("colname", "analysis", "spanner", "title") -#' ) -#' ) -#' -#' # Example 5 ---- -#' # Usage of display_bound = ... -#' # to either show efficacy bound or futility bound, or both(default) -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt(display_bound = "Efficacy") -#' -#' # Example 6 ---- -#' # Usage of display_columns = ... -#' # to select the columns to display in the summary table -#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> -#' summary() |> -#' as_gt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) -#' } -as_gt.gs_design_summary <- function( - x, - title = NULL, - subtitle = NULL, - colname_spanner = "Cumulative boundary crossing probability", - colname_spannersub = c("Alternate hypothesis", "Null hypothesis"), - footnote = NULL, - display_bound = c("Efficacy", "Futility"), - display_columns = NULL, - display_inf_bound = FALSE, - ...) { - - x_old <- x - parts <- gsd_parts( - x, title, subtitle, colname_spannersub, footnote, - display_bound, display_columns, display_inf_bound - ) - - x <- parts$x |> - group_by(Analysis) |> - gt::gt() |> - gt::tab_spanner( - columns = all_of(colname_spannersub), - label = colname_spanner - ) |> - gt::tab_header(title = parts$title, subtitle = parts$subtitle) - - # Add footnotes ---- - add_footnote <- !isFALSE(footnote) - footnote <- parts$footnote - for (i in seq_along(footnote$content)) { - att <- footnote$attr[i] - loc <- if (att == "colname") { - # footnotes are added on the colnames - gt::cells_column_labels(columns = footnote$location[i]) - } else if (att %in% c("title", "subtitle")) { - # on the title/subtitle - gt::cells_title(group = att) - } else if (att == "analysis") { - # on the analysis summary row, which is a grouping variable, i.e., Analysis - gt::cells_row_groups(groups = dplyr::starts_with("Analysis")) - } else if (att == "spanner") { - # on the column spanner - gt::cells_column_spanners(spanners = colname_spanner) - } - if (!is.null(loc)) - x <- gt::tab_footnote(x, footnote = footnote$content[i], locations = loc) - } - - # add footnote for non-binding design - footnote_nb <- if (add_footnote) gsd_footnote_nb(x_old, parts$alpha) - if (!is.null(footnote_nb)) x <- gt::tab_footnote( - x, - footnote = footnote_nb, - locations = gt::cells_body( - columns = colname_spannersub[2], - rows = gsd_footnote_row(parts$x, display_bound[1]) - ) - ) - - return(x) -} - # get different default columns to display gsd_columns <- function(columns, method, x) { # set different default columns to display @@ -349,7 +97,7 @@ gsd_footnote_row <- function(x, bound) { i & x$Bound == bound } -# a list of information for `as_[gt|rtf].gs_design()` methods: the transformed +# a list of information for `as_[lt|rtf].gs_design()` methods: the transformed # data, title, and footnote, etc. gsd_parts <- function( x, title, subtitle, spannersub, footnote, bound, columns, inf_bound, @@ -388,12 +136,3 @@ gsd_parts <- function( alpha = max(filter(x, Bound == bound[1])[["Null hypothesis"]]) ) } - -# Only purpose of the method below is to fix S3 redirection when gsDesign2 is -# loaded after simtrial, which masks the as_gt() generic from simtrial - -#' @export -as_gt.simtrial_gs_wlr <- function(x, ...) { - f <- getFromNamespace("as_gt.simtrial_gs_wlr", "simtrial") - f(x, ...) -} diff --git a/R/as_lt.R b/R/as_lt.R new file mode 100644 index 000000000..4580c3069 --- /dev/null +++ b/R/as_lt.R @@ -0,0 +1,260 @@ +# Copyright (c) 2025 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. +# All rights reserved. +# +# This file is part of the gsDesign2 program. +# +# gsDesign2 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 . + +#' Convert summary table of a fixed or group sequential design object to an lt table +#' +#' @param x A summary object of a fixed or group sequential design. +#' @param ... Additional arguments (not used). +#' +#' @return An `lt_tbl` object. +#' +#' @export +as_lt <- function(x, ...) { + UseMethod("as_lt", x) +} + +#' @rdname as_lt +#' +#' @export +#' +#' @examples +#' # Fixed design examples ---- +#' +#' # Enrollment rate +#' enroll_rate <- define_enroll_rate( +#' duration = 18, +#' rate = 20 +#' ) +#' +#' # Failure rates +#' fail_rate <- define_fail_rate( +#' duration = c(4, 100), +#' fail_rate = log(2) / 12, +#' dropout_rate = .001, +#' hr = c(1, .6) +#' ) +#' +#' # Study duration in months +#' study_duration <- 36 +#' +#' # Experimental / Control randomization ratio +#' ratio <- 1 +#' +#' # 1-sided Type I error +#' alpha <- 0.025 +#' +#' # Type II error (1 - power) +#' beta <- 0.1 +#' +#' # Example 1 ---- +#' fixed_design_ahr( +#' alpha = alpha, power = 1 - beta, +#' enroll_rate = enroll_rate, fail_rate = fail_rate, +#' study_duration = study_duration, ratio = ratio +#' ) |> +#' summary() |> +#' as_lt() +#' +#' # Example 2 ---- +#' fixed_design_fh( +#' alpha = alpha, power = 1 - beta, +#' enroll_rate = enroll_rate, fail_rate = fail_rate, +#' study_duration = study_duration, ratio = ratio +#' ) |> +#' summary() |> +#' as_lt() +as_lt.fixed_design_summary <- function(x, title = NULL, footnote = NULL, ...) { + if (is.null(title)) title <- attr(x, "title") + if (is.null(footnote)) footnote <- attr(x, "footnote") + + ans <- lt::lt(as.data.frame(x)) |> + lt::lt_header(title = title) + + if (!isFALSE(footnote)) { + ans <- ans |> + lt::lt_footnote(text = footnote, where = "title") + } + + ans +} + +#' @rdname as_lt +#' +#' @param title A string to specify the title of the table. +#' @param subtitle A string to specify the subtitle of the table. +#' @param colname_spanner A string to specify the spanner of the table. +#' @param colname_spannersub A vector of strings to specify the spanner details +#' of the table. +#' @param footnote A list containing `content`, `location`, and `attr`. +#' `content` is a vector of string to specify the footnote text; `location` is +#' a vector of string to specify the locations to put the superscript of the +#' footnote index; `attr` is a vector of string to specify the attributes of +#' the footnotes, for example, `c("colname", "title", "subtitle", "analysis", +#' "spanner")`. To disable footnotes, use `footnote = FALSE`. +#' @param display_bound A vector of strings specifying the label of the bounds. +#' The default is `c("Efficacy", "Futility")`. +#' @param display_columns A vector of strings specifying the variables to be +#' displayed in the summary table. +#' @param display_inf_bound Logical, whether to display the +/-inf bound. +#' +#' @export +#' +#' @examples +#' \donttest{ +#' # Group sequential design examples --- +#' +#' # Example 1 ---- +#' # The default output +#' +#' gs_design_ahr() |> +#' summary() |> +#' as_lt() +#' +#' gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt() +#' +#' gs_design_wlr() |> +#' summary() |> +#' as_lt() +#' +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt() +#' +#' gs_power_combo() |> +#' summary() |> +#' as_lt() +#' +#' gs_design_rd() |> +#' summary() |> +#' as_lt() +#' +#' gs_power_rd() |> +#' summary() |> +#' as_lt() +#' +#' # Example 2 ---- +#' # Usage of title = ..., subtitle = ... +#' # to edit the title/subtitle +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt( +#' title = "Bound Summary", +#' subtitle = "from gs_power_wlr" +#' ) +#' +#' # Example 3 ---- +#' # Usage of colname_spanner = ..., colname_spannersub = ... +#' # to edit the spanner and its sub-spanner +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt( +#' colname_spanner = "Cumulative probability to cross boundaries", +#' colname_spannersub = c("under H1", "under H0") +#' ) +#' +#' # Example 4 ---- +#' # Usage of footnote = ... +#' # to edit the footnote +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt( +#' footnote = list( +#' content = c( +#' "approximate weighted hazard ratio to cross bound.", +#' "wAHR is the weighted AHR.", +#' "the crossing probability.", +#' "this table is generated by gs_power_wlr." +#' ), +#' location = c("~wHR at bound", NA, NA, NA), +#' attr = c("colname", "analysis", "spanner", "title") +#' ) +#' ) +#' +#' # Example 5 ---- +#' # Usage of display_bound = ... +#' # to either show efficacy bound or futility bound, or both(default) +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt(display_bound = "Efficacy") +#' +#' # Example 6 ---- +#' # Usage of display_columns = ... +#' # to select the columns to display in the summary table +#' gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> +#' summary() |> +#' as_lt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) +#' } +as_lt.gs_design_summary <- function( + x, + title = NULL, + subtitle = NULL, + colname_spanner = "Cumulative boundary crossing probability", + colname_spannersub = c("Alternate hypothesis", "Null hypothesis"), + footnote = NULL, + display_bound = c("Efficacy", "Futility"), + display_columns = NULL, + display_inf_bound = FALSE, + ...) { + + x_old <- x + parts <- gsd_parts( + x, title, subtitle, colname_spannersub, footnote, + display_bound, display_columns, display_inf_bound + ) + + ans <- lt::lt(as.data.frame(parts$x), row_group = "Analysis") |> + lt::lt_spanner( + label = colname_spanner, + columns = colname_spannersub + ) |> + lt::lt_header(title = parts$title, subtitle = parts$subtitle) + + # Add footnotes + add_footnote <- !isFALSE(footnote) + footnote <- parts$footnote + for (i in seq_along(footnote$content)) { + att <- footnote$attr[i] + if (att == "colname") { + ans <- lt::lt_footnote(ans, text = footnote$content[i], + where = "column", columns = footnote$location[i]) + } else if (att == "title") { + ans <- lt::lt_footnote(ans, text = footnote$content[i], where = "title") + } else if (att == "subtitle") { + ans <- lt::lt_footnote(ans, text = footnote$content[i], where = "subtitle") + } else if (att == "analysis") { + ans <- lt::lt_footnote(ans, text = footnote$content[i], + where = "group", columns = "Analysis", + match = "starts_with") + } else if (att == "spanner") { + ans <- lt::lt_footnote(ans, text = footnote$content[i], + where = "spanner", columns = colname_spanner) + } + } + + # Add footnote for non-binding design + footnote_nb <- if (add_footnote) gsd_footnote_nb(x_old, parts$alpha) + if (!is.null(footnote_nb)) { + rows <- which(gsd_footnote_row(parts$x, display_bound[1])) + ans <- lt::lt_footnote(ans, text = footnote_nb, where = "body", + columns = colname_spannersub[2], rows = rows) + } + + ans +} diff --git a/R/globals.R b/R/globals.R index 3adf300d0..112eef4a0 100644 --- a/R/globals.R +++ b/R/globals.R @@ -25,7 +25,7 @@ utils::globalVariables( c("stratum", "rate", "hr", "treatment", "time", "info0", "info"), # From `ahr_blinded()` c("status"), - # From `as_gt.gs_design()` + # From `as_lt.gs_design()` c("Bound", "Alternate hypothesis", "Null hypothesis", "Analysis"), # From `expected_accrual()` c("stratum", "rate", "duration"), diff --git a/R/summary.R b/R/summary.R index 821944c9d..50965eddc 100644 --- a/R/summary.R +++ b/R/summary.R @@ -82,7 +82,7 @@ summary.fixed_design <- function(object, ...) { # capitalize names ans <- cap_names(ans) - # Propagate attributes for as_gt()/as_rtf() tables + # Propagate attributes for as_lt()/as_rtf() tables attr(ans, "title") <- attr(object, "title") attr(ans, "footnote") <- attr(object, "footnote") diff --git a/R/utility_tidy_tbl.R b/R/utility_tidy_tbl.R index 423b1682f..1661033a8 100644 --- a/R/utility_tidy_tbl.R +++ b/R/utility_tidy_tbl.R @@ -37,7 +37,7 @@ #' #' @examples #' library(tidyr) -#' library(gt) +#' library(lt) #' a <- data.frame(Index = 1:2, a1 = c(1.1234, 5.9876), a2 = c("text 1", "text 2"), a3 = c(3.12, 4.98)) #' b <- data.frame( #' Index = c(1, 2, 2), @@ -46,17 +46,16 @@ #' b3 = (10:8) / 3 #' ) #' table_ab(a, b, byvar = "Index", decimals = c(0, 2, 0, 1), aname = "Index") |> -#' group_by(Index) |> -#' gt() |> -#' fmt_number(b3, decimals = 2) |> -#' tab_header(title = "Grouped data table") |> -#' tab_footnote( +#' lt(row_group = "Index") |> +#' lt_format("b3", decimals = 2) |> +#' lt_header(title = "Grouped data table") |> +#' lt_footnote( #' "The table a variables have been concatenated into a text string, rounded appropriately.", -#' cells_row_groups(groups = 1) +#' where = "group", columns = "1" #' ) |> -#' tab_footnote( +#' lt_footnote( #' "Note that footnotes cannot be made for individual variables in the row groups generated using table a.", -#' cells_row_groups(groups = 2) +#' where = "group", columns = "2" #' ) table_ab <- function(table_a, table_b, byvar, decimals = 1, aname = names(table_a)[1]) { anames <- names(table_a) diff --git a/README.Rmd b/README.Rmd index 8b6693bb9..bddd0b81a 100644 --- a/README.Rmd +++ b/README.Rmd @@ -96,13 +96,11 @@ rows and strata as needed can be specified to approximate whatever patterns you wish. ```{r, eval = FALSE} -fail_rate |> gt::gt() +fail_rate |> lt() ``` -```{r, echo = FALSE, eval = getRversion() >= "4.1"} -fail_rate |> - gt::gt() |> - gt::as_raw_html(inline_css = FALSE) +```{r, echo = FALSE} +knitr::kable(fail_rate) ``` ### Step 2: derive a fixed design with no interim analyses @@ -126,13 +124,11 @@ fd <- fixed_design_ahr( The input enrollment rates have now been scaled to achieve power: ```{r, eval = FALSE} -fd$enroll_rate |> gt::gt() +fd$enroll_rate |> lt() ``` -```{r, echo = FALSE, eval = getRversion() >= "4.1"} -fd$enroll_rate |> - gt::gt() |> - gt::as_raw_html(inline_css = FALSE) +```{r, echo = FALSE} +knitr::kable(fd$enroll_rate) ``` The failure and dropout rates remain unchanged from what was input. @@ -149,14 +145,11 @@ The summary is obtained below. The columns are: ```{r, eval = FALSE} fd |> summary() |> - as_gt() + as_lt() ``` -```{r, echo = FALSE, eval = getRversion() >= "4.1"} -fd |> - summary() |> - as_gt() |> - gt::as_raw_html(inline_css = FALSE) +```{r, echo = FALSE} +knitr::kable(fd |> summary()) ``` ### Step 3: group sequential design @@ -200,8 +193,7 @@ gsd <- gs_design_ahr( ``` Now we summarize the derived design. The summary table is further described -in the vignette [summarize group sequential designs in gt -tables](https://merck.github.io/gsDesign2/articles/story-summarize-designs.html). +in the vignette [summarize group sequential designs](https://merck.github.io/gsDesign2/articles/story-summarize-designs.html). Note that the design trend in favor of experimental treatment is very minor at 8 months due to the delayed effect assumption used (see AHR at analysis 1 in table). The design trend at 16 months is somewhat @@ -213,12 +205,9 @@ provocative for what might be considered. ```{r, eval = FALSE} gsd |> summary() |> - as_gt() + as_lt() ``` -```{r, echo = FALSE, eval = getRversion() >= "4.1"} -gsd |> - summary() |> - as_gt() |> - gt::as_raw_html(inline_css = FALSE) +```{r, echo = FALSE} +knitr::kable(gsd |> summary()) ``` diff --git a/inst/achieved_vignettes/style.Rmd b/inst/achieved_vignettes/style.Rmd index 7954e8d6a..6cccdc6f6 100644 --- a/inst/achieved_vignettes/style.Rmd +++ b/inst/achieved_vignettes/style.Rmd @@ -64,10 +64,10 @@ connect the method name and class name. ```r # Good -as_gt.gsDesign <- function(...) {} +as_lt.gsDesign <- function(...) {} # Bad -as.gt.gsDesign <- function(...) {} +as.lt.gsDesign <- function(...) {} ``` ## Object-oriented API diff --git a/man/as_gt.Rd b/man/as_gt.Rd deleted file mode 100644 index 4912d73de..000000000 --- a/man/as_gt.Rd +++ /dev/null @@ -1,193 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/as_gt.R -\name{as_gt} -\alias{as_gt} -\alias{as_gt.fixed_design_summary} -\alias{as_gt.gs_design_summary} -\title{Convert summary table of a fixed or group sequential design object to a gt object} -\usage{ -as_gt(x, ...) - -\method{as_gt}{fixed_design_summary}(x, title = NULL, footnote = NULL, ...) - -\method{as_gt}{gs_design_summary}( - x, - title = NULL, - subtitle = NULL, - colname_spanner = "Cumulative boundary crossing probability", - colname_spannersub = c("Alternate hypothesis", "Null hypothesis"), - footnote = NULL, - display_bound = c("Efficacy", "Futility"), - display_columns = NULL, - display_inf_bound = FALSE, - ... -) -} -\arguments{ -\item{x}{A summary object of a fixed or group sequential design.} - -\item{...}{Additional arguments (not used).} - -\item{title}{A string to specify the title of the gt table.} - -\item{footnote}{A list containing \code{content}, \code{location}, and \code{attr}. -\code{content} is a vector of string to specify the footnote text; \code{location} is -a vector of string to specify the locations to put the superscript of the -footnote index; \code{attr} is a vector of string to specify the attributes of -the footnotes, for example, \code{c("colname", "title", "subtitle", "analysis", "spanner")}; users can use the functions in the \code{gt} package to customize -the table. To disable footnotes, use \code{footnote = FALSE}.} - -\item{subtitle}{A string to specify the subtitle of the gt table.} - -\item{colname_spanner}{A string to specify the spanner of the gt table.} - -\item{colname_spannersub}{A vector of strings to specify the spanner details -of the gt table.} - -\item{display_bound}{A vector of strings specifying the label of the bounds. -The default is \code{c("Efficacy", "Futility")}.} - -\item{display_columns}{A vector of strings specifying the variables to be -displayed in the summary table.} - -\item{display_inf_bound}{Logical, whether to display the +/-inf bound.} -} -\value{ -A \code{gt_tbl} object. -} -\description{ -Convert summary table of a fixed or group sequential design object to a gt object -} -\examples{ -# Fixed design examples ---- - -# Enrollment rate -enroll_rate <- define_enroll_rate( - duration = 18, - rate = 20 -) - -# Failure rates -fail_rate <- define_fail_rate( - duration = c(4, 100), - fail_rate = log(2) / 12, - dropout_rate = .001, - hr = c(1, .6) -) - -# Study duration in months -study_duration <- 36 - -# Experimental / Control randomization ratio -ratio <- 1 - -# 1-sided Type I error -alpha <- 0.025 - -# Type II error (1 - power) -beta <- 0.1 - -# Example 1 ---- -fixed_design_ahr( - alpha = alpha, power = 1 - beta, - enroll_rate = enroll_rate, fail_rate = fail_rate, - study_duration = study_duration, ratio = ratio -) |> - summary() |> - as_gt() - -# Example 2 ---- -fixed_design_fh( - alpha = alpha, power = 1 - beta, - enroll_rate = enroll_rate, fail_rate = fail_rate, - study_duration = study_duration, ratio = ratio -) |> - summary() |> - as_gt() -\donttest{ -# Group sequential design examples --- - -# Example 1 ---- -# The default output - -gs_design_ahr() |> - summary() |> - as_gt() - -gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt() - -gs_design_wlr() |> - summary() |> - as_gt() - -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt() - -gs_power_combo() |> - summary() |> - as_gt() - -gs_design_rd() |> - summary() |> - as_gt() - -gs_power_rd() |> - summary() |> - as_gt() - -# Example 2 ---- -# Usage of title = ..., subtitle = ... -# to edit the title/subtitle -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - title = "Bound Summary", - subtitle = "from gs_power_wlr" - ) - -# Example 3 ---- -# Usage of colname_spanner = ..., colname_spannersub = ... -# to edit the spanner and its sub-spanner -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - colname_spanner = "Cumulative probability to cross boundaries", - colname_spannersub = c("under H1", "under H0") - ) - -# Example 4 ---- -# Usage of footnote = ... -# to edit the footnote -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - footnote = list( - content = c( - "approximate weighted hazard ratio to cross bound.", - "wAHR is the weighted AHR.", - "the crossing probability.", - "this table is generated by gs_power_wlr." - ), - location = c("~wHR at bound", NA, NA, NA), - attr = c("colname", "analysis", "spanner", "title") - ) - ) - -# Example 5 ---- -# Usage of display_bound = ... -# to either show efficacy bound or futility bound, or both(default) -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt(display_bound = "Efficacy") - -# Example 6 ---- -# Usage of display_columns = ... -# to select the columns to display in the summary table -gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) -} -} diff --git a/tests/testit/helper.R b/tests/testit/helper.R index f1c33dd55..662884c23 100644 --- a/tests/testit/helper.R +++ b/tests/testit/helper.R @@ -1,5 +1,3 @@ -gt_to_latex <- function(data) cat(as.character(gt::as_latex(data))) - test_event <- function(enroll_rate, fail_rate, td = 15) { enroll_rate_1 <- enroll_rate enroll_rate_1$rate <- enroll_rate$rate / 2 diff --git a/tests/testit/test-developer-as_gt.R b/tests/testit/test-developer-as_gt.R deleted file mode 100644 index 1c3ef5773..000000000 --- a/tests/testit/test-developer-as_gt.R +++ /dev/null @@ -1,22 +0,0 @@ -assert("footnote=FALSE removes footnote", { - - # fixed design - x <- fixed_design_ahr( - enroll_rate = define_enroll_rate(duration = 18, rate = 1), - fail_rate = define_fail_rate(duration = 18, fail_rate = 0.1, dropout_rate = 0.001) - ) - y <- summary(x) - z1 <- as_gt(y) - (nrow(z1$`_footnotes`) %==% 1L) - z2 <- as_gt(y, footnote = FALSE) - (nrow(z2$`_footnotes`) %==% 0L) - - # gs design - x <- gs_design_ahr() - y <- summary(x) - z1 <- as_gt(y) - (nrow(z1$`_footnotes`) %==% 2L) - z2 <- as_gt(y, footnote = FALSE) - (nrow(z2$`_footnotes`) %==% 0L) - -}) diff --git a/tests/testit/test-developer-as_lt.R b/tests/testit/test-developer-as_lt.R new file mode 100644 index 000000000..c505cecc5 --- /dev/null +++ b/tests/testit/test-developer-as_lt.R @@ -0,0 +1,26 @@ +count_footnotes <- function(x) { + sum(vapply(x$ops, function(op) op$type == "footnote", logical(1))) +} + +assert("as_lt: footnote=FALSE removes footnote", { + + # fixed design + x <- fixed_design_ahr( + enroll_rate = define_enroll_rate(duration = 18, rate = 1), + fail_rate = define_fail_rate(duration = 18, fail_rate = 0.1, dropout_rate = 0.001) + ) + y <- summary(x) + z1 <- as_lt(y) + (count_footnotes(z1) %==% 1L) + z2 <- as_lt(y, footnote = FALSE) + (count_footnotes(z2) %==% 0L) + + # gs design + x <- gs_design_ahr() + y <- summary(x) + z1 <- as_lt(y) + (count_footnotes(z1) %==% 2L) + z2 <- as_lt(y, footnote = FALSE) + (count_footnotes(z2) %==% 0L) + +}) diff --git a/tests/testit/test-independent-gs_update_ahr.R b/tests/testit/test-independent-gs_update_ahr.R index a060958f5..c1d7b4cbd 100644 --- a/tests/testit/test-independent-gs_update_ahr.R +++ b/tests/testit/test-independent-gs_update_ahr.R @@ -1,5 +1,4 @@ library(gsDesign2) -library(gt) library(dplyr) library(simtrial) library(testit) diff --git a/tests/testit/test-independent_as_gt.md b/tests/testit/test-independent_as_gt.md deleted file mode 100644 index c47fb1e89..000000000 --- a/tests/testit/test-independent_as_gt.md +++ /dev/null @@ -1,693 +0,0 @@ -## `fixed_design()` summary `as_gt()` - -```r -enroll_rate <- define_enroll_rate(duration = 18, rate = 20) - fail_rate <- define_fail_rate( - duration = c(4, 100), - fail_rate = log(2) / 12, - dropout_rate = .001, hr = c(1, .6) - ) - - output <- fixed_design_ahr( - alpha = 0.025, - power = 1 - 0.1, - enroll_rate = enroll_rate, - fail_rate = fail_rate, - study_duration = 36, - ratio = 1 - ) |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Fixed Design under AHR Method\textsuperscript{\textit{1}}\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrrrr} -\toprule -Design & N & Events & Time & AHR & Bound & alpha & Power \\ -\midrule\addlinespace[2.5pt] -Average hazard ratio & 463.078 & 324.7077 & 36 & 0.697102 & 1.959964 & 0.025 & 0.9 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}Power computed with average hazard ratio method.\\ -\end{minipage} -\end{table} -``` - -## `fixed_design()` summary `as_gt()` with custom title and footnote - -```r -enroll_rate <- define_enroll_rate(duration = 18, rate = 20) - fail_rate <- define_fail_rate( - duration = c(4, 100), - fail_rate = log(2) / 12, - dropout_rate = .001, hr = c(1, .6) - ) - - output <- fixed_design_ahr( - alpha = 0.025, - power = 1 - 0.1, - enroll_rate = enroll_rate, - fail_rate = fail_rate, - study_duration = 36, - ratio = 1 - ) |> - summary() |> - as_gt(title = "Custom Title", footnote = "Custom footnote.") -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Custom Title\textsuperscript{\textit{1}}\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrrrr} -\toprule -Design & N & Events & Time & AHR & Bound & alpha & Power \\ -\midrule\addlinespace[2.5pt] -Average hazard ratio & 463.078 & 324.7077 & 36 & 0.697102 & 1.959964 & 0.025 & 0.9 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}Custom footnote.\\ -\end{minipage} -\end{table} -``` - -## `fixed_design_fh()` summary `as_gt()` - -```r -enroll_rate <- define_enroll_rate( - duration = 18, - rate = 20 - ) - fail_rate <- define_fail_rate( - duration = c(4, 100), - fail_rate = log(2) / 12, - dropout_rate = .001, - hr = c(1, .6) - ) - - output <- fixed_design_fh( - alpha = 0.025, - power = 1 - 0.1, - enroll_rate = enroll_rate, - fail_rate = fail_rate, - study_duration = 36, - ratio = 1 - ) |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Fixed Design under Fleming-Harrington Method\textsuperscript{\textit{1}}\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrrrr} -\toprule -Design & N & Events & Time & AHR & Bound & alpha & Power \\ -\midrule\addlinespace[2.5pt] -Fleming-Harrington FH(0, 0) (logrank) & 458.3509 & 321.3931 & 36 & 0.6969049 & 1.959964 & 0.025 & 0.9 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}Power for Fleming-Harrington test FH(0, 0) (logrank) using method of Yung and Liu.\\ -\end{minipage} -\end{table} -``` - -## `gs_design_ahr()` summary `as_gt()` - -```r -output <- gs_design_ahr() |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for AHR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont AHR approximations of \textasciitilde{}HR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}HR at bound\textsuperscript{\textit{2}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 36 N: 476 Events: 291.9 AHR: 0.68 Information fraction: 1} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 1.96 & 0.025 & 0.795 & 0.9 & 0.025 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_ahr()` summary `as_gt()` - -```r -output <- gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for AHR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont AHR approximations of \textasciitilde{}HR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}HR at bound\textsuperscript{\textit{2}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.17 & 0.8792 & 1.5336 & 0.0349 & 0.1208 \\ -Efficacy & 2.67 & 0.0038 & 0.3774 & 0.0231 & 0.0038 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.74 Information fraction: 0.8} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.66 & 0.7462 & 1.2331 & 0.0668 & 0.2655 \\ -Efficacy & 2.29 & 0.0110 & 0.4849 & 0.0897 & 0.0122 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.23 & 0.5897 & 1.0662 & 0.1008 & 0.4303 \\ -Efficacy & 2.03 & 0.0211 & 0.5631 & 0.2070 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\end{minipage} -\end{table} -``` - -## `gs_design_wlr()` summary `as_gt()` - -```r -output <- gs_design_wlr() |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}wHR at bound\textsuperscript{\textit{2}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 36 N: 471.1 Events: 289 AHR: 0.68 Information fraction: 1\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 1.96 & 0.025 & 0.7941 & 0.9 & 0.025 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\textsuperscript{\textit{3}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - footnote = list( - content = c( - "approximate weighted hazard ratio to cross bound.", - "wAHR is the weighted AHR.", - "the crossing probability.", - "this table is generated by gs_power_wlr." - ), - location = c("~wHR at bound", NA, NA, NA), - attr = c("colname", "analysis", "spanner", "title") - ) - ) -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\textsuperscript{\textit{1}}\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}}\textsuperscript{\textit{2}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p & \textasciitilde{}wHR at bound\textsuperscript{\textit{3}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.17 & 0.8798 & 1.5353 & 0.0341 & 0.1202 \\ -Efficacy & 2.68 & 0.0037 & 0.3765 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.66 & 0.7452 & 1.2319 & 0.0664 & 0.2664 \\ -Efficacy & 2.29 & 0.0110 & 0.4846 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.22 & 0.5881 & 1.0650 & 0.1002 & 0.4319 \\ -Efficacy & 2.03 & 0.0212 & 0.5631 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}this table is generated by gs\_power\_wlr.\\ -\textsuperscript{\textit{2}}the crossing probability.\\ -\textsuperscript{\textit{3}}approximate weighted hazard ratio to cross bound.\\ -\textsuperscript{\textit{4}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_combo()` summary `as_gt()` - -```r -with_seed <- function(seed, code) { - code <- substitute(code) - original_seed <- .Random.seed - on.exit(.Random.seed <<- original_seed) - set.seed(seed) - eval.parent(code) - } - - # See - output <- with_seed( - 42, - { - gs_power_combo() |> - summary() |> - as_gt() - } - ) -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for MaxCombo design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont MaxCombo approximation\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrr} -\toprule - & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){4-5} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 1 Time: 12 N: 500 Events: 107.4 AHR: 0.84 Event fraction: 0.32\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1 & 0.8413 & 0.0293 & 0.0000 \\ -Efficacy & 3 & 0.0013 & 0.0175 & 0.0013 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 2 Time: 24 N: 500 Events: 246.3 AHR: 0.72 Event fraction: 0.74\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & 0 & 0.5000 & 0.0314 & 0.0000 \\ -Efficacy & 2 & 0.0228 & 0.7261 & 0.0233 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 3 Time: 36 N: 500 Events: 331.3 AHR: 0.68 Event fraction: 1\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & 1 & 0.1587 & 0.0326 & 0.0000 \\ -Efficacy & 1 & 0.1587 & 0.9674 & 0.1956 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}EF is event fraction. AHR is under regular weighted log rank test.\\ -\end{minipage} -\end{table} -``` - -## `gs_design_rd()` summary `as_gt()` - -```r -output <- gs_design_rd() |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary of Binary Endpoint\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont measured by risk difference\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}Risk difference at bound & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 N: 2423.1 Risk difference: 0.05 Information fraction: 1} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 1.96 & 0.025 & 0.0302 & 0.9 & 0.025 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_rd()` summary `as_gt()` - -```r -output <- gs_power_rd() |> - summary() |> - as_gt() -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary of Binary Endpoint\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont measured by risk difference\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}Risk difference at bound & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 N: 40 Risk difference: 0.05 Information fraction: 0.67} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.28 & 0.9000 & -0.1537 & 0.0444 & 0.1000 \\ -Efficacy & 3.71 & 0.0001 & 0.4448 & 0.0005 & 0.0001 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 N: 50 Risk difference: 0.05 Information fraction: 0.83} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 2.51 & 0.0060 & 0.2693 & 0.0204 & 0.0060 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 N: 60 Risk difference: 0.05 Information fraction: 1} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 1.99 & 0.0231 & 0.1951 & 0.0705 & \textsuperscript{\textit{2}}0.0238 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Cumulative alpha for final analysis (0.0238) is less than the full alpha (0.025) when the futility bound is non-binding. The smaller value subtracts the probability of crossing a futility bound before crossing an efficacy bound at a later analysis (0.025 - 0.0012 = 0.0238) under the null hypothesis.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` with custom title and subtitle - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt(title = "Bound Summary", subtitle = "from gs_power_wlr") -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound Summary\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont from gs\_power\_wlr\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}wHR at bound\textsuperscript{\textit{2}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.17 & 0.8798 & 1.5353 & 0.0341 & 0.1202 \\ -Efficacy & 2.68 & 0.0037 & 0.3765 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.66 & 0.7452 & 1.2319 & 0.0664 & 0.2664 \\ -Efficacy & 2.29 & 0.0110 & 0.4846 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.22 & 0.5881 & 1.0650 & 0.1002 & 0.4319 \\ -Efficacy & 2.03 & 0.0212 & 0.5631 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\textsuperscript{\textit{3}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` with colname_spanner and colname_spannersub - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - colname_spanner = "Cumulative probability to cross boundaries", - colname_spannersub = c("under H1", "under H0") - ) -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative probability to cross boundaries}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}wHR at bound\textsuperscript{\textit{2}} & under H1 & under H0 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.17 & 0.8798 & 1.5353 & 0.0341 & 0.1202 \\ -Efficacy & 2.68 & 0.0037 & 0.3765 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.66 & 0.7452 & 1.2319 & 0.0664 & 0.2664 \\ -Efficacy & 2.29 & 0.0110 & 0.4846 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.22 & 0.5881 & 1.0650 & 0.1002 & 0.4319 \\ -Efficacy & 2.03 & 0.0212 & 0.5631 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\textsuperscript{\textit{3}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` with custom footnotes - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt( - footnote = list( - content = c( - "approximate weighted hazard ratio to cross bound.", - "wAHR is the weighted AHR.", - "the crossing probability.", - "this table is generated by gs_power_wlr." - ), - location = c("~wHR at bound", NA, NA, NA), - attr = c("colname", "analysis", "spanner", "title") - ) - ) -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\textsuperscript{\textit{1}}\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}}\textsuperscript{\textit{2}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p & \textasciitilde{}wHR at bound\textsuperscript{\textit{3}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -1.17 & 0.8798 & 1.5353 & 0.0341 & 0.1202 \\ -Efficacy & 2.68 & 0.0037 & 0.3765 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.66 & 0.7452 & 1.2319 & 0.0664 & 0.2664 \\ -Efficacy & 2.29 & 0.0110 & 0.4846 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{4}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & -0.22 & 0.5881 & 1.0650 & 0.1002 & 0.4319 \\ -Efficacy & 2.03 & 0.0212 & 0.5631 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}this table is generated by gs\_power\_wlr.\\ -\textsuperscript{\textit{2}}the crossing probability.\\ -\textsuperscript{\textit{3}}approximate weighted hazard ratio to cross bound.\\ -\textsuperscript{\textit{4}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` with display_bound - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt(display_bound = "Efficacy") -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrrr} -\toprule - & & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){5-6} -Bound & Z & Nominal p\textsuperscript{\textit{1}} & \textasciitilde{}wHR at bound\textsuperscript{\textit{2}} & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 2.68 & 0.0037 & 0.3765 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 2.29 & 0.0110 & 0.4846 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{6}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{3}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Efficacy & 2.03 & 0.0212 & 0.5631 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}Approximate hazard ratio to cross bound.\\ -\textsuperscript{\textit{3}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - -## `gs_power_wlr()` summary `as_gt()` with display_columns - -```r -output <- gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> - summary() |> - as_gt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) -gt_to_latex(output) -``` - -``` -\begin{table}[t] -\caption*{ -{\fontsize{20}{25}\selectfont Bound summary for WLR design\fontsize{12}{15}\selectfont } \\ -{\fontsize{14}{17}\selectfont WLR approximation of \textasciitilde{}wHR at bound\fontsize{12}{15}\selectfont } -} -\fontsize{12.0pt}{14.0pt}\selectfont -\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}lrrrr} -\toprule - & & & \multicolumn{2}{c}{{Cumulative boundary crossing probability}} \\ -\cmidrule(lr){4-5} -Bound & Nominal p\textsuperscript{\textit{1}} & Z & Alternate hypothesis & Null hypothesis \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 1 Time: 14.9 N: 108 Events: 30 AHR: 0.79 Information fraction: 0.6\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & 0.8798 & -1.17 & 0.0341 & 0.1202 \\ -Efficacy & 0.0037 & 2.68 & 0.0217 & 0.0037 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 2 Time: 19.2 N: 108 Events: 40 AHR: 0.75 Information fraction: 0.8\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & 0.7452 & -0.66 & 0.0664 & 0.2664 \\ -Efficacy & 0.0110 & 2.29 & 0.0886 & 0.0121 \\ -\midrule\addlinespace[2.5pt] -\multicolumn{5}{l}{Analysis: 3 Time: 24.5 N: 108 Events: 50 AHR: 0.71 Information fraction: 1\textsuperscript{\textit{2}}} \\[2.5pt] -\midrule\addlinespace[2.5pt] -Futility & 0.5881 & -0.22 & 0.1002 & 0.4319 \\ -Efficacy & 0.0212 & 2.03 & 0.2071 & 0.0250 \\ -\bottomrule -\end{tabular*} -\begin{minipage}{\linewidth} -\vspace{.05em} -\textsuperscript{\textit{1}}One-sided p-value for experimental vs control treatment. Value < 0.5 favors experimental, > 0.5 favors control.\\ -\textsuperscript{\textit{2}}wAHR is the weighted AHR.\\ -\end{minipage} -\end{table} -``` - diff --git a/vignettes/articles/story-ahr-under-nph.Rmd b/vignettes/articles/story-ahr-under-nph.Rmd index d20a90f63..fc86c2fc0 100644 --- a/vignettes/articles/story-ahr-under-nph.Rmd +++ b/vignettes/articles/story-ahr-under-nph.Rmd @@ -99,7 +99,7 @@ library(ggplot2) library(dplyr) library(tibble) library(survival) -library(gt) +library(lt) ``` # Single stratum non-proportional hazards example @@ -147,7 +147,7 @@ avehr <- ahr( total_duration = as.numeric(total_duration) ) -avehr |> gt() +avehr |> lt() ``` This result can be explained by the number of events observed before and after the first 3 months of treatment in each treatment group. @@ -158,7 +158,7 @@ xx <- pw_info( fail_rate = fail_rate, total_duration = as.numeric(total_duration) ) -xx |> gt() +xx |> lt() ``` Now we can replicate the geometric average hazard ratio (AHR) computed using the `ahr()` routine above. @@ -168,7 +168,7 @@ Exponentiating the resulting weighted average gives the geometric mean hazard ra ```{r, message=FALSE} xx |> summarize(AHR = exp(sum(event * log(hr) / sum(event)))) |> - gt() + lt() ``` ## Deriving the design @@ -199,7 +199,7 @@ avehr <- ahr( total_duration = as.numeric(total_duration) ) -avehr |> gt() +avehr |> lt() ``` We also compute sample size, rounding up to the nearest even integer. @@ -268,8 +268,8 @@ results1 |> sdEvents = sd(event), Events = mean(event), HR = exp(mean(ln_hr)), sdlnhr = sd(ln_hr), info = 1 / sdlnhr^2 ) |> - gt() |> - fmt_number(column = 2:9, decimals = 3) + lt() |> + lt_format(columns = 2:9, decimals = 3) ``` The column `HR` above is the exponentiated mean of the Cox regression coefficients (geometric mean of HR). @@ -279,7 +279,7 @@ In this case, the information approximation under the alternate hypothesis appea Nonetheless, the approximation for power appear quite good as noted above. ```{r} -avehr |> gt() +avehr |> lt() ``` # Different proportional hazards by strata @@ -320,14 +320,14 @@ Now we transform the enrollment rates to account for stratified population. ```{r avehr2, warning=FALSE, message=FALSE} ahr2 <- ahr(enroll_rate, fail_rate, total_duration) -ahr2 |> gt() +ahr2 |> lt() ``` We examine the expected events by stratum. ```{r} xx <- pw_info(enroll_rate, fail_rate, total_duration) -xx |> gt() +xx |> lt() ``` Getting the average of `log(HR)` weighted by `Events` and exponentiating, we get the overall `AHR` just derived. @@ -336,7 +336,7 @@ Getting the average of `log(HR)` weighted by `Events` and exponentiating, we get xx |> ungroup() |> summarise(lnhr = sum(event * log(hr)) / sum(event), AHR = exp(lnhr)) |> - gt() + lt() ``` ## Deriving the design @@ -364,7 +364,7 @@ ahr( enroll_rate = enroll_rate, fail_rate = fail_rate, total_duration = total_duration -) |> gt() +) |> lt() ``` The targeted sample size, rounding up to an even integer, is: @@ -410,7 +410,7 @@ er <- enroll_rate |> group_by(period) |> summarise(rate = sum(rate), duration = last(duration)) -er |> gt() +er |> lt() ``` @@ -440,8 +440,8 @@ results2 |> sdEvents = sd(event), Events = mean(event), HR = exp(mean(ln_hr)), sdlnhr = sd(ln_hr), info = 1 / sdlnhr^2 ) |> - gt() |> - fmt_number(column = 2:9, decimals = 3) + lt() |> + lt_format(columns = 2:9, decimals = 3) ``` Finally, compare the simulation results above to the asymptotic approximation below. @@ -453,7 +453,7 @@ ahr( enroll_rate = enroll_rate, fail_rate = fail_rate, total_duration = total_duration -) |> gt() +) |> lt() ``` # References diff --git a/vignettes/articles/story-compare-power-delay-effect.Rmd b/vignettes/articles/story-compare-power-delay-effect.Rmd index cc2fce4f4..bfd2440b2 100644 --- a/vignettes/articles/story-compare-power-delay-effect.Rmd +++ b/vignettes/articles/story-compare-power-delay-effect.Rmd @@ -20,7 +20,7 @@ knitr::opts_chunk$set(echo = TRUE) ``` ```{r packages, message=FALSE, warning=FALSE} -library(gt) +library(lt) library(tidyr) library(ggplot2) library(gsDesign) @@ -47,12 +47,12 @@ fail_rate <- define_fail_rate( ) enroll_rate |> - gt() |> - tab_header(title = "Enrollment Table of Scenario 1") + lt() |> + lt_header(title = "Enrollment Table of Scenario 1") fail_rate |> - gt() |> - tab_header(title = "Failure Table of Scenario 1") + lt() |> + lt_header(title = "Failure Table of Scenario 1") ``` For the above scenarios, we investigate the power, sample size and events under 6 tests: @@ -180,11 +180,11 @@ for (trial_duration in seq(24, 60, 4)) { } tab |> - gt() |> - fmt_number(columns = c(2, 3), decimals = 1) |> - fmt_number(columns = 4, decimals = 2) |> - fmt_number(columns = 5, decimals = 4) |> - fmt_number(columns = 6:11, decimals = 2) + lt() |> + lt_format(columns = c(2, 3), decimals = 1) |> + lt_format(columns = 4, decimals = 2) |> + lt_format(columns = 5, decimals = 4) |> + lt_format(columns = 6:11, decimals = 2) ``` # An Alternative Scenario @@ -202,11 +202,11 @@ fail_rate <- define_fail_rate( hr = c(1, .6, .85) ) enroll_rate |> - gt() |> - tab_header(title = "Enrollment Table of Scenario 2") + lt() |> + lt_header(title = "Enrollment Table of Scenario 2") fail_rate |> - gt() |> - tab_header(title = "Failure Table of Scenario 2") + lt() |> + lt_header(title = "Failure Table of Scenario 2") ``` ```{r, message=FALSE} @@ -320,9 +320,9 @@ for (trial_duration in seq(20, 60, 4)) { } tab |> - gt() |> - fmt_number(columns = c(2, 3), decimals = 1) |> - fmt_number(columns = 4, decimals = 2) |> - fmt_number(columns = 5, decimals = 4) |> - fmt_number(columns = 6:11, decimals = 2) + lt() |> + lt_format(columns = c(2, 3), decimals = 1) |> + lt_format(columns = 4, decimals = 2) |> + lt_format(columns = 5, decimals = 4) |> + lt_format(columns = 6:11, decimals = 2) ``` diff --git a/vignettes/articles/story-cp.Rmd b/vignettes/articles/story-cp.Rmd index 2d379a0b0..f787c7e19 100644 --- a/vignettes/articles/story-cp.Rmd +++ b/vignettes/articles/story-cp.Rmd @@ -28,7 +28,7 @@ options(width = 58) ```{r, message=FALSE, warning=FALSE} library(gsDesign) library(gsDesign2) -library(gt) +library(lt) library(ggplot2) library(tibble) ``` @@ -73,7 +73,7 @@ x <- gs_design_ahr( # Round analysis time to nearest month x$analysis$time <- round(x$analysis$time) -x |> gs_bound_summary() |> gt() +x |> gs_bound_summary() |> lt() ``` # Update design at time of interim analysis @@ -103,7 +103,7 @@ xu <- gs_update_ahr( event_tbl = data.frame(analysis = c(1, 1), event = c(90, 55))) xu$analysis$time <- c(17, x$analysis$time[2:3]) -xu |> gs_bound_summary() |> gt() +xu |> gs_bound_summary() |> lt() ``` diff --git a/vignettes/articles/story-design-with-ahr.Rmd b/vignettes/articles/story-design-with-ahr.Rmd index f4a391904..a2d5c21f1 100644 --- a/vignettes/articles/story-design-with-ahr.Rmd +++ b/vignettes/articles/story-design-with-ahr.Rmd @@ -53,7 +53,7 @@ library(gsDesign) library(gsDesign2) library(ggplot2) library(dplyr) -library(gt) +library(lt) library(tidyr) library(tibble) ``` @@ -288,10 +288,10 @@ ss_ahr_fixed <- do.call( ) ss_ahr_fixed |> - gt() |> - fmt_number(columns = 1:3, decimals = 0) |> - fmt_number(columns = 4, decimals = 3) |> - tab_header( + lt() |> + lt_format(columns = 1:3, decimals = 0) |> + lt_format(columns = 4, decimals = 3) |> + lt_header( title = "Sample Size and Events Required by Scenario", subtitle = "36 Month Trial duration, 2.5% One-sided Type 1 Error, 90% Power" ) @@ -323,10 +323,10 @@ do.call( } ) ) |> - gt() |> - fmt_number(columns = 1:3, decimals = 0) |> - fmt_number(columns = 4, decimals = 3) |> - tab_header( + lt() |> + lt_format(columns = 1:3, decimals = 0) |> + lt_format(columns = 4, decimals = 3) |> + lt_header( title = "Sample Size and Events Required by Trial Duration", subtitle = "Delayed Effect of 4 Months, HR = 0.6 Thereafter; 90% Power" ) @@ -370,8 +370,8 @@ ahr_by_analysis <- events_by_time_period |> ahr_by_analysis |> pivot_wider(names_from = Scenario, values_from = AHR1) |> - gt() |> - fmt_number(columns = 2:5, decimals = 3) + lt() |> + lt_format(columns = 2:5, decimals = 3) ``` ## Group Sequential Design @@ -402,7 +402,7 @@ nph_asymmetric <- gs_design_ahr( lpar = lpar ) -summary(nph_asymmetric) |> as_gt() +summary(nph_asymmetric) |> as_lt() ``` By scenario, we now wish to compute the adjusted expected futility bounds and the power implied. @@ -432,9 +432,9 @@ do.call( } ) ) |> - gt() |> - fmt_number(columns = "event", decimals = 1) |> - fmt_number(columns = 5:10, decimals = 4) + lt() |> + lt_format(columns = "event", decimals = 1) |> + lt_format(columns = 5:10, decimals = 4) ``` ### Weighted Logrank Method @@ -462,8 +462,8 @@ do.call( } ) ) |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` The fixed design under the second weighting scheme for four scenario are summarized as follows. @@ -489,8 +489,8 @@ do.call( } ) ) |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` # References diff --git a/vignettes/articles/story-design-with-spending.Rmd b/vignettes/articles/story-design-with-spending.Rmd index 9d46e4f6d..5cad587f4 100644 --- a/vignettes/articles/story-design-with-spending.Rmd +++ b/vignettes/articles/story-design-with-spending.Rmd @@ -25,6 +25,7 @@ knitr::opts_chunk$set( ```{r, message=FALSE, warning=FALSE} library(gsDesign) library(gsDesign2) +library(lt) ``` # Overview @@ -53,8 +54,8 @@ enroll_rate <- define_enroll_rate( ) enroll_rate |> - gt::gt() |> - gt::tab_header(title = "Planned Relative Enrollment Rates") + lt() |> + lt_header(title = "Planned Relative Enrollment Rates") ``` We assume a hazard ratio (HR) of 0.9 for the first 3 months 0.6 thereafter. @@ -69,8 +70,8 @@ fail_rate <- define_fail_rate( ) fail_rate |> - gt::gt() |> - gt::tab_header(title = "Table of Failure Rate Assumptions") + lt() |> + lt_header(title = "Table of Failure Rate Assumptions") ``` # Fixed design with no interim analysis @@ -124,5 +125,5 @@ gs <- gs_design_ahr( gs |> summary() |> - gt::gt() + lt() ``` diff --git a/vignettes/articles/story-integer-design.Rmd b/vignettes/articles/story-integer-design.Rmd index 20b9f244e..d4c3af6c3 100644 --- a/vignettes/articles/story-integer-design.Rmd +++ b/vignettes/articles/story-integer-design.Rmd @@ -27,7 +27,7 @@ library(gsDesign) library(gsDesign2) library(tibble) library(dplyr) -library(gt) +library(lt) ``` # Unstratified design @@ -82,12 +82,12 @@ tibble( ) ) |> group_by(Design) |> - gt() |> - tab_header( + lt() |> + lt_header( title = "Comparison between the original/integer design", subtitle = "on binary endpoints (unstratified design)" ) |> - fmt_number(columns = 2:5, decimals = 4) + lt_format(columns = 2:5, decimals = 4) ``` ## Survival outcome @@ -122,12 +122,12 @@ tibble( ) ) |> group_by(Design) |> - gt() |> - tab_header( + lt() |> + lt_header( title = "Comparison between the original/integer design", subtitle = "on survival endpoints (unstratified design)" ) |> - fmt_number(columns = 2:5, decimals = 4) + lt_format(columns = 2:5, decimals = 4) ``` # Stratified design @@ -184,10 +184,10 @@ tibble( ) ) |> group_by(Design) |> - gt() |> - tab_header( + lt() |> + lt_header( title = "Comparison between the original/integer design", subtitle = "on binary endpoints (unstratified design)" ) |> - fmt_number(columns = 2:5, decimals = 4) + lt_format(columns = 2:5, decimals = 4) ``` diff --git a/vignettes/articles/story-nph-futility.Rmd b/vignettes/articles/story-nph-futility.Rmd index 3f08890e3..5ac2b9b96 100644 --- a/vignettes/articles/story-nph-futility.Rmd +++ b/vignettes/articles/story-nph-futility.Rmd @@ -17,7 +17,7 @@ vignette: > ```{r, warning=FALSE, message=FALSE} library(gsDesign2) -library(gt) +library(lt) library(dplyr) library(tibble) library(ggplot2) @@ -68,9 +68,9 @@ fixedevents <- fixed_design_ahr( fixedevents |> summary() |> select(-Bound) |> - as_gt(footnote = "Power based on 512 events") |> - fmt_number(columns = 3:4, decimals = 2) |> - fmt_number(columns = 5:6, decimals = 3) + as_lt(footnote = "Power based on 512 events") |> + lt_format(columns = 3:4, decimals = 2) |> + lt_format(columns = 5:6, decimals = 3) ``` # Beta-spending futility bound with AHR @@ -133,7 +133,7 @@ betaspending <- gs_power_ahr( betaspending |> summary() |> - as_gt( + as_lt( title = "Group sequential design with futility only", subtitle = "Beta-spending futility bound" ) @@ -164,7 +164,7 @@ wieand <- gs_power_ahr( wieand |> summary() |> - as_gt( + as_lt( title = "Group sequential design with futility only at interim analyses", subtitle = "Wieand futility rule stops if HR > 1" ) @@ -299,7 +299,7 @@ kf <- gs_power_ahr( kf |> summary() |> - as_gt(title = "Group sequential design with futility only", + as_lt(title = "Group sequential design with futility only", subtitle = "Korn and Freidlin futility rule stops if HR > 1") ``` @@ -329,7 +329,7 @@ betaspending_classic <- gs_power_ahr( betaspending_classic |> summary() |> - as_gt( + as_lt( title = "Group sequential design with futility only", subtitle = "Classical beta-spending futility bound" ) diff --git a/vignettes/articles/story-package-architecture.Rmd b/vignettes/articles/story-package-architecture.Rmd index 1370de38f..37b38b14a 100644 --- a/vignettes/articles/story-package-architecture.Rmd +++ b/vignettes/articles/story-package-architecture.Rmd @@ -51,10 +51,10 @@ Since the only class designation used by the package is `"fixed_design"` or Specifically, the package provides S3 methods for `print()`, `summary()`, and `to_integer()`. Furthermore, the `summary()` S3 method returns corresponding objects of class `"fixed_design_summary"` or `"gs_design_summary"`, and the -package provides the S3 methods `as_gt()` and `as_rtf()` to convert the summary -tables to [gt][] or [RTF][] format, respectively. +package provides the S3 methods `as_lt()` and `as_rtf()` to convert the summary +tables to [lt][] or [RTF][] format, respectively. -[gt]: https://github.com/rstudio/gt +[lt]: https://github.com/yihui/lt [rtf]: https://en.wikipedia.org/wiki/Rich_Text_Format ## How to query the trial characteristics from the design object diff --git a/vignettes/articles/story-power-evaluation-with-spending-bound.Rmd b/vignettes/articles/story-power-evaluation-with-spending-bound.Rmd index 6fbddd30a..de068ef62 100644 --- a/vignettes/articles/story-power-evaluation-with-spending-bound.Rmd +++ b/vignettes/articles/story-power-evaluation-with-spending-bound.Rmd @@ -25,7 +25,7 @@ knitr::opts_chunk$set( ```{r, message=FALSE, warning=FALSE} library(tibble) -library(gt) +library(lt) library(gsDesign2) ``` @@ -213,7 +213,7 @@ For the CAPTURE trial, we have ```{r} h1 <- gs_info_binomial(p1 = .15, p2 = .1, xi1 = .5, n = c(350, 700, 1400)) -h1 |> gt() +h1 |> lt() ``` We can plug these into `gs_power_npe()` with the intended spending functions. We begin with power under the alternate hypothesis @@ -230,8 +230,8 @@ gs_power_npe( lower = gs_spending_bound, lpar = list(sf = gsDesign::sfHSD, param = -2, total_spend = 0.2) ) |> - gt() |> - fmt_number(columns = 3:10, decimals = 4) + lt() |> + lt_format(columns = 3:10, decimals = 4) ``` Now we examine information for a smaller assumed treatment difference than the alternative: @@ -247,8 +247,8 @@ gs_power_npe( lower = gs_spending_bound, lpar = list(sf = gsDesign::sfHSD, param = -2, total_spend = 0.2) ) |> - gt() |> - fmt_number(columns = 3:10, decimals = 4) + lt() |> + lt_format(columns = 3:10, decimals = 4) ``` # References diff --git a/vignettes/articles/story-risk-difference.Rmd b/vignettes/articles/story-risk-difference.Rmd index a3e5bcce6..b1333a078 100644 --- a/vignettes/articles/story-risk-difference.Rmd +++ b/vignettes/articles/story-risk-difference.Rmd @@ -34,7 +34,7 @@ library(dplyr) library(knitr) library(gsDesign) library(gsDesign2) -library(gt) +library(lt) ``` # Overview @@ -555,7 +555,7 @@ theta_h1 <- abs(p_c - p_e) / sigma_h1 tibble::tribble( ~n_c, ~n_e, ~p_c, ~p_e, ~theta_h1, ~theta_h0, ~info_h1, ~info_h0, n_c, n_e, p_c, p_e, theta_h1, theta_h0, info_h1, info_h0, -) |> gt::gt() +) |> lt() ``` The above logic is implemented in the function `gs_info_rd()`. @@ -571,8 +571,8 @@ x <- gs_info_rd( ) x |> - gt::gt() |> - gt::fmt_number(columns = 5:8, decimals = 6) + lt() |> + lt_format(columns = 5:8, decimals = 6) ``` By plugging the `theta` and `info` above into `gs_design_npe()`, one can @@ -626,8 +626,8 @@ tibble( `info_scale = "h1_info"` = y_1$info1[1] / x$info1[1], `info_scale = "h0_h1_info"` = y_2$info[1] / x$info1[1] ) |> - gt::gt() |> - gt::tab_header(title = "The sample size calculated by gsDesign2 under 3 info_scale") + lt() |> + lt_header(title = "The sample size calculated by gsDesign2 under 3 info_scale") ``` The above logic is implement in `gs_design_rd()` to calculate the sample @@ -702,16 +702,16 @@ tibble::tibble( EAST_unpool = 645, EAST_pool = 651 ) |> - gt::gt() |> - gt::tab_spanner( + lt() |> + lt_spanner( label = "gsDesign2", columns = c(gsDesign2_info_scale_0, gsDesign2_info_scale_1, gsDesign2_info_scale_2) ) |> - gt::tab_spanner( + lt_spanner( label = "EAST", columns = c(EAST_unpool, EAST_pool) ) |> - cols_label( + lt_cols_label( gsDesign2_info_scale_0 = "info_scale = \"h0_info\"", gsDesign2_info_scale_1 = "info_scale = \"h1_info\"", gsDesign2_info_scale_2 = "info_scale = \"h0_h1_info\"", @@ -745,8 +745,8 @@ x_gs <- gs_info_rd( ) x_gs |> - gt::gt() |> - gt::tab_header(title = "The statistical information of the group sequential design") + lt() |> + lt_header(title = "The statistical information of the group sequential design") ``` ```{r} @@ -794,8 +794,8 @@ tibble( `info_scale = "h1_info"` = y_gs1$info1 / x_gs$info1[3], `info_scale = "h0_h1_info"` = y_gs2$info / x_gs$info1[3] ) |> - gt::gt() |> - gt::tab_header( + lt() |> + lt_header( title = "The sample size calculated by `gsDesign2` under 3 info_scale", subtitle = "under group sequential design" ) @@ -933,16 +933,16 @@ tibble::tibble( EAST_unpool = c(617, 1233, 1850), EAST_pool = c(619, 1238, 1857) ) |> - gt::gt() |> - gt::tab_spanner( + lt() |> + lt_spanner( label = "gsDesign2", columns = c(gsDesign2_info_scale_0, gsDesign2_info_scale_1, gsDesign2_info_scale_2) ) |> - gt::tab_spanner( + lt_spanner( label = "EAST", columns = c(EAST_unpool, EAST_pool) ) |> - cols_label( + lt_cols_label( gsDesign2_info_scale_0 = "info_scale = \"h0_info\"", gsDesign2_info_scale_1 = "info_scale = \"h1_info\"", gsDesign2_info_scale_2 = "info_scale = \"h0_h1_info\"", @@ -990,29 +990,14 @@ x <- p_c |> mutate(n_c = n_c * xi_c, n_e = n_e * xi_e) x |> - gt::gt() |> - gt::fmt_number(columns = 4:8, decimals = 4) |> - gt::tab_footnote( - footnote = "p_pool = (p_c * n_c + p_e * n_e) / (n_c * n_e).", - locations = gt::cells_column_labels(columns = p_pool) - ) |> - gt::tab_footnote( - footnote = "xi_c = sample size of a strata / sample size of the control arm.", - locations = gt::cells_column_labels(columns = xi_c) - ) |> - gt::tab_footnote( - footnote = "xi_e = sample size of a strata / sample size of the experimental arm.", - locations = gt::cells_column_labels(columns = xi_e) - ) |> - gt::tab_footnote( - footnote = "n_c = total sample size of the control arm.", - locations = gt::cells_column_labels(columns = n_c) - ) |> - gt::tab_footnote( - footnote = "n_e = total size of the experimental arm.", - locations = gt::cells_column_labels(columns = n_e) - ) |> - gt::tab_header(title = "Stratified Example") + lt() |> + lt_format(columns = 4:8, decimals = 4) |> + lt_footnote(text = "p_pool = (p_c * n_c + p_e * n_e) / (n_c * n_e).", where = "column", columns = "p_pool") |> + lt_footnote(text = "xi_c = sample size of a strata / sample size of the control arm.", where = "column", columns = "xi_c") |> + lt_footnote(text = "xi_e = sample size of a strata / sample size of the experimental arm.", where = "column", columns = "xi_e") |> + lt_footnote(text = "n_c = total sample size of the control arm.", where = "column", columns = "n_c") |> + lt_footnote(text = "n_e = total size of the experimental arm.", where = "column", columns = "n_e") |> + lt_header(title = "Stratified Example") ``` First, we calculate the variance @@ -1049,16 +1034,10 @@ x <- x |> ) x |> - gt() |> - gt::fmt_number(6:11, decimals = 4) |> - gt::tab_footnote( - footnote = "sigma_h0 = the H0 sd per stratum per analysis.", - locations = gt::cells_column_labels(columns = sigma_h0) - ) |> - gt::tab_footnote( - footnote = "sigma_h1 = the H0 sd per stratum per analysis.", - locations = gt::cells_column_labels(columns = sigma_h1) - ) + lt() |> + lt_format(6:11, decimals = 4) |> + lt_footnote(text = "sigma_h0 = the H0 sd per stratum per analysis.", where = "column", columns = "sigma_h0") |> + lt_footnote(text = "sigma_h1 = the H0 sd per stratum per analysis.", where = "column", columns = "sigma_h1") ``` Second, we calculate the weight by using inverse variance @@ -1086,20 +1065,11 @@ x <- x |> select(-c(sum_invar_H0, sum_invar_H1, sum_ss)) x |> - gt() |> - fmt_number(6:14, decimals = 4) |> - gt::tab_footnote( - footnote = "weight_invar_H0 = the weight per stratum per analysis calculated by INVAR by using variance under H0.", - locations = gt::cells_column_labels(columns = weight_invar_H0) - ) |> - gt::tab_footnote( - footnote = "weight_invar_H1 = the weight per stratum per analysis calculated by INVAR by using variance under H1.", - locations = gt::cells_column_labels(columns = weight_invar_H1) - ) |> - gt::tab_footnote( - footnote = "weight_ss = the weight per stratum per analysis calculated by SS.", - locations = gt::cells_column_labels(columns = weight_ss) - ) + lt() |> + lt_format(6:14, decimals = 4) |> + lt_footnote(text = "weight_invar_H0 = the weight per stratum per analysis calculated by INVAR by using variance under H0.", where = "column", columns = "weight_invar_H0") |> + lt_footnote(text = "weight_invar_H1 = the weight per stratum per analysis calculated by INVAR by using variance under H1.", where = "column", columns = "weight_invar_H1") |> + lt_footnote(text = "weight_ss = the weight per stratum per analysis calculated by SS.", where = "column", columns = "weight_ss") ``` Third, we calculate the weighted risk difference and weighted @@ -1176,38 +1146,14 @@ x <- x |> ```{r} x |> - gt::gt() |> - fmt_number(c(2:4, 6:11), decimals = 6) |> - gt::tab_footnote( - footnote = "info_invar_H0 = the statistical information under H1 - per stratum per analysis calculated by INVAR by using variance under H0.", - locations = gt::cells_column_labels(columns = info_invar_H0) - ) |> - gt::tab_footnote( - footnote = "info_invar_H1 = the statistical information under H1 - per stratum per analysis calculated by INVAR by using variance under H0.", - locations = gt::cells_column_labels(columns = info_invar_H1) - ) |> - gt::tab_footnote( - footnote = "info_ss = the statistical information under H1 - per stratum per analysis calculated by SS.", - locations = gt::cells_column_labels(columns = info_ss) - ) |> - gt::tab_footnote( - footnote = "info0_invar_H0 = the statistical information under H0 - per stratum per analysis calculated by INVAR by using variance under H0.", - locations = gt::cells_column_labels(columns = info0_invar_H0) - ) |> - gt::tab_footnote( - footnote = "info0_invar_H1 = the statistical information under H0 - per stratum per analysis calculated by INVAR by using variance under H0.", - locations = gt::cells_column_labels(columns = info0_invar_H1) - ) |> - gt::tab_footnote( - footnote = "info0_ss = the statistical information under H0 - per stratum per analysis calculated by SS.", - locations = gt::cells_column_labels(columns = info0_ss) - ) + lt() |> + lt_format(c(2:4, 6:11), decimals = 6) |> + lt_footnote(text = "info_invar_H0 = the statistical information under H1 per stratum per analysis calculated by INVAR by using variance under H0.", where = "column", columns = "info_invar_H0") |> + lt_footnote(text = "info_invar_H1 = the statistical information under H1 per stratum per analysis calculated by INVAR by using variance under H0.", where = "column", columns = "info_invar_H1") |> + lt_footnote(text = "info_ss = the statistical information under H1 per stratum per analysis calculated by SS.", where = "column", columns = "info_ss") |> + lt_footnote(text = "info0_invar_H0 = the statistical information under H0 per stratum per analysis calculated by INVAR by using variance under H0.", where = "column", columns = "info0_invar_H0") |> + lt_footnote(text = "info0_invar_H1 = the statistical information under H0 per stratum per analysis calculated by INVAR by using variance under H0.", where = "column", columns = "info0_invar_H1") |> + lt_footnote(text = "info0_ss = the statistical information under H0 per stratum per analysis calculated by SS.", where = "column", columns = "info0_ss") ``` ```{r} @@ -1311,8 +1257,8 @@ ans_math <- tibble::tibble( ) ans_math |> - gt::gt() |> - gt::tab_header(title = "Sample size calculated by INVAR and SS") + lt() |> + lt_header(title = "Sample size calculated by INVAR and SS") ``` The above logic is implemented in `gs_design_rd()`. @@ -1518,9 +1464,9 @@ ans <- tibble::tibble( ) ans |> - gt::gt() |> - gt::tab_header(title = "Sample size calculated by INVAR and SS") |> - gt::tab_spanner( + lt() |> + lt_header(title = "Sample size calculated by INVAR and SS") |> + lt_spanner( label = "Inverse variance weighting ", columns = c( "INVAR0", @@ -1528,11 +1474,11 @@ ans |> "INVAR2" ) ) |> - gt::tab_spanner( + lt_spanner( label = "Sample size weighting", columns = c(SS0, SS1, SS2) ) |> - cols_label( + lt_cols_label( INVAR0 = "info_scale = \"h0_info\"", INVAR1 = "info_scale = \"h1_info\"", INVAR2 = "info_scale = \"h0_h1_info\"", diff --git a/vignettes/articles/story-seven-test-types.Rmd b/vignettes/articles/story-seven-test-types.Rmd index 8c68d621f..0120ef862 100644 --- a/vignettes/articles/story-seven-test-types.Rmd +++ b/vignettes/articles/story-seven-test-types.Rmd @@ -100,7 +100,7 @@ one_sided <- gsDesign2::gs_design_ahr( one_sided |> summary() |> - gsDesign2::as_gt(title = "Efficacy bound only", subtitle = "alpha-spending") + gsDesign2::as_lt(title = "Efficacy bound only", subtitle = "alpha-spending") ``` Now we check this with `gsDesign::gsSurv().` As noted above, sample size and event counts vary slightly from the design derived using `gs_design_ahr()`. @@ -153,7 +153,7 @@ symmetric <- gs_design_ahr( symmetric |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided Symmetric Design", subtitle = "Single spending function" ) @@ -209,7 +209,7 @@ asymmetric_binding <- gs_design_ahr( asymmetric_binding |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided asymmetric design with binding futility", subtitle = "Both alpha- and beta-spending used" ) @@ -265,7 +265,7 @@ asymmetric_nonbinding <- gs_design_ahr( asymmetric_nonbinding |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided asymmetric design with non-binding futility", subtitle = "Both alpha- and beta-spending used" ) @@ -325,7 +325,7 @@ asymmetric_safety_binding <- gs_design_ahr( asymmetric_safety_binding |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided asymmetric safety design with binding futility", subtitle = "Alpha-spending used for both bounds, asymmetrically" ) @@ -381,11 +381,11 @@ asymmetric_safety_nonbinding <- gs_design_ahr( asymmetric_safety_nonbinding |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided asymmetric safety design with non-binding futility", subtitle = "Alpha-spending used for both bounds, asymmetrically" ) |> - gt::tab_footnote(footnote = "Integer-based sample size and event counts") + lt::lt_note("Integer-based sample size and event counts") ``` The corresponding `gsDesign::gsSurv()` design is not strictly comparable since the option to eliminate some futility and efficacy analyses is not enabled. @@ -477,11 +477,11 @@ asymmetric_fixed_bounds <- gs_design_ahr( asymmetric_fixed_bounds |> summary() |> - gsDesign2::as_gt( + gsDesign2::as_lt( title = "2-sided asymmetric safety design with fixed non-binding futility", subtitle = "Futility bounds computed to approximate HR" ) |> - gt::tab_footnote(footnote = "Integer-based sample size and event counts") + lt::lt_note("Integer-based sample size and event counts") ``` We see that the targeted bounds are achieved with nominal $p$-values of 0.0001 for each interim efficacy bound and the targeted hazard ratios at interim futility bounds. diff --git a/vignettes/articles/story-spending-time-example.Rmd b/vignettes/articles/story-spending-time-example.Rmd index 6b972622c..f75ba3cdb 100644 --- a/vignettes/articles/story-spending-time-example.Rmd +++ b/vignettes/articles/story-spending-time-example.Rmd @@ -28,7 +28,7 @@ library(gsDesign) library(gsDesign2) library(tibble) library(dplyr) -library(gt) +library(lt) ``` # Overview @@ -128,7 +128,7 @@ xx <- gs_design_ahr(enroll_rate, summary(xx, analysis_vars = c("time", "n", "event", "ahr", "info_frac"), analysis_decimals = c(0, 0, 0, 4, 4) -) |> as_gt() +) |> as_lt() ``` ## Power when assumptions design are wrong @@ -166,7 +166,7 @@ yy <- gs_power_ahr( yy |> summary() |> - as_gt() + as_lt() ``` Now we also require 30 months trial duration in addition to the targeted events. @@ -192,7 +192,7 @@ yy <- gs_power_ahr( # get the summary table of updated design yy |> summary() |> - as_gt() + as_lt() ``` ## Scenario 2: low control event rates @@ -222,7 +222,7 @@ yy <- gs_power_ahr( yy |> summary() |> - as_gt() + as_lt() ``` If we also require adequate events, we restore power to 94.5, above the originally targeted level of 90%. @@ -247,7 +247,7 @@ yy <- gs_power_ahr( yy |> summary() |> - as_gt() + as_lt() ``` ## Conclusions for fixed design @@ -379,7 +379,7 @@ xx <- gs_design_ahr( # get the summary table xx |> summary() |> - as_gt() + as_lt() ``` ## Two alternate approaches @@ -416,7 +416,7 @@ yy <- gs_power_ahr( yy |> summary() |> - as_gt() + as_lt() ``` ### Fixed incremental spend with a variable number of analyses @@ -479,7 +479,7 @@ fho <- gs_power_ahr( fho |> summary() |> - as_gt() + as_lt() ``` ## Scenario with less treatment effect @@ -523,8 +523,8 @@ yy <- gs_power_ahr( yy |> summary() |> filter(Bound == "Efficacy") |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` Just as important, the general design principle of making interim analysis criteria more stringent that final is ensured for this alternate scenario. @@ -544,8 +544,8 @@ yz <- gs_power_ahr( yz |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ## Scenario with longer control median @@ -578,8 +578,8 @@ yy <- gs_power_ahr( yy |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` Since the number of events was less than expected, if we had used the actual number of events the interim bound would be more stringent than above and we obtain slightly greater power. @@ -598,8 +598,8 @@ yz <- gs_power_ahr( yz |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ## Summary for spending time motivation assuming delayed benefit @@ -683,8 +683,8 @@ positive <- gs_design_ahr( positive |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ## Planned design for overall population @@ -697,7 +697,7 @@ inflation_factor <- positive$enroll_rate$rate[1] / enroll_rate$rate[1] # Using this inflation factor, set planned enrollment rates planned_enroll_rate <- enroll_rate |> mutate(rate = rate * inflation_factor) -planned_enroll_rate |> gt() +planned_enroll_rate |> lt() # Store overall enrollment rates for future use overall_enroll_rate <- planned_enroll_rate |> @@ -707,7 +707,7 @@ overall_enroll_rate <- planned_enroll_rate |> rate = sum(rate) ) -overall_enroll_rate |> gt() +overall_enroll_rate |> lt() ``` Now we can examine the power for the overall population based on hazard ratio assumptions in biomarker negative and biomarker positive subgroups and the just calculated enrollment assumption. @@ -746,8 +746,8 @@ overall_planned_bounds <- gs_power_ahr( overall_planned_bounds |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ## Alternate scenarios overview @@ -817,8 +817,8 @@ positive_60_enroll_rate$duration <- max(positive$analysis$n) / # display the updated enrollment rate table positive_60_enroll_rate |> - gt() |> - fmt_number(columns = "rate", decimals = 1) + lt() |> + lt_format(columns = "rate", decimals = 1) ``` Now we can compute the power for the biomarker positive group with the targeted events. @@ -843,8 +843,8 @@ positive_60_power <- gs_power_ahr( positive_60_power |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` #### Overall population power @@ -869,8 +869,8 @@ gs_power_ahr( lpar = rep(-Inf, 2) ) |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` If we had used information-based (i.e., event-based) spending, we would not have reached full spending at final analysis and thus would have lower power. @@ -891,8 +891,8 @@ gs_power_ahr( lpar = lpar ) |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ### Biomarker subgroup prevalence lower than planned @@ -913,8 +913,8 @@ positive_40_enroll_rate$duration <- max(positive$analysis$n) / # display the enrollment table positive_40_enroll_rate |> - gt() |> - fmt_number(columns = "rate", decimals = 1) + lt() |> + lt_format(columns = "rate", decimals = 1) ``` #### Biomarker positive subgroup power @@ -942,8 +942,8 @@ positive_40_power <- gs_power_ahr( positive_40_power |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` #### Overall population power @@ -963,8 +963,8 @@ gs_power_ahr( lpar = rep(-Inf, 2) ) |> summary() |> - gt() |> - fmt_number(columns = 3:6, decimals = 4) + lt() |> + lt_format(columns = 3:6, decimals = 4) ``` ## Summary of findings diff --git a/vignettes/articles/story-update-boundary.Rmd b/vignettes/articles/story-update-boundary.Rmd index 3aa580551..c346e921f 100644 --- a/vignettes/articles/story-update-boundary.Rmd +++ b/vignettes/articles/story-update-boundary.Rmd @@ -23,7 +23,7 @@ knitr::opts_chunk$set(echo = TRUE) ```{r, message=FALSE, warning=FALSE} library(gsDesign2) -library(gt) +library(lt) ``` # Design assumptions @@ -116,8 +116,7 @@ over the targeted 90\%. ```{r} x |> summary() |> - as_gt() |> - tab_header(title = "Planned design") + as_lt(title = "Planned design") ``` ## Bounds for alternate alpha @@ -132,7 +131,7 @@ gs_update_ahr( alpha = 0.025 ) |> summary(col_decimals = c(z = 4)) |> - as_gt(title = "Updated design", + as_lt(title = "Updated design", subtitle = "For alternate alpha = 0.025") ``` The above updated boundaries utilize the planned treatment effect and the planned statistical information under null hypothesis, considering the original design has `info_scale = "h0_info"`. @@ -164,7 +163,7 @@ gs_update_ahr( event = c(30, 210, 32, 320)) ) |> summary(col_decimals = c(z = 4)) |> - as_gt(title = "Updated design", + as_lt(title = "Updated design", subtitle = paste0("With observed 240 events at IA and 352 events at FA")) ``` @@ -223,9 +222,8 @@ larger than we had above in the 1-sided example. ```{r} x |> summary() |> - as_gt() |> - tab_header(title = "Planned design", - subtitle = "2-sided asymmetric design, non-binding futility") + as_lt(title = "Planned design", + subtitle = "2-sided asymmetric design, non-binding futility") ``` ## Bounds for alternate alpha @@ -239,7 +237,7 @@ gs_update_ahr( alpha = 0.025 ) |> summary(col_decimals = c(z = 4)) |> - as_gt(title = "Updated design", + as_lt(title = "Updated design", subtitle = "For alpha = 0.025") ``` @@ -261,7 +259,7 @@ gs_update_ahr( event = c(30, 210, 32, 320)) ) |> summary(col_decimals = c(z = 4)) |> - as_gt(title = "Updated design", + as_lt(title = "Updated design", subtitle = paste0("With observed 240 events at IA and 352 events at FA")) ``` diff --git a/vignettes/gsDesign2.Rmd b/vignettes/gsDesign2.Rmd index abfd6450a..ae1588e4b 100644 --- a/vignettes/gsDesign2.Rmd +++ b/vignettes/gsDesign2.Rmd @@ -69,7 +69,7 @@ library(gsDesign) library(gsDesign2) library(knitr) library(dplyr) -library(gt) +library(lt) library(ggplot2) ``` @@ -86,7 +86,7 @@ enroll_rate <- define_enroll_rate( rate = (1:4) / 4 ) -enroll_rate |> gt() +enroll_rate |> lt() ``` # Failure and dropout rates @@ -112,7 +112,7 @@ fail_rate <- define_fail_rate( dropout_rate = .001 ) -fail_rate |> gt() +fail_rate |> lt() ``` # Fixed design @@ -138,14 +138,14 @@ Note that you would normally round up `N` up to an even number and `Events` to t ```{r} d |> summary() |> - as_gt() + as_lt() ``` The enrollment rates for each period have been increased proportionately to size the trial for the desired properties; the duration for each enrollment rate has not changed. ```{r} -d$enroll_rate |> gt() +d$enroll_rate |> lt() ``` # Group sequential design @@ -210,7 +210,7 @@ Note that expected sample size at time of each data cutoff for analysis is also ```{r} design1s |> summary() |> - as_gt( + as_lt( title = "1-sided group sequential bound using AHR method", subtitle = "Lan-DeMets spending to approximate O'Brien-Fleming bound" ) @@ -260,7 +260,7 @@ Design bounds are confirmed with: ```{r, message=FALSE} design2ss |> summary() |> - as_gt( + as_lt( title = "2-sided symmetric group sequential bound using AHR method", subtitle = "Lan-DeMets spending to approximate O'Brien-Fleming bound" ) @@ -308,7 +308,7 @@ Bounds are now: ```{r} design2sa |> summary() |> - as_gt( + as_lt( title = "2-sided asymmetric group sequential bound using AHR method", subtitle = "Lan-DeMets spending to approximate O'Brien-Fleming bound for efficacy, futility disaster check at IA1, IA2 only" From 836d523f7b20e654f88b9a088c7089023f0f296a Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 21 May 2026 14:19:14 -0400 Subject: [PATCH 02/12] Add as_lt() documentation; update roxygen metadata Co-Authored-By: Claude Opus 4.6 --- DESCRIPTION | 2 +- man/as_lt.Rd | 192 +++++++++++++++++++++++++++++++++++++++ man/gsDesign2-package.Rd | 1 + 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 man/as_lt.Rd diff --git a/DESCRIPTION b/DESCRIPTION index b95ec4496..bf113ed9f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -68,4 +68,4 @@ VignetteBuilder: LinkingTo: Rcpp Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.3 +Config/roxygen2/version: 8.0.0 diff --git a/man/as_lt.Rd b/man/as_lt.Rd new file mode 100644 index 000000000..8ee52e666 --- /dev/null +++ b/man/as_lt.Rd @@ -0,0 +1,192 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/as_lt.R +\name{as_lt} +\alias{as_lt} +\alias{as_lt.fixed_design_summary} +\alias{as_lt.gs_design_summary} +\title{Convert summary table of a fixed or group sequential design object to an lt table} +\usage{ +as_lt(x, ...) + +\method{as_lt}{fixed_design_summary}(x, title = NULL, footnote = NULL, ...) + +\method{as_lt}{gs_design_summary}( + x, + title = NULL, + subtitle = NULL, + colname_spanner = "Cumulative boundary crossing probability", + colname_spannersub = c("Alternate hypothesis", "Null hypothesis"), + footnote = NULL, + display_bound = c("Efficacy", "Futility"), + display_columns = NULL, + display_inf_bound = FALSE, + ... +) +} +\arguments{ +\item{x}{A summary object of a fixed or group sequential design.} + +\item{...}{Additional arguments (not used).} + +\item{title}{A string to specify the title of the table.} + +\item{footnote}{A list containing \code{content}, \code{location}, and \code{attr}. +\code{content} is a vector of string to specify the footnote text; \code{location} is +a vector of string to specify the locations to put the superscript of the +footnote index; \code{attr} is a vector of string to specify the attributes of +the footnotes, for example, \code{c("colname", "title", "subtitle", "analysis", "spanner")}. To disable footnotes, use \code{footnote = FALSE}.} + +\item{subtitle}{A string to specify the subtitle of the table.} + +\item{colname_spanner}{A string to specify the spanner of the table.} + +\item{colname_spannersub}{A vector of strings to specify the spanner details +of the table.} + +\item{display_bound}{A vector of strings specifying the label of the bounds. +The default is \code{c("Efficacy", "Futility")}.} + +\item{display_columns}{A vector of strings specifying the variables to be +displayed in the summary table.} + +\item{display_inf_bound}{Logical, whether to display the +/-inf bound.} +} +\value{ +An \code{lt_tbl} object. +} +\description{ +Convert summary table of a fixed or group sequential design object to an lt table +} +\examples{ +# Fixed design examples ---- + +# Enrollment rate +enroll_rate <- define_enroll_rate( + duration = 18, + rate = 20 +) + +# Failure rates +fail_rate <- define_fail_rate( + duration = c(4, 100), + fail_rate = log(2) / 12, + dropout_rate = .001, + hr = c(1, .6) +) + +# Study duration in months +study_duration <- 36 + +# Experimental / Control randomization ratio +ratio <- 1 + +# 1-sided Type I error +alpha <- 0.025 + +# Type II error (1 - power) +beta <- 0.1 + +# Example 1 ---- +fixed_design_ahr( + alpha = alpha, power = 1 - beta, + enroll_rate = enroll_rate, fail_rate = fail_rate, + study_duration = study_duration, ratio = ratio +) |> + summary() |> + as_lt() + +# Example 2 ---- +fixed_design_fh( + alpha = alpha, power = 1 - beta, + enroll_rate = enroll_rate, fail_rate = fail_rate, + study_duration = study_duration, ratio = ratio +) |> + summary() |> + as_lt() +\donttest{ +# Group sequential design examples --- + +# Example 1 ---- +# The default output + +gs_design_ahr() |> + summary() |> + as_lt() + +gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt() + +gs_design_wlr() |> + summary() |> + as_lt() + +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt() + +gs_power_combo() |> + summary() |> + as_lt() + +gs_design_rd() |> + summary() |> + as_lt() + +gs_power_rd() |> + summary() |> + as_lt() + +# Example 2 ---- +# Usage of title = ..., subtitle = ... +# to edit the title/subtitle +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt( + title = "Bound Summary", + subtitle = "from gs_power_wlr" + ) + +# Example 3 ---- +# Usage of colname_spanner = ..., colname_spannersub = ... +# to edit the spanner and its sub-spanner +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt( + colname_spanner = "Cumulative probability to cross boundaries", + colname_spannersub = c("under H1", "under H0") + ) + +# Example 4 ---- +# Usage of footnote = ... +# to edit the footnote +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt( + footnote = list( + content = c( + "approximate weighted hazard ratio to cross bound.", + "wAHR is the weighted AHR.", + "the crossing probability.", + "this table is generated by gs_power_wlr." + ), + location = c("~wHR at bound", NA, NA, NA), + attr = c("colname", "analysis", "spanner", "title") + ) + ) + +# Example 5 ---- +# Usage of display_bound = ... +# to either show efficacy bound or futility bound, or both(default) +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt(display_bound = "Efficacy") + +# Example 6 ---- +# Usage of display_columns = ... +# to select the columns to display in the summary table +gs_power_wlr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |> + summary() |> + as_lt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) +} +} diff --git a/man/gsDesign2-package.Rd b/man/gsDesign2-package.Rd index c31fdc74c..e5a286eeb 100644 --- a/man/gsDesign2-package.Rd +++ b/man/gsDesign2-package.Rd @@ -24,6 +24,7 @@ Useful links: Authors: \itemize{ + \item Yujie Zhao \email{yujie.zhao@merck.com} \item Keaven Anderson \email{keaven_anderson@merck.com} \item Yilong Zhang \email{elong0527@gmail.com} \item John Blischak \email{jdblischak@gmail.com} From 6b0938813e09023e073b2d12b3d833d1fcb2d705 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 21 May 2026 14:27:43 -0400 Subject: [PATCH 03/12] Fix unquoted column names in lt_spanner() calls lt requires character strings for column names (unlike gt's tidy-select). Co-Authored-By: Claude Opus 4.6 --- vignettes/articles/story-risk-difference.Rmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vignettes/articles/story-risk-difference.Rmd b/vignettes/articles/story-risk-difference.Rmd index b1333a078..5c377d807 100644 --- a/vignettes/articles/story-risk-difference.Rmd +++ b/vignettes/articles/story-risk-difference.Rmd @@ -705,11 +705,11 @@ tibble::tibble( lt() |> lt_spanner( label = "gsDesign2", - columns = c(gsDesign2_info_scale_0, gsDesign2_info_scale_1, gsDesign2_info_scale_2) + columns = c("gsDesign2_info_scale_0", "gsDesign2_info_scale_1", "gsDesign2_info_scale_2") ) |> lt_spanner( label = "EAST", - columns = c(EAST_unpool, EAST_pool) + columns = c("EAST_unpool", "EAST_pool") ) |> lt_cols_label( gsDesign2_info_scale_0 = "info_scale = \"h0_info\"", @@ -936,11 +936,11 @@ tibble::tibble( lt() |> lt_spanner( label = "gsDesign2", - columns = c(gsDesign2_info_scale_0, gsDesign2_info_scale_1, gsDesign2_info_scale_2) + columns = c("gsDesign2_info_scale_0", "gsDesign2_info_scale_1", "gsDesign2_info_scale_2") ) |> lt_spanner( label = "EAST", - columns = c(EAST_unpool, EAST_pool) + columns = c("EAST_unpool", "EAST_pool") ) |> lt_cols_label( gsDesign2_info_scale_0 = "info_scale = \"h0_info\"", @@ -1476,7 +1476,7 @@ ans |> ) |> lt_spanner( label = "Sample size weighting", - columns = c(SS0, SS1, SS2) + columns = c("SS0", "SS1", "SS2") ) |> lt_cols_label( INVAR0 = "info_scale = \"h0_info\"", From f8604047b39d47be113fafc45ee891e0b959cd6e Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 21 May 2026 15:06:17 -0400 Subject: [PATCH 04/12] Add Remotes: yihui/lt for CI installation Co-Authored-By: Claude Opus 4.6 --- DESCRIPTION | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index bf113ed9f..680c0d024 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -67,5 +67,7 @@ VignetteBuilder: knitr LinkingTo: Rcpp +Remotes: + yihui/lt Roxygen: list(markdown = TRUE) Config/roxygen2/version: 8.0.0 From 1cf48736ea54c4e866a5d2495248758fe5d6d33c Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 21 May 2026 15:14:28 -0400 Subject: [PATCH 05/12] Update _pkgdown.yml: as_gt -> as_lt Co-Authored-By: Claude Opus 4.6 --- _pkgdown.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index 732aad044..eae45ec40 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -93,9 +93,9 @@ reference: - summary.fixed_design - summary.gs_design - text_summary - - as_gt - - as_gt.fixed_design_summary - - as_gt.gs_design_summary + - as_lt + - as_lt.fixed_design_summary + - as_lt.gs_design_summary - as_rtf - as_rtf.fixed_design_summary - as_rtf.gs_design_summary From 2d91429eaa7a74d9a02a14fb325bbf51c9fdab99 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 14:26:51 -0400 Subject: [PATCH 06/12] Deprecate as_gt(); style as_lt() to match gt appearance - Restore as_gt() as a thin, deprecated wrapper that warns and delegates to as_lt(), so existing users get a migration path instead of a hard break. - Bundle inst/css/gt-style.css and apply it from both as_lt() methods via lt::lt_css(), making lt output nearly indistinguishable from the old gt tables (top caption, light-grey rules, system-ui font, bare footnote superscripts). lt dedups the stylesheet across a knitted document. - Fix count_footnotes() test helper to read $footnotes (where lt_footnote stores them) instead of $ops. Co-Authored-By: Claude Opus 4.7 --- NAMESPACE | 1 + R/as_gt.R | 24 ++++++++++++++++ R/as_lt.R | 11 ++++++-- inst/css/gt-style.css | 44 +++++++++++++++++++++++++++++ man/as_gt.Rd | 27 ++++++++++++++++++ tests/testit/test-developer-as_lt.R | 2 +- 6 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 inst/css/gt-style.css create mode 100644 man/as_gt.Rd diff --git a/NAMESPACE b/NAMESPACE index dba88e9dc..cfc36dc9d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,6 +12,7 @@ S3method(to_integer,fixed_design) S3method(to_integer,gs_design) export(ahr) export(ahr_blinded) +export(as_gt) export(as_lt) export(as_rtf) export(define_enroll_rate) diff --git a/R/as_gt.R b/R/as_gt.R index 6c97f2727..a0001040d 100644 --- a/R/as_gt.R +++ b/R/as_gt.R @@ -16,6 +16,30 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +#' Convert a design summary to a gt table (deprecated) +#' +#' @description +#' **Deprecated.** +#' +#' `as_gt()` is deprecated in favor of [as_lt()], which produces a lightweight +#' HTML table with nearly identical appearance and no dependency on the `gt` +#' package. `as_gt()` is currently a thin wrapper around `as_lt()` and will be +#' removed in a future release; please switch to `as_lt()`. +#' +#' @param x A summary object of a fixed or group sequential design. +#' @param ... Additional arguments passed to [as_lt()]. +#' +#' @return An `lt_tbl` object (previously a `gt_tbl` object). +#' +#' @seealso [as_lt()] +#' +#' @export +as_gt <- function(x, ...) { + .Deprecated("as_lt", package = "gsDesign2", + msg = "as_gt() is deprecated; please use as_lt() instead.") + as_lt(x, ...) +} + # get different default columns to display gsd_columns <- function(columns, method, x) { # set different default columns to display diff --git a/R/as_lt.R b/R/as_lt.R index 4580c3069..38d347389 100644 --- a/R/as_lt.R +++ b/R/as_lt.R @@ -28,6 +28,13 @@ as_lt <- function(x, ...) { UseMethod("as_lt", x) } +# Apply the bundled gt-style theme so as_lt() output resembles the gt tables +# that as_gt() used to produce. lt::lt_css() dedups this stylesheet across a +# knitted document, so it is emitted once even with many tables. +lt_gt_style <- function(x) { + lt::lt_css(x, system.file("css", "gt-style.css", package = "gsDesign2")) +} + #' @rdname as_lt #' #' @export @@ -90,7 +97,7 @@ as_lt.fixed_design_summary <- function(x, title = NULL, footnote = NULL, ...) { lt::lt_footnote(text = footnote, where = "title") } - ans + lt_gt_style(ans) } #' @rdname as_lt @@ -256,5 +263,5 @@ as_lt.gs_design_summary <- function( columns = colname_spannersub[2], rows = rows) } - ans + lt_gt_style(ans) } diff --git a/inst/css/gt-style.css b/inst/css/gt-style.css new file mode 100644 index 000000000..cf01ed67e --- /dev/null +++ b/inst/css/gt-style.css @@ -0,0 +1,44 @@ +/* Make lt tables resemble the gt tables that gsDesign2 used to produce via + * as_gt(). Tuned to match gt's default theme (system-ui font, light-grey + * #D3D3D3 rules, #333 text, normal-weight column labels, top caption). */ +.lt-table { + caption-side: top; + border-collapse: collapse; + width: 100%; + color: #333; + font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; + + th, td { padding: 8px 5px; } + + /* gt draws its header/body rules in light grey, not black */ + border-top: 2px solid #A8A8A8; + border-bottom: 2px solid #A8A8A8; + + caption { + border-top: none; + .lt-title { font-weight: bold; } + .lt-subtitle { font-weight: normal; } + } + + thead th { + font-weight: normal; + border-bottom: 2px solid #D3D3D3; + } + thead .lt-spanner-row { + .lt-spanner { border-bottom: 2px solid #D3D3D3; } + /* empty cells above the stub columns carry no rule in gt */ + .lt-spanner-empty { border-bottom: none; } + } + + tbody tr:not(:last-child) :is(td, th) { border-bottom: 1px solid #D3D3D3; } + + /* group rows: a subtle full-width rule like gt's row-group divider */ + .lt-row-group th { font-weight: bold; } + + /* footnote references: gt uses bare dark superscripts, not blue [n] */ + sup.lt-fnref { + color: inherit; + &::before { content: none; } + &::after { content: none; } + } +} diff --git a/man/as_gt.Rd b/man/as_gt.Rd new file mode 100644 index 000000000..ffc456283 --- /dev/null +++ b/man/as_gt.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/as_gt.R +\name{as_gt} +\alias{as_gt} +\title{Convert a design summary to a gt table (deprecated)} +\usage{ +as_gt(x, ...) +} +\arguments{ +\item{x}{A summary object of a fixed or group sequential design.} + +\item{...}{Additional arguments passed to \code{\link[=as_lt]{as_lt()}}.} +} +\value{ +An \code{lt_tbl} object (previously a \code{gt_tbl} object). +} +\description{ +\strong{Deprecated.} + +\code{as_gt()} is deprecated in favor of \code{\link[=as_lt]{as_lt()}}, which produces a lightweight +HTML table with nearly identical appearance and no dependency on the \code{gt} +package. \code{as_gt()} is currently a thin wrapper around \code{as_lt()} and will be +removed in a future release; please switch to \code{as_lt()}. +} +\seealso{ +\code{\link[=as_lt]{as_lt()}} +} diff --git a/tests/testit/test-developer-as_lt.R b/tests/testit/test-developer-as_lt.R index c505cecc5..718283a9e 100644 --- a/tests/testit/test-developer-as_lt.R +++ b/tests/testit/test-developer-as_lt.R @@ -1,5 +1,5 @@ count_footnotes <- function(x) { - sum(vapply(x$ops, function(op) op$type == "footnote", logical(1))) + length(x$footnotes) } assert("as_lt: footnote=FALSE removes footnote", { From 93a52963119d9c62648060589e0703c118ebd35f Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 14:37:15 -0400 Subject: [PATCH 07/12] Add as_gt to pkgdown reference index as_gt() is exported again (as a deprecated wrapper), so pkgdown requires it in the reference index. Co-Authored-By: Claude Opus 4.7 --- _pkgdown.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index eae45ec40..39cf53238 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -96,6 +96,7 @@ reference: - as_lt - as_lt.fixed_design_summary - as_lt.gs_design_summary + - as_gt - as_rtf - as_rtf.fixed_design_summary - as_rtf.gs_design_summary From 059a19a1f7e0928c60c029a086011a1450858f15 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 14:37:15 -0400 Subject: [PATCH 08/12] Trim gt-style.css to only what differs from lt.css Drop properties already set by lt's default stylesheet or by browser defaults (caption-side, empty-spanner border, normal-weight subtitle/th), keeping only the rules that actually change the appearance toward gt. Co-Authored-By: Claude Opus 4.7 --- inst/css/gt-style.css | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/inst/css/gt-style.css b/inst/css/gt-style.css index cf01ed67e..146d66920 100644 --- a/inst/css/gt-style.css +++ b/inst/css/gt-style.css @@ -1,8 +1,8 @@ /* Make lt tables resemble the gt tables that gsDesign2 used to produce via - * as_gt(). Tuned to match gt's default theme (system-ui font, light-grey - * #D3D3D3 rules, #333 text, normal-weight column labels, top caption). */ + * as_gt(). Only properties that differ from lt's default lt.css are declared + * here, tuned to gt's default theme (system-ui font, #333 text, light-grey + * #D3D3D3 rules, normal-weight column labels). */ .lt-table { - caption-side: top; border-collapse: collapse; width: 100%; color: #333; @@ -10,31 +10,23 @@ th, td { padding: 8px 5px; } - /* gt draws its header/body rules in light grey, not black */ + /* gt draws its outer + body rules in light grey, not black/1px */ border-top: 2px solid #A8A8A8; border-bottom: 2px solid #A8A8A8; caption { border-top: none; - .lt-title { font-weight: bold; } - .lt-subtitle { font-weight: normal; } + .lt-title { font-weight: bold; } } thead th { font-weight: normal; border-bottom: 2px solid #D3D3D3; } - thead .lt-spanner-row { - .lt-spanner { border-bottom: 2px solid #D3D3D3; } - /* empty cells above the stub columns carry no rule in gt */ - .lt-spanner-empty { border-bottom: none; } - } + thead .lt-spanner-row .lt-spanner { border-bottom: 2px solid #D3D3D3; } tbody tr:not(:last-child) :is(td, th) { border-bottom: 1px solid #D3D3D3; } - /* group rows: a subtle full-width rule like gt's row-group divider */ - .lt-row-group th { font-weight: bold; } - /* footnote references: gt uses bare dark superscripts, not blue [n] */ sup.lt-fnref { color: inherit; From bd3bedf78d126302b8096644b70a224cd0a4edb0 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 15:20:16 -0400 Subject: [PATCH 09/12] Simplify as_gt() docs to a deprecation pointer Drop the gt-era prose; the help page now just states as_gt() is superseded by as_lt() and points there. Co-Authored-By: Claude Opus 4.7 --- R/as_gt.R | 12 +++--------- man/as_gt.Rd | 11 +++-------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/R/as_gt.R b/R/as_gt.R index a0001040d..09916e0db 100644 --- a/R/as_gt.R +++ b/R/as_gt.R @@ -16,20 +16,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -#' Convert a design summary to a gt table (deprecated) +#' Deprecated: superseded by [as_lt()] #' -#' @description -#' **Deprecated.** -#' -#' `as_gt()` is deprecated in favor of [as_lt()], which produces a lightweight -#' HTML table with nearly identical appearance and no dependency on the `gt` -#' package. `as_gt()` is currently a thin wrapper around `as_lt()` and will be -#' removed in a future release; please switch to `as_lt()`. +#' `as_gt()` is deprecated; use [as_lt()] instead. It now calls [as_lt()]. #' #' @param x A summary object of a fixed or group sequential design. #' @param ... Additional arguments passed to [as_lt()]. #' -#' @return An `lt_tbl` object (previously a `gt_tbl` object). +#' @return An `lt_tbl` object. #' #' @seealso [as_lt()] #' diff --git a/man/as_gt.Rd b/man/as_gt.Rd index ffc456283..b8d9341ce 100644 --- a/man/as_gt.Rd +++ b/man/as_gt.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/as_gt.R \name{as_gt} \alias{as_gt} -\title{Convert a design summary to a gt table (deprecated)} +\title{Deprecated: superseded by \code{\link[=as_lt]{as_lt()}}} \usage{ as_gt(x, ...) } @@ -12,15 +12,10 @@ as_gt(x, ...) \item{...}{Additional arguments passed to \code{\link[=as_lt]{as_lt()}}.} } \value{ -An \code{lt_tbl} object (previously a \code{gt_tbl} object). +An \code{lt_tbl} object. } \description{ -\strong{Deprecated.} - -\code{as_gt()} is deprecated in favor of \code{\link[=as_lt]{as_lt()}}, which produces a lightweight -HTML table with nearly identical appearance and no dependency on the \code{gt} -package. \code{as_gt()} is currently a thin wrapper around \code{as_lt()} and will be -removed in a future release; please switch to \code{as_lt()}. +\code{as_gt()} is deprecated; use \code{\link[=as_lt]{as_lt()}} instead. It now calls \code{\link[=as_lt]{as_lt()}}. } \seealso{ \code{\link[=as_lt]{as_lt()}} From 7fe511c7e5e99e98d884240c4bd32a78c88deb28 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 16:30:40 -0400 Subject: [PATCH 10/12] Use lt's bundled lt-gt.css theme instead of a local copy lt now ships the gt-like theme as lt-gt.css and lt_css() resolves bare filenames against the package, so gsDesign2 no longer needs its own copy. Co-Authored-By: Claude Opus 4.7 --- R/as_lt.R | 9 +++++---- inst/css/gt-style.css | 36 ------------------------------------ 2 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 inst/css/gt-style.css diff --git a/R/as_lt.R b/R/as_lt.R index 38d347389..bc1ce2157 100644 --- a/R/as_lt.R +++ b/R/as_lt.R @@ -28,11 +28,12 @@ as_lt <- function(x, ...) { UseMethod("as_lt", x) } -# Apply the bundled gt-style theme so as_lt() output resembles the gt tables -# that as_gt() used to produce. lt::lt_css() dedups this stylesheet across a -# knitted document, so it is emitted once even with many tables. +# Apply lt's bundled gt-like theme so as_lt() output resembles the gt tables +# that as_gt() used to produce. lt::lt_css() resolves the bare filename to the +# stylesheet shipped with lt, and dedups it across a knitted document so it is +# emitted once even with many tables. lt_gt_style <- function(x) { - lt::lt_css(x, system.file("css", "gt-style.css", package = "gsDesign2")) + lt::lt_css(x, "lt-gt.css") } #' @rdname as_lt diff --git a/inst/css/gt-style.css b/inst/css/gt-style.css deleted file mode 100644 index 146d66920..000000000 --- a/inst/css/gt-style.css +++ /dev/null @@ -1,36 +0,0 @@ -/* Make lt tables resemble the gt tables that gsDesign2 used to produce via - * as_gt(). Only properties that differ from lt's default lt.css are declared - * here, tuned to gt's default theme (system-ui font, #333 text, light-grey - * #D3D3D3 rules, normal-weight column labels). */ -.lt-table { - border-collapse: collapse; - width: 100%; - color: #333; - font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; - - th, td { padding: 8px 5px; } - - /* gt draws its outer + body rules in light grey, not black/1px */ - border-top: 2px solid #A8A8A8; - border-bottom: 2px solid #A8A8A8; - - caption { - border-top: none; - .lt-title { font-weight: bold; } - } - - thead th { - font-weight: normal; - border-bottom: 2px solid #D3D3D3; - } - thead .lt-spanner-row .lt-spanner { border-bottom: 2px solid #D3D3D3; } - - tbody tr:not(:last-child) :is(td, th) { border-bottom: 1px solid #D3D3D3; } - - /* footnote references: gt uses bare dark superscripts, not blue [n] */ - sup.lt-fnref { - color: inherit; - &::before { content: none; } - &::after { content: none; } - } -} From 9bd6d863340a5aad9403efe1181d8fc00bca4e35 Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Tue, 2 Jun 2026 18:45:13 -0400 Subject: [PATCH 11/12] Drop lt_gt_style(); gt-like look is now lt's default lt's default stylesheet is now gt-like, so as_lt() no longer needs to attach a separate theme via lt_css(). Co-Authored-By: Claude Opus 4.7 --- R/as_lt.R | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/R/as_lt.R b/R/as_lt.R index bc1ce2157..4580c3069 100644 --- a/R/as_lt.R +++ b/R/as_lt.R @@ -28,14 +28,6 @@ as_lt <- function(x, ...) { UseMethod("as_lt", x) } -# Apply lt's bundled gt-like theme so as_lt() output resembles the gt tables -# that as_gt() used to produce. lt::lt_css() resolves the bare filename to the -# stylesheet shipped with lt, and dedups it across a knitted document so it is -# emitted once even with many tables. -lt_gt_style <- function(x) { - lt::lt_css(x, "lt-gt.css") -} - #' @rdname as_lt #' #' @export @@ -98,7 +90,7 @@ as_lt.fixed_design_summary <- function(x, title = NULL, footnote = NULL, ...) { lt::lt_footnote(text = footnote, where = "title") } - lt_gt_style(ans) + ans } #' @rdname as_lt @@ -264,5 +256,5 @@ as_lt.gs_design_summary <- function( columns = colname_spannersub[2], rows = rows) } - lt_gt_style(ans) + ans } From ac673698fa70a31707c6b24798be3f281f5c703c Mon Sep 17 00:00:00 2001 From: Yihui Xie Date: Thu, 4 Jun 2026 18:07:31 -0400 Subject: [PATCH 12/12] Adapt to lt 0.0.9: use lt_group(~ col) instead of lt(row_group = ...) Co-Authored-By: Claude Opus 4.6 --- R/as_lt.R | 2 +- R/utility_tidy_tbl.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/as_lt.R b/R/as_lt.R index 4580c3069..ce28e4df3 100644 --- a/R/as_lt.R +++ b/R/as_lt.R @@ -219,7 +219,7 @@ as_lt.gs_design_summary <- function( display_bound, display_columns, display_inf_bound ) - ans <- lt::lt(as.data.frame(parts$x), row_group = "Analysis") |> + ans <- lt::lt(as.data.frame(parts$x)) |> lt::lt_group(~ Analysis) |> lt::lt_spanner( label = colname_spanner, columns = colname_spannersub diff --git a/R/utility_tidy_tbl.R b/R/utility_tidy_tbl.R index 1661033a8..f49bd001a 100644 --- a/R/utility_tidy_tbl.R +++ b/R/utility_tidy_tbl.R @@ -46,7 +46,7 @@ #' b3 = (10:8) / 3 #' ) #' table_ab(a, b, byvar = "Index", decimals = c(0, 2, 0, 1), aname = "Index") |> -#' lt(row_group = "Index") |> +#' lt() |> lt_group(~ Index) |> #' lt_format("b3", decimals = 2) |> #' lt_header(title = "Grouped data table") |> #' lt_footnote(