Skip to content

[Bug]: mathtext not always rendering combining accents in the same way #23257

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
oscargus opened this issue Jun 12, 2022 · 7 comments
Open

Comments

@oscargus
Copy link
Member

Bug summary

In the reference figure https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.pdf

the dot above the s is differently positioned. Not clear why as the expressions are \dot s and \dot{s} respectively. This doesn't happen to all fonts (maybe only this?).

It also happens in the svg image, although not as clear. Looking at the source, the x-position difference between the accent and character is 54.4 for the left and 57.5 for the right.

Code for reproduction

import matplotlib.pyplot
plt.text(0.5, 0.5, r'$\dot s + \dot{s}$')
plt.savefig('sdot.pdf')
plt.savefig('sdot.svg')

Actual outcome

Different rendering

Expected outcome

Identical rendering

Additional information

No response

Operating system

No response

Matplotlib Version

3.6.0.dev2642+g25292618a9.d20220612

Matplotlib Backend

No response

Python version

No response

Jupyter version

No response

Installation

git checkout

@tfpf
Copy link
Contributor

tfpf commented Jul 7, 2022

It looks like this happens with all fonts. I don't think it's specific to the SVG and PDF backends, since the differences in rendering are visible in the plot window. (I am using the GTK3Agg backend.)

import matplotlib.pyplot as plt
fig = plt.figure()
for (i, fontset) in zip([.1, .3, .5, .7, .9], ['cm', 'dejavusans', 'dejavuserif', 'stix', 'stixsans']):
    plt.rc('mathtext', fontset=fontset)
    fig.text(i, 0.5, r'$\dot s$', ha='center', va='center', size=250, alpha=0.5, color='red')
    fig.text(i, 0.5, r'$\dot{s}$', ha='center', va='center', size=250, alpha=0.5, color='green')
plt.show()

image

The root of the problem is the difference in the way s and {s} are treated. The former is a symbol (which gets converted into a Char), whereas the latter is a group (which gets inserted into an Hlist).

def group(self, s, loc, toks):
grp = Hlist(toks.get("group", []))
return [grp]

By default, an Hlist adds kerning to characters, so {s} is actually rendered with some additional space after it. The dot is then centred above the Hlist. That's why it is displaced to the right.

@anntzer
Copy link
Contributor

anntzer commented Jul 7, 2022

Good catch. The behavior of \dot{s} would seem to be in error, no?

@oscargus
Copy link
Member Author

oscargus commented Jul 7, 2022

I think that it is an error, yes. At least https://www.ctan.org/pkg/comprehensive writes with {} around the character for accents. (And I always was under the impression that it is the same, but indeed a less authoritative source...)

Indeed a good catch @tfpf !

@tfpf
Copy link
Contributor

tfpf commented Jul 8, 2022

I agree with oscargus. LaTeX does not add that extra space at the end, so the behaviour of \dot{s} is incorrect. However, LaTeX's behaviour resembles that of \dot{s}, probably because it shifts the accent when the character is italicised. Which might be the purpose of sym.width / 4.0 in the accent function.

centered = HCentered([Hbox(sym.width / 4.0), accent_box])

The italic correction messes up the placement (which isn't obvious unless the text under the accent is long), while the extra space at the end is responsible for the difference between s and {s}.

I should add that the point about the italic correction has already been noted in #19299.

@oscargus
Copy link
Member Author

oscargus commented Jul 8, 2022

I think that #23189 actually solves this (and explains one of the failing tests). One can probably make a simpler patch that just handles this, something like:

             if not isinstance(sym, Char):
                sym = sym.children[0]

if it is expected that #23189 will take a long time to get ready (I think that it is probably worthwhile to spend the effort there if we are still planning to "break" how the accents are rendered...).

@tfpf
Copy link
Contributor

tfpf commented Jul 8, 2022

if not isinstance(sym, Char):
    sym = sym.children[0]

This works well! However, if the group contains another group nested inside it (e.g. \dot{{s}}), the placement of the dot will again be off.

@oscargus
Copy link
Member Author

oscargus commented Jul 8, 2022

Yeah, you are right. Probably better to do something like:

while isinstance(sym, Hlist):
   sym = sym.children[0]

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

Successfully merging a pull request may close this issue.

3 participants