Skip to content

02-02: Graphical Displays

A frequency table tells you the numbers; a graph tells you the shape. Shape decides which centre and which spread you should report, and whether the normal-based tests of Chapters 09–13 are even appropriate.


Which Graph for Which Data

Graph Data type Shows
Bar chart Qualitative Frequency per category — bars separated
Pareto chart Qualitative (ordinal by count) Categories sorted largest → smallest, with cumulative % line
Pie chart Qualitative Each category's share of the whole
Histogram Quantitative, grouped Distribution shape — bars touching (continuous scale)
Frequency polygon Quantitative, grouped Same shape as a line through class midpoints; good for overlaying two groups
Ogive Quantitative, cumulative "How many are at or below x" — plotted at class boundaries
Stem-and-leaf Quantitative, small n Shape and the original values at once
Dot plot Quantitative, small n Every observation as a dot; ties stack
Boxplot Quantitative Five-number summary, spread, skew, outliers
Scatterplot Two quantitative Relationship between two variables (Chapter 13)
Time series plot Quantitative over time Trend, seasonality, shifts

Warning

A bar chart is not a histogram. Bar-chart bars are separated because the categories are discrete labels with no order. Histogram bars touch because the horizontal axis is a continuous number line. Drawing a histogram with gaps is a classic exam deduction.


Reading Distribution Shape

Symmetric (bell)              Right-skewed (positive)        Left-skewed (negative)

     ▁▃▅█▅▃▁                       ▁█▆▄▃▂▁▁                        ▁▁▂▃▄▆█▁         

mean ≈ median ≈ mode         mean > median > mode          mean < median < mode
Shape Tail Typical example Report
Symmetric Balanced Heights, measurement error Mean and standard deviation
Right-skewed Long tail to the right Income, house prices, waiting times Median and IQR
Left-skewed Long tail to the left Exam scores on an easy test, age at retirement Median and IQR
Uniform Flat Fair die rolls, random digits Range
Bimodal Two peaks Two mixed subgroups Split the groups and describe separately

The skew rule of thumb: the mean gets dragged toward the long tail. That single sentence explains every mean/median comparison in Chapter 03.


Stem-and-Leaf Plot

Splits each value into a stem (leading digits) and a leaf (final digit). It shows the shape like a sideways histogram while preserving every original value.

Data: 23 27 29 31 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 51 52 54 57 58

Stem | Leaf
-----+-------------------------
   2 | 3 7 9
   3 | 1 3 4 5 6 7 8 9
   4 | 0 1 2 3 4 5 6 7 8
   5 | 1 2 4 7 8

Key: 3 | 4  =  34

Always include a key — without it, 3 | 4 could mean 34, 3.4, or 340.


Ogive (Cumulative Frequency Graph)

An ogive plots cumulative frequency against upper class boundaries and always rises left to right. Start it at the lower boundary of the first class with a cumulative frequency of 0.

Cum f
  25 |                              ●────
  20 |                    ●─────────
     |
  11 |          ●─────────
     |
   3 |  ●───────
   0 |──┴───────┴─────────┴─────────┴────
     19.5     29.5      39.5      49.5   59.5
                 upper class boundary

Reading an ogive: draw across from a cumulative frequency to the curve and down to the axis to find the value below which that many observations fall — this is how percentiles are read graphically (04-02).


Boxplot (Box-and-Whisker)

Built from the five-number summary: minimum, Q1, median, Q3, maximum.

        ┌───────┬────────┐
   ├────┤       │        ├────────┤          ●
        └───────┴────────┘
   Min     Q1  Median  Q3      Max         outlier

   |<--- whisker --->|<-- box (IQR) -->|<- whisker ->|
  • The box spans Q1 to Q3 — the middle 50% of the data (the IQR).
  • The line inside the box is the median, not the mean.
  • Whiskers extend to the most extreme values within 1.5 × IQR of the box.
  • Points beyond that are drawn individually as outliers.

Reading skew from a boxplot: if the median sits left of centre in the box and the right whisker is longer → right-skewed. Mirror image → left-skewed.


Graphs That Mislead

