diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 45e51f53984d..3a8c13b1403d 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -2035,6 +2035,7 @@ def __init__(self): p.non_math = Forward() p.operatorname = Forward() p.overline = Forward() + p.overset = Forward() p.placeable = Forward() p.rbrace = Forward() p.rbracket = Forward() @@ -2053,6 +2054,7 @@ def __init__(self): p.symbol = Forward() p.symbol_name = Forward() p.token = Forward() + p.underset = Forward() p.unknown_symbol = Forward() # Set names on everything -- very useful for debugging @@ -2169,6 +2171,18 @@ def __init__(self): - (p.required_group | Error("Expected \\overline{value}")) ) + p.overset <<= Group( + Suppress(Literal(r"\overset")) + - ((p.simple_group + p.simple_group) + | Error("Expected \\overset{body}{annotation}")) + ) + + p.underset <<= Group( + Suppress(Literal(r"\underset")) + - ((p.simple_group + p.simple_group) + | Error("Expected \\underset{body}{annotation}")) + ) + p.unknown_symbol <<= Combine(p.bslash + Regex("[A-Za-z]*")) p.operatorname <<= Group( @@ -2190,6 +2204,8 @@ def __init__(self): | p.dfrac | p.binom | p.genfrac + | p.overset + | p.underset | p.sqrt | p.overline | p.operatorname @@ -2842,6 +2858,38 @@ def binom(self, s, loc, toks): return self._genfrac('(', ')', 0.0, self._MathStyle.TEXTSTYLE, num, den) + def _genset(self, state, body, annotation, overunder): + thickness = state.font_output.get_underline_thickness( + state.font, state.fontsize, state.dpi) + + body.shrink() + + cbody = HCentered([body]) + cannotation = HCentered([annotation]) + width = max(cbody.width, cannotation.width) + cbody.hpack(width, 'exactly') + cannotation.hpack(width, 'exactly') + + vgap = thickness * 3 + if overunder == "under": + vlist = Vlist([cannotation, # annotation + Vbox(0, vgap), # space + cbody # body + ]) + # Shift so the annotation sits in the same vertical position + shift_amount = cannotation.depth + cbody.height + vgap + + vlist.shift_amount = shift_amount + else: + vlist = Vlist([cbody, # body + Vbox(0, vgap), # space + cannotation # annotation + ]) + + # To add horizontal gap between symbols: wrap the Vlist into + # an Hlist and extend it with an Hbox(0, horizontal_gap) + return vlist + def sqrt(self, s, loc, toks): (root, body), = toks state = self.get_state() @@ -2902,6 +2950,24 @@ def overline(self, s, loc, toks): hlist = Hlist([rightside]) return [hlist] + def overset(self, s, loc, toks): + assert len(toks) == 1 + assert len(toks[0]) == 2 + + state = self.get_state() + body, annotation = toks[0] + + return self._genset(state, body, annotation, overunder="over") + + def underset(self, s, loc, toks): + assert len(toks) == 1 + assert len(toks[0]) == 2 + + state = self.get_state() + body, annotation = toks[0] + + return self._genset(state, body, annotation, overunder="under") + def _auto_sized_delimiter(self, front, middle, back): state = self.get_state() if len(middle): diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png new file mode 100644 index 000000000000..f303fe49e281 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png differ diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 9bd6ca7366dc..16ac7c7bacbd 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -115,6 +115,7 @@ # images. lightweight_math_tests = [ r'$\sqrt[ab]{123}$', # github issue #8665 + r'$x \overset{f}{\rightarrow} \overset{f}{x} \underset{xx}{ff} \overset{xx}{ff} \underset{f}{x} \underset{f}{\leftarrow} x$', # github issue #18241 ] digits = "0123456789" @@ -246,6 +247,8 @@ def test_fontinfo(): (r'$\left($', r'Expected "\right"'), (r'$\dfrac$', r'Expected \dfrac{num}{den}'), (r'$\dfrac{}{}$', r'Expected \dfrac{num}{den}'), + (r'$\overset$', r'Expected \overset{body}{annotation}'), + (r'$\underset$', r'Expected \underset{body}{annotation}'), ], ids=[ 'hspace without value', @@ -266,6 +269,8 @@ def test_fontinfo(): 'unclosed parentheses without sizing', 'dfrac without parameters', 'dfrac with empty parameters', + 'overset without parameters', + 'underset without parameters', ] ) def test_mathtext_exceptions(math, msg): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy