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.

Leave a Comment

Your email address will not be published. Required fields are marked *