The Beginnings of an Exploration of Matplotlib and Pyplot
By: Rob Blatt
Tags: Data Visualization, Pyplot, Dataviz, Matplotlib

it’s a figure with an ax. you’ll get this joke eventually.

In a previous blog post, I wrote about how I’ve always enjoyed tearing something apart (and sometimes reassembling it) to understand it better. If it worked for Da Vinci, it should work for me, right? The purpose of this blog post is two fold. I intend to tear Matpltlib and pyplot apart to have a deeper understanding of how it works on a conceptual level (with visual and code examples) and then I also intend to show as many examples as possible of how different keyword arguments can change the appearance of a plot.

This wasn’t the project that I assumed it would be when I started out. There’s a good amount under the hood that I had taken for granted and a lot of information that I was assuming that was twisted and incorrect. As a result, the early version of this post may seem a bit jumbled, but I’ll be adding to it over time.

Let’s dig until we break it, or it breaks us.

Matplotlib is has layers. Spoilers. It broke me.

Jack Kirby

Understanding the Artist/Renderer/FigureCanvas relationship

The Matplotlib FigureCanvas is the area onto which the figure is drawn. If you think about your computer’s memory, this is the allocated area of memory where an image will go. This is the paper.

If you think about your computer’s memory, this is the allocated area of memory where an image will go. This is the paper. The Matplotlib Renderer is the object which knows how to draw on the FigureCanvas. The pencil can draw on the paper just as the renderer can draw on the FigureCanvas.

The pencil can draw on the paper just as the renderer can draw on the FigureCanvas. The Matplotlib Artist is what knows how to use a renderer to paint an onject onto the canvas. Without the Artist to use a pencil on the paper, the pencil and the paper simply exist or do not exist.

But also the Jack Kirby Metaphor doesn’t work

Putting that relationship into perspective

This isn’t like Jack Kirby drawing everything onto a piece of paper. The metaphor above is used for each object. The figure has an Artist, the axes has an Artist, the title has an Artist and so on and so forth.

import matplotlib.pyplot as plt

We have imported Matplotlib and Pyplot as plt. It does everything important like the maths and the graphs.

fig / figure

fig is the figure, which refers to everything being created. figsize(10,2)? That creates a figure that’s 10 inches by 2 inches. The plot is not the figure, it’s the frame that surrounds it. The figure is a class object.

The figure object container contains:

axes A list of Axes instances (includes Subplot)

A list of Axes instances (includes Subplot) patch The Rectangle background

The Rectangle background images A list of FigureImages

A list of FigureImages patches — useful for raw pixel display

— useful for raw pixel display legends A list of Figure Legend instances (different from Axes.legends)

A list of Figure Legend instances (different from Axes.legends) lines A list of Figure Line2D instances (rarely used, see Axes.lines)

A list of Figure Line2D instances (rarely used, see Axes.lines) patches A list of Figure patches (rarely used, see Axes.patches)

A list of Figure patches (rarely used, see Axes.patches) texts A list Figure Text instances

That first item? Axes? Let’s take a look.

ax / axes but not axis

If the figure is the frame of the plot, it is the region of the image with the data space, or the axes in the image. There can be multiple figures with multiple axes, there can be one figure with ultipel axes, there can be one figure with one ax, or one figure with no ax, but an ax can’t be seen without a figure. The axes is a subplot instance of the figure class object.

Axes has a ton of helper methods, let’s take a look at a few of them:

ax.annotate — text annotations

— text annotations ax.bar — bar charts

— bar charts ax.errorbar — error bar plots

— error bar plots ax.fill — shared area

— shared area ax.hist — histograms

— histograms ax.imshow — image data

— image data ax.legend — axes legends

— axes legends ax.plot — xy plots

— xy plots ax.scatter — scatter charts

— scatter charts ax.text — text

Some of this is starting to connect. Within the axes, you can call on helper methods to place histograms, scatter plots, text, images, error bar plots, bar charts, etc. If you’re plotting one set of data in a plot, the difference between plt.plot() and ax.plot() is negligible from the observered output.

axis objects

Yes, they’re different from axes. The are two axis objects (the x axis and y axis) in 2D axes and three (the x, y, and z axis) in 3D axes.

plot / plots / subplots

These are instance variables, not objects.

Building a pyplot sandwich

hooray, a new metaphor!

plt.figure()

plt.show() output: <Figure size 864x432 with 0 Axes>

This is as basic as it gets. These two lines of code are the sandwich in the pyplot sandwich. Without anything between them, it’s not a sandwich, it’s two pieces of bread. It’s created a figure with 0 axes, because there is nothing. It’s important to think of it as a sandwich and not a blank canvas. There isn’t a blank Axes, there’s no Axes.

plt.figure()

ax = fig.add_subplot(1,1,1) - or - (111)

plt.show() output: (plot below)

an added, but empty subplot

Now we have a frame and a subplot within that frame. The (1,1,1) indicates there will be 1 row of plots, 1 column of plots and this will be the first plot. (rows, columns, plot number). There is no ax to display, but there is a figure and that is why it is empty.

plt.figure()

fig, ax = plt.subplots()

ax.plot(x,y)

plt.show()

the visual output is the same

plt.plot(x, y)

We can go one step further to simplify this.

y = [1,2,3,4]

plt.plot(y) # is the same as x = [0,1,2,3]

y = [1,2,3,4]

plt.plot(x,y)

Matplotlib assumes the values you are giving are a sequence of y values if you onlt provide one set of values, so it automatically assigns them x values of [0,1,2,3,…,n-1, n].

But what’s the actual difference here?

Glad you asked. These are two approaches to creating plots and they’re rooted in the difference between Matplotlib and Pyplot.

plt.plot(x, y)

This is “Pyplot” style. It’s modeled after MATLAB and I have begun to hate that statement.

plt.figure()

fig, ax = plt.subplots()

ax.plot(x,y)

plt.show()

This is Matplotlib’s Object Oriented API. Once you accept that Matplotlib is using an OO API, the concept of it all changes. They are interchangeable for small tasks and easy to use, but separating them from each other will help understand how each works and how each works independent from each other.