Matplotlib: Save figure as file from iPython notebook

Go To StackoverFlow.com

20

I am trying to save a Matplotlib figure as a file from an iPython notebook.

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_axes([1,1,1,1])
ax.plot([1,2])

fig.savefig('test.png')

The inline view in the iPython notebook looks good:

Inline view of figure in iPython notebook


The file 'test.png' is almost empty though. It looks like the plot is shifted to the top right, you can see the tick labels '1.0' and '0.0' in the corner.

test.png

How can I produce a file from the iPython notebook that looks like the inline view?

2013-10-09 11:54
by Martin Preusse


18

Problem solved: add 'bbox_inches='tight' argument to savefig.

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_axes([1,1,1,1])
plt.plot([1,2])

savefig('test.png', bbox_inches='tight')

I don't understand what's happening here, but the file looks like the iPython notebook inline file now. Yay.

2013-10-09 12:41
by Martin Preusse
But it shouldn't be happening at all, so it might still be worth finding out whats your issue - Rutger Kassies 2013-10-09 12:43
Good point. Here's what the docs say about 'bbox_inches': "Bbox in inches. Only the given portion of the figure is saved. If ‘tight’, try to figure out the tight bbox of the figure." I kind of don't get it - Martin Preusse 2013-10-09 12:54
Normal behavior often has a very wide white border around the axes, tight tries to minimize that. Its not really related to your issue i think. But only by using tight, the correct "figure area" is determined, but that doesn't tell (me) much on why it is wrong in the first place - Rutger Kassies 2013-10-09 13:15
Me neither :) What I figured out so far is that it works when I only do 'plt.plot([1,2]) plt.savefig('file.png')' and don't define the fig = plt.figure() and ax = fig.add_axes(). So I assume it has something to do with the settings on the figure or axes. It's also not an iPython or notebook issue. Same behavior in iPython console and plain Python script - Martin Preusse 2013-10-09 13:20


5

Actually, the savefig is working properly. When you call add_axes, your list specifies a rectangle: [left, bottom, width, height]. Since the figure goes from 0 to 1 on both axes with the origin at the bottom left, you're making a rectangle of width and height 1 starting from the very top-right of the figure. You likely want to be doing ax = fig.add_axes([0,0,1,1]).

I'm not sure why the inline plot doesn't respect where you've placed the axes. If I had to guess, I would say that the inline backend automatically figures out the bounding box and places the inline figure according to that.

2013-10-09 15:22
by tbekolay
When I do "ax = fig.addaxes([0,0,1,1])" everything outside of the actual axes is cut off. When I move everything up with "ax = fig.addaxes([0.1,0.1,1,1])" the top and right part of the plot are missing. Even if I combine it with a 'figsize' some parts are always cut off. With "bbox_inches='tight'" everything is nicely placed. I don't really understand what number sets what, docs don't help - Martin Preusse 2013-10-11 15:03
In general, you shouldn't be creating your own axes with .make_axes; you should let Matplotlib handle that itself. Your example could be done with plt.plot([1,2]); plt.savefig('test.png'). Adding axes manually is an advanced thing that you would do if you need precise placement of axes; in most cases, however, you should just let Matplotlib do its thing, and use plt.tight_layout() when things go wrong - tbekolay 2013-10-11 16:17
In the real life case I use 'imshow' and all the examples I found use axes. Strange, I think I need to get my head around this plotting logic ; - Martin Preusse 2013-10-21 09:06
Ads