前言
在使用matplotlib.pyplot
画图时,默认情况下都是黑体字,很不美观。如果含有中文,可能无法显示;显示了中文之后英文字体就不能使用。本文针对这些问题逐一给出解决方案。
同时设置中英文字体
我们都知道,按照下面的代码是无法显示中文字体的。
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(100)
y = np.sin(x/6)
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.title("正弦函数的图象")
plt.plot(x,y,label='$\sin x$')
plt.legend()
plt.show()
代码中默认字体缺少对中文的支持,从而画出来是下图(左)这样,原本的中文标题变成了一堆方框。在源代码中加入plt.rcParams['font.family'] = 'KaiTi'
可以提供楷体支持(同时加入plt.rc('axes',unicode_minus=False)
以正确显示负号),从而画出下图(右),以楷体形式正确显示中文。
现在有一个问题:我想在正确显示中文的同时,设置英文字体为 Times New Roman。网上很多人都提供下面的办法:
plt.rcParams['font.family'] = ['KaiTi', 'Times New Roman']
这个办法是错误的,英文字体仍然无法正常显示。正确的做法是在代码中加入以下内容:
plt.rcParams['mathtext.fontset'] = 'stix'
plt.xticks(fontproperties = 'Times New Roman')
plt.yticks(fontproperties = 'Times New Roman')
从而图中所有的英文、数字都变成了 Times New Roman 字体,如下图(左)所示:
当然,如果你和我一样更喜欢用 Euclid 字体(Latex 默认风格字体),那么只需要加入下面这些代码,画出来的图如上图(右)所示。
plt.rcParams['mathtext.fontset'] = 'cm'
plt.xticks(fontproperties = 'Euclid')
plt.yticks(fontproperties = 'Euclid')
注意:如果你想实现中英文文本混排,比如将上面的标题改为“正弦函数的 figure”,这是不行的,使用plt.title("正弦函数的图象 figrue")
的结果如下(左)所示,英文正文逃脱了字体的控制,还是丑陋的默认黑体。
这种情况下,可以使用 Latex 公式来表示正文,比如plt.title("正弦函数的图象 $\mathrm{figure}$")
的结果如上图(右)所示。因为正文不应该是斜体字,所以使用\mathrm
将英文文本变成正体字。
只含英文文本的环境
这种情况只需要加入下面两行代码就能够使字体全部变为标准的 Euclid 字体。
plt.rcParams['font.family'] = 'Euclid'
plt.rcParams['mathtext.fontset'] = 'cm'
当然,如果你更喜欢 Times New Roman 字体,那么可以改用以下的代码:
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['mathtext.fontset'] = 'stix'
关于 seaborn 库的字体设置
前文提到的都是matplotlib.pyplot
画图时的字体设置。Seaborn 其实也是利用该库画图,但是有时候不起作用,比如下面一段代码(你只需注意第
6
6
6 到
10
10
10 行的代码):
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# 设置字体、背景(白色)以及图片大小
plt.rcParams['axes.facecolor'] = 'w'
plt.figure(figsize=(10,10))
plt.rcParams['mathtext.fontset'] = 'stix'
plt.xticks(fontproperties = 'Times New Roman')
plt.yticks(fontproperties = 'Times New Roman')
# 化学式名字数组
name_list = ['$\mathrm{Na_2O}$','$\mathrm{MgO}$','$\mathrm{K_2O}$','$\mathrm{SiO_2}$','$\mathrm{Al_2O_3}$','$\mathrm{BaO}$','$\mathrm{CuO}$','$\mathrm{SO_2}$','$\mathrm{PbO}$','$\mathrm{SrO}$','$\mathrm{P_2O_5}$','$\mathrm{CaO}$','$\mathrm{Fe_2O_3}$']
# 模拟出数据
np.random.seed(114)
data = np.random.rand(13,13) * 2 - 1
# 构造 mask 矩阵的形状
mask = np.zeros_like(data)
# 将矩阵对角线右上部分置为 True,隐藏
mask[np.triu_indices_from(mask)] = True
for i in range(13):
data[i][i] = 1.
mask[i][i] = False
# 画热图
ax = sns.heatmap(data,annot=True,fmt='.2g',cbar_kws={"orientation": "horizontal","shrink":0.5},square=True,mask=mask,cmap="YlGnBu")
ax.set_yticklabels(name_list,rotation = 0)
for i in range(len(name_list)):
plt.text(i + 0.2,i - 0.2,name_list[i],rotation = 45)
plt.show()
该代码画出的图片如下图(左)所示,这张图很明显存在不足,热图上的数字以及热条旁边的刻度都是默认的黑体。这时我们可以尝试使用sns.set
方法,直接对 seaborn 进行参数设置,代码如下所示。画出来的图如下图(右)所示,可以看到克服了这些缺点。
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# 设置字体、背景(白色)以及图片大小
sns.set(rc={'font.sans-serif': ['Times New Roman'],'mathtext.fontset':'stix'})
plt.rcParams['axes.facecolor'] = 'w'
plt.figure(figsize=(10,10))
# 化学式名字数组
name_list = ['$\mathrm{Na_2O}$','$\mathrm{MgO}$','$\mathrm{K_2O}$','$\mathrm{SiO_2}$','$\mathrm{Al_2O_3}$','$\mathrm{BaO}$','$\mathrm{CuO}$','$\mathrm{SO_2}$','$\mathrm{PbO}$','$\mathrm{SrO}$','$\mathrm{P_2O_5}$','$\mathrm{CaO}$','$\mathrm{Fe_2O_3}$']
# 模拟出数据
np.random.seed(114)
data = np.random.rand(13,13) * 2 - 1
# 构造 mask 矩阵的形状
mask = np.zeros_like(data)
# 将矩阵对角线右上部分置为 True,隐藏
mask[np.triu_indices_from(mask)] = True
for i in range(13):
data[i][i] = 1.
mask[i][i] = False
# 画热图
ax = sns.heatmap(data,annot=True,fmt='.2g',cbar_kws={"orientation": "horizontal","shrink":0.5},square=True,mask=mask,cmap="YlGnBu")
ax.set_yticklabels(name_list,rotation = 0)
for i in range(len(name_list)):
plt.text(i + 0.2,i - 0.2,name_list[i],rotation = 45)
plt.show()