Two functions produce publication-ready figures and tables with minimal post-processing:
| Function | Output | Typical use |
|---|---|---|
plot_forest() |
Forest plot (PNG / PDF / JPG / TIFF) | Regression results from assoc_*() |
plot_tableone() |
Table 1 (DOCX / HTML / PDF / PNG) | Baseline characteristics |
When save = TRUE, both functions write all supported
formats in a single call and return the plot/table object invisibly for
further customisation.
plot_forest() — Forest Plotplot_forest() takes a data frame whose first
column is the row label, plus any additional display columns.
The CI graphic and formatted OR (95% CI) text column are
inserted automatically.
library(ukbflow)
df <- data.frame(
item = c("Exposure vs. control", "Unadjusted", "Fully adjusted"),
`Cases/N` = c("", "89 / 4 521", "89 / 4 521"),
p_value = c(NA_real_, 0.001, 0.006),
check.names = FALSE
)
p <- plot_forest(
data = df,
est = c(NA, 1.52, 1.43),
lower = c(NA, 1.18, 1.11),
upper = c(NA, 1.96, 1.85),
ci_column = 3L,
indent = c(0L, 1L, 1L),
p_cols = "p_value",
xlim = c(0.5, 3.0)
)
plot(p)assoc_*()
resultsThe output of assoc_coxph() (and siblings) can be
reshaped directly into the format expected by
plot_forest():
dt <- ops_toy(scenario = "association")
dt <- dt[dm_timing != 1L]
res <- assoc_coxph(
data = dt,
outcome_col = "dm_status",
time_col = "dm_followup_years",
exposure_col = "p20116_i0",
covariates = c("bmi_cat", "tdi_cat", "p1558_i0")
)
res <- as.data.frame(res)
# Reshape: one row per model, label column first
df2 <- data.frame(
item = c("Smoking status", as.character(res$model)),
`N` = c("", paste0(res$n, " / ", res$n_events)),
p_value = c(NA_real_, res$p_value),
check.names = FALSE
)
p <- plot_forest(
data = df2,
est = c(NA, res$HR),
lower = c(NA, res$CI_lower),
upper = c(NA, res$CI_upper),
ci_column = 3L,
indent = c(0L, rep(1L, nrow(res))),
p_cols = "p_value",
xlim = c(0.5, 2.5)
)
plot(p)CI appearance
# uses df, est, lower, upper from the minimal example above
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
ci_col = c("grey50", "steelblue", "steelblue"), # per-row colours
ci_sizes = 0.5, # point size
ci_Theight = 0.15, # cap height
ref_line = 1, # reference line (use 0 for beta coefficients)
xlim = c(0.2, 5), ticks_at = c(0.5, 1, 2, 3)
)Row labels and indentation
# indent = 0 → bold parent row; indent >= 1 → indented sub-row (plain)
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
indent = c(0L, 1L, 1L), # parent + 2 sub-rows
bold_label = c(TRUE, FALSE, FALSE) # explicit control (overrides indent default)
)P-value formatting
# p_cols: column names in data that contain raw numeric p-values.
# Values < 10^(-p_digits) are displayed as e.g. "<0.001".
# bold_p = TRUE bolds all p < p_threshold (default 0.05).
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
p_cols = "p_value",
p_digits = 3L,
bold_p = TRUE,
p_threshold = 0.05
)Column headers and alignment
header renames all columns in the final
rendered table. The final table always has ncol(data) + 2
columns: the original columns, plus the gap_ci graphic
column and the auto-generated OR (95% CI) text column. Pass
"" for the gap column position.
# data has 3 columns → final table has 5 columns (original 3 + gap_ci + OR label)
# Layout with ci_column = 3L: item | Cases/N | gap_ci | OR (95% CI) | p_value
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
header = c("Comparison", "Cases / N", "", "HR (95% CI)", "P-value")
# col 1 col 2 gap OR label col 5
)align controls per-column text alignment across all
ncol(data) + 2 columns: -1 = left,
0 = centre, 1 = right. NULL
(default) left-aligns column 1 and centres the rest.
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
align = c(-1L, 0L, 0L, 0L, 1L) # label left | Cases/N centre | gap | OR centre | p right
)Background and borders
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
background = "zebra", # "zebra" | "bold_label" | "none"
bg_col = "#F0F0F0", # shading colour
border = "three_line", # "three_line" | "none"
border_width = 3 # scalar or length-3 vector (top / mid / bottom)
)Layout and saving
# uses df, est, lower, upper from the minimal example above
p <- plot_forest(
data = df,
est = est, lower = lower, upper = upper,
ci_column = 3L,
row_height = NULL, # auto (8 / 12 / 10 / 15 mm); or scalar/vector
col_width = NULL, # auto (rounds up to nearest 5 mm)
save = TRUE,
dest = "forest_main", # extension ignored; all 4 formats saved
save_width = 20, # cm
save_height = NULL # auto: nrow(data) * 0.9 + 3 cm
)All four formats (PNG, PDF, JPG, TIFF) are written at 300 dpi with a white background. The function returns the plot object invisibly; display with
plot(p)orgrid::grid.draw(p).
plot_tableone() — Baseline Characteristics TableVariable types and statistics
dt <- as.data.frame(ops_toy(scenario = "association"))
plot_tableone(
data = dt,
vars = c("p21022", "p21001_i0", "p31", "p20116_i0"),
strata = "dm_status",
type = list(p21022 = "continuous2"), # show median + IQR
statistic = list(
all_continuous() ~ "{mean} ({sd})",
all_categorical() ~ "{n} ({p}%)"
),
digits = list(p21022 ~ 1, p21001_i0 ~ 1),
missing = "ifany", # show missing counts when present
save = FALSE
)SMD column
The SMD column summarises covariate balance between groups: - Continuous variables: Cohen’s d (pooled-SD formula) - Categorical variables: RMSD of group proportions
plot_tableone(
data = dt,
vars = c("p21022", "p21001_i0", "p31"),
strata = "dm_status",
add_smd = TRUE,
save = FALSE
)Excluding rows
Use exclude_labels to remove specific level rows from
the rendered table (e.g. a redundant reference category or an “Unknown”
level):
plot_tableone(
data = dt,
vars = c("p31", "p20116_i0"),
strata = "dm_status",
exclude_labels = "Never", # e.g. remove reference category from display
save = FALSE
)Export formats
When save = TRUE, four files are written
simultaneously:
| Format | Tool | Notes |
|---|---|---|
.docx |
gt::gtsave() |
Ready for Word submission |
.html |
gt::gtsave() |
Interactive preview |
.pdf |
pagedown::chrome_print() |
Requires Chrome / Chromium |
.png |
webshot2::webshot() |
2x zoom, table element only |
PDF and PNG rendering requires
pagedownandwebshot2respectively. Install withinstall.packages(c("pagedown", "webshot2")).
?plot_forest, ?plot_tableonevignette("assoc") — association analysis producing
forest plot inputs