Unit 08.02: Palettes that survive colour-blind readers
Red and green are the most common encoding pair and the one that fails most often.
What the palette looks like to a colour-blind reader
A rough simulation of deuteranopia applied to three palettes.
The code shows the separation that survives for each.
def simulate_deuteranopia(rgb):
"""Rough approximation: the most common form of red-green deficiency."""
r, g, b = rgb
return (int(0.625 * r + 0.375 * g), int(0.7 * g + 0.3 * r), b)
PALETTES = {
"red / green": [(214, 39, 40), (44, 160, 44)],
"blue / orange": [(31, 119, 180), (255, 127, 14)],
"blue / light blue": [(31, 119, 180), (174, 199, 232)],
}
for name, colours in PALETTES.items():
seen = [simulate_deuteranopia(c) for c in colours]
diff = sum(abs(a - b) for a, b in zip(*seen))
print(f"{name:20} as seen: {seen} separation: {diff:>4}")
print("""
Red and green collapse to nearly the same colour. Blue and orange stay
distinct, which is why it is the default first pair in most modern palettes.
Around 1 in 12 men has some form of this. Do not rely on hue alone -- vary
lightness too, or add a shape or a direct label.
""")
Red and green collapse to nearly the same colour. Blue and orange stay clearly separated - which is why it is the first pair in most modern default palettes rather than an aesthetic preference.
The third pair, blue against light blue, works for colour-blind readers because the separation is in lightness rather than hue, and lightness is preserved.
The mistake this prevents
The mistake is relying on hue alone even with a safe palette. Vary lightness too, or add a shape or a direct label - then the chart survives greyscale printing as well, which is a separate and common failure.
Takeaway
Do not encode meaning in red versus green. Prefer blue/orange, vary lightness as well as hue, and add a second channel so the chart survives greyscale.
