Beyond the basicsChapter 93 of 114
Matplotlib Intro
Turn numbers into a chart, and save it to a file.
The shape of a plot
pyplot is the everyday interface. Build a figure, add data, then show or save it:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
years = [2021, 2022, 2023, 2024]
users = [120, 260, 410, 580]
fig, ax = plt.subplots()
ax.plot(years, users)
ax.set_title("Users by year")
ax.set_xlabel("Year")
ax.set_ylabel("Users")
fig.savefig("chart.png")
print("saved", fig.get_size_inches().tolist())Output
saved [6.4, 4.8]
Figure and axes
Two objects, and knowing which is which saves a lot of confusion:
- the figure is the whole image: size, title, saving
- the axes is one set of x and y inside it, and is where you draw
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(8, 3))
axes[0].plot([1, 2, 3], [1, 4, 9])
axes[1].bar(["a", "b"], [3, 5])
axes[0].set_title("squares")
axes[1].set_title("counts")
fig.tight_layout()
fig.savefig("two.png")
print(len(fig.axes), "axes in the figure")Output
2 axes in the figure
You will also see the older style — plt.plot(), plt.title() — which works on whatever the "current" axes is. It is shorter for a throwaway plot and gets confusing with more than one, so prefer fig, ax.
Chart types
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.bar(["a", "b", "c"], [3, 7, 2])
fig.savefig("bar.png")
fig2, ax2 = plt.subplots()
ax2.scatter([1, 2, 3], [2, 4, 3])
fig2.savefig("scatter.png")
fig3, ax3 = plt.subplots()
ax3.hist([1, 1, 2, 3, 3, 3, 4], bins=4)
fig3.savefig("hist.png")
print("three files written")Output
three files written
| Method | Shows |
|---|---|
ax.plot | change over a continuous axis |
ax.bar | a value per category |
ax.scatter | the relationship between two variables |
ax.hist | how one variable is distributed |
ax.pie | parts of a whole, rarely the clearest choice |
Labelling
An unlabelled chart is not much use to anyone:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [2, 4, 8], label="doubling")
ax.plot([1, 2, 3], [1, 2, 3], label="linear")
ax.set_title("Growth")
ax.set_xlabel("Step")
ax.set_ylabel("Value")
ax.legend()
ax.grid(True, alpha=0.3)
fig.savefig("labelled.png")
print(ax.get_title(), "|", ax.get_xlabel())Output
Growth | Step
label= on each series plus ax.legend() is how the key appears. Forgetting the labels and then calling legend() gives you an empty box and a warning.
Saving
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import os
fig, ax = plt.subplots(figsize=(4, 3))
ax.plot([1, 2], [1, 2])
fig.savefig("small.png", dpi=150, bbox_inches="tight")
print(os.path.exists("small.png"))Output
True
dpi controls resolution and bbox_inches="tight" trims the white margin, which is almost always what you want for a chart going into a document.
Close what you open
Every figure holds memory until it is closed. In a loop that matters:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
for n in range(3):
fig, ax = plt.subplots()
ax.plot([0, n], [0, n])
fig.savefig(f"plot-{n}.png")
plt.close(fig)
print("closed each one")Output
closed each one
Test yourself
2 questionsWhat is the difference between a figure and an axes?
Show the answer
The figure is the whole image; the axes is one set of x and y inside it — fig.savefig saves the image; ax.plot draws on one panel of it.
Why call matplotlib.use("Agg")?
Show the answer
It selects the file-writing backend, for when there is no window to open — On your own machine you would drop it and call plt.show() instead.
Working with APIs
Ask another service for data over HTTP, and handle what comes back.