无法在Matplotlib中使用自定义字体 [英] Unable to use custom fonts in matplotlib

查看:79
本文介绍了无法在Matplotlib中使用自定义字体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows上的Python 3.7.3上获取自定义字体以与Matplotlib(版本3.1.1)一起使用时遇到麻烦.标准方式使用

 将matplotlib导入为mplmpl.rcParams ['font.family'] ='sans-serif'mpl.rcParams ['font.sans-serif'] = [FONTNAME] 

对于系统上预装的多种字体都可以正常工作.我最近手动安装了Lato系列字体.但是,当我使用"Lato"作为FONTNAME时,Matplotlib默认返回到Deja Vu Sans,甚至不会引发任何错误.我还使用

重建了字体缓存

  mpl.font_manager._rebuild() 

当我运行时,现在会出现几种名为"Lato"的字体

  mpl.font_manager.fontManager.ttflist 

例如

 <字体'Lato'(Lato-Semibold.ttf)正常正常半粗体正常>,<字体'Lato'(Lato-Thin.ttf)正常正常400正常>,... 

然而,这些情节仍然看起来像他们在使用Deja Vu Sans.我四处张望,但找不到解决此问题的方法.

解决方案

matplotlib的打印样式中的字体属性由

findfont()函数将始终查找缓存文件(如果不存在,则创建一个),如果我在计算机上安装了新字体,则重要的是此缓存文件已更新,否则它将继续显示后备字体(与默认字体相同).在继续下一步之前,请确保正确安装

您还将观察到已经创建了一个新的缓存文件.上面的代码片段重新构建了缓存文件,该文件现在还包含Lato字体的信息.同样,您可以在文本编辑器中打开此缓存文件以验证其存在.现在,让我们验证sans-serif系列的TTF文件路径:

 在[4]中:从matplotlib.font_manager导入findfont,FontProperties在[5]中:font = findfont(FontProperties(family = ['sans-serif']))在[6]中:字体出[6]:"C:\\ Users \\ xxxxx \\ AppData \\ Local \\ Microsoft \\ Windows \\ Fonts \\ Lato-Thin.ttf" 

您可以看到sans-serif系列现在指向的是Lato-Thin TTF文件.

将字体样式更改为 italic 还需要首先删除缓存文件:

 在[3]中:在[4]中:将matplotlib作为mpl导入...:...:mpl.rcParams ['font.family'] ='sans-serif'...:...:mpl.rcParams ['font.sans-serif'] ='Lato'...:...:mpl.rcParams ['font.style'] ='斜体'...:...:导入matplotlib.pyplot作为plt...:...:plt.plot(范围(0,50,10))...:...:plt.title('字体测试',size = 32)...:...:plt.show()在[4]中:从matplotlib.font_manager导入findfont,FontProperties在[5]中:font = findfont(FontProperties(family = ['sans-serif']))在[6]中:字体出[6]:"C:\\ Users \\ xxxxxx \\ AppData \\ Local \\ Microsoft \\ Windows \\ Fonts \\ Lato-HairlineItalic.ttf" 

情节:

注意:所有步骤都是在IPython控制台上执行的,可能需要重新启动IPython会话才能使更改生效.

I'm having trouble getting a custom font to work with Matplotlib (version 3.1.1) on Python 3.7.3 on Windows. The standard way using

import matplotlib as mpl
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = [FONTNAME] 

works fine for a range of fonts preinstalled on the system. I recently manually installed the Lato family of fonts. However, when I use 'Lato' as FONTNAME, Matplotlib defaults back to Deja Vu Sans and doesn't even throw any errors. I also rebuilt the font cache using

mpl.font_manager._rebuild()

Several fonts named 'Lato' now appear when I run

mpl.font_manager.fontManager.ttflist

such as

 <Font 'Lato' (Lato-Semibold.ttf) normal normal semibold normal>,
 <Font 'Lato' (Lato-Thin.ttf) normal normal 400 normal>,
...

Yet the plots still look like they use Deja Vu Sans. I've looked all over but couldn't find a solution to this issue.

解决方案

The font properties in matplotlib's plot styles are managed by a FontManager class and are specified with a FontProperties class. To fetch these font properties, matplotlib internally uses an instance of the FontManager class to call a findfont() function that searches for fonts and returns the best TrueType (TTF) font file in the local or system font path that matches the font specifications in the FontProperties instance. The default fallback font in the specification is DejaVu Sans. The font family can be set to either of the following parameters: 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace'. It is possible to find out the TTF file location for any of the font families like this:

