diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 79f8e1a1d3b5..938475c8d6c5 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -220,7 +220,7 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi): if bunch is not None: return bunch - font, num, slanted = self._get_glyph( + font, num, slanted, substituted_glyph = self._get_glyph( fontname, font_class, sym, fontsize) font.set_size(fontsize, dpi) @@ -239,7 +239,8 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi): ymax = ymax+offset, # iceberg is the equivalent of TeX's "height" iceberg = glyph.horiBearingY/64.0 + offset, - slanted = slanted + slanted = slanted, + substituted_glyph = substituted_glyph ) result = self.glyphd[key] = types.SimpleNamespace( @@ -323,7 +324,7 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): if font is not None: num = ord(sym) if font is not None and font.get_char_index(num) != 0: - return font, num, slanted + return font, num, slanted, False else: return self._stix_fallback._get_glyph( fontname, font_class, sym, fontsize) @@ -448,6 +449,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): found_symbol = False _log.warning("No TeX to Unicode mapping for {!a}.".format(sym)) + substituted_glyph = False + fontname, uniindex = self._map_virtual_font( fontname, font_class, uniindex) @@ -499,8 +502,9 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): font = self._get_font('rm') uniindex = 0xA4 # currency char, for lack of anything better slanted = False + substituted_glyph = True - return font, uniindex, slanted + return font, uniindex, slanted, substituted_glyph def get_sized_alternatives_for_symbol(self, fontname, sym): if self._fallback_font: @@ -935,6 +939,9 @@ def _update_metrics(self): def is_slanted(self): return self._metrics.slanted + def is_substituted(self): + return self._metrics.substituted_glyph + def get_kerning(self, next): """ Return the amount of kerning between this and the given character. @@ -2011,7 +2018,7 @@ def unknown_symbol(self, s, loc, toks): raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}") _accent_map = { - r'hat': r'\circumflexaccent', + r'hat': r'\combiningcircumflexaccent', r'breve': r'\combiningbreve', r'bar': r'\combiningoverline', r'grave': r'\combininggraveaccent', @@ -2027,10 +2034,13 @@ def unknown_symbol(self, s, loc, toks): r"'": r'\combiningacuteaccent', r'~': r'\combiningtilde', r'.': r'\combiningdotabove', - r'^': r'\circumflexaccent', - r'overrightarrow': r'\rightarrow', - r'overleftarrow': r'\leftarrow', - r'mathring': r'\circ', + r'^': r'\combiningcircumflexaccent', + r'overrightarrow': r'\combiningrightarrowabove', + r'overleftarrow': r'\combiningleftarrowabove', + r'mathring': r'\combiningringabove', + r'=': r'\combiningmacron', + r'H': r'\combiningdoubleacuteaccent', + r'check': r'\combiningcaron', } _wide_accents = set(r"widehat widetilde widebar".split()) @@ -2050,10 +2060,27 @@ def accent(self, s, loc, toks): accent_box = AutoWidthChar( '\\' + accent, sym.width, state, char_class=Accent) else: + # Check if accent and character can be combined + a = get_unicode_index(self._accent_map[accent]) + if isinstance(sym, Char): + c = sym.c + else: + c = sym.children[0].c + if c == chr(305): # Dotless i, but normal i combines + c = 'i' + comb = unicodedata.normalize('NFC', c + chr(a)) + if len(comb) == 1: # Check that they did combine + newsym = Char(comb, state) + # Check that glyph exists + if not newsym.is_substituted(): + return newsym + if c == 'i': # Turn i into dotless i + sym = Char(chr(305), state) + if sym.is_substituted(): + # Dotless i does not exist + sym = Char('i', state) + # Cannot be combined accent_box = Accent(self._accent_map[accent], state) - if accent == 'mathring': - accent_box.shrink() - accent_box.shrink() centered = HCentered([Hbox(sym.width / 4.0), accent_box]) centered.hpack(sym.width, 'exactly') return Vlist([ @@ -2137,9 +2164,6 @@ def is_slanted(self, nucleus): return nucleus.is_slanted() return False - def is_between_brackets(self, s, loc): - return False - def subsuper(self, s, loc, toks): nucleus = toks.get("nucleus", Hbox(0)) subsuper = toks.get("subsuper", []) diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index 8dac9301ed81..3df66edbf6fe 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -117,13 +117,18 @@ '\\Upsilon' : ('cmr10', 0xa8), '\\Xi' : ('cmr10', 0xa5), '\\circumflexaccent' : ('cmr10', 0x5e), + '\\combiningcircumflexaccent' : ('cmr10', 0x5e), '\\combiningacuteaccent' : ('cmr10', 0xb6), '\\combiningbreve' : ('cmr10', 0xb8), '\\combiningdiaeresis' : ('cmr10', 0xc4), '\\combiningdotabove' : ('cmr10', 0x5f), '\\combininggraveaccent' : ('cmr10', 0xb5), '\\combiningoverline' : ('cmr10', 0xb9), + '\\combiningmacron' : ('cmr10', 0x16), + '\\combiningringabove' : ('cmr10', 0x15), + '\\combiningcaron' : ('cmr10', 0x14), '\\combiningtilde' : ('cmr10', 0x7e), + '\\combiningdoubleacuteaccent' : ('cmr10', 0x7d), '\\leftbracket' : ('cmr10', 0x5b), '\\leftparen' : ('cmr10', 0x28), '\\rightbracket' : ('cmr10', 0x5d), @@ -994,14 +999,20 @@ 'circumflexaccent' : 770, 'combiningbreve' : 774, 'combiningoverline' : 772, + 'combiningmacron' : 773, 'combininggraveaccent' : 768, 'combiningacuteaccent' : 769, 'combiningdiaeresis' : 776, 'combiningtilde' : 771, 'combiningrightarrowabove' : 8407, + 'combiningleftarrowabove' : 8406, 'combiningdotabove' : 775, + 'combiningringabove' : 778, 'combiningthreedotsabove' : 8411, 'combiningfourdotsabove' : 8412, + 'combiningdoubleacuteaccent' : 779, + 'combiningcaron' : 780, + 'combiningcircumflexaccent' : 770, 'to' : 8594, 'succeq' : 8829, 'emptyset' : 8709, diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf new file mode 100644 index 000000000000..79a90506a70e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png new file mode 100644 index 000000000000..53c60279aa17 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg new file mode 100644 index 000000000000..5ee071517f59 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg @@ -0,0 +1,770 @@ + + + + + + + + 2022-06-12T18:25:44.401062 + image/svg+xml + + + Matplotlib v3.6.0.dev2709+ge671b41e95.d20220612, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf new file mode 100644 index 000000000000..fa0df1d359cb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png new file mode 100644 index 000000000000..054ff4f0ee1f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg new file mode 100644 index 000000000000..8156a604bb21 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg @@ -0,0 +1,617 @@ + + + + + + + + 2022-06-12T18:26:20.653928 + image/svg+xml + + + Matplotlib v3.6.0.dev2709+ge671b41e95.d20220612, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf new file mode 100644 index 000000000000..5e8a4d53f20b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png new file mode 100644 index 000000000000..ea0868cae9a3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg new file mode 100644 index 000000000000..fec22d7c4a04 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg @@ -0,0 +1,662 @@ + + + + + + + + 2022-06-12T18:26:31.423625 + image/svg+xml + + + Matplotlib v3.6.0.dev2709+ge671b41e95.d20220612, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf new file mode 100644 index 000000000000..7e84ff37aae7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png new file mode 100644 index 000000000000..df0746cc3e9e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg new file mode 100644 index 000000000000..164417504719 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg @@ -0,0 +1,674 @@ + + + + + + + + 2022-06-12T18:25:57.513744 + image/svg+xml + + + Matplotlib v3.6.0.dev2709+ge671b41e95.d20220612, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf new file mode 100644 index 000000000000..a50c8060a4ed Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png new file mode 100644 index 000000000000..e2fcb2eafd65 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg new file mode 100644 index 000000000000..a412d8918b40 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg @@ -0,0 +1,615 @@ + + + + + + + + 2022-06-12T18:26:10.638169 + image/svg+xml + + + Matplotlib v3.6.0.dev2709+ge671b41e95.d20220612, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 9d4b00bb5126..194a238668d9 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -115,6 +115,9 @@ r'$,$ $.$ $1{,}234{, }567{ , }890$ and $1,234,567,890$', # github issue 5799 r'$\left(X\right)_{a}^{b}$', # github issue 7615 r'$\dfrac{\$100.00}{y}$', # github issue #1888 + r'$\={M}\H{a}\check{t}\hat{p}\overleftarrow{l}\overrightarrow{o}\"{t}' + r'\.{l}\mathring{i}\~{b}$ $\breve{M}\bar{a}\grave{t}\acute{p}\vec{l}' + r'\dddot{o}\ddddot{t}\^{l}\ddot{i}\overline{b}$' ] # 'svgastext' tests switch svg output to embed text as text (rather than as # paths). diff --git a/tutorials/text/mathtext.py b/tutorials/text/mathtext.py index 9e9abfc52344..19119477e802 100644 --- a/tutorials/text/mathtext.py +++ b/tutorials/text/mathtext.py @@ -306,7 +306,7 @@ Command Result ============================== ================================= ``\acute a`` or ``\'a`` :mathmpl:`\acute a` - ``\bar a`` :mathmpl:`\bar a` + ``\bar a`` or ``\= a`` :mathmpl:`\bar a` ``\breve a`` :mathmpl:`\breve a` ``\dot a`` or ``\.a`` :mathmpl:`\dot a` ``\ddot a`` or ``\''a`` :mathmpl:`\ddot a` @@ -316,6 +316,8 @@ ``\hat a`` or ``\^a`` :mathmpl:`\hat a` ``\tilde a`` or ``\~a`` :mathmpl:`\tilde a` ``\vec a`` :mathmpl:`\vec a` + ``\check a`` :mathmpl:`\check a` + ``\H a`` :mathmpl:`\H a` ``\overline{abc}`` :mathmpl:`\overline{abc}` ============================== =================================