Python 3下Matplotlib畫圖中文顯示亂碼的解決方法

Matplotlib是Python的一個很好的繪圖包,但是其本身並不支持中文(貌似其默認配置中沒有中文字體),所以如果繪圖中出現了中文,就會出現亂碼。

在《用Python作科學計算》一書中,有一個最小二乘擬合的例子,我用Python 3.3重寫的代碼如下:

# 最小二乘擬合示例
import numpy as np
from scipy.optimize import leastsq
import matplotlib.pyplot as plt
import matplotlib

def func(x, p):
    """
    數據擬合所用的函數: A*sin(2*pi*k*x + theta)
    """
    A, k, theta = p
    return A*np.sin(2*np.pi*k*x+theta)   

def residuals(p, y, x):
    """
    實驗數據x, y和擬合函數之間的差,p爲擬合需要找到的係數
    """
    return y - func(x, p)

x = np.linspace(0, -2*np.pi, 100)
A, k, theta = 10, 0.34, np.pi/6 # 真實數據的函數參數
y0 = func(x, [A, k, theta]) # 真實數據
y1 = y0 + 2 * np.random.randn(len(x)) # 加入噪聲之後的實驗數據    

p0 = [7, 0.2, 0] # 第一次猜測的函數擬合參數

# 調用leastsq進行數據擬合
# residuals爲計算誤差的函數
# p0爲擬合參數的初始值
# args爲需要擬合的實驗數據
plsq = leastsq(residuals, p0, args=(y1, x))

print("真實參數:", [A, k, theta])
print("擬合參數", plsq[0]) # 實驗數據擬合後的參數

plt.plot(x, y0, label="真實數據")
plt.plot(x, y1, label="帶噪聲的實驗數據")
plt.plot(x, func(x, plsq[0]), label="擬合數據")
plt.legend()
plt.savefig('fit.jpg')
plt.show()

運行結果如下:

真實參數: [10, 0.34, 0.5235987755982988]
擬合參數 [ 10.02733131   0.3409059   -5.73652932]

這裏圖例使用的是中文,畫出來的圖如下:
raw

可以看出,圖例中的中文並沒有顯示出來。

爲了解決這個問題,可以使用如下方法:

因爲亂碼是Matplotlib缺少中文配置所導致的,所以我們只需要在程序中說明使用中文字體即可。

先選一個字體。在計算機中找到字體,選擇一種中文字體,比如我這裏用的是楷體
楷體

右鍵可以查看其屬性從而得知字體名稱:
shuxing

即該字體文件爲simkai.ttf

然後在程序中定義Matplotlib的字體管理,這裏將其命名爲zhfont1,代碼如下:

zhfont1 = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simkai.ttf')

接着我們只要在繪圖中出現中文的地方加上字體選項即可,在最小二乘擬合的例子中,我們只需要加上語句:

plt.legend(prop=zhfont1)

完整的程序代碼如下:

# 最小二乘擬合示例
import numpy as np
from scipy.optimize import leastsq
import matplotlib.pyplot as plt
import matplotlib

zhfont1 = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simkai.ttf')

def func(x, p):
    """
    數據擬合所用的函數: A*sin(2*pi*k*x + theta)
    """
    A, k, theta = p
    return A*np.sin(2*np.pi*k*x+theta)   

def residuals(p, y, x):
    """
    實驗數據x, y和擬合函數之間的差,p爲擬合需要找到的係數
    """
    return y - func(x, p)

x = np.linspace(0, -2*np.pi, 100)
A, k, theta = 10, 0.34, np.pi/6 # 真實數據的函數參數
y0 = func(x, [A, k, theta]) # 真實數據
y1 = y0 + 2 * np.random.randn(len(x)) # 加入噪聲之後的實驗數據    

p0 = [7, 0.2, 0] # 第一次猜測的函數擬合參數

# 調用leastsq進行數據擬合
# residuals爲計算誤差的函數
# p0爲擬合參數的初始值
# args爲需要擬合的實驗數據
plsq = leastsq(residuals, p0, args=(y1, x))

print("真實參數:", [A, k, theta])
print("擬合參數", plsq[0]) # 實驗數據擬合後的參數

plt.plot(x, y0, label="真實數據")
plt.plot(x, y1, label="帶噪聲的實驗數據")
plt.plot(x, func(x, plsq[0]), label="擬合數據")
plt.legend(prop=zhfont1)
plt.savefig('fit.jpg')
plt.show()

運行後可以畫出圖像
fit

這樣中文圖例便正常顯示了。

此外,在用LaTex寫論文時,我們經常需要插入矢量格式的圖,最好是eps或者pdf格式的圖,即將存圖的那行代碼改爲

plt.savefig('fit.pdf')

但是使用以上代碼保存生成的圖爲pdf格式時,可能會出現錯誤(如果沒有出現,可以無視下面的內容了),錯誤提示缺少第三方字體。
error

這時我們只要把剛纔的字體文件複製到Matplotlib的字體文件夾中即可,我是把Python安裝到了E:\Program Files中,所以只要把simkai.ttf文件複製到如下文件夾中就ok了。

E:\Program Files\Python\Lib\site-packages\matplotlib\mpl-data\fonts\ttf

如此一來,程序便能正確輸出pdf格式的圖片了。

最後,再附上一個簡單的例子(注:該例子改用了宋體-simsun.ttc,但圖像無法存成pdf格式,但若換成simhei.ttf或者simkai.ttf均可以存成pdf格式),代碼如下:

#中文標題與座標軸示例
import matplotlib.pyplot as plt
import matplotlib
zhfont1 = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\simsun.ttc')
plt.xlabel('性別',fontproperties=zhfont1)
plt.ylabel('人數',fontproperties=zhfont1)
plt.title('直方圖',fontproperties=zhfont1)
plt.xticks( (0,1),('男','女') ,fontproperties=zhfont1)
plt.bar(left=(0,1), height=(1,0.5), width=0.35)
plt.show()

畫出的圖像如下:
p2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章