首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法在matplotlib中使用自定义字体

无法在matplotlib中使用自定义字体
EN

Stack Overflow用户
提问于 2019-12-18 11:27:04
回答 2查看 5.1K关注 0票数 2

在Windows的Python3.7.3上,我很难使用Matplotlib (版本3.1.1)的定制字体。标准使用方式

代码语言:javascript
复制
import matplotlib as mpl
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = [FONTNAME] 

对于预装在系统上的字体范围很好。我最近手动安装了Lato系列字体。但是,当我使用'Lato‘作为FONTNAME时,Matplotlib默认为Deja Vu Sans,甚至不会抛出任何错误。我还使用

代码语言:javascript
复制
mpl.font_manager._rebuild()

当我运行时,有几个名为“Lato”的字体出现了

代码语言:javascript
复制
mpl.font_manager.fontManager.ttflist

比如

代码语言:javascript
复制
 <Font 'Lato' (Lato-Semibold.ttf) normal normal semibold normal>,
 <Font 'Lato' (Lato-Thin.ttf) normal normal 400 normal>,
...

然而,这些阴谋看起来仍然像使用Deja Vu Sans。我到处找遍了,但找不到解决这个问题的办法。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-03 20:23:32

matplotlib的绘图样式中的字体属性由FontManager类管理,并由FontProperties类指定。要获取这些字体属性,matplotlib内部使用FontManager类的一个实例调用一个findfont()函数,该函数搜索字体并返回符合FontProperties实例中字体规范的本地或系统字体路径中的最佳TrueType (TTF)字体文件。规范中的默认回退字体是DejaVu Sans。字体系列可以设置为以下参数之一:“serif”、“sans-serif”、“cursive”、“幻想”或“monospace”。可以为以下任何字体系列查找TTF文件的位置:

代码语言:javascript
复制
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'

“单空间”家族的另一个例子是:

代码语言:javascript
复制
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'

正如您所看到的,上面的sans-serif家族指向默认的DejaVuSans TTF文件,因为我还没有将FONTNAME设置为类似于sans-serif家族的'Lato‘字体。

在我更改FONTNAME之前,首先了解字体搜索是如何发生的,这一点很重要。现在,字体搜索是一项昂贵的任务,为了提高后续请求的效率,字体信息被缓存在一个JSON文件中。您可以在源代码中找到FontManager类的证据。对于Windows,此文件位于:%userprofile%.matplotlib。有关详细信息,请参阅FontManager类文档的Notes部分:

这执行最近的邻居搜索。每个字体都被赋予与目标字体属性相似的分数。返回得分最高的第一个字体。如果未找到低于某个阈值的匹配项,则返回默认字体(通常为DejaVu Sans)。 结果是缓存的,因此后续查找不必执行O(n)最近邻搜索。

在我的计算机(Windows 10)上,我有两个缓存文件:fontlist-V 300和fontlist-V 310。如果检查这些文件的内容,它将显示字体列表及其属性,如TTF文件位置、样式、权重等。请遵守默认的家族键:

代码语言:javascript
复制
"defaultFamily": {
    "ttf": "DejaVu Sans",
    "afm": "Helvetica"
  }

此时,我们理解字体将以DejaVu Sans显示。这一点在情节的标题中最为明显:

代码语言:javascript
复制
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()

绘图(默认字体)

findfont()函数将始终查找缓存文件(如果缓存文件不存在,则创建缓存文件),如果我在计算机上安装了新字体,则重要的是更新该缓存文件,否则它将继续显示回退字体(与默认字体相同)。在继续下一步之前,请确保Lato字体为正确安装。字体应可在控制面板中的字体下使用。

现在正确安装了Lato字体,删除缓存文件并将sans-serif字体设置为Lato:

代码语言:javascript
复制
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()

绘图(Lato serif字体)

您还将看到已经创建了一个新的缓存文件。上面的片段重新构建了缓存文件,该文件现在也有Lato字体的信息。同样,您可以在文本编辑器中打开这个缓存文件以验证它的存在。现在让我们验证sans-serif家族的TTF文件路径:

代码语言:javascript
复制
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'

如您所见,sans-serif家族现在指向Lato-Thin TTF文件。

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

代码语言:javascript
复制
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'

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

票数 4
EN

Stack Overflow用户

发布于 2020-01-03 21:43:12

如果您想使用新安装的字体,那么不需要重新构建缓存,您必须按照@amanb的建议,首先使用 删除和更新 缓存,然后必须重新启动IPython会话/朱庇特笔记本/任何编程Python on的内容,然后matplotlib.rcParams才能识别您的新字体。

我给出的链接是Linux的说明,但想法是相同的-删除旧缓存,以便创建一个包含新字体的新缓存。对于Windows,只需在文件资源管理器中输入%userprofile%/.matplotlib,您就会看到类似于fontlist-v300.json的文件。那是字体缓存文件。您还可以在Python中运行matplotlib.get_cachedir()来查看缓存文件的路径。

你应该删除那个缓存文件。然后重新启动会话/记事本,然后运行

代码语言:javascript
复制
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = [FONTNAME]

看看你的新字体现在是否显示。(将创建一个新的缓存。)

由于Lato不是最近在这台(Linux) PC上安装的,所以运行以下代码(设置并找到字体)确实给出了正确的字体。因此,我很确定的问题在于您的字体缓存在安装新字体后没有被更新的

代码语言:javascript
复制
import matplotlib as mpl
from matplotlib.font_manager import findfont, FontProperties
import matplotlib.pyplot as plt

x = [1, 2, 3]
y = [4, 5, 6]

mpl.rcParams['font.sans-serif'] = ['Lato']               # sets font to Lato
mpl.rcParams['font.weight'] = 'heavy'                    # otherwise can't see it lol
font = findfont(FontProperties(family=['sans-serif']))   # finds the font used
print(font)
plt.plot(x, y)
plt.title("Hello", size=45)
plt.show()

mpl.rcParams['font.sans-serif'] = ['DejaVu Sans']
mpl.rcParams['font.weight'] = 'normal'
font = findfont(FontProperties(family=['sans-serif']))
print(font)
plt.plot(x, y)
plt.title("Hello", size=45)
plt.show()

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59391050

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档