The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

plot_or: Forest plots for logistic regression

library(plotor)
set.seed(123) # reproducibility

Overview

plot_or() creates publication-ready forest plots from logistic regression models fitted with stats::glm(family = "binomial"). It visualises odds ratios with confidence intervals, making it easy to communicate effect sizes, precision and statistical significance at a glance.

When to use this function

Use plot_or() when you need to:

Note: plot_or() works only with glm(family = "binomial"). It does not support logistic regression via other packages (e.g., glm2, logistf) or ordinal / multinomial logistic regression.

Quick example - minimal workflow

# create a small example dataset
rows <- 400
df <- data.frame(
  outcome = rbinom(n = rows, size = 1, prob = 0.25) |> 
    factor(labels = c("Healthy", "Disease")),
  age = rnorm(n = rows, mean = 50, sd = 12),
  sex = sample(x = 0:1, size = rows, replace = TRUE) |> 
    factor(labels = c("Female", "Male")),
  smoke = sample(x = 0:2, size = rows, replace = TRUE) |> 
    factor(labels = c("Never", "Former", "Current"))
)

# fit a logistic regression model
m <- glm(
  formula = outcome ~ age + sex + smoke,
  family = "binomial",
  data = df
)

# create the forest plot
plot_or(m)

Output

The resulting plot displays:

Interpreting effect sizes

Interpreting confidence intervals

# ensure reproducibility
set.seed(123)

# create a small example dataset
rows <- 400
df <- data.frame(
  narrow_interval = rnorm(n = rows, sd = 10),
  wide_interval = rnorm(n = rows, sd = 1),
  interval_crosses_1 = rnorm(n = rows, sd = 3),
  interval_doesnt_cross_1 = rnorm(n = rows, sd = 3)
)

# create outcome based on predictors to achieve desired associations:
# narrow_interval: strong association (narrow CI)
# wide_interval: weak association (wide CI)
# interval_crosses_1: very weak association (CI crosses 1)
# interval_doesnt_cross_1: moderate association (CI doesn't cross 1)
df$outcome <- 
  rbinom(
    n = rows,
    size = 1,
    prob = plogis(
      0 + # intercept
      2 * scale(df$narrow_interval)[, 1] + 
      0.1 * scale(df$wide_interval)[, 1] + 
      0.01 * scale(df$interval_crosses_1)[, 1] + 
      -0.3 * scale(df$interval_doesnt_cross_1)[, 1]
    )
  ) |> factor(labels = c("Healthy", "Disease"))

# fit a logistic regression model
m <- glm(
  formula = outcome ~ narrow_interval + wide_interval + 
    interval_crosses_1 + interval_doesnt_cross_1,
  family = "binomial",
  data = df
)

# create the forest plot (skip checks on logistic regression assumptions)
plotor::plot_or(m, assumption_checks = FALSE)

Exporting plots

Use the ggplot2::ggsave() function to export your forest plot to a file for further use.

Save as PNG (raster)

p <- plot_or(m)
ggplot2::ggsave(
  filename = "forest_plot.png",
  plot = p,
  width = 10,
  height = 6,
  dpi = 300
)

Use PNG for:

Save as PDF (vector)

p <- plot_or(m)
ggplot2::ggsave(
  filename = "forest_plot.pdf",
  plot = p,
  width = 10,
  height = 6
)

Use PDF for:

Tips for publication-ready plots

Choose appropriate dimensions

Adjust width and height in ggsave() accordingly.

Label predictors clearly

Ensure predictor and factor level names are:

Notes and limitations

Conclusion

plot_or() transforms logistic regression results into intuitive, publication-ready forecast plots. By visualising odds ratios, confidence intervals and statistical significance together, it helps readers quickly grasp effect sizes and precision - making it an essential tool for communicating statistical findings effectively.

See also

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.