Matplotlib PDF 导出使用错误的字体
我想为一个演示文稿生成高质量的图表。我正在使用Python的matplotlib来制作这些图形。不过,导出为PDF时,似乎我的字体设置没有被识别。
我尝试过通过传递一个FontProperties
对象给文本绘制函数来设置字体,也尝试过全局设置字体选项。为了说明问题,这里有一个简单的示例:
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)
在这两种情况下,生成的输出是一样的,都是使用Helvetica字体(而且我确实安装了这两种字体)。
为了确认,以下方法也没有帮助:
matplotlib.rc('font', family = 'Gill Sans')
最后,如果我更换后端,使用原生查看器:
matplotlib.use('MacOSX')
我确实能在查看器界面中看到正确的字体——但这仅限于查看器的界面。PDF输出又一次出错了。
为了确认——我确实可以设置其他字体——但只能是其他类型的字体系列:我可以设置serif
字体、fantasy
字体或monospace
字体。但所有的无衬线字体似乎都默认使用Helvetica。
4 个回答
如果你是为了寻找非cairo后端的解决方案而来到这里,这里有一些补充信息。
matplotlib的pdf后端目前还不支持真正的字体集合(也就是保存为.ttc文件的字体)。你可以查看这个问题。
现在推荐的解决办法是从.ttc文件中提取你需要的字体,然后把它保存为.ttf文件。接着按照Konrad Rudolph的方式使用这个字体。
你可以使用一个叫做fonttools的Python包来做到这一点:
font = TTFont("/System/Library/Fonts/Helvetica.ttc", fontNumber=0)
font.save("Helvetica-regular.ttf")
据我所知,无法通过将新生成的.ttf
文件路径传递给rc来让这个设置变成“全局”的。如果你真的很着急,可以尝试将一个.ttc
文件中的所有字体提取到单独的.ttf
文件中,然后卸载.ttc
文件,单独安装.ttf
文件。为了让提取的字体和原始的.ttc
字体并排使用,你需要使用像FontForge这样的工具来更改字体名称。不过我还没有测试过这个方法。
基本上,@Jouni 的回答是正确的,但因为我在实现时遇到了一些问题,所以这里分享一下我的最终解决方案:
#!/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')
注意,字体必须通过 fontproperties
这个键来明确设置。显然,fname
属性没有 rc
设置(至少我没有找到)。
在创建 font
的时候,给 family
这个键并不是绝对必要的,PDF 后端会忽略它。
这段代码只适用于 cairo
后端,使用 MacOSX
是不行的。
这里提到的“family”参数和相应的rc参数其实并不是用来指定字体名称的,但可以这样使用。它有一个(可以说是复杂的)类似CSS的字体选择系统,帮助同一个脚本在不同的电脑上运行时,选择最接近的可用字体。通常推荐的使用方法是,比如说要用Gill Sans字体,可以把它放在rc参数font.sans-serif的值前面(具体可以参考这个示例rc文件),然后把font.family设置为sans-serif。
不过,如果字体管理器因为某些不明的原因决定Gill Sans不是最接近你要求的字体,这就会让人感到烦恼。为了绕过这种字体选择的逻辑,可以使用FontProperties(fname='/path/to/font.ttf')
(具体可以查看这个文档)。
在你的情况下,我猜测MacOSX的后端通过操作系统的机制来使用字体,因此自动支持各种字体,但pdf后端有自己的一套字体支持代码,可能不支持你版本的Gill Sans。