Visualization and Executive Storytelling
By the end: For a given analysis you choose the chart that fits the comparison, write a title that states the finding with a number, and add one interpretation limit that a careful reader would otherwise miss.
At a glance
Pick the chart for the comparison the reader must make, write the finding as the title, and check that the encoding and the aggregate do not change the reader's sentence.
Comparison first
Time, ranking, distribution, relationship or parts of a change: each has a default chart.
Title = finding
Finding + number + scope, as a sentence a director could repeat.
Honest encoding
Bars start at zero; small multiples share one axis.
Hidden splits
A flat total can be a fall and a rise; split by the segment you suspect.
SCIIA
Situation, complication, insight, implication, action, with the limit stated.
Recall
Without notes: a report joined flight results to all 13 booking-curve snapshots. Which of its tiles were wrong - total passengers, average load factor, revenue per passenger - and why did the others survive?
Concept
A chart is an argument with a picture attached. The reader gets about five seconds: they read the title, glance at the shape, and leave with one sentence. If the title only names the axes ("Bookings by month"), the reader writes their own sentence, often the wrong one. Start from the comparison the reader must make, then pick the chart.
Predict first
The network total is flat from March. What is the most likely reason the deck missed a story?
Text description of the figure
A chart editor with a chart-type selector, an axis-baseline toggle and a choice of titles for the same airline booking data. Switching from a single total line to small multiples by route group reveals opposite movements; starting a bar axis above zero visibly exaggerates a 6% drop. The widget uses its own seeded table, so its percentages differ slightly from the query's (for example -5.5% rather than -5.6%).
- What must the reader compare?before choosing a chart
- over timeLineindexed lines (base = 100) when levels differ
- a rankingSorted bars or dotshorizontal, largest first
- a distributionHistogram, box, ECDFtry several bin widths
- a relationshipScatterwith a reference line
- a breakdownWaterfall or driver treewhere it sits, not why
- by segmentSmall multiplesone shared axis
One comparison per chart. When the reader needs two, draw two panels rather than one chart that serves neither.
- Total by monthtwo lines, almost identical
- Segments may differ?
- yes: to Split by route group
no - Keep one lineand say the segments agree
- Split by route groupcompetitor routes vs the rest
- to Small multiples
rise capped? - Check capacityshare of flights at the limit
- to State the limit
- Small multiplesYoY bars, shared axis, 1 March marker
- State the limit+3.8% is a floor for demand
From March the network moved +0.4%. The reader concludes "flat".
Split by the segment you suspect, plot the change from a zero line, and mark the date that matters.
Contributions add up to the total: bookkeeping, not causes. Each bar says where the change sits, not why.
Seeded monthly bookings from the Day 8 chart critic (3 competitor routes, 8 other routes). The sample database tells the same story with slightly different numbers.
The deck's chart, the same data as change by segment on one axis, and where the change sits. Same numbers, three different first sentences.
- FindingBookings fell on three routes and rose on the rest.
- Number-5.6% and +3.8%.
- ScopeFrom March 2024; the three routes where competitors added seats.
- LimitUnder the chart: +3.8% is a floor, because more flights hit their limit.
The title is a claim, so it must be one the data support and no stronger. Timing is not a cause (Day 5).
Log scale: the exaggeration is not linear; it explodes as the axis start approaches the smaller bar.
A change metric has a natural zero. Bars from it are honest at any zoom, and both segments fit one axis.
Seeded monthly bookings from the Day 8 chart critic, March-December, competitor routes; the sample database gives slightly different totals.
Bars encode value by length, so moving the baseline changes the story. The lie factor grows without limit as the baseline approaches the smaller bar.
- Title = finding + number + scope: an insight-led title no stronger than the evidence.
- Honest encoding: bar axes start at zero (proportional ink); small multiples share one axis.
- Distortions need no bad axis: aggregation, selection, the calendar and capacity censoring.
- Structure the message with SCIIA: situation, complication, insight, implication, action.
Assumptions
The underlying numbers are already correct at the right grain (Days 6-7); design cannot rescue a fan-out or a data gap.
The reader's comparison is known; a chart designed for "which route grew most" fails a reader asking "is the network growing".
A title states an association unless a design supports a causal claim (Day 5); timing alone is not a cause.
Application and workplace decision
The deck's chart sums all routes by month. Run the query, which splits 2024 vs 2023 bookings by route group and period and adds how often flights hit their booking limit. Then (a) choose the chart, (b) rewrite "Bookings by month" as an insight-led title, and (c) write one interpretation limit for the slide.
SQL (airline sample database)
-- "Bookings by month" hides two segments. Compare 2024 with 2023 by route group and period.
-- Booking limit = capacity x 1.06 (the simulated airline's overbooking limit = max bookings seen per aircraft size)
WITH t AS (
SELECT CASE WHEN route IN ('IST-ADB', 'IST-AYT', 'IST-FRA') THEN 'competitor-added-seats'
ELSE 'other-routes' END AS route_group,
CASE WHEN substr(date, 6, 2) IN ('01', '02') THEN '1 Jan-Feb' ELSE '2 Mar-Dec' END AS period,
date >= '2024-01-01' AS is_2024,
bookings_final,
bookings_final >= CAST(capacity * 1.06 AS INTEGER) AS at_limit
FROM flight_day
WHERE date >= '2023-01-01'
)
SELECT route_group, period,
SUM(CASE WHEN is_2024 = 0 THEN bookings_final END) AS bookings_2023,
SUM(CASE WHEN is_2024 = 1 THEN bookings_final END) AS bookings_2024,
ROUND(100.0 * SUM(CASE WHEN is_2024 = 1 THEN bookings_final END)
/ SUM(CASE WHEN is_2024 = 0 THEN bookings_final END) - 100, 1) AS yoy_pct,
ROUND(100.0 * AVG(CASE WHEN is_2024 = 0 THEN at_limit END), 1) AS pct_at_limit_2023,
ROUND(100.0 * AVG(CASE WHEN is_2024 = 1 THEN at_limit END), 1) AS pct_at_limit_2024
FROM t
GROUP BY route_group, period
ORDER BY route_group, period;
Mini-assessment
Technical depth
Perceptual encoding theory: why position beats length beats areaThe ranking of elementary perceptual tasks, Stevens' power law and Weber's law, and what each implies for the chart you draw.
- 1. Position, common scaledot plot, aligned bars: conversion rate by channel
- 2. Position, nonalignedsmall multiples, stacked segments: claims by region
- 3. Length, direction, angleunaligned bars, slopes, pies: fine for 2-3 slices only
- 4. Areabubbles, treemaps: store revenue as bubble size
- 5. Volume, curvature3D columns of telecom subscribers
- 6. Shading, saturationheatmaps, choropleths: patterns yes, values no
Cleveland and McGill (1984); their experiments supported position over length and angle, the rest is a hypothesis, and spacing is schematic. Position wins because two points are read against one ruler; each step down the ranking adds a judgment. Put the title's comparison as high in the ranking as the data allow; use colour to group or highlight.
- the physical magnitude drawn: a length, an area, a volume
- the magnitude the reader perceives (Stevens' power law)
- close to 1 for length (judgments roughly unbiased), below 1 for area and lower still for volume: big marks look smaller than they are
- Weber's law: the difference detected with probability p grows in proportion to the length x being judged
- a constant that does not depend on x; small differences between long bars are therefore hard to see
Both laws as summarised by Cleveland and McGill (1984). With alpha below 1 an area chart understates ratios; Weber's law is why you plot a small change from a zero line instead of asking readers to compare two long bars.
Values 2, 4, 8 in every row. Dots and bars are read against one scale; circles must be compared by area, the weakest of the four tasks drawn.
A mark 4 times larger is perceived 2.64 times larger at alpha = 0.7 and 2.00 times at 0.5. Length judgments sit near alpha = 1, which is why bars and dots carry the number the title is about.
Illustrative values. The power law and the ordering of tasks are from Cleveland and McGill (1984); the alpha values 0.7 and 0.5 are examples of “below 1”, not measured constants - they vary by person and experiment.
Left: values 2, 4, 8 as dots, bars, area-scaled and radius-scaled circles. Right: the power law turns a true ratio into a perceived one; only alpha near 1 reads true.
The eye compares two lengths of about 300; a 2% step at the top is close to the threshold of what anyone notices.
Same data, same honest zero baseline; now the finding is the length being judged, not a sliver on top of it.
Illustrative values 300 and 306. Weber’s law as summarised by Cleveland and McGill (1984): the just-noticeable difference grows in proportion to the length judged.
Weber's law in practice. Between two long bars the 6 is 2% of the length and nearly invisible; drawn as its own bar from a zero line it is the whole mark. Chart the change when the change is the finding.
The lie factor, derived and computedTufte's definition, the one-line derivation for a truncated bar axis, and two charts worked by hand: a SaaS line of users and a clinic bubble chart.
- the first and second value in the data; each effect is measured relative to the first one
- where the bar axis starts; the drawn lengths are v_1 - c and v_2 - c
- the graphic changes exactly as much as the data; c = 0 always gives 1 for bars
- the size of the difference cancels: distortion depends only on how close the axis start sits to the first bar, and explodes as c approaches v_1
- a quick review test: once the axis starts above half the first value, a bar chart's lie factor is already above 2
The derivation is two lines: the numerator and denominator share |v_2 - v_1|, so what is left is the ratio of the first bar's true value to its drawn length.
| Step | By hand | Value |
|---|---|---|
| Data: monthly active users | 48,000 in May, 52,000 in June | - |
| Effect in data | (52,000 - 48,000) / 48,000 | 8.3% |
| Axis from 45,000: drawn lengths | 48,000 - 45,000 and 52,000 - 45,000 | 3,000 and 7,000 |
| Effect shown | (7,000 - 3,000) / 3,000 | 133.3% |
| Lie factor | 133.3 / 8.3, or directly 48,000 / (48,000 - 45,000) | 16.0 |
| Bar-length ratio, same chart | 7,000 / 3,000: compares the two drawn bars, not the drawn change with the real one | 2.33 - a different number; say which you report |
| Axis from zero | lengths 48,000 and 52,000 | 1.0 |
| Clinic visits 100 vs 200, circle radius set to the value | area grows 4x: effect shown 300% for a 100% effect | 3.0 |
| Same clinics, circle area set to the value | area grows 2x | 1.0 drawn, still under-read (alpha < 1) |
Hypothetical numbers, verified in Python. A chart can be numerically honest (LF = 1) and still be decoded badly: the last row is the case for position and length over area. Lines and dots encode by position, so a zoomed line has no lie factor; it only needs a labelled range.
Choosing the chartThe comparison decides the chart; the encoding decides how precisely it can be read.
| Criterion | Bars | Lines | Dots |
|---|---|---|---|
| Encodes value by | Length from a baseline | Position and slope | Position |
| Axis must | Start at zero | May zoom, labelled clearly | May zoom, labelled clearly |
| Best for | Comparing amounts and changes from zero | Change over time | Rankings and many categories |
Direct labels beat legends; units go in the axis title; remove ink that carries no data.
Honest axesWhy a truncated bar axis inflates a 6% drop several times over, and when a zoom is fine.
Bars encode value by length, so a truncated axis multiplies the visual difference. Lines and dots may zoom, if the axis says so.
| Chart | Start at zero? | Why |
|---|---|---|
| Bars, areas | always | length and area are the value; a cut baseline multiplies differences |
| Lines, dots | not required; label the range | position is read relative to other points, not to zero |
| Change or difference | the zero line is the reference | draw bars from it; signs stay visible |
| Ratios and growth over orders of magnitude | log scale | equal distances mean equal ratios |
| Two series, two units | avoid dual axes | two free scales let any two lines cross where the designer wants |
Practitioner rules consistent with proportional ink (Wilke, chapter 17). The question is never zoom or no zoom; it is whether the encoding is length.
Show the distribution, not only its meanIdentical summaries can hide a tail, a second group or a few disasters.
A summary chart answers only the question its summary answers. Here it says “the stations are alike”.
Show the distribution when the reader’s question is about typical cases, tails or groups; a mean bar hides all three.
Seeded synthetic delays, 120 flights per station, each rescaled to mean 18 and SD 9 minutes exactly; red tick: median.
Bars of a summary statistic answer one question. Dots show whether the typical flight, the tail or a second group is the story: few points, show every dot; many, a box or violin per group. Anscombe (1973) and Matejka and Fitzmaurice (2017) built whole datasets on this trick.
one lump: the two groups merge
two peaks: the real structure
spikes: noise that looks like shape
Seeded synthetic delivery times: 300 orders from two groups (60% around 21 minutes, 40% around 34). "Peaks visible" counts bins that stand clearly above both neighbours.
Histogram shape depends on the bin width: too wide merges two groups into one lump, too narrow turns noise into peaks. Try several widths before you trust or report a shape (Wilke, chapter 7).
Distortions without a bad axisAggregation, selection, calendar and capacity, each with today's example.
Aggregation
A flat total over a rise and a fall; split before concluding.
Selection
Only stores that survived, only loans that were approved, only routes still flown.
Calendar
A leap day or a moved holiday fakes growth: about 1.7 points in Jan-Feb 2024.
Capacity censoring
Sales are a floor for demand when shelves empty, clinics book out or flights fill.
Bar length shows size; the value shows the sign. A flat total hid a fall and a rise (airline sample database, synthetic).
When more flights fill, bookings understate demand growth (Day 28 estimates unconstrained demand).
Writing the title and the limitFinding, number, scope, and a verb no stronger than the evidence.
Describe: rose, fell, flat
Any correct aggregate supports it, at the stated grain and scope.
Compare: higher on, lower than
Needs a like-for-like comparison: same days, same mix, same population.
Associate: moved with, coincided with
Timing or correlation; say so, and name the obvious alternative.
Cause: drove, caused, because
Needs a design (Day 5): randomization, a credible control group, a break.
Bound: a floor or a ceiling
When the measure is capped or incomplete, say on which side the truth lies.
Rule out: changed by less than
A null result says what the data exclude: 'changed by less than 2 points' is a finding; 'no impact' is not.
Most overclaiming titles are one rung too high on this ladder. Lowering the verb keeps the finding and drops the unsupported part.
Uncertainty and colouradvancedError bars that say what they are, and colour that every reader can decode.
Say what the bars are
SD shows spread of the units (patients, orders); SE or a CI shows precision of an estimate. Label which.
Error bars read as limits
Readers often take them as minimum and maximum. Prefer a sentence plus a band.
Dots for many points
Overplotting hides density: transparency or binning, and jitter only a little.
Null results
Show the interval and the decision threshold on one axis.
From Wilke, chapters 16 and 18.
About 8% of men
have a colour-vision deficiency, most often red-green: never encode good or bad by red versus green alone.
Few categories
Beyond about eight colours the legend becomes a lookup task; label lines directly.
Diverging scales
Need a meaningful midpoint, such as zero change or a 50% threshold.
Rainbow scales
Are not ordered in lightness and invent boundaries in smooth data.
From Wilke, chapters 4, 19 and 20. Redundant coding (colour plus a label or shape) survives greyscale printing and every viewer.
The two-minute storySCIIA applied to "is the network growing?".
Situation
Network bookings +1.3% in 2024.
Complication
Flat from March.
Insight
Competitor routes -5.6%, the other eight +3.8% and increasingly capped.
Implication
Lost share on three routes; unserved demand on the rest.
Action
Pricing review on the three routes; unconstrained demand before the summer plan.
Memory anchor
Comparison first, chart second, finding in the title, limit next to the claim.
Useful for
Weekly and monthly business reviews where a chart must change a decision in a few seconds - retail sales, SaaS activation, hospital capacity.
Turning an analysis into a one-page note or slide with a defensible headline and its limit, for example a churn or claims-cost update.
Reviewing a colleague's deck for axis, aggregation and selection distortions before it goes to leadership.
Not suitable for
Exploratory analysis - EDA charts are for you, can be many and rough, and should not carry polished headlines too early.
Settling a causal question - a clear chart of a timing association still needs a design (Day 5) to support "because".
Traps
A title stronger than the evidence
"Demand stopped growing" from capped bookings or out-of-stock retail sales, or "the competitor's price cut took our customers" from timing alone, gets repeated as fact and drives capacity or pricing decisions.
How to avoid it
Write what the data show (bookings, association, segment), then the limit; reserve causal verbs for causal designs.
The flat total
Opposite movements in segments cancel in the aggregate, and the deck reports stability while both segments need action.
How to avoid it
Before calling a total flat, split it by the one or two segments most likely to move differently.
Senior reasoning
A senior starts from the decision and the reader's comparison, not from the chart library. They write the headline first, test it against the strongest objection ("is that demand or bookings?", "which routes are missing?"), and put the limit next to the claim rather than in a footnote. They prefer two plain panels on a shared axis to one clever chart, and they say what a null or mixed result rules out instead of calling it "no change".
Interview question
"Present this analysis to our CFO in two minutes." What structure do you use, and what do you leave out?
Recall cards scheduled after completion
- Name the default chart for change over time, ranking, distribution, relationship, parts of a change, and the same comparison across segments.
- Name four ways a correctly drawn chart can still mislead.
Prerequisites and related concepts
- Joins and join explosions · day 7
- Hypothesis-driven EDA · day 6
- Selection and survivorship bias · day 5
- Confounding · day 5
- Chart choice
- Insight-led titles and storytelling
- Misleading charts and interpretation limits
- Driver and contribution analysis
- Simpson's paradox · day 5
- Capacity-censored demand · day 28
References
- Fundamentals of Data Visualizationcore
Proportional ink (bars start at zero; dots and lines encode by position), titles that state the point of a figure, small multiples, and building a story arc across figures. (Chapters 17, 21, 22 and 29)
- The Visual Display of Quantitative Information (2nd edition)optional
Data-ink and graphical integrity - removing non-data ink and detecting graphical deception (the lie factor in the axis illustration).
- Fundamentals of Data Visualization, chapter 16: Visualizing uncertaintyoptional
State what error bars show (SD, SE or a confidence interval and its level); readers often take them as hard limits.
- Fundamentals of Data Visualization, chapter 19: Common pitfalls of color useoptional
Too many qualitative colours, rainbow scales, and designing for colour-vision deficiency.
- Fundamentals of Data Visualization, chapter 7: Visualizing distributions, histograms and density plotsoptional
Histogram shape depends on bin width; explore several before trusting a shape.
- Graphical Perception: Theory, Experimentation, and Application to the Development of Graphical Methodsoptional
The ordering of elementary perceptual tasks (position, length, angle, area, volume, shading), Stevens' power law and Weber's law applied to graphs. (Section 3 (theory: ordering the elementary perceptual tasks))
- Same Stats, Different Graphs: Generating Datasets with Varied Appearance and Identical Statistics through Simulated Annealingoptional
Datasets with identical summary statistics and very different plots - why the distribution must be shown.
Optional sections
Deep dive
Driver analysis and waterfalls. When the question is "what made the total change", decompose: total change = sum of segment contributions (here -18,627 bookings on the competitor routes and +23,349 on the others from March). A waterfall shows each contribution as a step from the old total to the new one; a driver tree splits a KPI into multiplicative parts (revenue = flights x seats x load factor x fare). Both are additive bookkeeping, not causal attribution - each bar says where the change sits, not why it happened.
Indexed trends. To compare routes of very different size, index each series to 100 in a base period. Choose the base deliberately: an unusual base month makes every later point look like growth or decline.
Null and mixed results. "The new booking page had no effect" is rarely what a test shows. Say what it rules out: "the conversion change was +0.4 points, and the data are consistent with anything from -0.6 to +1.4 points; we can rule out the +2-point lift the business case assumed." That keeps a useful result from being filed as a failure, and it ties back to interval reading on Day 4.
Executive structure without frameworks. Situation-Complication-Insight-Implication-Action is a generic narrative order, not a proprietary method. Its value is discipline: every slide must say what is known, what is surprising, what explains it, what it means and who does what next. If a slide cannot fill "Action", it is backup.
Hands-on lab: Build the small multiples and measure an axis distortion
The script draws the two-panel chart in memory (no file is written) from the monthly year-on-year changes the sample database gives for each route group, then measures how much a truncated bar axis would exaggerate the March-December drop. Then:
- Change
sharey=TruetoFalse. What false impression does the right panel now create? - Replace the bars with one line per group on a single panel. Which comparison gets easier and which harder?
- Write the one-sentence limit you would put directly under the title.
import io
import matplotlib.pyplot as plt
# Monthly 2024-vs-2023 booking change (%) from the sample DB (synthetic airline), by route group
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
yoy = {
"Competitor added seats (ADB, AYT, FRA)": [6.0, 8.6, -8.4, -4.7, -3.1, -2.4, -5.5, -3.4, -8.4, -7.2, -8.0, -5.3],
"Other 8 routes": [4.7, 4.9, 4.5, 6.1, 1.6, 2.6, 2.8, 3.2, 5.2, 3.9, 6.6, 2.3],
}
fig, axes = plt.subplots(1, 2, figsize=(10, 3.5), sharey=True) # small multiples on ONE shared y-axis
for ax, (name, values) in zip(axes, yoy.items()):
ax.bar(months, values, color=["#b5b5b5" if v >= 0 else "#c0392b" for v in values])
ax.axhline(0, color="black", linewidth=0.8) # zero line: the reference for a change metric
ax.axvline(1.5, color="grey", linestyle=":", linewidth=1) # 1 March: competitor capacity step
ax.set_title(name, fontsize=10, loc="left")
ax.tick_params(axis="x", labelsize=8)
ax.spines[["top", "right"]].set_visible(False)
axes[0].set_ylabel("Bookings vs same month 2023 (%)")
fig.suptitle("From March, bookings fell on the three routes where competitors added seats and grew elsewhere",
fontsize=11, x=0.01, ha="left")
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=100) # rendered in memory, no file written
lo, hi = axes[0].get_ylim()
print(f"rendered small multiples ({buf.getbuffer().nbytes > 0}); shared y-axis from {lo:.1f} to {hi:.1f} %")
# How much would a truncated bar chart exaggerate the Mar-Dec drop on the competitor routes?
b23, b24, axis_start = 333898, 315271, 300000
data_ratio = b23 / b24
ink_ratio = (b23 - axis_start) / (b24 - axis_start)
print(f"data ratio 2023/2024: {data_ratio:.3f}; bar-length ratio with axis at {axis_start:,}: {ink_ratio:.2f}")
print(f"exaggeration factor: {ink_ratio / data_ratio:.1f}x")
Interview practice
A retail stakeholder wants a dual-axis chart: units sold (bars, left axis) and average selling price (line, right axis) by month, "to show that higher prices cause lower sales". How do you respond?