@@ -122,8 +122,11 @@ def writeln(fh, line):
122
122
fh .write ("%\n " )
123
123
124
124
125
- def _font_properties_str (prop ):
126
- # translate font properties to latex commands, return as string
125
+ def _escape_and_apply_props (s , prop ):
126
+ """
127
+ Generate a TeX string that renders string *s* with font properties *prop*,
128
+ also applying any required escapes to *s*.
129
+ """
127
130
commands = []
128
131
129
132
families = {"serif" : r"\rmfamily" , "sans" : r"\sffamily" ,
@@ -149,7 +152,7 @@ def _font_properties_str(prop):
149
152
commands .append (r"\bfseries" )
150
153
151
154
commands .append (r"\selectfont" )
152
- return "" .join (commands )
155
+ return "" .join (commands ) + " " + common_texification ( s )
153
156
154
157
155
158
def _metadata_to_str (key , value ):
@@ -296,7 +299,10 @@ def __init__(self):
296
299
"or error in preamble." , stdout )
297
300
298
301
self .latex = None # Will be set up on first use.
299
- self .str_cache = {} # cache for strings already processed
302
+ # Per-instance cache.
303
+ self ._get_box_metrics = functools .lru_cache ()(self ._get_box_metrics )
304
+
305
+ str_cache = _api .deprecated ("3.5" )(property (lambda self : {}))
300
306
301
307
def _setup_latex_process (self ):
302
308
# Open LaTeX process for real work; register it for deletion. On
@@ -322,46 +328,34 @@ def finalize_latex(latex):
322
328
323
329
def get_width_height_descent (self , text , prop ):
324
330
"""
325
- Get the width, total height and descent for a text typeset by the
326
- current LaTeX environment.
331
+ Get the width, total height, and descent (in TeX points) for a text
332
+ typeset by the current LaTeX environment.
327
333
"""
334
+ return self ._get_box_metrics (_escape_and_apply_props (text , prop ))
328
335
329
- # apply font properties and define textbox
330
- prop_cmds = _font_properties_str (prop )
331
- textbox = "\\ sbox0{%s %s}" % (prop_cmds , text )
332
-
333
- # check cache
334
- if textbox in self .str_cache :
335
- return self .str_cache [textbox ]
336
-
337
- # send textbox to LaTeX and wait for prompt
338
- self ._stdin_writeln (textbox )
339
- try :
340
- self ._expect_prompt ()
341
- except LatexError as e :
342
- raise ValueError ("Error processing '{}'\n LaTeX Output:\n {}"
343
- .format (text , e .latex_output )) from e
344
-
345
- # typeout width, height and text offset of the last textbox
346
- self ._stdin_writeln (r"\typeout{\the\wd0,\the\ht0,\the\dp0}" )
347
- # read answer from latex and advance to the next prompt
336
+ def _get_box_metrics (self , tex ):
337
+ """
338
+ Get the width, total height and descent (in TeX points) for a TeX
339
+ command's output in the current LaTeX environment.
340
+ """
341
+ # This method gets wrapped in __init__ for per-instance caching.
342
+ self ._stdin_writeln ( # Send textbox to TeX & request metrics typeout.
343
+ r"\sbox0{%s}\typeout{\the\wd0,\the\ht0,\the\dp0}" % tex )
348
344
try :
349
345
answer = self ._expect_prompt ()
350
- except LatexError as e :
351
- raise ValueError ("Error processing '{}'\n LaTeX Output:\n {}"
352
- .format (text , e .latex_output )) from e
353
-
354
- # parse metrics from the answer string
346
+ except LatexError as err :
347
+ raise ValueError ("Error measuring {!r}\n LaTeX Output:\n {}"
348
+ .format (tex , err .latex_output )) from err
355
349
try :
356
- width , height , offset = answer .splitlines ()[0 ].split ("," )
350
+ # Parse metrics from the answer string. Last line is prompt, and
351
+ # next-to-last-line is blank line from \typeout.
352
+ width , height , offset = answer .splitlines ()[- 3 ].split ("," )
357
353
except Exception as err :
358
- raise ValueError ("Error processing '{}' \n LaTeX Output:\n {}"
359
- .format (text , answer )) from err
354
+ raise ValueError ("Error measuring {!r} \n LaTeX Output:\n {}"
355
+ .format (tex , answer )) from err
360
356
w , h , o = float (width [:- 2 ]), float (height [:- 2 ]), float (offset [:- 2 ])
361
-
362
- # the height returned from LaTeX goes from base to top.
363
- # the height matplotlib expects goes from bottom to top.
364
- self .str_cache [textbox ] = (w , h + o , o )
357
+ # The height returned from LaTeX goes from base to top;
358
+ # the height Matplotlib expects goes from bottom to top.
365
359
return w , h + o , o
366
360
367
361
@@ -671,9 +665,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
671
665
# docstring inherited
672
666
673
667
# prepare string for tex
674
- s = common_texification (s )
675
- prop_cmds = _font_properties_str (prop )
676
- s = r"%s %s" % (prop_cmds , s )
668
+ s = _escape_and_apply_props (s , prop )
677
669
678
670
writeln (self .fh , r"\begin{pgfscope}" )
679
671
@@ -718,10 +710,6 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
718
710
719
711
def get_text_width_height_descent (self , s , prop , ismath ):
720
712
# docstring inherited
721
-
722
- # check if the math is supposed to be displaystyled
723
- s = common_texification (s )
724
-
725
713
# get text metrics in units of latex pt, convert to display units
726
714
w , h , d = (LatexManager ._get_cached_or_new ()
727
715
.get_width_height_descent (s , prop ))
0 commit comments