lt vs gt — gsDesign2 examples

This document re-runs a few of the as_gt() examples from gsDesign2’s documentation, but builds the tables with lt instead of gt. The first goal of lt is to be a drop-in lightweight replacement for gt in gsDesign2 outputs.

Because lt() is an S3 generic, we define methods for gsDesign2’s summary classes. In practice these methods would live in gsDesign2 (or a bridge package); here they’re defined inline for demonstration.

library(lt)
library(gsDesign2)

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)
)
study_duration = 36
alpha = 0.025
beta = 0.1

lt.fixed_design_summary = function(data, ...) {
  x = lt(as.data.frame(data), ...)
  if (!is.null(attr(data, "title")))
    x = lt_header(x, title = attr(data, "title"))
  if (!is.null(attr(data, "footnote")))
    x = lt_footnote(x, attr(data, "footnote"), "title")
  x
}

lt.gs_design_summary = function(data, ...) {
  x = lt(as.data.frame(data), ...) |>
    lt_group(~ Analysis, sep = TRUE) |>
    lt_spanner(
      label = "Cumulative boundary crossing probability",
      columns = c("Alternate hypothesis", "Null hypothesis")
    ) |>
    lt_format(
      c("Z", "~HR at bound", "Nominal p",
        "Alternate hypothesis", "Null hypothesis"),
      decimals = 4
    )
  x
}

registerS3method("lt", "fixed_design_summary", lt.fixed_design_summary, asNamespace("lt"))
registerS3method("lt", "gs_design_summary", lt.gs_design_summary, asNamespace("lt"))

1 Fixed design — AHR method

Equivalent of fixed_design_ahr() |> summary() |> as_gt().

fixed_design_ahr(
  alpha = alpha, power = 1 - beta,
  enroll_rate = enroll_rate, fail_rate = fail_rate,
  study_duration = study_duration, ratio = 1
) |> summary() |> lt()

2 Fixed design — Fleming-Harrington

Equivalent of fixed_design_fh() |> summary() |> as_gt().

fixed_design_fh(
  alpha = alpha, power = 1 - beta,
  enroll_rate = enroll_rate, fail_rate = fail_rate,
  study_duration = study_duration, ratio = 1
) |> summary() |> lt()

3 Group sequential — gs_power_ahr

Equivalent of gs_power_ahr(lpar = ...) |> summary() |> as_gt(). The long “Analysis: N Time: … AHR: …” label is a natural row-group header. The lt.gs_design_summary method handles grouping, spanner, and formatting automatically.

gs_power_ahr(lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.1)) |>
  summary() |>
  lt() |>
  lt_header(
    title = "Bound summary for AHR design",
    subtitle = "AHR approximations of ~HR at bound"
  ) |>
  lt_footnote(
    "Approximate hazard ratio to cross bound.",
    "column", "~HR at bound"
  ) |>
  lt_footnote(
    "One-sided p-value for experimental vs control treatment.",
    "column", "Nominal p"
  )

4 Group sequential — gs_design_ahr

Equivalent of gs_design_ahr() |> summary() |> as_gt().

gs_design_ahr() |>
  summary() |>
  lt() |>
  lt_header(
    title = "Bound summary for AHR design",
    subtitle = "AHR approximations of ~HR at bound"
  )

5 What’s missing vs as_gt()

With lt() as an S3 generic, gsDesign2 can ship its own lt.gs_design_summary and lt.fixed_design_summary methods (similar to the ones defined above), making summary() |> lt() work out of the box. The mapping from gt to lt is:

gt lt
gt::gt(groupname_col=, rowname_col=) lt_group(~ col) (first column auto-becomes stub)
gt::tab_header(title=, subtitle=) lt_header(title=, subtitle=)
gt::tab_spanner(label=, columns=) lt_spanner(label=, columns=)
gt::tab_footnote(footnote=, locations=cells_*()) lt_footnote(text, where, columns)
gt::tab_source_note(source_note=) lt_note(text)
gt::fmt_number(columns=, decimals=) lt_format(columns, decimals)