R ggplot2 Histogram

A histogram shows the distribution of a single numeric variable by grouping values into bins and displaying how many observations fall in each bin. Unlike a bar chart (which compares categories), a histogram reveals the shape of your data — whether it is symmetric, skewed, peaked, or spread out.

Basic Histogram

library(ggplot2)

scores <- data.frame(
  score = c(45,52,58,60,62,65,67,68,70,72,72,74,75,
            76,78,78,80,82,84,85,88,90,92,95,98)
)

ggplot(scores, aes(x=score)) +
  geom_histogram(binwidth=10, fill="steelblue", color="white") +
  labs(title="Exam Score Distribution",
       x="Score", y="Number of Students") +
  theme_minimal()

Choosing the Right Number of Bins

# binwidth: width of each bin (in data units)
geom_histogram(binwidth=5)    # narrow bins — more detail
geom_histogram(binwidth=10)   # medium bins — balanced
geom_histogram(binwidth=20)   # wide bins — more smoothed

# bins: total number of bins
geom_histogram(bins=10)
geom_histogram(bins=20)

# Sturges rule: bins ≈ log2(n) + 1  (ggplot2 default: 30)
Effect of bin width:
  binwidth=5 (narrow):    ▄▆█▇▆▄▃▂  more detailed, noisier
  binwidth=10 (medium):    ▄██▇▄▂    good balance
  binwidth=20 (wide):       ▄█▆▃     smoother, less detail

Filled by Group (Multiple Distributions)

class_scores <- data.frame(
  score = c(45,60,72,68,80,75,88,92, 55,70,65,78,82,90,85,95),
  class = rep(c("Class A","Class B"), each=8)
)

ggplot(class_scores, aes(x=score, fill=class)) +
  geom_histogram(binwidth=10, alpha=0.6, position="identity") +
  scale_fill_manual(values=c("Class A"="steelblue","Class B"="tomato")) +
  labs(title="Score Distribution by Class",
       x="Score", y="Count", fill="Class") +
  theme_minimal()

Density Histogram

# y-axis shows density (area = 1) instead of count
ggplot(scores, aes(x=score)) +
  geom_histogram(aes(y=after_stat(density)),
                 binwidth=10, fill="steelblue", color="white", alpha=0.7) +
  geom_density(color="red", linewidth=1.2) +   # overlay density curve
  labs(title="Score Distribution with Density Curve",
       x="Score", y="Density") +
  theme_minimal()

Adding Reference Lines

mean_score   <- mean(scores$score)
median_score <- median(scores$score)

ggplot(scores, aes(x=score)) +
  geom_histogram(binwidth=10, fill="steelblue", color="white", alpha=0.8) +
  geom_vline(xintercept=mean_score,   color="red",    linetype="dashed", linewidth=1) +
  geom_vline(xintercept=median_score, color="orange", linetype="dashed", linewidth=1) +
  annotate("text", x=mean_score+1,   y=5.5, label=paste("Mean:",round(mean_score,1)),
           color="red",    hjust=0, size=3) +
  annotate("text", x=median_score+1, y=5,   label=paste("Median:",round(median_score,1)),
           color="orange", hjust=0, size=3) +
  labs(title="Score Distribution with Mean and Median") +
  theme_minimal()

Reading Distribution Shapes

Shape           Description                  What It Means
─────────────────────────────────────────────────────────────────────
Bell curve      Symmetric, single peak       Normal distribution
Right-skewed    Long tail on right           Most values low, few high
Left-skewed     Long tail on left            Most values high, few low
Bimodal         Two peaks                    Two subgroups in data
Uniform         Flat, roughly equal bars     Equal probability across range
Right-skewed (income data):
  │███
  │██████
  │█████████▄▃▂▁▁
  └────────────────
   Low      High

Left-skewed (exam scores near ceiling):
  │           ▁▂▄
  │       ▃████████
  │   ▁▂▄████████
  └────────────────
   Low         High

Faceted Histograms

ggplot(class_scores, aes(x=score, fill=class)) +
  geom_histogram(binwidth=10, color="white", show.legend=FALSE) +
  facet_wrap(~class, ncol=1) +
  scale_fill_manual(values=c("Class A"="steelblue","Class B"="tomato")) +
  labs(title="Score Distribution by Class", x="Score", y="Count") +
  theme_minimal()

Histograms answer the question "how is my data distributed?" before any other analysis begins. Always examine your data's distribution first — it tells you whether to use parametric tests, whether outliers exist, and whether transformations are needed before modeling.

Leave a Comment

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