PyQtGraph 繪圖


數據繪圖方案

Python語言 的數據可視化(繪圖) 方法,常見的有 Matplotlib 和 PyQtGraph

  • Matplotlib

說到 Python語言 的數據作圖, Matplotlib 當然是最有名的。

優點: 功能完備、成熟穩定、社區生態圈龐大。

缺點: 某些作圖場景性能不高。

  • PyQtGraph

PyQtGraph 是基於Qt 的純Python 庫。

優點: 大數據量的作圖性能高於 Matplotlib, 動態更新圖的性能也比Matplotlib高。

並且和Qt圖形界面框架完美融合,因為它的2D作圖就是基於 Qt View Framework 開發的。

缺點: 作圖功能沒有Matplotlib多,開發社區沒有Matplotlib大。

那么,我們應該使用哪種方案呢?我的建議是:

如果你已經使用Qt開發圖形界面程序了,並且作圖功能是PyQtGraph支持的, 建議使用 PyQtGraph,因為它和Qt界面無縫結合。

否則 使用 Matplotlib。

本文先介紹 PyQtGraph 的使用示例。

PyQtGraph 安裝

pip install pyqtgraph

官方文檔 和 案例

PyQtGraph 官方文檔可以點擊這里查閱

其中包含了很多示例代碼,我們只需運行如下代碼,即可查看這些demo和對應的代碼

import pyqtgraph.examples
pyqtgraph.examples.run()


曲線圖 示例

下面是一個最常見的 根據x/y軸對應的值 作曲線圖的例子

from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg

# 創建 繪制窗口類 PlotWindow 對象,內置一個繪圖控件類 PlotWidget 對象
pw = pg.plot()

# 設置圖表標題、顏色、字體大小
pw.setTitle("氣溫趨勢",color='008080',size='12pt')

# 背景色改為白色
pw.setBackground('w')

# 顯示表格線
pw.showGrid(x=True, y=True)

# 設置上下左右的label
# 第一個參數 只能是 'left', 'bottom', 'right', or 'top'
pw.setLabel("left", "氣溫(攝氏度)")
pw.setLabel("bottom", "時間")

# 設置Y軸 刻度 范圍
pw.setYRange(min=-10,  # 最小值
             max=50)  # 最大值

# 創建 PlotDataItem ,缺省是曲線圖
curve = pw.plot( pen=pg.mkPen('b')) # 線條顏色

hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
temperature = [30, 32, 34, 32, 33, 31, 29, 32, 35, 45]

curve.setData(hour, # x坐標
              temperature  # y坐標
              )

QtGui.QApplication.instance().exec_()


清除畫圖區,重新繪制

如果使用新的數據再次繪圖,可以先調用clear方法清除原來的內容(plotitem),如下

# 清除原來的plot內容
pw.clear()

# 創建 PlotDataItem ,缺省是曲線圖
curve = pw.plot( pen=pg.mkPen('b')) # 線條顏色
hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
temperature = [130, 132, 134, 132, 133,131, 129, 132, 135, 145]

curve.setData(hour, # x坐標
              temperature  # y坐標
              )


PlotWidget 和 GraphicsLayoutWidget

PyQtGraph 中 繪圖控件類 有兩種 PlotWidget 和 GraphicsLayoutWidget, 都是 GraphicsView 子類。GraphicsView 是 Qt 的 QGraphicsView 子類,在其基礎上改進了一些功能。

PlotWidget 只能內置一個 繪圖對象PlotItem, 而 GraphicsLayoutWidget 可以內置多個 繪圖對象。 通常我們使用最多的是PlotWidget

PlotWidget對象的 內置繪圖對象 PlotItem ,可以通過 getPlotItem() 方法獲取。

為了方便,大部分的PlotItem方法都可以直接通過 PlotWidget對象調用。 比如我們上面示例代碼中的 setTitle、showGrid、setLabel、setYRange、plot 等。

調用 plot方法,會創建一個PlotDataItem, 缺省是曲線圖

關於PyQtGraph繪圖基本架構的更多細節,點擊這里查看官方文檔

嵌入到Qt程序界面中

上面的例子,圖表是在單獨的程序中運行顯示。

