Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a5b8b42

Browse files
committed
feat: mathtext.fallback replaces fallback_to_cm with options 'cm', 'stix', 'stixsans'
1 parent ad877a0 commit a5b8b42

File tree

8 files changed

+136
-20
lines changed

8 files changed

+136
-20
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Add generalized "mathtext.fallback" rcParam
2+
------------------------------------------------------------------------
3+
New "mathtext.fallback" rcParam. Takes "cm", "stix", "stixsans"
4+
or "none" to turn fallback off. "mathtext.fallback_to_cm" is
5+
deprecated, but if used, will override new fallback.

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ def gen_candidates():
602602
_deprecated_remain_as_none = {
603603
'animation.avconv_path': ('3.3',),
604604
'animation.avconv_args': ('3.3',),
605+
'mathtext.fallback_to_cm': ('3.3',),
605606
'keymap.all_axes': ('3.3',),
606607
}
607608

lib/matplotlib/mathtext.py

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,18 @@ class UnicodeFonts(TruetypeFonts):
769769

770770
def __init__(self, *args, **kwargs):
771771
# This must come first so the backend's owner is set correctly
772-
if rcParams['mathtext.fallback_to_cm']:
772+
fallback_rc = rcParams['mathtext.fallback']
773+
if rcParams['mathtext.fallback_to_cm'] is not None:
774+
if rcParams['mathtext.fallback_to_cm']:
775+
fallback_rc = 'cm'
776+
else:
777+
fallback_rc = None
778+
779+
if fallback_rc == 'stix':
780+
self.cm_fallback = StixFonts(*args, **kwargs)
781+
elif fallback_rc == 'stixsans':
782+
self.cm_fallback = StixSansFonts(*args, **kwargs)
783+
elif fallback_rc == 'cm':
773784
self.cm_fallback = BakomaFonts(*args, **kwargs)
774785
else:
775786
self.cm_fallback = None
@@ -783,6 +794,21 @@ def __init__(self, *args, **kwargs):
783794
font = findfont(prop)
784795
self.fontmap['ex'] = font
785796

797+
# include STIX sized alternatives for glyphs if fallback is STIX
798+
if isinstance(self.cm_fallback, StixFonts):
799+
stixsizedaltfonts = {
800+
0: 'STIXGeneral',
801+
1: 'STIXSizeOneSym',
802+
2: 'STIXSizeTwoSym',
803+
3: 'STIXSizeThreeSym',
804+
4: 'STIXSizeFourSym',
805+
5: 'STIXSizeFiveSym'}
806+
807+
for size, name in stixsizedaltfonts.items():
808+
fullpath = findfont(name)
809+
self.fontmap[size] = fullpath
810+
self.fontmap[name] = fullpath
811+
786812
_slanted_symbols = set(r"\int \oint".split())
787813

788814
def _map_virtual_font(self, fontname, font_class, uniindex):
@@ -830,16 +856,19 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True):
830856

831857
if not found_symbol:
832858
if self.cm_fallback:
833-
if isinstance(self.cm_fallback, BakomaFonts):
834-
_log.warning(
835-
"Substituting with a symbol from Computer Modern.")
836-
if (fontname in ('it', 'regular') and
837-
isinstance(self.cm_fallback, StixFonts)):
838-
return self.cm_fallback._get_glyph(
839-
'rm', font_class, sym, fontsize)
840-
else:
841-
return self.cm_fallback._get_glyph(
842-
fontname, font_class, sym, fontsize)
859+
if (fontname in ('it', 'regular')
860+
and isinstance(self.cm_fallback, StixFonts)):
861+
fontname = 'rm'
862+
863+
g = self.cm_fallback._get_glyph(fontname, font_class,
864+
sym, fontsize)
865+
fname = g[0].family_name
866+
if fname in list(BakomaFonts._fontmap.values()):
867+
fname = "Computer Modern"
868+
_log.warning("Substituting symbol {} "
869+
"from {}".format(sym, fname))
870+
return g
871+
843872
else:
844873
if (fontname in ('it', 'regular')
845874
and isinstance(self, StixFonts)):

lib/matplotlib/mpl-data/stylelib/classic.mplstyle

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@ mathtext.bf : serif:bold
154154
mathtext.sf : sans\-serif
155155
mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix',
156156
# 'stixsans' or 'custom'
157-
mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
158-
# fonts when a symbol can not be found in one of
159-
# the custom math fonts.
157+
mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix'
158+
# 'stixsans'] when a symbol can not be found in one of the
159+
# custom math fonts. Select 'None' to not perform fallback
160+
# and replace the missing character by a dummy.
160161

161162
mathtext.default : it # The default font to use for math.
162163
# Can be any of the LaTeX font names, including

lib/matplotlib/rcsetup.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,37 @@ def validate_font_properties(s):
413413
return s
414414

415415

