Matplotlib - Grid arrangement subplots spacing
Question: I am trying to arrange a bunch of subplots in a grid like fashion. The problem
is that the number of subplots varies with user selection of what data to
plot. Right now I am trying to add plots this way:

    
    
        l = len(clicked)
    
        self.p=wx.Panel(self)
        self.dpi=100
        self.fig = Figure()
        self.canvas = FigCanvas(self.p, -1, self.fig)
        if l == 1:
            self.splt = self.fig.add_subplot(1,1,1)
            self.plt=self.splt.plot(np.arange(5),np.arange(5))
        else:
            for i in np.arange(l):
                self.splt=self.fig.add_subplot(l+1,2,i+1)
                self.fig.subplots_adjust(left=0.7, bottom=0.6, right=0.75, top=0.75)
                self.plt=self.splt.plot(np.arange(5),np.arange(5))
    

I am just using fake data for debugging purposes. Anyhow, I am using wxPython
to draw this inside a frame. `clicked` here provides the number of selections
the user made. I already tried using `subplots_adjust()`, with quite the
opposite result than I wanted. The plots are being shrunk something
indiscernable. Is there a way to arrange teh plots in some sort of grid. I saw
there is an option `subplot2grid`, but I havent gotten it to work with the
variable number of subplots.


Answer: Hopefully this helps:

    
    
    from __future__ import division
    import numpy as np
    import pylab as plt
    
    def divideSquare(N):
        if N<1:
            return 1,1
    
        minX = max(1,int(np.floor(np.sqrt(N))))
        maxX = max(minX+1, int(np.ceil(np.sqrt(5.0/3*N))))
        Nx = range(minX, maxX+1)
        Ny = [np.ceil(N/y) for y in Nx]
        err = [np.uint8(y*x - N) for y in Nx for x in Ny]
        ind = np.argmin(err)
        y = Nx[int(ind/len(Ny))]
        x = Ny[ind%len(Nx)]
        return min(y,x), max(y,x)
    
    Nlist = np.arange(0,101)
    empty = np.zeros_like(Nlist)
    ratio = np.zeros_like(Nlist, dtype = float)
    for k, N in enumerate(Nlist):
        y,x = divideSquare(N)
        empty[k] = y*x - N
        ratio[k] = 1.0 * x/y
        print y,x,y/x
    
    plt.figure(1)
    plt.clf()
    y,x = divideSquare(2)
    plt.subplot(y,x,1)    
    plt.plot(Nlist, empty, 'k')
    plt.xlabel('Number of plots')
    plt.ylabel('Empty squares left')
    plt.subplot(y,x,2)
    plt.plot(Nlist, ratio, 'r')
    plt.xlabel('Number of plots')
    plt.ylabel('Ratio')
    
    def divide2or3(N):
        if N<1:
            return 1,1
        if N%2==0:
            return int(np.ceil(N/2)), 2
        return int(np.ceil(N/3)), 3
    
    Nlist = np.arange(0,101)
    empty = np.zeros_like(Nlist)
    ratio = np.zeros_like(Nlist, dtype = float)
    for k, N in enumerate(Nlist):
        y,x = divide2or3(N)
        empty[k] = y*x - N
        ratio[k] = 1.0 * x/y
        print y,x,y/x
    
    plt.figure(2)
    plt.clf()
    y,x = divide2or3(2)
    plt.subplot(y,x,1)    
    plt.plot(Nlist, empty, 'k')
    plt.xlabel('Number of plots')
    plt.ylabel('Empty squares left')
    plt.subplot(y,x,2)
    plt.plot(Nlist, ratio, 'r')
    plt.xlabel('Number of plots')
    plt.ylabel('Ratio')
    
    plt.show()
    

divideSquare(N) attempts to get a ratio close to 1 but with a minimal number
of empty positions. divide2or3(N) gives you a grid of 2 or 3 columns (or rows
if you invert x and y), but I'm not sure if this is what you want for 90
plots.

