@@ -46,12 +46,23 @@ class RendererAgg(RendererBase):
4646 context instance that controls the colors/styles
4747 """
4848 debug = 1
49- _fontd = maxdict (50 )
49+
50+ # we want to cache the fonts at the class level so that when
51+ # multiple figures are created we can reuse them. This helps with
52+ # a bug on windows where the creation of too many figures leads to
53+ # too many open file handles. However, storing them at the class
54+ # level is not thread safe. The solution here is to cache the
55+ # fonts at class level, but for a given renderer to slurp them
56+ # down into the instance cache "_fontd_instance" from the
57+ # "_fontd_class" in a call to pre_draw_hook (managed by the
58+ # FigureCanvas) and to restore them to the fontd_class in the
59+ # post_draw_hook.
60+ _fontd_class = maxdict (50 )
5061 def __init__ (self , width , height , dpi ):
5162 if __debug__ : verbose .report ('RendererAgg.__init__' , 'debug-annoying' )
5263 RendererBase .__init__ (self )
5364 self .texd = maxdict (50 ) # a cache of tex image rasters
54-
65+ self . _fontd_instance = maxdict ( 50 )
5566
5667
5768 self .dpi = dpi
@@ -71,6 +82,16 @@ def __init__(self, width, height, dpi):
7182 if __debug__ : verbose .report ('RendererAgg.__init__ done' ,
7283 'debug-annoying' )
7384
85+ def pre_draw_hook (self ):
86+ 'called by FigureCanvas right before draw; slurp in the class level cache'
87+ self ._fontd_instance = RendererAgg ._fontd_class
88+ RendererAgg ._fontd_class = {}
89+
90+ def post_draw_hook (self ):
91+ 'called by FigureCanvas right after draw; restore the class level cache'
92+ RendererAgg ._fontd_class = self ._fontd_instance
93+ self ._fontd_instance = {}
94+
7495 def _get_hinting_flag (self ):
7596 if rcParams ['text.hinting' ]:
7697 return LOAD_FORCE_AUTOHINT
@@ -217,16 +238,16 @@ def _get_agg_font(self, prop):
217238 'debug-annoying' )
218239
219240 key = hash (prop )
220- font = RendererAgg . _fontd .get (key )
241+ font = self . _fontd_instance .get (key )
221242
222243 if font is None :
223244 fname = findfont (prop )
224- font = RendererAgg . _fontd .get (fname )
245+ font = self . _fontd_instance .get (fname )
225246 if font is None :
226247 font = FT2Font (str (fname ))
227- RendererAgg . _fontd [fname ] = font
248+ self . _fontd_instance [fname ] = font
228249
229- RendererAgg . _fontd [key ] = font
250+ self . _fontd_instance [key ] = font
230251
231252 font .clear ()
232253 size = prop .get_size_in_points ()
@@ -361,6 +382,7 @@ def post_processing(image, dpi):
361382 image )
362383
363384
385+
364386def new_figure_manager (num , * args , ** kwargs ):
365387 """
366388 Create a new figure manager instance
@@ -401,7 +423,9 @@ def draw(self):
401423 if __debug__ : verbose .report ('FigureCanvasAgg.draw' , 'debug-annoying' )
402424
403425 self .renderer = self .get_renderer ()
426+ self .renderer .pre_draw_hook ()
404427 self .figure .draw (self .renderer )
428+ self .renderer .post_draw_hook ()
405429
406430 def get_renderer (self ):
407431 l , b , w , h = self .figure .bbox .bounds
0 commit comments