Skip to content
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

Large TrueType font does not render correctly when saving in .pdf #7937

Closed
TomDLT opened this issue Jan 24, 2017 · 16 comments
Closed

Large TrueType font does not render correctly when saving in .pdf #7937

TomDLT opened this issue Jan 24, 2017 · 16 comments
Labels
backend: pdf Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. topic: text
Milestone

Comments

@TomDLT
Copy link
Contributor

TomDLT commented Jan 24, 2017

Bug summary

Large TrueType serif font does not render correctly when saving in .pdf

Interestingly, the bug does not happen when:

  • saving in .png
  • using default font size
  • using sans-serif font
  • using type 3 font

Code for reproduction

import matplotlib as mpl
import matplotlib.pyplot as plt

for param in [3, 42]:
    mpl.rcParams['pdf.fonttype'] = param
    mpl.rcParams["font.family"] = "serif"
    mpl.rcParams["font.size"] = 20

    fig = plt.figure()
    plt.plot([0, 1])
    plt.title('This is the title')

    fig.savefig('save_%d.pdf' % param)
    plt.close(fig)

Actual outcome
save_42.pdf

Expected outcome
save_3.pdf

Matplotlib version

Matplotlib 2.0.0 installed with conda (same behavior with pip)

System version
Linux-3.16.0-4-amd64-x86_64-with-debian-8.7
Python 3.5.2 |Continuum Analytics, Inc.| (default, Jul 2 2016, 17:53:06)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]

@afvincent afvincent added this to the 2.0.1 (next bug fix release) milestone Jan 24, 2017
@afvincent
Copy link
Contributor

Hey Tom, thanks for the bug report! Are you totally certain the bug does not exist with type 42 sans-serif fonts? Because I also have a weird letter spacing with those fonts, as well as with the serif ones. For example,

import matplotlib as mpl
import matplotlib.pyplot as plt

plt.style.use('default')

for fam, ft in [('sans', 3), ('sans', 42), ('serif', 3), ('serif', 42)]:

    plt.rcParams['pdf.fonttype'] = ft  # in {3, 42}
    plt.rcParams['font.family'] = fam  # in {'serif', 'sans'}
    plt.rcParams['font.size'] = 20

    fig_label = "{fam}_T{ft}".format(fam=plt.rcParams['font.family'][0],
                                     ft=plt.rcParams['pdf.fonttype'])
    fig, ax = plt.subplots(num=fig_label)
    ax.plot([0, 1])
    ax.set_xlabel("mpl " + mpl.__version__, fontsize=10)
    ax.set_title("This is the title")

    fig.savefig(fig.get_label() + ".pdf")

produces weird outputs with both type 42 font families
sans_T42.pdf
serif_T42.pdf
while the outputs are OK with both type 3 font families:
sans_T3.pdf
serif_T3.pdf

Setup:
matplotlib from master ('2.0.0rc2.post3092+g2374c9b')
CentOS 7 (Linux 3.10.0-327.3.1.el7.x86_64)
Python 2.7.11 (from Continuum Analytics, Inc.)

@TomDLT
Copy link
Contributor Author

TomDLT commented Jan 26, 2017

Indeed you are right, the weird spacing happens also with sans-serif font, I overlooked this test.

@TomDLT TomDLT changed the title Large TrueType serif font does not render correctly when saving in .pdf Large TrueType font does not render correctly when saving in .pdf Jan 26, 2017
@afvincent
Copy link
Contributor

I wonder if the weird spacing with type 42 fonts isn't a bigger issue than first thought. Running

import matplotlib as mpl
import matplotlib.pyplot as plt


def plot_font_grade(family, fonttype):
    plt.style.use('default')  # just to be sure

    plt.rcParams['pdf.fonttype'] = fonttype  # in {3, 42}
    plt.rcParams['font.family'] = family  # in {'serif', 'sans'}

    fig_label = "{fam}_T{ft}_grade".format(fam=plt.rcParams['font.family'][0],
                                           ft=plt.rcParams['pdf.fonttype'])
    fig, ax = plt.subplots(num=fig_label, figsize=(6.4, 12.4))

    # Cosmeticks & version info
    ax.set_xlabel("mpl " + mpl.__version__, fontsize=10)
    ax.xaxis.set_major_locator(plt.NullLocator())
    ax.yaxis.set_major_locator(plt.NullLocator())
    ax.set_ylim(-10, 600)

    # Plot text with bigger and bigger size
    for i, fs in enumerate(range(4, 50, 2)):
        ax.text(0.1, i*30, "{fs} pt font size".format(fs=fs), fontsize=fs)

    fig.savefig(fig.get_label() + ".pdf")
    plt.close(fig)


if __name__ == "__main__":

    for fam, ft in [('sans', 3), ('sans', 42), ('serif', 3), ('serif', 42)]:
        plot_font_grade(fam, ft)

results in :
type 3 fonts (OK)
sans_T3_grade.pdf
serif_T3_grade.pdf
vs type 42 fonts (does not seem OK : there are huge spaces between each character)
sans_T42_grade.pdf
serif_T42_grade.pdf
whatever the font size is…

@QuLogic
Copy link
Member

QuLogic commented Jan 27, 2017

Bisect:

