發表於 PyQT5Python

【Python】PyQT5 Sin,Cos Matplotlib 動畫應用程式 -5 加入 Matplotlib 的藝術吧!

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


結尾:

不知道大家覺得這樣的系列文好不好 在下面留言告訴我喔
或是有什麼其他的想法都可以告訴我喔~
(不敢公開留言的話可以用 聯絡我 寄信跟我說喔~

那就先這樣啦!
我們下一篇見囉!

ㄅㄅ

作者:

一位 熱愛資工領域、喜歡好笑事物、偶爾打打網球 的學生 ! For A Better Me!

發表迴響

Please log in using one of these methods to post your comment:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.