A headline and a pile of cubes
Two schools in the same town had a paper-recycling competition. Riverside School collected 52 kg of paper and Hilltop School collected 48 kg. The next day the Riverside newsletter printed a bar chart under the headline "Riverside crushes Hilltop!" — and in the chart, Riverside's bar was one and a half times as tall as Hilltop's.
Was it really a crushing win? The numbers are 52 and 48. Something about the chart was not telling the truth.
Meanwhile, four friends — Ana, Ben, Chen and Dina — have built towers of cubes: 4, 6, 8 and 2 cubes tall. They decide to share the cubes fairly, so that everyone has the same. How many cubes will each of them get?
This lesson is about pictures of numbers: how to read them, how they can fool us, and what the "average" of some numbers really is.
Read the labels first
A data display is a picture of numbers. Before you look at the bars or dots, read the words and numbers around them:
- The title: what was counted or measured?
- The labels: what does each bar or dot stand for?
- The scale: how much is each step on the axis worth — 1, 2, 5, 10? And does the axis start at 0?
Only then compare the bars.
Words we need
Definition— bar graph
A bar graph shows each category as a bar. The length of the bar shows the count or amount for that category, measured against the axis.
Definition— scale
The scale of an axis says how many items (or how much) each step along the axis stands for. If each grid line is worth 5, a bar that reaches the fourth grid line stands for .
Definition— line plot
A line plot (or dot plot) draws a number line and puts one dot (or cross) above the line for every value in the data. Stacks of dots show which values are common. Measurements in halves or quarters of a unit fit on a number line marked in halves or quarters.
Definition— mean
The mean of a list of numbers is their total divided by how many numbers there are. It is the amount each one would have if the total were shared out equally.
Reading displays
Example— A bar graph with a scale
Ms Wanjiku's class in Kisumu asked: How do you come to school? On their bar graph each grid line stands for 2 children.
- The "walk" bar reaches the 6th grid line: children walk.
- The "bus" bar stops halfway between the lines for 6 and 8: that is 7 children.
- The "bicycle" bar reaches the line for 4, and the "car" bar stops halfway between the lines for 2 and 4: 3 children.
How many more children walk than come by bus? . How many children answered? Every child gave exactly one answer, so we add the bars: .
Example— A line plot of measurements
Kenji's group grew bean seedlings and measured them to the nearest quarter of a centimetre:
cm.
On a line plot marked in quarters, and each have two dots. The tallest seedling is cm taller than the shortest. If all eight seedlings were laid end to end they would stretch cm.
Explore: the same data, different pictures
Here is Ms Wanjiku's survey. Switch between the views: a tally chart, a pictograph (look at the key: what does one picture stand for?), a bar graph and a dot plot. They all show the same numbers.
How we come to school
Show the same data as tallies, pictures, bars or dots, and find the mean, median and mode.
And here are the bean seedlings as a line plot. Try the histogram view too, and add your own measurements.
Bean seedlings (cm)
Show the same data as tallies, pictures, bars or dots, and find the mean, median and mode.
How a graph can mislead
Here is the trick in the Riverside newsletter. On the left, the axis starts at 0 kg, as it should. On the right, the axis starts at 40 kg.
Theorem— Raised axes exaggerate
If the axis of a bar graph starts above zero, the bigger of two bars looks relatively bigger than it really is: the ratio of the drawn bars is larger than the ratio of the numbers.
Proof
Starting the axis at 40 is like chopping 40 kg off the bottom of both bars. Both lose the same amount, but that amount is a bigger share of the shorter bar. From 48 we keep only 8; from 52 we keep 12. The short bar has lost of itself, the tall bar only , so what is left of the short bar is much shorter compared with what is left of the tall bar. The higher the axis starts, the worse it gets: start at 47, and the bars are 5 and 1 — Riverside looks five times as big!
∎
Other ways a display can mislead: an axis whose steps are not evenly spaced, pictures of different sizes in a pictograph, a missing scale, or a missing title. A careful reader always checks.
Note
Starting an axis above zero is not always dishonest. For a temperature graph or a line graph of a child's height over the years, zooming in can show small changes clearly. But for bar graphs, where we compare the lengths of the bars, the axis should start at zero — or the graph must say very clearly that it does not.
Gideon's true-or-false game
Gideon only plays with statements that are exactly true or exactly false. Decide, and give a reason.
- "In the newsletter chart, Riverside's bar is 1.5 times as tall, so Riverside collected 1.5 times as much paper." — False. 52 kg is less than 1.1 times 48 kg. The axis started at 40.
- "Moving cubes from one tower to another can change the total." — False. One tower loses exactly what another gains.
- "The mean of 4, 6, 8 and 2 is one of those numbers." — False. It is 5.
- "The mean of some towers can be taller than the tallest tower." — False. Level towers that tall would need more cubes than there are.
For grown-ups · the same ideas in Lean, a proof checker
In Lean, a data set is a list of whole numbers. A move takes one cube off a tower and puts it on another (to the right or to the left); Reach d e means the towers d can be turned into e by moves:
/-- One **move**: take one cube off a tower and put it on another tower. The towers are listed
in order; `xs`, `ys` and `zs` are the towers we do not touch. The cube can move to a tower
further right, or to a tower further left. -/
inductive Move : Data → Data → Prop
| right (xs ys zs : Data) (a b : Nat) :
Move (xs ++ (a + 1) :: ys ++ b :: zs) (xs ++ a :: ys ++ (b + 1) :: zs)
| left (xs ys zs : Data) (a b : Nat) :
Move (xs ++ a :: ys ++ (b + 1) :: zs) (xs ++ (a + 1) :: ys ++ b :: zs)Lean proves that moves never change the total or the number of towers, and so that the level is always total ÷ number of towers:
/-- However many moves we make, the total and the number of towers stay the same. -/
theorem reach_total {d e : Data} (h : Reach d e) : e.sum = d.sum ∧ e.length = d.length := by
induction h with
| refl => exact ⟨rfl, rfl⟩
| step hm _ ih => exact ⟨ih.1.trans (move_total hm), ih.2.trans (move_length hm)⟩/-- `n` towers that are all `m` tall hold `n × m` cubes. -/
theorem level_total (n m : Nat) : (List.replicate n m).sum = n * m := by
induction n with
| zero => simp
| succ n ih => simp only [List.replicate_succ, List.sum_cons, ih, Nat.succ_mul]; omega/-- **The mean as a fair share.** If moves turn the towers `d` into level towers of height `m`,
then `m × (number of towers) = total`. So the level is always total ÷ number of towers — it
does not depend on which moves were made. -/
theorem fair_share {d : Data} {m : Nat} (h : Reach d (List.replicate d.length m)) :
d.length * m = d.sum := by
rw [← level_total, (reach_total h).1]The same fact about level towers is also in Lean's core library; the second version just applies it:
/-- The same fact, applying core Lean's `List.sum_replicate_nat`. -/
theorem level_total_library (n m : Nat) : (List.replicate n m).sum = n * m :=
List.sum_replicate_natThe friends' towers, levelled in four moves, and two consequences: the mean need not be a data value, and some towers cannot be levelled with whole cubes at all:
/-- Four towers of 4, 6, 8 and 2 cubes can be levelled at 5 in four moves:
`4 6 8 2 → 5 5 8 2 → 5 5 7 3 → 5 5 6 4 → 5 5 5 5`. -/
theorem cubes_levelled : Reach [4, 6, 8, 2] [5, 5, 5, 5] :=
.step (.left [] [] [8, 2] 4 5) <|
.step (.right [5, 5] [] [] 7 2) <|
.step (.right [5, 5] [] [] 6 3) <|
.step (.right [5, 5] [] [] 5 4) <|
.refl _/-- The fair share of 4, 6, 8 and 2 is 5 — and 5 is **not** one of the data values. -/
theorem mean_not_a_value : [4, 6, 8, 2].length * 5 = [4, 6, 8, 2].sum ∧ 5 ∉ [4, 6, 8, 2] :=
⟨fair_share cubes_levelled, by decide⟩/-- Towers of 3, 7, 2 and 6 cubes (18 in all) can **never** be levelled with whole cubes: four
equal towers would need `4 × m = 18`, and 18 is not a multiple of 4. The fair share is
`4½`, which needs a cube cut in half. -/
theorem cannot_level (m : Nat) : ¬ Reach [3, 7, 2, 6] (List.replicate 4 m) := by
intro h
have := fair_share h
simp at this
omega/-- **The fair share is never more than the tallest tower.** If the towers `d` can be levelled
at height `m`, and no tower is taller than `M`, then `m ≤ M`. -/
theorem fair_share_le_max {d : Data} {m M : Nat} (hd : d ≠ [])
(h : Reach d (List.replicate d.length m)) (hM : ∀ x ∈ d, x ≤ M) : m ≤ M := by
have h1 := fair_share h
have h2 := sum_le_length_mul d M hM
have hpos : 0 < d.length := List.length_pos_iff.mpr hd
exact Nat.le_of_mul_le_mul_left (h1 ▸ h2) hposFinally, misleading bar charts. drawn base v is the height of a bar for v when the axis starts at base. Lean checks the newsletter's numbers, and then proves for all whole numbers that a raised axis exaggerates the ratio of two bars (written without fractions):
/-- Two schools collect 52 kg and 48 kg of paper. With the axis starting at 40, the bars are
drawn 12 and 8 units tall: one looks one and a half times as tall as the other
(`2 × 12 = 3 × 8`), although 52 kg is not even 1.1 times 48 kg (`10 × 52 < 11 × 48`). -/
theorem misleading_example :
drawn 40 52 = 12 ∧ drawn 40 48 = 8 ∧ 2 * drawn 40 52 = 3 * drawn 40 48 ∧
10 * 52 < 11 * 48 := by
decide/-- **An axis that does not start at zero exaggerates differences.** If the axis starts at
`b > 0` and two values satisfy `b < c < a`, then the drawn bars compare as
`(a − b) : (c − b)`, which is a bigger ratio than the true one, `a : c`. Written without
fractions: `a × (c − b) < (a − b) × c`. -/
theorem baseline_exaggerates (a b c : Nat) (hb : 0 < b) (hbc : b < c) (hca : c < a) :
a * (c - b) < (a - b) * c := by
rw [Nat.mul_sub, Nat.sub_mul]
have h1 : b * c < a * b := by
rw [Nat.mul_comm a b]
exact Nat.mul_lt_mul_of_pos_left hca hb
have h2 : a * b ≤ a * c := Nat.mul_le_mul_left a (Nat.le_of_lt hbc)
omegaWhat is not formalised here: means that are fractions (this module uses whole numbers only), and drawing the charts themselves.
Margaret levels towers and redraws the chart
"""The mean as a fair share: levelling towers of cubes, one cube at a time.
Each child in a group has built a tower of cubes. To share fairly, we
repeatedly move one cube from a tallest tower to a shortest tower, until no
move can make things fairer. The program prints every step and compares the
final level with total / number of towers. Then it finds the mean of some
measurements in quarter centimetres, exactly, with fractions.
Runs unchanged in the browser (Pyodide) using only the standard library.
"""
import textwrap
from fractions import Fraction
def level_once(towers):
"""Move one cube from a tallest tower to a shortest tower, if that helps.
Returns the new list of towers, or None when the tallest and shortest
towers differ by at most one cube (no move can make it fairer).
"""
tall = towers.index(max(towers))
short = towers.index(min(towers))
if towers[tall] - towers[short] <= 1:
return None
new = list(towers)
new[tall] -= 1
new[short] += 1
return new
def level(towers):
"""Level the towers step by step; return the list of all stages."""
stages = [list(towers)]
while True:
nxt = level_once(stages[-1])
if nxt is None:
return stages
stages.append(nxt)
def mean(values):
"""The mean as an exact fraction: total divided by how many values."""
if not values:
raise ValueError("the mean of no values is not defined")
return Fraction(sum(values), len(values))
def show(values):
"""Format a list of numbers or fractions compactly."""
return " ".join(str(v) for v in values)
def main():
names = ["Ana", "Ben", "Chen", "Dina"]
towers = [4, 6, 8, 2]
print("Towers:", ", ".join(f"{n} {t}" for n, t in zip(names, towers)))
stages = level(towers)
for i, stage in enumerate(stages[1:], start=1):
print(f" move {i}: {show(stage)}")
m = mean(towers)
answer = "yes" if m in towers else "no"
print(f"Level {stages[-1][0]} = total {sum(towers)} / {len(towers)} towers"
f" = {m}. Is {m} one of the towers? {answer}")
print()
odd = [3, 7, 2, 6]
stages = level(odd)
print(f"Towers {show(odd)}: after {len(stages) - 1} moves they are"
f" {show(stages[-1])}.")
print(f"They cannot be level with whole cubes: the fair share is"
f" {sum(odd)}/{len(odd)} = {mean(odd)} = {float(mean(odd))}.")
print()
beans = [Fraction(9, 4), Fraction(5, 2), Fraction(5, 2), Fraction(11, 4),
Fraction(13, 4), Fraction(7, 2), Fraction(7, 2), Fraction(15, 4)]
print("Bean seedlings, heights in cm:", show(beans))
total = sum(beans)
mb = mean(beans)
print(f"Total {total} cm, so the mean is {total} / {len(beans)}"
f" = {mb} cm.")
print(f"Check: mean x number of values = {mb * len(beans)} = total.")
print(f"Is the mean one of the heights? {'yes' if mb in beans else 'no'}")
print()
print(textwrap.fill(
"Epistemic status: exact. Whole cubes and fractions are computed "
"exactly, with no rounding. The program checks these data sets; the "
"lesson and the Lean module prove that levelling always ends at "
"total / number of towers when the towers can be levelled.",
width=78,
))
if __name__ == "__main__":
main()"""How a bar chart can mislead: an axis that does not start at zero.
Two schools collected paper for recycling: Riverside 52 kg and Hilltop
48 kg. The program draws the two bars in text twice - once with the axis
starting at 0 and once starting at 40 - and computes how many times taller
one bar *looks* than the other for several starting values. Finally it
checks, for every whole-number case up to 60, that starting the axis above
zero always makes the bigger bar look relatively bigger than it is.
Runs unchanged in the browser (Pyodide) using only the standard library.
"""
import textwrap
from fractions import Fraction
SCHOOLS = [("Riverside", 52), ("Hilltop", 48)]
def drawn_height(value, base):
"""The height of a bar when the axis starts at `base` instead of 0."""
if value < base:
raise ValueError("the bar would start below the axis")
return value - base
def apparent_ratio(big, small, base):
"""How many times taller the bigger bar looks, as an exact fraction."""
return Fraction(drawn_height(big, base), drawn_height(small, base))
def text_bar(value, base, per_char):
"""A bar of '#' characters: one '#' for every `per_char` units above base."""
return "#" * int(drawn_height(value, base) / per_char)
def exaggeration_always(limit):
"""Check apparent ratio > true ratio for all 0 < b < c < a <= limit.
Returns (number of cases checked, list of failures).
"""
checked, failures = 0, []
for a in range(1, limit + 1):
for c in range(1, a):
for b in range(1, c):
checked += 1
if not apparent_ratio(a, c, b) > Fraction(a, c):
failures.append((a, b, c))
return checked, failures
def main():
for base, per_char in ((0, 2), (40, Fraction(1, 3))):
print(f"Axis starting at {base} kg:")
for name, kg in SCHOOLS:
print(f" {name:<9} {kg} kg |{text_bar(kg, base, per_char)}")
print()
print("Axis starts at bars drawn looks this many times taller")
for base in (0, 20, 30, 40, 44, 46, 47):
r = apparent_ratio(52, 48, base)
print(f"{base:>14} {52 - base:>4} : {48 - base:<4}"
f" {str(r):>6} = {float(r):.2f}")
print("True ratio: 52/48 = 13/12, only about 1.08.")
print()
checked, failures = exaggeration_always(60)
print(f"Every whole-number case 0 < b < c < a <= 60: {checked} cases.")
print(f"Cases where the raised axis did not exaggerate: {len(failures)}.")
print()
print(textwrap.fill(
"Epistemic status: exact arithmetic with fractions. The table is "
"exact for these two schools, and the final check covers every "
"whole-number case up to 60 (finite evidence only). The lesson's "
"argument and the Lean module prove the rule for all whole numbers.",
width=78,
))
if __name__ == "__main__":
main()Both programs do exact arithmetic, with no rounding. The last check in the second program tries every whole-number case up to 60 — strong evidence, but only finite. The argument in the lesson and the Lean proof cover every case.
Your turn
Read every question carefully — especially the scales! You can ask for a hint whenever you like.
1. Data displays and the mean as a fair share
Warm-upHumanOn a bar graph, each grid line stands for 5 children. The bar for "football" reaches exactly the 4th grid line. How many children chose football?
2. Data displays and the mean as a fair share
Warm-upHumanOn another bar graph the grid lines are labelled 0, 2, 4, 6, 8, … The bar for "cycling" stops exactly halfway between the lines for 8 and 10. How many children cycle?
3. Data displays and the mean as a fair share
CoreHumanA fruit seller in Accra makes two pictographs. In the mango chart, one picture stands for 5 mangoes, and the row has 6 pictures. In the banana chart, one picture stands for 2 bananas, and the row has 9 pictures. How many more mangoes than bananas did she sell?
4. Data displays and the mean as a fair share
CoreHumanNadia scored 6, 9, 3 and 10 points in four basketball games. If her points were shared out equally over the four games, how many points would each game get? (This is the mean.)
5. Data displays and the mean as a fair share
CoreHumanFive friends have a mean of 8 stickers each. Four of them have 6, 9, 5 and 10 stickers. How many stickers does the fifth friend have?
6. Data displays and the mean as a fair share
CoreHumanA bar graph about two buses has an axis that starts at 90. The bar for Bus A (100 passengers) looks twice as tall as the bar for Bus B (95 passengers). What is true?
7. Data displays and the mean as a fair share
CoreHumanRahul says: "The mean of 2, 4 and 9 can't be 5, because 5 isn't one of the numbers." Is he right?
8. Data displays and the mean as a fair share
StretchComputationalHelp Margaret. Complete fair_share(towers) so it returns the mean (total ÷ number of towers), and can_level(towers) so it returns True exactly when the towers can be levelled with whole cubes.
9. Data displays and the mean as a fair share
StretchHumanA list of data values are all between 3 and 9 (some may be equal to 3 or 9). Which of these could not be the mean?
10. Data displays and the mean as a fair share
StretchFormalLean proved fair_share: if moves turn the towers d into level towers of height m, then d.length * m = d.sum. (d.length is the number of towers and d.sum is the total number of cubes.) Which sentence says the same thing?
Things that trip people up
Misconception
Reading bar heights without checking the scale. A bar that reaches the 4th grid line stands for 4 only if each step is worth 1. If each step is worth 5, it stands for 20. Two graphs with different scales cannot be compared bar against bar.
Misconception
"Twice as tall means twice as much" — whatever the axis. That is only true when the axis starts at zero. With the axis starting at 40, a bar for 52 looks one and a half times as tall as a bar for 48.
Misconception
"The mean must be one of the data values." The mean of 4, 6, 8 and 2 is 5, which is not in the list. The mean can even be a fraction, like .
Misconception
"The mean is the middle number." The middle value of a sorted list is called the median, and it is often different from the mean. For 1, 2 and 9 the middle number is 2, but the fair share is .
Other ways of seeing
Physics— The mean is the balance point
Imagine the line plot as a light ruler with a small equal weight at the place of every dot. Where must you put your finger so that the ruler balances? Exactly at the mean. Physicists call this the centre of mass. For the values 2 and 8, the balance point is at 5; add a third weight at 8, and the balance point moves to 6, because . The heavier side pulls the balance point towards it — just as one very large value pulls the mean towards it.
Probability— A sample is not the whole story
Ms Wanjiku's class is only one class. If we asked another class, or the whole school, the bars would come out a little different. Statisticians study how much a sample can differ from the whole population, and how sure we can be about the whole from a part — see sampling and statistical reasoning.
Categories and totals
When every child gives exactly one answer, the categories split the class into groups with nobody left out and nobody in two groups. In the language of sets, the categories form a partition of the class. That is why the bar heights add up to the number of children — a rule from data, tallies and picture graphs. If children could choose two answers ("bus and walk"), the bars would add up to more than the number of children.
History and global context
- In the Andes of South America, Inca record-keepers stored counts of people, animals and goods on khipu, cords with knots — data recorded long before paper charts.
- The Scottish engineer William Playfair published some of the first bar charts and line graphs in The Commercial and Political Atlas (1786), showing trade between countries; he later introduced the pie chart (1801).
- Florence Nightingale used her "rose" diagrams (1858) to show that more soldiers in the Crimean War died from disease in badly run hospitals than from their wounds, and helped to change how hospitals were run.
- For the 1900 World's Fair in Paris, the African American scholar W. E. B. Du Bois and his students at Atlanta University made striking hand-drawn charts about the lives of Black Americans.
- In 1954 Darrell Huff wrote How to Lie with Statistics, a funny little book that warned readers about tricks such as bar charts with axes that do not start at zero.
For grown-ups: further reading
- Darrell Huff, How to Lie with Statistics (1954) — still the classic warning about misleading graphs and averages.
- Edward R. Tufte, The Visual Display of Quantitative Information (1983) — how to draw honest, clear graphs.
- Hans Rosling, with Ola Rosling and Anna Rosling Rönnlund, Factfulness (2018) — reading data about the world with care.