cdea77c009c0c85640334825fdedb22bb4543374 is the first bad commit
commit cdea77c009c0c85640334825fdedb22bb4543374
Author: Thomas A Caswell <tcaswell@gmail.com>
Date:   Wed Oct 28 20:38:47 2015 -0400

    Merge pull request #5295 from mdboom/too-many-open-files
    
    MNT: Reduce number of font file handles opened

:100644 100644 6ea8d7a5d515fd568171cd3678ce7c8c5a73bde1 96dbae42b71737e0fd7b113086b408caa7834cbd M	INSTALL
:040000 040000 d6e17bd787602c5b461e97ec363e15144e65d73a 3d14da43cdd5bbd8c1998c923d2a0065af9d757e M	lib
:100644 100644 e294363bce578be093db779a80782c4cd905afb2 e2a6393bc4062d0408dc82afa0f2d59a6341f87a M	setup.py
:100755 100755 dd872fdc7ebdcf5ff761c84e2679d7299354dfb1 4a31bd8f049b5ed9444c9505cd69a475e205388b M	setupext.py

Seems innocuous from the title...

@QuLogic
Copy link
Member

QuLogic commented Jan 27, 2017

Editing matplotlib/font_manager.py and replacing get_font with:

def get_font(*args, **kwargs):
    return ft2font.FT2Font(*args, **kwargs)

fixes the problem, so indeed the cache is not quite right.

@jkseppan
Copy link
Member

This fixes the test case too:

diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py
index a5e6253ca..c293fea7c 100644
--- a/lib/matplotlib/backends/backend_pdf.py
+++ b/lib/matplotlib/backends/backend_pdf.py
@@ -41,6 +41,7 @@ from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
 from matplotlib.afm import AFM
 import matplotlib.type1font as type1font
 import matplotlib.dviread as dviread
+from matplotlib.ft2font import FT2Font
 from matplotlib.ft2font import (FIXED_WIDTH, ITALIC, LOAD_NO_SCALE,
                                 LOAD_NO_HINTING, KERNING_UNFITTED)
 from matplotlib.mathtext import MathTextParser
@@ -853,7 +854,7 @@ end"""
     def embedTTF(self, filename, characters):
         """Embed the TTF font from the named file into the document."""
 
-        font = get_font(filename)
+        font = FT2Font(filename)
         fonttype = rcParams['pdf.fonttype']
 
         def cvt(length, upe=font.units_per_EM, nearest=True):

@jkseppan jkseppan added backend: pdf Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. labels Jan 27, 2017
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Jan 29, 2017
Adapted from the code samples in matplotlib#7937 by @TomDLT and @afvincent.
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Jan 29, 2017
Adapted from the code samples in matplotlib#7937 by @TomDLT and @afvincent.
@NelleV
Copy link
Member

NelleV commented Jan 29, 2017

Closed by #7961

@NelleV NelleV closed this as completed Jan 29, 2017
@breedlun
Copy link
Contributor

breedlun commented Feb 5, 2017

Glad to see this is fixed. I just ran into the same funny spacing, and spent 30 min tracking it back to Type 42 fonts.

@sergiocallegari
Copy link

I wonder if this could be considered serious enough to trigger the release of a 2.0.1 version of matplotlib as soon as possible, since this issue prevents upgrading from the 1.5 branch whenever you use matplotlib to prepare illustrations that need to obey some editorial flow (being in PDF, using certain fonts).

@jkseppan
Copy link
Member

jkseppan commented Mar 22, 2017 via email

@breedlun
Copy link
Contributor

For what it's worth, I like to use type 42 fonts, but I can handle type 3 fonts. All the fonts I use come in a type 42 and type 3 version. Type 3 fonts are not editable if you import a pdf into Adobe Illustrator (or similar vector graphics programs), while type 42 fonts are editable. Matplotlib, however, creates a separate text box for every individual letter when type 42 fonts are employed. This makes it a pain to edit any word longer than one letter, so type 3 fonts are not much of a downgrade. I thought I remembered a proposal to fix matplotlib's breaking up a word into multiple text boxes, but I cannot find it anywhere.

@WeatherGod
Copy link
Member

WeatherGod commented Mar 22, 2017 via email

@mdboom
Copy link
Member

mdboom commented Mar 22, 2017

The behavior is switchable. Use the pdf.fonttype rcParam.

@sergiocallegari
Copy link

I'm on a linux machine (Ubuntu 16.10) where matplotlib seems to invariably pick fonts (or the font version) that show the issue. As a matter of fact, matplotlib 2.0 seems to have other font nuisances too here, like picking by default a sans serif font for math expressions in $...$. It is unclear to me how to assure that matplotlib prefers a type 3 font when the type 42 is also present.

@breedlun
Copy link
Contributor

@mdboom Last I checked, pdf.fonttype only allows you to switch between type 3 and type 42. With type 3, the text is just outlined, making it totally un-editable. With type 42 you get text that is editable, but words are broken into individual characters. Having a separate text box for each character is only slightly better than un-editable text. If you are not using a fixed width font, you can't even just edit one character at a time to change a word. You have to delete all but the first text box and start from there.

@WeatherGod I had not considered the file size issue with including the entire font package with the pdf. I like the idea of making it a rcParam, though.

@QuLogic
Copy link
Member

QuLogic commented Mar 23, 2017

The release is very soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend: pdf Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. topic: text
Projects
None yet
Development

No branches or pull requests

9 participants