无法在 matplotlib 中使用自定义字体
Unable to use custom fonts in matplotlib
我在 Python 3.7.3 Windows 上无法使用自定义字体与 Matplotlib(版本 3.1.1)一起使用。使用
的标准方式
import matplotlib as mpl
mpl.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
比如
<Font 'Lato' (Lato-Semibold.ttf) normal normal semibold normal>,
<Font 'Lato' (Lato-Thin.ttf) normal normal 400 normal>,
...
然而这些情节看起来仍然像是在使用 Deja Vu Sans。我找遍了,但找不到解决此问题的方法。
matplotlib 绘图样式中的字体属性由 FontManager class and are specified with a FontProperties class 管理。
为了获取这些字体属性,matplotlib 在内部使用 FontManager class 的实例来调用搜索字体的 findfont()
函数和 returns 本地或本地的最佳 TrueType (TTF) 字体文件与 FontProperties 实例中的字体规范匹配的系统字体路径。规范中的默认后备字体是 DejaVu Sans。字体系列可以设置为以下任一参数:'serif'、'sans-serif'、'cursive'、'fantasy' 或 'monospace'。可以像这样找到任何字体系列的 TTF 文件位置:
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'
'monospace' 家族的另一个例子:
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
设置为其他字体,例如 'Lato' 字体这也属于 sans-serif 家族。
之前,我更改了 FONTNAME
,重要的是首先了解字体搜索是如何发生的。
现在字体搜索是一项昂贵的任务,为了使后续请求更高效,字体信息缓存在 JSON 文件中。您可以在 source code 中找到 FontManager
class 的证据。对于 Windows,此文件位于:%userprofile%\.matplotlib。有关详细信息,请参阅 FontManager
class 文档的注释部分:
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.
在我的电脑上(Windows 10),我有两个缓存文件:fontlist-v300 & fontlist-v310 .如果您检查这些文件中的任何一个的内容,它会显示字体列表及其属性,例如 TTF 文件位置、样式、粗细等。观察默认系列键:
"defaultFamily": {
"ttf": "DejaVu Sans",
"afm": "Helvetica"
}
至此,我们了解到该字体将以 DejaVu Sans 显示。这在情节的标题中最为明显:
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 字体为 installed correctly。该字体应该在控制面板的字体下可用。
现在正确安装了 Lato 字体,删除缓存文件并将 sans-serif 字体设置为 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()
绘图(Lato sans-serif 字体):
您还将观察到一个新的缓存文件已创建。上面的片段有 re-build 缓存文件,现在也有 Lato 字体的信息。同样,您可以在文本编辑器中打开此缓存文件以验证其存在。现在让我们验证 sans-serif 家族的 TTF 文件路径:
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 文件。
将字体样式改为斜体也需要先删除缓存文件:
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 session才能更改生效。
如果你想使用新安装的字体,而不是重建缓存,你必须首先delete and update缓存如@amanb建议的,然后您必须 重新启动 IPython 会话 / Jupyter notebook / 无论您正在 Python 在 上编程,然后 matplotlib.rcParams
才能识别您的新字体。
我给出的 link 是 Linux 的说明,但想法是一样的 - 删除旧缓存,以便创建一个包含新字体的新缓存。对于 Windows,只需在文件资源管理器中输入 %userprofile%/.matplotlib
,您就会看到类似 fontlist-v300.json
的文件。那是字体缓存文件。也可以在Python中运行matplotlib.get_cachedir()
查看缓存文件的路径
您应该删除该缓存文件。然后重启你的session/notebook,然后运行
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = [FONTNAME]
然后查看您的新字体现在是否显示。 (将创建一个新缓存。)
由于这台 (Linux) PC 上没有新安装 Lato,运行使用以下代码(设置和查找字体)确实提供了正确的字体。所以,我很确定问题出在安装新字体后你的字体缓存没有更新。
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()
我在 Python 3.7.3 Windows 上无法使用自定义字体与 Matplotlib(版本 3.1.1)一起使用。使用
的标准方式import matplotlib as mpl
mpl.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
比如
<Font 'Lato' (Lato-Semibold.ttf) normal normal semibold normal>,
<Font 'Lato' (Lato-Thin.ttf) normal normal 400 normal>,
...
然而这些情节看起来仍然像是在使用 Deja Vu Sans。我找遍了,但找不到解决此问题的方法。
matplotlib 绘图样式中的字体属性由 FontManager class and are specified with a FontProperties class 管理。
为了获取这些字体属性,matplotlib 在内部使用 FontManager class 的实例来调用搜索字体的 findfont()
函数和 returns 本地或本地的最佳 TrueType (TTF) 字体文件与 FontProperties 实例中的字体规范匹配的系统字体路径。规范中的默认后备字体是 DejaVu Sans。字体系列可以设置为以下任一参数:'serif'、'sans-serif'、'cursive'、'fantasy' 或 'monospace'。可以像这样找到任何字体系列的 TTF 文件位置:
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'
'monospace' 家族的另一个例子:
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
设置为其他字体,例如 'Lato' 字体这也属于 sans-serif 家族。
之前,我更改了 FONTNAME
,重要的是首先了解字体搜索是如何发生的。
现在字体搜索是一项昂贵的任务,为了使后续请求更高效,字体信息缓存在 JSON 文件中。您可以在 source code 中找到 FontManager
class 的证据。对于 Windows,此文件位于:%userprofile%\.matplotlib。有关详细信息,请参阅 FontManager
class 文档的注释部分:
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.
在我的电脑上(Windows 10),我有两个缓存文件:fontlist-v300 & fontlist-v310 .如果您检查这些文件中的任何一个的内容,它会显示字体列表及其属性,例如 TTF 文件位置、样式、粗细等。观察默认系列键:
"defaultFamily": {
"ttf": "DejaVu Sans",
"afm": "Helvetica"
}
至此,我们了解到该字体将以 DejaVu Sans 显示。这在情节的标题中最为明显:
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 字体为 installed correctly。该字体应该在控制面板的字体下可用。
现在正确安装了 Lato 字体,删除缓存文件并将 sans-serif 字体设置为 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()
绘图(Lato sans-serif 字体):
您还将观察到一个新的缓存文件已创建。上面的片段有 re-build 缓存文件,现在也有 Lato 字体的信息。同样,您可以在文本编辑器中打开此缓存文件以验证其存在。现在让我们验证 sans-serif 家族的 TTF 文件路径:
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 文件。
将字体样式改为斜体也需要先删除缓存文件:
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 session才能更改生效。
如果你想使用新安装的字体,而不是重建缓存,你必须首先delete and update缓存如@amanb建议的,然后您必须 重新启动 IPython 会话 / Jupyter notebook / 无论您正在 Python 在 上编程,然后 matplotlib.rcParams
才能识别您的新字体。
我给出的 link 是 Linux 的说明,但想法是一样的 - 删除旧缓存,以便创建一个包含新字体的新缓存。对于 Windows,只需在文件资源管理器中输入 %userprofile%/.matplotlib
,您就会看到类似 fontlist-v300.json
的文件。那是字体缓存文件。也可以在Python中运行matplotlib.get_cachedir()
查看缓存文件的路径
您应该删除该缓存文件。然后重启你的session/notebook,然后运行
matplotlib.rcParams['font.family'] = 'sans-serif'
matplotlib.rcParams['font.sans-serif'] = [FONTNAME]
然后查看您的新字体现在是否显示。 (将创建一个新缓存。)
由于这台 (Linux) PC 上没有新安装 Lato,运行使用以下代码(设置和查找字体)确实提供了正确的字体。所以,我很确定问题出在安装新字体后你的字体缓存没有更新。
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()