I often produce individual figures with matplotlib which are supposed to be aligned vertically or horizontally e.g. in a LaTeX document. My goals are:
bbox_inches='tight'
in savefig
.My current solution is a very inconvenient trial and error approach: I manually try to guess reasonable margins and set them via plt.subplots_adjust()
. This often takes a lot of time until I have a satisfactory result.
I'm wondering if it is possible to combine the power of bbox_inches='tight'
with plt.subplots_adjust()
? Is it possible to programmatically get the resulting bounding box of bbox_inches='tight'
? This would allow my to determining the bounding box for the figure with the largest axis labels/titles, and use this bounding box for all other figures.
Thanks to @Schorsch and @tcaswell for pointing out that ax.get_tightbbox
almost solves this problem. The only tricky part is to convert the renderer dependent bbox into an "inches" bbox. The general solution is:
tight_bbox_raw = ax.get_tightbbox(fig.canvas.get_renderer())
tight_bbox = TransformedBbox(tight_bbox_raw, Affine2D().scale(1./fig.dpi))
I can now reuse the tight_bbox
for my other plots as well, resulting in nice, identically boxed figures.
I have also written a small helper class -- not elegant, but useful: I call max_box_tracker.add_figure
for every figure I create, and it will internally update a maximum bounding box. After generating all plots, I can print out the resulting bounding box (directly in the form of code to add to my script).
class MaxBoxTracker:
def __init__(self):
self.box = None
def add_figure(self, fig, ax):
from matplotlib.transforms import TransformedBbox, Affine2D
box_raw = ax.get_tightbbox(fig.canvas.get_renderer())
box = TransformedBbox(box_raw, Affine2D().scale(1./fig.dpi)).get_points()
if self.box is None:
self.box = box
else:
self.box[0][0] = min(self.box[0][0], box[0][0])
self.box[0][1] = min(self.box[0][1], box[0][1])
self.box[1][0] = max(self.box[1][0], box[1][0])
self.box[1][1] = max(self.box[1][1], box[1][1])
def print_max(self):
print 'Code to set maximum bbox:\nfrom matplotlib.transforms import Bbox\ntight_bbox = Bbox([[%f, %f], [%f, %f]])' % (
self.box[0][0], self.box[0][1], self.box[1][0], self.box[1][1]
)
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