In [1]: from matplotlib.font_manager import findfont, FontProperties

In [2]: font = findfont(FontProperties(family=['sans-serif']))

In [3]: font
Out[3]: 'C:\\Users\\xxxxxx\\Anaconda3\\envs\\py3.7.4\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\DejaVuSans.ttf'

Another example for the 'monospace' family:

In [7]: font = findfont(FontProperties(family=['monospace']))

In [8]: font
Out[8]: 'C:\\Users\\xxxxxx\\Anaconda3\\envs\\py3.7.4\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\DejaVuSansMono.ttf'

As you can see, the sans-serif family above is pointing to the default DejaVuSans TTF file because I haven't yet set the FONTNAME to something else like the 'Lato' font which also belongs to the sans-serif family.

Before, I change the FONTNAME, it is important to understand first how the font search happens. Now font search is an expensive task and to make this efficient for subsequent requests, the font info is cached in a JSON file. You can find the evidence in the source code for the FontManager class. For Windows, this file is found at: %userprofile%\.matplotlib. For more details, refer to the Notes section of the FontManager class docs:

This performs a nearest neighbor search. Each font is given a similarity score to the target font properties. The first font with the highest score is returned. If no matches below a certain threshold are found, the default font (usually DejaVu Sans) is returned.

The result is cached, so subsequent lookups don't have to perform the O(n) nearest neighbor search.

On my computer(Windows 10), I had two cache files: fontlist-v300 & fontlist-v310. If you examine the contents of any of these files, it shows a list of fonts and their properties such as TTF file location, style, weight etc. Observe the default family key:

"defaultFamily": {
    "ttf": "DejaVu Sans",
    "afm": "Helvetica"
  }

At this point, we understand that the font will display in DejaVu Sans. This is most noticeable in the title of the plot:

In [1]: import matplotlib as mpl
   ...: mpl.rcParams['font.family'] = 'sans-serif'
   ...: import matplotlib.pyplot as plt
   ...: plt.plot(range(0,50,10))
   ...: plt.title('Font test', size=32)
   ...: plt.show()

Plot(default font):

The findfont() function will always look for the cache file(and create one if it doesn't exist) and if I install a new font on my computer, it is important that this cache file is updated otherwise it would continue to display the fallback font(which is same as default). Before proceeding to next steps, make sure the Lato font is installed correctly. The font should be available under Fonts in the Control Panel.

Now with the Lato font properly installed, delete the cache file(s) and set the sans-serif font to Lato:

In [4]: import matplotlib as mpl^M
   ...: mpl.rcParams['font.family'] = 'sans-serif'
   ...: mpl.rcParams['font.sans-serif'] = 'Lato'
   ...: import matplotlib.pyplot as plt
   ...: plt.plot(range(0,50,10))
   ...: plt.title('Font test', size=32)
   ...: plt.show()

Plot(Lato sans-serif font):

You will also observe a new cache file has been created. The above snippet has re-build the cache file, which now also has Lato fonts' info. Again, you can open this cache file in a text editor to verify its presence. Let's verify the TTF file path for the sans-serif family now:

In [4]: from matplotlib.font_manager import findfont, FontProperties

In [5]: font = findfont(FontProperties(family=['sans-serif']))

In [6]: font
Out[6]: 'C:\\Users\\xxxxx\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Lato-Thin.ttf'

As you can see that the sans-serif family is now pointing to the Lato-Thin TTF file.

Changing the font style to italic also requires that the cache file is deleted first:

In [3]: In [4]: import matplotlib as mpl
   ...:    ...: mpl.rcParams['font.family'] = 'sans-serif'
   ...:    ...: mpl.rcParams['font.sans-serif'] = 'Lato'
   ...:    ...: mpl.rcParams['font.style'] = 'italic'
   ...:    ...: import matplotlib.pyplot as plt
   ...:    ...: plt.plot(range(0,50,10))
   ...:    ...: plt.title('Font test', size=32)
   ...:    ...: plt.show()

In [4]: from matplotlib.font_manager import findfont, FontProperties

In [5]: font = findfont(FontProperties(family=['sans-serif']))

In [6]: font
Out[6]: 'C:\\Users\\xxxxxx\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Lato-HairlineItalic.ttf'

Plot:

Note: All the steps were performed on IPython console, it may be required to restart the IPython session in order for the changes to take effect.

这篇关于无法在Matplotlib中使用自定义字体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