2525 The base class for the Toolbar class of each interactive backend.
2626"""
2727
28- from contextlib import contextmanager
28+ from contextlib import contextmanager , suppress
2929from enum import Enum , IntEnum
3030import functools
3131import importlib
4646from matplotlib .backend_managers import ToolManager
4747from matplotlib .transforms import Affine2D
4848from matplotlib .path import Path
49+ from matplotlib .cbook import _setattr_cm
4950
5051
5152_log = logging .getLogger (__name__ )
@@ -708,6 +709,23 @@ def stop_filter(self, filter_func):
708709 Currently only supported by the agg renderer.
709710 """
710711
712+ def _draw_disabled (self ):
713+ """
714+ Context manager to temporary disable drawing.
715+
716+ This is used for getting the drawn size of Artists. This lets us
717+ run the draw process to update any Python state but does not pay the
718+ cost of the draw_XYZ calls on the canvas.
719+ """
720+ no_ops = {
721+ meth_name : lambda * args , ** kwargs : None
722+ for meth_name in dir (RendererBase )
723+ if (meth_name .startswith ("draw_" )
724+ or meth_name in ["open_group" , "close_group" ])
725+ }
726+
727+ return _setattr_cm (self , ** no_ops )
728+
711729
712730class GraphicsContextBase :
713731 """An abstract base class that provides color, line styles, etc."""
@@ -1506,15 +1524,14 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):
15061524 LocationEvent .__init__ (self , name , canvas , x , y , guiEvent = guiEvent )
15071525
15081526
1509- def _get_renderer (figure , print_method = None , * , draw_disabled = False ):
1527+ def _get_renderer (figure , print_method = None ):
15101528 """
15111529 Get the renderer that would be used to save a `~.Figure`, and cache it on
15121530 the figure.
15131531
1514- If *draw_disabled* is True, additionally replace drawing methods on
1515- *renderer* by no-ops. This is used by the tight-bbox-saving renderer,
1516- which needs to walk through the artist tree to compute the tight-bbox, but
1517- for which the output file may be closed early.
1532+ If you need a renderer without any active draw methods use
1533+ renderer._draw_disabled to temporary patch them out at your call site.
1534+
15181535 """
15191536 # This is implemented by triggering a draw, then immediately jumping out of
15201537 # Figure.draw() by raising an exception.
@@ -1533,12 +1550,6 @@ def _draw(renderer): raise Done(renderer)
15331550 except Done as exc :
15341551 renderer , = figure ._cachedRenderer , = exc .args
15351552
1536- if draw_disabled :
1537- for meth_name in dir (RendererBase ):
1538- if (meth_name .startswith ("draw_" )
1539- or meth_name in ["open_group" , "close_group" ]):
1540- setattr (renderer , meth_name , lambda * args , ** kwargs : None )
1541-
15421553 return renderer
15431554
15441555
@@ -2097,9 +2108,14 @@ def print_figure(
20972108 renderer = _get_renderer (
20982109 self .figure ,
20992110 functools .partial (
2100- print_method , orientation = orientation ),
2101- draw_disabled = True )
2102- self .figure .draw (renderer )
2111+ print_method , orientation = orientation )
2112+ )
2113+ ctx = (renderer ._draw_disabled ()
2114+ if hasattr (renderer , '_draw_disabled' )
2115+ else suppress ())
2116+ with ctx :
2117+ self .figure .draw (renderer )
2118+
21032119 bbox_inches = self .figure .get_tightbbox (
21042120 renderer , bbox_extra_artists = bbox_extra_artists )
21052121 if pad_inches is None :
0 commit comments