Complex layouts of subplots

Dear all,

I am working on figures for my thesis, which consist of several related panels. Each of the panel contains several subplots. In order to arrange the plots I would like to split the figure into two (or more) panels and within each of them create a nested set of subplots. Optimally, the main panels should define their own coordinate systems, such that all of the nested subplot positions are defined within their frame. The syntax could look like that:

panel1 = subplot(1,2,1)
panel2 = subplot(1,2,2)

ax1 = panel1.add_subplot(1,2,1)
ax2 = panel1.add_subplot(1,2,2)

ax3 = panel2.add_subplot(111)

For now it is not possible, because panel1 and panel2 are Axes instances which do not have add_subplot method. The only solution I am aware of is to define all of the subplots by hand using subplot or axes function with positions defined within whole figure coordinate system:

fig = figure()
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,3)
ax3 = fig.add_subplot(1,2,2)

This is of course more difficult, less flexible and requires the user to decide in advance on the layout of the panel.

Until now I exported each figure to SVG file and arranged them in one file using SVG directives. I also started implementing my own Multipanel class for matplotlib, but it proved out to be not so easy. Therefore I would like to ask if someone has implemented a similar approach or could give me some hints on the implementation.

I will be very grateful for any help.

Cheers,

Bartek

2010/5/7 Bartosz Telenczuk <bartosz.telenczuk@…287…>:

Dear all,

I am working on figures for my thesis, which consist of several related panels. Each of the panel contains several subplots. In order to arrange the plots I would like to split the figure into two (or more) panels and within each of them create a nested set of subplots. Optimally, the main panels should define their own coordinate systems, such that all of the nested subplot positions are defined within their frame. The syntax could look like that:

panel1 = subplot(1,2,1)
panel2 = subplot(1,2,2)

ax1 = panel1.add_subplot(1,2,1)
ax2 = panel1.add_subplot(1,2,2)

ax3 = panel2.add_subplot(111)

I think what you could maybe try is to write a class using figure.add_axes()

http://matplotlib.sourceforge.net/api/figure_api.html#matplotlib.figure.Figure.add_axes

The class could store a relative area and a “master”. For the panels you need, the master would be the Figure. Such a Panel class could expose an add_axes() method too, but forwarding the call to its master. To calculate the rect argument when callings its master’s .add_axes(), it would use a linear transformation from the stored extent to the (0, 1) extent relative to the master. Let it be depicted:

±---------------------+ Figure
±------------+ Panel
±-----+ Axes

There could be more Panels in between. You would do:

panel = Panel(figure, (0.2, 0.6)) # left = 0.2, width = 0.6, i.e. right = 0.8
axes = panel.add_axes((0, 0.5)) # left = 0, width = 0.5, i.e. right = 0.5

The last call would do:

  1. Transform the (0, 0.5) to the Figure reference frame (more precise, to the master ref frame, where by coincidence the Figure is the master). Thie yields here (0.2, 0.3) = (left, width), i.e. right = 0.5 (in the master ref frame).

  2. Call master.add_axes((0.2, 0.3)). This actually creates the Axes instance by recusions until the master is a Figure.

I think this approach is feasible in < 200 loc.

hth
Friedrich