This function adds a forest plot column to a gtsummary table, typically produced by tbl_roche_subgroups(). The forest plot visualizes estimates and confidence intervals for each subgroup in the table. The function supports rendering with either the gt or flextable engines, making it suitable for different outputs.

add_forest(
  x,
  estimate = starts_with("estimate"),
  conf_low = starts_with("conf.low"),
  conf_high = starts_with("conf.high"),
  pvalue = starts_with("p.value"),
  after = starts_with("p.value"),
  header_spaces = 20,
  table_engine = c("flextable", "gt")
)

Arguments

x

(gtsummary)
A gtsummary table with estimates and confidence intervals in the table body. Usually produced by tbl_roche_subgroups().

estimate

(tidy-select)
Estimate column name.

conf_low

(tidy-select)
Confidence interval lower bound column name.

conf_high

(tidy-select)
Confidence interval upper bound column name.

pvalue

(tidy-select, optional)
P-value column name. Point sizes in the forest plot will be scaled according to p-value (smaller p-values = smaller points). NULL to turn this off.

after

(tidy-select)
Column name after which the forest plot column will be added. Default is after the p-value column.

header_spaces

(integer)
Spaces to add to the forest plot header to visually separate the two treatment areas (trt A\n Better and trt B\nBetter). It is suggested to modify manually this variable if the treatment names are long, with add_forest(..., header_spaces = 5) or flextable::set_header_labels(ggplot = "*").

table_engine

(character)
Table rendering engine to use. Default is "flextable".

Value

a gt table or flextable object with an added forest plot column.

Details

Both gt and flextable outputs could produce issues in line continuity between rows if there are wrapping in the statistical cells.

Examples

# Simple example ------------------------------------------------------------
trial |>
  select(age, marker, grade, response) |>
  tbl_uvregression(
    y = response,
    method = glm,
    method.args = list(family = binomial),
    exponentiate = TRUE,
    hide_n = TRUE
  ) |>
  modify_column_merge(
    pattern = "{estimate} (95% CI {ci}; {p.value})",
    rows = !is.na(estimate)
  ) |>
  modify_header(estimate = "**Odds Ratio**") |>
  add_forest(table_engine = "gt")
#> Warning: Less than 2 spanning headers detected. The forest plot column will have an
#> empty header.
Characteristic Odds Ratio 95% CI
Age 1.02 (95% CI 1.00, 1.04; 0.10) 1.00, 1.04
Marker Level (ng/mL) 1.35 (95% CI 0.94, 1.93; 0.10) 0.94, 1.93
Grade

    I
    II 0.95 (95% CI 0.45, 2.00; 0.9) 0.45, 2.00
    III 1.10 (95% CI 0.52, 2.29; 0.8) 0.52, 2.29



Abbreviations: CI = Confidence Interval, OR = Odds Ratio
# Realistic example --------------------------------------------------------- trial |> tbl_roche_subgroups( rsp = "response", by = "trt", subgroups = c("grade"), ~ glm(response ~ trt, data = .x) |> gtsummary::tbl_regression( show_single_row = trt, exponentiate = TRUE # , tidy_fun = broom.helpers::tidy_parameters ) ) |> add_forest(pvalue = starts_with("p.value"), table_engine = "flextable") |> flextable::set_header_labels(ggplot = "---------")

Drug A

Drug B

Baseline Risk Factors

Total n

n Response (%)

n Response (%)

estimate

95% CI

p-value

---------

All Participants

193

95 (29.5 %)

98 (33.7 %)

1.04

0.91, 1.19

0.5

Grade

I

67

35 (22.9 %)

32 (40.6 %)

1.19

0.96, 1.49

0.12

II

63

30 (23.3 %)

33 (36.4 %)

1.14

0.91, 1.43

0.3

III

63

30 (43.3 %)

33 (24.2 %)

0.83

0.66, 1.04

0.11