From cd519f8afa053e59c7d43801ad77ce23ab55e04e Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 11 Mar 2020 19:17:32 +0100 Subject: [PATCH] Disable draw_foo methods on renderer used to estimate tight extents. For the pgf backend, in particular draw_image() cannot succeed because that needs actual filesystem access (to set up \includegraphics). --- lib/matplotlib/backend_bases.py | 20 ++++++++++++++++---- lib/matplotlib/tests/test_backend_pgf.py | 8 ++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index b17da96dbee9..2e4a2d6a43b2 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1489,10 +1489,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. @@ -1506,8 +1511,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): @@ -2058,7 +2069,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( diff --git a/lib/matplotlib/tests/test_backend_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index 3ac59d39dff1..7016f2e04758 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -291,3 +291,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")