How to make a grid of (plot) grids?

I’m trying to do something in matplotlib that I do routinely in Mathematica, a “grid of grids” of plots.

I made a hi-res JPEG of what this looks like in Mathematica: http://is.gd/k2cXb (you may need to zoom in, but it’s definitely legible; don’t focus too much on the Mathematica code; what matters are the figures).

This is just an example for illustration. In reality, I’m interested in plotting experimental data.

In that example, I have a function called squiggle that takes 4 positive integers as arguments and produces a squiggly plot. Then I create a “grid of grids” of such plots, parametrized by row and column numbers. For example, the lower-left cell of the outer grid corresponds to a=4 and b=1. The inner grid within that cell consists of all the plots squiggle[4, 1, c, d], where c and d each range over {1, 2, 3}.

Notice in particular that the outer grid is constructed with different specs from those used in the inner grid (in this example, the outer grid has gridlines separating the cells, whereas the inner grids don’t). This is what differentiates this problem from the one of simply building one giant grid with all the figures. In particular, it is of paramount importance that the inner grids be grouped visually.

When I try to replicate this with matplotlib I get stuck at the inner level. IOW, I can make the inner grids, but I don’t know how to aggregate them into the outer grid. For example, this code produces the inner grid corresponding to a=4, b=1:

-----------------------------------------------------------------------------

import matplotlib.pyplot as plt
from numpy import arange, sin, cos, pi
from itertools import product

def squiggle_xy(a, b, c, d, i=arange(0.0, 2pi, 0.005)):
return sin(i
a)cos(ib), sin(i*c)cos(id)

plt.figure(figsize=(8, 8))

a, b = 4, 1
for i, (c, d) in enumerate(product(range(1, 4), repeat=2)):
ax = plt.subplot(3, 3, i + 1)
plt.plot(*squiggle_xy(a, b, c, d))
ax.set_xticks([])
ax.set_yticks([])

plt.show()

-----------------------------------------------------------------------------

Can such a “grid of grids” be done with matplotlib? If so, could someone show me how?

Thanks!

G.

Gf B, on 2011-01-03 15:23, wrote:

Can such a "grid of grids" be done with matplotlib? If so, could someone
show me how?

Take a look at GridSpec - in particular:
http://matplotlib.sourceforge.net/users/gridspec.html#gridspec-using-subplotspec

You'll be able to group the inner grids visually by adjusting the
spacing. As far as getting the spines to only outline the outer
grid, and not the inner grid - I think you'll have to do it
manually by hiding the appropriate spines for the inner subplots.
Have a look here for how to do that:
http://matplotlib.sourceforge.net/examples/pylab_examples/spine_placement_demo.html

best

···

--
Paul Ivanov
314 address only used for lists, off-list direct email at:
http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7

Hi, Paul. Thanks for the links!

Gf B, on 2011-01-03 15:23, wrote:

Can such a “grid of grids” be done with matplotlib? If so, could someone

show me how?

You’ll be able to group the inner grids visually by adjusting the

spacing. As far as getting the spines to only outline the outer

grid, and not the inner grid - I think you’ll have to do it

manually by hiding the appropriate spines for the inner subplots.

This sort of ad-hoc manual tweaking is what I was hoping to avoid.

What would it take to implement a “true” grid-of-grids function in matplotlib? What I mean by this is a function that can arrange in a grid not only plots but also other grids. (Is this a question for the devel group?)

G.

···

On Mon, Jan 3, 2011 at 3:53 PM, Paul Ivanov <pivanov314@…287…> wrote:

Gf B, on 2011-01-04 12:31, wrote:

···

On Mon, Jan 3, 2011 at 3:53 PM, Paul Ivanov <pivanov314@...287...> wrote:
Gf B, on 2011-01-03 15:23, wrote:
> > Can such a "grid of grids" be done with matplotlib? If so, could someone
> > show me how?
>
> You'll be able to group the inner grids visually by adjusting the
> spacing. As far as getting the spines to only outline the outer
> grid, and not the inner grid - I think you'll have to do it
> manually by hiding the appropriate spines for the inner subplots.
>

This sort of ad-hoc manual tweaking is what I was hoping to avoid.

What would it take to implement a "true" grid-of-grids function in
matplotlib? What I mean by this is a function that can arrange in a grid
not only plots but also other grids. (Is this a question for the devel
group?)

I think the true grid-of-grids functunality is already
implemented. Here's a replication of your Mathematica plots:

------------
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from itertools import product

def squiggle_xy(a, b, c, d, i=np.linspace(0.0, 2*np.pi, 200)):
    return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d)

f = plt.figure(figsize=(8, 8))

