顯示 Matplotlib 圖表 ( 靜態圖表、圖表動畫 )
這篇教學會介紹如何運用 PyQt6 的 QGraphicsView,在 PyQt6 中顯示 Matplotlib 圖表,最後還會搭配 QTimer 實作圖表動畫 ( 不斷移動的正弦波形 )。
快速導覽:
因為 Google Colab 不支援 PyQt6,所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda )。
安裝 Matplotlib 和 NumPy 函式庫
輸入下列指令安裝 Matplotlib 和 NumPy 函式庫,根據個人環境使用 pip 或 pip3,如果使用 Anaconda Jupyter,已經內建 Matplotlib 和 NumPy 函式庫。
pip install matplotlib
pip install numpy
Matplotlib 顯示正弦波形
參考「折線圖 Line Chart」教學範例,下方的程式碼執行後,就會產生 0~2 之間的正弦波形。
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(3,2), dpi=150)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
line.set_data([], [])
x = np.linspace(0, 2, 100)
y = np.sin(5 * np.pi * x)
line.set_data(x, y)
plt.show()
PyQt6 顯示 Matplotlib 圖表
如果要在 PyQt6 中顯示 Matplotlib 圖表,需要額外載入 matplotlib.backends.backend_qt5agg 模組,並將 Matplotlib 設定為使用 Qt5Agg,接著就能透過 PyQt6 的 QGraphicsView 元件顯示圖表,下方的程式碼執行後,會開啟 PyQt6 視窗顯示 Matplotlib 圖表 ( 注意 import 函式庫的順序 )。
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg") # 使用 Qt5
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
# 建立正弦波繪圖函式
def sinWave(i=0):
fig = plt.figure(figsize=(3,2), dpi=100)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
line.set_data([], [])
x = np.linspace(0, 2, 100)
y = np.sin(5 * np.pi * (x - 0.01*i))
line.set_data(x, y)
return fig
canvas = FigureCanvas(sinWave()) # 將圖表繪製在 FigureCanvas 裡
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(360, 240)
graphicview = QtWidgets.QGraphicsView(MainWindow) # 建立顯示圖片元件
graphicview.setGeometry(0, 0, 360, 240)
graphicscene = QtWidgets.QGraphicsScene() # 建立場景
graphicscene.setSceneRect(0, 0, 340, 220)
graphicscene.addWidget(canvas) # 場景中放入圖表
graphicview.setScene(graphicscene) # 元件中放入場景
MainWindow.show()
sys.exit(app.exec())
class 寫法:
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg") # 使用 Qt5
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
class mainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('oxxo.studio')
self.resize(360, 240)
self.ui()
def ui(self):
canvas = FigureCanvas(self.sinWave()) # 將圖表繪製在 FigureCanvas 裡
graphicview = QtWidgets.QGraphicsView(self) # 建立顯示圖片元件
graphicview.setGeometry(0, 0, 360, 240)
graphicscene = QtWidgets.QGraphicsScene() # 建立場景
graphicscene.setSceneRect(0, 0, 340, 220)
graphicscene.addWidget(canvas) # 場景中放入圖表
graphicview.setScene(graphicscene) # 元件中放入場景
def sinWave(self, i=0):
fig = plt.figure(figsize=(3,2), dpi=100)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
line.set_data([], [])
x = np.linspace(0, 2, 100)
y = np.sin(5 * np.pi * (x - 0.01*i))
line.set_data(x, y)
return fig
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = mainWindow()
Form.show()
sys.exit(app.exec())
PyQt6 顯示 Matplotlib 圖表動畫
能夠顯示圖表後,就能再透過 QTimer 定時器功能,不斷改變圖表內容,就能實現圖表動畫的效果 ( 注意,繪製圖表時先加入 plt.close() 關閉已存在但不顯示的圖表,避免圖表數量到達上限 )。
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg") # 使用 Qt5
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
def sinWave(i=0):
plt.close() # 執行時先刪除已有的 plt
fig = plt.figure(figsize=(3,2), dpi=100)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
line.set_data([], [])
x = np.linspace(0, 2, 100)
y = np.sin(5 * np.pi * (x - 0.01*i))
line.set_data(x, y)
return fig
canvas = FigureCanvas(sinWave())
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(360, 240)
graphicview = QtWidgets.QGraphicsView(MainWindow)
graphicview.setGeometry(0, 0, 360, 240)
graphicscene = QtWidgets.QGraphicsScene()
graphicscene.setSceneRect(0, 0, 340, 220)
graphicscene.addWidget(canvas)
graphicview.setScene(graphicscene)
dx = 0 # x 位移初始值
def count():
global dx, canvas
dx = dx + 5 # 每次定時器執行位移 5
canvas = FigureCanvas(sinWave(dx)) # 產生新的正弦波圖形
graphicscene.clear() # 清空場景
graphicscene.addWidget(canvas) # 場景放入圖形
timer = QTimer() # 加入定時器
timer.timeout.connect(count) # 設定定時要執行的 function
timer.start(50) # 啟用定時器,設定間隔時間為 500 毫秒
MainWindow.show()
sys.exit(app.exec())
使用 class 寫法:
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg") # 使用 Qt5
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('oxxo.studio')
self.resize(360, 240)
self.t = 0
self.ui()
def ui(self):
self.canvas = FigureCanvas(self.sinWave())
self.graphicview = QtWidgets.QGraphicsView(self)
self.graphicview.setGeometry(0, 0, 360, 240)
self.graphicscene = QtWidgets.QGraphicsScene()
self.graphicscene.setSceneRect(0, 0, 340, 220)
self.graphicscene.addWidget(self.canvas)
self.graphicview.setScene(self.graphicscene)
def sinWave(self, i=0):
fig = plt.figure(figsize=(3,2), dpi=100)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
line.set_data([], [])
x = np.linspace(0, 2, 100)
y = np.sin(5 * np.pi * (x - 0.01*i))
line.set_data(x, y)
plt.close()
return fig
def count(self):
self.t = self.t + 5
self.canvas = FigureCanvas(self.sinWave(self.t))
self.graphicscene.clear()
self.graphicscene.addWidget(self.canvas)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
timer = QTimer() # 加入定時器
timer.timeout.connect(Form.count) # 設定定時要執行的 function
timer.start(50) # 啟用定時器,設定間隔時間為 500 毫秒
sys.exit(app.exec())
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~