200
votes

I am a little confused about how this code works:

fig, axes = plt.subplots(nrows=2, ncols=2)
plt.show()

How does the fig, axes work in this case? What does it do?

Also why wouldn't this work to do the same thing:

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)
8

8 Answers

277
votes

There are several ways to do it. The subplots method creates the figure along with the subplots that are then stored in the ax array. For example:

import matplotlib.pyplot as plt

x = range(10)
y = range(10)

fig, ax = plt.subplots(nrows=2, ncols=2)

for row in ax:
    for col in row:
        col.plot(x, y)

plt.show()

enter image description here

However, something like this will also work, it's not so "clean" though since you are creating a figure with subplots and then add on top of them:

fig = plt.figure()

plt.subplot(2, 2, 1)
plt.plot(x, y)

plt.subplot(2, 2, 2)
plt.plot(x, y)

plt.subplot(2, 2, 3)
plt.plot(x, y)

plt.subplot(2, 2, 4)
plt.plot(x, y)

plt.show()

enter image description here

78
votes
import matplotlib.pyplot as plt

fig, ax = plt.subplots(2, 2)

ax[0, 0].plot(range(10), 'r') #row=0, col=0
ax[1, 0].plot(range(10), 'b') #row=1, col=0
ax[0, 1].plot(range(10), 'g') #row=0, col=1
ax[1, 1].plot(range(10), 'k') #row=1, col=1
plt.show()

enter image description here

29
votes
  • You can also unpack the axes in the subplots call

  • And set whether you want to share the x and y axes between the subplots

Like this:

import matplotlib.pyplot as plt
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
ax1.plot(range(10), 'r')
ax2.plot(range(10), 'b')
ax3.plot(range(10), 'g')
ax4.plot(range(10), 'k')
plt.show()

enter image description here

17
votes

You might be interested in the fact that as of matplotlib version 2.1 the second code from the question works fine as well.

From the change log:

Figure class now has subplots method The Figure class now has a subplots() method which behaves the same as pyplot.subplots() but on an existing figure.

Example:

import matplotlib.pyplot as plt

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)

plt.show()
11
votes

Read the documentation: matplotlib.pyplot.subplots

pyplot.subplots() returns a tuple fig, ax which is unpacked in two variables using the notation

fig, axes = plt.subplots(nrows=2, ncols=2)

The code:

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)

does not work because subplots() is a function in pyplot not a member of the object Figure.

3
votes
# Generate figure and its subplots
fig, axes = plt.subplots(nrows, ncols)

Iterating through all subplots sequentially:

for ax in axes.flatten():
    ax.plot(x,y)

Accessing a specific subplot via its index:

for row in range(nrows):
    for col in range(ncols):
        axes[row,col].plot(x[row], y[col])
0
votes

Go with the following if you really want to use a loop:

def plot(data):
    fig = plt.figure(figsize=(100, 100))
    for idx, k in enumerate(data.keys(), 1):
        x, y = data[k].keys(), data[k].values
        plt.subplot(63, 10, idx)
        plt.bar(x, y)  
    plt.show()
0
votes

The other answers are great, this answer is a combination which might be useful.

import numpy as np
import matplotlib.pyplot as plt

# Optional: define x for all the sub-plots
x = np.linspace(0,2*np.pi,100)

# (1) Prepare the figure infrastructure 
fig, ax_array = plt.subplots(nrows=2, ncols=2)

# flatten the array of axes, which makes them easier to iterate through and assign
ax_array = ax_array.flatten()

# (2) Plot loop
for i, ax in enumerate(ax_array):
  ax.plot(x , np.sin(x + np.pi/2*i))
  #ax.set_title(f'plot {i}')

# Optional: main title
plt.suptitle('Plots')

code result: plots

Summary

  1. Prepare the figure infrastructure

    • Get ax_array, an array of the subplots
    • Flatten the array in order to use it in one 'for loop'
  2. Plot loop

    • Loop over the flattened ax_array to update the subplots
    • optional: use enumeration to track subplot number