37

I am trying to make a simple box plot of a variable 'x' contained in two dataframes, df1 and df2. To do this I am using the following code:

fig, axs = plt.subplots()
axs[0, 0].boxplot([df1['x'], df2['x']])
plt.show();

However, I get this:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-108-ce962754d553> in <module>()
----> 2 axs[0, 0].boxplot([df1['x'], df2['x']])
      3 plt.show();
      4 

TypeError: 'AxesSubplot' object is not subscriptable

Any ideas?

SHV_la
  • 875
  • 1
  • 10
  • 14

1 Answers1

67
fig, axs = plt.subplots()

returns a figure with only one single subplot, so axs already holds it without indexing.

fig, axs = plt.subplots(3)

returns a 1D array of subplots.

fig, axs = plt.subplots(3, 2)

returns a 2D array of subplots.

Note that this is only due to the default setting of the kwarg squeeze=True.
By setting it to False you can force the result to be a 2D-array, independent of the number or arrangement of the subplots.

import numpy
from PIL import Image
import matplotlib.pyplot as plt

imarray = numpy.random.rand(10,10,3) * 255
im = Image.fromarray(imarray.astype('uint8')).convert('RGBA')

#rows = 1; cols = 1;
#rows = 5; cols = 3;
rows = 1; cols = 5;
fig, ax = plt.subplots(rows, cols, squeeze=False)
fig.suptitle('random plots')
i = 0
for r in range(rows):
    for c in range(cols): 
        ax[r][c].imshow(im)
        i = i + 1     
plt.show()
plt.close()
Nav
  • 19,885
  • 27
  • 92
  • 135
SpghttCd
  • 10,510
  • 2
  • 20
  • 25
  • 24
    This is horrible programming practice tho. They are inventing unnecessary edge cases. Now I have to write different code for the case where there is only 1 subplot – MuhsinFatih Oct 05 '19 at 20:46
  • @MuhsinFatih I think I can imagine, what you mean. Can you describe, in which concrete way you have to write different code? – SpghttCd Oct 06 '19 at 00:05
  • This is what I had to add to take care of the edge case: axs = np.array(axs); axs = np.reshape(axs, n). n being the shape variable – MuhsinFatih Oct 06 '19 at 00:38
  • It just occured to me that adding this as another answer could be useful. I was initially going to suggest an edit but lets not complicate your answer, it's nicely short and clear – MuhsinFatih Oct 06 '19 at 04:46
  • Ugh.. Can't add answer :( Is it because it's marked as duplicate? Personally I don't agree with the duplicate mark, it's much different wording and shorter question – MuhsinFatih Oct 06 '19 at 04:48
  • 5
    @MuhsinFatih see my edit, this should help – SpghttCd Oct 06 '19 at 05:57
  • Ugh! How I missed that. So much more convenient – MuhsinFatih Oct 06 '19 at 07:00
  • Yes - exactly what is explained in the duplicate link, as I just checked again... :) – SpghttCd Oct 06 '19 at 07:04
  • @Nav I do not think that your additions to this answer are an improvement: if you use `squeeze=False` then, as the answer already stated, you always get a 2D array. Then you do not need those if loops. – RuthC Aug 30 '23 at 07:02
  • @RuthC: I agree. I've changed the example now to incorporate `squeeze`. Classic example of how a poorly named parameter and misleading blog posts cause confusion. – Nav Aug 30 '23 at 12:09