02-09-2020, 03:51 AM
Matplotlib Subplots – A Helpful Illustrated Guide
<div><p>Too much stuff happening in a single plot? No problem—use multiple subplots!</p>
<p><em>This in-depth tutorial shows you everything you need to know to get started with Matplotlib’s <code>subplots()</code> function.</em></p>
<p>If you want, just hit “play” and watch the explainer video. I’ll then guide you through the tutorial:</p>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<div class="ast-oembed-container"><iframe title="Matplotlib Subplots - A Helpful Illustrated Guide" width="1100" height="825" src="https://www.youtube.com/embed/B9NTkxrOXjk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div>
</figure>
<p>Let’s start with the short answer on how to use it—you’ll learn all the details later!</p>
<p><strong>The <code>plt.subplots()</code> function creates a <code>Figure</code> and a <a href="https://blog.finxter.com/what-are-advantages-of-numpy-over-regular-python-lists/">Numpy array</a> of <code>Subplot</code>/<code>Axes</code> objects which you store in <code>fig</code> and <code>axes</code> respectively.</strong></p>
<p><strong>Specify the number of rows and columns you want with the <code>nrows</code> and <code>ncols</code> arguments.</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=3, ncols=1)
</pre>
<p><strong>This creates a <code>Figure</code> and <code>Subplots</code> in a 3×1 grid. The Numpy array <code>axes</code> has shape <code>(nrows, ncols)</code> the same shape as the grid, in this case <code>(3,)</code> (it’s a 1D array since one of <code>nrows</code> or <code>ncols</code> is 1). Access each <code>Subplot</code> using Numpy <a href="https://blog.finxter.com/how-do-you-slice-and-index-multidimensional-arrays-in-numpy/">slice notation</a> and call the <code>plot()</code> method to plot a line graph.</strong></p>
<p>Once all <code>Subplots</code> have been plotted, call <code>plt.tight_layout()</code> to ensure no parts of the plots overlap. Finally, call <code>plt.show()</code> to display your plot.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Import necessary modules and (optionally) set Seaborn style
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
import numpy as np # Generate data to plot
linear = [x for x in range(5)]
square = [x**2 for x in range(5)]
cube = [x**3 for x in range(5)] # Generate Figure object and Axes object with shape 3x1
fig, axes = plt.subplots(nrows=3, ncols=1) # Access first Subplot and plot linear numbers
axes[0].plot(linear) # Access second Subplot and plot square numbers
axes[1].plot(square) # Access third Subplot and plot cube numbers
axes[2].plot(cube) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img0.png" alt=""/></figure>
<h2>Matplotlib Figures and Axes</h2>
<p>Up until now, you have probably made all your plots with the functions in <code>matplotlib.pyplot</code> i.e. all the functions that start with <code>plt.</code>.</p>
<p>These work nicely when you draw one plot at a time. But to draw multiple plots on one <code>Figure</code>, you need to learn the underlying classes in matplotlib.</p>
<p>Let’s look at an image that explains the main classes from the <a href="https://github.com/matplotlib/AnatomyOfMatplotlib">AnatomyOfMatplotlib</a> tutorial:</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img1.png" alt=""/></figure>
<p>To quote AnatomyOfMatplotlib:</p>
<blockquote class="wp-block-quote">
<p>The <code>Figure</code> is the top-level container in this hierarchy. It is the overall window/page that everything is drawn on. You can have multiple independent figures and <code>Figure</code>s can contain multiple <code>Axes</code>.</p>
<p>Most plotting ocurs on an <code>Axes</code>. The axes is effectively the area that we plot data on and any ticks/labels/etc associated with it. Usually we’ll set up an Axes with a call to <code>subplots</code> (which places Axes on a regular grid), so in most cases, <code>Axes</code> and <code>Subplot</code> are synonymous.</p>
<p>Each <code>Axes</code> has an <code>XAxis</code> and a <code>YAxis</code>. These contain the ticks, tick locations, labels, etc. In this tutorial, we’ll mostly control ticks, tick labels, and data limits through other mechanisms, so we won’t touch the individual <code>Axis</code> part of things all that much. However, it is worth mentioning here to explain where the term <code>Axes</code> comes from.</p>
</blockquote>
<p>The typical variable names for each object are:</p>
<ul>
<li><code>Figure</code> – <code>fig</code> or <code>f</code>,</li>
<li><code>Axes</code> (plural) – <code>axes</code> or <code>axs</code>,</li>
<li><code>Axes</code> (singular) – <code>ax</code> or <code>a</code></li>
</ul>
<p>The word <code>Axes</code> refers to the area you plot on and is synonymous with <code>Subplot</code>. However, you can have multiple <code>Axes</code> (<code>Subplots</code>) on a <code>Figure</code>. In speech and writing use the same word for the singular and plural form. In your code, you should make a distinction between each – you plot on a singular <code>Axes</code> but will store all the <code>Axes</code> in a Numpy array.</p>
<p>An <code>Axis</code> refers to the <code>XAxis</code> or <code>YAxis</code> – the part that gets ticks and labels.</p>
<p>The <code>pyplot</code> module implicitly works on one <code>Figure</code> and one <code>Axes</code> at a time. When we work with <code>Subplots</code>, we work with multiple <code>Axes</code> on one <code>Figure</code>. So, it makes sense to plot with respect to the <code>Axes</code> and it is much easier to keep track of everything.</p>
<p>The main differences between using <code>Axes</code> methods and <code>pyplot</code> are:</p>
<ol>
<li>Always create a <code>Figure</code> and <code>Axes</code> objects on the first line</li>
<li>To plot, write <code>ax.plot()</code> instead of <code>plt.plot()</code>.</li>
</ol>
<p>Once you get the hang of this, you won’t want to go back to using <code>pyplot</code>. It’s much easier to create interesting and engaging plots this way. In fact, this is why most <a href="https://stackoverflow.com/questions/tagged/matplotlib">StackOverflow answers</a> are written with this syntax.</p>
<p>All of the functions in <code>pyplot</code> have a corresponding method that you can call on <code>Axes</code> objects, so you don’t have to learn any new functions.</p>
<p>Let’s get to it.</p>
<h2>Matplotlib Subplots Example</h2>
<p>The <code>plt.subplots()</code> function creates a <code>Figure</code> and a Numpy array of <code>Subplots</code>/<code>Axes</code> objects which we store in <code>fig</code> and <code>axes</code> respectively.</p>
<p>Specify the number of rows and columns you want with the <code>nrows</code> and <code>ncols</code> arguments.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=3, ncols=1)
</pre>
<p>This creates a <code>Figure</code> and <code>Subplots</code> in a 3×1 grid. The <a href="https://blog.finxter.com/numpy-tutorial/">Numpy</a> array <code>axes</code> is the same shape as the grid, in this case <code>(3,)</code>. Access each <code>Subplot</code> using Numpy slice notation and call the <code>plot()</code> method to plot a line graph.</p>
<p>Once all <code>Subplots</code> have been plotted, call <code>plt.tight_layout()</code> to ensure no parts of the plots overlap. Finally, call <code>plt.show()</code> to display your plot. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img2.png" alt=""/></figure>
<p>The most important arguments for <code>plt.subplots()</code> are similar to the <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html">matplotlib subplot</a> function but can be specified with keywords. Plus, there are more powerful ones which we will discuss later.</p>
<p>To create a <code>Figure</code> with one <code>Axes</code> object, call it without any arguments</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, ax = plt.subplots()
</pre>
<p>Note: this is implicitly called whenever you use the <code>pyplot</code> module. All ‘normal’ plots contain one <code>Figure</code> and one <code>Axes</code>.</p>
<p>In advanced blog posts and StackOverflow answers, you will see a line similar to this at the top of the code. It is much more Pythonic to create your plots with respect to a <code>Figure</code> and <code>Axes</code>.</p>
<p>To create a <code>Grid</code> of subplots, specify <code>nrows</code> and <code>ncols</code> – the number of rows and columns respectively</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2)
</pre>
<p>The variable <code>axes</code> is a numpy array with shape <code>(nrows, ncols)</code>. Note that it is in the plural form to indicate it contains more than one <code>Axes</code> object. Another common name is <code>axs</code>. Choose whichever you prefer. If you call <code>plt.subplots()</code> without an argument name the variable <code>ax</code> as there is only one <code>Axes</code> object returned.</p>
<p>I will select each <code>Axes</code> object with slicing notation and plot using the appropriate methods. Since I am using Numpy slicing, the index of the first <code>Axes</code> is 0, not 1.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Create Figure and 2x2 gris of Axes objects
fig, axes = plt.subplots(nrows=2, ncols=2) # Generate data to plot. data = np.array([1, 2, 3, 4, 5]) # Access Axes object with Numpy slicing then plot different distributions
axes[0, 0].plot(data)
axes[0, 1].plot(data**2)
axes[1, 0].plot(data**3)
axes[1, 1].plot(np.log(data)) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img3.png" alt=""/></figure>
<p>First I import the necessary modules, then create the <code>Figure</code> and <code>Axes</code> objects using <code>plt.subplots()</code>. The <code>Axes</code> object is a Numpy array with shape <code>(2, 2)</code> and I access each subplot via Numpy slicing before doing a line plot of the data. Then, I call <code>plt.tight_layout()</code> to ensure the axis labels don’t overlap with the plots themselves. Finally, I call <code>plt.show()</code> as you do at the end of all matplotlib plots.</p>
<h2>Matplotlib Subplots Title</h2>
<p>To add an overall title to the <code>Figure</code>, use <code>plt.suptitle()</code>.</p>
<p>To add a title to each <code>Axes</code>, you have two methods to choose from:</p>
<ol>
<li><code>ax.set_title('bar')</code></li>
<li><code>ax.set(title='bar')</code></li>
</ol>
<p>In general, you can set anything you want on an <code>Axes</code> using either of these methods. I recommend using <code>ax.set()</code> because you can pass <em>any</em> setter function to it as a keyword argument. This is faster to type, takes up fewer lines of code and is easier to read.</p>
<p>Let’s set the title, xlabel and ylabel for two <code>Subplots</code> using both methods for comparison</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Unpack the Axes object in one line instead of using slice notation
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) # First plot - 3 lines
ax1.set_title('many')
ax1.set_xlabel('lines')
ax1.set_ylabel('of code') # Second plot - 1 line
ax2.set(title='one', xlabel='line', ylabel='of code') # Overall title
plt.suptitle('My Lovely Plot')
plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img4.png" alt=""/></figure>
<p>Clearly using <code>ax.set()</code> is the better choice.</p>
<p>Note that I unpacked the <code>Axes</code> object into individual variables on the first line. You can do this instead of Numpy slicing if you prefer. It is easy to do with 1D arrays. Once you create grids with multiple rows and columns, it’s easier to read if you don’t unpack them.</p>
<h2>Matplotlib Subplots Share X Axis</h2>
<p>To share the x axis for subplots in matplotlib, set <code>sharex=True</code> in your <code>plt.subplots()</code> call.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data
data = [0, 1, 2, 3, 4, 5] # 3x1 grid that shares the x axis
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # 3 different plots
axes[0].plot(data)
axes[1].plot(np.sqrt(data))
axes[2].plot(np.exp(data)) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img5.png" alt=""/></figure>
<p>Here I created 3 line plots that show the linear, square root and exponential of the numbers 0-5.</p>
<p>As I used the same numbers, it makes sense to share the x-axis.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img6.png" alt=""/></figure>
<p>Here I wrote the same code but set <code>sharex=False</code> (the default behavior). Now there are unnecessary axis labels on the top 2 plots.</p>
<p>You can also share the y axis for plots by setting <code>sharey=True</code> in your <code>plt.subplots()</code> call.</p>
<h2>Matplotlib Subplots Legend</h2>
<p>To add a legend to each <code>Axes</code>, you must</p>
<ol>
<li>Label it using the <code>label</code> keyword</li>
<li>Call <code>ax.legend()</code> on the <code>Axes</code> you want the legend to appear</li>
</ol>
<p>Let’s look at the same plot as above but add a legend to each <code>Axes</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data, 3x1 plot with shared XAxis
data = [0, 1, 2, 3, 4, 5]
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # Plot the distributions and label each Axes
axes[0].plot(data, label='Linear')
axes[1].plot(np.sqrt(data), label='Square Root')
axes[2].plot(np.exp(data), label='Exponential') # Add a legend to each Axes with default values
for ax in axes: ax.legend() plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img7.png" alt=""/></figure>
<p>The legend now tells you which function has been applied to the data. I used a for loop to call <code>ax.legend()</code> on each of the <code>Axes</code>. I could have done it manually instead by writing:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">axes[0].legend()
axes[1].legend()
axes[2].legend()
</pre>
<p>Instead of having 3 legends, let’s just add one legend to the <code>Figure</code> that describes each line. Note that you need to change the color of each line, otherwise the legend will show three blue lines.</p>
<p>The <a href="https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.legend.html">matplotlib legend</a> function takes 2 arguments</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax.legend(handles, labels)
</pre>
<ul>
<li><code>handles</code> – the lines/plots you want to add to the legend (list)</li>
<li><code>labels</code> – the labels you want to give each line (list)</li>
</ul>
<p>Get the <code>handles</code> by storing the output of you <code>ax.plot()</code> calls in a list. You need to create the list of <code>labels</code> yourself. Then call <code>legend()</code> on the <code>Axes</code> you want to add the legend to.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data and 3x1 grid with a shared x axis
data = [0, 1, 2, 3, 4, 5]
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # Store the output of our plot calls to use as handles
# Plot returns a list of length 1, so unpack it using a comma
linear, = axes[0].plot(data, 'b')
sqrt, = axes[1].plot(np.sqrt(data), 'r')
exp, = axes[2].plot(np.exp(data), 'g') # Create handles and labels for the legend
handles = [linear, sqrt, exp]
labels = ['Linear', 'Square Root', 'Exponential'] # Draw legend on first Axes
axes[0].legend(handles, labels) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img8.png" alt=""/></figure>
<p>First I generated the data and a 3×1 grid. Then I made three <code>ax.plot()</code> calls and applied different functions to the data.</p>
<p>Note that <code>ax.plot()</code> returns a <code>list</code> of <code>matplotlib.line.Line2D</code> objects. You have to pass these <code>Line2D</code> objects to <code>ax.legend()</code> and so need to unpack them first.</p>
<p>Standard unpacking syntax in Python is:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">a, b = [1, 2]
# a = 1, b = 2
</pre>
<p>However, each <code>ax.plot()</code> call returns a list of length 1. To unpack these lists, write</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">x, = [5]
# x = 5
</pre>
<p>If you just wrote <code>x = [5]</code> then <code>x</code> would be a list and not the object inside the list.</p>
<p>After the <code>plot()</code> calls, I created 2 lists of <code>handles</code> and <code>labels</code> which I passed to <code>axes[0].legend()</code> to draw it on the first plot.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img9.png" alt=""/></figure>
<p>In the above plot, I changed the<code>legend</code> call to <code>axes[1].legend(handles, labels)</code> to plot it on the second (middle) <code>Axes</code>.</p>
<h2>Matplotlib Subplots Size</h2>
<p>You have total control over the size of subplots in matplotlib.</p>
<p>You can either change the size of the entire <code>Figure</code> or the size of the <code>Subplots</code> themselves.</p>
<p>First, let’s look at changing the <code>Figure</code>.</p>
<h3>Matplotlib Figure Size</h3>
<p>If you are happy with the size of your subplots but you want the final image to be larger/smaller, change the <code>Figure</code>.</p>
<p>If you’ve read my article on the matplotlib subplot function, you know to use the <code>plt.figure()</code> function to to change the <code>Figure</code>. Fortunately, any arguments passed to <code>plt.subplots()</code> are also passed to <code>plt.figure()</code>. So, you don’t have to add any extra lines of code, just keyword arguments.</p>
<p>Let’s change the size of the <code>Figure</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Create 2x1 grid - 3 inches wide, 6 inches long
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(3, 6))
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img10.png" alt=""/></figure>
<p>I created a 2×1 plot and set the <code>Figure</code> size with the <code>figsize</code> argument. It accepts a tuple of 2 numbers – the <code>(width, height)</code> of the image in inches.</p>
<p>So, I created a plot 3 inches wide and 6 inches long – <code>figsize=(3, 6)</code>. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># 2x1 grid - twice as long as it is wide
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=plt.figaspect(2))
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img11.png" alt=""/></figure>
<p>You can set a more general <code>Figure</code> size with the <a href="https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.figure.figaspect.html">matplotlib figaspect</a> function. It lets you set the aspect ratio (height/width) of the <code>Figure</code>.</p>
<p>Above, I created a <code>Figure</code> twice as long as it is wide by setting <code>figsize=plt.figaspect(2)</code>.</p>
<p>Note: Remember the aspect ratio (height/width) formula by recalling that <code>height</code> comes first in the alphabet before <code>width</code>.</p>
<h2>Matplotlib Subplots Different Sizes</h2>
<p>If you have used <code>plt.subplot()</code> before (<a href="https://blog.finxter.com/matplotlib-subplot/">I’ve written a whole tutorial on this too</a>), you’ll know that the grids you create are limited. Each <code>Subplot</code> must be part of a regular grid i.e. of the form <code>1/x</code> for some integer <code>x</code>. If you create a 2×1 grid, you have 2 rows and each row takes up 1/2 of the space. If you create a 3×2 grid, you have 6 subplots and each takes up 1/6 of the space.</p>
<p>Using <code>plt.subplots()</code> you can create a 2×1 plot with 2 rows that take up any fraction of space you want.</p>
<p>Let’s make a 2×1 plot where the top row takes up 1/3 of the space and the bottom takes up 2/3.</p>
<p>You do this by specifying the <code>gridspec_kw</code> argument and passing a <a href="https://blog.finxter.com/python-dictionary/">dictionary </a>of values. The main arguments we are interested in are <code>width_ratios</code> and <code>height_ratios</code>. They accept lists that specify the width ratios of columns and height ratios of the rows. In this example the top row is <code>1/3</code> of the <code>Figure</code> and the bottom is <code>2/3</code>. Thus the height ratio is <code>1:2</code> or <code>[1, 2]</code> as a list.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># 2 x1 grid where top is 1/3 the size and bottom is 2/3 the size
fig, axes = plt.subplots(nrows=2, ncols=1, gridspec_kw={'height_ratios': [1, 2]}) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img12.png" alt=""/></figure>
<p>The only difference between this and a regular 2×1 <code>plt.subplots()</code> call is the <code>gridspec_kw</code> argument. It accepts a dictionary of values. These are passed to the <a href="https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec">matplotlib GridSpec</a> constructor (the underlying class that creates the grid).</p>
<p>Let’s create a 2×2 plot with the same <code>[1, 2]</code> height ratios but let’s make the left hand column take up 3/4 of the space. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Heights: Top row is 1/3, bottom is 2/3 --> [1, 2]
# Widths : Left column is 3/4, right is 1/4 --> [3, 1]
ratios = {'height_ratios': [1, 2], 'width_ratios': [3, 1]} fig, axes = plt.subplots(nrows=2, ncols=2, gridspec_kw=ratios) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img13.png" alt=""/></figure>
<p>Everything is the same as the previous plot but now we have a 2×2 grid and have specified <code>width_ratios</code>. Since the left column takes up <code>3/4</code> of the space and the right takes up <code>1/4</code> the ratios are <code>[3, 1]</code>.</p>
<h2>Matplotlib Subplots Size</h2>
<p>In the previous examples, there were white lines that cross over each other to separate the <code>Subplots</code> into a clear grid. But sometimes you will not have that to guide you. To create a more complex plot, you have to manually add <code>Subplots</code> to the grid.</p>
<p>You could do this using the <code>plt.subplot()</code> function. But since we are focusing on <code>Figure</code> and <code>Axes</code> notation in this article, I’ll show you how to do it another way.</p>
<p>You need to use the <code>fig.add_subplot()</code> method and it has the same notation as <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html"><code>plt.subplot()</code></a>. Since it is a <code>Figure</code> method, you first need to create one with the <code>plt.figure()</code> function.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure()
</pre>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""><Figure size 432x288 with 0 Axes></pre>
<p>The hardest part of creating a <code>Figure</code> with different sized <code>Subplots</code> in matplotlib is figuring out what fraction of space each <code>Subplot</code> takes up.</p>
<p>So, it’s a good idea to know what you are aiming for before you start. You could sketch it on paper or draw shapes in PowerPoint. Once you’ve done this, everything else is much easier.</p>
<p>I’m going to create this shape.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img14.png" alt=""/></figure>
<p>I’ve labeled the fraction each <code>Subplot</code> takes up as we need this for our <code>fig.add_subplot()</code> calls.</p>
<p>I’ll create the biggest <code>Subplot</code> first and the others in descending order.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img15.png" alt=""/></figure>
<p>The right hand side is half of the plot. It is one of two plots on a <code>Figure</code> with 1 row and 2 columns. To select it with <code>fig.add_subplot()</code>, you need to set <code>index=2</code>.</p>
<p>Remember that indexing starts from 1 for the functions <code>plt.subplot()</code> and <code>fig.add_subplot()</code>.</p>
<p>In the image, the blue numbers are the index values each <code>Subplot</code> has.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax1 = fig.add_subplot(122)
</pre>
<p>As you are working with <code>Axes</code> objects, you need to store the result of <code>fig.add_subplot()</code> so that you can plot on it afterwards.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img16.png" alt=""/></figure>
<p>Now, select the bottom left <code>Subplot</code> in a a 2×2 grid i.e. <code>index=3</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax2 = fig.add_subplot(223)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img17.png" alt=""/></figure>
<p>Lastly, select the top two <code>Subplots</code> on the left hand side of a 4×2 grid i.e. <code>index=1</code> and <code>index=3</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax3 = fig.add_subplot(423)
ax4 = fig.add_subplot(421)
</pre>
<p>When you put this altogether you get </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Initialise Figure
fig = plt.figure() # Add 4 Axes objects of the size we want
ax1 = fig.add_subplot(122)
ax2 = fig.add_subplot(223)
ax3 = fig.add_subplot(423)
ax4 = fig.add_subplot(421) plt.tight_layout(pad=0.1)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img18.png" alt=""/></figure>
<p>Perfect! Breaking the <code>Subplots</code> down into their individual parts and knowing the shape you want, makes everything easier.</p>
<p>Now, let’s do something you can’t do with <code>plt.subplot()</code>. Let’s have 2 plots on the left hand side with the bottom plot twice the height as the top plot.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img19.png" alt=""/></figure>
<p>Like with the above plot, the right hand side is half of a plot with 1 row and 2 columns. It is <code>index=2</code>.</p>
<p>So, the first two lines are the same as the previous plot</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure()
ax1 = fig.add_subplot(122)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img20.png" alt=""/></figure>
<p>The top left takes up <code>1/3</code> of the space of the left-hand half of the plot. Thus, it takes up <code>1/3 x 1/2 = 1/6</code> of the total plot. So, it is <code>index=1</code> of a 3×2 grid.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax2 = fig.add_subplot(321)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img21.png" alt=""/></figure>
<p>The final subplot takes up 2/3 of the remaining space i.e. <code>index=3</code> and <code>index=5</code> of a 3×2 grid. But you can’t add both of these indexes as that would add two <code>Subplots</code> to the <code>Figure</code>. You need a way to add one <code>Subplot</code> that <em>spans</em> two rows.</p>
<p>You need the <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot2grid.html#matplotlib.pyplot.subplot2grid">matplotlib subplot2grid</a> function – <code>plt.subplot2grid()</code>. It returns an <code>Axes</code> object and adds it to the current <code>Figure</code>.</p>
<p>Here are the most important arguments:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax = plt.subplot2grid(shape, loc, rowspan, colspan)
</pre>
<ul>
<li><code>shape</code> – tuple of 2 integers – the <em>shape</em> of the overall grid e.g. (3, 2) has 3 rows and 2 columns.</li>
<li><code>loc</code> – tuple of 2 integers – the <em>location</em> to place the <code>Subplot</code> in the grid. It uses 0-based indexing so (0, 0) is first row, first column and (1, 2) is second row, third column.</li>
<li><code>rowspan</code> – integer, default 1- number of rows for the <code>Subplot</code> to span to the right</li>
<li><code>colspan</code> – integer, default 1 – number of columns for the <code>Subplot</code> to span down</li>
</ul>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img22.png" alt=""/></figure>
<p>From those definitions, you need to select the middle left <code>Subplot</code> and set <code>rowspan=2</code> so that it spans down 2 rows.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img23.png" alt=""/></figure>
<p>Thus, the arguments you need for <code>subplot2grid</code> are:</p>
<ul>
<li><code>shape=(3, 2)</code> – 3×2 grid</li>
<li><code>loc=(1, 0)</code> – second row, first colunn (0-based indexing)</li>
<li><code>rowspan=2</code> – span down 2 rows</li>
</ul>
<p>This gives</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax3 = plt.subplot2grid(shape=(3, 2), loc=(1, 0), rowspan=2)
</pre>
<p>Sidenote: why matplotlib chose 0-based indexing for <code>loc</code> when <em>everything else</em> uses 1-based indexing is a mystery to me. One way to remember it is that <code>loc</code> is similar to <code>locating</code>. This is like slicing Numpy arrays which use 0-indexing. Also, if you use <code>GridSpec</code>, you will often use Numpy slicing to choose the number of rows and columns that <code>Axes</code> span.</p>
<p>Putting this together, you get </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure() ax1 = fig.add_subplot(122)
ax2 = fig.add_subplot(321)
ax3 = plt.subplot2grid(shape=(3, 2), loc=(1, 0), rowspan=2) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img24.png" alt=""/></figure>
<h2>Matplotlib Subplots_Adjust</h2>
<p>If you aren’t happy with the spacing between plots that <code>plt.tight_layout()</code> provides, manually adjust the spacing with the <a href="https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.subplots_adjust.html">matplotlib subplots_adjust</a> function.</p>
<p>It takes 6 optional, self explanatory arguments. Each is a float in the range [0.0, 1.0] and is a fraction of the font size:</p>
<ul>
<li><code>left</code>, <code>right</code>, <code>bottom</code> and <code>top</code> is the spacing on each side of the <code>Suplots</code></li>
<li><code>wspace</code> – the <strong>width</strong> between <code>Subplots</code></li>
<li><code>hspace</code> – the <strong>height</strong> between <code>Subplots</code></li>
</ul>
<p>Let’s compare <code>tight_layout</code> with <code>subplots_adjust</code>. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2, sharex=<strong>True</strong>, sharey=<strong>True</strong>) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img25.png" alt=""/></figure>
<p>Here is a 2×2 grid with <code>plt.tight_layout()</code>. I’ve set <code>sharex</code> and <code>sharey</code> to <code>True</code> to remove unnecessary axis labels. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2, sharex=<strong>True</strong>, sharey=<strong>True</strong>) plt.subplots_adjust(wspace=0.05, hspace=0.05)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img26.png" alt=""/></figure>
<p>Now I’ve decreased the height and width between <code>Subplots</code> to <code>0.05</code> and there is hardly any space between them.</p>
<p>To avoid loads of similar examples, I recommend you play around with the arguments to get a feel for how this function works.</p>
<h2>Matplotlib Subplots Colorbar</h2>
<p>Adding a colorbar to each <code>Axes</code> is similar to adding a legend. You store the <code>ax.plot()</code> call in a variable and pass it to <code>fig.colorbar()</code>.</p>
<p>Colorbars are <code>Figure</code> methods since they are placed on the <code>Figure</code> itself and not the <code>Axes</code>. Yet, they do take up space from the <code>Axes</code> they are placed on.</p>
<p>Let’s look at an example.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate two 10x10 arrays of random numbers in the range [0.0, 1.0]
data1 = np.random.random((10, 10))
data2 = np.random.random((10, 10)) # Initialise Figure and Axes objects with 1 row and 2 columns
# Constrained_layout=True is better than plt.tight_layout()
# Make twice as wide as it is long with figaspect
fig, axes = plt.subplots(nrows=1, ncols=2, constrained_layout=True, figsize=plt.figaspect(1/2)) pcm1 = axes[0].pcolormesh(data1, cmap='Blues')
# Place first colorbar on first column - index 0
fig.colorbar(pcm1, ax=axes[0]) pcm2 = axes[1].pcolormesh(data2, cmap='Greens')
# Place second colorbar on second column - index 1
fig.colorbar(pcm2, ax=axes[1]) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img27.png" alt=""/></figure>
<p>First, I generated two 10×10 arrays of random numbers in the range [0.0, 1.0] using the <code>np.random.random()</code> function. Then I initialized the 1×2 grid with <code>plt.subplots()</code>.</p>
<p>The keyword argument <code>constrained_layout=True</code> achieves a similar result to calling <code>plt.tight_layout()</code>. However, <code>tight_layout</code> only checks for tick labels, axis labels and titles. Thus, it ignores colorbars and legends and often produces bad looking plots. Fortunately, <code>constrained_layout</code> takes colorbars and legends into account. Thus, it should be your go-to when automatically adjusting these types of plots.</p>
<p>Finally, I set <code>figsize=plt.figaspect(1/2)</code> to ensure the plots aren’t too squashed together.</p>
<p>After that, I plotted the first heatmap, colored it blue and saved it in the variable <code>pcm1</code>. I passed that to <code>fig.colorbar()</code> and placed it on the first column – <code>axes[0]</code> with the <code>ax</code> keyword argument. It’s a similar story for the second heatmap.</p>
<p>The more <code>Axes</code> you have, the fancier you can be with <a href="https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/colorbar_placement.html">placing colorbars in matplotlib</a>. Now, let’s look at a 2×2 example with 4 <code>Subplots</code> but only 2 colorbars.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Set seed to reproduce results
np.random.seed(1) # Generate 4 samples of the same data set using a list comprehension # and assignment unpacking
data1, data2, data3, data4 = [np.random.random((10, 10)) for _ in range(4)] # 2x2 grid with constrained layout
fig, axes = plt.subplots(nrows=2, ncols=2, constrained_layout=True) # First column heatmaps with same colormap
pcm1 = axes[0, 0].pcolormesh(data1, cmap='Blues')
pcm2 = axes[1, 0].pcolormesh(data2, cmap='Blues') # First column colorbar - slicing selects all rows, first column
fig.colorbar(pcm1, ax=axes[:, 0]) # Second column heatmaps with same colormap
pcm3 = axes[0, 1].pcolormesh(data3+1, cmap='Greens')
pcm4 = axes[1, 1].pcolormesh(data4+1, cmap='Greens') # Second column colorbar - slicing selects all rows, second column
# Half the size of the first colorbar
fig.colorbar(pcm3, ax=axes[:, 1], shrink=0.5) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img28.png" alt=""/></figure>
<p>If you pass a list of <code>Axes</code> to <code>ax</code>, matplotlib places the colorbar along those <code>Axes</code>. Moreover, you can specify where the colorbar is with the <code>location</code> keyword argument. It accepts the strings <code>'bottom'</code>, <code>'left'</code>, <code>'right'</code>, <code>'top'</code> or <code>'center'</code>.</p>
<p>The code is similar to the 1×2 plot I made above. First, I set the seed to 1 so that you can reproduce the results – you will soon plot this again with the colorbars in different places.</p>
<p>I used a <a href="https://blog.finxter.com/list-comprehension/">list comprehension</a> to generate 4 samples of the same <a href="https://blog.finxter.com/sets-in-python/">dataset</a>. Then I created a 2×2 grid with <code>plt.subplots()</code> and set <code>constrained_layout=True</code> to ensure nothing overlaps.</p>
<p>Then I made the plots for the first column – <code>axes[0, 0]</code> and <code>axes[1, 0]</code> – and saved their output. I passed one of them to <code>fig.colorbar()</code>. It doesn’t matter which one of <code>pcm1</code> or <code>pcm2</code> I pass since they are just different samples of the same dataset. I set <code>ax=axes[:, 0]</code> using Numpy slicing notation, that is all rows <code>:</code> and the first column <code>0</code>.</p>
<p>It’s a similar process for the second column but I added 1 to <code>data3</code> and <code>data4</code> to give a range of numbers in [1.0, 2.0] instead. Lastly, I set <code>shrink=0.5</code> to make the colorbar half its default size.</p>
<p>Now, let’s plot the same data with the same colors on each row rather than on each column.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Same as above
np.random.seed(1)
data1, data2, data3, data4 = [np.random.random((10, 10)) for _ in range(4)]
fig, axes = plt.subplots(nrows=2, ncols=2, constrained_layout=True) # First row heatmaps with same colormap
pcm1 = axes[0, 0].pcolormesh(data1, cmap='Blues')
pcm2 = axes[0, 1].pcolormesh(data2, cmap='Blues') # First row colorbar - placed on first row, all columns
fig.colorbar(pcm1, ax=axes[0, :], shrink=0.8) # Second row heatmaps with same colormap
pcm3 = axes[1, 0].pcolormesh(data3+1, cmap='Greens')
pcm4 = axes[1, 1].pcolormesh(data4+1, cmap='Greens') # Second row colorbar - placed on second row, all columns
fig.colorbar(pcm3, ax=axes[1, :], shrink=0.8) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img29.png" alt=""/></figure>
<p>This code is similar to the one above but the plots of the same color are on the same row rather than the same column. I also shrank the colorbars to 80% of their default size by setting <code>shrink=0.8</code>.</p>
<p>Finally, let’s set the blue colorbar to be on the bottom of the heatmaps.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img30.png" alt=""/></figure>
<p>You can change the location of the colorbars with the <code>location</code> keyword argument in <code>fig.colorbar()</code>. The only difference between this plot and the one above is this line</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig.colorbar(pcm1, ax=axes[0, :], shrink=0.8, location='bottom')
</pre>
<p>If you increase the <code>figsize</code> argument, this plot will look much better – at the moment it’s quite cramped.</p>
<p>I recommend you play around with matplotlib colorbar placement. You have total control over how many colorbars you put on the <code>Figure</code>, their location and how many rows and columns they span. These are some basic ideas but check out the docs to see more examples of how you can <a href="https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/colorbar_placement.html">place colorbars in matplotlib</a>.</p>
<h2>Matplotlib Subplot Grid</h2>
<p>I’ve spoken about <a href="https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html"><code>GridSpec</code></a> a few times in this article. It is the underlying class that <em>specifies the geometry of the grid that a subplot can be placed in</em>.</p>
<p>You can create any shape you want using <code>plt.subplots()</code> and <code>plt.subplot2grid()</code>. But some of the more complex shapes are easier to create using <code>GridSpec</code>. If you want to become a total pro with matplotlib, check out the docs and look out for my article discussing it in future.</p>
<h2>Summary</h2>
<p>You can now create <em>any</em> shape you can imagine in matplotlib. Congratulations! This is a huge achievement. Don’t worry if you didn’t fully understand everything the first time around. I recommend you bookmark this article and revisit it from time to time.</p>
<p>You’ve learned the underlying classes in matplotlib: <code>Figure</code>, <code>Axes</code>, <code>XAxis</code> and <code>YAxis</code> and how to plot with respect to them. You can write shorter, more readable code by using these methods and <code>ax.set()</code> to add titles, xlabels and many other things to each <code>Axes</code>. You can create more professional looking plots by sharing the x-axis and y-axis and add legends anywhere you like.</p>
<p>You can create <code>Figures</code> of any size that include <code>Subplots</code> of any size – you’re no longer restricted to those that take up <code>1/x</code>th of the plot. You know that to make the best plots, you should plan ahead and figure out the shape you are aiming for.</p>
<p>You know when to use <code>plt.tight_layout()</code> (ticks, labels and titles) and <code>constrained_layout=True</code> (legends and colorbars) and how to manually adjust spacing between plots with <code>plt.subplots_adjust()</code>.</p>
<p>Finally, you can add colorbars to as many <code>Axes</code> as you want and place them wherever you’d like.</p>
<p>You’ve done everything now. All that is left is to practice these plots so that you can quickly create amazing plots whenever you want.</p>
<h2>Where To Go From Here?</h2>
<p>Do you wish you could be a programmer full-time but don’t know how to start?</p>
<p>Check out my pure value-packed webinar where I teach you to become a Python freelancer in 60 days or your money back!</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
<p>It doesn’t matter if you’re a Python novice or Python pro. If you are not making six figures/year with Python right now, you will learn something from this webinar. </p>
<p>These are proven, no-BS methods that get you results fast.</p>
<p>This webinar won’t be online forever. Click the link below before the seats fill up and learn how to become a Python freelancer, guaranteed.</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
</div>
https://www.sickgaming.net/blog/2020/02/...ted-guide/
<div><p>Too much stuff happening in a single plot? No problem—use multiple subplots!</p>
<p><em>This in-depth tutorial shows you everything you need to know to get started with Matplotlib’s <code>subplots()</code> function.</em></p>
<p>If you want, just hit “play” and watch the explainer video. I’ll then guide you through the tutorial:</p>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<div class="ast-oembed-container"><iframe title="Matplotlib Subplots - A Helpful Illustrated Guide" width="1100" height="825" src="https://www.youtube.com/embed/B9NTkxrOXjk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div>
</figure>
<p>Let’s start with the short answer on how to use it—you’ll learn all the details later!</p>
<p><strong>The <code>plt.subplots()</code> function creates a <code>Figure</code> and a <a href="https://blog.finxter.com/what-are-advantages-of-numpy-over-regular-python-lists/">Numpy array</a> of <code>Subplot</code>/<code>Axes</code> objects which you store in <code>fig</code> and <code>axes</code> respectively.</strong></p>
<p><strong>Specify the number of rows and columns you want with the <code>nrows</code> and <code>ncols</code> arguments.</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=3, ncols=1)
</pre>
<p><strong>This creates a <code>Figure</code> and <code>Subplots</code> in a 3×1 grid. The Numpy array <code>axes</code> has shape <code>(nrows, ncols)</code> the same shape as the grid, in this case <code>(3,)</code> (it’s a 1D array since one of <code>nrows</code> or <code>ncols</code> is 1). Access each <code>Subplot</code> using Numpy <a href="https://blog.finxter.com/how-do-you-slice-and-index-multidimensional-arrays-in-numpy/">slice notation</a> and call the <code>plot()</code> method to plot a line graph.</strong></p>
<p>Once all <code>Subplots</code> have been plotted, call <code>plt.tight_layout()</code> to ensure no parts of the plots overlap. Finally, call <code>plt.show()</code> to display your plot.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Import necessary modules and (optionally) set Seaborn style
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
import numpy as np # Generate data to plot
linear = [x for x in range(5)]
square = [x**2 for x in range(5)]
cube = [x**3 for x in range(5)] # Generate Figure object and Axes object with shape 3x1
fig, axes = plt.subplots(nrows=3, ncols=1) # Access first Subplot and plot linear numbers
axes[0].plot(linear) # Access second Subplot and plot square numbers
axes[1].plot(square) # Access third Subplot and plot cube numbers
axes[2].plot(cube) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img0.png" alt=""/></figure>
<h2>Matplotlib Figures and Axes</h2>
<p>Up until now, you have probably made all your plots with the functions in <code>matplotlib.pyplot</code> i.e. all the functions that start with <code>plt.</code>.</p>
<p>These work nicely when you draw one plot at a time. But to draw multiple plots on one <code>Figure</code>, you need to learn the underlying classes in matplotlib.</p>
<p>Let’s look at an image that explains the main classes from the <a href="https://github.com/matplotlib/AnatomyOfMatplotlib">AnatomyOfMatplotlib</a> tutorial:</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img1.png" alt=""/></figure>
<p>To quote AnatomyOfMatplotlib:</p>
<blockquote class="wp-block-quote">
<p>The <code>Figure</code> is the top-level container in this hierarchy. It is the overall window/page that everything is drawn on. You can have multiple independent figures and <code>Figure</code>s can contain multiple <code>Axes</code>.</p>
<p>Most plotting ocurs on an <code>Axes</code>. The axes is effectively the area that we plot data on and any ticks/labels/etc associated with it. Usually we’ll set up an Axes with a call to <code>subplots</code> (which places Axes on a regular grid), so in most cases, <code>Axes</code> and <code>Subplot</code> are synonymous.</p>
<p>Each <code>Axes</code> has an <code>XAxis</code> and a <code>YAxis</code>. These contain the ticks, tick locations, labels, etc. In this tutorial, we’ll mostly control ticks, tick labels, and data limits through other mechanisms, so we won’t touch the individual <code>Axis</code> part of things all that much. However, it is worth mentioning here to explain where the term <code>Axes</code> comes from.</p>
</blockquote>
<p>The typical variable names for each object are:</p>
<ul>
<li><code>Figure</code> – <code>fig</code> or <code>f</code>,</li>
<li><code>Axes</code> (plural) – <code>axes</code> or <code>axs</code>,</li>
<li><code>Axes</code> (singular) – <code>ax</code> or <code>a</code></li>
</ul>
<p>The word <code>Axes</code> refers to the area you plot on and is synonymous with <code>Subplot</code>. However, you can have multiple <code>Axes</code> (<code>Subplots</code>) on a <code>Figure</code>. In speech and writing use the same word for the singular and plural form. In your code, you should make a distinction between each – you plot on a singular <code>Axes</code> but will store all the <code>Axes</code> in a Numpy array.</p>
<p>An <code>Axis</code> refers to the <code>XAxis</code> or <code>YAxis</code> – the part that gets ticks and labels.</p>
<p>The <code>pyplot</code> module implicitly works on one <code>Figure</code> and one <code>Axes</code> at a time. When we work with <code>Subplots</code>, we work with multiple <code>Axes</code> on one <code>Figure</code>. So, it makes sense to plot with respect to the <code>Axes</code> and it is much easier to keep track of everything.</p>
<p>The main differences between using <code>Axes</code> methods and <code>pyplot</code> are:</p>
<ol>
<li>Always create a <code>Figure</code> and <code>Axes</code> objects on the first line</li>
<li>To plot, write <code>ax.plot()</code> instead of <code>plt.plot()</code>.</li>
</ol>
<p>Once you get the hang of this, you won’t want to go back to using <code>pyplot</code>. It’s much easier to create interesting and engaging plots this way. In fact, this is why most <a href="https://stackoverflow.com/questions/tagged/matplotlib">StackOverflow answers</a> are written with this syntax.</p>
<p>All of the functions in <code>pyplot</code> have a corresponding method that you can call on <code>Axes</code> objects, so you don’t have to learn any new functions.</p>
<p>Let’s get to it.</p>
<h2>Matplotlib Subplots Example</h2>
<p>The <code>plt.subplots()</code> function creates a <code>Figure</code> and a Numpy array of <code>Subplots</code>/<code>Axes</code> objects which we store in <code>fig</code> and <code>axes</code> respectively.</p>
<p>Specify the number of rows and columns you want with the <code>nrows</code> and <code>ncols</code> arguments.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=3, ncols=1)
</pre>
<p>This creates a <code>Figure</code> and <code>Subplots</code> in a 3×1 grid. The <a href="https://blog.finxter.com/numpy-tutorial/">Numpy</a> array <code>axes</code> is the same shape as the grid, in this case <code>(3,)</code>. Access each <code>Subplot</code> using Numpy slice notation and call the <code>plot()</code> method to plot a line graph.</p>
<p>Once all <code>Subplots</code> have been plotted, call <code>plt.tight_layout()</code> to ensure no parts of the plots overlap. Finally, call <code>plt.show()</code> to display your plot. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img2.png" alt=""/></figure>
<p>The most important arguments for <code>plt.subplots()</code> are similar to the <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html">matplotlib subplot</a> function but can be specified with keywords. Plus, there are more powerful ones which we will discuss later.</p>
<p>To create a <code>Figure</code> with one <code>Axes</code> object, call it without any arguments</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, ax = plt.subplots()
</pre>
<p>Note: this is implicitly called whenever you use the <code>pyplot</code> module. All ‘normal’ plots contain one <code>Figure</code> and one <code>Axes</code>.</p>
<p>In advanced blog posts and StackOverflow answers, you will see a line similar to this at the top of the code. It is much more Pythonic to create your plots with respect to a <code>Figure</code> and <code>Axes</code>.</p>
<p>To create a <code>Grid</code> of subplots, specify <code>nrows</code> and <code>ncols</code> – the number of rows and columns respectively</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2)
</pre>
<p>The variable <code>axes</code> is a numpy array with shape <code>(nrows, ncols)</code>. Note that it is in the plural form to indicate it contains more than one <code>Axes</code> object. Another common name is <code>axs</code>. Choose whichever you prefer. If you call <code>plt.subplots()</code> without an argument name the variable <code>ax</code> as there is only one <code>Axes</code> object returned.</p>
<p>I will select each <code>Axes</code> object with slicing notation and plot using the appropriate methods. Since I am using Numpy slicing, the index of the first <code>Axes</code> is 0, not 1.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Create Figure and 2x2 gris of Axes objects
fig, axes = plt.subplots(nrows=2, ncols=2) # Generate data to plot. data = np.array([1, 2, 3, 4, 5]) # Access Axes object with Numpy slicing then plot different distributions
axes[0, 0].plot(data)
axes[0, 1].plot(data**2)
axes[1, 0].plot(data**3)
axes[1, 1].plot(np.log(data)) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img3.png" alt=""/></figure>
<p>First I import the necessary modules, then create the <code>Figure</code> and <code>Axes</code> objects using <code>plt.subplots()</code>. The <code>Axes</code> object is a Numpy array with shape <code>(2, 2)</code> and I access each subplot via Numpy slicing before doing a line plot of the data. Then, I call <code>plt.tight_layout()</code> to ensure the axis labels don’t overlap with the plots themselves. Finally, I call <code>plt.show()</code> as you do at the end of all matplotlib plots.</p>
<h2>Matplotlib Subplots Title</h2>
<p>To add an overall title to the <code>Figure</code>, use <code>plt.suptitle()</code>.</p>
<p>To add a title to each <code>Axes</code>, you have two methods to choose from:</p>
<ol>
<li><code>ax.set_title('bar')</code></li>
<li><code>ax.set(title='bar')</code></li>
</ol>
<p>In general, you can set anything you want on an <code>Axes</code> using either of these methods. I recommend using <code>ax.set()</code> because you can pass <em>any</em> setter function to it as a keyword argument. This is faster to type, takes up fewer lines of code and is easier to read.</p>
<p>Let’s set the title, xlabel and ylabel for two <code>Subplots</code> using both methods for comparison</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Unpack the Axes object in one line instead of using slice notation
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) # First plot - 3 lines
ax1.set_title('many')
ax1.set_xlabel('lines')
ax1.set_ylabel('of code') # Second plot - 1 line
ax2.set(title='one', xlabel='line', ylabel='of code') # Overall title
plt.suptitle('My Lovely Plot')
plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img4.png" alt=""/></figure>
<p>Clearly using <code>ax.set()</code> is the better choice.</p>
<p>Note that I unpacked the <code>Axes</code> object into individual variables on the first line. You can do this instead of Numpy slicing if you prefer. It is easy to do with 1D arrays. Once you create grids with multiple rows and columns, it’s easier to read if you don’t unpack them.</p>
<h2>Matplotlib Subplots Share X Axis</h2>
<p>To share the x axis for subplots in matplotlib, set <code>sharex=True</code> in your <code>plt.subplots()</code> call.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data
data = [0, 1, 2, 3, 4, 5] # 3x1 grid that shares the x axis
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # 3 different plots
axes[0].plot(data)
axes[1].plot(np.sqrt(data))
axes[2].plot(np.exp(data)) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img5.png" alt=""/></figure>
<p>Here I created 3 line plots that show the linear, square root and exponential of the numbers 0-5.</p>
<p>As I used the same numbers, it makes sense to share the x-axis.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img6.png" alt=""/></figure>
<p>Here I wrote the same code but set <code>sharex=False</code> (the default behavior). Now there are unnecessary axis labels on the top 2 plots.</p>
<p>You can also share the y axis for plots by setting <code>sharey=True</code> in your <code>plt.subplots()</code> call.</p>
<h2>Matplotlib Subplots Legend</h2>
<p>To add a legend to each <code>Axes</code>, you must</p>
<ol>
<li>Label it using the <code>label</code> keyword</li>
<li>Call <code>ax.legend()</code> on the <code>Axes</code> you want the legend to appear</li>
</ol>
<p>Let’s look at the same plot as above but add a legend to each <code>Axes</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data, 3x1 plot with shared XAxis
data = [0, 1, 2, 3, 4, 5]
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # Plot the distributions and label each Axes
axes[0].plot(data, label='Linear')
axes[1].plot(np.sqrt(data), label='Square Root')
axes[2].plot(np.exp(data), label='Exponential') # Add a legend to each Axes with default values
for ax in axes: ax.legend() plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img7.png" alt=""/></figure>
<p>The legend now tells you which function has been applied to the data. I used a for loop to call <code>ax.legend()</code> on each of the <code>Axes</code>. I could have done it manually instead by writing:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">axes[0].legend()
axes[1].legend()
axes[2].legend()
</pre>
<p>Instead of having 3 legends, let’s just add one legend to the <code>Figure</code> that describes each line. Note that you need to change the color of each line, otherwise the legend will show three blue lines.</p>
<p>The <a href="https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.legend.html">matplotlib legend</a> function takes 2 arguments</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax.legend(handles, labels)
</pre>
<ul>
<li><code>handles</code> – the lines/plots you want to add to the legend (list)</li>
<li><code>labels</code> – the labels you want to give each line (list)</li>
</ul>
<p>Get the <code>handles</code> by storing the output of you <code>ax.plot()</code> calls in a list. You need to create the list of <code>labels</code> yourself. Then call <code>legend()</code> on the <code>Axes</code> you want to add the legend to.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate data and 3x1 grid with a shared x axis
data = [0, 1, 2, 3, 4, 5]
fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True) # Store the output of our plot calls to use as handles
# Plot returns a list of length 1, so unpack it using a comma
linear, = axes[0].plot(data, 'b')
sqrt, = axes[1].plot(np.sqrt(data), 'r')
exp, = axes[2].plot(np.exp(data), 'g') # Create handles and labels for the legend
handles = [linear, sqrt, exp]
labels = ['Linear', 'Square Root', 'Exponential'] # Draw legend on first Axes
axes[0].legend(handles, labels) plt.tight_layout()
plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img8.png" alt=""/></figure>
<p>First I generated the data and a 3×1 grid. Then I made three <code>ax.plot()</code> calls and applied different functions to the data.</p>
<p>Note that <code>ax.plot()</code> returns a <code>list</code> of <code>matplotlib.line.Line2D</code> objects. You have to pass these <code>Line2D</code> objects to <code>ax.legend()</code> and so need to unpack them first.</p>
<p>Standard unpacking syntax in Python is:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">a, b = [1, 2]
# a = 1, b = 2
</pre>
<p>However, each <code>ax.plot()</code> call returns a list of length 1. To unpack these lists, write</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">x, = [5]
# x = 5
</pre>
<p>If you just wrote <code>x = [5]</code> then <code>x</code> would be a list and not the object inside the list.</p>
<p>After the <code>plot()</code> calls, I created 2 lists of <code>handles</code> and <code>labels</code> which I passed to <code>axes[0].legend()</code> to draw it on the first plot.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img9.png" alt=""/></figure>
<p>In the above plot, I changed the<code>legend</code> call to <code>axes[1].legend(handles, labels)</code> to plot it on the second (middle) <code>Axes</code>.</p>
<h2>Matplotlib Subplots Size</h2>
<p>You have total control over the size of subplots in matplotlib.</p>
<p>You can either change the size of the entire <code>Figure</code> or the size of the <code>Subplots</code> themselves.</p>
<p>First, let’s look at changing the <code>Figure</code>.</p>
<h3>Matplotlib Figure Size</h3>
<p>If you are happy with the size of your subplots but you want the final image to be larger/smaller, change the <code>Figure</code>.</p>
<p>If you’ve read my article on the matplotlib subplot function, you know to use the <code>plt.figure()</code> function to to change the <code>Figure</code>. Fortunately, any arguments passed to <code>plt.subplots()</code> are also passed to <code>plt.figure()</code>. So, you don’t have to add any extra lines of code, just keyword arguments.</p>
<p>Let’s change the size of the <code>Figure</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Create 2x1 grid - 3 inches wide, 6 inches long
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(3, 6))
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img10.png" alt=""/></figure>
<p>I created a 2×1 plot and set the <code>Figure</code> size with the <code>figsize</code> argument. It accepts a tuple of 2 numbers – the <code>(width, height)</code> of the image in inches.</p>
<p>So, I created a plot 3 inches wide and 6 inches long – <code>figsize=(3, 6)</code>. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># 2x1 grid - twice as long as it is wide
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=plt.figaspect(2))
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img11.png" alt=""/></figure>
<p>You can set a more general <code>Figure</code> size with the <a href="https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.figure.figaspect.html">matplotlib figaspect</a> function. It lets you set the aspect ratio (height/width) of the <code>Figure</code>.</p>
<p>Above, I created a <code>Figure</code> twice as long as it is wide by setting <code>figsize=plt.figaspect(2)</code>.</p>
<p>Note: Remember the aspect ratio (height/width) formula by recalling that <code>height</code> comes first in the alphabet before <code>width</code>.</p>
<h2>Matplotlib Subplots Different Sizes</h2>
<p>If you have used <code>plt.subplot()</code> before (<a href="https://blog.finxter.com/matplotlib-subplot/">I’ve written a whole tutorial on this too</a>), you’ll know that the grids you create are limited. Each <code>Subplot</code> must be part of a regular grid i.e. of the form <code>1/x</code> for some integer <code>x</code>. If you create a 2×1 grid, you have 2 rows and each row takes up 1/2 of the space. If you create a 3×2 grid, you have 6 subplots and each takes up 1/6 of the space.</p>
<p>Using <code>plt.subplots()</code> you can create a 2×1 plot with 2 rows that take up any fraction of space you want.</p>
<p>Let’s make a 2×1 plot where the top row takes up 1/3 of the space and the bottom takes up 2/3.</p>
<p>You do this by specifying the <code>gridspec_kw</code> argument and passing a <a href="https://blog.finxter.com/python-dictionary/">dictionary </a>of values. The main arguments we are interested in are <code>width_ratios</code> and <code>height_ratios</code>. They accept lists that specify the width ratios of columns and height ratios of the rows. In this example the top row is <code>1/3</code> of the <code>Figure</code> and the bottom is <code>2/3</code>. Thus the height ratio is <code>1:2</code> or <code>[1, 2]</code> as a list.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># 2 x1 grid where top is 1/3 the size and bottom is 2/3 the size
fig, axes = plt.subplots(nrows=2, ncols=1, gridspec_kw={'height_ratios': [1, 2]}) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img12.png" alt=""/></figure>
<p>The only difference between this and a regular 2×1 <code>plt.subplots()</code> call is the <code>gridspec_kw</code> argument. It accepts a dictionary of values. These are passed to the <a href="https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec">matplotlib GridSpec</a> constructor (the underlying class that creates the grid).</p>
<p>Let’s create a 2×2 plot with the same <code>[1, 2]</code> height ratios but let’s make the left hand column take up 3/4 of the space. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Heights: Top row is 1/3, bottom is 2/3 --> [1, 2]
# Widths : Left column is 3/4, right is 1/4 --> [3, 1]
ratios = {'height_ratios': [1, 2], 'width_ratios': [3, 1]} fig, axes = plt.subplots(nrows=2, ncols=2, gridspec_kw=ratios) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img13.png" alt=""/></figure>
<p>Everything is the same as the previous plot but now we have a 2×2 grid and have specified <code>width_ratios</code>. Since the left column takes up <code>3/4</code> of the space and the right takes up <code>1/4</code> the ratios are <code>[3, 1]</code>.</p>
<h2>Matplotlib Subplots Size</h2>
<p>In the previous examples, there were white lines that cross over each other to separate the <code>Subplots</code> into a clear grid. But sometimes you will not have that to guide you. To create a more complex plot, you have to manually add <code>Subplots</code> to the grid.</p>
<p>You could do this using the <code>plt.subplot()</code> function. But since we are focusing on <code>Figure</code> and <code>Axes</code> notation in this article, I’ll show you how to do it another way.</p>
<p>You need to use the <code>fig.add_subplot()</code> method and it has the same notation as <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot.html"><code>plt.subplot()</code></a>. Since it is a <code>Figure</code> method, you first need to create one with the <code>plt.figure()</code> function.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure()
</pre>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""><Figure size 432x288 with 0 Axes></pre>
<p>The hardest part of creating a <code>Figure</code> with different sized <code>Subplots</code> in matplotlib is figuring out what fraction of space each <code>Subplot</code> takes up.</p>
<p>So, it’s a good idea to know what you are aiming for before you start. You could sketch it on paper or draw shapes in PowerPoint. Once you’ve done this, everything else is much easier.</p>
<p>I’m going to create this shape.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img14.png" alt=""/></figure>
<p>I’ve labeled the fraction each <code>Subplot</code> takes up as we need this for our <code>fig.add_subplot()</code> calls.</p>
<p>I’ll create the biggest <code>Subplot</code> first and the others in descending order.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img15.png" alt=""/></figure>
<p>The right hand side is half of the plot. It is one of two plots on a <code>Figure</code> with 1 row and 2 columns. To select it with <code>fig.add_subplot()</code>, you need to set <code>index=2</code>.</p>
<p>Remember that indexing starts from 1 for the functions <code>plt.subplot()</code> and <code>fig.add_subplot()</code>.</p>
<p>In the image, the blue numbers are the index values each <code>Subplot</code> has.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax1 = fig.add_subplot(122)
</pre>
<p>As you are working with <code>Axes</code> objects, you need to store the result of <code>fig.add_subplot()</code> so that you can plot on it afterwards.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img16.png" alt=""/></figure>
<p>Now, select the bottom left <code>Subplot</code> in a a 2×2 grid i.e. <code>index=3</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax2 = fig.add_subplot(223)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img17.png" alt=""/></figure>
<p>Lastly, select the top two <code>Subplots</code> on the left hand side of a 4×2 grid i.e. <code>index=1</code> and <code>index=3</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax3 = fig.add_subplot(423)
ax4 = fig.add_subplot(421)
</pre>
<p>When you put this altogether you get </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Initialise Figure
fig = plt.figure() # Add 4 Axes objects of the size we want
ax1 = fig.add_subplot(122)
ax2 = fig.add_subplot(223)
ax3 = fig.add_subplot(423)
ax4 = fig.add_subplot(421) plt.tight_layout(pad=0.1)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img18.png" alt=""/></figure>
<p>Perfect! Breaking the <code>Subplots</code> down into their individual parts and knowing the shape you want, makes everything easier.</p>
<p>Now, let’s do something you can’t do with <code>plt.subplot()</code>. Let’s have 2 plots on the left hand side with the bottom plot twice the height as the top plot.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img19.png" alt=""/></figure>
<p>Like with the above plot, the right hand side is half of a plot with 1 row and 2 columns. It is <code>index=2</code>.</p>
<p>So, the first two lines are the same as the previous plot</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure()
ax1 = fig.add_subplot(122)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img20.png" alt=""/></figure>
<p>The top left takes up <code>1/3</code> of the space of the left-hand half of the plot. Thus, it takes up <code>1/3 x 1/2 = 1/6</code> of the total plot. So, it is <code>index=1</code> of a 3×2 grid.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax2 = fig.add_subplot(321)
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img21.png" alt=""/></figure>
<p>The final subplot takes up 2/3 of the remaining space i.e. <code>index=3</code> and <code>index=5</code> of a 3×2 grid. But you can’t add both of these indexes as that would add two <code>Subplots</code> to the <code>Figure</code>. You need a way to add one <code>Subplot</code> that <em>spans</em> two rows.</p>
<p>You need the <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplot2grid.html#matplotlib.pyplot.subplot2grid">matplotlib subplot2grid</a> function – <code>plt.subplot2grid()</code>. It returns an <code>Axes</code> object and adds it to the current <code>Figure</code>.</p>
<p>Here are the most important arguments:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax = plt.subplot2grid(shape, loc, rowspan, colspan)
</pre>
<ul>
<li><code>shape</code> – tuple of 2 integers – the <em>shape</em> of the overall grid e.g. (3, 2) has 3 rows and 2 columns.</li>
<li><code>loc</code> – tuple of 2 integers – the <em>location</em> to place the <code>Subplot</code> in the grid. It uses 0-based indexing so (0, 0) is first row, first column and (1, 2) is second row, third column.</li>
<li><code>rowspan</code> – integer, default 1- number of rows for the <code>Subplot</code> to span to the right</li>
<li><code>colspan</code> – integer, default 1 – number of columns for the <code>Subplot</code> to span down</li>
</ul>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img22.png" alt=""/></figure>
<p>From those definitions, you need to select the middle left <code>Subplot</code> and set <code>rowspan=2</code> so that it spans down 2 rows.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img23.png" alt=""/></figure>
<p>Thus, the arguments you need for <code>subplot2grid</code> are:</p>
<ul>
<li><code>shape=(3, 2)</code> – 3×2 grid</li>
<li><code>loc=(1, 0)</code> – second row, first colunn (0-based indexing)</li>
<li><code>rowspan=2</code> – span down 2 rows</li>
</ul>
<p>This gives</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">ax3 = plt.subplot2grid(shape=(3, 2), loc=(1, 0), rowspan=2)
</pre>
<p>Sidenote: why matplotlib chose 0-based indexing for <code>loc</code> when <em>everything else</em> uses 1-based indexing is a mystery to me. One way to remember it is that <code>loc</code> is similar to <code>locating</code>. This is like slicing Numpy arrays which use 0-indexing. Also, if you use <code>GridSpec</code>, you will often use Numpy slicing to choose the number of rows and columns that <code>Axes</code> span.</p>
<p>Putting this together, you get </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig = plt.figure() ax1 = fig.add_subplot(122)
ax2 = fig.add_subplot(321)
ax3 = plt.subplot2grid(shape=(3, 2), loc=(1, 0), rowspan=2) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img24.png" alt=""/></figure>
<h2>Matplotlib Subplots_Adjust</h2>
<p>If you aren’t happy with the spacing between plots that <code>plt.tight_layout()</code> provides, manually adjust the spacing with the <a href="https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.subplots_adjust.html">matplotlib subplots_adjust</a> function.</p>
<p>It takes 6 optional, self explanatory arguments. Each is a float in the range [0.0, 1.0] and is a fraction of the font size:</p>
<ul>
<li><code>left</code>, <code>right</code>, <code>bottom</code> and <code>top</code> is the spacing on each side of the <code>Suplots</code></li>
<li><code>wspace</code> – the <strong>width</strong> between <code>Subplots</code></li>
<li><code>hspace</code> – the <strong>height</strong> between <code>Subplots</code></li>
</ul>
<p>Let’s compare <code>tight_layout</code> with <code>subplots_adjust</code>. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2, sharex=<strong>True</strong>, sharey=<strong>True</strong>) plt.tight_layout()
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img25.png" alt=""/></figure>
<p>Here is a 2×2 grid with <code>plt.tight_layout()</code>. I’ve set <code>sharex</code> and <code>sharey</code> to <code>True</code> to remove unnecessary axis labels. </p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig, axes = plt.subplots(nrows=2, ncols=2, sharex=<strong>True</strong>, sharey=<strong>True</strong>) plt.subplots_adjust(wspace=0.05, hspace=0.05)
plt.show()
</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img26.png" alt=""/></figure>
<p>Now I’ve decreased the height and width between <code>Subplots</code> to <code>0.05</code> and there is hardly any space between them.</p>
<p>To avoid loads of similar examples, I recommend you play around with the arguments to get a feel for how this function works.</p>
<h2>Matplotlib Subplots Colorbar</h2>
<p>Adding a colorbar to each <code>Axes</code> is similar to adding a legend. You store the <code>ax.plot()</code> call in a variable and pass it to <code>fig.colorbar()</code>.</p>
<p>Colorbars are <code>Figure</code> methods since they are placed on the <code>Figure</code> itself and not the <code>Axes</code>. Yet, they do take up space from the <code>Axes</code> they are placed on.</p>
<p>Let’s look at an example.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Generate two 10x10 arrays of random numbers in the range [0.0, 1.0]
data1 = np.random.random((10, 10))
data2 = np.random.random((10, 10)) # Initialise Figure and Axes objects with 1 row and 2 columns
# Constrained_layout=True is better than plt.tight_layout()
# Make twice as wide as it is long with figaspect
fig, axes = plt.subplots(nrows=1, ncols=2, constrained_layout=True, figsize=plt.figaspect(1/2)) pcm1 = axes[0].pcolormesh(data1, cmap='Blues')
# Place first colorbar on first column - index 0
fig.colorbar(pcm1, ax=axes[0]) pcm2 = axes[1].pcolormesh(data2, cmap='Greens')
# Place second colorbar on second column - index 1
fig.colorbar(pcm2, ax=axes[1]) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img27.png" alt=""/></figure>
<p>First, I generated two 10×10 arrays of random numbers in the range [0.0, 1.0] using the <code>np.random.random()</code> function. Then I initialized the 1×2 grid with <code>plt.subplots()</code>.</p>
<p>The keyword argument <code>constrained_layout=True</code> achieves a similar result to calling <code>plt.tight_layout()</code>. However, <code>tight_layout</code> only checks for tick labels, axis labels and titles. Thus, it ignores colorbars and legends and often produces bad looking plots. Fortunately, <code>constrained_layout</code> takes colorbars and legends into account. Thus, it should be your go-to when automatically adjusting these types of plots.</p>
<p>Finally, I set <code>figsize=plt.figaspect(1/2)</code> to ensure the plots aren’t too squashed together.</p>
<p>After that, I plotted the first heatmap, colored it blue and saved it in the variable <code>pcm1</code>. I passed that to <code>fig.colorbar()</code> and placed it on the first column – <code>axes[0]</code> with the <code>ax</code> keyword argument. It’s a similar story for the second heatmap.</p>
<p>The more <code>Axes</code> you have, the fancier you can be with <a href="https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/colorbar_placement.html">placing colorbars in matplotlib</a>. Now, let’s look at a 2×2 example with 4 <code>Subplots</code> but only 2 colorbars.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Set seed to reproduce results
np.random.seed(1) # Generate 4 samples of the same data set using a list comprehension # and assignment unpacking
data1, data2, data3, data4 = [np.random.random((10, 10)) for _ in range(4)] # 2x2 grid with constrained layout
fig, axes = plt.subplots(nrows=2, ncols=2, constrained_layout=True) # First column heatmaps with same colormap
pcm1 = axes[0, 0].pcolormesh(data1, cmap='Blues')
pcm2 = axes[1, 0].pcolormesh(data2, cmap='Blues') # First column colorbar - slicing selects all rows, first column
fig.colorbar(pcm1, ax=axes[:, 0]) # Second column heatmaps with same colormap
pcm3 = axes[0, 1].pcolormesh(data3+1, cmap='Greens')
pcm4 = axes[1, 1].pcolormesh(data4+1, cmap='Greens') # Second column colorbar - slicing selects all rows, second column
# Half the size of the first colorbar
fig.colorbar(pcm3, ax=axes[:, 1], shrink=0.5) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img28.png" alt=""/></figure>
<p>If you pass a list of <code>Axes</code> to <code>ax</code>, matplotlib places the colorbar along those <code>Axes</code>. Moreover, you can specify where the colorbar is with the <code>location</code> keyword argument. It accepts the strings <code>'bottom'</code>, <code>'left'</code>, <code>'right'</code>, <code>'top'</code> or <code>'center'</code>.</p>
<p>The code is similar to the 1×2 plot I made above. First, I set the seed to 1 so that you can reproduce the results – you will soon plot this again with the colorbars in different places.</p>
<p>I used a <a href="https://blog.finxter.com/list-comprehension/">list comprehension</a> to generate 4 samples of the same <a href="https://blog.finxter.com/sets-in-python/">dataset</a>. Then I created a 2×2 grid with <code>plt.subplots()</code> and set <code>constrained_layout=True</code> to ensure nothing overlaps.</p>
<p>Then I made the plots for the first column – <code>axes[0, 0]</code> and <code>axes[1, 0]</code> – and saved their output. I passed one of them to <code>fig.colorbar()</code>. It doesn’t matter which one of <code>pcm1</code> or <code>pcm2</code> I pass since they are just different samples of the same dataset. I set <code>ax=axes[:, 0]</code> using Numpy slicing notation, that is all rows <code>:</code> and the first column <code>0</code>.</p>
<p>It’s a similar process for the second column but I added 1 to <code>data3</code> and <code>data4</code> to give a range of numbers in [1.0, 2.0] instead. Lastly, I set <code>shrink=0.5</code> to make the colorbar half its default size.</p>
<p>Now, let’s plot the same data with the same colors on each row rather than on each column.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Same as above
np.random.seed(1)
data1, data2, data3, data4 = [np.random.random((10, 10)) for _ in range(4)]
fig, axes = plt.subplots(nrows=2, ncols=2, constrained_layout=True) # First row heatmaps with same colormap
pcm1 = axes[0, 0].pcolormesh(data1, cmap='Blues')
pcm2 = axes[0, 1].pcolormesh(data2, cmap='Blues') # First row colorbar - placed on first row, all columns
fig.colorbar(pcm1, ax=axes[0, :], shrink=0.8) # Second row heatmaps with same colormap
pcm3 = axes[1, 0].pcolormesh(data3+1, cmap='Greens')
pcm4 = axes[1, 1].pcolormesh(data4+1, cmap='Greens') # Second row colorbar - placed on second row, all columns
fig.colorbar(pcm3, ax=axes[1, :], shrink=0.8) plt.show()</pre>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img29.png" alt=""/></figure>
<p>This code is similar to the one above but the plots of the same color are on the same row rather than the same column. I also shrank the colorbars to 80% of their default size by setting <code>shrink=0.8</code>.</p>
<p>Finally, let’s set the blue colorbar to be on the bottom of the heatmaps.</p>
<figure class="wp-block-image"><img src="https://raw.githubusercontent.com/theadammurphy/matplotlib_articles/master/subplots/final_html/img/img30.png" alt=""/></figure>
<p>You can change the location of the colorbars with the <code>location</code> keyword argument in <code>fig.colorbar()</code>. The only difference between this plot and the one above is this line</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fig.colorbar(pcm1, ax=axes[0, :], shrink=0.8, location='bottom')
</pre>
<p>If you increase the <code>figsize</code> argument, this plot will look much better – at the moment it’s quite cramped.</p>
<p>I recommend you play around with matplotlib colorbar placement. You have total control over how many colorbars you put on the <code>Figure</code>, their location and how many rows and columns they span. These are some basic ideas but check out the docs to see more examples of how you can <a href="https://matplotlib.org/3.1.1/gallery/subplots_axes_and_figures/colorbar_placement.html">place colorbars in matplotlib</a>.</p>
<h2>Matplotlib Subplot Grid</h2>
<p>I’ve spoken about <a href="https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html"><code>GridSpec</code></a> a few times in this article. It is the underlying class that <em>specifies the geometry of the grid that a subplot can be placed in</em>.</p>
<p>You can create any shape you want using <code>plt.subplots()</code> and <code>plt.subplot2grid()</code>. But some of the more complex shapes are easier to create using <code>GridSpec</code>. If you want to become a total pro with matplotlib, check out the docs and look out for my article discussing it in future.</p>
<h2>Summary</h2>
<p>You can now create <em>any</em> shape you can imagine in matplotlib. Congratulations! This is a huge achievement. Don’t worry if you didn’t fully understand everything the first time around. I recommend you bookmark this article and revisit it from time to time.</p>
<p>You’ve learned the underlying classes in matplotlib: <code>Figure</code>, <code>Axes</code>, <code>XAxis</code> and <code>YAxis</code> and how to plot with respect to them. You can write shorter, more readable code by using these methods and <code>ax.set()</code> to add titles, xlabels and many other things to each <code>Axes</code>. You can create more professional looking plots by sharing the x-axis and y-axis and add legends anywhere you like.</p>
<p>You can create <code>Figures</code> of any size that include <code>Subplots</code> of any size – you’re no longer restricted to those that take up <code>1/x</code>th of the plot. You know that to make the best plots, you should plan ahead and figure out the shape you are aiming for.</p>
<p>You know when to use <code>plt.tight_layout()</code> (ticks, labels and titles) and <code>constrained_layout=True</code> (legends and colorbars) and how to manually adjust spacing between plots with <code>plt.subplots_adjust()</code>.</p>
<p>Finally, you can add colorbars to as many <code>Axes</code> as you want and place them wherever you’d like.</p>
<p>You’ve done everything now. All that is left is to practice these plots so that you can quickly create amazing plots whenever you want.</p>
<h2>Where To Go From Here?</h2>
<p>Do you wish you could be a programmer full-time but don’t know how to start?</p>
<p>Check out my pure value-packed webinar where I teach you to become a Python freelancer in 60 days or your money back!</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
<p>It doesn’t matter if you’re a Python novice or Python pro. If you are not making six figures/year with Python right now, you will learn something from this webinar. </p>
<p>These are proven, no-BS methods that get you results fast.</p>
<p>This webinar won’t be online forever. Click the link below before the seats fill up and learn how to become a Python freelancer, guaranteed.</p>
<p><a href="https://tinyurl.com/become-a-python-freelancer">https://tinyurl.com/become-a-python-freelancer</a></p>
</div>
https://www.sickgaming.net/blog/2020/02/...ted-guide/