From Exploratory Plot to Communication Figure
Lecture · Module 3 · Mon Aug 31
How today works
This page is your roadmap for today’s class.
Some parts are self-paced: you’ll think on your own, try something in R, or talk briefly with a neighbor. Other parts are whole-class moments: we’ll pause, look up from our screens, and work through an idea together.
Whole-class moment
When you see a box like this, pause what you’re doing and look up. We’ll work through the idea together as a class.
Today’s class has four big phases:
- We’ll start with the Datasaurus Dozen — a hands-on discovery that settles, once and for all, why you plot at all. You will make the discovery yourself, with a partner.
- We’ll then take apart a published chart, naming the grammar-of-graphics layers that built it — aesthetic mappings, geoms, scales, labels — using the vocabulary from the M03 Module and Friday’s pre-study.
- We’ll use Dr. Alberto Cairo’s five qualities of effective data visualization to decide what separates a competent chart from a truly effective one — scoring that same chart, then digging into the hardest of the five on a real case.
- We’ll introduce Cole Nussbaumer Knaflic’s design moves for turning a chart into a clear data story.
At the end, you’ll sketch the first chart you would make from your own research data and share your thinking with a neighbor.
What’s pre-loaded in every WebR chunk on this page
Every chunk on this page already has tidyverse, scales, datasauRus, and ggrepel attached, plus inequality_tidy (after-tax Gini for 5 countries, 1990–2023) in memory, and the site-wide ggplot theme set. You don’t need to write library() or read_rds() — just pipe straight into ggplot().
Why plot at all?
Everything else today — what makes a chart good, how to build a good one — assumes you have accepted that you must make one. So we start there.
The temptation, especially as the statistical machinery gets more sophisticated, is to skip the picture and go straight to the numbers. The next twenty minutes exist to argue otherwise — and you’ll be the one making the discovery, with your partner.
The setup: an R package called datasauRus ships 13 different datasets in one tibble called datasaurus_dozen. Each dataset has two variables, \(x\) and \(y\), and the same number of observations. Here’s a peek at the structure:
You should see 13 dataset names — dino, away, h_lines, v_lines, x_shape, star, high_lines, dots, circle, bullseye, slant_up, slant_down, wide_lines.
Activity 1 · compute summary stats for one of them
In the chunk below, change "dino" to any of the 13 dataset names, then click Run Code:
Going further · curious what that code is actually doing?
You do not need to know today — the activity works whether or not you read a line of it. But if you want it unpacked, it is a sneak peek at the workflow M05 teaches in depth, and the same pattern returns every time you summarize data in R.
Read it as two steps connected by the pipe |>:
Move 1 · narrow the data. filter(dataset == my_dataset) keeps only the rows where the dataset column matches the name you assigned to my_dataset. With 13 stacked datasets in datasaurus_dozen, this is how you isolate just one of them.
Move 2 · collapse to a summary. summarize() takes whatever rows came out of Move 1 and collapses them into a single row of summary numbers. Each line inside summarize() is the shape <new column name> = <function of the data>, and creates one column in the output:
| Line | What it computes |
|---|---|
| n = n() | Count of rows after filtering — the same for any dataset you pick, which is part of the trick. |
| mean_x = round(mean(x), 2) | Arithmetic mean of the x values, rounded to 2 decimals. |
| sd_x = round(sd(x), 2) | Standard deviation of the x values (a measure of spread), rounded to 2 decimals. |
| mean_y = round(mean(y), 2) | Mean of y. |
| sd_y = round(sd(y), 2) | Standard deviation of y. |
| corr_xy = round(cor(x, y), 2) | The Pearson correlation between x and y — a number from \(-1\) to \(+1\) summarizing the direction and strength of their linear association. Near \(0\) means little linear pattern. It does not mean the two variables are unrelated — hold onto that, because it is about to matter. |
The output is a one-row tibble with six columns — the row count plus the five summary statistics. A tibble is the tidyverse’s data-frame class; whether a dataset is tidy is a separate question about how its observations and variables are arranged, which M04 takes up formally.
What you see should raise questions. Every dataset has essentially the same five summary statistics: mean(x) ≈ 54.27, sd(x) ≈ 16.77, mean(y) ≈ 47.83, sd(y) ≈ 26.94, and corr(x, y) ≈ -0.06. To two decimal places — they’re identical. If you used only the summary numbers to write up these datasets, you’d describe all 13 in the same paragraph.
Activity 2 · plot the dataset you picked
So the summary stats are the same. What about the data themselves?
Now run the chunk. Use the same dataset name you picked above:
- The plots should look completely different from each other, even though the summary statistics are identical.
- Look at what those shapes actually are — circles, stars, clusters, curves. Several are strong structures with a correlation near zero, because a Pearson correlation only measures the linear part of a relationship. It isn’t lying to you; it’s answering a narrower question than you asked.
- Finish this sentence together: “The same numerical summaries can hide ___.” (Shape. Clusters. Curvature. Gaps. Outliers.)
The reveal — all 13 at once
Here are all 13 side by side, so the absurdity of “same summary statistics” lands in full:
The lesson, written out
If you only inspect the summary statistics, you will be wrong about your data — sometimes spectacularly wrong. The Datasaurus Dozen is engineered to make the point, but real data does this all the time, just less theatrically. Modes, gaps, ceiling effects, bimodality, censoring, recording errors, single-value-dominance — every one of these is invisible at the level of the mean. The only reliable way to see them is to plot.
So the first move of every analysis you do this semester is: load the data, look at the structure, plot it. Then summarize. Then model. Plot first. Always.
(The Datasaurus is famous, but the underlying idea is older. Anscombe’s quartet — 1973 — made the same point with four datasets instead of 13. Matejka & Fitzmaurice (2017) extended it as a proof that the trick generalizes.)
Taking apart a chart in the wild
So plotting is not optional. The next question is what a serious plot is actually made of.
On Friday you built a Rosling-style chart one layer at a time, and by Activity 2.5 you had the whole skeleton in your hands: data piped into ggplot(), variables mapped inside aes(), a geom, a scale, labels. You now know enough to read someone else’s chart the same way.
The chart below was not made for a class. It was made by a professional data-visualization designer, published, and shared with its source code. Before we talk about what makes a chart good, we are going to take this one apart and name its pieces.
Where this chart comes from
TidyTuesday is a weekly social data project run by the Data Science Learning Community. Every Tuesday a new dataset is posted, and people around the world build something from it and share both the chart and the code that made it. It is one of the best places to see what working data visualization actually looks like.
The dataset behind this chart is from Opportunity Insights — anonymized tax records linking where students came from economically to where they ended up. It reached a wide audience through the New York Times Upshot piece “Some Colleges Have More Students From the Top 1 Percent Than the Bottom 60” — worth a look before or after class as background on the question the data was built to answer.
You will meet this project again: the college-mobility data behind our confidence-interval and hypothesis-testing work in M07 and M08 comes from the same source.
Graphic by Nicola Rennie, reproduced under CC BY 4.0. Data: Opportunity Insights.
| # | Layer | In this chart | The code that does it |
|---|---|---|---|
| 1 | Data | One row per college × parent-income band. Six school tiers collapsed into three; rows with missing values dropped. | select() → drop_na() → mutate() |
| 2 | Aesthetics | x = ratio of relative attendance to relative application · y = parent income band · color = school group | aes(x = rel_att_cond_app, y = par_income_lab, colour = tier) |
| 3 | Geometry | One dot per college, nudged sideways so overlapping dots stay countable | geom_beeswarm() |
| 4 | Facets | Not used. Every college sits in one panel. | — |
| 5 | Statistics | Not used. These are raw observed values — nothing averaged, smoothed, or modeled. | — |
| 6 | Scales | Income bands reversed so the lowest sits at the top; three hand-picked colors instead of the defaults | scale_y_discrete(limits = rev), scale_colour_manual() |
| 7 | Coordinates, labels, themes | Title, subtitle, axis titles, source caption; minimal theme, warm background — and the legend switched off | labs(), theme_minimal(), theme(legend.position = "none", …) |
Whole-class · one thing that should bother you
Color is clearly mapped to a variable — the dots come in three colors. So where is the legend?
Find where the reader is actually told what pink, gold, and teal mean. Then: was that a good decision, or a risky one?
The code that made it — read this after class
We are not walking through this in the room. It is here so that later, at your own pace, you can see that the thing separating your Friday chart from a published one is not a different language — it is the same seven layers, with a lot of deliberate polish stacked on layer 7. The full code is on the author’s GitHub. None of it is on any assessment.
ggplot(
data = plot_data,
mapping = aes(
x = rel_att_cond_app,
y = par_income_lab,
colour = tier
)
) +
geom_beeswarm(size = 0.5, cex = 0.6, alpha = 0.7) +
scale_y_discrete(limits = rev) +
scale_colour_manual(values = c("#D1495B", "#EDAE49", "#00798C")) +
labs(
title = title,
subtitle = st, # the colored-text sentence that replaces the legend
caption = cap,
x = "Ratio of relative attendance rate to relative application rate",
y = "Parent\nIncome\n(Percentile)\n"
) +
theme_minimal(base_size = 22, base_family = body_font) +
theme(
legend.position = "none", # <- the legend, switched off
plot.background = element_rect(fill = bg_col, colour = bg_col),
plot.title.position = "plot",
plot.title = element_textbox_simple(face = "bold", size = rel(1.7)),
plot.subtitle = element_textbox_simple(lineheight = 0.5),
panel.grid.major.x = element_blank(), # <- vertical gridlines removed
panel.grid.major.y = element_line(linewidth = 0.3, colour = alpha(text_col, 0.3))
# ...roughly 20 more lines of theme() fine-tuning
)Strip the polish away and what is left is the shape you already know:
data |>
ggplot(aes(x = ..., y = ..., colour = ...)) +
geom_*()A practical note. Three of the packages behind this chart — ggbeeswarm (the dot-spreading geom), showtext (the Google font), and the designer’s own personal branding package — are not installed with the course packages, so this script will not run as-is on your laptop. ggtext, which draws the colored subtitle, is one of ours.
You have, in your hands right now, the syntactic skeleton for every chart you will make this semester. Today is not about mastering new syntax — you’ll see a fair bit of it in the worked examples below, and M04 and M05 teach it properly. Today is about deciding what to put in those blanks — and why. Read the new code for the design move it makes, not to memorize it.
Today’s premise
Two things are now settled: you have to plot, and a plot is made of nameable parts. That leaves the question today is really about — once you’ve plotted, what makes one chart good and another bad?
Most chart-making advice you’ll see online lives at the level of taste — “use these colors,” “this font,” “don’t 3D pie charts.” That’s practical, but it doesn’t tell you why one chart works and another doesn’t. Two design vocabularies make the why explicit. We’ll work with both today.
- Dr. Alberto Cairo’s five qualities — a checklist of what an effective chart should be. Useful for diagnosing whether a finished chart is doing its job.
- Cole Nussbaumer Knaflic’s design moves — a sequence of actions a designer takes when creating a chart. Useful for producing a chart that does its job in the first place.
Cairo tells you what to check. Nussbaumer Knaflic tells you what to do.
Cairo’s five qualities
Alberto Cairo — a journalist-turned-information-design professor at the University of Miami — proposes in The Truthful Art that an effective visualization should be all five of the following:

