如何修复matplotlib检测错误的字体权重?

3

我从Google Fonts下载了字体,想在我的论文和所有图表中使用,即Alegreya字体家族。将字体安装到$HOME/.fonts后,我删除了.cache/matplotlib/fontList.cache,并在rcParams中创建了一个新的font.family = 'Alegreya Sans'的绘图。不幸的是,matplotlib将Alegreya Sans的Thin字体错误地识别为Regular字体。以下最小示例说明了这个错误的检测:

import matplotlib.font_manager

weights = ['ultralight', 'light', 'normal', 'regular', 'book', 'medium', 
           'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 
           'extra bold', 'black']

print 'weight'+6*' ', 'file name', '\n'+70*'-'
for weight in weights:
    fprops = matplotlib.font_manager.FontProperties(family='Alegreya Sans', 
                                                    weight=weight)
    print weight+(12-len(weight))*' ', matplotlib.font_manager.findfont(fprops)

输出:

weight       file name 
----------------------------------------------------------------------
ultralight   /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Light.ttf
light        /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Light.ttf
normal       /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Thin.ttf
regular      /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Thin.ttf
book         /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Thin.ttf
medium       /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Medium.ttf
roman        /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Medium.ttf
semibold     /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
demibold     /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
demi         /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
bold         /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
heavy        /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
extra bold   /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-ExtraBold.ttf
black        /hmi/kme/.fonts/Alegreya_Sans/AlegreyaSans-Black.ttf

这个问题怎么解决,为什么会出现这种情况?谢谢!
编辑:
当然,在文件夹/hmi/kme/.fonts/Alegreya_Sans/中有更多的文件。
完整列表如下:
AlegreyaSans-BlackItalic.ttf
AlegreyaSans-BoldItalic.ttf
AlegreyaSans-ExtraBoldItalic.ttf
AlegreyaSans-Italic.ttf
AlegreyaSans-Light.ttf
AlegreyaSans-Medium.ttf
AlegreyaSans-ThinItalic.ttf
AlegreyaSans-Black.ttf
AlegreyaSans-Bold.ttf
AlegreyaSans-ExtraBold.ttf
AlegreyaSans-LightItalic.ttf
AlegreyaSans-MediumItalic.ttf
AlegreyaSans-Regular.ttf
AlegreyaSans-Thin.ttf
我的系统:
OpenSuse 13.1 python 2.7
matplotlib 版本 1.4.3

使用相同版本的matplotlib和python,但在Mac(10.10.5)上,我得到了不同的结果。你得到的是AlegreyaSans-Thin.ttf,而我得到的是AlegreyaSans-Regular.ttf,你得到的是AlegreyaSans-ExtraBold.ttf,而我得到的是AlegreyaSans-Bold.ttf。其他一切都是相同的。不确定这是否有任何帮助,但至少增加了一个数据点! - tmdavison
哦,其实这很奇怪。如果字体直接放在$HOME/.fonts中,我在上面的评论中得到的结果是正确的。但是,如果我将它们移动到子目录$HOME/.fonts/Alegreya_Sans中,就会得到与您相同的结果。 - tmdavison
@tom 这听起来非常奇怪。这怎么可能呢?我想知道matplotlib是使用什么来检测字体重量的。显然他们不是在解析文件名 :) 很遗憾我不理解fontList.cache中的语法,所以即使手动修复也无法完成。还有其他的想法吗? - carlo_barth
你又清除字体缓存了吗?抱歉,我对font_manager的工作原理不是很了解,但希望很快会有更有经验的人过来 :) - tmdavison
这可能也是一个后端的问题吗?请在此处尝试:https://dev59.com/G2nWa4cB1Zd3GeqPzlpb - tmdavison
显示剩余2条评论
2个回答

2
谢谢您发布这篇文章——我也遇到了类似的问题,当我尝试安装Fira Sans字体以配合matplotlib使用时,无法显示正确的字重。您关联字重与文件名的诊断非常有帮助。
在Mac上,我通过删除计算机上所有Fira Sans .ttf文件并通过Font Book重新安装来解决了我的问题。结果发现,以前我曾经将几个Fira Sans字体文件(包括FiraSans-Regular)放在其他字体目录中,当时我不知道自己在做什么。随后,当我尝试使用Font Book安装Fira Sans时,regular字体未能正确安装,导致fontmanager选择了奇怪的字体。
简而言之,如果您运行上述诊断并且在给定字重旁边看不到预期的文件名,请检查字体是否已在Font Book中正确安装。

2
我手动使用一个解决方法修复了问题。不管怎样,这似乎是一个错误。正如Tom所提到的,我将所有字体复制到$HOME/.fonts没有子目录。这改变了我在问题中给出的脚本的输出结果。为了找出问题所在,我尝试以以下方式打印Alegreya和Alegreya Sans的weightstyle的所有组合:
import matplotlib
matplotlib.use('Qt4Agg')
print matplotlib.get_backend()
import matplotlib.pyplot as plt

alignment = {'horizontalalignment':'center', 'verticalalignment':'baseline'}
alegreya_weights = { 'Alegreya': ['regular', 'bold', 'black'],
                     'Alegreya Sans': ['ultralight', 'light', 'regular', 
                                       'medium', 'bold', 'extra bold', 
                                       'black'] }
styles = ['normal', 'italic']

combinations = []
for family in alegreya_weights.keys():
    for style in styles:
        for weight in alegreya_weights[family]:
            combinations.append((family, weight, style))
N = len(combinations)

def textPlot(ax, i, N, family, weight, style):
    y = 1.-(1./float(N)) -float(i)/(float(N)+1)
    ax.text(0.5, y, family+' '+weight+' '+style, 
            family=family, weight=weight, style = style, 
            fontsize = 30, **alignment)

fig = plt.figure(figsize=(8, .7*N), frameon=False)
ax = plt.gca()
ax.axis('off')
plt.xlim((0.,1.))
plt.ylim((0.,1.))

for i,c in enumerate(combinations):
    textPlot(ax, i, N, c[0], c[1], c[2])

plt.show()

原文已经是英文了,我直接翻译成中文:

事实证明,只有 AlegreyaSans-Regular.ttf 被替换成了 AlegreyaSans-Thin.ttf。我无法确定这是否与单词 "Thin" 有关,matplotlib-syntax 中将其称为 "ultralight"。我在 $HOME/.cache/matplotlib/fontList.cache 中用 "AlegreyaSans-Regular.ttf" 替换了 "AlegreyaSans-Thin.ttf",以解决这个问题。

现在,以上脚本生成的图片如下所示:无法检测到 Thin (ultralight) 字体

enter image description here

感谢Tom提供的任何帮助。

Matplotlib目前在这个问题上有一个开放的问题。当向Matplotlib添加字体时,不幸的是你必须删除所有的“thin”文件! - Luke Davis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接