Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding matplotlib.subplots python [duplicate]

I have constructed a set of pie charts with some help Insert image into pie chart slice My charts look wonderful, now I need to place all 6 of them in a 2x3 figure with common tick marks on the shared x and y axis. For starting I am looking at subplots and thought I could get it to work. I downloaded some examples and started to try a few things.

    f, (a) = (plt.subplots(nrows=1, ncols=1, sharex=True, sharey=True))#,
                 #squeeze=False, subplot_kw=None, gridspec_kw=None))
    print(type(f),'\n',type(a),'\n')#,type(b))

yields:

class 'matplotlib.figure.Figure'

class 'matplotlib.axes._subplots.AxesSubplot'

while:

    f, (a) = (plt.subplots(nrows=1, ncols=1, sharex=True, sharey=True, squeeze=False, subplot_kw=None, gridspec_kw=None))
    print(type(f),'\n',type(a),'\n')#,type(b))

returns:

class 'matplotlib.figure.Figure'

class 'numpy.ndarray'

When I do this:

f, (a,b) = (plt.subplots(nrows=2, ncols=1, sharex=True, sharey=True, squeeze=False, subplot_kw=None, gridspec_kw=None))
    print(type(f),'\n',type(a),'\n',type(b))

I get the similar results, however if nrows=1 and ncols=2 I get an error:

    f, (a,b) = (plt.subplots(nrows=1, ncols=2, sharex=True, sharey=True, squeeze=False, subplot_kw=None, gridspec_kw=None))
    print(type(f),'\n',type(a),'\n',type(b))

ValueError: not enough values to unpack (expected 2, got 1)

but again this:

    f, (a , b) = (
    plt.subplots(nrows=1, ncols=2, sharex=True, sharey=True))#,
                 #squeeze=False, subplot_kw=None, gridspec_kw=None))
    print(type(f),'\n',type(a),'\n',type(b))

gives class 'matplotlib.figure.Figure'

class 'matplotlib.axes._subplots.AxesSubplot'

class 'matplotlib.axes._subplots.AxesSubplot'

Why is it either or array or axes, and also why does a 2X1 work and a 1X2 does not? I wish to high heaven I could better understand the documentation. Thanks.

like image 277
CJD Avatar asked Jun 16 '17 22:06

CJD


1 Answers

The different return types are due to the squeeze keyword argument to plt.subplots() which is set to True by default. Let's enhance the documentation with the respective unpackings:

squeeze : bool, optional, default: True

  • If True, extra dimensions are squeezed out from the returned Axes object:

    • if only one subplot is constructed (nrows=ncols=1), the resulting single Axes object is returned as a scalar.
      fig, ax = plt.subplots()
    • for Nx1 or 1xN subplots, the returned object is a 1D numpy object array of Axes objects are returned as numpy 1D arrays.
      fig, (ax1, ..., axN) = plt.subplots(nrows=N, ncols=1) (for Nx1)
      fig, (ax1, ..., axN) = plt.subplots(nrows=1, ncols=N) (for 1xN)
    • for NxM, subplots with N>1 and M>1 are returned as a 2D arrays.
      fig, ((ax11, .., ax1M),..,(axN1, .., axNM)) = plt.subplots(nrows=N, ncols=M)
  • If False, no squeezing at all is done: the returned Axes object is always a 2D array containing Axes instances, even if it ends up being 1x1.
    fig, ((ax,),) = plt.subplots(nrows=1, ncols=1, squeeze=False)
    fig, ((ax,), .. ,(axN,)) = plt.subplots(nrows=N, ncols=1, squeeze=False) for Nx1
    fig, ((ax, .. ,axN),) = plt.subplots(nrows=1, ncols=N, squeeze=False) for 1xN
    fig, ((ax11, .., ax1M),..,(axN1, .., axNM)) = plt.subplots(nrows=N, ncols=M)

Alternatively you may always use the unpacked version

fig, ax_arr = plt.subplots(nrows=N, ncols=M, squeeze=False)

and index the array to obtain the axes, ax_arr[1,2].plot(..).

So for a 2 x 3 grid it wouldn't actually matter if you set squeeze to False. The result will always be a 2D array. You may unpack it as

fig, ((ax1, ax2, ax3),(ax4, ax5, ax6)) = plt.subplots(nrows=2, ncols=3)

to have ax{i} as the matplotlib axes objects, or you may use the packed version

fig, ax_arr = plt.subplots(nrows=2, ncols=3)
ax_arr[0,0].plot(..) # plot to first top left axes
ax_arr[1,2].plot(..) # plot to last bottom right axes
like image 196
ImportanceOfBeingErnest Avatar answered Oct 03 '22 01:10

ImportanceOfBeingErnest