# gridspec inside gridspec
outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0)
for i in xrange(16):
    inner_grid = gridspec.GridSpecFromSubplotSpec(3, 3,
            subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0)
    a, b = int(i/4)+1,i%4+1
    for j, (c, d) in enumerate(product(range(1, 4), repeat=2)):
        ax = plt.Subplot(f, inner_grid[j])
        ax.plot(*squiggle_xy(a, b, c, d))
        ax.set_xticks([])
        ax.set_yticks([])
        f.add_subplot(ax)

all_axes = f.get_axes()

#show only the outside spines
for ax in all_axes:
    for sp in ax.spines.values():
        sp.set_visible(False)
    if ax.is_first_row():
        ax.spines['top'].set_visible(True)
    if ax.is_last_row():
        ax.spines['bottom'].set_visible(True)
    if ax.is_first_col():
        ax.spines['left'].set_visible(True)
    if ax.is_last_col():
        ax.spines['right'].set_visible(True)

plt.show()
------------

It's a matter of taste, but I think you can get away hiding all
spines, and just setting the hspace and wspace for the outer_grid
to some small value (this is what I meant by 'adjusting the
spacing').

I'll send a patch to the devel list shortly adding this example
with the following documentation

A Complex Nested GridSpec using SubplotSpec

Here's a more sophisticated example of nested gridspect where we put
a box around outer 4x4 grid, by hiding appropriate spines in each of the
inner 3x3 grids.

it'll be placed on the gridspec page, after this section:
http://matplotlib.sourceforge.net/users/gridspec.html#gridspec-using-subplotspec

best,
--
Paul Ivanov
314 address only used for lists, off-list direct email at:
http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7

Just to add, because it is related, another tool that gives you advanced control over your axes is the AxesGrid toolkit:

http://matplotlib.sourceforge.net/mpl_toolkits/axes_grid/index.html#toolkit-axesgrid-index

However, gridspec should be exactly what you need for this particular problem.

Ben Root

···

On Tue, Jan 4, 2011 at 6:17 PM, Paul Ivanov <pivanov314@…1972…> wrote:

Gf B, on 2011-01-04 12:31, wrote:

On Mon, Jan 3, 2011 at 3:53 PM, Paul Ivanov <pivanov314@…287…> wrote:

Gf B, on 2011-01-03 15:23, wrote:

Can such a “grid of grids” be done with matplotlib? If so, could someone

show me how?

You’ll be able to group the inner grids visually by adjusting the

spacing. As far as getting the spines to only outline the outer

grid, and not the inner grid - I think you’ll have to do it

manually by hiding the appropriate spines for the inner subplots.

This sort of ad-hoc manual tweaking is what I was hoping to avoid.

What would it take to implement a “true” grid-of-grids function in

matplotlib? What I mean by this is a function that can arrange in a grid

not only plots but also other grids. (Is this a question for the devel

group?)

I think the true grid-of-grids functunality is already

implemented. Here’s a replication of your Mathematica plots:


import numpy as np
import matplotlib.pyplot as plt

import matplotlib.gridspec as gridspec

from itertools import product

def squiggle_xy(a, b, c, d, i=np.linspace(0.0, 2*np.pi, 200)):

return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d)

f = plt.figure(figsize=(8, 8))

gridspec inside gridspec

outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0)

for i in xrange(16):

inner_grid = gridspec.GridSpecFromSubplotSpec(3, 3,

        subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0)

a, b = int(i/4)+1,i%4+1

for j, (c, d) in enumerate(product(range(1, 4), repeat=2)):

ax = plt.Subplot(f, inner_grid[j])

    ax.plot(*squiggle_xy(a, b, c, d))

ax.set_xticks([])

    ax.set_yticks([])

f.add_subplot(ax)

all_axes = f.get_axes()

#show only the outside spines

for ax in all_axes:

for sp in ax.spines.values():

    sp.set_visible(False)

if ax.is_first_row():

    ax.spines['top'].set_visible(True)

if ax.is_last_row():

    ax.spines['bottom'].set_visible(True)

if ax.is_first_col():

    ax.spines['left'].set_visible(True)

if ax.is_last_col():

    ax.spines['right'].set_visible(True)

plt.show()


It’s a matter of taste, but I think you can get away hiding all

spines, and just setting the hspace and wspace for the outer_grid

to some small value (this is what I meant by 'adjusting the

spacing’).

I’ll send a patch to the devel list shortly adding this example

with the following documentation

A Complex Nested GridSpec using SubplotSpec

===========================================

Here’s a more sophisticated example of nested gridspect where we put

a box around outer 4x4 grid, by hiding appropriate spines in each of the

inner 3x3 grids.

it’ll be placed on the gridspec page, after this section:
http://matplotlib.sourceforge.net/users/gridspec.html#gridspec-using-subplotspec

best,

Paul Ivanov

314 address only used for lists, off-list direct email at:

http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7