8000 [Bug]: bbox and alignment issues with math text · Issue #22459 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

[Bug]: bbox and alignment issues with math text #22459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
gartrog opened this issue Feb 12, 2022 · 2 comments
Open

[Bug]: bbox and alignment issues with math text #22459

gartrog opened this issue Feb 12, 2022 · 2 comments

Comments

@gartrog
Copy link
gartrog commented Feb 12, 2022

Bug summary

There are several issues with bbox and text alignement when math is used, as evidenced in the mwe below.

In the 'normal' case (1st line), all is ok.

When using mathtext (2nd), the height of the bounding box depends on the text contents while it should not (no fancy super/under script that would extend beyond 'lp'). Also note that the horizontal alignment is different wrt the 1st and 3rd lines (space to the left of the V, no space to the right of the last letter).

When using 'usetex' (3rd line), the bounding box seems correctly placed, but the text position itself in the second case is off by a little bit (see the 'l' being slightly above the line).

Code for reproduction

import matplotlib.pyplot as plt

kw = dict(
    fontsize=55,
    bbox=dict(boxstyle='round,pad=0', fc='lightsteelblue', ec='none')
)

plt.annotate('V lp', xy=(0.2, 0.7), **kw)
plt.annotate('V l', xy=(0.5, 0.7), **kw)
plt.axhline(y=0.7, zorder=10)

plt.annotate('$V$ lp', xy=(0.2, 0.4), **kw)
plt.annotate('$V$ l', xy=(0.5, 0.4), **kw)
plt.axhline(y=0.4, zorder=10)

plt.annotate('$V$ lp', xy=(0.2, 0.1), usetex=True, **kw)
plt.annotate('$V$ l', xy=(0.5, 0.1), usetex=True, **kw)
plt.axhline(y=0.1, zorder=10)

plt.show()

Actual outcome

example

Expected outcome

2nd row: the height of the first bbox should be fixed.

3rd row: the vertical positioning of the text in the second case should be fixed.

Additional information

No response

Operating system

No response

Matplotlib Version

3.5.1

Matplotlib Backend

QtAgg

Python version

3.10.2

Jupyter version

No response

Installation

No response

@anntzer
Copy link
Contributor
anntzer commented Feb 13, 2022

In the usetex case, the origin of the shift is, I believe, the following. Remember that usetex+agg is currently implemented by compiling the tex string to a dvi, converting that to png with dvipng and inserting the image "at the right place". In order to determine that place, we must compute the descent of the text, i.e. how much it extends below the baseline. dvipng cannot report this (actually, it has an option to do this using the TeX preview package, but that is GPL), so we infer it by parsing the dvi file ourselves and getting the glyph metrics font via the TeX font metrics (tfm) files. Unfortunately, tfm files actually lie(!) about the real rasterized metrics (see e.g. https://tex.stackexchange.com/questions/526103 for why, see also #21653 (comment)); in the current specific case, it claims that the italic V has zero descent even though it actually has a small one. Because of that, in the $V$ l string, we believe that the bottom-most pixel that is black is the baseline of the png image and we (incorrectly) align on that. For $V$ lp, this doesn't occur because the descent of p is bigger (and correct) anyways.

Two fixes are possible. One is to stop using the tfm files to get glyph metrics, and instead get them from the actual font files with FreeType. Probably a fair bit of code surgery is required, but this seems doable. The other (already suggested elsewhere) is to stop using dvipng and render the glyphs ourselves. This is in fact already the approach used by the vector backends, which is why you don't see the problem e.g. when saving to pdf. This is also the approach used by mplcairo (even for raster output), so you can also use that in the meantime (probably mplcairo master, the last release of mplcairo is too old to work with matplotlib 3.5).

For the mathtext case, regarding vertical positioning, I suspect that the problem comes at least in part from the use of "+1/-1" at

bbox = [bbox[0] - 1, bbox[1] - 1, bbox[2] + 1, bbox[3] + 1]
whereas we should track more carefully the bbox size, but just changing that is not sufficient 8000 . Here too, mplcairo fixes the problem for vertical bbox sizing.

Still in the mathtext case, regarding horizontal spacing, the presence of space before the V is (I think, though I haven't checked) just because it is an italic glyph, which gets drawn a bit further to the left from the origin (technically, it has a positive xMin; see the "glyph metrics" figure at https://freetype.org/freetype2/docs/glyphs/glyphs-3.html); this can be checked by typesetting the non-mathtext case in italic (with style="italic") which also gives the spacing before the V. As for the space after the "l", I still need to investigate this (funnily, mplcairo shows the opposite behavior: no space after the non-mathtext case, and space after the mathtext case), but this may be due to inconsistency as to whether the limit is set by the last glyph's width (i.e., actually inked area) or advance (i.e., how much does the pen advance in prevision of a (hypothetical) following glyph).

@gartrog
Copy link
Author
gartrog commented Feb 13, 2022

Thanks a lot @anntzer !

Using mplcairo indeed fixes almost everything.

It is not 100% perfect for mathtext: as you can see the 'l' extends a little bit over the box in the "$V$ l" case (the bbox is a tiny bit too short). But that's already much better for my use-case !
example_2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants
0