R ggplot2 Box Plot
A box plot (also called a box-and-whisker plot) summarizes the distribution of a numeric variable using five statistics: minimum, first quartile (Q1), median, third quartile (Q3), and maximum. It is ideal for comparing distributions across groups and spotting outliers.
Box Plot Anatomy
─── Max whisker (Q3 + 1.5×IQR, or actual max if smaller)
│
┌──┴──┐
│ │ ← Q3 (75th percentile)
├─────┤ ← Median (50th percentile)
│ │ ← Q1 (25th percentile)
└──┬──┘
│ IQR = Q3 - Q1 (Inter-Quartile Range)
─── Min whisker (Q1 - 1.5×IQR, or actual min if larger)
● ← Outlier (beyond 1.5×IQR from box)
Basic Box Plot
library(ggplot2)
exam <- data.frame(
class = rep(c("Class A","Class B","Class C"), each=20),
score = c(rnorm(20,75,10), rnorm(20,68,12), rnorm(20,82,8))
)
exam$score <- pmin(pmax(round(exam$score),40),100)
ggplot(exam, aes(x=class, y=score)) +
geom_boxplot(fill="steelblue", color="gray30", alpha=0.8) +
labs(title="Score Distribution by Class",
x="Class", y="Score") +
theme_minimal()
Color by Group
ggplot(exam, aes(x=class, y=score, fill=class)) + geom_boxplot(color="gray30", alpha=0.8, show.legend=FALSE) + scale_fill_brewer(palette="Pastel1") + labs(title="Score Distribution by Class") + theme_minimal()
Notched Box Plot
# Notches show 95% confidence interval around the median # Non-overlapping notches suggest medians are significantly different ggplot(exam, aes(x=class, y=score, fill=class)) + geom_boxplot(notch=TRUE, color="gray30", alpha=0.8, show.legend=FALSE) + labs(title="Score Distribution — Notched (Median CI)") + theme_minimal()
Box Plot + Jittered Data Points
# Show the actual data points on top of the box plot ggplot(exam, aes(x=class, y=score)) + geom_boxplot(fill="steelblue", alpha=0.5, outlier.shape=NA) + geom_jitter(width=0.15, alpha=0.4, color="steelblue") + labs(title="Score Distribution with Data Points") + theme_minimal()
Violin Plot — Distribution Shape
# Violin plots show the full distribution shape ggplot(exam, aes(x=class, y=score, fill=class)) + geom_violin(alpha=0.7, show.legend=FALSE) + geom_boxplot(width=0.15, fill="white", color="gray30") + scale_fill_brewer(palette="Set2") + labs(title="Score Distribution — Violin + Box") + theme_minimal()
Box vs Violin:
Box plot: shows 5 key statistics
│ ┌──┐ │
──┤ ├──
└──┘
Violin: shows full density shape
│ ╔══╗ │
╔╝ ╚══╝╔╗
╚════════╝
Horizontal Box Plot
ggplot(exam, aes(x=score, y=class, fill=class)) + geom_boxplot(show.legend=FALSE) + scale_fill_brewer(palette="Pastel2") + labs(title="Score Distribution (Horizontal)", x="Score", y=NULL) + theme_minimal()
Grouped Box Plot
exam2 <- exam
exam2$year <- rep(c("2023","2024"), 30)
ggplot(exam2, aes(x=class, y=score, fill=year)) +
geom_boxplot(position=position_dodge(0.8), alpha=0.8) +
scale_fill_manual(values=c("2023"="steelblue","2024"="tomato")) +
labs(title="Score Distribution by Class and Year", fill="Year") +
theme_minimal()
What Box Plots Tell You
Feature Interpretation ────────────────────────────────────────────────────────────── High median Group tends to score higher overall Wide IQR (tall box) Scores are spread out, inconsistent Narrow IQR (short box) Scores are consistent within group Long upper whisker Some high-performing outliers Many outlier dots Data has unusual extreme values Non-overlapping notches Groups likely differ significantly
Box plots pack five statistics into a single compact shape, making them perfect for comparing distributions across many groups simultaneously. When you have more than three groups to compare, box plots are almost always clearer than overlapping histograms.
