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

Skip to content

Missing character upon savefig() with Free Serif font #17197

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

Closed
fperonaci opened this issue Apr 20, 2020 · 11 comments · Fixed by #18181
Closed

Missing character upon savefig() with Free Serif font #17197

fperonaci opened this issue Apr 20, 2020 · 11 comments · Fixed by #18181
Labels
backend: pdf Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
Milestone

Comments

@fperonaci
Copy link

Bug report

Bug summary

Choosing the font "Free Serif".

Right parenthesis character ")" is not printed upon using fig.savefig().

It is correctly printed upon using plt.show().

Code for reproduction

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(s='(Some text)', x=0.5, y=0.5, fontname='freeserif')
fig.savefig('fig.pdf')

Actual outcome

Right parenthesis is not printed on pdf.

Expected outcome

All characters should be printed on pdf.

Matplotlib version

  • Operating system: Fedora 31 Workstation
  • Matplotlib version: 3.2.1
  • Python version: 3.7.6
@anntzer
Copy link
Contributor

anntzer commented Apr 20, 2020

fwiw I cannot repro this locally: out.pdf

@QuLogic
Copy link
Member

QuLogic commented Apr 20, 2020

I can reproduce on Fedora 30; maybe the font was old?

@QuLogic
Copy link
Member

QuLogic commented Apr 20, 2020

Or not, because the font hasn't been touched in ages. TTF vs OTF, maybe?

@QuLogic
Copy link
Member

QuLogic commented Apr 20, 2020

In Inkscape, the closing parenthesis is there, but in evince, it's invisible. In okular, it's even weirder:
image

@anntzer
Copy link
Contributor

anntzer commented Apr 20, 2020

Arch provides an otf file (and I was using mpl's pdf backend, not mplcairo).

@fperonaci
Copy link
Author

Also with LibreOffice Draw it shows correctly.
Besides, even if the right parenthesis is invisible in Evince, I can copy paste it.

Could it be a problem of the pdf viewer and not at all of Matplotlib?
In this case should I close the issue?

@anntzer
Copy link
Contributor

anntzer commented Apr 21, 2020

Can either of you post the failing file? I would suggest using figtext() instead of text to not include axes, so that there's as little text as possible in the pdf to simplify the troubleshooting.

@fperonaci
Copy link
Author

Here is the output of the code below: fig.pdf
OS and Matplotlib version as in my original message.

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(2,2))
fig.text(s='(Some text)', x=0.5, y=0.5, fontname='freeserif')
fig.savefig('fig.pdf')

@anntzer
Copy link
Contributor

anntzer commented Apr 21, 2020

ok, I can repro now.
Looking at Fedora's FreeSerif.ttf (that's the difference, Arch ships an otf), I notice that the closing parenthesis appears(?) to be defined as the reflection of the opening parenthesis along a vertical axis, and a very wild guess would be that this reflection is somehow lost during font subsetting by ttconv -- a part of the codebase which I guess basically no one understands among the current devs...

@anntzer anntzer added Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues and removed status: needs confirmation labels Apr 21, 2020
@jkseppan
Copy link
Member

I think you're right. When converting the ttf file to ttx format with fonttools, the parenleft program is

    <TTGlyph name="parenleft" xMin="48" yMin="-177" xMax="304" yMax="676">
      <contour>
        <pt x="292" y="-177" on="1"/>
        <pt x="266" y="-161" on="0"/>
             ...
        <pt x="304" y="-161" on="1"/>
      </contour>
      <instructions/>
    </TTGlyph>

and the parenright program is

    <TTGlyph name="parenright" xMin="29" yMin="-177" xMax="285" yMax="676">
      <component glyphName="parenleft" x="333" y="499" scale="-1.0" flags="0x1004"/>
    </TTGlyph>

The corresponding charprocs in the pdf file are parenleft:

333 0 48 -176 304 676 d1
292 -176 m
274 -165 256 -152 238 -137 c
...
292 -176 l
f

and parenright:

333 0 29 -176 285 676 d1
q 1 0 0 1 333 499 cm
292 -176 m
274 -165 256 -152 238 -137 c
...
292 -176 l
f
Q

The only differences in the charproc outputs are in the d1 line (which I think is the bounding box) and the added q..Q stack push/pop sequence and the 1 0 0 1 333 499 cm operation. That operation translates the glyph by (333, 499) but the initial part is just the identity matrix, so the scale="-1.0" specification has been ignored. I suspect that the matrix should be -1 0 0 -1 333 499 instead.

jkseppan added a commit to jkseppan/matplotlib that referenced this issue Jul 27, 2020
@jkseppan
Copy link
Member

I think the linked #18081 should fix this. If anyone with a good collection of ttf fonts and an eye for detail is interested in testing that, please do.

jkseppan added a commit to jkseppan/matplotlib that referenced this issue Aug 1, 2020
@QuLogic QuLogic added this to the v3.4.0 milestone Aug 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend: pdf Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
Projects
None yet
4 participants