python-3.x - 当有多个同名字体时,按家族名称设置 matplotlib 字体

标签 python-3.x matplotlib fonts

我怎么知道matplotlib当它们具有相同的名称和特征时使用字体的特定变体?

例如,我可以告诉 matplotlib使用拉丁现代罗马:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
from pathlib import Path

import matplotlib as mpl
import PyQt5
mpl.use('Qt5Agg')
import matplotlib.pyplot as plt

mpl.rcParams['font.family'] = 'Latin Modern Roman'
mpl.rcParams['font.weight'] = '400'
mpl.rcParams['font.style'] = 'normal'
mpl.rcParams['font.variant'] = 'normal'
mpl.rcParams['mathtext.fontset'] = 'custom'
mpl.rcParams['mathtext.default'] = 'it'
mpl.rcParams['mathtext.rm'] = 'Latin Modern Roman:normal'
mpl.rcParams['mathtext.it'] = 'Latin Modern Roman:italic'
mpl.rcParams['mathtext.bf'] = 'Latin Modern Roman:bold'

mpl.rcParams['xtick.labelsize'] = 8
mpl.rcParams['ytick.labelsize'] = 8
mpl.rcParams['axes.titlesize'] = 10
mpl.rcParams['axes.labelsize'] = 10

x = np.linspace(0,2*np.pi,100)
y = np.sin(x)

fig1 = plt.figure(figsize=(3, 3*(9/16)), dpi=300)
ax1 = fig1.gca()
ax1.plot(x, y, c='r', linewidth=1.0, zorder=20)
ax1.set_xlabel(r'$x\ label$')
ax1.set_ylabel(r'$y\ label$')
fig1.tight_layout(pad=0.15)
plt.show()

enter image description here

好的,很好。但是,如果我想使用拉丁现代罗马的特定“子样式”怎么办?例如,在我的系统上,当我列出具有 name='Latin Modern Roman' 的可用字体条目时和weight=400style='normal'variant='normal'通过:

fonts = mpl.font_manager.fontManager.ttflist
for f in fonts:
    if (f.name=='Latin Modern Roman'):
        if all([(f.style=='normal'),(f.weight==400),(f.style=='normal'),(f.variant=='normal')]):
            print(f.name)
            print(Path(f.fname).stem)
            print(f.fname)
            print('weight : %s'%str(f.weight))
            print('style : %s'%str(f.style))
            print('stretch : %s'%str(f.stretch))
            print('variant : %s'%str(f.variant))
            print('\n')

我得到:

Latin Modern Roman
lmroman9-regular
/usr/share/texmf/fonts/opentype/public/lm/lmroman9-regular.otf
weight : 400
style : normal
stretch : normal
variant : normal

...
...

Latin Modern Roman
lmroman10-regular
/usr/share/texmf/fonts/opentype/public/lm/lmroman10-regular.otf
weight : 400
style : normal
stretch : normal
variant : normal

那么我该如何告诉 matplotlib我想使用 lmroman9-regular.otflmroman10-regular.otf ?在 mpl.rcParams我只能指定 font.family , font.weight , font.stylefont.variant所以如果两个 .otf文件具有所有相同的值,我如何告诉它使用一个 .otf而不是另一个?字体之间实际上是有区别的,例如:

enter image description here

我尝试引用.otf直接使用 matplotlib.FontProperties 文件实例,然后重命名它,然后指向新名称,例如:

prop = mpl.font_manager.FontProperties(fname='/usr/share/fonts/opentype/lmodern/lmroman10-regular.otf')
prop.set_name('Latin Modern Roman Type 10')
mpl.rcParams['font.family'] = 'Latin Modern Roman Type 10'

但后来我得到 findfont: Font family ['Latin Modern Roman Type 10'] not found. Falling back to DejaVu Sans.因为prop.get_name()仍然(神秘地)返回Latin Modern Roman而不是Latin Modern Roman Type 10

我怎么知道matplotlib我想使用其中一个而不是另一个?

可以显式使用 fontproperties指向font_manager.FontProperties()大多数set_label中的实例和set_ticklabel调用(如 answer ),但我正在寻找一种通过 rcParams 进行全局设置的方法.

注意:我不想使用 LaTeXtext.usetex 中渲染 ( matplotlib ) .

系统:

  • Windows 10 Pro 19042 上 WSL2 上的 Ubuntu-20.04
  • Linux 上的 Python 3.8.5/[GCC 9.3.0]
  • matplotlib 3.4.1