如果我們要把它 嵌入到我們的Qt程序界面 中,主要通過 pyqtgraph 的 PlotWidget 或者 GraphicsLayoutWidget 控件類, 代碼如下所示

from PySide2 import QtWidgets
import pyqtgraph as pg

class MainWindow(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()

        self.setWindowTitle('pyqtgraph作圖示例')

        # 創建 PlotWidget 對象
        self.pw = pg.PlotWidget()

        # 設置圖表標題
        self.pw.setTitle("氣溫趨勢",color='008080',size='12pt')

        # 設置上下左右的label
        self.pw.setLabel("left","氣溫(攝氏度)")
        self.pw.setLabel("bottom","時間")
        # 背景色改為白色
        self.pw.setBackground('w')


        hour = [1,2,3,4,5,6,7,8,9,10]
        temperature = [30,32,34,32,33,31,29,32,35,45]

        # hour 和 temperature 分別是 : x, y 軸上的值
        self.pw.plot(hour,
                     temperature,
                     pen=pg.mkPen('b') # 線條顏色
                    )

        # 創建其他Qt控件
        okButton = QtWidgets.QPushButton("OK")
        lineEdit = QtWidgets.QLineEdit('點擊信息')
        # 水平layout里面放 edit 和 button
        hbox = QtWidgets.QHBoxLayout()
        hbox.addWidget(lineEdit)
        hbox.addWidget(okButton)

        # 垂直layout里面放 pyqtgraph圖表控件 和 前面的水平layout
        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.pw)
        vbox.addLayout(hbox)

        # 設置全局layout
        self.setLayout(vbox)

if __name__ == '__main__':
    app = QtWidgets.QApplication()
    main = MainWindow()
    main.show()
    app.exec_()


柱狀圖

pyqtgraph 可以產生這樣的 柱狀圖

image

繪制多個圖形

可以使用 GraphicsLayoutWidget,創建多個繪圖對形

image

實時更新圖

要畫動態的實時更新圖,只需要在把變更的內容重新plot即可。

示例代碼如下

from PySide2 import QtWidgets
from pyqtgraph.Qt import  QtCore
import pyqtgraph as pg
import sys
from random import randint

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.setWindowTitle('pyqtgraph作圖')

        # 創建 PlotWidget 對象
        self.pw = pg.PlotWidget()

        # 設置圖表標題
        self.pw.setTitle("氣溫趨勢",
                         color='008080',
                         size='12pt')

        # 設置上下左右的label
        self.pw.setLabel("left","氣溫(攝氏度)")
        self.pw.setLabel("bottom","時間")

        # 設置Y軸 刻度 范圍
        self.pw.setYRange(min=-10, # 最小值
                          max=50)  # 最大值

        # 顯示表格線
        self.pw.showGrid(x=True, y=True)

        # 背景色改為白色
        self.pw.setBackground('w')

        # 設置Y軸 刻度 范圍
        self.pw.setYRange(min=-10, # 最小值
                          max=50)  # 最大值

        # 居中顯示 PlotWidget
        self.setCentralWidget(self.pw)

        # 實時顯示應該獲取 plotItem, 調用setData,
        # 這樣只重新plot該曲線,性能更高
        self.curve = self.pw.getPlotItem().plot(
            pen=pg.mkPen('r', width=1)
        )

        self.i = 0
        self.x = [] # x軸的值
        self.y = [] # y軸的值

        # 啟動定時器,每隔1秒通知刷新一次數據
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateData)
        self.timer.start(1000)

    def updateData(self):
        self.i += 1
        self.x.append(self.i)
        # 創建隨機溫度值
        self.y.append(randint(10,30))

        # plot data: x, y values
        self.curve.setData(self.x,self.y)

if __name__ == '__main__':
    app = QtWidgets.QApplication()
    main = MainWindow()
    main.show()
    app.exec_()

PyQtGraph圖形可以作為一個 Qt的 widget控件,嵌入到 Qt 程序主窗口中。

我們可以在 Qt Designer 中把 PyQtGraph圖形控件 作為第三方控件 加入。

比如,像下面這樣:

image

在Qt Designer中加入第三方控件

