Regression tables are the evidence. Plots are the quick read. Use
km_plot(), km_risk_table(),
rmst_table(), survival_summary(),
survival_quantiles(), survival_prob(),
logrank_test(), surv_model_compare(),
plot_surv_fit(), surv_predict(),
plot_reg(), plot_reg_combine(),
forest_df(), and forest_reg() to visualise
survival and regression results, inspect reference categories, and
prepare figures for manuscripts or reports.
library(gtregression)
library(dplyr)
data("data_birthwt", package = "gtregression")
data("data_lungcancer", package = "gtregression")
birthwt_data <- data_birthwt |>
mutate(
race = factor(race, levels = c(1, 2, 3),
labels = c("White", "Black", "Other")),
smoke = factor(smoke, levels = c(0, 1), labels = c("No", "Yes")),
ht = factor(ht, levels = c(0, 1), labels = c("No", "Yes")),
ui = factor(ui, levels = c(0, 1), labels = c("No", "Yes")),
low = factor(low, levels = c(0, 1), labels = c("Normal BW", "Low BW")),
ptl_cat = factor(ifelse(ptl > 0, "Yes", "No"), levels = c("No", "Yes")),
ftv_cat = factor(case_when(
ftv == 0 ~ "None",
ftv == 1 ~ "One",
ftv >= 2 ~ "Two or more"
), levels = c("None", "One", "Two or more"))
)
birthwt_exposures <- c(
"age", "lwt", "race", "smoke", "ht", "ui", "ptl_cat", "ftv_cat"
)
attr(birthwt_data$age, "label") <- "Maternal age"
attr(birthwt_data$lwt, "label") <- "Maternal weight"
attr(birthwt_data$race, "label") <- "Maternal race"
attr(birthwt_data$smoke, "label") <- "Smoking during pregnancy"
attr(birthwt_data$ht, "label") <- "Hypertension"
attr(birthwt_data$ui, "label") <- "Uterine irritability"
attr(birthwt_data$ptl_cat, "label") <- "Previous preterm labour"
attr(birthwt_data$ftv_cat, "label") <- "First trimester visits"
birthwt_desc <- descriptive_table(
birthwt_data,
exposures = birthwt_exposures,
by = "low",
show_overall = "last"
)
birthwt_uni <- uni_reg(
birthwt_data,
outcome = "low",
exposures = birthwt_exposures,
approach = "logit"
)
birthwt_multi <- multi_reg(
birthwt_data,
outcome = "low",
exposures = c("smoke", "ht", "ui", "ptl_cat", "ftv_cat"),
adjust_for = c("age", "lwt", "race"),
approach = "logit"
)
lung_data <- data_lungcancer |>
mutate(
trt = factor(trt, levels = c(1, 2),
labels = c("Standard treatment", "Test treatment")),
prior = factor(prior, levels = c(0, 10), labels = c("No", "Yes"))
)
lung_surv <- surv_reg(
data = lung_data,
time = time,
event = status,
exposures = "trt",
adjust_for = c("age", "karno"),
distribution = weibull
)km_plot() gives the survival curve before regression
modelling. Use it to show the observed survival experience by group,
with optional confidence intervals, censoring marks, log-rank p-value,
and number-at-risk table. If the curves sit near the top of the graph,
use ylim = c(50, 100) on the default percentage scale, or
ylim = c(0.5, 1) when y_percent = FALSE.
km_plot(
data = lung_data,
time = time,
event = status,
by = trt,
break_time_by = 200,
ylim = c(50, 100),
title = "Kaplan-Meier Survival by Treatment"
)When preparing a multi-panel figure, use compact titles and control
the legend directly. The result remains a normal ggplot object when
risk_table = FALSE, so it can be combined with
patchwork.
km_treatment <- km_plot(
data = lung_data,
time = time,
event = status,
by = trt,
risk_table = FALSE,
title = "A. Treatment",
title_size = 10,
title_face = plain,
legend_position = bottom,
base_size = 10
)
km_prior <- km_plot(
data = lung_data,
time = time,
event = status,
by = prior,
risk_table = FALSE,
title = "B. Prior therapy",
title_size = 10,
title_face = plain,
legend_position = bottom,
base_size = 10
)
patchwork::wrap_plots(km_treatment, km_prior, ncol = 2) +
patchwork::plot_layout(guides = "collect") &
ggplot2::theme(legend.position = "bottom")km_risk_table() gives the number at risk at selected
follow-up times as a standalone table. This is useful when the risk
table needs to be reported beside or underneath a Kaplan-Meier
curve.
km_risk_table(
data = lung_data,
time = time,
event = status,
by = trt,
times = c(0, 90, 180, 365)
)## a flextable object.
## col_keys: `Group`, `Time`, `At risk`, `Events`, `Censored`
## header has 1 row(s)
## body has 8 row(s)
## original dataset sample:
## 'data.frame': 8 obs. of 5 variables:
## $ Group : chr "Standard treatment" "Standard treatment" "Standard treatment" "Standard treatment" ...
## $ Time : chr "0.0" "90.0" "180.0" "365.0" ...
## $ At risk : chr "69" "37" "13" "4" ...
## $ Events : chr "0" "31" "21" "8" ...
## $ Censored: chr "0" "1" "3" "1" ...
rmst_table() reports the average survival time up to a
fixed follow-up point, called tau. This is useful when
readers want an absolute survival-time summary, or when hazard ratios
are difficult to explain.
## a flextable object.
## col_keys: `Group`, `Tau`, `N`, `Events`, `RMST (95% CI)`, `RMST difference (95% CI)`, `p-value`
## header has 1 row(s)
## body has 3 row(s)
## original dataset sample:
## 'data.frame': 3 obs. of 7 variables:
## $ Group : chr "Standard treatment" "Test treatment" "Difference (Test treatment - Standard treatment)"
## $ Tau : chr "365.0" "365.0" "365.0"
## $ N : chr "69" "68" ""
## $ Events : chr "64" "64" ""
## $ RMST (95% CI) : chr "119.0 (93.5-144.5)" "112.4 (83.3-141.6)" ""
## $ RMST difference (95% CI): chr "" "" "-6.6 (-45.3-32.2)"
## $ p-value : chr "" "" "0.740"
survival_summary() is the table companion to the
Kaplan-Meier curve. It reports the number analysed, events, censored
observations, and median survival with a 95% confidence interval. Use it
when readers need the key survival numbers without reading them from the
plot.
## a flextable object.
## col_keys: `Group`, `N`, `Events`, `Censored`, `Median survival (95% CI)`
## header has 1 row(s)
## body has 2 row(s)
## original dataset sample:
## 'data.frame': 2 obs. of 5 variables:
## $ Group : chr "Standard treatment" "Test treatment"
## $ N : chr "69" "68"
## $ Events : chr "64" "64"
## $ Censored : chr "5" "4"
## $ Median survival (95% CI): chr "103.0 (59.0-132.0)" "52.5 (44.0-95.0)"
survival_quantiles() reports detailed Kaplan-Meier time
points. This is useful when the median alone is not enough, or when you
want to show the 25th, 50th, and 75th percentile event times by
group.
## a flextable object.
## col_keys: `Group`, `Event percentile`, `Survival probability`, `Time (95% CI)`
## header has 1 row(s)
## body has 6 row(s)
## original dataset sample:
## 'data.frame': 6 obs. of 4 variables:
## $ Group : chr "Standard treatment" "Standard treatment" "Standard treatment" "Test treatment" ...
## $ Event percentile : chr "25%" "50%" "75%" "25%" ...
## $ Survival probability: chr "75%" "50%" "25%" "75%" ...
## $ Time (95% CI) : chr "27.0 (16.0-54.0)" "103.0 (59.0-132.0)" "162.0 (139.0-260.0)" "24.5 (19.0-43.0)" ...
survival_prob() reports Kaplan-Meier survival
probability at fixed follow-up times. This is useful for clinically
familiar summaries such as 90-day, 6-month, or 1-year survival.
## a flextable object.
## col_keys: `Group`, `Time`, `At risk`, `Events`, `Censored`, `Survival probability (95% CI)`
## header has 1 row(s)
## body has 6 row(s)
## original dataset sample:
## 'data.frame': 6 obs. of 6 variables:
## $ Group : chr "Standard treatment" "Standard treatment" "Standard treatment" "Test treatment" ...
## $ Time : chr "90.0" "180.0" "365.0" "90.0" ...
## $ At risk : chr "37" "13" "4" "25" ...
## $ Events : chr "31" "21" "8" "42" ...
## $ Censored : chr "1" "3" "1" "2" ...
## $ Survival probability (95% CI): chr "54.7% (44.0%-67.9%)" "21.2% (13.2%-34.1%)" "7.1% (2.8%-18.0%)" "38.0% (28.0%-51.6%)" ...
logrank_test() formally compares Kaplan-Meier curves
between groups. It is useful after the curve and summary table, but it
does not give an effect size; use cox_reg() when a hazard
ratio is needed.
## a flextable object.
## col_keys: `Group`, `N`, `Observed events`, `Expected events`
## header has 1 row(s)
## body has 2 row(s)
## original dataset sample:
## 'data.frame': 2 obs. of 4 variables:
## $ Group : chr "Standard treatment" "Test treatment"
## $ N : chr "69" "68"
## $ Observed events: chr "64" "64"
## $ Expected events: chr "64.50" "63.50"
surv_model_compare() helps users choose a candidate
distribution before using surv_reg(). It fits the same
model with Weibull, exponential, lognormal, and loglogistic
distributions, then compares AIC and BIC.
surv_model_compare(
data = lung_data,
time = time,
event = status,
exposures = c("trt", "celltype"),
adjust_for = c("age", "karno")
)## a flextable object.
## col_keys: `Distribution`, `AIC`, `BIC`, `Log-likelihood`, `Scale`, `N`, `Events`, `Best AIC`, `Best BIC`
## header has 1 row(s)
## body has 4 row(s)
## original dataset sample:
## 'data.frame': 4 obs. of 9 variables:
## $ Distribution : chr "loglogistic" "lognormal" "exponential" "weibull"
## $ AIC : chr "1,440.12" "1,445.61" "1,446.39" "1,447.17"
## $ BIC : chr "1,463.48" "1,468.97" "1,466.83" "1,470.53"
## $ Log-likelihood: chr "-712.06" "-714.80" "-716.19" "-715.59"
## $ Scale : chr "0.58" "1.06" "1.00" "0.93"
## $ N : chr "137" "137" "137" "137"
## $ Events : chr "128" "128" "128" "128"
## $ Best AIC : chr "Yes" "No" "No" "No"
## $ Best BIC : chr "Yes" "No" "No" "No"
plot_surv_fit() is the visual companion to
surv_model_compare(). It overlays the observed Kaplan-Meier
curve with fitted parametric survival curves, so users can check whether
a distribution that looks good by AIC/BIC also follows the observed
survival pattern.
plot_surv_fit(
data = lung_data,
time = time,
event = status,
by = trt,
distributions = c(weibull, lognormal),
break_time_by = 200
)Adjusted fitted curves can also be drawn. In that case, the curves are predicted at typical adjustment values, such as medians for numeric variables and the most common level for categorical variables.
plot_surv_fit(
data = lung_data,
time = time,
event = status,
by = trt,
adjust_for = c(age, karno),
distributions = loglogistic,
xlim = c(0, 800)
)surv_predict() turns a fitted parametric survival model
into predicted survival probabilities at clinically useful follow-up
times. This helps users move from a time-ratio table to a more direct
statement such as predicted 90-day, 180-day, or 1-year survival for a
profile.
surv_predict(
model = lung_surv$models$trt,
newdata = data.frame(
trt = factor("Test treatment", levels = levels(lung_data$trt)),
age = 60,
karno = 70
),
times = c(90, 180, 365)
)## a flextable object.
## col_keys: `Profile`, `trt`, `age`, `karno`, `Time`, `Predicted survival`, `Model distribution`
## header has 1 row(s)
## body has 3 row(s)
## original dataset sample:
## 'data.frame': 3 obs. of 7 variables:
## $ Profile : int 1 1 1
## $ trt : Factor w/ 2 levels "Standard treatment",..: 2 2 2
## $ age : num 60 60 60
## $ karno : num 70 70 70
## $ Time : chr "90.0" "180.0" "365.0"
## $ Predicted survival: chr "55.3%" "31.1%" "9.7%"
## $ Model distribution: chr "weibull" "weibull" "weibull"
If newdata is omitted, surv_predict() uses
a typical profile from the model data, using medians for numeric
variables and the most common level for categorical variables.
plot_reg() turns a uni_reg() or
multi_reg() result into a forest-style plot. By default,
categorical reference levels are shown and labelled as
(Ref.); the caption explains the abbreviation. Variable
labels set on the data are used automatically in the plot.
The default style uses colour-blind-safe blue estimates and
vermillion for estimates whose confidence interval excludes the null.
Use point_size, point_stroke,
ci_linewidth, and base_size when preparing a
slide or a larger single-panel figure.
plot_reg(
birthwt_uni,
show_ref = FALSE,
point_size = 3.5,
point_stroke = 0.7,
ci_linewidth = 0.75,
base_size = 13,
title = "Crude Associations With Low Birth Weight"
)When the input comes from multi_reg(adjust_for = ...),
the adjustment set is shown in the plot caption by default. This keeps
the figure interpretable when it is copied into slides or a manuscript
draft.
plot_reg(
birthwt_multi,
show_ref = FALSE,
log_x = TRUE,
title = "Adjusted Associations With Low Birth Weight"
)For Yes/No, 1/0, true/false, or similar binary predictors, set
show_ref = FALSE to hide reference rows. Affirmative binary
levels such as Yes are displayed as the exposure name
itself, so the plot remains compact: smoke,
ht, ui, and ptl_cat are easier to
read than repeated variable: Yes labels.
For ratio measures such as odds ratios, risk ratios, and incidence
rate ratios, log_x = TRUE uses a log-scaled x-axis. If you
do not provide tick marks, gtregression chooses sensible
defaults around the null value of 1.
You can still take full control of the visible axis range and tick marks.
plot_reg(
birthwt_uni,
show_ref = FALSE,
log_x = TRUE,
xlim = c(0.25, 12),
breaks = c(0.5, 1, 2, 4, 8),
title = "Crude Associations With Custom Axis"
)plot_reg_combine() places crude and adjusted model
results side by side. This is useful when a manuscript needs to show how
adjustment changes the estimate. Axis limits and tick marks can be
controlled separately for each side.
plot_reg_combine(
tbl_uni = birthwt_uni,
tbl_multi = birthwt_multi,
show_ref = FALSE,
log_x = TRUE,
xlim_uni = c(0.25, 12),
breaks_uni = c(0.5, 1, 2, 4, 8),
xlim_multi = c(0.25, 16),
breaks_multi = c(0.5, 1, 2, 4, 8),
title_uni = "Crude Effects",
title_multi = "Adjusted Effects"
)forest_df() prepares the data. forest_reg()
draws the forest table. This is the most manuscript-oriented plot when
you want descriptive summaries and crude or adjusted estimates in the
same figure.
forest_data <- forest_df(
uni = birthwt_uni,
multi = birthwt_multi,
desc = birthwt_desc
)
forest_reg(forest_data)Wide forest tables combine descriptive summaries, crude estimates,
adjusted estimates, and one or two forest plot panels. If the x-axis
labels are crowded, control the axis range and tick marks with
xlim and ticks_at.
Use a list when the table has crude and adjusted forest plot columns.
forest_reg(
forest_data,
xlim = list(c(0.25, 8), c(0.8, 25)),
ticks_at = list(
c(0.5, 1, 2, 4, 8),
c(1, 2, 4, 8, 16)
),
quiet = TRUE
)If the plot panel itself looks too narrow or too wide, tune
ci_col_width. This changes the blank spacer column that
forestploter uses for drawing the confidence intervals.
Larger values give the CI panel more room; smaller values make the
overall table more compact.
forest_reg(
forest_data,
ci_col_width = c(18, 22),
xlim = list(c(0.25, 8), c(0.8, 25)),
ticks_at = list(
c(0.5, 1, 2, 4, 8),
c(1, 2, 4, 8, 16)
)
)For publication export, use a wider graphics device or document canvas when the table includes several descriptive columns and two model columns.
You can also build and draw in one call.
plot_reg() returns a ggplot.plot_reg_combine() returns a combined
ggplot.km_risk_table() reports at-risk, event, and censored
counts at requested follow-up times.rmst_table() reports restricted mean survival time up
to a chosen time point.show_ref = TRUE displays reference levels as
(Ref.).show_ref = FALSE hides reference levels; affirmative
binary predictors are shown as compact bold exposure rows.multi_reg(adjust_for = ...)
are carried into plot captions.log_x = TRUE uses log scaling for non-linear model
effect measures.forest_df() returns the plotting data frame.survival_prob() reports survival probability at
requested follow-up times.surv_model_compare() compares parametric survival
distributions before fitting final surv_reg() tables.plot_surv_fit() overlays fitted parametric survival
curves on the observed Kaplan-Meier curve.surv_predict() reports model-based survival
probabilities at user-specified follow-up times.forest_reg(), use xlim and
ticks_at when x-axis labels overlap.forest_reg(), use ci_col_width when the
CI plot panel is too narrow or too wide.forest_reg() returns plot,
data, input_data, and meta.