Unit 10 • Lesson 2

Labels and Honesty

Overview

A chart without units is a decoration, and a cut axis is an argument.

Intermediate 20–25 min

What You Will Learn in This Lesson

By the end of this lesson, you will be able to:

  • Say what every chart needs before it is readable.
  • Explain what a truncated axis does to a comparison.
  • State a comparison in words, with its size.
  • Recognise a choice that is making an argument for you.

Why This Matters

Every chart makes a claim. The labels are what let a reader check it, and the axis is what decides how big the claim looks. Neither is a styling question: a chart with no units and a zoomed axis can make a one per cent difference look like a crisis, without a single number being wrong.

Step 1: The label is part of the answer

A number with no unit is not information. The reader cannot tell pounds from thousands of pounds from a percentage.

1

What a chart needs

A title saying what it shows, both axes labelled with units, and a note of how many observations are behind it. Four things, and a chart missing any of them is asking the reader to guess.

# title:  "Mean exam score by team, 2024"
# y axis: "Mean score (out of 100)"
# x axis: "Team"
# note:   "n = 48 students"
print("the units are half the claim")
2

The claim in words

If you cannot write the sentence, the chart is not finished. The sentence needs the direction, the size and the comparison.

import pandas as pd

df = pd.DataFrame({"team": ["red", "red", "blue"], "score": [90.0, 80.0, 70.0]})
means = df.groupby("team")["score"].mean().round(1)
gap = round(float(means.max() - means.min()), 1)
print(f"{means.idxmax()} leads on {means.max()}, {gap} ahead of {means.idxmin()}")

Mini Practice #1: Write the sentence

Try It Yourself

Produce the means, then print a sentence naming the leader, its value and the gap.

Press Run to see output

Step 2: A truncated axis exaggerates

Starting a bar chart's axis at 80 rather than 0 makes a small difference fill the frame. It can be defensible; it is never neutral.

1

The same numbers, two impressions

85 and 82 differ by three and a half per cent. On an axis from 80 to 90 one bar is more than twice the other.

import pandas as pd

means = pd.Series({"red": 85.0, "blue": 82.0})
print(means)
print("real difference:", round(float(means.max() - means.min()), 1))
print("as a share of the smaller:", f"{(means.max() - means.min()) / means.min():.1%}")

full = means / 100
zoomed = (means - 80) / 10
print("bar heights on a 0-100 axis:", full.round(2).to_dict())
print("bar heights on an 80-90 axis:", zoomed.round(2).to_dict())

The numbers did not change. The picture did. If you truncate an axis, say so on the chart — and be sure the reason is that the detail matters, not that the difference looked small.

2

The other quiet arguments

A colour scale with an off-centre midpoint, a y-axis that is a rate in one panel and a total in the next, a time axis with uneven gaps. Each is a decision the reader will not see you make.

import pandas as pd

# Totals favour the big region; rates favour the small one.
df = pd.DataFrame({"region": ["big", "small"], "sales": [1000.0, 300.0], "people": [500, 50]})
df["per_person"] = df["sales"] / df["people"]
print(df)
print("by total:", df.loc[df["sales"].idxmax(), "region"])
print("by rate: ", df.loc[df["per_person"].idxmax(), "region"])

Mini Practice #2: How big is the difference, really

Try It Yourself

Print the absolute gap and the gap as a share of the smaller value, then decide whether it deserves a zoomed axis.

Press Run to see output

Step 3: When to Use It

Every chart you share

A title that states the finding, axis labels with units, and the data source.

Small differences that matter

A cut axis is acceptable when it is labelled clearly and the difference is the point.

When Not to Use It

Do not start a bar chart’s axis above zero. Bar length is the value, and a cut axis turns a 2% gap into what looks like double.

End-of-Lesson Exercises

Exercise 1: The headline sentence

Write headline(df) that returns a sentence of the form "red leads on 85.0, 15.0 ahead of blue", using the highest and lowest mean score per team.

Group to a mean per team, round to one place, then use idxmax and idxmin for the names. The gap is the difference between the two means.

Press Run to try it, then Check my work to mark it.

Exercise 2: How big is the gap, in context

Write gap_size(df) returning a two-element list of [the absolute gap between the highest and lowest team mean, that gap as a percentage of the lowest mean], both to one decimal place. The second number is what says whether the first one matters.

Group to means, take max and min, subtract for the gap, then divide the gap by the minimum and multiply by 100. Round both at the end.

Press Run to try it, then Check my work to mark it.