英文:
update PyqtGraph plot in PyQt5
问题
我正在编写一个使用PyQT5创建的小界面,其中包含一个图形,我使用PyQtGraph来创建。通过按下"Start"按钮开始绘制图形,一开始一切都看起来正常:
但随着时间的推移和点数的增加,整个图形会收缩到屏幕的宽度,变得不具信息性:
因此,有两个问题:
- 如何使窗口不试图一次性适应整个图形,将其挤压,而是向后移动,显示最新的数据?
- 现在数据每秒传入一次,我每次都重新绘制图形。是否可以进行部分更新,只传入新数据?
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:
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:
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
函数中,使用PlotcurveItem
的getData()
和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
PlotCurveItem
s as members ofMainwindow
, set them up in the constructor, so you can access them later - step 2: in the
draw_graph
function use thegetData()
andsetData()
functions of thePlotcurveItem
s, 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])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论