views:

343

answers:

2

I want to generate high-quality diagrams for a presentation. I’m using Python’s matplotlib to generate the graphics. Unfortunately, the PDF export seems to ignore my font settings.

I tried setting the font both by passing a FontProperties object to the text drawing functions and by setting the option globally. For the record, here is a MWE to reproduce the problem:

import scipy
import matplotlib
matplotlib.use('cairo')
import matplotlib.pylab as pylab
import matplotlib.font_manager as fm

data = scipy.arange(5)

for font in ['Helvetica', 'Gill Sans']:
    fig = pylab.figure()
    ax = fig.add_subplot(111)
    ax.bar(data, data)
    ax.set_xticks(data)
    ax.set_xticklabels(data, fontproperties = fm.FontProperties(family = font))
    pylab.savefig('foo-%s.pdf' % font)

In both cases, the produced output is identical and uses Helvetica (and yes, I do have both fonts installed).

Just to be sure, the following doesn’t help either:

matplotlib.rc('font', family = 'Gill Sans')

Finally, if I replace the backend, instead using the native viewer:

matplotlib.use('MacOSX')

I do get the correct font displayed – but only in the viewer GUI. The PDF output is once again wrong.

To be sure – I can set other fonts – but only other classes of font families: I can set serif fonts or fantasy or monospace. But all sans-serif fonts seem to default to Helvetica.

+1  A: 

The "family" argument and the corresponding rc parameter are not meant to specify the name of the font can actually be used this way. There's an (arguably baroque) CSS-like font selection system that helps the same script work on different computers, selecting the closest font available. The usually recommended way to use e.g. Gill Sans is to add it to the front of the value of the rc parameter font.sans-serif (see sample rc file), and then set font.family to sans-serif.

This can be annoying if the font manager decides for some obscure reason that Gill Sans is not the closest match to your specification. A way to bypass the font selection logic is to use FontProperties(fname='/path/to/font.ttf') (docstring).

In your case, I suspect that the MacOSX backend uses fonts via the operating system's mechanisms and so automatically supports all kinds of fonts, but the pdf backend has its own font support code that doesn't support your version of Gill Sans.

Jouni K. Seppänen
You said, “The "family" argument [is] not meant to specify the name of the font” – sorry but [the documentation](http://matplotlib.sourceforge.net/api/font_manager_api.html#matplotlib.font_manager.FontProperties) says differently: “The items **may** include a generic font family name […]. **In that case**, the actual font to be used will be looked up …” (emphasis mine). Furthermore, *it works* in the GUI. Anyway, I will try your proposed solutions. Thanks.
Konrad Rudolph
By using `fname = …` I get a RuntimeError “TrueType font is missing table” in line 776 of backend_pdf.py, in `embedTTFType3` when calling `savefig`. I’m not at home with TTF and PDF but I *have* already embedded Gill Sans in PDFs via other routes so I’m not sure what is amiss here.
Konrad Rudolph
You're right about using real font names as family arguments. The error message sounds like a bug. Please file it at the Sourceforge tracker, mentioning the exact font, matplotlib version and the full traceback.
Jouni K. Seppänen
@Jouni K. Seppänen: OK, I’ll do that. Thanks again.
Konrad Rudolph
OK, I just noticed that I had only tried your `fname` solution with the `MacOSX` backend. Using the `cairo` backend, everything works fine. I’ll post a working code sample.
Konrad Rudolph
+1  A: 

Basically, @Jouni’s is the right answer but since I still had some trouble getting it to work, here’s my final solution:

#!/usr/bin/env python2.6

import scipy
import matplotlib
matplotlib.use('cairo')
import matplotlib.pylab as pylab
import matplotlib.font_manager as fm

font = fm.FontProperties(
        family = 'Gill Sans', fname = '/Library/Fonts/GillSans.ttc')

data = scipy.arange(5)
fig = pylab.figure()
ax = fig.add_subplot(111)
ax.bar(data, data)
ax.set_yticklabels(ax.get_yticks(), fontproperties = font)
ax.set_xticklabels(ax.get_xticks(), fontproperties = font)
pylab.savefig('foo.pdf')

Notice that the font has to be set explicitly using the fontproperties key. Apparently, there’s no rc setting for the fname property (at least I didn’t find it).

Giving a family key in the instantiation of font isn’t strictly necessary here, it will be ignored by the PDF backend.

This code works with the cairo backend only. Using MacOSX won’t work.

Konrad Rudolph