Trick Effect Fix
Truncated y-axis (not starting at 0 on a bar chart) Small differences look huge Start bar charts at 0
3-D pie or 3-D bars Perspective distorts area Use flat 2-D
Unequal class widths on a histogram Wide classes look taller Equal widths, or plot density
Too few classes Detail lost, looks uniform 5–20 classes
Too many classes Comb-like, noise looks like structure Reduce k
Pictograms scaled in 2-D for a 1-D quantity Doubling the height quadruples the area Scale one dimension only

Excel

Bar / column / pie

Select the frequency table ▸ Insert ▸ Charts ▸ Clustered Column, Bar, or Pie. For a Pareto chart in Excel 2016+: Insert ▸ Insert Statistic Chart ▸ Pareto — it sorts and adds the cumulative line automatically.

Histogram

Three routes, in increasing order of control:

1. Insert ▸ Insert Statistic Chart ▸ Histogram
   Then right-click the horizontal axis ▸ Format Axis ▸ set
   "Bin width" or "Number of bins" to match your class design.

2. Data ▸ Data Analysis ▸ Histogram
   Input Range = raw data, Bin Range = upper class limits,
   tick Chart Output and Cumulative Percentage.

3. Build the frequency table with COUNTIFS, then
   Insert ▸ Clustered Column, and set
   Format Data Series ▸ Gap Width = 0  (this is what makes bars touch).

Frequency polygon and ogive

' Frequency polygon: plot class MIDPOINTS (x) against frequency (y)
'   Insert ▸ Scatter with Straight Lines and Markers
'   Add a midpoint one class below the first and one above the last,
'   each with frequency 0, so the polygon closes on the axis.

' Ogive: plot upper class BOUNDARIES (x) against cumulative frequency (y)
'   Start with the lower boundary of class 1 at cumulative frequency 0.
=SUM($F$2:F2)                     ' cumulative frequency column
=SUM($F$2:F2)/SUM($F$2:$F$5)      ' cumulative relative frequency

Boxplot

Select the data ▸ Insert ▸ Insert Statistic Chart ▸ Box and Whisker. Tick Show mean markers to display the mean as an ✕ alongside the median line.

Supporting formulas

=MIN(A2:A26)                       ' five-number summary
=QUARTILE.EXC(A2:A26, 1)           ' Q1   (see 04-02 for EXC vs INC)
=MEDIAN(A2:A26)
=QUARTILE.EXC(A2:A26, 3)           ' Q3
=MAX(A2:A26)
=SKEW(A2:A26)                      ' >0 right-skewed, <0 left-skewed

R

service <- c(23,27,31,33,34,35,36,38,39,40,41,42,43,44,45,
             46,47,48,51,52,54,57,58,29,37)
blood   <- factor(c("A","O","B","A","AB","O","O","A","O","B"))

# ── Qualitative ────────────────────────────────────────────────────
barplot(table(blood), col = "#5B2A86", border = NA,
        main = "Blood type", xlab = "Type", ylab = "Frequency")

pie(table(blood), main = "Blood type share")

# Pareto: sort descending, add cumulative line
tb <- sort(table(blood), decreasing = TRUE)
bp <- barplot(tb, col = "#0FA3A3", ylim = c(0, sum(tb)))
lines(bp, cumsum(tb), type = "b", pch = 19, col = "#5B2A86")

# ── Quantitative ───────────────────────────────────────────────────
breaks <- seq(19.5, 59.5, by = 10)

hist(service, breaks = breaks, col = "#8A5FBF", border = "white",
     main = "Service times", xlab = "Minutes", ylab = "Frequency")

# Frequency polygon — line through the class midpoints
h <- hist(service, breaks = breaks, plot = FALSE)
plot(h$mids, h$counts, type = "b", pch = 19,
     xlab = "Class midpoint", ylab = "Frequency", main = "Frequency polygon")

# Ogive — cumulative frequency at upper boundaries
plot(breaks, c(0, cumsum(h$counts)), type = "b", pch = 19,
     xlab = "Upper class boundary", ylab = "Cumulative frequency",
     main = "Ogive")

# Stem-and-leaf
stem(service)

# Dot plot
stripchart(service, method = "stack", pch = 19, col = "#0B7A7A")

# Boxplot (+ side-by-side comparison)
boxplot(service, horizontal = TRUE, col = "#56C7C7", main = "Service times")
# boxplot(score ~ group, data = df)     # comparison across groups

