Create a gtsummary table with Kaplan-Meier estimated survival quantiles. If you must further customize the way these results are presented, see the Details section below for the full details.

tbl_survfit_quantiles(
  data,
  y = "survival::Surv(time = AVAL, event = 1 - CNSR, type = 'right', origin = 0)",
  by = NULL,
  header = "Time to event",
  estimate_fun = label_style_number(digits = 1, na = "NE"),
  method.args = list(conf.int = 0.95)
)

# S3 method for class 'tbl_survfit_quantiles'
add_overall(
  x,
  last = FALSE,
  col_label = "All Participants  \nN = {gtsummary::style_number(N)}",
  ...
)

Arguments

data

(data.frame)
A data frame

y

(string or expression)
A string or expression with the survival outcome, e.g. survival::Surv(time, status). The default value is survival::Surv(time = AVAL, event = 1 - CNSR, type = "right", origin = 0).

by

(tidy-select)
A single column from data. Summary statistics will be stratified by this variable. Default is NULL, which returns results for the unstratified model.

header

(string)
String for the header of the survival quantile chunks. Default is "Time to event".

estimate_fun

(function)
Function used to round and format the estimates in the table. Default is label_style_number(digits = 1).

method.args

(named list)
Named list of arguments that will be passed to survival::survfit().

Note that this list may contain non-standard evaluation components, and must be handled similarly to tidyselect inputs by using rlang's embrace operator {{ . }} or !!enquo() when programming with this function.

x

(tbl_survfit_quantiles)
A stratified 'tbl_survfit_quantiles' object.

last

(scalar logical)
Logical indicator to display overall column last in table. Default is FALSE, which will display overall column first.

col_label

(string)
String indicating the column label. Default is "**Overall** \nN = {style_number(N)}"

...

These dots are for future extensions and must be empty.

Value

a gtsummary table

ARD-first

This function is a helper for creating a common summary. But if you need to modify the appearance of this table, you may need to build it from ARDs.

Here's the general outline for creating this table directly from ARDs.

  1. Create an ARD of survival quantiles using cardx::ard_survival_survfit().

  2. Construct an ARD of the minimum and maximum survival times using cards::ard_summary().

  3. Combine the ARDs and build summary table with gtsummary::tbl_ard_summary().

# get the survival quantiles with 95% CI
ard_surv_quantiles <-
  cardx::ard_survival_survfit(
    x = cards::ADTTE,
    y = survival::Surv(time = AVAL, event = 1 - CNSR, type = 'right', origin = 0),
    variables = "TRTA",
    probs = c(0.25, 0.50, 0.75)
  ) |>
  # modify the shape of the ARD to look like a
  # 'continuous' result to feed into `tbl_ard_summary()`
  dplyr::mutate(
    stat_name = paste0(.data$stat_name, 100 * unlist(.data$variable_level)),
    variable_level = list(NULL)
  )

# get the min/max followup time
ard_surv_min_max <-
  cards::ard_summary(
    data = cards::ADTTE,
    variables = AVAL,
    by = "TRTA",
    statistic = everything() ~ cards::continuous_summary_fns(c("min", "max"))
  )

# stack the ARDs and pass them to `tbl_ard_summary()`
cards::bind_ard(
  ard_surv_quantiles,
  ard_surv_min_max
) |>
  tbl_ard_summary(
    by = "TRTA",
    type = list(prob = "continuous2", AVAL = "continuous"),
    statistic = list(
      prob = c("{estimate50}", "({conf.low50}, {conf.high50})", "{estimate25}, {estimate75}"),
      AVAL = "{min} to {max}"
    ),
    label = list(
      prob = "Time to event",
      AVAL = "Range"
    )
  ) |>
  # directly modify the labels in the table to match spec
  modify_table_body(
    ~ .x |>
      dplyr::mutate(
        label = dplyr::case_when(
          .data$label == "Survival Probability" ~ "Median",
          .data$label == "(CI Lower Bound, CI Upper Bound)" ~ "95% CI",
          .data$label == "Survival Probability, Survival Probability" ~ "25% and 75%-ile",
          .default = .data$label
        )
      )
  ) |>
  # update indentation to match spec
  modify_indent(columns = "label", rows = label == "95% CI", indent = 8L) |>
  modify_indent(columns = "label", rows = .data$label == "Range", indent = 4L) |>
  # remove default footnotes
  remove_footnote_header(columns = all_stat_cols())

Examples

# Example 1 ----------------------------------
tbl_survfit_quantiles(
  data = cards::ADTTE,
  by = "TRTA",
  estimate_fun = label_style_number(digits = 1, na = "NE")
) |>
  add_overall(last = TRUE, col_label = "**All Participants**  \nN = {n}")
Placebo
(N = 86)
Xanomeline High Dose
(N = 84)
Xanomeline Low Dose
(N = 84)
All Participants
N = 254
Time to event



    Median NE 36.0 33.0 51.0
        95% CI (NE, NE) (25.0, 47.0) (28.0, 51.0) (44.0, 70.0)
    25% and 75%-ile 70.0, NE 14.0, 58.0 19.0, 80.0 22.0, NE
    Range 1.0 to 198.0 1.0 to 189.0 1.0 to 190.0 1.0 to 198.0
# Example 2: unstratified analysis ----------- tbl_survfit_quantiles(data = cards::ADTTE)
Overall
(N = 254)
Time to event
    Median 51.0
        95% CI (44.0, 70.0)
    25% and 75%-ile 22.0, NE
    Range 1.0 to 198.0