3232 The base class for the messaging area.
3333"""
3434
35- from contextlib import contextmanager
35+ from contextlib import contextmanager , suppress
3636from enum import IntEnum
3737import functools
3838import importlib
5252from matplotlib ._pylab_helpers import Gcf
5353from matplotlib .transforms import Affine2D
5454from matplotlib .path import Path
55+ from matplotlib .cbook import _setattr_cm
5556
5657try :
5758 from PIL import __version__ as PILLOW_VERSION
@@ -712,6 +713,23 @@ def stop_filter(self, filter_func):
712713 Currently only supported by the agg renderer.
713714 """
714715
716+ def _draw_disabled (self ):
717+ """
718+ Context manager to temporary disable drawing.
719+
720+ This is used for getting the drawn size of Artists. This lets us
721+ run the draw process to update any Python state but does not pay the
722+ cost of the draw_XYZ calls on the canvas.
723+ """
724+ no_ops = {
725+ meth_name : lambda * args , ** kwargs : None
726+ for meth_name in dir (RendererBase )
727+ if (meth_name .startswith ("draw_" )
728+ or meth_name in ["open_group" , "close_group" ])
729+ }
730+
731+ return _setattr_cm (self , ** no_ops )
732+
715733
716734class GraphicsContextBase :
717735 """An abstract base class that provides color, line styles, etc."""
@@ -1520,15 +1538,14 @@ def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):
15201538 LocationEvent .__init__ (self , name , canvas , x , y , guiEvent = guiEvent )
15211539
15221540
1523- def _get_renderer (figure , print_method , * , draw_disabled = False ):
1541+ def _get_renderer (figure , print_method ):
15241542 """
15251543 Get the renderer that would be used to save a `~.Figure`, and cache it on
15261544 the figure.
15271545
1528- If *draw_disabled* is True, additionally replace drawing methods on
1529- *renderer* by no-ops. This is used by the tight-bbox-saving renderer,
1530- which needs to walk through the artist tree to compute the tight-bbox, but
1531- for which the output file may be closed early.
1546+ If you need a renderer without any active draw methods use
1547+ renderer._draw_disabled to temporary patch them out at your call site.
1548+
15321549 """
15331550 # This is implemented by triggering a draw, then immediately jumping out of
15341551 # Figure.draw() by raising an exception.
@@ -1544,12 +1561,6 @@ def _draw(renderer): raise Done(renderer)
15441561 except Done as exc :
15451562 renderer , = figure ._cachedRenderer , = exc .args
15461563
1547- if draw_disabled :
1548- for meth_name in dir (RendererBase ):
1549- if (meth_name .startswith ("draw_" )
1550- or meth_name in ["open_group" , "close_group" ]):
1551- setattr (renderer , meth_name , lambda * args , ** kwargs : None )
1552-
15531564 return renderer
15541565
15551566
@@ -2079,9 +2090,13 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
20792090 renderer = _get_renderer (
20802091 self .figure ,
20812092 functools .partial (
2082- print_method , dpi = dpi , orientation = orientation ),
2083- draw_disabled = True )
2084- self .figure .draw (renderer )
2093+ print_method , dpi = dpi , orientation = orientation )
2094+ )
2095+ ctx = (renderer ._draw_disabled ()
2096+ if hasattr (renderer , '_draw_disabled' )
2097+ else suppress ())
2098+ with ctx :
2099+ self .figure .draw (renderer )
20852100 bbox_artists = kwargs .pop ("bbox_extra_artists" , None )
20862101 bbox_inches = self .figure .get_tightbbox (renderer ,
20872102 bbox_extra_artists = bbox_artists )
0 commit comments