Hello~ Internet!
終於來到這個系列的第五篇了~ 現在,就在這一篇要進入比較好玩一點的部分了~
在這一篇我想要加入 Matplotlib 的圖片到我們的應用程式中,這次的UI介面檔案我推薦直接去 github 下載喔!
如果還沒看得之前 UI 設計與分離的文章的話,可以點這裡看上一篇介紹喔!
這一篇我們來讓程式加入常用的 Matplotlib 吧!
這篇會介紹到:
- Matplotlib 應用介紹
- Qt5Agg FigureCanvas
- 使用 Numpy 產生資料吧!
- 結合到 MainWindow 囉!
- 中文顯示有問題?
Matplotlib 應用介紹
說到使用 Python 繪圖就一定會想到 Matplotlib 吧!
它可以說是幾乎每個初學者都一定會學到的一個超級好用套件呢!(甚至很多研究者都也是使用它來製作圖表的!)
大家一定在想,如果可以把繪圖放入應用程式中的話,一定可以做出更好的報告成果(或軟體?)吧~
像是我之前就是需要將數據的變化放入應用程式中然後觀察,這時候這樣製作就很方便了!
所以接下來就來看看怎麼製作吧!
Qt5Agg FigureCanvas
因為並沒有任何一個 PyQt5 元件是預設給 Matplotlib 的,所以我們需要客製化一下其他元件囉!
這時我們需要請出一個繪圖的class來幫助我們客製繪圖機制
FigureCanvasQTAgg
所以我們先來設置一下基本設定吧
我們需要指定 Matplotlib 使用 QT5Agg 的繪圖機制,並且更改一下不讓負號的顯示出問題
matplotlib.use('QT5Agg')
matplotlib.rcParams["axes.unicode_minus"] = False
我們創建一個 CanvasRenderer 繼承了剛剛提到的 FigureCanvasQTAgg 以便稍後的客製化
不過,你一定在想為什麼我們需要在用 as 改變 import 的 class 名稱吧!
因為這是為了要讓 PyQt5 跟以前的 PyQt 版本相容啦!
以前繪圖機制的 class 名稱叫做 FigureCanvas!
所以前置的設定完整 code 就像下方這樣
import matplotlib from matplotlib.figure import Figure from matplotlib import pyplot as plt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from PyQt5 import QtWidgets import numpy as np matplotlib.use('QT5Agg') matplotlib.rcParams["axes.unicode_minus"] = False class CanvasRenderer(FigureCanvas): pass
接下來我們來完成 繪圖的部分吧!
創建 Matplotlib 圖表的方式就跟一般的用法一樣,fig, ax 設定好就好了
為了比較清楚 Sin 的波型,我有加入顯示 grid( 格線 )。
然後把 FigureCanvas 繼承的類別也初始化
並且設定它顯示的方式,這行的用意是讓圖表能擴大就擴大,能盡量占滿整個版面就佔滿整個版面
FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
其實 FigureCanvas 初始化設定的 這段寫法也可以改成這樣
詳情可以看這篇 繼承其時每你想的那麼簡單–Feat. super()
super().init(self.fig)
super().setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
super().updateGeometry()
完整的 init funtion 長這樣
class CanvasRenderer(FigureCanvas): def __init__(self, width=5, height=4, dpi=100, layoutInt=111): self.fig = Figure(figsize=(width, height), dpi=dpi) self.fig.suptitle("Sin 正弦波", fontproperties=self.zhfont1) self.axes = self.fig.add_subplot(layoutInt) self.axes.clear() self.axes.grid(True) FigureCanvas.__init__(self, self.fig) FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self)
使用 Numpy 產生資料吧 !
接下來我們來使用 Numpy 幫我們產生 Sin 波的資料吧!
我們在剛剛的 CanvasRenderer 中加入繪圖的 function drawStaticImgae
繪圖資料
X 軸 從 0~20
Y 軸 Sin(0)~Sin(20)
資料設定完之後就可以使用原本的 draw function 囉!
(因為我們是繼承 FigureCanvas 所以原本就內建繪圖的 draw function)
注意: function Name 不要衝突到了!
完整的繪圖 Function 就在下面啦!
def drawStaticImgae(self): # 插入資料 self.X = np.linspace(0, 20, 100) self.Y = np.sin(self.X) # 繪圖 self.axes.set_xlim(0, 20) self.axes.plot(self.X, self.Y, "c") self.axes.set_xlabel("時間", fontproperties=self.zhfont1) self.axes.set_ylabel("震幅", fontproperties=self.zhfont1) self.axes.grid(True) self.draw()
結合到 MainWindow 囉 !
那現在我們就整合到我們的 MainWindow裡面吧!
因為我們的圖表示在UI創建好以後才設定的,所以我們要用擴充的方式加入 MainWindow 裡面,並加入 CentralWidget 裡面
如果還不理解 CentralWidget 的原理的話可以看一下第一篇的講解喔!
這邊就不重複介紹了!
這一段比較簡單就直接上程式碼囉!
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) self.addCanvasToWidget(self.plot_widget) # 擴充 UI def addCanvasToWidget(self, parent=None): self.canvasRenderer = CanvasRenderer() parent.addWidget(self.canvasRenderer)
現在我們的程式就完成啦~
恭喜~ 你現在已經可以盡情地把所有的 Matplotlib 圖表都放進程式中了~
到目前為止都沒有錯誤的話畫面應該是像這樣吧~

等等?! 別心裡太快地對我罵幹
中文有問題是哪招?!
別急! 畢竟我們中文的編碼不一樣嘛!
如果中文或是想要的語系有問題的話可以像我一樣把文字的 ttc 檔案下載下來並且設定路徑然後改變 Matplotlib 的字體就好了喔!
像是這樣!
# 載入字體 zhfont1 = matplotlib.font_manager.FontProperties(fname="resource/font/msjh.ttc") # 改變文字的字體 self.axes.set_xlabel("時間", fontproperties=self.zhfont1) self.axes.set_ylabel("震幅", fontproperties=self.zhfont1)
當然~這次也是一樣的~
完整程式碼我都放在 gtihub 上給大家直接下載喔~
在這裡 github ep5
結尾:
不知道大家覺得這樣的系列文好不好 在下面留言告訴我喔
或是有什麼其他的想法都可以告訴我喔~
(不敢公開留言的話可以用 聯絡我 寄信跟我說喔~
那就先這樣啦!
我們下一篇見囉!
ㄅㄅ