Matplotlib 2 Mathtext:刻度标签中的字形错误 [英] Matplotlib 2 mathtext: Glyph errors in tick labels

查看:962
本文介绍了Matplotlib 2 Mathtext:刻度标签中的字形错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用默认的文字文本,而不是 LaTeX 数学渲染引擎.似乎某些字形(在我的情况下为负号和乘法符号)不能被mathtext识别.真正奇怪的是,仅当这些特定字形出现在刻度标签中时,才会发生错误.当我故意在其中输入一些数学表达式时图形标题,效果很好.

I've observed errors when rendering math in matplotlib 2.0.2, when using the default mathtext as opposed to the LaTeX math rendering engine. It seems that some glyphs (in my case the minus and the multiplication sign) is not recognized by mathtext. What makes it really weird is that the error only occurs when these particular glyphs appear in tick labels. When I deliberately type some mathy expression into e.g. the figure title, it works fine.

请考虑以下示例和生成的图像:

Consider the below example and the resultant image:

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),则所有内容都能很好地呈现.为什么会发生这种情况,更重要的是,如何在不将数学文本更改为LaTeX的情况下进行修复?

As seen on the image, multiplication and some minus signs in the tick labels have been replaced with other characters. If I use LaTeX (by setting 'text.usetex' to True), everything renders nicely. Why does this happen, and more importantly, how can I fix it without changing from mathtext to LaTeX?

这是在运行示例代码时显示的警告:

This is the warning which gets printed when running the example code:

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'并产生另一个类似的警告,这些也可能无法呈现:

Note that the minus signs appearing in exponents get rendered correctly. These also do not render probably if I leave out 'mathtext.fontset': 'cm', producing another, similar warning:

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)

此外,如果我在rcParams中包含'axes.unicode_minus': False(并保留'mathtext.fontset': 'cm'),则所有负号都将正确呈现,尽管问题仍然存在于乘号上.

Also, if I include 'axes.unicode_minus': False in the rcParams (and keep 'mathtext.fontset': 'cm'), all minus signs render properly, though the problem remains for the multiplication signs.

在较旧版本的matplotlib上,乘法符号错误似乎不是问题(我已经测试了1.5.1、1.4.3和1.3.1).但是,这些matplotib坚持只在10⁻²,10⁻¹,1、10、10²等处生成刻度线标签,因此根本不需要乘法符号.

The multiplication sign error do not seem to be a problem on older versions of matplotlib (I've tested 1.5.1, 1.4.3 and 1.3.1). However, these matplotib's insist on only producing tick labels at 10⁻², 10⁻¹, 1, 10, 10² etc., and so no multiplication sign is ever needed.

推荐答案

问题原因

我现在了解发生了什么. yticklabel的格式都类似于

Cause of problem

I now understand what is going on. The yticklabels all have a format similar to

r'$\mathdefault{6\times10^{-2}}$'

可以很好地用于主要刻度标签,而缺少\times10^{-2}部分.我相信这对于次要刻度标签将失败,因为\times\mathdefault{}内部不起作用.如此处所述,\mathdefault{}用于生成常规(非数学) )的文本,其字体与用于Mathtext的字体相同,但其局限性在于可用的符号要少得多.由于\mathdefault{} 中的所有内容都是数学,因此\mathdefault{}的使用完全是多余的,因此可以安全地删除它.这样就解决了这个问题.

which works fine for major tick labels, where the \times10^{-2} part is absent. I believe this fails for minor tick labels because \times does not work inside of \mathdefault{}. As stated here, \mathdefault{} is used to produce regular (non-math) text with the same font as is used for mathtext, with the limitation that far fewer symbols are available. As everything inside of \mathdefault{} is math, the use of \mathdefault{} is completely redundant, and so it can safely be removed. This solves the issue.

可以使用matplotlib的 tick格式化程序解决此问题.但是,我想保留默认的(较小的)刻度标签位置和(预期的)格式,因此一个更简单的解决方案是简单地剔除刻度标签的\mathdefault部分:

One could solve this using matplotlib's tick formatters. I would like however to keep the default (minor) tick label positions and (intended) formatting, and so an easier solution is simply to rip out the \mathdefault part of the tick labels:

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可以解决带有减号的类似问题.

The tricky part in writing this fix is the fact that you cannot get the tick labels before the figure has been drawn. Thus we need to first call fig.canvas.draw(). This will raise the warning, which I have suppressed. This also means that you should call fix() as late as possible, so that all axes gets drawn as they would in the end. Finally (as stated already in the question), the 'axes.unicode_minus' has been set to False to fix the similar issue with the minus signs.

结果图像: 敏锐的LaTeX眼睛可能会发现,关于xticklabel中的缺点,仍有一些问题.这与问题无关,但会发生,因为xticklabel中的数字未包含在$...$中.

The resultant image: The keen LaTeX eye might spot that something is still slightly off regarding the minuses in the xticklabels. This is unrelated to the question, but happens because the numbers in the xticklabels are not enclosed in $...$.

从matplotlib 3.1.0版开始,警告通过logging模块而不是warnings发出.要使警告静音,请替换

From matplotlib version 3.1.0, the warning is emitted through the logging module, not warnings. To silent the warning, replace

    # Force the figure to be drawn
    with warnings.catch_warnings():
        warnings.simplefilter('ignore', category=MathTextWarning)
        fig.canvas.draw()

使用

    # Force the figure to be drawn
    import logging
    logger = logging.getLogger('matplotlib.mathtext')
    original_level = logger.getEffectiveLevel()
    logger.setLevel(logging.ERROR)
    with warnings.catch_warnings():
        warnings.simplefilter('ignore', category=MathTextWarning)
        fig.canvas.draw()
    logger.setLevel(original_level)

现在将忽略该警告,无论它是通过logging还是warnings发出的.

which now ignores the warning regardless of whether it is emitted through logging or warnings.

这篇关于Matplotlib 2 Mathtext:刻度标签中的字形错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