67

The information below may be superfluous if you are trying to understand the error message. Please start off by reading the answer by @user707650.

Using MatPlotLib, I wanted a generalizable script that creates the following from my data.

A window containing a subplots arranged so that there are b subplots per column. I want to be able to change the values of a and b.

If I have data for 2a subplots, I want 2 windows, each with the previously described "a subplots arranged according to b subplots per column".

The x and y data I am plotting are floats stored in np.arrays and are structured as follows:

  • The x data is always the same for all plots and is of length 5.

     'x_vector': [0.000, 0.005, 0.010, 0.020, 0.030, 0.040]
    
  • The y data of all plots are stored in y_vector where the data for the first plot is stored at indexes 0 through 5. The data for the second plot is stored at indexes 6 through 11. The third plot gets 12-18, the fourth 19-24, and so on.

In total, for this dataset, I have 91 plots (i.e. 91*6 = 546 values stored in y_vector).

Attempt:

import matplotlib.pyplot as plt

# Options:
plots_tot = 14 # Total number of plots. In reality there is going to be 7*13 = 91 plots.
location_of_ydata = 6 # The values for the n:th plot can be found in the y_vector at index 'n*6' through 'n*6 + 6'.
plots_window = 7 # Total number of plots per window.
rows = 2 # Number of rows, i.e. number of subplots per column.

# Calculating number of columns:
prim_cols = plots_window / rows
extra_cols = 0
if plots_window % rows > 0:
    extra_cols = 1
cols = prim_cols + extra_cols

print 'cols:', cols
print 'rows:', rows

# Plotting:
n=0
x=0
fig, ax = plt.subplots(rows, cols)
while x <= plots_tot:
    ax[x].plot(x_vector, y_vector[n:(n+location_of_ydata)], 'ro')
    if x % plots_window == plots_window - 1:
        plt.show() # New window for every 7 plots.
    n = n+location_of_ydata
    x = x+1

I get the following error:

cols: 4
rows: 2
Traceback (most recent call last):
  File "Script.py", line 222, in <module>
    ax[x].plot(x_vector, y_vector[n:(n+location_of_ydata)], 'ro')
AttributeError: 'numpy.ndarray' object has no attribute 'plot'
2
  • Importing numpy doesn't matter: matplotlib (pyplot) already does that behind the scenes, since it is a major dependency of matplotlib. Commented Jun 22, 2016 at 12:38
  • matplotlib and numpy really should work together here to throw a better error. This is one of those rare instances when I wish it was Matlab. :) Commented Dec 7, 2021 at 23:02

4 Answers 4

134

If you debug your program by simply printing ax, you'll quickly find out that ax is a two-dimensional array: one dimension for the rows, one for the columns.

Thus, you need two indices to index ax to retrieve the actual AxesSubplot instance, like:

ax[1,1].plot(...)

If you want to iterate through the subplots in the way you do it now, by flattening ax first:

ax = ax.flatten()

and now ax is a one dimensional array. I don't know if rows or columns are stepped through first, but if it's the wrong around, use the transpose:

ax = ax.T.flatten()

Of course, by now it makes more sense to simply create each subplot on the fly, because that already has an index, and the other two numbers are fixed:

for x < plots_tot:
     ax = plt.subplot(nrows, ncols, x+1)

Note: you have x <= plots_tot, but with x starting at 0, you'll get an IndexError next with your current code (after flattening your array). Matplotlib is (unfortunately) 1-indexed for subplots. I prefer using a 0-indexed variable (Python style), and just add +1 for the subplot index (like above).

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

Comments

12

The problem here is with how matplotlib handles subplots. Just do the following:

fig, axes = plt.subplots(nrows=1, ncols=2)
for axis in axes:
    print(type(axis))

you will get a matplotlib object which is actually a 1D array which can be traversed using single index i.e. axis[0], axis[1]...and so on. But if you do

fig, axes = plt.subplots(nrows=2, ncols=2)
for axis in axes:
    print(type(axis))

you will get a numpy ndarray object which is actually a 2D array which can be traversed only using 2 indices i.e. axis[0, 0], axis[1, 0]...and so on. So be mindful how you incorporate your for loop to traverse through axes object.

Comments

2

The axes are in 2-d, not 1-d so you can't iterate through using one loop. You need one more loop:

 fig,axes=plt.subplots(nrows=2,ncols=2)
    plt.tight_layout()
    for ho in axes:
        for i in ho:
            i.plot(a,a**2)

This gives no problem but if I try:

for i in axes:
      i.plot(a,a**2)

the error occurs.

Comments

1

In case if you use N by 1 graphs, for example if you do like fig, ax = plt.subplots(3, 1) then please do likeax[plot_count].plot(...)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.