更新PyQt5中的PyqtGraph绘图。

huangapple go评论75阅读模式
英文:

update PyqtGraph plot in PyQt5

问题

我正在编写一个使用PyQT5创建的小界面,其中包含一个图形,我使用PyQtGraph来创建。通过按下"Start"按钮开始绘制图形,一开始一切都看起来正常:

但随着时间的推移和点数的增加,整个图形会收缩到屏幕的宽度,变得不具信息性:

因此,有两个问题:

  1. 如何使窗口不试图一次性适应整个图形,将其挤压,而是向后移动,显示最新的数据?
  2. 现在数据每秒传入一次,我每次都重新绘制图形。是否可以进行部分更新,只传入新数据?
from pyqtgraph import PlotWidget
import pyqtgraph
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QThread, QTimer, QObject, pyqtSignal, QTimer
from PyQt5.QtWidgets import QHBoxLayout, QMainWindow, QPushButton, QVBoxLayout, QWidget, QApplication
import sys
import random

# 以下是您提供的代码的翻译部分:

class Graph(PlotWidget):
    # 省略部分...

class ReadingWorker(QObject):
    # 省略部分...

class MainWindow(QMainWindow):
    # 省略部分...

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

请注意,这是代码的翻译部分。如果您需要更详细的帮助或有其他问题,请随时提出。

英文:

I'm writing a small interface in PyQT5 that has a graph that I use PyQtGraph to create. The graph starts to be drawn by pressing the "Start" button, and at first everything looks fine:更新PyQt5中的PyqtGraph绘图。

But over time and an increase in the number of points, the entire graph shrinks to the width of the screen and becomes not informative:
更新PyQt5中的PyqtGraph绘图。

In this regard, there are two questions:

How can I make the window not try to fit the whole graph at once, squeezing it, but rather move behind it, showing the latest data?
Now the data comes in once a second and I redraw the graph every time. Is it possible to make it a partial update so that I just pass only new data into it?

from pyqtgraph import PlotWidget
import pyqtgraph
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QThread, QTimer, QObject, pyqtSignal, QTimer
from PyQt5.QtWidgets import QHBoxLayout, QMainWindow,  QPushButton, QVBoxLayout, QWidget, QApplication
import sys
import random


def get_kl_test():
    choices = [50, 50, 50, 51, 51, 51, 52, 52, 52]
    list = [random.choice(choices) for i in range(11)]
    return list


def get_iopd_test():
    choices = [40, 40, 40, 50, 50, 50, 60, 60, 60]
    return random.choice(choices)


class Graph(PlotWidget):
    def __init__(self):
        super().__init__()
        self.setBackground('white')
        self.addLegend()
        self.showGrid(x=True, y=True)
        self.setYRange(0, 255, padding=0)


