我在使用默认的mathtext而不是LaTeX数学渲染引擎时,在matplotlib 2.0.2中渲染数学时观察到错误。似乎一些字形(在我的情况下是减号和乘号)不能被mathtext识别。真正奇怪的是,只有当这些特定字形出现在刻度标签中时才会出现错误。当我刻意将一些蹩脚的表达式输入到例如图标题,它工作正常。
考虑以下示例和结果图像:
import matplotlib
import matplotlib.pyplot as plt
# Customize matplotlib
matplotlib.rcParams.update({# Use mathtext, not LaTeX
'text.usetex': False,
# Use the Computer modern font
'font.family': 'serif',
'font.serif': 'cmr10',
'mathtext.fontset': 'cm',
})
# Plot
plt.semilogy([-0.03, 0.05], [0.3, 0.05])
plt.title(r'$-6\times 10^{-2}$')
plt.savefig('test.png')
如图所示,刻度标签中的乘法和一些减号已被其他字符替换。如果我使用LaTeX(通过将'text.usetex'
设置为True
),一切都很好。为什么会发生这种情况,更重要的是,如何在不将mathtext更改为LaTeX的情况下修复它?
这是运行示例代码时打印的警告:
mathtext.py:866: MathTextWarning: Font 'default' does not have a glyph for '\times' [U+d7]
MathTextWarning)
mathtext.py:867: MathTextWarning: Substituting with a dummy symbol.
warn("Substituting with a dummy symbol.", MathTextWarning)
请注意,指数中出现的减号会正确呈现。如果我遗漏'mathtext.fontset': 'cm'
,这些也不会渲染,产生另一个类似的警告:
mathtext.py:866: MathTextWarning: Font 'default' does not have a glyph for '-' [U+2212]
MathTextWarning)
mathtext.py:867: MathTextWarning: Substituting with a dummy symbol.
warn("Substituting with a dummy symbol.", MathTextWarning)
此外,如果我在'axes.unicode_minus': False
中包含rcParams
(并保持'mathtext.fontset': 'cm'
),所有减号都会正确呈现,但问题仍然存在于乘法符号上。
在旧版本的matplotlib上,乘法符号错误似乎不是问题(我已经测试过1.5.1,1.4.3和1.3.1)。然而,这些matplotib坚持只生产10-2,1,10 -1,1,10,10 2等刻度标签,因此不需要乘法符号。
我发现STIX字体可以替代现代计算机。
import matplotlib
import matplotlib.pyplot as plt
# Customize matplotlib
matplotlib.rcParams.update(
{
'text.usetex': False,
'font.family': 'stixgeneral',
'mathtext.fontset': 'stix',
}
)
# Plot
plt.semilogy([-0.03, 0.05], [0.3, 0.05])
plt.title(r'$-6\times 10^{-2}$')
plt.savefig('test.png')
这会在我的笔记本电脑上产生以下输出:
我现在明白发生了什么。 yticklabels都有类似的格式
r'$\mathdefault{6\times10^{-2}}$'
这适用于主要的刻度标签,其中没有\times10^{-2}
部分。我认为这对于小标记标签是失败的,因为\times
在\mathdefault{}
内部不起作用。如here所述,\mathdefault{}
用于生成常规(非数学)文本,其字体与用于mathtext的字体相同,但限制的可用符号要少得多。由于\mathdefault{}
内部的所有内容都是数学,因此使用\mathdefault{}
是完全多余的,因此可以安全地删除它。这解决了这个问题。
人们可以使用matplotlib的tick formatters来解决这个问题。但是,我想保留默认(次要)刻度标签位置和(预期)格式,因此更简单的解决方案是简单地删除刻度标签的\mathdefault
部分:
import warnings
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.mathtext import MathTextWarning
# Customize matplotlib
matplotlib.rcParams.update({# Use mathtext, not LaTeX
'text.usetex': False,
# Use the Computer modern font
'font.family': 'serif',
'font.serif': 'cmr10',
'mathtext.fontset': 'cm',
# Use ASCII minus
'axes.unicode_minus': False,
})
# Function implementing the fix
def fix(ax=None):
if ax is None:
ax = plt.gca()
fig = ax.get_figure()
# Force the figure to be drawn
with warnings.catch_warnings():
warnings.simplefilter('ignore', category=MathTextWarning)
fig.canvas.draw()
# Remove '\mathdefault' from all minor tick labels
labels = [label.get_text().replace('\mathdefault', '')
for label in ax.get_xminorticklabels()]
ax.set_xticklabels(labels, minor=True)
labels = [label.get_text().replace('\mathdefault', '')
for label in ax.get_yminorticklabels()]
ax.set_yticklabels(labels, minor=True)
# Plot
plt.semilogy([-0.03, 0.05], [0.3, 0.05])
plt.title(r'$-6\times 10^{-2}$')
fix()
plt.savefig('test.png')
编写此修复程序的棘手部分是,在绘制图形之前无法获取刻度标签。因此,我们需要先打电话给fig.canvas.draw()
。这会引发我已经压制的警告。这也意味着您应该尽可能晚地调用fix()
,以便所有轴都像最终一样绘制。最后(正如问题中已经说明的那样),'axes.unicode_minus'
已被设置为False
以修复与减号相似的问题。
由此产生的图像:敏锐的LaTeX眼睛可能会发现xticklabels中的缺陷仍然略微偏离。这与问题无关,但是因为xticklabels中的数字未包含在$...$
中而发生。