diff --git a/NAMESPACE b/NAMESPACE index cc1a2a41..dacfbf2c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,10 +1,10 @@ # Generated by roxygen2: do not edit by hand -S3method(as_gt,fixed_design) -S3method(as_gt,gs_design) +S3method(as_gt,fixed_design_summary) +S3method(as_gt,gs_design_summary) S3method(as_gt,simtrial_gs_wlr) -S3method(as_rtf,fixed_design) -S3method(as_rtf,gs_design) +S3method(as_rtf,fixed_design_summary) +S3method(as_rtf,gs_design_summary) S3method(summary,fixed_design) S3method(summary,gs_design) S3method(to_integer,fixed_design) diff --git a/R/as_gt.R b/R/as_gt.R index 160479b8..b925d6f2 100644 --- a/R/as_gt.R +++ b/R/as_gt.R @@ -78,60 +78,22 @@ as_gt <- function(x, ...) { #' ) |> #' summary() |> #' as_gt() -as_gt.fixed_design <- function(x, title = NULL, footnote = NULL, ...) { - method <- fd_method(x) - ans <- gt::gt(x) |> - gt::tab_header(title = title %||% fd_title(method)) - if (!isFALSE(footnote)) ans <- ans |> - gt::tab_footnote( - footnote = footnote %||% fd_footnote(x, method), - locations = gt::cells_title(group = "title") - ) - return(ans) -} - -get_method <- function(x, methods) intersect(methods, class(x))[1] +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") -# get the fixed design method -fd_method <- function(x) { - get_method(x, c("ahr", "fh", "mb", "lf", "rd", "maxcombo", "milestone", "rmst")) -} + ans <- gt::gt(x) |> + gt::tab_header(title = title) -# get the default title -fd_title <- function(method) { - sprintf("Fixed Design %s Method", switch( - method, - ahr = "under AHR", fh = "under Fleming-Harrington", mb = "under Magirr-Burman", - lf = "under Lachin and Foulkes", maxcombo = "under MaxCombo", - milestone = "under Milestone", rmst = "under Restricted Mean Survival Time", - rd = "of Risk Difference under Farrington-Manning" - )) -} + if (!isFALSE(footnote)) { + ans <- ans |> + gt::tab_footnote( + footnote = footnote, + locations = gt::cells_title(group = "title") + ) + } -# get the default footnote -fd_footnote <- function(x, method) { - switch( - method, - ahr = "Power computed with average hazard ratio method.", - fh = paste( - "Power for Fleming-Harrington test", substring(x$Design, 19), - "using method of Yung and Liu." - ), - lf = paste( - "Power using Lachin and Foulkes method applied using expected", - "average hazard ratio (AHR) at time of planned analysis." - ), - rd = paste( - "Risk difference power without continuity correction using method of", - "Farrington and Manning." - ), - maxcombo = paste0( - "Power for MaxCombo test with Fleming-Harrington tests ", - substring(x$Design, 9), "." - ), - # for mb, milestone, and rmst - paste("Power for", x$Design, "computed with method of Yung and Liu.") - ) + return(ans) } #' @rdname as_gt @@ -243,7 +205,7 @@ fd_footnote <- function(x, method) { #' summary() |> #' as_gt(display_columns = c("Analysis", "Bound", "Nominal p", "Z", "Probability")) #' } -as_gt.gs_design <- function( +as_gt.gs_design_summary <- function( x, title = NULL, subtitle = NULL, @@ -355,7 +317,7 @@ gsd_footnote <- function(method, columns) { # footnote for non-binding designs gsd_footnote_nb <- function(x, x_alpha) { full_alpha <- attr(x, "full_alpha") - if (!inherits(x, "non_binding") || x_alpha >= full_alpha) return() + if (attr(x, "binding") || x_alpha >= full_alpha) return() a1 <- format(x_alpha, scientific = FALSE) a2 <- format(full_alpha, scientific = FALSE) a3 <- format(full_alpha - x_alpha, scientific = FALSE) @@ -387,7 +349,7 @@ gsd_parts <- function( x, title, subtitle, spannersub, footnote, bound, columns, inf_bound, transform = identity ) { - method <- intersect(c("ahr", "wlr", "combo", "rd"), class(x))[1] + method <- attr(x, "design") if (!inf_bound) x <- filter(x, !is.infinite(Z)) # `x` needs a custom transformation in as_rtf() x2 <- transform(x) diff --git a/R/as_rtf.R b/R/as_rtf.R index fd8eb040..a8bc18e8 100644 --- a/R/as_rtf.R +++ b/R/as_rtf.R @@ -90,7 +90,7 @@ as_rtf <- function(x, ...) { #' ) |> #' summary() |> #' as_rtf(file = tempfile(fileext = ".rtf")) -as_rtf.fixed_design <- function( +as_rtf.fixed_design_summary <- function( x, title = NULL, footnote = NULL, @@ -100,9 +100,10 @@ as_rtf.fixed_design <- function( file, ...) { orientation <- match.arg(orientation) - method <- fd_method(x) - title <- title %||% paste(fd_title(method), "{^a}") - footnote <- footnote %||% paste("{^a}", fd_footnote(x, method)) + if (is.null(title)) title <- attr(x, "title") + if (is.null(footnote)) footnote <- attr(x, "footnote") + title <- paste(title, "{^a}") + footnote <- paste("{^a}", footnote) # set default column width n_row <- nrow(x) @@ -266,7 +267,7 @@ check_rel_width <- function(width, n_col) { #' file = tempfile(fileext = ".rtf") #' ) #' } -as_rtf.gs_design <- function( +as_rtf.gs_design_summary <- function( x, title = NULL, subtitle = NULL, diff --git a/R/fixed_design_ahr.R b/R/fixed_design_ahr.R index a5dce740..f506e075 100644 --- a/R/fixed_design_ahr.R +++ b/R/fixed_design_ahr.R @@ -122,6 +122,8 @@ fixed_design_ahr <- function( info_scale = info_scale ) } + + # Prepare output ---- ans <- tibble( design = "ahr", n = d$analysis$n, @@ -132,10 +134,16 @@ fixed_design_ahr <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, enroll_rate = d$enroll_rate, - fail_rate = d$fail_rate, analysis = ans, design = "ahr" + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "ahr" + ), + class = "fixed_design", + design_display = "Average hazard ratio", + title = "Fixed Design under AHR Method", + footnote = "Power computed with average hazard ratio method." ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_fh.R b/R/fixed_design_fh.R index 95fe6dbe..52df87a1 100644 --- a/R/fixed_design_fh.R +++ b/R/fixed_design_fh.R @@ -121,6 +121,8 @@ fixed_design_fh <- function( info_scale = info_scale ) } + + # Prepare output ---- ans <- tibble( design = "fh", n = d$analysis$n, @@ -131,11 +133,23 @@ fixed_design_fh <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, - analysis = ans, - design = "fh", design_par = list(rho = rho, gamma = gamma) + design_display <- paste0( + "Fleming-Harrington FH(", rho, ", ", gamma, ")", + if (rho == 0 && gamma == 0) " (logrank)" + ) + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "fh", design_par = list(rho = rho, gamma = gamma) + ), + class = "fixed_design", + design_display = design_display, + title = "Fixed Design under Fleming-Harrington Method", + footnote = paste( + "Power for Fleming-Harrington test", substring(design_display, 19), + "using method of Yung and Liu." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_lf.R b/R/fixed_design_lf.R index d4805625..fa8510bf 100644 --- a/R/fixed_design_lf.R +++ b/R/fixed_design_lf.R @@ -172,6 +172,8 @@ fixed_design_lf <- function( rr[, 1] }) ) + + # Prepare output ---- ans <- tibble( design = "lf", n = d$n, @@ -181,13 +183,22 @@ fixed_design_lf <- function( alpha = d$alpha, power = d$power ) - y <- list( - input = input, - enroll_rate = enroll_rate |> mutate(rate = rate * d$n / sum(enroll_rate$duration * enroll_rate$rate)), - fail_rate = fail_rate, - analysis = ans, - design = "lf" + y <- structure( + list( + input = input, + enroll_rate = enroll_rate |> mutate(rate = rate * d$n / sum(enroll_rate$duration * enroll_rate$rate)), + fail_rate = fail_rate, + analysis = ans, + design = "lf" + ), + class = "fixed_design", + design_display = "Lachin and Foulkes", + title = "Fixed Design under Lachin and Foulkes Method", + footnote = paste( + "Power using Lachin and Foulkes method applied using expected", + "average hazard ratio (AHR) at time of planned analysis." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_maxcombo.R b/R/fixed_design_maxcombo.R index 36ce20cf..99bacebd 100644 --- a/R/fixed_design_maxcombo.R +++ b/R/fixed_design_maxcombo.R @@ -116,7 +116,8 @@ fixed_design_maxcombo <- function( lower = gs_b, lpar = -Inf ) } - # get the output of MaxCombo + + # Prepare output ---- ans <- tibble( design = "maxcombo", n = d$analysis$n, @@ -126,11 +127,30 @@ fixed_design_maxcombo <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, - enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, analysis = ans, - design = "maxcombo", design_par = list(rho = rho, gamma = gamma, tau = tau) + design_display <- gsub( + "FH(0, 0)", "logrank", paste( + "MaxCombo:", paste0( + "FHC(", rho, ", ", gamma, ")", + collapse = ", " + ) + ), + fixed = TRUE + ) + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "maxcombo", + design_par = list(rho = rho, gamma = gamma, tau = tau) + ), + class = "fixed_design", + design_display = design_display, + title = "Fixed Design under MaxCombo Method", + footnote = paste0( + "Power for MaxCombo test with Fleming-Harrington tests ", + substring(design_display, 9), + "." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_mb.R b/R/fixed_design_mb.R index c4c66cdf..fafc4d35 100644 --- a/R/fixed_design_mb.R +++ b/R/fixed_design_mb.R @@ -118,7 +118,8 @@ fixed_design_mb <- function( info_scale = info_scale ) } - # get the output of MB + + # Prepare output ---- ans <- tibble( design = "mb", n = d$analysis$n, @@ -129,10 +130,20 @@ fixed_design_mb <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, analysis = ans, - design = "mb", design_par = list(tau = tau, w_max = w_max) + design_display <- paste0("Modestly weighted LR: tau = ", tau) + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "mb", design_par = list(tau = tau, w_max = w_max) + ), + class = "fixed_design", + design_display = design_display, + title = "Fixed Design under Magirr-Burman Method", + footnote = paste( + "Power for", design_display, + "computed with method of Yung and Liu." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_milestone.R b/R/fixed_design_milestone.R index 4ecea03e..6b5e7186 100644 --- a/R/fixed_design_milestone.R +++ b/R/fixed_design_milestone.R @@ -104,7 +104,8 @@ fixed_design_milestone <- function( tau = tau ) } - # get the output of MaxCombo + + # Prepare output ---- ans <- tibble( design = "milestone", n = d$analysis$n, @@ -114,11 +115,20 @@ fixed_design_milestone <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, - enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, analysis = ans, - design = "milestone", design_par = list(tau = tau) + design_display <- paste("Milestone: tau =", tau) + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "milestone", design_par = list(tau = tau) + ), + class = "fixed_design", + design_display = design_display, + title = "Fixed Design under Milestone Method", + footnote = paste( + "Power for", design_display, + "computed with method of Yung and Liu." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_rd.R b/R/fixed_design_rd.R index 8ad69fac..256a24f5 100644 --- a/R/fixed_design_rd.R +++ b/R/fixed_design_rd.R @@ -100,7 +100,8 @@ fixed_design_rd <- function( info_scale = info_scale ) } - # get the output of MaxCombo + + # Prepare output ---- ans <- tibble( design = "rd", n = d$analysis$n, @@ -108,10 +109,19 @@ fixed_design_rd <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, - enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, analysis = ans, design = "rd" + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "rd" + ), + class = "fixed_design", + design_display = "Risk difference", + title = "Fixed Design of Risk Difference under Farrington-Manning Method", + footnote = paste( + "Risk difference power without continuity correction using method of", + "Farrington and Manning." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/fixed_design_rmst.R b/R/fixed_design_rmst.R index f514f09b..6c7c883e 100644 --- a/R/fixed_design_rmst.R +++ b/R/fixed_design_rmst.R @@ -103,7 +103,8 @@ fixed_design_rmst <- function( tau = tau ) } - # get the output + + # Prepare output ---- ans <- tibble( design = "rmst", n = d$analysis$n, @@ -113,11 +114,21 @@ fixed_design_rmst <- function( alpha = alpha, power = (d$bound |> filter(bound == "upper"))$probability ) - y <- list( - input = input, - enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, analysis = ans, - design = "rmst", design_par = list(tau = tau), study_duration + design_display <- paste("RMST: tau =", tau) + y <- structure( + list( + input = input, enroll_rate = d$enroll_rate, fail_rate = d$fail_rate, + analysis = ans, design = "rmst", design_par = list(tau = tau), + study_duration + ), + class = "fixed_design", + design_display = design_display, + title = "Fixed Design under Restricted Mean Survival Time Method", + footnote = paste( + "Power for", design_display, + "computed with method of Yung and Liu." + ) ) - class(y) <- c("fixed_design", class(y)) + return(y) } diff --git a/R/gs_bound_summary.R b/R/gs_bound_summary.R index b388c9d1..72f8b9c6 100644 --- a/R/gs_bound_summary.R +++ b/R/gs_bound_summary.R @@ -30,7 +30,7 @@ gs_bound_summary <- function(x, digits = 4, ddigits = 2, tdigits = 0, timename = tdigits = tdigits, timename = timename) return(out) } - if (!inherits(x, "ahr")) stop("The argument `alpha` is only supported for AHR design objects") + if (!x$design == "ahr") stop("The argument `alpha` is only supported for AHR design objects") if (!is.numeric(alpha)) stop("The argument `alpha` must be a numeric vector") # Support multiple alphas @@ -100,9 +100,9 @@ gs_bound_summary_single <- function(x, col_efficacy_name = "Efficacy", digits, hr <- round(hr, ddigits) hr_label <- "HR" # logrank test (gs_xxx_ahr): HR -> AHR - if (inherits(x, "ahr")) hr_label <- "AHR" + if (x$design == "ahr") hr_label <- "AHR" # weighted logrank test (gs_xxx_wlr): HR -> wAHR - if (inherits(x, "wlr")) hr_label <- "wAHR" + if (x$design == "wlr") hr_label <- "wAHR" col_value <- c( col_value, "Z", "p (1-sided)", "~HR at bound", "P(Cross) if HR=1", diff --git a/R/gs_design_ahr.R b/R/gs_design_ahr.R index f9cc7bc0..a8e29324 100644 --- a/R/gs_design_ahr.R +++ b/R/gs_design_ahr.R @@ -396,16 +396,19 @@ gs_design_ahr <- function( ) # Return the output ---- - ans <- list( - input = input, - enroll_rate = enroll_rate |> mutate(rate = rate * inflac_fct), - fail_rate = fail_rate, - bound = bound |> filter(!is.infinite(z)), - analysis = analysis + ans <- structure( + list( + design = "ahr", + input = input, + enroll_rate = enroll_rate |> mutate(rate = rate * inflac_fct), + fail_rate = fail_rate, + bound = bound |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_design_ahr" ) - ans <- add_class(ans, if (!binding) "non_binding", "ahr", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_design_ahr" - return(ans) } diff --git a/R/gs_design_combo.R b/R/gs_design_combo.R index f60f42ca..24d7b78b 100644 --- a/R/gs_design_combo.R +++ b/R/gs_design_combo.R @@ -316,17 +316,17 @@ gs_design_combo <- function( arrange(analysis) # Output ---- - output <- list( - enroll_rate = enroll_rate |> mutate(rate = rate * max(analysis$n) / sum(rate * duration)), - fail_rate = fail_rate, - bounds = bounds, - analysis = analysis + output <- structure( + list( + design = "combo", + enroll_rate = enroll_rate |> mutate(rate = rate * max(analysis$n) / sum(rate * duration)), + fail_rate = fail_rate, + bounds = bounds, + analysis = analysis + ), + class = "gs_design", + binding = binding ) - class(output) <- c("combo", "gs_design", class(output)) - if (!binding) { - class(output) <- c("non_binding", class(output)) - } - return(output) } diff --git a/R/gs_design_rd.R b/R/gs_design_rd.R index b4f425e3..0f76f13b 100644 --- a/R/gs_design_rd.R +++ b/R/gs_design_rd.R @@ -271,14 +271,17 @@ gs_design_rd <- function(p_c = tibble::tibble(stratum = "All", rate = .2), select(analysis, n, rd, rd0, info, info0, info_frac, info_frac0) # Return the output ---- - ans <- list( - input = input, - bound = bound |> filter(!is.infinite(z)), - analysis = analysis + ans <- structure( + list( + design = "rd", + input = input, + bound = bound |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_design_rd" ) - ans <- add_class(ans, if (!binding) "non_binding", "rd", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_design_rd" - return(ans) } diff --git a/R/gs_design_wlr.R b/R/gs_design_wlr.R index 6423dd22..a208302c 100644 --- a/R/gs_design_wlr.R +++ b/R/gs_design_wlr.R @@ -329,15 +329,19 @@ gs_design_wlr <- function( info_scale = info_scale, r = r, tol = tol) # final output - ans <- list( - input = input, - enroll_rate = enroll_rate |> mutate(rate = rate * inflac_fct), - fail_rate = fail_rate, - bounds = bounds |> filter(!is.infinite(z)), - analysis = analysis) - - ans <- add_class(ans, if (!binding) "non_binding", "wlr", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_design_wlr" + ans <- structure( + list( + design = "wlr", + input = input, + enroll_rate = enroll_rate |> mutate(rate = rate * inflac_fct), + fail_rate = fail_rate, + bounds = bounds |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_design_wlr" + ) return(ans) } diff --git a/R/gs_power_ahr.R b/R/gs_power_ahr.R index 3da9b98c..16e37158 100644 --- a/R/gs_power_ahr.R +++ b/R/gs_power_ahr.R @@ -291,16 +291,19 @@ gs_power_ahr <- function( info_scale = info_scale, r = r, tol = tol ) - ans <- list( - input = input, - enroll_rate = enroll_rate, - fail_rate = fail_rate, - bound = bound |> filter(!is.infinite(z)), - analysis = analysis + ans <- structure( + list( + design = "ahr", + input = input, + enroll_rate = enroll_rate, + fail_rate = fail_rate, + bound = bound |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_power_ahr" ) - ans <- add_class(ans, if (!binding) "non_binding", "ahr", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_power_ahr" - return(ans) } diff --git a/R/gs_power_combo.R b/R/gs_power_combo.R index 7ba2f33c..c22429c9 100644 --- a/R/gs_power_combo.R +++ b/R/gs_power_combo.R @@ -238,17 +238,17 @@ gs_power_combo <- function( arrange(analysis) # Output ---- - output <- list( - enroll_rate = enroll_rate |> mutate(rate = rate * max(analysis$n) / sum(rate * duration)), - fail_rate = fail_rate, - bound = bound, - analysis = analysis + output <- structure( + list( + design = "combo", + enroll_rate = enroll_rate |> mutate(rate = rate * max(analysis$n) / sum(rate * duration)), + fail_rate = fail_rate, + bound = bound, + analysis = analysis + ), + class = "gs_design", + binding = binding ) - class(output) <- c("combo", "gs_design", class(output)) - if (!binding) { - class(output) <- c("non_binding", class(output)) - } - return(output) } diff --git a/R/gs_power_rd.R b/R/gs_power_rd.R index 057e6721..4bfc3910 100644 --- a/R/gs_power_rd.R +++ b/R/gs_power_rd.R @@ -343,13 +343,16 @@ gs_power_rd <- function( select(analysis, n, rd, rd0, theta1, theta0, info, info0, info_frac, info_frac0) ) - ans <- list( - bound = bound |> filter(!is.infinite(z)), - analysis = analysis + ans <- structure( + list( + design = "rd", + bound = bound |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_power_rd" ) - ans <- add_class(ans, if (!binding) "non_binding", "rd", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_power_rd" - return(ans) } diff --git a/R/gs_power_wlr.R b/R/gs_power_wlr.R index f47b2c24..93c7d80e 100644 --- a/R/gs_power_wlr.R +++ b/R/gs_power_wlr.R @@ -308,17 +308,20 @@ gs_power_wlr <- function(enroll_rate = define_enroll_rate(duration = c(2, 2, 10) ) # Return the output ---- - ans <- list( - input = input, - enroll_rate = enroll_rate, - fail_rate = fail_rate, - bounds = bounds |> filter(!is.infinite(z)), - analysis = analysis + ans <- structure( + list( + design = "wlr", + input = input, + enroll_rate = enroll_rate, + fail_rate = fail_rate, + bounds = bounds |> filter(!is.infinite(z)), + analysis = analysis + ), + class = "gs_design", + binding = binding, + uninteger_is_from = "gs_power_wlr" ) - ans <- add_class(ans, if (!binding) "non_binding", "wlr", "gs_design") - attr(ans, 'uninteger_is_from') <- "gs_power_wlr" - return(ans) } diff --git a/R/gs_update_ahr.R b/R/gs_update_ahr.R index 63aea17f..023bc07f 100644 --- a/R/gs_update_ahr.R +++ b/R/gs_update_ahr.R @@ -132,7 +132,7 @@ gs_update_ahr <- function( stop("gs_update_ahr(): please input the original design created either by gs_design_ahr or gs_power_ahr.") } - if (!any((c("ahr", "wlr") %in% class(x)))) { + if (!x$design %in% c("ahr", "wlr")) { stop("gs_update_ahr(): the original design must be created either by gs_design_ahr, gs_power_ahr, gs_design_wlr, or gs_power_wlr.") } @@ -303,6 +303,8 @@ gs_update_ahr <- function( # ----------------------------------- # ans <- list() + ans$design <- x$design + ans$enroll_rate <- x$enroll_rate ans$fail_rate <- x$fail_rate @@ -359,7 +361,10 @@ gs_update_ahr <- function( } ) - class(ans) <- c(class(x), "updated_design") + class(ans) <- "gs_design" + attr(ans, "binding") <- attr(x, "binding") + attr(ans, "uninteger_is_from") <- attr(x, "uninteger_is_from") + attr(ans, "updated_design") <- TRUE return(ans) } diff --git a/R/summary.R b/R/summary.R index 433bc564..f6ebe77e 100644 --- a/R/summary.R +++ b/R/summary.R @@ -77,29 +77,16 @@ #' ) |> summary() #' summary.fixed_design <- function(object, ...) { - x <- object - p <- x$design_par - ans <- x$analysis - ans$design <- switch( - x$design, - ahr = "Average hazard ratio", - lf = "Lachin and Foulkes", - rd = "Risk difference", - milestone = paste0("Milestone: tau = ", p$tau), - rmst = paste0("RMST: tau = ", p$tau), - mb = paste0("Modestly weighted LR: tau = ", p$tau), - fh = paste0( - "Fleming-Harrington FH(", p$rho, ", ", p$gamma, ")", - if (p$rho == 0 && p$gamma == 0) " (logrank)" - ), - maxcombo = gsub("FH(0, 0)", "logrank", paste( - "MaxCombo:", paste0("FHC(", p[[1]], ", ", p[[2]], ")", collapse = ", ") - ), fixed = TRUE) - ) + ans <- object$analysis + ans$design <- attr(object, "design_display") # capitalize names ans <- cap_names(ans) - ans <- add_class(ans, "fixed_design", x$design) + # Propagate attributes for as_gt()/as_rtf() tables + attr(ans, "title") <- attr(object, "title") + attr(ans, "footnote") <- attr(object, "footnote") + + ans <- add_class(ans, "fixed_design_summary") return(ans) } @@ -273,7 +260,7 @@ summary.gs_design <- function(object, x <- object x_bound <- x$bound x_analysis <- x$analysis - method <- get_method(x, c("ahr", "wlr", "combo", "rd")) + method <- x$design # Prepare the analysis summary row ---- # get the @@ -351,9 +338,9 @@ summary.gs_design <- function(object, # Set the decimals to display ---- for (j in col_vars) output[[j]] <- round2(output[[j]], col_decimals[j]) - output <- add_class( - output, method, intersect("non_binding", class(object)), method, "gs_design" - ) + output <- add_class(output, "gs_design_summary") + attr(output, "binding") <- attr(x, "binding") + attr(output, "design") <- x$design # Save the full alpha as an attribute of the output summary table # Use input$alpha when given power to calculate sample size diff --git a/R/to_integer.R b/R/to_integer.R index fdb06b90..8d19467b 100644 --- a/R/to_integer.R +++ b/R/to_integer.R @@ -178,12 +178,16 @@ to_integer.fixed_design <- function(x, round_up_final = TRUE, ratio = x$input$ra power = (x_new$bound |> filter(bound == "upper"))$probability ) - ans <- list( - input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, - analysis = analysis, design = "ahr" + ans <- structure( + list( + input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, + analysis = analysis, design = "ahr" + ), + class = "fixed_design", + design_display = attr(x, "design_display"), + title = attr(x, "title"), + footnote = attr(x, "footnote") ) - - ans <- add_class(ans, "fixed_design") } else if ((x$design == "fh") && (input_n != output_n)) { x_new <- gs_power_wlr( enroll_rate = enroll_rate_new, @@ -207,12 +211,16 @@ to_integer.fixed_design <- function(x, round_up_final = TRUE, ratio = x$input$ra power = (x_new$bound |> filter(bound == "upper"))$probability ) - ans <- list( - input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, - analysis = analysis, design = "fh", design_par = x$design_par + ans <- structure( + list( + input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, + analysis = analysis, design = "fh", design_par = x$design_par + ), + class = "fixed_design", + design_display = attr(x, "design_display"), + title = attr(x, "title"), + footnote = attr(x, "footnote") ) - - ans <- add_class(ans, "fixed_design") } else if ((x$design == "mb") && (input_n != output_n)) { x_new <- gs_power_wlr( enroll_rate = enroll_rate_new, @@ -236,12 +244,16 @@ to_integer.fixed_design <- function(x, round_up_final = TRUE, ratio = x$input$ra power = (x_new$bound |> filter(bound == "upper"))$probability ) - ans <- list( - input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, - analysis = analysis, design = "mb", design_par = x$design_par + ans <- structure( + list( + input = x$input, enroll_rate = x_new$enroll_rate, fail_rate = x_new$fail_rate, + analysis = analysis, design = "mb", design_par = x$design_par + ), + class = "fixed_design", + design_display = attr(x, "design_display"), + title = attr(x, "title"), + footnote = attr(x, "footnote") ) - - ans <- add_class(ans, "fixed_design") } else { message("The input object is not applicable to get an integer sample size.") ans <- x @@ -320,9 +332,9 @@ to_integer.fixed_design <- function(x, round_up_final = TRUE, ratio = x$input$ra #' gsDesign::sfLDOF(alpha = 0.025, t = 18 / 30)$spend #' } to_integer.gs_design <- function(x, round_up_final = TRUE, ratio = x$input$ratio, ...) { - is_ahr <- inherits(x, "ahr") - is_wlr <- inherits(x, "wlr") - is_rd <- inherits(x, "rd") + is_ahr <- x$design == "ahr" + is_wlr <- x$design == "wlr" + is_rd <- x$design == "rd" if (!(is_ahr || is_wlr || is_rd)) { message("The input object is not applicable to get an integer sample size.") return(x) diff --git a/R/utils.R b/R/utils.R index db748f61..f8991b56 100644 --- a/R/utils.R +++ b/R/utils.R @@ -103,3 +103,6 @@ prune_hash <- function(h, size = 2^23) { n <- object.size(h) } } + +# Require exact matching by default when retrieving attributes +attr = function(...) base::attr(..., exact = TRUE) diff --git a/_pkgdown.yml b/_pkgdown.yml index c185ce9a..59f7f563 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -92,11 +92,11 @@ reference: - summary.gs_design - text_summary - as_gt - - as_gt.fixed_design - - as_gt.gs_design + - as_gt.fixed_design_summary + - as_gt.gs_design_summary - as_rtf - - as_rtf.fixed_design - - as_rtf.gs_design + - as_rtf.fixed_design_summary + - as_rtf.gs_design_summary - gs_bound_summary - to_integer - to_integer.fixed_design diff --git a/man/as_gt.Rd b/man/as_gt.Rd index c60c9070..4912d73d 100644 --- a/man/as_gt.Rd +++ b/man/as_gt.Rd @@ -2,15 +2,15 @@ % Please edit documentation in R/as_gt.R \name{as_gt} \alias{as_gt} -\alias{as_gt.fixed_design} -\alias{as_gt.gs_design} +\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}(x, title = NULL, footnote = NULL, ...) +\method{as_gt}{fixed_design_summary}(x, title = NULL, footnote = NULL, ...) -\method{as_gt}{gs_design}( +\method{as_gt}{gs_design_summary}( x, title = NULL, subtitle = NULL, diff --git a/man/as_rtf.Rd b/man/as_rtf.Rd index cba82a1e..b66ef174 100644 --- a/man/as_rtf.Rd +++ b/man/as_rtf.Rd @@ -2,13 +2,13 @@ % Please edit documentation in R/as_rtf.R \name{as_rtf} \alias{as_rtf} -\alias{as_rtf.fixed_design} -\alias{as_rtf.gs_design} +\alias{as_rtf.fixed_design_summary} +\alias{as_rtf.gs_design_summary} \title{Write summary table of a fixed or group sequential design object to an RTF file} \usage{ as_rtf(x, ...) -\method{as_rtf}{fixed_design}( +\method{as_rtf}{fixed_design_summary}( x, title = NULL, footnote = NULL, @@ -19,7 +19,7 @@ as_rtf(x, ...) ... ) -\method{as_rtf}{gs_design}( +\method{as_rtf}{gs_design_summary}( x, title = NULL, subtitle = NULL, diff --git a/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_footnote.rtf b/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_footnote.rtf index 3994c76b..08d3539e 100644 --- a/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_footnote.rtf +++ b/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_footnote.rtf @@ -58,7 +58,7 @@ \intbl\row\pard \trowd\trgaph108\trleft0\trqc \clbrdrl\brdrs\brdrw15\clbrdrt\brdrw15\clbrdrr\brdrs\brdrw15\clbrdrb\brdrdb\brdrw15\clvertalt\cellx9000 -\pard\hyphpar0\sb15\sa15\fi0\li0\ri0\ql\fs18{\f0 Power computed with average hazard ratio method given the sample size}\cell +\pard\hyphpar0\sb15\sa15\fi0\li0\ri0\ql\fs18{\f0 {\super a} Power computed with average hazard ratio method given the sample size}\cell \intbl\row\pard diff --git a/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_title.rtf b/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_title.rtf index 49301765..4f75ba97 100644 --- a/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_title.rtf +++ b/tests/testthat/_snaps/independent_as_rtf/fixed_design_ahr_title.rtf @@ -17,7 +17,7 @@ \margl1800\margr1440\margt2520\margb1800\headery2520\footery1449 -{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Fixed design under non-proportional hazards}\par} +{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Fixed design under non-proportional hazards {\super a}}\par} \trowd\trgaph108\trleft0\trqc diff --git a/tests/testthat/test-developer-as_gt.R b/tests/testthat/test-developer-as_gt.R new file mode 100644 index 00000000..cd0b4b2b --- /dev/null +++ b/tests/testthat/test-developer-as_gt.R @@ -0,0 +1,22 @@ +test_that("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) + expect_equal(nrow(z1$`_footnotes`), 1) + z2 <- as_gt(y, footnote = FALSE) + expect_equal(nrow(z2$`_footnotes`), 0) + + # gs design + x <- gs_design_ahr() + y <- summary(x) + z1 <- as_gt(y) + expect_equal(nrow(z1$`_footnotes`), 2) + z2 <- as_gt(y, footnote = FALSE) + expect_equal(nrow(z2$`_footnotes`), 0) + +})