class ReadingWorker(QObject):
    update_graph = pyqtSignal(list, list, list, list)

    def __init__(self):
        super().__init__()
        self.time_from_start = 0
        self.time_values = []
        self.green_values = []
        self.blue_values = []
        self.red_values = []

    def run(self):
        self.read()
        self.update_time()

    def read(self):
        ipd_values = get_kl_test()
        iopd_value = get_iopd_test()

        self.green_values.append(ipd_values[0])
        self.blue_values.append(ipd_values[1])
        self.red_values.append(iopd_value)
        self.time_values.append(self.time_from_start)

        self.update_graph.emit(
            self.green_values, self.blue_values, self.red_values, self.time_values)
        QTimer.singleShot(1000, self.read)

    def update_time(self):
        self.time_from_start += 1
        QTimer.singleShot(1000, self.update_time)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.central_widget = QWidget(self)
        self.setGeometry(50, 50, 1300, 700)
        self.setCentralWidget(self.central_widget)
        self.layout_main_window = QVBoxLayout()
        self.central_widget.setLayout(self.layout_main_window)

        # конфигурация тулбара
        self.layout_toolbar = QHBoxLayout()
        self.layout_toolbar.addStretch(1)
        self.btn_start = QPushButton("Старт")
        self.btn_start.clicked.connect(self.start)
        self.layout_toolbar.addWidget(self.btn_start)
        self.layout_main_window.addLayout(self.layout_toolbar)

        # конфигурация графика
        self.graph = Graph()
        self.layout_main_window.addWidget(self.graph)

    def start(self):
        self.reading_thread = QThread(parent=self)
        self.reading_widget = ReadingWorker()
        self.reading_widget.moveToThread(self.reading_thread)
        self.reading_widget.update_graph.connect(self.draw_graph)
        self.reading_thread.started.connect(self.reading_widget.run)
        self.reading_thread.start()

    @QtCore.pyqtSlot(list, list, list, list)
    def draw_graph(self, ipd_1_values, ipd_2_values, iopd_values, time_values):
        
        self.graph.plotItem.clearPlots()
        pen_ipd_1 = pyqtgraph.mkPen(color='green', width=4)
        pen_ipd_2 = pyqtgraph.mkPen(color='blue', width=4, style=Qt.DashDotLine)
        pen_iopd = pyqtgraph.mkPen(color='red', width=4, style=Qt.DashLine)

        line_ipd_1 = self.graph.plotItem.addItem(pyqtgraph.PlotCurveItem(
            time_values, 
            ipd_1_values,
            pen=pen_ipd_1,
            name='1'
        ))
        line_ipd_2 = self.graph.plotItem.addItem(pyqtgraph.PlotCurveItem(
            time_values, 
            ipd_2_values,
            pen=pen_ipd_2,
            name='2'
        ))
        line_iopd = self.graph.plotItem.addItem(pyqtgraph.PlotCurveItem(
            time_values, 
            iopd_values,
            pen=pen_iopd,
            name='3'
        ))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

答案1

