8

I've kept a set of references to figures in a dictionary so that I could save them later if desired. I am troubled that the saved figures are blank if invoke a show() command and look at them first. Since the show() command blocks and I am not using a spyder-like interpreter, I have to close the figures before I get to savefig()

figures['myfig_1'] = figure()
...
figures['myfig_n'] = figure()
...

#show() #disabling this makes the problem go away
print "Saving:"
for fig in figures:
   figure(figures[fig].number)
   savefig(fig)
   print "Figure " + str(figures[fig].number) + ": " + fig

The print statement here has given me the indication that the dictionary is still intact, which I think means that I have not lost the figure references (they are still returning meaningful numbers in their .number attribute.)

Another twist I have noticed is that when I have done a similar thing in a class, storing the dictionary as a member and dividing the store and save functions into their own methods, this does not happen. Is there something about the way I am closing the figures or storing the data which is making the figures loose their data?

Serenity
  • 35,289
  • 20
  • 120
  • 115
2NinerRomeo
  • 2,687
  • 4
  • 29
  • 35
  • I came up with an answer, but I'm locked out of adding it for 8 hours. Rats... The short version is that I changed my rendering backend to 'TkAgg' for now until I can figure out how to get Qt4Agg to behave the way I'd like. – 2NinerRomeo May 16 '11 at 18:44

2 Answers2

7

Generally speaking, in cases like this don't use the interactive matlab-ish state machine interface to matplotlib. It's meant for interactive use.

You're trying to make a figure "active", and creating a new figure instead. It doesn't matter which figure is active, if you just retain the returned figure and/or axis objects and use them directly. (Also, don't use wildcard imports! You will regret it at some later point when you're maintaining your code!)

Just do something like this:

import matplotlib.pyplot as plt
figures = {}

figures['a'] = plt.figure()
ax = figures['a'].add_subplot(111)
ax.plot(range(10), 'ro-')

figures['b'] = plt.figure()
ax = figures['b'].add_subplot(111)
ax.plot(range(10), 'bo-')

plt.show()

for name, fig in figures.iteritems():
    fig.savefig('figure-%s.png' % name)
Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • My newness is coming out here, I did not even know there was such a slick way to iterate the keys and values simultaneously. I also agree on the wildcard import issue. I'm in a new environment with a 'git er done' culture. Additionally to opening the possibility of name collisions, it makes it harder to learn where functionality is coming from. – 2NinerRomeo May 16 '11 at 17:03
  • I've changed my ways, now using the .iteritems() approach, but I'm running into the same problem: after a show(), the figures seem to be deleted after I close the interactive window. The interpreter is stopping on the .savefig command and goes through a call stack of print_figure.draw() draw.update() where it tells me the underlying c/c++ object has been deleted. – 2NinerRomeo May 16 '11 at 17:08
  • The "state machine" approach appears to work. Without the pyplot.show(), the figures are being recalled and saved properly. If they are shown, then closed, then they are lost. I don't know if this is part of the intention of pyplot.show() but it seems to be what is happening. I don't know if it is a factor, but I am importing a package called pylab which I presume is giving me pyplot, but I don't really know. – 2NinerRomeo May 16 '11 at 17:19
2

From the documentation, whether or not the drawing elements are destroyed from show() depends on the backend, and the version of matplotlib. Not having the figures destroyed seems to be available with version 1.1.0. To figure out which backend is in use, use the get_backend() function. In my case, I was using the Qt4Agg backend. By invoking the TkAgg backend, with the call matplotlib.use('TkAgg') the figures were not destroyed before the save. Now to find out how to change the behavior of the Qt4Agg...

Community
  • 1
  • 1
2NinerRomeo
  • 2,687
  • 4
  • 29
  • 35
  • Nice! I didn't realize that... The backends I use (mostly TkAgg) don't destroy the figure when you call show. I wasn't aware that some did. I just jumped to the assumption that you were clearing the figure when you called `figure(figures[fig].number)`. Regardless, I do find it much easier to stick to the OO interface and not rely on making figures active. – Joe Kington May 16 '11 at 23:44
  • Incidentally, you should probably mark your answer as corrected, as you solved your own problem. It's perfectly acceptable to do so, though I believe you'll have to wait 2 days to mark your own answer as the accepted one. – Joe Kington May 16 '11 at 23:51
  • Yep, it's telling me I still have 23 hours to mark my own answer. – 2NinerRomeo May 17 '11 at 16:36