Box Plot
ggplot2: geom_boxplot() · Package: ggplot2 · Variables: 1 numerical + 0-1 categorical
WHAT IS A BOX PLOT?
A box plot (also called a box-and-whisker plot) provides a compact five-number summary: minimum, first quartile (Q1), median, third quartile (Q3), and maximum — with outliers shown as individual points. It is the most space-efficient way to compare distributions across multiple groups. Box plots answer "how does the spread and center of group A compare to group B?" They work well with 3-20 groups and are standard in scientific and statistical reporting. Note that box plots hide distribution shape (bimodality) — consider violin plots if shape matters. In ggplot2, use geom_boxplot().
HOW TO READ A BOX PLOT
The box spans the interquartile range: its lower edge is the 25th percentile, its upper edge the 75th, and the line inside is the median — not the mean. Half the observations fall inside the box, so its height is a direct read of spread. The whiskers extend to the most extreme point still within 1.5 times the IQR of the box, and anything beyond is drawn individually. That 1.5 is a convention, not a test: points outside it are candidates for investigation, not confirmed errors. A median sitting off-centre within the box indicates skew, and comparing notch overlap between groups gives a rough visual significance test. The critical limitation is that a box plot cannot show multimodality — two distributions with wildly different shapes can produce identical boxes, which is the single best argument for overlaying the raw points.
BEST FOR
- · Comparing distributions across groups
- · Identifying outliers
- · Compact summary
- · 3-20 groups
AVOID WHEN
- · Non-technical audience
- · When distribution shape matters (bimodality hidden)
- · Very small samples
R + GGPLOT2 CODE EXAMPLE
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) + geom_boxplot(fill = "#ff6a00", alpha = 0.7) + labs(title = "MPG by Cylinder Count", x = "Cylinders", y = "MPG")
BOX PLOT WITH JITTERED POINTS AND GROUP COUNTS
The version that fixes the box plot’s main weakness: raw points overlaid so distribution shape stays visible, and the sample size printed per group.
library(ggplot2)
library(dplyr)
counts <- mtcars |>
count(cyl) |>
mutate(label = paste0("n = ", n))
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_boxplot(
fill = "#ff6a00", alpha = 0.3,
outlier.shape = NA, width = 0.55
) +
geom_jitter(width = 0.12, alpha = 0.7, size = 2, colour = "#1c1c17") +
stat_summary(
fun = mean, geom = "point",
shape = 23, size = 3, fill = "white"
) +
geom_text(data = counts, aes(x = factor(cyl), y = 33, label = label),
size = 3.2, colour = "grey40") +
labs(
title = "Fuel economy by cylinder count",
subtitle = "Box shows median and IQR; diamond marks the mean",
x = "Cylinders", y = "Miles per gallon"
) +
theme_minimal(base_size = 12)COMMON MISTAKES WITH THIS CHART
Reading the centre line as the mean
It is the median. For skewed data the two differ substantially. Add stat_summary(fun = mean, geom = "point") if the mean matters to your argument.
Hiding bimodality behind the box
A box plot summarises to five numbers and cannot show two peaks. Overlay the points with geom_jitter(), or use a violin plot when shape is part of the question.
Drawing boxes for groups with very few observations
Quartiles are meaningless below roughly ten points per group. Plot the individual values instead — with n that small the reader can see the distribution directly.
Calling everything past the whisker an outlier
The 1.5 IQR rule flags around 0.7% of a normal distribution by construction, so large samples always produce some. They are worth a look, not automatic removal.
Run this code now
Paste the code above into RChat and see the box plot rendered instantly in your browser.