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

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

问题描述

使用默认的

在图像上看到,刻度标签中的乘法和一些减号已被其他字符替换.如果我使用LaTeX(通过将'text.usetex'设置为 True ),则所有内容都能很好地呈现.为什么会发生这种情况,更重要的是,如何在不将数学文本更改为LaTeX的情况下进行修复?

其他信息

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

  mathtext.py:866:MathTextWarning:字体默认"没有"\ times"的字形[U + d7]MathTextWarning)mathtext.py:867:MathTextWarning:用虚拟符号代替.警告(用虚拟符号替换.",MathTextWarning) 

请注意,指数中出现的减号会正确显示.如果我省略'mathtext.fontset':'cm',并产生另一个类似的警告,则这些也可能不会呈现:

  mathtext.py:866:MathTextWarning:字体默认"没有-"的字形[U + 2212]MathTextWarning)mathtext.py:867:MathTextWarning:用虚拟符号代替.警告(用虚拟符号替换.",MathTextWarning) 

此外,如果我在 rcParams 中包含'axes.unicode_minus':False (并保留'mathtext.fontset':'cm'),尽管减号仍然存在问题,但所有负号都能正确渲染.

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

错误报告

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

matplotlib 3.1.0的更新

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

 # 强制绘制图形带有warnings.catch_warnings():warnings.simplefilter('ignore',category = MathTextWarning)fig.canvas.draw() 

使用

 #强制绘制图形导入日志logger = logging.getLogger('matplotlib.mathtext')original_level = logger.getEffectiveLevel()logger.setLevel(logging.ERROR)带有warnings.catch_warnings():warnings.simplefilter('ignore',category = MathTextWarning)fig.canvas.draw()logger.setLevel(原始级别) 

现在,

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

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')

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?

Additional information

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)

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)

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.

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.

Bug report

This has been submitted as a bug report to Matplotlib.

解决方案

Cause of problem

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

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

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.

Solution

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')

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.

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 $...$.

Update for matplotlib 3.1.0

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()

with

    # 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)

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

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

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