Description
Bug summary
I tested the font customization and fallback functionality in Matplotlib, and also tested whether this works with mathematical formulas.
However, I found that without mathematical formulas (i.e., text not containing formulas wrapped by $ $
), Matplotlib handles fallback properly. For example, when I set rcParams['font.family']=['monospace', custom_font_name, 'sans-serif']
, any unsupported Chinese characters in monospace will automatically fallback to custom_font_name
, which refers to a custom font.
But, when math formulas are included in the text, only characters supported by monospace are rendered correctly, while Chinese characters fail to be rendered properly due to "glyph missing".
Code for reproduction
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# Can be get from https://github.com/adobe-fonts/source-han-serif/releases/download/2.003R/14_SourceHanSerifCN.zip
FONT_PATH = './SourceHanSerifCN-Regular.otf'
fm.fontManager.addfont(FONT_PATH)
font_props=fm.FontProperties(fname=FONT_PATH)
font_name=font_props.get_name()
# Custom font
font_name
plt.rcParams['font.family']=['monospace', font_name, 'sans-serif']
# Set a mathtext font
plt.rcParams["mathtext.fontset"]='cm'
import numpy as np
x=np.linspace(0,10,num=1000)
y=np.sin(x)
# This works perfectly, "正弦函数" will be rendered with the custom font while other chars will be rendered with monospace
plt.xlabel('x')
plt.ylabel(r'sin(x)')
plt.title('正弦函数 Sine Function')
plt.grid()
plt.plot(x,y)
# However, "正弦函数" here won't fallback to the custom font. "Sine Function" will be rendered with monospace.
plt.xlabel('x')
plt.ylabel(r'sin(x)')
plt.title(r'正弦函数 Sine Function : '+r'$sin(x)$')
plt.grid()
plt.plot(x,y)
Actual outcome
Image produced by the first plot
:
Image produced by the second plot
:
(Note that sin(x)
in the title is rendered with specified mathtext font)
Related warnings from output:
WARNING:matplotlib.mathtext:Font 'default' does not have a glyph for '\u6b63' [U+6b63], substituting with a dummy symbol.
WARNING:matplotlib.mathtext:Font 'default' does not have a glyph for '\u5f26' [U+5f26], substituting with a dummy symbol.
WARNING:matplotlib.mathtext:Font 'default' does not have a glyph for '\u51fd' [U+51fd], substituting with a dummy symbol.
WARNING:matplotlib.mathtext:Font 'default' does not have a glyph for '\u6570' [U+6570], substituting with a dummy symbol.
Expected outcome
I expected "正弦函数" to be rendered with my custom font in the second plot
, instead of dummy symbols.
Additional information
- I've tested this short code snippet on both Google Colab and my local machine, and I reproduced the issue every time.
- I spent the whole afternoon trying to figure out where the problem might be, but this is a bit beyond my ability. I suspect it might be in this part of the code: https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/_mathtext.py (or other related modules) , I hope this will help.
Operating system
Ubuntu 22.04.3 LTS (Google Colab), Windows (Local machine)
Matplotlib Version
3.8.0 (Google Colab), 3.9.2 (Local machine)
Matplotlib Backend
module://matplotlib_inline.backend_inline
Python version
3.10.12
Jupyter version
6.5.5
Installation
pip