# Five-number summary and shape
fivenum(service)
summary(service)

ggplot2 versions (publication quality):

library(ggplot2)
df <- data.frame(service)

ggplot(df, aes(service)) +
  geom_histogram(breaks = breaks, fill = "#5B2A86", colour = "white") +
  labs(title = "Service times", x = "Minutes", y = "Frequency") +
  theme_minimal()

ggplot(df, aes(y = service)) +
  geom_boxplot(fill = "#0FA3A3", alpha = 0.6) +
  coord_flip() + theme_minimal()

Python

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

service = np.array([23,27,31,33,34,35,36,38,39,40,41,42,43,44,45,
                    46,47,48,51,52,54,57,58,29,37])
blood = pd.Series(["A","O","B","A","AB","O","O","A","O","B"])

# ── Qualitative ────────────────────────────────────────────────────
counts = blood.value_counts()
fig, ax = plt.subplots()
ax.bar(counts.index, counts.values, color="#5B2A86")
ax.set(title="Blood type", xlabel="Type", ylabel="Frequency")

fig, ax = plt.subplots()
ax.pie(counts.values, labels=counts.index, autopct="%1.1f%%")

# Pareto
srt = counts.sort_values(ascending=False)
fig, ax = plt.subplots()
ax.bar(srt.index, srt.values, color="#0FA3A3")
ax2 = ax.twinx()
ax2.plot(srt.index, 100 * srt.cumsum() / srt.sum(), "o-", color="#5B2A86")
ax2.set_ylabel("Cumulative %")

# ── Quantitative ───────────────────────────────────────────────────
edges = np.arange(19.5, 69.5, 10)

fig, ax = plt.subplots()
ax.hist(service, bins=edges, color="#8A5FBF", edgecolor="white")
ax.set(title="Service times", xlabel="Minutes", ylabel="Frequency")

# Frequency polygon
counts_q, _ = np.histogram(service, bins=edges)
mids = edges[:-1] + np.diff(edges) / 2
fig, ax = plt.subplots()
ax.plot(mids, counts_q, "o-")
ax.set(xlabel="Class midpoint", ylabel="Frequency", title="Frequency polygon")

# Ogive
fig, ax = plt.subplots()
ax.plot(edges, np.concatenate(([0], counts_q.cumsum())), "o-")
ax.set(xlabel="Upper class boundary", ylabel="Cumulative frequency", title="Ogive")

# Boxplot
fig, ax = plt.subplots()
ax.boxplot(service, vert=False, showmeans=True)
ax.set(title="Service times", xlabel="Minutes")

# Five-number summary and shape
np.percentile(service, [0, 25, 50, 75, 100])
pd.Series(service).describe()
pd.Series(service).skew()

plt.show()

Quick Reference

Graph Excel R Python
Bar chart Insert ▸ Column barplot(table(x)) ax.bar()
Pareto Insert ▸ Statistic ▸ Pareto sorted barplot + lines(cumsum) ax.bar() + twinx()
Pie chart Insert ▸ Pie pie(table(x)) ax.pie()
Histogram Insert ▸ Statistic ▸ Histogram hist(x, breaks) ax.hist(x, bins)
Frequency polygon Scatter with lines on midpoints plot(h$mids, h$counts) ax.plot(mids, counts)
Ogive Scatter with lines on boundaries plot(breaks, cumsum(counts)) ax.plot(edges, cumsum)
Stem-and-leaf manual stem(x) scipy.stats / manual
Dot plot Scatter stripchart(x) ax.plot(x, jitter, "o")
Boxplot Insert ▸ Statistic ▸ Box and Whisker boxplot(x) ax.boxplot(x)
Skewness SKEW(range) psych::skew(x) s.skew()

Common Mistakes

  • Gaps between histogram bars (set Gap Width = 0 in Excel).
  • Plotting an ogive at class limits instead of boundaries, so the curve is shifted half a unit.
  • Forgetting the key on a stem-and-leaf plot.
  • Reporting a mean for an obviously skewed distribution — the graph told you to use the median.
  • A pie chart with 12 slices; nobody can compare them. Use a sorted bar chart.

Exercises: 02-02: Exercises — Graphical Displays


⬅️ Previous: 02-01: Frequency Distributions ➡️ Next: 03-01: Mean, Median and Mode