416+
def _validate_mathtext_fallback_to_cm(b):
417+
"""
418+
Temporary validate for fallback_to_cm, while deprecated
419+
420+
"""
421+
if isinstance(b, str):
422+
b = b.lower()
423+
if b is None or b == 'none':
424+
return None
425+
else:
426+
cbook.warn_deprecated(
427+
"3.3", message="Support for setting the 'mathtext.fallback_to_cm' rcParam "
428+
"is deprecated since %(since)s and will be removed "
429+
"%(removal)s; use 'mathtext.fallback : 'cm' instead.")
430+
return validate_bool_maybe_none(b)
431+
432+
433+
def _validate_mathtext_fallback(s):
434+
_fallback_fonts = ['cm', 'stix', 'stixsans']
435+
if isinstance(s, str):
436+
s = s.lower()
437+
if s is None or s == 'none':
438+
return None
439+
elif s.lower() in _fallback_fonts:
440+
return s
441+
else:
442+
raise ValueError("{} is not a valid fallback font name. Valid fallback "
443+
"font names are {}. Passing 'None' will turn fallback "
444+
"off.".format(s, ", ".join(_fallback_fonts)))
445+
446+
416447
validate_fontset = ValidateInStrings(
417448
'fontset',
418449
['dejavusans', 'dejavuserif', 'cm', 'stix', 'stixsans', 'custom'],
@@ -1150,7 +1181,8 @@ def _convert_validator_spec(key, conv):
11501181
'mathtext.default': [
11511182
'it',
11521183
['rm', 'cal', 'it', 'tt', 'sf', 'bf', 'default', 'bb', 'frak', 'scr', 'regular']],
1153-
'mathtext.fallback_to_cm': [True, validate_bool],
1184+
'mathtext.fallback_to_cm': [None, _validate_mathtext_fallback_to_cm],
1185+
'mathtext.fallback': ['cm', _validate_mathtext_fallback],
11541186

11551187
'image.aspect': ['equal', validate_aspect], # equal, auto, a number
11561188
'image.interpolation': ['antialiased', validate_string],

lib/matplotlib/tests/test_mathtext.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io
2+
import os
23
import re
34

45
import numpy as np
@@ -283,3 +284,48 @@ def test_single_minus_sign():
283284
def test_spaces(fig_test, fig_ref):
284285
fig_test.subplots().set_title(r"$1\,2\>3\ 4$")
285286
fig_ref.subplots().set_title(r"$1\/2\:3~4$")
287+
288+
289+
def test_mathtext_fallback_valid():
290+
for fallback in ['cm', 'stix', 'stixsans', 'None']:
291+
mpl.rcParams['mathtext.fallback'] = fallback
292+
293+
294+
@pytest.mark.xfail
295+
def test_mathtext_fallback_invalid():
296+
for fallback in ['abc', '']:
297+
mpl.rcParams['mathtext.fallback'] = fallback
298+
299+
300+
@pytest.mark.xfail
301+
def test_mathtext_fallback_to_cm_invalid():
302+
for fallback in [True, False]:
303+
mpl.rcParams['mathtext.fallback_to_cm'] = fallback
304+
305+
306+
@pytest.mark.parametrize(
307+
"fallback,fontlist",
308+
[("cm", ['DejaVu Sans', 'mpltest', 'STIXGeneral', 'cmr10', 'STIXGeneral']),
309+
("stix", ['DejaVu Sans', 'mpltest', 'STIXGeneral'])])
310+
def test_mathtext_fallback(fallback, fontlist):
311+
mpl.font_manager.fontManager.addfont(
312+
os.path.join((os.path.dirname(os.path.realpath(__file__))), 'mpltest.ttf'))
313+
mpl.rcParams["svg.fonttype"] = 'none'
314+
mpl.rcParams['mathtext.fontset'] = 'custom'
315+
mpl.rcParams['mathtext.rm'] = 'mpltest'
316+
mpl.rcParams['mathtext.it'] = 'mpltest:italic'
317+
mpl.rcParams['mathtext.bf'] = 'mpltest:bold'
318+
mpl.rcParams['mathtext.fallback'] = fallback
319+
320+
test_str = r'a$A\AA\breve\gimel$'
321+
322+
buff = io.BytesIO()
323+
fig, ax = plt.subplots()
324+
fig.text(.5, .5, test_str, fontsize=40, ha='center')
325+
fig.savefig(buff, format="svg")
326+
char_fonts = [
327+
line.split("font-family:")[-1].split(";")[0]
328+
for line in str(buff.getvalue()).split(r"\n") if "tspan" in line
329+
]
330+
assert char_fonts == fontlist
331+
mpl.font_manager.fontManager.ttflist = mpl.font_manager.fontManager.ttflist[:-1]

matplotlibrc.template

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,10 @@
329329
#mathtext.rm: sans
330330
#mathtext.sf: sans
331331
#mathtext.tt: monospace
332-
#mathtext.fallback_to_cm: True # When True, use symbols from the Computer Modern
333-
# fonts when a symbol can not be found in one of
334-
# the custom math fonts.
332+
#mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix'
333+
# 'stixsans'] when a symbol can not be found in one of the
334+
# custom math fonts. Select 'None' to not perform fallback
335+
# and replace the missing character by a dummy symbol.
335336
#mathtext.default: it # The default font to use for math.
336337
# Can be any of the LaTeX font names, including
337338
# the special name "regular" for the same font

tutorials/text/mathtext.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,9 @@
296296
The fonts used should have a Unicode mapping in order to find any
297297
non-Latin characters, such as Greek. If you want to use a math symbol
298298
that is not contained in your custom fonts, you can set
299-
:rc:`mathtext.fallback_to_cm` to ``True`` which will cause the mathtext system
300-
to use characters from the default Computer Modern fonts whenever a particular
299+
:rc:`mathtext.fallback` to either ``'cm'``, ``'stix'`` or ``'stixsans'``
300+
which will cause the mathtext system to use
301+
characters from an alternative font whenever a particular
301302
character can not be found in the custom font.
302303
303304
Note that the math glyphs specified in Unicode have evolved over time, and many

0 commit comments

Comments
 (0)