JohnLyu的blog

橙汁事务所艾欧泽亚分部

0%

matplotlib字体的那些坑

尝试做个包含matplotlib的docker image, 把 STKAITI.TTF 放到了 /usr/local/share/fonts, 然后运行 fc-cache -fv.

然而字体还是不能显示, 奇了个怪了, 做了如下测试, 首先是能检测到STKaiti的:

1
2
3
4
5
6
7
8
9
10
In [13]: matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
Out[13]:
['/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf',
'/usr/local/share/fonts/STKAITI.TTF', # font is here
'/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf',
'/usr/local/share/fonts/NotoSansSC-Regular.otf',
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt
In [6]: plt.rcParams["font.sans-serif"] ## this is definded in my '~/.config/matplotlib/matplotlibrc'
Out[6]:
['STKaiti', # is here
'DejaVu Sans',
'Bitstream Vera Sans',
'Computer Modern Sans Serif',
'Lucida Grande',
'Verdana',
'Geneva',
'Lucid',
'Arial',
'Helvetica',
'Avant Garde',
'sans-serif']

ok…testing

1
2
3
4
5
6
7
8
9
10
11
12
13
In [7]: matplotlib.font_manager.get_fontconfig_fonts()
<ipython-input-7-b1c4039c0e25>:1: MatplotlibDeprecationWarning:
The get_fontconfig_fonts function was deprecated in Matplotlib 3.5 and will be removed two minor releases later.
matplotlib.font_manager.get_fontconfig_fonts()
Out[7]:
['/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
'/usr/local/share/fonts/NotoSansSC-Regular.otf',
'/usr/local/share/fonts/STKAITI.TTF', # here
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf']

然而,还有不能检测到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
In [8]: [f.name for f in matplotlib.font_manager.fontManager.ttflist]
Out[8]:
['cmb10',
'cmr10',
'STIXGeneral',
'STIXSizeOneSym',
'DejaVu Sans Mono',
'STIXSizeTwoSym',
'cmex10',
'DejaVu Serif',
'DejaVu Sans',
'cmss10',
'STIXGeneral',
'cmtt10',
'DejaVu Sans',
'cmmi10',
'STIXSizeThreeSym',
'STIXSizeTwoSym',
'STIXSizeFourSym',
'DejaVu Serif',
'STIXSizeFiveSym',
'DejaVu Sans Mono',
'DejaVu Sans Mono',
'STIXNonUnicode',
'STIXGeneral',
'cmsy10',
'DejaVu Sans',
'STIXSizeOneSym',
'STIXNonUnicode',
'STIXSizeFourSym',
'DejaVu Serif Display',
'STIXSizeThreeSym',
'DejaVu Sans Mono',
'STIXNonUnicode',
'STIXNonUnicode',
'STIXGeneral',
'DejaVu Sans',
'DejaVu Sans Display',
'DejaVu Serif',
'DejaVu Serif',
'DejaVu Sans Mono',
'DejaVu Sans',
'DejaVu Serif',
'DejaVu Serif',
'DejaVu Sans',
'DejaVu Sans Mono']

还有这

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
In [10]: matplotlib.font_manager.findfont("STKaiti", rebuild_if_missing=True)
findfont: Font family ['STKaiti'] not found. Falling back to DejaVu Sans.
Out[10]: '/usr/local/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'

In [14]: matplotlib.font_manager.findfont("STIXSizeTwoSym", rebuild_if_missing=True)
Out[14]: '/usr/local/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXSizTwoSymReg.ttf'

In [19]: matplotlib.font_manager.findfont("STKaiti", directory="/usr/local/share/fonts/",rebuild_if_missing=True)
findfont: Font family ['STKaiti'] not found. Falling back to DejaVu Sans.
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [19], in <cell line: 1>()
----> 1 matplotlib.font_manager.findfont("STKaiti", directory="/usr/local/share/fonts/",rebuild_if_missing=True)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1307, in FontManager.findfont(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing)
1301 # Pass the relevant rcParams (and the font manager, as `self`) to
1302 # _findfont_cached so to prevent using a stale cache entry after an
1303 # rcParam was changed.
1304 rc_params = tuple(tuple(rcParams[key]) for key in [
1305 "font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
1306 "font.monospace"])
-> 1307 return self._findfont_cached(
1308 prop, fontext, directory, fallback_to_default, rebuild_if_missing,
1309 rc_params)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1361, in FontManager._findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params)
1359 default_prop = prop.copy()
1360 default_prop.set_family(self.defaultFamily[fontext])
-> 1361 return self.findfont(default_prop, fontext, directory,
1362 fallback_to_default=False)
1363 else:
1364 raise ValueError(f"Failed to find font {prop}, and fallback "
1365 f"to the default font was disabled")

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1307, in FontManager.findfont(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing)
1301 # Pass the relevant rcParams (and the font manager, as `self`) to
1302 # _findfont_cached so to prevent using a stale cache entry after an
1303 # rcParam was changed.
1304 rc_params = tuple(tuple(rcParams[key]) for key in [
1305 "font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
1306 "font.monospace"])
-> 1307 return self._findfont_cached(
1308 prop, fontext, directory, fallback_to_default, rebuild_if_missing,
1309 rc_params)

File /usr/local/lib/python3.8/site-packages/matplotlib/font_manager.py:1364, in FontManager._findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params)
1361 return self.findfont(default_prop, fontext, directory,
1362 fallback_to_default=False)
1363 else:
-> 1364 raise ValueError(f"Failed to find font {prop}, and fallback "
1365 f"to the default font was disabled")
1366 else:
1367 _log.debug('findfont: Matching %s to %s (%r) with score of %f.',
1368 prop, best_font.name, best_font.fname, best_score)

ValueError: Failed to find font DejaVu Sans:style=normal:variant=normal:weight=normal:stretch=normal:size=16.0, and fallback to the default font was disabled

反正matplotlib提供的方法众多,我也不知道以哪个为准, 再加上matplotlibttc字体文件对处理是仅仅支持collection里的第一个文件,导致众多现代字体包没有意义,例如fonts-wqy-zenheifonts-noto-cjk.

大概和$\LaTeX$一样,差不多成为屎山了吧.

最终解决方案是把.cahce/matplotlib/下的缓存手动删除完事儿。

PS: 不知道是哪个大聪明,把matplotlib.font_manager._rebuild()方法给删了,我愿称之为把茅坑里的手纸给移除了。