cauchy
cauchy

Reputation: 1853

pad_inches=0 and bbox_inches="tight" makes the plot smaller than declared figsize

I am producing a publication-quality plot to be embedded in latex and I would like to be very precise in terms of sizes and fonts (so that fonts are of the same size in the article as in the plot). To prevent the plot from scaling in latex I would like to have it exact size, but I cannot. Here is my code:

import matplotlib.pyplot as plt
from matplotlib import rc, rcParams
from numpy import sin

rc('text', usetex=True)
rc('font', family='serif', serif='Computer Modern Roman', size=8)
rc('legend', fontsize=10)

width_in = 5
fig = plt.figure(1, figsize=(width_in, 2))
ax = fig.add_subplot(111)
ax.plot(range(0,100), sin(range(0,100)))

fig.tight_layout()
fig.savefig('test.eps', bbox_inches='tight', pad_inches=0)
plt.close()

The problem is with bbox_inches='tight' and pad_inches=0. Adding those options makes my plot 4.76 inches wide instead of declared 5 inches. But I want them to save space. So how to solve it?

Edit: Well, the answers suggest to remove bbox_inches='tight' and pad_inches=0 and use just the tight_layout(). Then the images is of right size, however it has still some white padding around. I can remove it with fig.tight_layout(pad=0), but then the figure title it moved inside the box, which looks ugly. On the other hand I can use tight_layout(rect=[...]) and obtain the desired result, but it is a manual work to get the numbers right - I don't like it. Thus, currently I don't see any easy and general solution to my problem.

Upvotes: 55

Views: 134147

Answers (3)

Kyrion
Kyrion

Reputation: 188

I have the same problem making matplotlib plots for LaTeX. Since my plots did not allow to use tight_layout, giving this warning, I ended up using fig.subplots_adjust(bottom=bottom_pos, top=top_pos, left=left_pos, right=right_pos). See this tutorial. It requires manually finding the best values for bottom_pos etc. but in my case it seems to be the only possibility to get images without much whitespace not changing the figure size of the output.

Upvotes: 8

tacaswell
tacaswell

Reputation: 87356

The problem you are having is that bbox_inches='tight' just removes all of the extra white space around your figure, it does not actually re-arrange anything in your figure, after it has been rendered.

You might need to tweak the parameters you pass to tight_layout (tutorial) to get your desired effect.

Hopefully this gets you pointed in the right direction.

Upvotes: 43

Vorticity
Vorticity

Reputation: 4926

Your original plot must have whitespace around it, otherwise bbox_inches=tight would not remove any of the area. There are two solutions to this that I know of:

  1. The simple method is to use tight_layout as mentioned by tcaswell.

  2. The more complicated, but more controllable method is to avoid using fig.add_subplot(111) and instead use fig.add_axes() which allows you to be much more strict in terms of how large your axes are when you define the axes instance. You can then tweak the size of your axes to take up as much of the figure area as required to maintain a 5" figure area. Once you have done this, I would recommend simply not using bbox_inches or set it to None (the default) to avoid unnessicary cropping. fig.add_axes() requires a rect parameter as its first argument which consists of [left_position, bottom_position, width, height] each of which range from 0 to 1.

Edit: After going through the tight_layout tutorial again, I have realized that it covers pretty much everything. I hadn't realized that it was able to maintain the aspect ratio of the axes instance easily, even if the aspect ratio of the figure is different from that of the axes instance. I tend to try to be very explicit when I define my axes areas because I deal with satellite imagery and try to keep it as the native sensor resolution or some factor of that sensor resolution, which requires a little bit more control.

Upvotes: 3

Related Questions