| Title: | Publication-Quality Forest and Funnel Plots with 'ggplot2' |
| Version: | 0.1.0 |
| Description: | A 'ggplot2' extension that creates publication-quality forest and funnel plots from 'meta' package objects or tidy data frames. Provides custom 'ggproto' geometries for study-level confidence intervals with weight-proportional squares, summary effect diamonds, prediction intervals, null-effect reference lines, and funnel-plot contours. Supports subgroup analysis, back-transformation of summary measures, on-the-fly effect pooling, effect and weight table columns, and journal-specific layout presets (JAMA, BMJ, RevMan5). |
| License: | GPL (≥ 3) |
| URL: | https://github.com/drhrf/ggmeta, https://drhrf.github.io/ggmeta/ |
| BugReports: | https://github.com/drhrf/ggmeta/issues |
| Depends: | R (≥ 4.0) |
| Imports: | cli (≥ 3.6.0), ggplot2 (≥ 3.4.0), grid, rlang (≥ 1.0.0), scales (≥ 1.2.0) |
| Suggests: | covr (≥ 3.6.0), knitr (≥ 1.40), meta (≥ 4.0), patchwork (≥ 1.1.0), pkgdown (≥ 2.0.0), rmarkdown (≥ 2.20), testthat (≥ 3.0.0), vdiffr (≥ 1.0.0) |
| Encoding: | UTF-8 |
| Language: | en-US |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Config/Needs/website: | pkgdown |
| Config/roxygen2/version: | 8.0.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-07-14 02:21:13 UTC; freitashr |
| Author: | Hercules R. Freitas
|
| Maintainer: | Hercules R. Freitas <hercules.freitas@uerj.br> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-22 08:30:14 UTC |
ggmeta: Publication-Quality Forest Plots with 'ggplot2'
Description
A 'ggplot2' extension for creating publication-quality forest plots
from meta package objects or tidy data frames. Provides custom
ggproto geometries for study-level confidence intervals,
summary diamonds, prediction intervals, and null-effect reference lines.
Main function
ggforest is the primary entry point. Pass either a
meta object (from meta) or a tidy data frame.
Custom geoms
-
geom_forest_ci— study-level CI with weight-proportional squares -
geom_forest_diamond— summary effect diamond polygon -
geom_forest_ref— vertical null-effect reference line -
geom_forest_predict— prediction interval display
Data conversion
tidy_meta converts meta objects to tidy data frames
suitable for use with ggmeta geoms or direct ggplot2 plotting.
Author(s)
Maintainer: Hercules R. Freitas hercules.freitas@uerj.br (ORCID) [copyright holder]
Authors:
Hercules R. Freitas hercules.freitas@uerj.br (ORCID) [copyright holder]
See Also
Useful links:
Report bugs at https://github.com/drhrf/ggmeta/issues
Format an effect estimate and confidence interval as text
Description
A small helper for building the label of a geom_forest_text() column,
producing strings such as "1.40 (0.65 to 3.00)".
Usage
format_effect(estimate, ci_lower, ci_upper, digits = 2, sep = " to ")
Arguments
estimate, ci_lower, ci_upper |
Numeric vectors of equal length. |
digits |
Number of decimal places. Default |
sep |
Separator between the confidence limits. Default |
Value
A character vector; NA estimates become empty strings.
Examples
format_effect(c(1.4, 0.9), c(0.65, 0.6), c(3.0, 1.35))
Fortify a 'meta' object for use with 'ggplot2'
Description
This S3 method for ggplot2::fortify() converts meta objects to
a tidy data frame. It is a wrapper around tidy_meta().
Usage
## S3 method for class 'meta'
fortify(model, data, ...)
Arguments
model |
An object of class |
data |
Ignored. Included for S3 generic compatibility. |
... |
Additional arguments passed to |
Value
A data.frame as returned by tidy_meta().
Examples
library(meta)
library(ggplot2)
m <- metabin(event.e, n.e, event.c, n.c,
data = data.frame(
event.e = c(14, 30), n.e = c(100, 150),
event.c = c(10, 25), n.c = c(100, 150)
),
studlab = c("Study A", "Study B"),
sm = "RR"
)
library(ggmeta)
ggplot(fortify(m), aes(x = estimate, y = studlab)) +
geom_point()
Study-level confidence intervals and point estimates for forest plots
Description
geom_forest_ci() draws a confidence interval line and a
weight-proportional square for each study in a forest plot.
The square area scales with the study weight, making more precise
studies visually prominent.
Usage
geom_forest_ci(
mapping = NULL,
data = NULL,
stat = "forest_ci",
position = "identity",
...,
ci_width = 0.3,
point_size_range = c(1, 6),
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to |
ci_width |
Width of the CI line end-marks as a proportion of the
spacing between study rows. Default: |
point_size_range |
Minimum and maximum point size in mm.
Default: |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
Value
A ggplot2 layer.
Aesthetics
geom_forest_ci() understands the following aesthetics
(required aesthetics are in bold):
-
x— point estimate -
xmin— lower confidence limit -
xmax— upper confidence limit -
y— study position (usually a factor) -
weight— study weight for square sizing -
colour— line and square border colour (default: "black") -
fill— square fill colour (default: "black") -
alpha— transparency (default: 1) -
linewidth— CI line width (default: 0.5) -
size— override for square size; computed from weight by default -
linetype— CI line type (default: "solid")
Examples
library(ggplot2)
df <- data.frame(
study = c("Study 1", "Study 2", "Study 3"),
estimate = c(0.5, 0.8, 0.3),
lower = c(0.2, 0.6, 0.1),
upper = c(0.8, 1.0, 0.5),
weight = c(1, 2, 0.5)
)
ggplot(df, aes(y = study, x = estimate, xmin = lower, xmax = upper,
weight = weight)) +
geom_forest_ref() +
geom_forest_ci()
Summary effect diamond for forest plots
Description
geom_forest_diamond() draws a diamond (lozenge) shape representing
a summary effect estimate in a forest plot. The left and right tips
mark the confidence limits and the widest point marks the estimate.
Usage
geom_forest_diamond(
mapping = NULL,
data = NULL,
stat = "forest_diamond",
position = "identity",
...,
diamond_height = 0.4,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to |
diamond_height |
Height of the diamond as a proportion of the
spacing between study rows. Default: |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
Value
A ggplot2 layer.
Aesthetics
geom_forest_diamond() understands the following aesthetics
(required aesthetics are in bold):
-
x— point estimate (diamond center) -
xmin— lower confidence limit (left tip) -
xmax— upper confidence limit (right tip) -
y— vertical position -
colour— diamond border colour (default: "black") -
fill— diamond fill colour (default: "black") -
alpha— fill transparency (default: 0.5) -
linewidth— border width (default: 0.5) -
linetype— border line type (default: "solid")
Examples
library(ggplot2)
df <- data.frame(
model = c("Common effect", "Random effects"),
estimate = c(0.22, 0.22),
lower = c(-0.08, -0.08),
upper = c(0.52, 0.52)
)
ggplot(df, aes(y = model, x = estimate, xmin = lower, xmax = upper)) +
geom_forest_diamond(aes(fill = model))
Prediction interval display for forest plots
Description
geom_forest_predict() draws a prediction interval around a random-effects
summary estimate. The prediction interval is wider than the confidence
interval and represents the range where the true effect in a new study
is expected to fall.
Usage
geom_forest_predict(
mapping = NULL,
data = NULL,
stat = "forest_predict",
position = "identity",
...,
cap_width = 0.32,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to |
cap_width |
Width of the capped end-marks as a proportion of
row spacing. Default: |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
Value
A ggplot2 layer.
Aesthetics
geom_forest_predict() understands the following aesthetics
(required aesthetics are in bold):
-
x— point estimate (typically the random effects estimate) -
xmin— lower prediction limit -
xmax— upper prediction limit -
y— vertical position -
colour— interval colour (default: "#6F9FBE") -
linewidth— interval line width (default: 0.45) -
linetype— interval line type (default: "dashed") -
alpha— transparency (default: 0.55)
Examples
library(ggplot2)
df <- data.frame(
estimate = c(0.22),
lower = c(-0.27),
upper = c(0.70),
model = c("Random effects")
)
ggplot(df, aes(y = model, x = estimate, xmin = lower, xmax = upper)) +
geom_forest_diamond() +
geom_forest_predict()
Reference line at null effect for forest plots
Description
geom_forest_ref() draws a vertical reference line at the null effect
value — typically 0 for difference measures (MD, SMD) or 1 for ratio
measures (RR, OR, HR). The line indicates where no treatment effect exists.
Usage
geom_forest_ref(
mapping = NULL,
data = NULL,
...,
xintercept = 0,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
... |
Other arguments passed on to |
xintercept |
X-axis intercept for the reference line.
Default: |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
Value
A ggplot2 layer.
Aesthetics
geom_forest_ref() understands the following aesthetics:
-
colour— line colour (default: "gray50") -
linewidth— line width (default: 0.5) -
linetype— line type (default: "dashed") -
alpha— transparency (default: 0.8)
Examples
library(ggplot2)
df <- data.frame(
study = c("Study 1", "Study 2"),
estimate = c(0.5, 0.8),
lower = c(0.2, 0.6),
upper = c(0.8, 1.0),
weight = c(1, 2)
)
ggplot(df, aes(y = study, x = estimate, xmin = lower,
xmax = upper, weight = weight)) +
geom_forest_ref(xintercept = 0) +
geom_forest_ci()
Add an aligned text column to a forest plot
Description
geom_forest_text() places a column of text labels aligned with the study
rows of a forest plot — for example event counts, sample sizes, weights, or
the effect estimate rendered as text. Rows align automatically through the
shared y (study) aesthetic; the horizontal position of the column is set
with the x argument. Place a column beside the data by widening the panel
with ggplot2::expand_limits().
Usage
geom_forest_text(
mapping = NULL,
data = NULL,
stat = "identity",
position = "identity",
...,
x = NULL,
hjust = 0,
size = 3.2,
na.rm = TRUE,
show.legend = FALSE,
inherit.aes = FALSE
)
Arguments
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to |
x |
Fixed horizontal position for the column, in x-axis data units. If
|
hjust |
Horizontal justification. Default |
size |
Text size in millimetres. Default |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
Value
A ggplot2 layer.
Aesthetics
geom_forest_text() understands the following aesthetics
(required aesthetics are in bold):
-
y— row position (map to the same study variable as the forest layers) -
label— text to display -
colour— text colour (default: "black") -
size— text size; set via thesizeargument -
fontface,family,angle,alpha
Examples
library(ggplot2)
df <- data.frame(
study = c("A", "B", "C"),
estimate = c(0.5, 0.8, 0.3),
lower = c(0.2, 0.6, 0.1),
upper = c(0.8, 1.0, 0.5),
n = c(120, 240, 90)
)
ggplot(df, aes(y = study, x = estimate, xmin = lower, xmax = upper)) +
geom_forest_ci() +
geom_forest_text(aes(y = study, label = n), x = 1.15) +
expand_limits(x = 1.25)
Pseudo-confidence-interval contours for a funnel plot
Description
geom_funnel_contour() draws the funnel-shaped pseudo confidence interval(s)
around a reference effect. For a study with standard error se, the expected
effect under no bias lies within centre +/- z * se, so the contours are
straight lines fanning out from the apex at se = 0. On a funnel plot with a
reversed standard-error axis they form the familiar funnel.
Usage
geom_funnel_contour(
centre,
se_max,
level = 0.95,
...,
colour = "grey55",
linetype = "dashed",
linewidth = 0.4,
alpha = NA
)
Arguments
centre |
Reference effect (usually the pooled estimate) the funnel is centred on, on the analysis scale. |
se_max |
Largest standard error the contours should reach (the bottom of the funnel). |
level |
Confidence level(s) for the contour(s), e.g. |
... |
Other arguments passed on to |
colour, linetype, linewidth, alpha |
Line appearance. |
Details
The layer builds its own data from centre, se_max, and level, so it does
not use the plot's data; add it to a plot that maps the effect to x and the
standard error to y.
Value
A ggplot2 layer.
Examples
library(ggplot2)
studies <- data.frame(
estimate = c(-0.5, -0.2, -0.4, 0.1, -0.3),
se = c(0.10, 0.30, 0.15, 0.35, 0.22)
)
ggplot(studies, aes(x = estimate, y = se)) +
geom_funnel_contour(centre = -0.3, se_max = 0.4) +
geom_point() +
scale_y_reverse()
Create a forest plot
Description
The primary function for creating publication-quality forest plots.
Accepts a meta object (created by meta::metabin(),
meta::metacont(), etc.) or a tidy data frame (as returned by
tidy_meta() or constructed manually).
Usage
ggforest(x, ...)
## Default S3 method:
ggforest(x, ...)
## S3 method for class 'meta'
ggforest(
x,
...,
back_trans = c("auto", "exp", "none"),
sort_studies = TRUE,
show_summary = TRUE,
show_predict = TRUE,
show_hetstats = TRUE,
null_effect = NULL,
xlab = NULL
)
## S3 method for class 'data.frame'
ggforest(
x,
null_effect = 0,
xlab = "Effect (95% CI)",
ylab = NULL,
title = NULL,
caption = NULL,
add_summary = FALSE,
summary_method = c("common", "random"),
level = 0.95,
columns = NULL,
effect_header = NULL,
ci_args = list(),
diamond_args = list(),
diamond_colours = NULL,
predict_args = list(),
ref_args = list(),
consensus = TRUE,
consensus_args = list(),
...
)
Arguments
x |
A meta object or a tidy data frame with columns
|
... |
Additional arguments passed to methods. |
back_trans |
Back-transform ratio measures? |
sort_studies |
Sort studies by effect estimate? Default: |
show_summary |
Include summary effect rows? Default: |
show_predict |
Include prediction interval? Default: |
show_hetstats |
Show heterogeneity statistics in plot caption?
Default: |
null_effect |
Null effect value for the reference line.
Default: |
xlab |
X-axis label. Default: |
ylab |
Y-axis label. Default: |
title |
Plot title. Default: |
caption |
Plot caption. Default: |
add_summary |
For the data-frame method, if |
summary_method |
Which pooled summaries to add when |
level |
Confidence level for the pooled summary interval. Default
|
columns |
Add a |
effect_header |
Header for the estimate column (e.g. |
ci_args, diamond_args, predict_args |
Lists of arguments used to restyle
the study confidence intervals ( |
diamond_colours |
Optional named colours for the summary diamonds,
overriding the default palette. Names are |
ref_args, consensus_args |
Lists of arguments for the null-effect
reference line and the dotted "consensus" line (both |
consensus |
Draw the dotted consensus line at the pooled estimate?
Default |
Value
A ggplot object. Add standard ggplot2 layers (themes,
scales, labels) to further customize.
Examples
library(meta)
m <- metabin(event.e, n.e, event.c, n.c,
data = data.frame(
event.e = c(14, 30, 15, 22),
n.e = c(100, 150, 100, 120),
event.c = c(10, 25, 12, 18),
n.c = c(100, 150, 100, 120)
),
studlab = c("Study A", "Study B", "Study C", "Study D"),
sm = "RR"
)
ggforest(m)
Funnel plot from a meta-analysis
Description
ggfunnel() draws a funnel plot: each study's effect estimate against its
standard error (a measure of precision), with pseudo confidence-interval
contours around the pooled effect. Asymmetry can signal small-study effects
or publication bias. Like ggforest(), it accepts a meta object or a
tidy data frame and returns an ordinary ggplot, so a forest and a funnel
plot compose on one canvas with, for example, patchwork.
Usage
ggfunnel(x, ...)
## Default S3 method:
ggfunnel(x, ...)
## S3 method for class 'meta'
ggfunnel(x, ..., ref = c("common", "random"), level = 0.95)
## S3 method for class 'data.frame'
ggfunnel(
x,
centre = NULL,
sm = NULL,
level = 0.95,
xlab = NULL,
ylab = "Standard error",
title = NULL,
point_args = list(),
contour_args = list(),
ref_args = list(),
...
)
Arguments
x |
A meta object, or a data frame with |
... |
Additional arguments passed to methods. |
ref |
Which pooled estimate to centre the funnel on: |
level |
Confidence level(s) for the funnel contours, e.g. |
centre |
Effect the funnel is centred on. Defaults to the inverse-variance (common-effect) estimate of the supplied studies. |
sm |
Summary measure (e.g. |
xlab, ylab |
Axis labels. |
title |
Plot title. Default |
point_args, contour_args, ref_args |
Lists of arguments used to restyle
the study points ( |
Value
A ggplot object.
Examples
library(meta)
m <- metabin(event.e, n.e, event.c, n.c,
data = data.frame(
event.e = c(12, 8, 25, 18, 30, 15), n.e = c(120, 90, 200, 150, 250, 130),
event.c = c(20, 14, 30, 28, 35, 25), n.c = c(118, 92, 205, 148, 245, 128)
),
studlab = paste("Study", 1:6), sm = "RR"
)
ggfunnel(m)
Apply BMJ-style formatting
Description
Modifies a forest plot to match BMJ (British Medical Journal) style conventions.
Usage
layout_bmj(p)
Arguments
p |
A ggplot object (typically from |
Value
A ggplot object with BMJ-style formatting applied.
Apply JAMA-style formatting
Description
Modifies a forest plot to match JAMA (Journal of the American Medical Association) style conventions.
Usage
layout_jama(p)
Arguments
p |
A ggplot object (typically from |
Value
A ggplot object with JAMA-style formatting applied.
Apply RevMan5-style formatting
Description
Modifies a forest plot to match Cochrane RevMan 5 style conventions.
Usage
layout_revman5(p)
Arguments
p |
A ggplot object (typically from |
Value
A ggplot object with RevMan5-style formatting applied.
Forest plot theme
Description
A complete ggplot2 theme optimized for forest plots. Removes unnecessary grid lines, adjusts margins, and sets sensible defaults for forest plot aesthetics.
Usage
theme_forest(
base_size = 11,
base_family = "",
base_line_size = base_size/22,
base_rect_size = base_size/22
)
Arguments
base_size |
Base font size in pts. Default: |
base_family |
Base font family. Default: |
base_line_size |
Base line size. Default: |
base_rect_size |
Base rect size. Default: |
Value
A ggplot2 theme object (a list of class "theme").
Examples
library(ggplot2)
df <- data.frame(
study = c("Study 1", "Study 2"),
estimate = c(0.5, 0.3),
lower = c(0.2, 0.1),
upper = c(0.8, 0.5),
weight = c(1, 2)
)
ggplot(df, aes(y = study, x = estimate, xmin = lower,
xmax = upper, weight = weight)) +
geom_forest_ref() +
geom_forest_ci() +
theme_forest()
Funnel plot theme
Description
A light ggplot2 theme for ggfunnel() plots.
Usage
theme_funnel(base_size = 11, base_family = "")
Arguments
base_size |
Base font size in pts. Default |
base_family |
Base font family. Default |
Value
A ggplot2 theme.
Examples
library(ggplot2)
df <- data.frame(estimate = c(-0.3, 0.1, -0.2), se = c(0.1, 0.3, 0.2))
ggplot(df, aes(estimate, se)) +
geom_point() +
scale_y_reverse() +
theme_funnel()
Tidy a 'meta' object into a plottable data frame
Description
Converts objects of class meta (from the meta package) into
a tidy data frame suitable for use with ggmeta geometries and
ggforest(). The returned data frame has one row per study or summary.
Usage
tidy_meta(x, ...)
## Default S3 method:
tidy_meta(x, ...)
## S3 method for class 'data.frame'
tidy_meta(
x,
add_summary = FALSE,
summary_method = c("common", "random"),
level = 0.95,
...
)
## S3 method for class 'meta'
tidy_meta(
x,
back_trans = c("auto", "exp", "none"),
sort_studies = TRUE,
add_summary = TRUE,
add_predict = TRUE,
add_subgroups = TRUE,
...
)
Arguments
x |
An object of class |
... |
Additional arguments passed to methods. |
add_summary |
For the data-frame method, if |
summary_method |
Which pooled summaries to add when |
level |
Confidence level for the pooled summary interval. Default
|
back_trans |
Should the estimate and confidence limits be
back-transformed to the natural scale? If |
sort_studies |
If |
add_predict |
If |
add_subgroups |
If |
Value
A data.frame with one row per study or summary, with columns:
- studlab
Study label (character)
- estimate
Point estimate (numeric)
- ci_lower
Lower confidence limit (numeric)
- ci_upper
Upper confidence limit (numeric)
- se
Standard error (numeric)
- weight
Study weight (numeric,
NAfor summaries)- p_value
P-value (numeric)
- n
Sample size or person-time (numeric, optional)
- event
Number of events (numeric, optional)
- is_summary
Logical,
TRUEfor summary rows- summary_type
Character:
"none","common","random","subgroup", or"predict"- subgroup
Subgroup label (character or
NA)
The returned data frame has the following attributes:
smsummary measure type (e.g.
"RR","OR","MD")null_effectnull effect value for reference line
methodmeta-analysis method
commonlogical, TRUE if common effect model was used
randomlogical, TRUE if random effects model was used
tauheterogeneity estimate tau
knumber of studies
Examples
library(meta)
m <- metabin(event.e, n.e, event.c, n.c,
data = data.frame(
event.e = c(14, 30), n.e = c(100, 150),
event.c = c(10, 25), n.c = c(100, 150)
),
studlab = c("Study A", "Study B"),
sm = "RR"
)
tidy_meta(m)