0

I have an application that have 3 figures, and dynamicaly change them. For now it's been working fine by using add_subplot() to the figure. But now I have to make my graphs more complex, and need to use subplot2grid()

self.figure1 = plt.figure()
self.canvas1 = FigureCanvas(self.figure1)
self.graphtoolbar1 = NavigationToolbar(self.canvas1, frameGraph1)

self.figure3 = plt.figure()
self.canvas3 = FigureCanvas(self.figure3)
self.graphtoolbar3 = NavigationToolbar(self.canvas3, frameGraph3)

self.figure4 = plt.figure()
self.canvas4 = FigureCanvas(self.figure4)
self.graphtoolbar4 = NavigationToolbar(self.canvas4, frameGraph4)

And here's the code that adds it, and what I've got so far.

#ax = self.figure1.add_subplot(2,1,1) <---- What I used to do

fig = self.figure1
ax = plt.subplot2grid((4,4), (0,0), rowspan=3, colspan=4) # <--- what I'm trying to do

ax.hold(False)
ax.plot(df['Close'], 'b-')
ax.legend(loc=0)
ax.set_xlabel("Date")
ax.set_ylabel("Price")
ax.grid(True)

for tick in ax.get_xticklabels():
     tick.set_rotation(20)            

self.canvas1.draw()

The above adds it to figure 4. Probably because that's the latest instantiated by plt. But I'd like the above to add a subplot2grid to self.figure1, while still having the dynamicly abilities as before.

vandelay
  • 1,965
  • 8
  • 35
  • 52

1 Answers1

2

Looking into the source code of matplotlib, the subplot2grid-function is defined in the following way:

def subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs):
    """
    Create a subplot in a grid.  The grid is specified by *shape*, at
    location of *loc*, spanning *rowspan*, *colspan* cells in each
    direction.  The index for loc is 0-based. ::

      subplot2grid(shape, loc, rowspan=1, colspan=1)

    is identical to ::

      gridspec=GridSpec(shape[0], shape[2])
      subplotspec=gridspec.new_subplotspec(loc, rowspan, colspan)
      subplot(subplotspec)
    """

    fig = gcf()  #  <-------- HERE
    s1, s2 = shape
    subplotspec = GridSpec(s1, s2).new_subplotspec(loc,
                                                   rowspan=rowspan,
                                                   colspan=colspan)
    a = fig.add_subplot(subplotspec, **kwargs)
    bbox = a.bbox
    byebye = []
    for other in fig.axes:
        if other==a: continue
        if bbox.fully_overlaps(other.bbox):
            byebye.append(other)
    for ax in byebye: delaxes(ax)

    draw_if_interactive()
    return a

As you can see from my comment "HERE" in the code snippet, it is only using the active figure, i.e. fig = gcf() (gcf is short for "get current figure").

Achieving your goal should be easily done by modifying the function slightly and put it into your script.

from matplotlib.gridspec import GridSpec
from matplotlib.backends import pylab_setup
_backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup()

def my_subplot2grid(fig, shape, loc, rowspan=1, colspan=1, **kwargs):

    s1, s2 = shape
    subplotspec = GridSpec(s1, s2).new_subplotspec(loc,
                                                   rowspan=rowspan,
                                                   colspan=colspan)
    a = fig.add_subplot(subplotspec, **kwargs)
    bbox = a.bbox
    byebye = []
    for other in fig.axes:
        if other==a: continue
        if bbox.fully_overlaps(other.bbox):
            byebye.append(other)
    for ax in byebye: delaxes(ax)

    draw_if_interactive()
    return a

Now it should be possible to do your thing, with a modification to your function call as

ax = plt.my_subplot2grid(self.figure1, (4,4), (0,0), rowspan=3, colspan=4)

Hope it helps!

pathoren
  • 1,634
  • 2
  • 14
  • 22
  • Thanks for pointing out cfg. I found out I could give a number to the figures as I instantiate them. self.figure1 = plt.figure(1) and then set the cfg with plt.figure(1). – vandelay Aug 03 '16 at 20:25
  • 1
    You are right! I think I overdid it a bit, it should indeed be better to just update the current figure. The a look at this previous answer http://stackoverflow.com/questions/7986567/matplotlib-how-to-set-the-current-figure . It suggest that you can even call your figures by a string and not just `figure(1)`. – pathoren Aug 03 '16 at 20:29