Definition
A Python script that processes data almost always ends up producing a list of numbers: sales by month, calculation results. Read as plain text in a terminal, that list shows no trend and no spike; the eye needs a drawing to do what text cannot.
matplotlib is the library that answers that need. It turns numbers into lines, bars, histograms or scatter plots, either shown in a window or saved as an image, in PNG, SVG or PDF. It is not part of the standard library: the first import raises a ModuleNotFoundError until it has been installed with pip, preferably inside a virtual environment.
pip install matplotlibOnce it is installed, the minimal script takes a few lines. The plt alias, set with the as keyword, is such a widespread convention that the official documentation and nearly every example found online already assume it is in place.
import matplotlib.pyplot as plt
months = ["January", "February", "March"]
sales = [120, 180, 150]
plt.plot(months, sales)
plt.savefig("sales.png")One question follows naturally: what data does it actually accept? The answer is reassuring: plain lists of numbers are enough. numpy arrays and pandas columns work just as well, but nothing requires them. A time axis is built from datetime objects, which matplotlib knows how to display without converting anything to text first.
What it replaces
The question that matters is not what matplotlib can do, but what was done before it. Before, a CSV file was exported, opened in a spreadsheet, two columns were selected and a chart was inserted. That method works perfectly well, once.
The problem shows up on the second pass. Next month's data arrives, and everything has to be done again: the selection, the colours, the title, the scale. matplotlib does not produce prettier figures than a spreadsheet, and with its default settings it produces plainer ones. What it brings is something else: reproducible figures, which give back exactly the same layout on the next run, without a single click. That guarantee is what justifies learning it, not how it looks.
It still helps to know when to reach for it. The table below compares the most common cases with the tool that fits each one.
| Situation | The right tool |
|---|---|
| Three numbers to show once | A spreadsheet, far quicker |
| A figure to regenerate on every new batch of data | matplotlib |
| A quick look at a table already loaded | The plot method of pandas |
| A chart to hover over inside a web page | An interactive library such as Plotly |
| Statistical figures with a polished style | seaborn, which builds on it |
The two writing styles
This is the first source of confusion, and it has nothing to do with charts. matplotlib can be written in two ways, and examples found online mix both without ever saying so.
The implicit style goes through plt, which keeps the current figure: every call applies to the last chart started. The explicit style does the opposite, it names the figure and its axes, then works directly on those objects.
# Implicit style: plt holds the current figure
plt.plot(x, y)
plt.title("Sales")
plt.xlabel("Month")
# Explicit style: the figure and the axes are named
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title("Sales")
ax.set_xlabel("Month")One detail changes along the way: title becomes set_title. Pasting one line from a tutorial into code written in the other style then gives a puzzling AttributeError, since both lines come from the same library. So how does one choose between the two? The implicit style suits a single throwaway figure. As soon as two charts sit side by side, or a figure is built inside a function, the explicit style becomes the only workable one: the notion of a current figure stops making sense once several figures exist.
The classic mistake
The most common trap is a matter of order: plt.show() empties the figure once the window is closed. Saving the image after displaying it therefore writes a perfectly blank file, with no error message.
# Blank image, and no error at all
plt.plot(x, y)
plt.show()
plt.savefig("curve.png")
# The correct order
plt.plot(x, y)
plt.savefig("curve.png")
plt.show()A second trap hides inside a loop, harder to spot because it does not raise an error either.
Without a fresh figure on every pass through the loop, all the curves pile up on the same chart: the tenth image generated actually holds ten stacked series. On a script that generates hundreds of files in one run, this build-up eventually eats up the available memory.
The fix is simple once the problem is spotted: a plt.figure() at the start of the pass, or a plt.close() at the end, resets the slate before each new image.
Frequently asked questions
Why does nothing appear when I run my script?
Either the call to plt.show() is missing at the end of the file, or the program runs where no window can open, on a server or inside a container. In that second case there is nothing to repair: the figure has to be written out with savefig instead of displayed.
Should I learn matplotlib or seaborn?
seaborn is built on top of it and does not replace it. It produces a presentable figure in one line, but every adjustment after that, moving a legend, changing a scale, tuning a date axis, goes back through matplotlib objects. Learning seaborn alone leads straight to a wall.
Can a chart be drawn straight from a pandas table?
Yes, df.plot() calls matplotlib underneath and hands back the axes object. Every command shown above still applies to that result, which makes it the shortest path between a raw data file and a readable figure.