- Truthful — based on thorough, honest research. No misleading axes, no cherry-picking, no visual tricks that don’t reflect the data.
- Functional — an accurate depiction of the data that lets the reader do meaningful operations on it (compare two groups, see a trend, identify an outlier).
- Beautiful — attractive, intriguing, aesthetically pleasing to the intended audience. Not the same as “pretty” — appropriate aesthetics for a scientific audience are not the same as for the general public.
- Insightful — reveals evidence that would be hard or impossible to see in the raw numbers.
- Enlightening — if a reader grasps and accepts the chart’s evidence, it should change their mind about the question at hand.
A chart that is truthful, functional, and beautiful — but not insightful — is still a failure, because it tells the reader nothing they didn’t already know. A chart that is insightful, enlightening, and beautiful — but not truthful — is worse than a failure; it’s a lie.
Back to the college-admissions chart
We now have the vocabulary we were missing a few minutes ago. Scroll back up to the college-admissions chart — we named its layers, but we had no language for whether it was any good. Let’s score it together before you score anything else.
Whole-class · score the opening chart
Five qualities, quick verdicts, out loud. Where does it clearly succeed? Where would you push back?
Do not assume the answer is five checkmarks. It was chosen as a well-made chart, not a perfect one.
| Quality | Verdict | Why |
|---|---|---|
| Truthful | ✓ | The axis starts at 0 and is proportional. Every college appears — nothing is filtered to flatter the story. The source is named in the caption. |
| Functional | ✓ / ? | You can compare distributions across income bands easily. But reading a single value is hard, and the x-variable — a ratio of a relative rate to another relative rate — takes real work to interpret. Functional for whom? For a data-literate audience, yes. For a general newspaper reader, arguably not. |
| Beautiful | ✓ | Restrained palette, generous whitespace, no chartjunk, no legend box competing for attention. The aesthetics fit the audience. |
| Insightful | ✓ | The widening spread in the top income bands is genuinely hard to see in a table of numbers. The chart earns its space. |
| Enlightening | ? | This is the weakest one — and the designer is honest about it. The subtitle hedges: income “appears to be somewhat correlated” with acceptance, “though variability also increases.” A chart that changes your mind states what it found. This one reports a pattern and lets you decide. |
That is the useful lesson, and it is not “the chart is bad.” It is very good. But truthful and beautiful are the qualities charts most often achieve, and enlightening is the one they most often miss — because it depends on having something to say, not on design skill. Hold that in mind for the next fifteen minutes.
Nussbaumer Knaflic’s design moves — a worked makeover
Cole Nussbaumer Knaflic’s Storytelling with Data turns chart design into a six-step process. Each step is a move you make on top of a workable rough draft:

