Lesson 15
Colour Maps and Dot Sizes
Add a third and fourth measurement to a scatter plot using the c and s arguments, a colour map, and a colour bar that explains the scale.
A scatter plot already carries two measurements, in x and y. The colour and the size of each dot can carry two more. It is a genuinely useful trick and an easy one to overdo: four measurements in one picture is close to the limit of what anyone can read.
A colour per dot
c accepts a list of numbers, one per dot, and cmap names the colour map that turns those numbers into colours. Note the difference from color, which paints every dot the same: only c takes a list of values to be mapped.
import matplotlib.pyplot as plt
hours = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
score = [41, 48, 44, 56, 61, 58, 69, 72, 68, 79, 84, 81]
lessons = [3, 4, 4, 6, 7, 7, 9, 11, 10, 13, 15, 14]
plt.scatter(hours, score, c=lessons, cmap="viridis")
plt.title("Colour shows lessons completed")
plt.xlabel("hours of practice")
plt.ylabel("score")
plt.show()
print("lessons range from", min(lessons), "to", max(lessons))Output:
lessons range from 3 to 15The colour bar is not optional
A colour scale that is never explained is decoration. plt.colorbar() draws the key beside the chart and label says what it measures. Without it, a reader can see that the dots differ and has no idea why.
import matplotlib.pyplot as plt
hours = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
score = [41, 48, 44, 56, 61, 58, 69, 72, 68, 79, 84, 81]
lessons = [3, 4, 4, 6, 7, 7, 9, 11, 10, 13, 15, 14]
plt.scatter(hours, score, c=lessons, cmap="plasma")
plt.colorbar(label="lessons completed")
plt.title("Practice, score, and lessons")
plt.xlabel("hours of practice")
plt.ylabel("score")
plt.show()
print("the bar turns colour back into numbers")Output:
the bar turns colour back into numbersChoosing a colour map
Colour maps come in kinds, and the kind matters more than the prettiness. A sequential map such as viridis runs dark to light and suits a quantity. A diverging map such as coolwarm has a neutral middle and suits values above and below a baseline. Add _r to any name to reverse it.
import matplotlib.pyplot as plt
kinds = {
"sequential": ["viridis", "plasma", "Blues", "magma"],
"diverging": ["coolwarm", "RdBu", "PiYG"],
"reversed": ["viridis_r", "Blues_r"],
}
for kind, names in kinds.items():
print(f"{kind:<12} {', '.join(names)}")
change = [-8, -5, -3, -1, 0, 2, 4, 6, 9]
position = list(range(len(change)))
plt.scatter(position, change, c=change, cmap="coolwarm", s=140)
plt.axhline(0, color="#94A3B8", linewidth=1)
plt.colorbar(label="change from target")
plt.title("A diverging map around a meaningful zero")
plt.show()Output:
sequential viridis, plasma, Blues, magma
diverging coolwarm, RdBu, PiYG
reversed viridis_r, Blues_rplt.axhline(0) draws the baseline the colours diverge around, so the neutral colour in the middle has something to point at.
Size as a fourth measurement
s takes a list of sizes, one per dot, in points squared. Because the eye compares areas poorly, use size for something rough, such as how big a group is, and never for the number you want read precisely.
import matplotlib.pyplot as plt
hours = [2, 4, 6, 8, 10, 12]
score = [44, 52, 61, 69, 78, 85]
cohort = [4, 9, 16, 12, 25, 20]
sizes = [size * 18 for size in cohort]
plt.scatter(hours, score, s=sizes, c=score, cmap="viridis", alpha=0.75)
plt.colorbar(label="score")
plt.title("Bigger dot means a bigger cohort")
plt.xlabel("hours of practice")
plt.ylabel("score")
plt.show()
print("largest cohort:", max(cohort), "learners")Output:
largest cohort: 25 learnersKey takeaways
-
c takes one value per dot; color paints them all the same
-
cmap names the colour map that turns values into colours
-
Always add a colorbar, or the colours mean nothing
-
Sequential maps suit quantities, diverging maps suit a baseline
-
Next: Histograms
-
Previous: Scatter Plots
Loading playground…
Check your understanding
Colour Maps and Dot Sizes Quiz
Which argument maps a value to a colour per dot?
1 / 10