Matplotlib 2 mathtext: Glyph errors in tick labels

I observed errors when rendering math in matplotlib 2.0.2 when using the standard mathtext unlike LaTeX . It seems that some glyphs (in my case the minus and the multiplication sign) are not recognized by the mathematical text. What is really strange is that an error only occurs when these specific glyphs appear in tick marks. When I intentionally type some expression for the mafia, for example. the name of the picture, it works great.

Consider the example below and the resulting 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') 

test.png

As you can see in the image, the multiplication and some minus signs in the label labels are replaced with other symbols. If I use LaTeX (setting 'text.usetex' to True ), everything will look beautiful. Why is this happening, and more importantly, how can I fix it without changing from mathtext to LaTeX?

Additional Information

This is a warning that is printed when the sample code runs:

 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) 

Please note that minus signs appearing in exhibitors are displayed correctly. They also do not appear, possibly if I leave 'mathtext.fontset': 'cm' , creating 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 rcParams (and keep 'mathtext.fontset': 'cm' ), all minus signs are displayed correctly, although the problem remains for the multiplication signs.

Multiplication sign error does not seem to be a problem in older versions of matplotlib (I tested 1.5.1, 1.4.3 and 1.3.1). However, these matplotib insist on producing only tick marks at 10⁻², 10⁻¹, 1, 10, 10², etc., therefore, the multiplication sign is never needed.

+7
source share
2 answers

Cause of the problem

Now I understand what is happening. All yticklabels have a format similar to

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

which works great for main labels where the \times10^{-2} part is missing. I believe this does not work for small labels, because \times does not work inside \mathdefault{} . As indicated here , \mathdefault{} used to create plain (non-mathematical) text with the same font as the mathematical text, with the restriction that much fewer characters are available. Since everything in \mathdefault{} is mathematical, using \mathdefault{} completely redundant and can therefore be safely removed. This solves the problem.

Decision

This can be resolved using the matplotlib tick formatting tools. However, I would like to preserve the standard (secondary) label positions and (supposed) formatting, and therefore a simpler solution would be to simply \mathdefault part of the 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 difficulty with writing this fix is ​​that you cannot get tick marks before the shape is drawn. So we need to call fig.canvas.draw() . This will raise a warning that I put down. It also means that you must call fix() as late as possible so that all axes are displayed the same way as at the end. Finally (as mentioned in the question), 'axes.unicode_minus' was set to False to fix a similar problem with minus signs.

Resulting Image: test.png LaTeX's keen eye may notice that something else is a little wrong with xticklabels cons. This is not related to the question, but because the numbers in xticklabels are not enclosed in $...$ .

Update for matplotlib 3.1.0

Starting with matplotlib version 3.1.0, a warning is sent through the logging module, not warnings . To disable 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 was sent through logging or warnings .

0
source

I believe that STIX fonts are an acceptable replacement for computer modern.

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

This produces the following output on my laptop:

enter image description here

+6
source

Source: https://habr.com/ru/post/1273302/


All Articles