R
ggplot2
pointrange
data visualization
R programming

R ggplot2 pointrange example

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

geom_pointrange in ggplot2 is useful when you want to show a central estimate together with a lower and upper bound. It is a compact way to visualize means with confidence intervals, model coefficients with standard errors, or any point estimate paired with uncertainty.

Build a Basic Point-Range Plot

The geometry expects one value for the point and two values for the range. In practice, that usually means mapping y, ymin, and ymax.

r
1library(ggplot2)
2
3results <- data.frame(
4  group = c("A", "B", "C"),
5  mean = c(10.2, 12.8, 9.7),
6  lower = c(9.4, 11.6, 8.9),
7  upper = c(11.0, 14.0, 10.5)
8)
9
10ggplot(results, aes(x = group, y = mean, ymin = lower, ymax = upper)) +
11  geom_pointrange()

Each category gets a point at mean and a vertical line from lower to upper. The result is more informative than a point alone because the viewer can immediately judge uncertainty or spread.

Customize the Appearance

geom_pointrange becomes more readable with a little styling. Color, point size, and line thickness all help emphasize the message.

r
1ggplot(results, aes(x = group, y = mean, ymin = lower, ymax = upper)) +
2  geom_pointrange(
3    color = "steelblue",
4    fatten = 3,
5    linewidth = 0.7
6  ) +
7  labs(
8    title = "Estimated mean and interval by group",
9    x = "Group",
10    y = "Value"
11  ) +
12  theme_minimal()

The fatten argument controls the size of the point relative to the line. That makes the center estimate easier to notice without losing the interval.

Compare Multiple Series with Position Adjustment

When you have more than one series per category, use dodging so the ranges do not overlap completely.

r
1results2 <- data.frame(
2  group = rep(c("A", "B", "C"), each = 2),
3  model = rep(c("Baseline", "New"), times = 3),
4  mean = c(10.2, 11.1, 12.8, 13.5, 9.7, 10.4),
5  lower = c(9.4, 10.3, 11.6, 12.7, 8.9, 9.6),
6  upper = c(11.0, 11.9, 14.0, 14.3, 10.5, 11.2)
7)
8
9ggplot(results2, aes(x = group, y = mean, ymin = lower, ymax = upper, color = model)) +
10  geom_pointrange(
11    position = position_dodge(width = 0.4)
12  ) +
13  theme_minimal()

This is a strong choice for comparing experimental conditions or model variants side by side.

Choose geom_pointrange for Summaries, Not Raw Distributions

geom_pointrange is great for summary statistics, but it is not a substitute for the raw data. If you want to show the actual distribution, consider adding points, violin plots, or boxplots. A point-range plot summarizes information; it does not reveal every observation.

That design tradeoff is often fine. For reports or model output, concise summaries are usually what the reader needs.

Common Pitfalls

The most common mistake is giving geom_pointrange raw observations rather than precomputed bounds. The geometry expects one point and one interval per row. If your data contains raw measurements, summarize it first or use a different statistic layer.

Another issue is unclear interval meaning. A reader cannot tell whether the range is a confidence interval, standard deviation, or minimum-to-maximum span unless you label it in the title, caption, or surrounding text.

Overlapping intervals can also become messy when categories are dense or when multiple groups share the same x position. In those cases, dodge the geometry, flip coordinates, or simplify the comparison so the plot stays readable.

Finally, be careful with axis scales. If the plot starts far from zero or uses a transformed axis, small differences can look larger than they really are. That is not always wrong, but it should be a deliberate choice.

Summary

  • Use geom_pointrange when you need to show a point estimate together with lower and upper bounds.
  • Map y, ymin, and ymax explicitly in the aesthetic mapping.
  • Adjust fatten, linewidth, labels, and themes to improve readability.
  • Use position_dodge when several series share the same category.
  • Make the meaning of the interval clear so viewers know what the range represents.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.