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?

1
  • 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. Commented May 16, 2011 at 18:44

2 Answers 2

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)
Sign up to request clarification or add additional context in comments.

3 Comments

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.
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.
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.
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...

3 Comments

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.
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.
Yep, it's telling me I still have 23 hours to mark my own answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.