How to make an infographic¶
A figure whose subject is numbers. The difference from a poster is not the look — it is that the numbers must come from the source rather than be retyped.
1. Compute the numbers, do not type them¶
This is the whole reason to draw an infographic in code:
MEASURES = [145, 165, 195, 250, 290]
greedy = [(f"{m} units", greedy_at(m)) for m in MEASURES]
total_fit = [(f"{m} units", total_fit_at(m)) for m in MEASURES]
examples/manual/line_breaking.py charts the library measuring itself, so the figure cannot drift away from the code. The same applies to a CSV, a database query or an API — read it at build time and the figure is never stale. Then say it in the caption:
note(
f"At 195 units greedy opens a gap of {dict(greedy)['195 units']:.1f} units "
f"where total-fit needs {dict(total_fit)['195 units']:.1f}."
)
An f-string in the caption means the prose cannot contradict the chart either.
2. Bars¶
from svg_plus import Bars
Bars(
[("2019", 20.6), ("2021", 34.5), ("2023", 51.0), ("2024", 61.0)],
color="blue",
top=70.0, # fix the scale
fmt="{:.1f} bn",
label_fraction=0.22, # width given to the labels
bar_height=18.0,
)
Two things worth knowing:
- The chart reserves room for its longest value label, so it cannot run out of its own box.
- Pass
top=whenever two charts are meant to be compared. Without it each picks its own ceiling from its own data, and two charts side by side will silently lie about their relative size.
ceiling = max(value for _, value in greedy + total_fit)
Row(panel("Greedy", greedy, "red", ceiling), panel("Total fit", total_fit, "green", ceiling))
3. The big number¶
The single figure everything else supports. A Frame with valign centres it in whatever height the row settles on:
Frame(
Stack(
Text("264 bn", size=46.0, weight=700, fill="page", align="center", wrap=False),
Text("leave Europe every year", size=13.0, fill="page", align="center"),
gap=6.0,
),
fill="accent",
stroke="none",
valign="middle",
)
Put several in a Row and they line up regardless of how much text each carries.
4. Emphasis inside the sentence¶
An infographic caption almost always needs one word carrying weight:
from svg_plus import Span, Text
Text([
"The market grew ",
Span("sixfold", weight=700),
", while European suppliers grew only ",
Span("threefold", weight=700, fill="red"),
".",
], align="justify")
Each piece is measured in its own style so the line still justifies exactly, and the full stop stays welded to the bold word before it.
5. Colour as redundancy, never as the message¶
Status colours exist so a figure survives being printed in black and white. Whatever red means, the text must say it too:
from svg_plus import tint
Frame(
Stack(
Text("Locked", size=12.0, weight=700, fill="red"),
Text("verrouillée", size=9.5, italic=True, fill="red"),
),
fill=tint(THEME.color("red")),
stroke="red",
)
tint() mixes a colour toward white for the pale ground that goes with the stroke. Add a legend — a Draw that walks the palette and measures each caption to place the next swatch:
def swatches(states):
def paint(canvas, box):
x = box.x
style = canvas.theme.style(11.0)
for color, caption in states:
canvas.rect(Rect(x, box.y, 12, 12), fill=tint(canvas.theme.color(color)),
stroke=color, radius=2.5)
canvas.text(x + 18, box.y + 10, caption, style)
x += 30 + style.width(caption)
return Draw(14.0, paint)
style.width(caption) is the point — the legend spaces itself from the actual text.
6. Shapes a bar chart cannot make¶
When the comparison is not a bar, reserve the height and draw it. An area comparison, for one — two squares whose areas carry the ratio:
from math import sqrt
def areas(big, small, side=250.0):
def paint(canvas, box):
canvas.rect(Rect(box.x, box.y, side, side), fill="#f4e0dc", stroke="red", radius=6)
edge = side * sqrt(small / big)
canvas.rect(Rect(box.x + side - edge - 16, box.y + side - edge - 16, edge, edge),
fill="#dde7ef", stroke="blue")
return Draw(side, paint)
sqrt because the eye reads area, not width. A log scale was tried in the original of that figure and rejected: it makes a ratio of a thousand look comparable.
7. Let the figure size itself¶
Unlike a poster, an infographic usually has no fixed page — so do not give Doc a height. Add a sentence to a card and the band grows, the canvas grows, and nothing is left with a strip of white at the bottom.
Use a fixed width across a set of figures, though, so their text bodies match when they sit in the same column.
Checklist¶
- Numbers read or computed at build time, never transcribed.
- Charts that are compared share a
top=. - Every colour is backed by words.
- The caption's claims come from the same variables as the chart.
- Width fixed across the set; height left to the content.
-
doc.describe(...)set, so the figure has an accessible name.