通過 Qt Designer,我們可以預先把界面上的控件的位置大小設計好,然后動態加載。

但是 界面上擺放的都是 Qt內置的控件, 那么像 PyQtGraph 里面的 PlotWidget這種第三方控件怎么 放到 Qt Designer中呢? 我們的代碼又怎么去獲取到該控件對應的對象呢?

點擊這里,邊看視頻講解,邊學習以下內容

根據上面的視頻,產生的界面ui文件在下面的鏈接zip文件中

http://cdn1.python3.vip/files/qt/stock-01.zip

如果你使用的是PySide2, 對應的代碼如下,注意第14行 注冊的作用

from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
import pyqtgraph as pg

class Stock:

    def __init__(self):

        loader = QUiLoader()

        # pyside2 一定要 使用registerCustomWidget 
        # 來注冊 ui文件中的第三方控件,這樣加載的時候
        # loader才知道第三方控件對應的類,才能實例化對象
        loader.registerCustomWidget(pg.PlotWidget)
        self.ui = loader.load("main.ui")

        hour = [1,2,3,4,5,6,7,8,9,10]
        temperature = [30,32,34,32,33,31,29,32,35,45]

        # 通過控件名稱 historyPlot,找到Qt designer設計的 控件
        self.ui.historyPlot.plot(hour,temperature)

app = QApplication([])
stock = Stock()
stock.ui.show()
app.exec_()

如果使用 PyQt5,就更簡單了, 無需注冊,對應的代碼如下

from PyQt5.QtWidgets import QApplication
from PyQt5 import QtWidgets, uic

class Stock:

    def __init__(self):

        # PyQt5 直接加載ui文件
        # 因為 第三方控件通過promote的定義
        # 已經可以知道 控件類所在模塊的路徑
        self.ui = uic.loadUi("main.ui")

        hour = [1,2,3,4,5,6,7,8,9,10]
        temperature = [30,32,34,32,33,31,29,32,35,45]
        self.ui.historyPlot.plot(hour, temperature)

app = QApplication([])
stock = Stock()
stock.ui.show()
app.exec_()

軸刻度為字符串

上面的程序運行起來, X軸的刻度是 數字, 如果我們希望軸刻度是文字怎么做呢?

我們參考了這個網址的介紹: https://stackoverflow.com/questions/31775468/show-string-values-on-x-axis-in-pyqtgraph?lq=1

需要定義從數字到字符串的映射列表,參考如下代碼

import pyqtgraph as pg

# 刻度表,注意是雙層列表
xTick = [[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f')]]
x = [0,1,2,3,4,5]
y = [1, 2, 3, 4, 5, 6]

win = pg.GraphicsWindow()
stringaxis = pg.AxisItem(orientation='bottom')
stringaxis.setTicks(xTick)
plot = win.addPlot(axisItems={'bottom': stringaxis})
curve = plot.plot(x,y)

pg.QtGui.QApplication.exec_()

如果使用 PlotWidget,則要獲取軸對象,參考代碼如下

# self.ui.historyPlot 就是 PlotWidget對象
xax = self.ui.historyPlot.getAxis('bottom')
xax.setTicks(xTick)

獲取鼠標所在處刻度值

有時候,我們的程序需要獲取 鼠標在 pyqtgraph 圖形上移動時,鼠標所在對應的數據是什么。

可以參考下面代碼的作法

import pyqtgraph as pg
import PySide2

x = [1,2,3,4,5]
y = [1,2,3,4,5]

win = pg.GraphicsWindow()
plot = win.addPlot()
curve = plot.plot(x,y)

def mouseover(pos):
    # 參數pos 是像素坐標,需要 轉化為  刻度坐標
    act_pos = curve.mapFromScene(pos)
    if type(act_pos) != PySide2.QtCore.QPointF:
        return
    print(act_pos.x(),act_pos.y())

    # 有了 刻度坐標值,下面就可以根據該值處理一些信息
    # 比如狀態欄展示 該處的 日期等

curve.scene().sigMouseMoved.connect(mouseover)

pg.QtGui.QApplication.exec_()

練習題

開發一個股票數據軟件,題目要求見 視頻說明 https://www.bilibili.com/video/BV1cJ411R7bP?p=14


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM