A few days ago, I found that Matplotlib can not show some Unicode characters (some Chinese characters) using its default settings. In the rendered output image, Chinese characters are shown as blank boxes. After reading a lot of posts about this issue, I am finally clear about how to use Unicode characters properly with Matplotlib.1

The reason that Chinese characters are shown as boxes is that Matplotlib’s default font does not support Chinese. In order to use Chinese, we need to tell Matplotlib to use a font which supports Chinese. Or, more directly, we can provide the path of a Chinese font to Matplotlib.

This post assumes that fc-list is available on your system. If this is not the case, you should first install fontconfig. On Linux, fontconfig is usually pre-installed, so no need to worry. On Windows, you can install MiKTeX or TeX Live in order to use fc-list.

Specify Chinese font by name

The first way to use Chinese is to give a valid font name to Matplotlib. Before going on to the next step, make sure that there are Chinese fonts on your system. If that is not the case, or if you want to try a new Chinese font, for example, Source Han Serif recently released by Google and Adobe. You should first install Chinese fonts on your system. If you do not know how to install fonts on Linux or Windows, see here and here for detailed guides.

Find valid Chinese fonts

Matplotlib provides the FontManager class to deal with fonts. This class has an attribute ttflist which provides a list of font files found by Matplotlib. We can also get each font’s name easily from the font list. The problem is that we do not know which of these fonts support Chinese.

This is when fc-list comes to help. This commnd can help us find Chinese fonts installed on the system. The command fc-list :lang=zh will list all the available Chinese fonts on your system. But it should be noted that not all Chinese fonts are indexed by Matplotlib. Some of the ttc font files can not be used by Matplotlib. So we need to find the intersection of avaiable Chinese fonts and fonts indexed by Matplotlib.

Use a font

After we have found a valid Chinese font indexed by Matplotlib. We can tell Matplotlib to use it by changing the Matplotlib rc in our script. In this way, all the following plot command will use the new font. Suppose that you have installed “STKaiti” on your system, the following code will use it to render Chinese:

import matplotlib as mpl
font_name = "STKaiti"
mpl.rcParams['font.family']=font_name
mpl.rcParams['axes.unicode_minus']=False # in case minus sign is shown as box

plt.text(0.5, 0.5, s=u'测试')
plt.show()

In the above code, font_name can be the name of any valid Chinese font. If you just want to use a Chinese font for a particular command, you can directly specify the font’s name in the plotting command. Like the following code:

plt.text(0.5, 0.5, s=u'测试', fontname=font_name)

This is my prefered way of using Chinese fonts with Matplotlib.

Specify Chinese font by path

In order to use any font in our system, We should try the second way — directly give a font’s path to Matplotlib. The code is like this:

import matplotlib.font_manager as mfm
import matplotlib.pyplot as plt

font_path = "/usr/share/fonts/custom/simhei.ttf"
prop = mfm.FontProperties(fname=font_path)
plt.text(0.5, 0.5, s=u'测试', fontproperties=prop)
plt.show()

where font_path is the path to a Chinese font on your system.

Conclusion

Both the two ways are easy to follow. You can choose whichever suits your need best. For the complete code and also info on how to find available Chinese fonts on your system, please refer to the code on this Github repo.


References


  1. While this post is about how to show Chinese Characters, it should work for other languages too, shoud you change the settings accordingly.