Matplotlib·Lesson 11·12 min·0/3 exercises

Colour

Three families, and picking the wrong one invents structure that is not there

prop_cyclecmapcolormapsto_hexTwoSlopeNormplt.style.use

Watch it happen

Play it through, or step back and forth yourself.

the property cycle
#ff7d0c#66aaf9#74dfa2#ae7ede#f871a0#f5a524#f9c97c
ax.plot(x, y)takes the next colour
color="C1"the second one, by name
plt.rcParams['axes.prop_cycle']the cycle itself
ax.set_prop_cycle(color=[...])set your own

You don't pick colours for series — matplotlib does, from the property cycle. Successive plot calls take the next one, and "C0""C6" name them, so you can reuse a series' colour somewhere else without hardcoding a hex.

The idea

Colour on a chart is a data-encoding decision, not a taste one. Get the family wrong and you don't get an ugly chart — you get a chart that shows structure the data doesn't contain.

The property cycle

You don't choose colours for series; matplotlib does, from the property cycle. Successive plot calls take the next entry, and they have names:

ax.plot(x, a)                 # takes the first colour
ax.plot(x, b, color="C0")     # the SAME colour, by name
plt.rcParams["axes.prop_cycle"].by_key()["color"]

"C0""C9" are worth knowing: they let a later annotation or arrow match a series without you hardcoding a hex that goes stale when the palette changes. To set your own for one Axes, ax.set_prop_cycle(color=[...]).

The three families

Sequential — for magnitude. Low to high, nothing special in the middle: rainfall, population, wait time. viridis, magma, Blues.

Diverging — for distance from a meaningful middle. Profit and loss, above and below average, temperature anomaly. coolwarm, RdBu. The centre has to be pinned to the value that matters, or the colours mislead:

from matplotlib.colors import TwoSlopeNorm
sc = ax.scatter(x, y, c=change, cmap="coolwarm",
                norm=TwoSlopeNorm(vcenter=0))

Without that, matplotlib centres the colormap on the middle of your data range, so "grey" lands wherever the data happens to average out — and a chart of all-positive numbers gets a big blue region meaning "less positive". That reads as negative to everybody.

Qualitative — for names. Cities, products, categories with no order. tab10, Set2: distinct hues at similar intensity, so nothing looks more important than anything else. Using a sequential map here implies a ranking you didn't mean.

Why viridis is the default

viridis is perceptually uniform: equal steps in the data are equal-looking steps to the eye, all the way along, and its lightness rises monotonically.

jet — the rainbow map, still the default in a lot of older software — is not. It has bright bands at cyan and yellow that the eye reads as edges, so a smooth gradient appears to have contours in it. Those contours are in the colormap, not in your data. It has produced a great many confidently misread heatmaps.

Sample a map to see what it's made of:

import matplotlib as mpl
mpl.colormaps["viridis"](0.0)                      # (r, g, b, a)
mpl.colors.to_hex(mpl.colormaps["viridis"](0.5))   # '#21918c'
mpl.colormaps["viridis"].N                          # 256 steps
"viridis_r"                                         # any map, reversed

Greyscale and colour blindness

Print viridis in greyscale and it still reads, because lightness carries the information. jet collapses — its two ends turn into the same mid-grey.

Roughly 8% of men can't reliably separate red from green, which is the most common way people encode "bad" and "good". Two habits fix nearly all of it:

plt.style.use("tableau-colorblind10")

ax.plot(x, a, color="C0", linestyle="-")     # never hue alone —
ax.plot(x, b, color="C1", linestyle="--")    # add style or a marker

The best palette is usually one colour

Four series in four colours asks the reader to work out which one you're talking about. Grey out the context and highlight the one that matters:

for name in others:
    ax.plot(x, df[name], color="#8a8a8a", linewidth=1.2)
ax.plot(x, df["delhi"], color="#ff7d0c", linewidth=2.6, label="Delhi")

The eye goes straight to the orange line, and the greys are still there as context. This is the single highest-return change you can make to a multi-series chart.

See it run

The lesson's code, ready to run and to fiddle with.

Putting the kettle on…

Starting up…

Worked example

not graded

Already written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.

tryswitching the highlight to "mumbai" and seeing how completely the emphasis moves.

Press Run — the output appears here.

Your turn

3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Return the first three colours of the current property cycle — the ones the next three plot calls would use.

your answer

Sample viridis at its start, middle and end, and return the three colours as hex strings in a list.

your answer

Do the same for coolwarm to show it's diverging: the two ends should be strongly coloured and the middle nearly neutral.

your answer