| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff 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. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -602,6 +602,7 @@ def gen_candidates(): | |||
| 602 | 602 | _deprecated_remain_as_none = { | |
| 603 | 603 | 'animation.avconv_path': ('3.3',), | |
| 604 | 604 | 'animation.avconv_args': ('3.3',), | |
| 605 | + 'mathtext.fallback_to_cm': ('3.3',), | ||
| 605 | 606 | 'keymap.all_axes': ('3.3',), | |
| 606 | 607 | } | |
| 607 | 608 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -769,10 +769,17 @@ class UnicodeFonts(TruetypeFonts): | |||
| 769 | 769 | ||
| 770 | 770 | def __init__(self, *args, **kwargs): | |
| 771 | 771 | # This must come first so the backend's owner is set correctly | |
| 772 | - if rcParams['mathtext.fallback_to_cm']: | ||
| 773 | - self.cm_fallback = BakomaFonts(*args, **kwargs) | ||
| 774 | - else: | ||
| 775 | - self.cm_fallback = None | ||
| 772 | + fallback_rc = rcParams['mathtext.fallback'] | ||
| 773 | + if rcParams['mathtext.fallback_to_cm'] is not None: | ||
| 774 | + fallback_rc = ('cm' if rcParams['mathtext.fallback_to_cm'] | ||
| 775 | + else None) | ||
| 776 | + | ||
| 777 | + font_class = {'stix': StixFonts, | ||
| 778 | + 'stixsans': StixSansFonts, | ||
| 779 | + 'cm': BakomaFonts | ||
| 780 | + }.get(fallback_rc) | ||
| 781 | + self.cm_fallback = font_class(*args, **kwargs) if font_class else None | ||
| 782 | + | ||
| 776 | 783 | TruetypeFonts.__init__(self, *args, **kwargs) | |
| 777 | 784 | self.fontmap = {} | |
| 778 | 785 | for texfont in "cal rm tt it bf sf".split(): | |
@@ -783,6 +790,21 @@ def __init__(self, *args, **kwargs): | |||
| 783 | 790 | font = findfont(prop) | |
| 784 | 791 | self.fontmap['ex'] = font | |
| 785 | 792 | ||
| 793 | + # include STIX sized alternatives for glyphs if fallback is STIX | ||
| 794 | + if isinstance(self.cm_fallback, StixFonts): | ||
| 795 | + stixsizedaltfonts = { | ||
| 796 | + 0: 'STIXGeneral', | ||
| 797 | + 1: 'STIXSizeOneSym', | ||
| 798 | + 2: 'STIXSizeTwoSym', | ||
| 799 | + 3: 'STIXSizeThreeSym', | ||
| 800 | + 4: 'STIXSizeFourSym', | ||
| 801 | + 5: 'STIXSizeFiveSym'} | ||
| 802 | + | ||
| 803 | + for size, name in stixsizedaltfonts.items(): | ||
| 804 | + fullpath = findfont(name) | ||
| 805 | + self.fontmap[size] = fullpath | ||
| 806 | + self.fontmap[name] = fullpath | ||
| 807 | + | ||
| 786 | 808 | _slanted_symbols = set(r"\int \oint".split()) | |
| 787 | 809 | ||
| 788 | 810 | def _map_virtual_font(self, fontname, font_class, uniindex): | |
@@ -830,16 +852,19 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): | |||
| 830 | 852 | ||
| 831 | 853 | if not found_symbol: | |
| 832 | 854 | 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) | ||
| 855 | + if (fontname in ('it', 'regular') | ||
| 856 | + and isinstance(self.cm_fallback, StixFonts)): | ||
| 857 | + fontname = 'rm' | ||
| 858 | + | ||
| 859 | + g = self.cm_fallback._get_glyph(fontname, font_class, | ||
| 860 | + sym, fontsize) | ||
| 861 | + fname = g[0].family_name | ||
| 862 | + if fname in list(BakomaFonts._fontmap.values()): | ||
| 863 | + fname = "Computer Modern" | ||
| 864 | + _log.warning("Substituting symbol {} " | ||
| 865 | + "from {}".format(sym, fname)) | ||
| 866 | + return g | ||
| 867 | + | ||
| 843 | 868 | else: | |
| 844 | 869 | if (fontname in ('it', 'regular') | |
| 845 | 870 | and isinstance(self, StixFonts)): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -154,9 +154,10 @@ mathtext.bf : serif:bold | |||
| 154 | 154 | mathtext.sf : sans\-serif | |
| 155 | 155 | mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix', | |
| 156 | 156 | # '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. | ||
| 160 | 161 | ||
| 161 | 162 | mathtext.default : it # The default font to use for math. | |
| 162 | 163 | # Can be any of the LaTeX font names, including | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -419,6 +419,37 @@ def validate_font_properties(s): | |||
| 419 | 419 | return s | |
| 420 | 420 | ||
| 421 | 421 | ||
| 422 | + def _validate_mathtext_fallback_to_cm(b): | ||
| 423 | + """ | ||
| 424 | + Temporary validate for fallback_to_cm, while deprecated | ||
| 425 | + | ||
| 426 | + """ | ||
| 427 | + if isinstance(b, str): | ||
| 428 | + b = b.lower() | ||
| 429 | + if b is None or b == 'none': | ||
| 430 | + return None | ||
| 431 | + else: | ||
| 432 | + cbook.warn_deprecated( | ||
| 433 | + "3.3", message="Support for setting the 'mathtext.fallback_to_cm' rcParam " | ||
| 434 | + "is deprecated since %(since)s and will be removed " | ||
| 435 | + "%(removal)s; use 'mathtext.fallback : 'cm' instead.") | ||
| 436 | + return validate_bool_maybe_none(b) | ||
| 437 | + | ||
| 438 | + | ||
| 439 | + def _validate_mathtext_fallback(s): | ||
| 440 | + _fallback_fonts = ['cm', 'stix', 'stixsans'] | ||
| 441 | + if isinstance(s, str): | ||
| 442 | + s = s.lower() | ||
| 443 | + if s is None or s == 'none': | ||
| 444 | + return None | ||
| 445 | + elif s.lower() in _fallback_fonts: | ||
| 446 | + return s | ||
| 447 | + else: | ||
| 448 | + raise ValueError(f"{s} is not a valid fallback font name. Valid fallback " | ||
| 449 | + f"font names are {','.join(_fallback_fonts)}. Passing " | ||
| 450 | + f"'None' will turn fallback off.") | ||
| 451 | + | ||
| 452 | + | ||
| 422 | 453 | validate_fontset = ValidateInStrings( | |
| 423 | 454 | 'fontset', | |
| 424 | 455 | ['dejavusans', 'dejavuserif', 'cm', 'stix', 'stixsans', 'custom'], | |
@@ -1156,7 +1187,8 @@ def _convert_validator_spec(key, conv): | |||
| 1156 | 1187 | 'mathtext.default': [ | |
| 1157 | 1188 | 'it', | |
| 1158 | 1189 | ['rm', 'cal', 'it', 'tt', 'sf', 'bf', 'default', 'bb', 'frak', 'scr', 'regular']], | |
| 1159 | - 'mathtext.fallback_to_cm': [True, validate_bool], | ||
| 1190 | + 'mathtext.fallback_to_cm': [None, _validate_mathtext_fallback_to_cm], | ||
| 1191 | + 'mathtext.fallback': ['cm', _validate_mathtext_fallback], | ||
| 1160 | 1192 | ||
| 1161 | 1193 | 'image.aspect': ['equal', validate_aspect], # equal, auto, a number | |
| 1162 | 1194 | 'image.interpolation': ['antialiased', validate_string], | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,5 @@ | |||
| 1 | 1 | import io | |
| 2 | + import os | ||
| 2 | 3 | import re | |
| 3 | 4 | ||
| 4 | 5 | import numpy as np | |
@@ -283,3 +284,48 @@ def test_single_minus_sign(): | |||
| 283 | 284 | def test_spaces(fig_test, fig_ref): | |
| 284 | 285 | fig_test.subplots().set_title(r"$1\,2\>3\ 4$") | |
| 285 | 286 | 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] | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -329,9 +329,10 @@ | |||
| 329 | 329 | #mathtext.rm: sans | |
| 330 | 330 | #mathtext.sf: sans | |
| 331 | 331 | #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. | ||
| 335 | 336 | #mathtext.default: it # The default font to use for math. | |
| 336 | 337 | # Can be any of the LaTeX font names, including | |
| 337 | 338 | # the special name "regular" for the same font | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -296,8 +296,9 @@ | |||
| 296 | 296 | The fonts used should have a Unicode mapping in order to find any | |
| 297 | 297 | non-Latin characters, such as Greek. If you want to use a math symbol | |
| 298 | 298 | 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 | ||
| 301 | 302 | character can not be found in the custom font. | |
| 302 | 303 | ||
| 303 | 304 | Note that the math glyphs specified in Unicode have evolved over time, and many | |
| Back | FazBrowse Home | New Git URL |
0 commit comments