Appendix A — Working with gsDesign objects

The gsDesign package uses the S3 object system. An S3 object is an R object, often a list or data frame, with a class attribute. Generic functions such as print(), summary(), and plot() inspect that class and select an appropriate method. This allows related design objects to share output and plotting behavior while retaining endpoint-specific information.

A.1 Principal class hierarchy

The class vector is ordered from most specific to most general. For example, a result from gsSurvPower() is also a gsSurv object and a gsDesign object:

design <- gsDesign(k = 2)
survival_design <- gsSurv(k = 2)
power_result <- gsSurvPower(x = survival_design)

tibble(
  Result = c("gsDesign()", "gsSurv()", "gsSurvPower()"),
  `Class vector` = c(
    paste(class(design), collapse = ", "),
    paste(class(survival_design), collapse = ", "),
    paste(class(power_result), collapse = ", ")
  )
) |>
  gt() |>
  tab_header(title = "Class inheritance for common design objects") |>
  tab_options(data_row.padding = px(1))
Class inheritance for common design objects
Result Class vector
gsDesign() gsDesign
gsSurv() gsSurv, gsDesign
gsSurvPower() gsSurvPower, gsSurv, gsDesign

When plot(power_result) is called, R looks first for a method for gsSurvPower, then for gsSurv, and then for gsDesign. The inherited plot.gsDesign() method therefore works without a separate plot.gsSurvPower() method. The same inheritance gives survival power objects the standard gsDesign summary behavior.

Use generic functions rather than calling a method such as plot.gsDesign() directly. Generic dispatch respects the full class vector and remains correct when a more specific method is added.

A.2 Inspecting an object

Three base R functions provide a useful first inspection:

class(power_result)
#> [1] "gsSurvPower" "gsSurv"      "gsDesign"
names(power_result)
#>  [1] "k"                   "test.type"          
#>  [3] "alpha"               "beta"               
#>  [5] "astar"               "delta"              
#>  [7] "n.fix"               "timing"             
#>  [9] "tol"                 "r"                  
#> [11] "n.I"                 "maxn.IPlan"         
#> [13] "nFixSurv"            "nSurv"              
#> [15] "endpoint"            "delta1"             
#> [17] "delta0"              "overrun"            
#> [19] "usTime"              "lsTime"             
#> [21] "testUpper"           "testLower"          
#> [23] "testHarm"            "upper"              
#> [25] "lower"               "theta"              
#> [27] "falseposnb"          "en"                 
#> [29] "T"                   "eDC"                
#> [31] "eDE"                 "eNC"                
#> [33] "eNE"                 "hr"                 
#> [35] "hr0"                 "R"                  
#> [37] "minfup"              "gamma"              
#> [39] "ratio"               "lambdaC"            
#> [41] "etaC"                "etaE"               
#> [43] "variable"            "method"             
#> [45] "call"                "inputs"             
#> [47] "N"                   "hr1"                
#> [49] "sided"               "spending"           
#> [51] "fullSpendingAtFinal" "power"

For a compact view of component types and dimensions, use:

str(power_result, max.level = 1)

Frequently used components of a gsDesign-style object include:

  • n.I: statistical information or expected events at each analysis;
  • timing: information fractions;
  • upper and lower: bounds, crossing probabilities, and spending;
  • theta: standardized effect sizes used for probability calculations.

Survival objects add enrollment, failure, dropout, hazard-ratio, and calendar timing assumptions. A gsSurvPower result also provides power, T, and the scenario inputs retained by the calculation. For example:

tibble(
  Quantity = c("Overall power", "Analysis times", "Expected events"),
  Value = c(
    format(round(power_result$power, 3)),
    paste(round(power_result$T, 1), collapse = ", "),
    paste(round(power_result$n.I, 1), collapse = ", ")
  )
) |>
  gt() |>
  tab_header(title = "Selected gsSurvPower result components") |>
  tab_options(data_row.padding = px(1))
Selected gsSurvPower result components
Quantity Value
Overall power 0.9
Analysis times 10.7, 18
Expected events 83.7, 167.4

The help page for the function that creates an object is the authoritative description of its components. Component names are useful for calculations and custom tables, but modifying components or changing class() manually can create an internally inconsistent object.

A.3 Output and conversion methods

The following calls illustrate the preferred interfaces:

print(design)
summary(design)
plot(design)
gsBoundSummary(design)

print() is intended for immediate console inspection. summary() provides a short narrative description, while plot() returns the graphical summaries documented for the class. gsBoundSummary() creates a data-frame-like boundary summary suitable for further table formatting. The package also registers methods for exact binomial designs, conditional-power sample size re-estimation, spending functions, RTF conversion, and xtable output.

The registered S3 methods in the installed package can be listed directly. This table reports explicit registrations; methods inherited from a later class in an object’s class vector are not repeated.

registered_methods <- getNamespaceInfo(asNamespace("gsDesign"), "S3methods")

s3_method_table <- tibble(
  Generic = registered_methods[, 1],
  Class = registered_methods[, 2],
  Method = registered_methods[, 3]
)

s3_method_table[order(s3_method_table$Class, s3_method_table$Generic), ] |>
  gt() |>
  tab_header(title = "Registered S3 methods in gsDesign") |>
  tab_options(data_row.padding = px(1))
Registered S3 methods in gsDesign
Generic Class Method
plot binomialSPRT plot.binomialSPRT
print eEvents print.eEvents
as_table gsBinomialExact as_table.gsBinomialExact
plot gsBinomialExact plot.gsBinomialExact
as_gt gsBinomialExactTable as_gt.gsBinomialExactTable
as_rtf gsBinomialExactTable as_rtf.gsBinomialExactTable
as_rtf gsBoundSummary as_rtf.gsBoundSummary
print gsBoundSummary print.gsBoundSummary
plot gsDesign plot.gsDesign
print gsDesign print.gsDesign
summary gsDesign summary.gsDesign
xtable gsDesign xtable.gsDesign
plot gsProbability plot.gsProbability
print gsProbability print.gsProbability
print gsSurv print.gsSurv
xtable gsSurv xtable.gsSurv
print nSurv print.nSurv
print nSurvival print.nSurvival
summary spendfn summary.spendfn
plot ssrCP plot.ssrCP

To determine which implementation R selects for a particular class, use getS3method():

summary_method <- getS3method("summary", "gsDesign")
environmentName(environment(summary_method))
#> [1] "gsDesign"

Printing the function is mainly useful for package development. In routine analysis, call summary(object) and let R perform dispatch.

A.4 Practical workflow

When working with a new result object:

  1. Check class() to identify its inheritance chain.
  2. Use print(), summary(), plot(), or a package conversion generic before constructing custom output.
  3. Use names() and the function help page to locate documented components.
  4. Preserve the original object and derive separate tables or vectors rather than altering its class or nested design components.
  5. Record the package version when output depends on development features.

This workflow is especially useful for gsSurvPower() results: they retain the familiar gsDesign structure while adding the assumptions and expected operating characteristics needed for scenario analysis. See Section 5.4 for the corresponding statistical workflow.