
ggerror extends ggplot2’s error geoms with
one error-focused API. Pass error for symmetric errors, or
error_neg and error_pos for asymmetric and
one-sided cases. ggerror infers orientation and lets you
style each side independently. It computes summaries from raw data with
stat_error(), and draws signed quantities such as residuals
with sign_aware.
aes(error = ...)error_neg and
error_poscolour_neg,
width_pos, linetype_neg, and moreerrorbar, linerange,
crossbar, or pointrangestat_error()sign_aware = TRUE# Install the stable release from CRAN:
install.packages("ggerror") # 0.3.0
# Or install the development version from GitHub:
pak::pak("iamyannc/ggerror") # 1.0.0The examples below use airquality, the same dataset used
throughout the package vignettes. For convenience I defined a theme, and
did minimal data processing on the original dataset.
library(ggplot2)
library(ggerror)
theme_set(
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(family = "mono", size = 11, hjust = 0),
plot.caption = element_text(face = "italic"),
legend.position = "none"
)
)
aq <- airquality
aq$Month <- factor(aq$Month, labels = month.abb[5:9])
# A function to transform numbered day (1-31) to name, given the year & month (1973, May - Sep)
day_in_month <- function(day_in_month, month, year) {
days_abbr <- format(
as.Date(sprintf("%d-%02d-%02d", year, month, day_in_month)),
"%a"
)
factor(days_abbr,
levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
ordered = TRUE)
}
aq$Day <- day_in_month(aq$Day, airquality$Month, 1973)
# Computing some centrality/spread measures with base R!
aq_monthly_avg <- aggregate(
Temp ~ Month,
data = aq,
FUN = function(x) c(
mean = mean(x),
sd = sd(x),
se = sd(x) / sqrt(length(x))
)
)
aq_monthly_avg <- do.call(data.frame, aq_monthly_avg)The usual case is a symmetric error around some central value.
ggplot(aq_monthly_avg, aes(Temp.mean, Month)) +
geom_error(aes(error = Temp.sd), width = 0.4) +
labs(x=NULL, y=NULL,
title = "geom_error(aes(error = Temp.sd))",
caption = "Default base geom: errorbar"
)
If you want a specific error geom (4 available, see below), either pick it with
error_geom = ... or use the pinned wrappers.
ggplot(aq_monthly_avg, aes(Temp.mean, Month)) +
geom_error_pointrange(aes(error = Temp.sd), size = 0.7) +
labs(title = "geom_error_pointrange(aes(error = Temp.sd))")
error_neg and error_pos extend in opposite
directions. That makes it easy to show genuinely different quantities on
each side, or to suppress one side entirely with NA.
ggplot(aq_monthly_avg, aes(Temp.mean, Month)) +
geom_error(
aes(error_neg = Temp.se, error_pos = Temp.sd),
error_geom = "crossbar",
fill_neg = "#d7e3f4",
fill_pos = "#f6d3c4",
width_neg = 0.25,
width_pos = 0.55
) +
labs(title = "error_neg = Temp.se ; error_pos = Temp.sd")
# Grabbing only the first week in the data and computing for each Temp, its distance from the minimum Temp and maximum Temp.
week_may <- subset(aq, Month == "May")[1:7, ]
week_may$dist2min <- week_may$Temp - min(week_may$Temp, na.rm = TRUE)
week_may$dist2max <- max(week_may$Temp, na.rm = TRUE) - week_may$Temp
ggplot(week_may, aes(Temp, Day)) +
geom_error(
aes(error_neg = dist2min, error_pos = NA),
colour = "steelblue",
linewidth = 1
) +
geom_point(size = 1.5) +
labs(title = "One-sided: error_pos = NA")
stat_error()When you do not want to pre-compute the bounds yourself,
stat_error() computes them directly and supports default
and custom functions.
ggplot(aq, aes(Month, Temp)) +
stat_error(fun = "mean_ci", error_geom = "pointrange") +
labs(title = 'stat_error(fun = "mean_ci", error_geom = "pointrange")')
# [1] `stat_error()` using fun = "mean_ci" and conf.int = 0.95.Custom summary functions work too, as long as they return data frames
of one row with y, ymin, and ymax
columns:
mae_summary <- function(x, scale_by = 1) {
md <- median(x)
mae <- mean(abs(x - md)) * scale_by
data.frame(y = md, ymin = md - mae, ymax = md + mae)
}
ggplot(aq, aes(Month, Temp)) +
stat_error(fun = mae_summary, error_geom = "crossbar", fill = "grey90") +
labs(title = "stat_error(fun = mae_summary, error_geom = \"crossbar\")")
sign_awareFor residual plots and other signed magnitudes,
sign_aware = TRUE assigns positive and negative values
automatically:
# Residual plot made easy
fit_temp <- lm(Temp ~ Wind, data = aq)
aq_fit <- data.frame(
Wind = aq$Wind,
Temp = aq$Temp,
fitted = predict(fit_temp),
residual = resid(fit_temp)
)
ggplot(aq_fit, aes(Wind, fitted)) +
geom_line(linewidth = 0.4, colour = "grey40") +
geom_point(aes(y = Temp), alpha = 0.45) +
geom_error(
aes(error = residual),
sign_aware = TRUE,
orientation = "x",
colour_pos = "firebrick",
colour_neg = "steelblue",
linewidth = 0.5,
alpha = 0.85
) +
labs(title = "geom_error(aes(error = residual), sign_aware = TRUE)")
| ggplot2 base | geom_error(error_geom = ...) |
Pinned wrapper |
|---|---|---|
geom_errorbar |
"errorbar" (default) |
geom_error() |
geom_linerange |
"linerange" |
geom_error_linerange() |
geom_pointrange |
"pointrange" |
geom_error_pointrange() |
geom_crossbar |
"crossbar" |
geom_error_crossbar() |
I tried to be as comprehensive as possible, without taking too much of your attention. For the full walkthroughs, see the package vignettes:
vignette("ggerror"):
simple defaults, asymmetric bars, one-sided barsvignette("use-cases"):
stat_error(), custom summaries, and
sign_awareThis package was developed with the assistance of AI tools. All code has been reviewed by the author, who remains responsible for its quality. Ideas for new geoms are welcome and features are very welcome.
Thank you for reading, forget everything and give me your best cookies recipe 🍪
Yann :)