得分: 1

  • 步骤1:将PlotCurveItem作为Mainwindow的成员添加,并在构造函数中进行设置,以便以后可以访问它们。
  • 步骤2:在draw_graph函数中,使用PlotcurveItemgetData()setData()函数,更新它们。
  • 步骤3:如果有足够的x值,设置x范围,以便不显示所有数据,这里我使用的最大x范围是20(self.window_size

在下面的代码中,我只使用您的列表中的最后一个条目(例如ipd_1_values[-1]),您可以只传递标量并删除[-1]

此外,我使用了import numpy as np来进行np.append()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.central_widget = QWidget(self)
        self.setGeometry(50, 50, 1300, 700)
        self.setCentralWidget(self.central_widget)
        self.layout_main_window = QVBoxLayout()
        self.central_widget.setLayout(self.layout_main_window)

        # 配置工具栏
        self.layout_toolbar = QHBoxLayout()
        self.layout_toolbar.addStretch(1)
        self.btn_start = QPushButton("开始")
        self.btn_start.clicked.connect(self.start)
        self.layout_toolbar.addWidget(self.btn_start)
        self.layout_main_window.addLayout(self.layout_toolbar)

        # 配置图表
        self.graph = Graph()
        self.layout_main_window.addWidget(self.graph)

        self.setup_graphs() # 步骤1
        self.window_size = 20 # 步骤3

    def start(self):
        self.reading_thread = QThread(parent=self)
        self.reading_widget = ReadingWorker()
        self.reading_widget.moveToThread(self.reading_thread)
        self.reading_widget.update_graph.connect(self.draw_graph)
        self.reading_thread.started.connect(self.reading_widget.run)
        self.reading_thread.start()

    def setup_graphs(self):
        pen_ipd_1 = pyqtgraph.mkPen(color='green', width=4)
        pen_ipd_2 = pyqtgraph.mkPen(color='blue', width=4, style=Qt.DashDotLine)
        pen_iopd = pyqtgraph.mkPen(color='red', width=4, style=Qt.DashLine)
        self.line_ipd_1 = pyqtgraph.PlotCurveItem([], [], pen=pen_ipd_1, name='1')
        self.line_ipd_2 = pyqtgraph.PlotCurveItem([], [], pen=pen_ipd_2, name='2')
        self.line_iopd = pyqtgraph.PlotCurveItem([], [], pen=pen_iopd, name='3')
        self.graph.plotItem.addItem(self.line_ipd_1)
        self.graph.plotItem.addItem(self.line_ipd_2)
        self.graph.plotItem.addItem(self.line_iopd)

    @QtCore.pyqtSlot(list, list, list, list)
    def draw_graph(self, ipd_1_values, ipd_2_values, iopd_values, time_values): # 步骤2
        x, y = self.line_ipd_1.getData()
        x = np.append(x, time_values[-1])
        self.line_ipd_1.setData(y=np.append(y, ipd_1_values[-1]), x=x)
        _, y = self.line_ipd_2.getData()
        self.line_ipd_2.setData(y=np.append(y, ipd_2_values[-1]), x=x)
        _, y = self.line_iopd.getData()
        self.line_iopd.setData(y=np.append(y, iopd_values[-1]), x=x)
        if (len(x) > 0 and x[-1] - x[0] > self.window_size): # 步骤3
            self.graph.plotItem.setXRange(x[-1] - self.window_size, x[-1])
英文:
  • step 1: add the PlotCurveItems as members of Mainwindow, set them up in the constructor, so you can access them later
  • step 2: in the draw_graph function use the getData() and setData() functions of the PlotcurveItems, update them
  • step 3: if you have enough x-values set the xRange, so not all data is shown, I use a maximal xRange of 20 here (self.window_size)

In the code below I only use the last entry in your lists (e.g. ipd_1_values[-1]), you can just pass scalars and remove the [-1].

Also I used import numpy as np for the np.append().

    class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget(self)
self.setGeometry(50, 50, 1300, 700)
self.setCentralWidget(self.central_widget)
self.layout_main_window = QVBoxLayout()
self.central_widget.setLayout(self.layout_main_window)
# конфигурация тулбара
self.layout_toolbar = QHBoxLayout()
self.layout_toolbar.addStretch(1)
self.btn_start = QPushButton("Старт")
self.btn_start.clicked.connect(self.start)
self.layout_toolbar.addWidget(self.btn_start)
self.layout_main_window.addLayout(self.layout_toolbar)
# конфигурация графика
self.graph = Graph()
self.layout_main_window.addWidget(self.graph)
self.setup_graphs() # step 1
self.window_size = 20 # step 3
def start(self):
self.reading_thread = QThread(parent=self)
self.reading_widget = ReadingWorker()
self.reading_widget.moveToThread(self.reading_thread)
self.reading_widget.update_graph.connect(self.draw_graph)
self.reading_thread.started.connect(self.reading_widget.run)
self.reading_thread.start()
def setup_graphs(self):
pen_ipd_1 = pyqtgraph.mkPen(color='green', width=4)
pen_ipd_2 = pyqtgraph.mkPen(color='blue', width=4, style=Qt.DashDotLine)
pen_iopd = pyqtgraph.mkPen(color='red', width=4, style=Qt.DashLine)
self.line_ipd_1 = pyqtgraph.PlotCurveItem([], [], pen=pen_ipd_1, name='1')
self.line_ipd_2 = pyqtgraph.PlotCurveItem([], [], pen=pen_ipd_2, name='2')
self.line_iopd = pyqtgraph.PlotCurveItem([], [], pen=pen_iopd, name='3')
self.graph.plotItem.addItem(self.line_ipd_1)
self.graph.plotItem.addItem(self.line_ipd_2)
self.graph.plotItem.addItem(self.line_iopd)
@QtCore.pyqtSlot(list, list, list, list)
def draw_graph(self, ipd_1_values, ipd_2_values, iopd_values, time_values): # step 2
x, y = self.line_ipd_1.getData()
x = np.append(x, time_values[-1])
self.line_ipd_1.setData(y=np.append(y, ipd_1_values[-1]), x=x)
_, y = self.line_ipd_2.getData()
self.line_ipd_2.setData(y=np.append(y, ipd_2_values[-1]), x=x)
_, y = self.line_iopd.getData()
self.line_iopd.setData(y=np.append(y, iopd_values[-1]), x=x)
if (len(x)>0 and x[-1]-x[0]>self.window_size): # step 3
self.graph.plotItem.setXRange(x[-1]-self.window_size, x[-1])

huangapple
  • 本文由 发表于 2023年6月1日 21:55:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76382660.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定