Choosing a form¶
Form is the decision you make before any other rule applies. A figure in the wrong form cannot be rescued by palette, type, or composition. Those only make a wrong reading legible.
check_figure.py gates the mechanical subset of this page: pie, 3D, and a bar
chart on a truncated baseline. Those three are wrong regardless of the data, so
a script can decide them. Everything else here needs the data in front of you,
which is why it is prose.
The lineage is statistical graphics rather than general information design:
Cleveland and McGill's perceptual experiments, Tukey's exploratory work, and
Wilkinson's grammar as it reached most people through ggplot2. Each rule below
names the perceptual or inferential result it rests on, so you can argue with it
on those terms.
The ordering everything else follows¶
Cleveland and McGill (1984) measured how accurately people read the same quantity encoded different ways. Their ordering, most accurate first, is six ranks and not seven:
- Position along a common scale
- Position along identical, non-aligned scales
- Length, direction, angle
- Area
- Volume, curvature
- Shading, color saturation
Colour hue is not ranked there. Lists that append it are extending the paper rather than quoting it. This guide gives hue no magnitude job at all. Hue carries identity, which is a different question from how accurately a magnitude can be read off it.
Almost every rule below is a corollary of one instruction: move the reader's judgement up the list. A dot plot beats a bar because position beats length. Small multiples beat grouped bars because identical non-aligned scales beat comparing lengths across a gap. A pie loses because angle and area are both near the bottom.
Color sits at the bottom. That is why it identifies series rather than carrying
their magnitudes, and it is why check_palette.py exists at all: the weakest
channel is the one that has to survive a reader who sees it differently.
The table¶
| The data | Form | Not |
|---|---|---|
| One distribution, n < ~30 | strip / jittered dot, points shown | box plot |
| One distribution, large n | box or violin, with n stated | a bare mean |
| Comparison across categories | dot plot on a common scale | bar with a cut baseline |
| Counts from zero | bar, baseline at zero | dot plot with a floating axis |
| Paired before/after | slope graph, or difference with its CI | two bars side by side |
| More than ~3 series × groups | small multiples | grouped bars |
| Parts of a whole, 2 parts | one number in the caption | pie |
| Parts of a whole, many parts | small multiples of proportions | stacked bar, pie |
| Data and a fitted model | data as marks, model as one line | both as lines |
| Two continuous variables, large n | hexbin or 2-D density | smaller markers |
| Ordered steps of one quantity | lightness ramp (viridis) | several hues |
| A second unit for the same values | axis relabel with no data of its own | twin axis with data |
Distributions: show the points while you can¶
At n below about 30, draw every observation as a strip or jittered dot plot. A box plot is a five-number summary, and Tukey designed it for batches too large to draw by hand. At n = 8 it hides the two things a reader needs: how many observations there are, and whether they are bimodal. Two groups with identical quartiles and completely different shapes draw the same box. In teaching material this matters more, not less, because readers take the summary as the data.
Above roughly 30 the summary starts earning its ink. Above a few hundred, a violin or a box beats a cloud of overlapping points.
State n either way, in the axis label or the caption. A distribution figure without n is not interpretable.
Never draw a bar with an error bar for a distribution. The "dynamite plunger" plot puts a mean on a length encoding and a spread on a whisker, so the eye reads the bar's area as the quantity and the actual variation as decoration. It is also ambiguous by construction: nothing on the figure says whether the whisker is an SD, an SE, or a CI. Draw the points, or draw a dot with an interval.
Baselines: length needs zero, position does not¶
A bar encodes its value as length, so its baseline must be zero. Cut the
axis and every ratio on the chart is misstated. Bars at 101 and 108 drawn from a
baseline of 100 look like a sevenfold difference. This is the one form error
that reliably changes a reader's conclusion, and it is the one check_figure.py
fails.
When the baseline is not meaningful, change the form. A Cleveland dot plot encodes the value as position, which carries no zero obligation, so the axis can start wherever the data lives. Put categories on the vertical axis and sort them by value rather than alphabetically. Sorting is free, and it turns "find the biggest" from a scan into a glance.
A log axis has the same constraint as a cut bar baseline: it cannot contain zero, so it cannot carry a bar. Use points, and say in the caption that the scale is multiplicative.
Paired data: draw the pairing¶
Two bars side by side throw away the pairing. If each subject was measured twice, the estimand is the per-subject difference, and a reader cannot recover it from two group means.
Use a slope graph instead: one line per subject, before on the left, after on the right, on one common scale. That puts every pair on the page and makes the exceptions visible.
Better still, plot the differences themselves with their interval. When the comparison is the point, make the comparison the thing on the axis.
Small multiples over grouped bars¶
Beyond about three series in three groups, a grouped bar chart asks the reader to compare lengths that are not adjacent and do not share a baseline position. That is task 3 crossed with task 2, done repeatedly.
Trellis display (Cleveland, 1993, and facet_wrap to everyone who met it
through ggplot2) splits the same comparison into panels on identical scales,
which is task 2 done once per panel.
Panels share their axis furniture: one tick column, one axis label.
check_figure.py gates that separately as Axis redundancy.
Consistency checklist for a small-multiple family¶
Every panel in a multi-panel figure was chosen for a reason the reader declares, and the same reason constrains how much the panels may differ. No script decides any of these:
- Keep the same context surface, or differ deliberately. A filled-terrain backdrop in one panel and white space in another reads as two different kinds of figure, not two instances of the same thing. If the surface must differ, say so once and keep the colormap identical.
- Put shared reference points in the same place. If panel A draws a dashed circle at the optimum, panel B draws it at the same data coordinate, not wherever the panel's limits happen to centre. The exception is a figure whose point is that the second panel has no optimum, where the missing circle is the distinctive absence.
- Keep emphasis and scale comparable. One panel at 10x the other's zoom asserts that panel matters more. If it does, make the difference explicit and let the scale bars say so. If it does not, keep the limits comparable.
- Use a consistent marker grammar. A circle is an observation, a triangle is a prediction, a cross is an extremum, and the mapping holds across every panel that shares that kind of mark.
- Check each panel's distinctive mark is actually present. If three panels carry a credible band, the fourth carries one too, or the caption says why it cannot. A missing band beside three that have one reads as an oversight rather than as a statement about the model. Draw it, label the panel "not applicable", or name the omission in the caption.
Stacked bars have one honest series¶
Only the bottom band of a stacked bar sits on a common baseline. Every band above it starts at a shifted, category-dependent origin. Comparing the third series across categories is therefore a length judgement with a moving zero, which is the hardest reading on the chart and usually the one the figure was drawn to support.
Stack only when the total is the quantity of interest and the parts are context. Otherwise use one panel per series, or one line per series.
Model and data in one panel¶
Draw the data as marks and the model as a single line. Drawing both as lines makes a fitted curve indistinguishable from an observed one, and the fit is the claim being argued. Drawing only the model is worse. Anscombe's quartet and its modern restatements exist because summary statistics and fitted lines survive data that looks nothing like what the reader is imagining.
Name the fit in the caption: OLS, loess with its span, a GAM with its basis. A smoother is a claim about functional form, and an unnamed one cannot be reproduced or argued with.
Uncertainty: say which kind, and put it on the estimand¶
Name every interval on a figure in the caption, because SD, SE, and CI are three different objects and the drawing is identical:
- SD describes the spread of the observations. It does not shrink with n.
- SE describes the precision of the estimate. It shrinks as
1/sqrt(n). - CI is an interval procedure with a stated coverage. Give the level.
Overlapping confidence intervals are not a significance test.
Non-overlapping 95% intervals do imply a difference significant at 0.05, but the
converse fails. Two 95% intervals can overlap substantially while the difference
is significant, because the standard error of a difference is
sqrt(se_a^2 + se_b^2), not se_a + se_b.
If the comparison between two groups is the figure's job, plot the difference and its interval. That is one reading of position on a common scale, instead of a comparison the reader has been quietly asked to do wrong.
Overplotting¶
At large n, marks stop being individually visible and the figure reports density rather than observations. Shrinking the marker does not fix it. It trades one unreadable picture for a fainter one.
Use transparency within the three-alpha-level budget, a hexbin, or a 2-D density estimate, and say which one you used. If the individual points genuinely matter, the honest answer is that the sample is too large for a scatter and the figure needs to change question.
Encode only what exists¶
A line through unordered categories asserts a sequence the data does not have. A smooth through five points asserts a function. An area fill under a curve asserts that the integral means something.
Each of those is a claim, and each is easy to make by accident, because the plotting call is one keyword away.
The corollary is the categorical-versus-ordinal decision, which is in the style guide: a numbered cycle is ordinal and takes a lightness ramp, not four unrelated hues.
Time series and aspect ratio¶
When the reader's job is to judge rates of change, the aspect ratio is a data choice rather than a layout choice. Cleveland's banking to 45 degrees, which chooses the height-to-width ratio so the typical line segment sits near 45 degrees, is where slope discrimination is most accurate. A cycle that is obvious in one aspect ratio disappears in another, and the wrong one is usually the one the default produced.
The failure is a resolution failure. Take a saw wave whose decay limbs alternate between two rates, one exactly twice the other. At 2.4 x 5.2 inches the two limbs land 1.6 degrees apart on the page, and the alternation cannot be seen at all. At 6.4 x 1.9 they land 10.6 degrees apart, and it is the first thing you see. Same data, same axes, same limits: a 2:1 difference in rate, rendered as a difference no reader can resolve.
check_figure.py gates this as an advisory row. It reads the median absolute
segment slope of each panel's strokes in display space, and warns outside a
factor of BANKING_SLOPE_MAX = 10.0 either side of banked, which is a typical
segment past 84 degrees or under 6. The row is deliberately loose: the right
aspect depends on what the reader's job is, and a script cannot know that. What
it can say is that a panel is essentially vertical or essentially flat over its
own typical step.
The gate skips what banking does not apply to:
- A fixed aspect, such as
set_aspect("equal")on a map or a phase portrait, where the ratio is a statement about the data. - A line whose x does not run one way.
- Any stroke under
BANKING_MIN_POINTS = 8vertices, which is furniture rather than a rate.
Segments that render flat are culled, after Heer and Agrawala's "slopeless
lines". A horizontal or vertical segment is unchanged by the aspect ratio, so it
cannot help set one, and a tail of them drags the median that does. The rule is
generalized from exactly zero or infinite slope to drawn flat: a segment whose
rise is under BANKING_FLAT_PX = 0.5 display pixels cannot be told from flat at
any aspect a reader will see.
A converged training run is mostly a flat tail, 92 near-flat segments out of 119. Culling them is the difference between a median slope of 0.0006, which warns and asks for a panel sixteen hundred times taller, and 1.30, which is banked.
The forms with no research-figure use¶
- Pie and donut. Angle and area are the two weakest quantitative tasks, for a job a sorted dot plot does better. Two categories do not need a figure.
- 3D bars, and 3D surfaces for 2D data. Perspective makes identical values plot at different sizes, and near marks occlude far ones. A third variable belongs in a facet, a color scale, or a contour.
- Radar and spider. Area scales as the square of the values, the shape depends on the arbitrary order of the axes, and the axes rarely share units.
- Dual y axes. Both scales are set by the author, so the crossing point of
the two curves is an artifact of the limits chosen.
check_figure.pygates this. The exception is a bare unit relabel that carries no data of its own.
References¶
- Cleveland, W. S. & McGill, R. (1984). Graphical perception: theory, experimentation, and application to the development of graphical methods. JASA 79(387), 531-554. The perceptual ordering above.
- Cleveland, W. S., McGill, M. E. & McGill, R. (1988). The shape parameter of a two-variable graph. JASA 83(402), 289-300. The median-absolute-slope criterion and the experiments behind banking to 45°.
- Cleveland, W. S. (1993). Visualizing Data. Dot plots, Trellis display, banking.
- Heer, J. & Agrawala, M. (2006). Multi-scale banking to 45 degrees. IEEE Transactions on Visualization and Computer Graphics 12(4), 701-708. The "slopeless lines" culling the gate applies, and the survey of banking criteria.
- Tukey, J. W. (1977). Exploratory Data Analysis. The box plot, and what it was for.
- Wilkinson, L. (2005). The Grammar of Graphics. The decomposition
ggplot2implements. - Anscombe, F. J. (1973). Graphs in statistical analysis. The American Statistician 27(1), 17-21.
- Schenker, N. & Gentleman, J. F. (2001). On judging the significance of differences by examining the overlap between confidence intervals. The American Statistician 55(3), 182-186. The overlapping-intervals result.