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

Skip to content

Commit 88de239

Browse files
authored
Merge pull request #30908 from anntzer/texphantoms
mathtext support for \phantom, \llap, \rlap for faking text metrics.
2 parents 3539117 + 6c357ee commit 88de239

3 files changed

Lines changed: 59 additions & 8 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mathtext support for ``\phantom``, ``\llap``, ``\rlap``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
mathtext gained support for the TeX macros ``\phantom``, ``\llap``, and
4+
``\rlap``. ``\phantom`` allows to occupy some space on the canvas as if
5+
some text was being rendered, without actually rendering that text, whereas
6+
``\llap`` and ``\rlap`` allows to render some text on the canvas while
7+
pretending that it occupies no space. Altogether these macros allow some finer
8+
control of text alignments.
9+
10+
See https://www.tug.org/TUGboat/tb22-4/tb72perlS.pdf for a detailed description
11+
of these macros.

lib/matplotlib/_mathtext.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,7 @@ def __init__(self, elements: T.Sequence[Node], w: float = 0.0,
13261326
if do_kern:
13271327
self.kern()
13281328
self.hpack(w=w, m=m)
1329+
self.is_phantom = False
13291330

13301331
def is_char_node(self) -> bool:
13311332
# See description in Node.is_char_node.
@@ -1716,6 +1717,11 @@ def ship(box: Box, xy: tuple[float, float] = (0, 0)) -> Output:
17161717
off_v = oy + box.height
17171718
output = Output(box)
17181719

1720+
phantom: list[bool] = []
1721+
def render(node, *args):
1722+
if not any(phantom):
1723+
node.render(*args)
1724+
17191725
def clamp(value: float) -> float:
17201726
return -1e9 if value < -1e9 else +1e9 if value > +1e9 else value
17211727

@@ -1729,9 +1735,11 @@ def hlist_out(box: Hlist) -> None:
17291735
base_line = cur_v
17301736
left_edge = cur_h
17311737

1738+
phantom.append(box.is_phantom)
1739+
17321740
for p in box.children:
17331741
if isinstance(p, Char):
1734-
p.render(output, cur_h + off_h, cur_v + off_v)
1742+
render(p, output, cur_h + off_h, cur_v + off_v)
17351743
cur_h += p.width
17361744
elif isinstance(p, Kern):
17371745
cur_h += p.width
@@ -1762,9 +1770,9 @@ def hlist_out(box: Hlist) -> None:
17621770
rule_depth = box.depth
17631771
if rule_height > 0 and rule_width > 0:
17641772
cur_v = base_line + rule_depth
1765-
p.render(output,
1766-
cur_h + off_h, cur_v + off_v,
1767-
rule_width, rule_height)
1773+
render(p, output,
1774+
cur_h + off_h, cur_v + off_v,
1775+
rule_width, rule_height)
17681776
cur_v = base_line
17691777
cur_h += rule_width
17701778
elif isinstance(p, Glue):
@@ -1782,6 +1790,8 @@ def hlist_out(box: Hlist) -> None:
17821790
rule_width += cur_g
17831791
cur_h += rule_width
17841792

1793+
phantom.pop()
1794+
17851795
def vlist_out(box: Vlist) -> None:
17861796
nonlocal cur_v, cur_h
17871797

@@ -1821,9 +1831,9 @@ def vlist_out(box: Vlist) -> None:
18211831
rule_height += rule_depth
18221832
if rule_height > 0 and rule_depth > 0:
18231833
cur_v += rule_height
1824-
p.render(output,
1825-
cur_h + off_h, cur_v + off_v,
1826-
rule_width, rule_height)
1834+
render(p, output,
1835+
cur_h + off_h, cur_v + off_v,
1836+
rule_width, rule_height)
18271837
elif isinstance(p, Glue):
18281838
glue_spec = p.glue_spec
18291839
rule_height = glue_spec.width - cur_g
@@ -2159,6 +2169,10 @@ def csnames(group: str, names: Iterable[str]) -> Regex:
21592169

21602170
p.customspace = cmd(r"\hspace", "{" + p.float_literal("space") + "}")
21612171

2172+
p.phantom = cmd(r"\phantom", p.optional_group("value"))
2173+
p.llap = cmd(r"\llap", p.optional_group("value"))
2174+
p.rlap = cmd(r"\rlap", p.optional_group("value"))
2175+
21622176
p.accent = (
21632177
csnames("accent", [*self._accent_map, *self._wide_accents])
21642178
- p.named_placeable("sym"))
@@ -2225,7 +2239,8 @@ def csnames(group: str, names: Iterable[str]) -> Regex:
22252239
r"\boldsymbol", "{" + ZeroOrMore(p.simple)("value") + "}")
22262240

22272241
p.placeable <<= (
2228-
p.accent # Must be before symbol as all accents are symbols
2242+
p.phantom | p.llap | p.rlap
2243+
| p.accent # Must be before symbol as all accents are symbols
22292244
| p.symbol # Must be second to catch all named symbols and single
22302245
# chars not in a group
22312246
| p.function
@@ -2419,6 +2434,16 @@ def symbol(self, s: str, loc: int,
24192434
def unknown_symbol(self, s: str, loc: int, toks: ParseResults) -> T.Any:
24202435
raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}")
24212436

2437+
def phantom(self, toks: ParseResults) -> T.Any:
2438+
toks["value"].is_phantom = True
2439+
return toks["value"]
2440+
2441+
def llap(self, toks: ParseResults) -> T.Any:
2442+
return [Hlist([Kern(-toks["value"].width), toks["value"]])]
2443+
2444+
def rlap(self, toks: ParseResults) -> T.Any:
2445+
return [Hlist([toks["value"], Kern(-toks["value"].width)])]
2446+
24222447
_accent_map = {
24232448
r'hat': r'\circumflexaccent',
24242449
r'breve': r'\combiningbreve',

lib/matplotlib/tests/test_mathtext.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,21 @@ def test_mathnormal(fig_test, fig_ref):
578578
fig_ref.text(0.1, 0.2, r"$\mathrm{0123456789}$")
579579

580580

581+
# Test vector output because in raster output some minor differences remain,
582+
# likely due to double-striking.
583+
@check_figures_equal(extensions=["pdf"])
584+
def test_phantoms(fig_test, fig_ref):
585+
fig_test.text(0.5, 0.9, r"$\rlap{rlap}extra$", ha="left")
586+
fig_ref.text(0.5, 0.9, r"$rlap$", ha="left")
587+
fig_ref.text(0.5, 0.9, r"$extra$", ha="left")
588+
589+
fig_test.text(0.5, 0.8, r"$extra\llap{llap}$", ha="right")
590+
fig_ref.text(0.5, 0.8, r"$llap$", ha="right")
591+
fig_ref.text(0.5, 0.8, r"$extra$", ha="right")
592+
593+
fig_test.text(0.5, 0.7, r"$\phantom{phantom}$")
594+
595+
581596
def test_box_repr():
582597
s = repr(_mathtext.Parser().parse(
583598
r"$\frac{1}{2}$",

0 commit comments

Comments
 (0)