Clearing the confusion: fig, ax = plt.subplots() | Towards Data Science

By reading this article, you will learn the two core objects in Maptlolib plots: figure and axes. You will finally understand the difference between simple plotting (plt.plot) and creating subplots with plt.subplots().
When you begin your journey into Data Science, you are introduced to Matplotlib as your first library for Data Visualization. Most tutorials for beginners play a cruel trick on students by introducing them first to the ‘beginner-friendly’ pyplot > plt interface. As these poor students venture into the real world, they will find out the dudes on StackOverflow and most other people use a more flexible object-oriented way. They will get confused and most probably move on to Seaborn and Plotly. Or even worse, to the no-code interface of Tableau, like I almost did. (Because of this confusion, I specifically remember myself going through Quora and StackOverflow threads wondering if people were using Tableau over Matplotlib)
This article will introduce you to figure and axes objects in Matplotlib and their advantages over other methods.
   I. Introduction  II. Setup III. plt.subplots(), preliminary understanding  IV. Axes methods vs. pyplot, understanding further   V. plt.subplots() grid system  VI. Doubling axis VII. Sharing a commong axis between subplotsVIII. Working with figure object  IX. Conclusion
The sample data and the notebook of the article are available in this GitHub repo.
>>> climate_change.head()
It all starts with calling .subplots() command:
>>> plt.subplots()(<Figure size 432x288 with 1 Axes>, <AxesSubplot:>)
If you pay attention, apart from the blank plot, the function also returned a tuple of two values:
[OUT]: (<Figure size 432x288 with 1 Axes>, <AxesSubplot:>)
Every time we call subplots() function, it will return these types of tuples always with two values. In Python, there is a technique called tuple unpacking. Let me show you a simple example:
If we print the values of the above three:
>>> print(ten)10>>> print(eleven)11>>> print(twelve)12
Great, we unpacked a tuple of size 3 into three different variables. So, now you will understand this code better:
We created two variables, fig and ax. Remember, these are arbitrary names but a standard and we are one of the good guys, so we will follow the convention.
These two variables now hold the two core objects used for all types of plotting operations. First object fig, short for figure, imagine it as the frame of your plot. You can resize, reshape the frame but you cannot draw on it. On a single notebook or a script, you can have multiple figures. Each figure can have multiple subplots. Here, subplot is synonymous with axes. The second object, ax, short for axes, is the canvas you draw on. Or rephrasing, it is the blank sheet you can plot and hold your data. An axes object can only belong to one figure.
At the beginning of the post, I said that pyplot was a more beginner-friendly method to interact with Matplotlib. It is true that compared to axes methods, pyplot offers a quicker and more concise method of plotting. It will have less local variables and syntax. But why most people prefer the object-oriented way?
Let’s see the concise way of pyplot:
Well, this was easy. It only took us three lines. Now let’s what happens if we try to plot (completely unrelated) the climate change data next to it:
In this case, we get a TypeError. pyplot, on its own, cannot create new axes or a new figure and intelligently plot the new data. As we get to more complex plotting like this one, we are going to need a more flexible approach.
Mpl has this concept called current figure. By default, pyplot itself creates a current figure axes and plots on it. If for example, we want to focus on that current figure and plot extra data on it, as we tried in the last example, pyplot moves the current figure to a new one immediately after a new plotting command is given.
To avoid this, let’s see the approach where we are in full control of each figure and axes:
We specifically point out that we are working on this fig object. It means that any plotting command we write will be applied to the axes (ax) object that belongs to fig. Unless, we define a new figure with plt.subplots() command, the current figure will be the variable fig. This way is very nice since now we can create as many axes or subplots in a single figure and work with them.
From now on, I will be using subplot and axes terms interchangeably as they are synonyms.
We saw an example of creating one subplot. Let’s see how can create more in a single figure:
Among other parameters, .subplots() have two parameters to specify the grid size. nrows and ncols are used to point out the number of rows and columns we need respectively. If you paid attention, now our second variable contains not one but two axes. And it is now given as a numpy.ndarray. So, we have to unpack or index this array to use our plotting commands:
Pro Tip: Notice the fig.tight_layout() function with padding set to 3. It will give the subplots a little breathing room.
The two methods are completely similar and up to you to choose one. Let’s see one more example but slightly more difficult:
Pro Tip: Set the figsize=(width, height) argument properly. It will make your plots more distinct.
This article is not about plotting in particular, but to give you intuition for figure and axes objects. However, let me briefly walk you through some of the other common methods for the axes object:
All the methods that are available in pyplot API has an equivalent through ax.set_. If you use a general, ax.set() method, you will avoid repetition when you have multiple subplots. However, if you need to specify additional parameters to specific parts of your plot, use ax.set_:
Sometimes, we want to have a single subplot to have more than one XAxis or YAxis. While it is not possible with plain pyplot interface, it is very easy with top-level figure object-oriented API. Let's say we want to plot the relative_temp and co2 columns of climate_change in a single plot. We want them to share an XAxis since the data is for the same time period:
We wanted to have a common XAxis, which was date column, so we created another axis using ax.twinx(). If in some cases you want a common YAxis, the equivalent function is ax.twiny().
Let’s say we wanted to compare the CO2 emissions of the eighties with nineties. Ideally, we would want to plot the eighties on one side and nineties to the other. So, let’s subset our data for these two time periods:
Pro Tip: Set the date column as an index for a dataframe if you are working with time-series data. Use .set_index() method or use index_col parameter in pd.read_csv() function. It will make subsetting for time periods much easier.
Great, we have the two plots side by side, but if we look closer, our plots are misleading. It looks like there was not much difference in CO2 emmissions throughout two time periods. The reason for this is that the two plots have different YAxis ranges. Let's set it right for better insight:
Now, it is clear that CO2 emissions continued increasing through time (it is much higher that this right now). We use sharey=True to specify that we want the same YAxis for all the subplots.
I think you noticed that once you create a figure object using .subplots() command or other methods, pretty much everything happens with axes objects. One common method of figure object is savefig() method. So, let's get exploring. We will get back to our double-axed plot of CO2. Let's save it to local memory:
We passed a filename as a string to save. This saves an image with that name in the root directory. Possible image formats to use:
.png - if you want your figures to be of high quality and do not care about disk space, use png. This format allows for lossless compression..jpg - lossy compression. jpg images will have less size than pngs and have lower quality. This format is recommended if you want to upload the images later to a website or any other similar ways..svg - supports animations and image editing. Use this format if you want to modify the figures using editing software like Adobe Illustrator.
.png - if you want your figures to be of high quality and do not care about disk space, use png. This format allows for lossless compression.
.jpg - lossy compression. jpg images will have less size than pngs and have lower quality. This format is recommended if you want to upload the images later to a website or any other similar ways.
.svg - supports animations and image editing. Use this format if you want to modify the figures using editing software like Adobe Illustrator.
Other parameters of .savefig() allows for controlling the quality of your figures:
I hope that you now have a clear understanding of figure and axes objects. We only covered one of the methods of plotting in Matplotlib. The library can go as deep as you want if you wish to explore further. You can learn more about the methods of figure and axes objects on the official documentation of Matplotlib. I highly suggest you try out other features and practice! (BTW, that was a lot of GitHub gists!)
Check out my other hits on Medium: