diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 0c85673b2b10..09dc3d6e8c42 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1516,10 +1516,15 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None): self.key = key -def _get_renderer(figure, print_method): +def _get_renderer(figure, print_method, *, draw_disabled=False): """ Get the renderer that would be used to save a `~.Figure`, and cache it on the figure. + + If *draw_disabled* is True, additionally replace draw_foo methods on + *renderer* by no-ops. This is used by the tight-bbox-saving renderer, + which needs to walk through the artist tree to compute the tight-bbox, but + for which the output file may be closed early. """ # This is implemented by triggering a draw, then immediately jumping out of # Figure.draw() by raising an exception. @@ -1533,8 +1538,14 @@ def _draw(renderer): raise Done(renderer) try: print_method(io.BytesIO()) except Done as exc: - figure._cachedRenderer, = exc.args - return figure._cachedRenderer + renderer, = figure._cachedRenderer, = exc.args + + if draw_disabled: + for meth_name in dir(RendererBase): + if meth_name.startswith("draw_"): + setattr(renderer, meth_name, lambda *args, **kwargs: None) + + return renderer def _is_non_interactive_terminal_ipython(ip): @@ -2063,7 +2074,8 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None, renderer = _get_renderer( self.figure, functools.partial( - print_method, dpi=dpi, orientation=orientation)) + print_method, dpi=dpi, orientation=orientation), + draw_disabled=True) self.figure.draw(renderer) bbox_artists = kwargs.pop("bbox_extra_artists", None) bbox_inches = self.figure.get_tightbbox(renderer, diff --git a/lib/matplotlib/tests/test_backend_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index 269606c7feca..7843b4101041 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -282,3 +282,11 @@ def test_tex_restart_after_error(): fig = plt.figure() # start from scratch fig.suptitle(r"this is ok") fig.savefig(BytesIO(), format="pgf") + + +@needs_xelatex +def test_bbox_inches_tight(tmpdir): + fig, ax = plt.subplots() + ax.imshow([[0, 1], [2, 3]]) + fig.savefig(os.path.join(tmpdir, "test.pdf"), backend="pgf", + bbox_inches="tight")