Skip to content

Commit cc628ce

Browse files
committed
slurp down a class level cache into the instance level at the start of draw, and push it back up when done
1 parent aa4bb8a commit cc628ce

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

lib/matplotlib/backends/backend_agg.py

+30-6
Original file line numberDiff line numberDiff line change
@@ -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+
364386
def 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

Comments
 (0)