最佳答案

这是一个非常好的问题。我将提供我找到该特定问题的解决方案的方法。为了重现它,我们首先必须从here下载给定的字体。 (我下载了 10 版常规版和 17 版常规版以查看更明显的差异)。安装后,我们可以检查 matplotlib 是否找到了我们的新字体:

from matplotlib import font_manager

font_manager.font_manager.findSystemFonts(fontext='otf') # Matplotlib associates with
# the .otf extension two more extensions viz. '.ttc' and '.ttf', as can be obtain over
# font_manager.get_fontext_synonyms('otf')

找到 .otf 文件的指定路径后,我们可以使用 font_manager 将该特定版本设为我们选择的字体。

# This will create an object which contains your file and give it a custom name
# Here is the idea of this: https://stackoverflow.com/questions/35668219/how-to-set-up-a-custom-font-with-custom-path-to-matplotlib-global-font
fe = font_manager.FontEntry(
    fname='C:\\Users\\<your_user_name>\\AppData\\Local\\Microsoft\\Windows\\Fonts\\latin-modern-roman.mroman10-regular.otf',
    name='10erLatin')
font_manager.fontManager.ttflist.insert(0, fe) 
mpl.rcParams['font.family'] = fe.name

让我们绘制它,以便我们稍后可以查看它是否有效。

import numpy as np
from pathlib import Path

import matplotlib as mpl
# import PyQt5
# mpl.use('Qt5Agg') # I want to plot it inline ;)
import matplotlib.pyplot as plt

mpl.rcParams['font.family'] = fe.name
mpl.rcParams['font.weight'] = '400'
mpl.rcParams['font.style'] = 'normal'
mpl.rcParams['font.variant'] = 'normal'
mpl.rcParams['mathtext.fontset'] = 'custom'
mpl.rcParams['mathtext.default'] = 'it'
mpl.rcParams['mathtext.rm'] = fe.name + ':normal'
mpl.rcParams['mathtext.it'] = fe.name + ':italic'
mpl.rcParams['mathtext.bf'] = fe.name + ':bold'

mpl.rcParams['xtick.labelsize'] = 8
mpl.rcParams['ytick.labelsize'] = 8
mpl.rcParams['axes.titlesize'] = 10
mpl.rcParams['axes.labelsize'] = 10

x = np.linspace(0,2*np.pi,100)
y = np.sin(x)

fig1 = plt.figure(figsize=(3, 3*(9/16)), dpi=300)
ax1 = fig1.gca()
ax1.plot(x, y, c='r', linewidth=1.0, zorder=20)
ax1.set_xlabel(r'$x\ label$')
ax1.set_ylabel(r'$y\ label$')
fig1.tight_layout(pad=0.15)
plt.show()

enter image description here

让我们将其更改为常规字体的 17 版本。

fe = font_manager.FontEntry(
    fname='C:\\Users\\<your_user_name>\\AppData\\Local\\Microsoft\\Windows\\Fonts\\latin-modern-roman.mroman17-regular.otf',
    name='17erLatin')
font_manager.fontManager.ttflist.insert(0, fe) 
mpl.rcParams['font.family'] = fe.name

再次,让我们绘制它(使用与上面完全相同的代码来创建该图,只是预先执行给定的代码)。

enter image description here

如果我的事后诸葛亮的话,那么文本会在全局范围内发生变化。还有一些其他函数可能有用,但是它们实际上隐藏在 source code 中。 。如果您遇到问题,请告诉我。

关于python-3.x - 当有多个同名字体时,按家族名称设置 matplotlib 字体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67401784/

相关文章:

python - 透明 "overlay"matplotlib stackplot

python - 如何在 matplotlib 的主图外绘制箭头和矩形(用于蛋白质 sec 结构)?

python - 如何在给定 Python 分布样本列表的情况下计算值的概率?

python - 在 FastAPI 中上传多部分形式的图像作为数据

python-3.x - 如何根据其他列查找列值是否被低估或高估?

fonts - 如何让单个字符在所有浏览器和操作系统中都居中?

flash - 谷歌字体 API 和 Actionscript

html - 验证错误 : Value Error : font-family 'Neue' is not a font-family value : Helvetica 'Neue' , Helvetica、Arial、sans-serif

python-3.x - 从源代码构建后无法导入 cv2

python - 使用 python/selenium 定位 instagram 中的点赞滚动条