- Understand the context — who’s reading, what do they already know, what action do you want them to take?
- Choose an appropriate display — line, bar, scatter, table; the choice flows from the question, not your tools.
- Eliminate clutter — every pixel that isn’t carrying meaning is hurting the chart.
- Focus attention — color, size, and contrast direct the eye to the finding.
- Think like a designer — alignment, whitespace, hierarchy of typography.
- Tell a story — title-as-finding, annotation as narration, captions that situate.
Two of those six happen before you write any ggplot: understand the context is the audience question, and choose an appropriate display is the line-vs-bar-vs-scatter decision. Moves 3 through 6 are the ones you can see in code — so here is what they add up to, on one dataset: after-tax income inequality (the Gini coefficient) for five countries, from TidyTuesday’s August 2025 release.
This is a bare-bones ggplot() — three lines of code, all five series on screen. It is a perfectly good exploratory chart: you can see the broad pattern, spot the outlier series, and check that nothing looks broken. What it is not is designed for a particular reader or a particular takeaway. That’s the gap the next four tabs close.
(One note on the code: this page sets a clean theme for every chunk, so we ask explicitly for theme_grey() — R’s real default — to show you the actual starting point.)
The gray panel and minor gridlines aren’t carrying meaning — they’re just noise. Drop them. Same data, same lines; less for the eye to filter.
Five equally-weighted colors give the eye nowhere to land — not because five is too many in principle, but because nothing in the design says which comparison carries the story. Our takeaway is about the United States, so we color that series and mute the rest. The design choice follows from the purpose, not from a rule about line counts.
Notice what the previous tab cost us: suppressing the legend told the reader which line matters, but it also left the four gray comparison lines unidentified. Rather than restore a separate key — which would force readers to bounce between chart and legend, and would give equal billing to all five — put each country’s name directly at the end of its own line.
This is the move you already met on the opening chart of Monday’s lecture, where the designer put the three group names, in their own colors, inside the subtitle.
The last move pulls everything together: a title that states the finding, a subtitle that names what’s measured and across what years, a source caption, and one annotation in the chart itself that narrates the takeaway. This is the chart that goes in a research talk.
Whole-class · name the moves
Click between the tabs. Every difference you can see is one of moves 3–6. Call them out:
- What got removed? (move 3)
- What got emphasized, and what faded? (move 4)
- Where did the legend go? (move 4 again — and it is the same trick the opening chart used)
- What does the reader now know before they look at a single line? (move 6)
Whole-class · name the moves
Click between the two tabs. Every difference you can see is one of moves 3–6. Call them out:
- What got removed? (move 3)
- What got emphasized, and what faded? (move 4)
- Where did the legend go? (move 4 again — and it is the same trick the opening chart used)
- What does the reader now know before they look at a single line? (move 6)
Going further · the makeover as a page you can break
The Knaflic makeover, standalone →
You have now seen all five versions, so that page is not there to re-teach them. It carries two things we did not do together:
- Four break-it-yourself prompts. Swap which country gets the highlight color and see whether the story survives. Delete the annotate() block and judge how much work that one sentence was doing. Put the legend back and compare it against direct labels. Retitle the chart descriptively — “Gini coefficient by country, 1990–2023” — and notice what the reader now has to work out alone.
- The dataset’s coverage caveats — which countries report in which years, and why some axes come out looking pre-labeled. Useful if you ever reuse inequality_tidy.
Every chunk there is runnable, which makes it a better place to experiment after class than during it.
Title-as-finding · the rule you’ll use all semester
A chart title should be a declarative sentence that states what the chart shows — not a description of what’s on the axes. Compare these two titles for the Rosling chart from M03:
- ❌ Descriptive: “Life expectancy vs. GDP per capita by region, 2022”
- ✅ Finding: “Countries with higher GDP per capita have higher life expectancy — a tenfold difference is associated with about a decade”
The descriptive title makes the reader work. The finding title rewards them immediately. Every communication figure you submit from M03 onward should have a finding-title — and you write it after inspecting the data, never before, because the title has to be something you’ve actually verified. Exploratory and diagnostic plots are a different case: a plain descriptive label is fine there, and journal formats often put the takeaway in the caption or the text instead. The rule underneath all of it is simply that the title should fit the figure’s purpose and never claim more than the evidence supports.
Apply it to a question you care about
Cairo and Nussbaumer Knaflic matter most when they help you communicate something you want to understand — so we are going back to the question you already wrote.
Last Monday you posed a research question, named its type of inquiry, specified a population, and said how you would measure your variables. Have that Week 1 discussion post open. For the next 15 minutes you are going to do the next thing a researcher does with a question: draw the figure that would answer it.
Two surfaces, two jobs. The boxes on this page hold the words — your question, your variables, your prediction — and they are there so the wording stays in front of you while you work. The drawing happens on paper, in marker. Nothing on this page is saved when you refresh it; the sketch is what you keep.
You do not need a completed study, a dataset, or even a fully settled question — the Week 1 version is exactly the right starting point. This is the step where a question stops being a sentence and starts having a shape.
Wrap-up · three things to carry into the lab
Three things to carry into Wednesday’s lab
- Never let a summary stand in for a look. The Datasaurus rule. Means, SDs, and correlations are real information — they are just incomplete, and what they omit is exactly what a plot shows. Use both, and plot early enough that the picture can still change your mind.
- Chart design is editorial. Every encoding decision (axis, color, geom, theme) is a small editorial choice about what to emphasize and what to fade. Cairo’s five qualities let you check that the editorial decisions add up to a finding. Nussbaumer Knaflic’s six moves let you produce that finding.
- For communication charts, make the takeaway easy to find. A supported, finding-oriented title is the simplest way to do it — written after you’ve checked that the claim holds.
Wednesday’s lab puts all of this into practice on your own machine. You’ll type a small Pew Research dataset into Excel, save it into your project, import it into R via read_excel(), build a four-stage line chart, then self-critique your chart with Cairo’s five qualities and apply one revision. The full R + RStudio + Quarto loop, end to end, for the first time.
Optional further reading
If today landed and you want the cognitive-science substrate behind why these design moves work, you might find this paper useful:
