Naming colours, the cycle, and picking a colormap that does not invent structure.
Overview
Naming a colour
matplotlib accepts several notations wherever a colour is wanted:
A CSS name: "crimson", "steelblue", "rebeccapurple".
Hex: "#4c72b0", with an optional alpha suffix.
A cycle reference: "C0" through "C9", meaning the nth colour of the current property cycle. Using these keeps a figure consistent when the style changes.
A grey level as a string: "0.55". The quotes matter — the bare number 0.55 is not a colour.
An RGB or RGBA tuple of floats from 0 to 1.
Single letters "r", "g", "b", "k" also work, and are the ones the format-string shorthand uses.
Worth knowing
Colours accept CSS names, hex, C0–C9 from the cycle, a grey level as a string, or an RGB tuple.
set_prop_cycle changes the colours for one axes; a cycler can vary linestyle too, so the chart survives greyscale.
Colormaps are sequential (magnitude), diverging (around a meaningful centre) or qualitative (categories). The wrong kind invents structure.
jet is not perceptually uniform — its brightness rises and falls, so the eye reads boundaries the data does not have.
A colormap needs a colorbar; fig.colorbar takes the mappable that imshow or scatter returned.
Roughly one man in twelve cannot separate red from green — vary linestyle or marker as well as colour.
Colour and Colormaps
Naming colours, the cycle, and picking a colormap that does not invent structure.
Ways to name a colour
Five notations, all accepted anywhere a colour is wanted.
example_01.pymatplotlib
Output
The property cycle
Replace it and every later plot on that axes follows.
example_02.pymatplotlib
Output
Each axes has a property cycle that supplies the colour for successive plots. The default has ten colours and then repeats.
ax.set_prop_cycle(cycler(color=[...])) replaces it for one axes. plt.rcParams["axes.prop_cycle"] replaces it globally, which is how you apply a house palette to a whole script.
+ pairs them elementwise, so the first series is the first colour and the first linestyle. That single change makes every chart in a script survive being printed in greyscale, which is worth more than it costs.
* gives the outer product instead, cycling every combination.
Three kinds of colormap
Picking the wrong kind invents structure that is not in the data.
example_03.pymatplotlib
Output
The choice of colormap is a statement about the data, and the wrong one asserts something false.
Sequential — viridis, plasma, Blues — runs from low to high in one direction. Use for magnitudes: counts, temperatures, concentrations.
Diverging — coolwarm, RdBu, BrBG — has two directions from a neutral centre. Use when there is a meaningful midpoint: zero, an average, a baseline. Applying one to data with no natural centre invents a boundary in the middle of the range.
Qualitative — tab10, Set2 — is a set of distinct hues with no ordering. Use for categories. Using a sequential map for categories implies an order that does not exist.
Cyclic — twilight, hsv — wraps around, for angles and phases.
Why not jet
It is not perceptually uniform, so equal steps in value look unequal.
example_04.pymatplotlib
Output
Colorbars
A colormap without a scale is decoration.
example_05.pymatplotlib
Output
A colour-mapped plot without a colorbar is decoration: the reader can see that values differ and not by how much.
fig.colorbar(mappable, ax=ax) needs the object returned by the drawing call — imshow, scatter, pcolormesh, contourf. That is why those return values are captured here.
label= names the quantity, which is as important as it is on an axis. shrink and pad adjust size and spacing; orientation="horizontal" puts it below.
For a grid of subplots, fig.colorbar(im, ax=axes.ravel().tolist()) makes one bar serve all panels, which is right when they share a scale — and they should, or the panels are not comparable.
Colour is not the only channel
About one man in twelve cannot distinguish red from green.
example_06.pymatplotlib
Output
Why jet is a problem
jet was the default in older tools and still appears everywhere. It is a bad choice, for a reason that is measurable rather than aesthetic.
A good colormap is perceptually uniform: equal steps in the data look like equal steps in colour. viridis was designed for this, and its brightness increases steadily from one end to the other.
jet does not. Its brightness rises, falls and rises again, with a bright band in the middle. The eye reads a sharp brightness change as a boundary, so jet shows edges and structure where the data is perfectly smooth — and hides real gradients in the flat regions.
It also collapses when converted to greyscale, because different values map to the same brightness.
The fourth editor plots the brightness of both, which makes the difference visible rather than assertable.
Accessibility
Around 8% of men and 0.5% of women have some form of colour vision deficiency, most commonly difficulty separating red from green.
Three habits cover most of it:
Avoid red against green as the primary distinction. Blue against orange is distinguishable for almost everyone.
Vary a second channel — linestyle, marker, or position — so colour is reinforcing rather than carrying the meaning alone.
Use viridis and friends for continuous data. They were designed to remain monotonic in brightness under common deficiencies, which is why they work in greyscale too.
The greyscale test is a good proxy for all of it: print the chart in black and white, and if it is still readable, it will survive most viewing conditions.
Transparency
alpha runs from 0 to 1 and can be set per artist or baked into a colour as a fourth channel.
Three places it earns its keep: showing density in an overplotted scatter, letting a shaded band sit under a line without hiding it, and de-emphasising context series without changing their colour.
Two cautions. Alpha compounds — ten overlapping shapes at 0.1 are opaque where they all coincide, which is exactly the density signal you want in a scatter and an unwanted colour shift elsewhere. And transparency is lost when a figure is flattened onto a background, so a chart designed with alpha over white looks different over grey.
Named palettes
matplotlib ships the tab10 and tab20 qualitative sets, and plt.get_cmap("tab10").colors gives the list for use in a cycler.
For categorical work, palettes designed for colour-vision deficiency are worth preferring — the Okabe–Ito set is eight colours chosen to remain distinguishable under the common deficiencies, and it is a plain list of hex codes you can paste into a cycler.
For sequential data, the perceptually uniform family is viridis, plasma, inferno, magma and cividis. cividis is designed specifically to look the same to viewers with and without colour-vision deficiency.
Appending _r to any colormap name reverses it: viridis_r.
Discrete colour from a continuous map
Sampling a continuous colormap gives a graded set for ordered categories:
cmap = plt.get_cmap("viridis")
colors = [cmap(i / (n - 1)) for i in range(n)]
That is right when the categories have an order — age bands, quartiles, years — because the colour then carries the ordering.
It is wrong for unordered categories, where a qualitative palette should be used instead, and it is a common way to imply a sequence that does not exist.
BoundaryNorm does the same thing for a mapped plot, banding a continuous scale into discrete steps with a colorbar that shows the boundaries.
Colorbar placement
The default steals space from the axes it is attached to, which shrinks that panel and misaligns it with its neighbours.
fig.colorbar(im, ax=axes.ravel().tolist()) spans several panels with one bar, which is right when they share a scale.
shrink=0.8 and aspect=30 adjust its proportions; pad sets the gap; location="bottom" moves it.
For precise control, fig.add_axes([left, bottom, width, height]) creates a dedicated axes for it in figure coordinates, which is how you get a colorbar that lines up exactly with a grid.
Backgrounds
fig.patch is the figure background and ax.patch the axes background, and they are separate.
ax.set_facecolor("#f7f7f7") gives the plotting area a light tint, which some styles use to make a white grid readable.
For a dark theme, both need setting along with the text, tick and spine colours — which is exactly what the dark_background style does, and a reason to use a style rather than setting six things by hand.
Building a palette
A palette for a project needs fewer colours than people expect.
One colour, for charts with a single series. Most charts.
Two, for a comparison or a before-and-after.
A greyscale plus one accent, for highlighting one series among many. This covers more cases than any multi-colour palette.
Five or six, for genuinely categorical work, drawn from a set designed for the purpose.
Beyond about six, colour stops distinguishing reliably, and the answer is small multiples rather than more hues.
Add a grey for context elements, a light grey for gridlines, and a dark grey rather than black for text, and that is a complete house palette.
Testing a colour scheme
Three checks, none of which needs a tool.
Greyscale. Convert the figure to greyscale and see whether the series are still distinguishable. If they are not, luminance is not varying and the chart depends entirely on hue.
Small size. View the figure at the size it will actually be seen. Colours that separate at full screen frequently do not at thumbnail size.
Print. A projector and a printer both compress the range, and colours that differ on a monitor often do not survive either.
Passing all three usually means the encoding is robust, and failing any of them is fixed the same way: vary luminance, and vary a second channel.
Colour with meaning
The strongest use of colour is when it encodes something the reader already understands.
Semantic colours — red for loss, green for gain, a brand colour for one product — are read without a legend because the meaning arrives with the hue. They are also culturally specific, and the red/green pairing is the worst possible choice for colour-blind readers, so the convention has to be weighed against accessibility.
Sequential colour for an ordered variable — darker for more — is read correctly with almost no instruction.
One accent against grey is the most reliable of all, because it says "this one" and nothing else.
The weakest use is colour as decoration: seven categories in seven hues because the palette had seven. That asks the reader to learn an arbitrary mapping and consult it repeatedly, and it is usually a sign the chart should be small multiples.
The test is whether removing the colour destroys the chart's meaning or only its appearance. If the former, the colour is doing work and should be chosen carefully. If the latter, it can be simplified away.
In summary
Colours accept names, hex, C0-style cycle references, greys as strings, and RGB tuples.
The property cycle supplies distinct colours automatically, and a cycler can vary linestyle alongside colour so the chart survives greyscale.
Colormaps come in three kinds, and using the wrong kind asserts something false: sequential for magnitude, diverging around a real centre, qualitative for unordered categories.
jet fails measurably rather than aesthetically — its brightness is not monotonic, so it shows edges the data does not have.
A colour-mapped plot needs a colorbar, with a label, and two such plots need a shared scale.
And roughly one man in twelve cannot separate red from green, which is why a second channel is worth varying and why greyscale is a good proxy test for the whole question.
A closing note
Colour is the most over-used channel in charting and the most rewarding to use sparingly.
The strongest charts usually have one colour, or one colour against grey. Colour that encodes a variable earns its place; colour that distinguishes seven categories nobody needs to distinguish does not.
The technical points matter too — perceptual uniformity, the right kind of colormap, a centred diverging scale, a colorbar that says what the colours mean — and they are all in service of the same thing: the reader should be able to work out what a colour means without being told twice.
The greyscale test remains the quickest check on all of it.
The short version
Colour is the most over-used channel in charting and the most rewarding to use sparingly.
One accent against grey outperforms a seven-hue palette in almost every case, and the greyscale test is the quickest check on whether the encoding survives contact with the real world.
Reading the code back
Colour decisions are made once for a project and applied through a cycler, not chosen per chart. A palette of five or six for categories, a sequential map for magnitudes, a diverging one for data with a real centre, and a grey for context is a complete set. Anything beyond that is usually a chart that should have been small multiples.
Check yourself
0 of 4
Answer without scrolling back up.
What does the string `'0.55'` mean as a colour?
The quotes matter - the bare number 0.55 is not a colour. C0-C9 refer to the current cycle instead.
When is a diverging colormap the wrong choice?
Sequential for magnitudes, diverging around a real centre like zero, qualitative for unordered categories.
What is measurably wrong with `jet`?
It also collapses in greyscale, because different values map to the same brightness. viridis is monotonic in brightness.
What does `fig.colorbar` need as its first argument?
Which is why those return values get captured. label= names the quantity, as important as it is on an axis.
Cheat sheet
Colour and Colormaps
A cycle reference: "C0" through "C9", meaning the nth colour of the current property cycle. Using these keeps a figure consistent when the style changes.
Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.