15

I'm producing graphics for publication with matplotlib and want very precisely sized figure output. I need this so that I can be sure the figure won't need to be resized when inserted into the latex document, which would mess with the font size in the figure which I want to keep at a consistent ratio to the font size in the main document.

I need to use the bbox_extra_artists argument to savefig because I have a legend down the bottom that gets cut off the figure if I don't. The problem I am having is that I haven't found a way to have the original figure dimensions I specify with figsize when creating the plot honoured after calling savefig with bbox_extra_artists.

My call to savefig looks like this:

savefig(output_file, bbox_inches='tight', pad_inches=0.0,dpi=72.27,bbox_extra_artists=(lgd,tp,ur,hrs))

The figure width I specify with figsize is:

516.0 * (1/72.27) = 7.1398 inches = 181.3532 millimeters 

The output PDF width I get using my savefig() call above is 171 millimeters (not the desired 181.3532 millimeters).

The solution I've seen proposed in other questions here on SO is to make a call to tight_layout(). So, immediately above my savefig() call, I put the following:

plt.tight_layout(pad=0.0,h_pad=0.0,w_pad=0.0)

This produces a figure with width 183 millimeters (again, not the 181.3532 millimeters I want). If I use tight_layout, and remove the bbox_extra_artists argument from my call to savefig(), I get a width of 190 millimeters (again, not 181.3532 millimeters that I want). This is besides the point that removing bbox_extra_artists in my case mangles up the figure by cutting things off.

So I guess this is a two part question:

  • When using tight_layout, even without bbox_extra_artists, why is the output figure incorrectly sized?
  • Is there any way to get a correctly sized figure when using bbox_extra_artists?

I know a few millimeters sounds like a trivial difference, but it's the fact that there is any difference at all that concerns me. It means there is some variable, which could change in my other figures which is causing a degree of error, and that error may well be magnified elsewhere.

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
Bryce Thomas
  • 10,479
  • 26
  • 77
  • 126

1 Answers1

11

The reason that you're getting a smaller plot is because you're specifying bbox_inches='tight'.

bbox_inches='tight' crops the plot down based on the extents of the artists in the plot. If you want the output to be exactly the size you specify, then just leave out the bbox_inches and bbox_extra_artists kwargs entirely.

If you just do savefig(output_file, dpi=72.72) without anything else the plot will be exactly the size you specified with creating the figure.

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • Is there a way to specify the exact figure size *after* using bbox_inches='tight'? Basically, the extent of any whitespace around the figure ought to be decided in the document I'm inserting it into and not encoded into the figure pdf itself. – Bryce Thomas Apr 21 '13 at 05:36
  • 1
    As a side not, I recently discovered that `bbox_inches='tight'` will also crop _out_ (that is if you artists are outside of your figure it will expand to include them. (http://stackoverflow.com/questions/16057869/setting-the-size-of-the-plotting-canvas-in-matplotlib/16061699?noredirect=1#comment22981282_16061699) If this is intentional as a different question. – tacaswell Apr 21 '13 at 06:18
  • 1
    @BryceThomas - It is possible, but it's a bit verbsose, and it requires drawing the plot an extra time (incurring a performance penalty, though that's probably not a major issue). I'll add an example in a bit. – Joe Kington Apr 21 '13 at 19:50
  • 1
    @BryceThomas - Actually, it may not be possible... At any rate, it's more complex than I initially thought. – Joe Kington Apr 23 '13 at 03:03
  • @BryceThomas Did you ever figure out how to do this? – Osmond Bishop Nov 07 '13 at 19:18
  • @OsmondBishop sadly not. I'd still like to know if someone does figure out a way though. – Bryce Thomas Nov 07 '13 at 23:51
  • I was having a narrow bounding box around the picture. By following this advice (removing bbox_inches="tight" from figure.savefig arguments) the bounding box completely. thanks – Lyrk Aug 05 '21 at 18:19