When you set bbox_inches = 'tight' in Matplotlib's savefig() function, it tries to find the tightest bounding box that encapsulates all the content in your figure window. Unfortunately, the tightest bounding box appears to include invisible axes.
For example, here is a snippet where setting bbox_inches = 'tight' works as desired:
import matplotlib.pylab as plt
fig = plt.figure(figsize = (5,5))
data_ax = fig.add_axes([0.2, 0.2, 0.6, 0.6])
data_ax.plot([1,2], [1,2])
plt.savefig('Test1.pdf', bbox_inches = 'tight', pad_inches = 0)
which produces:
The bounds of the saved pdf correspond to the bounds of the content. This is great, except that I like to use a set of invisible figure axes to place annotations in. If the invisible axes extend beyond the bounds of the visible content, then the pdf bounds are larger than the visible content. For example:
import matplotlib.pylab as plt
fig = plt.figure(figsize = (5,5))
fig_ax = fig.add_axes([0, 0, 1, 1], frame_on = False)
fig_ax.xaxis.set_visible(False)
fig_ax.yaxis.set_visible(False)
data_ax = fig.add_axes([0.2, 0.2, 0.6, 0.6])
data_ax.plot([1,2], [1,2])
plt.savefig('Test2.pdf', bbox_inches = 'tight', pad_inches = 0)
producing
How can I force savefig() to ignore invisible items in the figure window? The only solution I have come up with is to calculate the bounding box myself and explicitly specify the bbox to savefig().
In case it matters, I am running Matplotlib 1.2.1 under Python 2.7.3 on Mac OS X 10.8.5.
The relevant function (called by canvas.print_figure
which is called by figure.savefig
to generate the bounding box) in backend_bases.py
:
def get_tightbbox(self, renderer):
"""
Return a (tight) bounding box of the figure in inches.
It only accounts axes title, axis labels, and axis
ticklabels. Needs improvement.
"""
bb = []
for ax in self.axes:
if ax.get_visible():
bb.append(ax.get_tightbbox(renderer))
_bbox = Bbox.union([b for b in bb if b.width != 0 or b.height != 0])
bbox_inches = TransformedBbox(_bbox,
Affine2D().scale(1. / self.dpi))
return bbox_inches
The only consideration that goes into deciding if an axes is 'visible' is if ax.get_visible()
returns true, even if you have no visible (either artist.get_visible() == False
or simple transparent) artists in the axes.
The bounding box behavior you observe is the correct behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With