54

I want to create a plot consisting of several subplots with shared x/y axes. It should look something like this from the documentation (though my subplots will be scatterblots): (code here)

3 subplots sharing x and y axis

But I want to create the subplots dynamically!

So the number of subplots depends on the output of a previous function. (It will probably be around 3 to 15 subplots per diagram, each from a distinct dataset, depending on the input of my script.)

Can anyone tell me how to accomplish that?

3
  • 2
    Can't you use plt.subplots(numplots, sharex=True, sharey=True) with numplots a variable? Commented Sep 7, 2012 at 14:26
  • @Tim - You should post that as an answer. :) (A lot of people aren't aware of subplots. It's relatively new.) Commented Sep 7, 2012 at 14:52
  • 3
    Well, it's in the source source code linked above, so I was guessing there was another problem. Commented Sep 7, 2012 at 15:21

4 Answers 4

46

Suppose you know total subplots and total columns you want to use:

import matplotlib.pyplot as plt

# Subplots are organized in a Rows x Cols Grid
# Tot and Cols are known

Tot = number_of_subplots
Cols = number_of_columns

# Compute Rows required

Rows = Tot // Cols 

#     EDIT for correct number of rows:
#     If one additional row is necessary -> add one:

if Tot % Cols != 0:
    Rows += 1

# Create a Position index

Position = range(1,Tot + 1)

First instance of Rows accounts only for rows completely filled by subplots, then is added one more Row if 1 or 2 or ... Cols - 1 subplots still need location.

Then create figure and add subplots with a for loop.

# Create main figure

fig = plt.figure(1)
for k in range(Tot):

  # add every single subplot to the figure with a for loop

  ax = fig.add_subplot(Rows,Cols,Position[k])
  ax.plot(x,y)      # Or whatever you want in the subplot

plt.show()

Please note that you need the range Position to move the subplots into the right place.

Sign up to request clarification or add additional context in comments.

1 Comment

Suggestion: Cols = int(Tot**0.5) (square root of the Tot)
30

Based on this post, what you want to do is something like this:

import matplotlib.pyplot as plt

# Start with one
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])

# Now later you get a new subplot; change the geometry of the existing
n = len(fig.axes)
for i in range(n):
    fig.axes[i].change_geometry(n+1, 1, i+1)

# Add the new
ax = fig.add_subplot(n+1, 1, n+1)
ax.plot([4,5,6])

plt.show() 

However, Paul H's answer points to the submodule called gridspec which might make the above easier. I am leaving that as an exercise for the reader ^_~.

5 Comments

How do you do this if you have x number of columns, not just one? If you change the '1' argument in change_geometry to something else the first plot is across all columns instead of being reasigned to a single column.
@DirkHaupt: I do not know the answer to that but I upvoted your question! Thank you.
change_geometry is deprecated. I came up with a new solution here, based on the set_subplotspec function.
This seems to be the only answer taking into account that the OP wants "to create the subplots dynamically".
28
import matplotlib.pyplot as plt
from pylab import *
import numpy as np

x = np.linspace(0, 2*np.pi, 400)
y = np.sin(x**2)

subplots_adjust(hspace=0.000)
number_of_subplots=3

for i,v in enumerate(xrange(number_of_subplots)):
    v = v+1
    ax1 = subplot(number_of_subplots,1,v)
    ax1.plot(x,y)

plt.show()

This code works but you will need to correct the axes. I used to subplot to plot 3 graphs all in the same column. All you need to do is assign an integer to number_of_plots variable. If the X and Y values are different for each plot you will need to assign them for each plot.

subplot works as follows, if for example I had a subplot values of 3,1,1. This creates a 3x1 grid and places the plot in the 1st position. In the next interation if my subplot values were 3,1,2 it again creates a 3x1 grid but places the plot in the 2nd position and so forth.

6 Comments

Thanks for explaining! I didn't understand the way the subplot values worked from the documentation, but it's clear now. Thank you! One question, though: what's the benefit of using for i,v in enumerate(xrange(number_of_subplots)) instead of for i in range(number_of_subplots)? Even if you needed the same value twice (which your code doesn't seem to), couldn't you just use i twice? Or am I missing something? (I'm still a beginner, hence curious.)
meh why not just tidy the code rather than defending it. for i in range(3): ...
I got error when trying this code: NameError: name 'xrange' is not defined. Sorry, it should be some stupid error, but I am an absolute beginner in Python. Any ideea?
You must be using Python 3 change xrange to range
@Harpal, How can I add title for each subplot and legend for the overall plot?
|
4

Instead of counting your own number of rows and columns, I found it easier to create the subplots using plt.subplots first, then iterate through the axes object to add plots.

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(12, 8))
x_array = np.random.randn(6, 10)
y_array = np.random.randn(6, 10)

i = 0
for row in axes:
    for ax in row:
        x = x_array[i] 
        y = y_array[i]
        ax.scatter(x, y)
        ax.set_title("Plot " + str(i))
        i += 1
plt.tight_layout()
plt.show()

Here I use i to iterate through elements of x_array and y_array, but you can likewise easily iterate through functions, or columns of dataframes to dynamically generate graphs.

1 Comment

This solution can be simplified by looping through the axes like this instead: for i, ax in enumerate(axes.flat): ax.scatter(x_array[i], y_array[i]); ax.set_title(f'Plot {i}')

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.