gpt4 book ai didi

python - 如何在 Qt 环境中嵌入的 matplotlib 中更快地绘制大量信号?

转载 作者:行者123 更新时间:2023-12-04 21:28:53 24 4
gpt4 key购买 nike

我正在尝试在嵌入在 Qt 环境中的 matplotlib 图中绘制大量信号。
这些图是根据 QScrollBar 更新的,它修改了我需要显示的信号部分。
我的问题是图形的更新需要很长时间,特别是因为我有 250 个信号要更新。因此,我正在寻找一种优化 EEG_plot.update 函数以减少其绘制时间的方法。
我不知道如何使用动画功能来加快流程或其他方式。
我担心的是我需要更新时间轴刻度,可能还有 y 轴标签位置。
另一件事是,如果我需要绘制的最后一段与选择的窗口大小不完全对应,我只需要绘制窗口的一部分(例如,最后一段将是 5 秒,但窗口大小是 10 秒)

我在下面给出整个脚本

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np


class Viewer(QMainWindow):
def __init__(self, parent=None):
super(Viewer, self).__init__()
self.parent = parent
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainVBOX_param_scene = QVBoxLayout()
self.mascene = plot(self)


self.paramPlotV = QVBoxLayout()
self.horizontalSliders = QScrollBar(Qt.Horizontal)
self.horizontalSliders.setFocusPolicy(Qt.StrongFocus)
self.horizontalSliders.valueChanged.connect(self.update_plot)
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(1)


self.paramPlot = QHBoxLayout()
l_gain = QLabel('Gain')
self.e_gain = QLineEdit('5')
l_win = QLabel('Window')
self.e_win = QLineEdit('10')
l_spacing = QLabel('vertical spacing')
self.e_spacing = QLineEdit('10')
l_linewidth = QLabel('linewidth')
self.e_linewidth = QLineEdit('1')

self.e_gain.returnPressed.connect(self.update_plot)
self.e_win.returnPressed.connect(self.udpate_plot_plus_slider)
self.e_spacing.returnPressed.connect(self.update_plot)
self.e_linewidth.returnPressed.connect(self.update_plot)

self.paramPlot.addWidget(l_gain)
self.paramPlot.addWidget(self.e_gain)
self.paramPlot.addWidget(l_win)
self.paramPlot.addWidget(self.e_win)
self.paramPlot.addWidget(l_spacing)
self.paramPlot.addWidget(self.e_spacing)
self.paramPlot.addWidget(l_linewidth)
self.paramPlot.addWidget(self.e_linewidth)

self.paramPlotV.addWidget(self.horizontalSliders)
self.paramPlotV.addLayout(self.paramPlot)

self.mainVBOX_param_scene.addWidget(self.mascene)
self.mainVBOX_param_scene.addLayout(self.paramPlotV)

self.centralWidget.setLayout(self.mainVBOX_param_scene)

self.Fs = 1024
self.Sigs_dict = np.random.rand(250,105*self.Fs)
self.t = np.arange(self.Sigs_dict.shape[1])/self.Fs
self.parent.processEvents()
self.update()

def updateslider(self):
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(np.ceil(self.t[-1]/int(self.e_win.text()))-1)
self.horizontalSliders.setPageStep(1)
self.horizontalSliders.update()

def udpate_plot_plus_slider(self):
self.updateslider()
self.mascene.update()

def update_plot(self):
self.mascene.update()

def update(self):
self.updateslider()
self.mascene.modify_sigs()
self.mascene.update()

class plot(QGraphicsView):
def __init__(self, parent=None):
super(plot, self).__init__(parent)
self.parent = parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure(facecolor='white')#Figure()
self.canvas = FigureCanvas(self.figure)

self.widget = QWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.scroll = QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)

layout = QVBoxLayout()
layout.addWidget(self.scroll)
self.setLayout(layout)

def modify_sigs(self):
self.Sigs_dict = self.parent.Sigs_dict
self.t = self.parent.t
self.Fs= self.parent.Fs


def update(self):
win_num = self.parent.horizontalSliders.value()
self.figure.clear()
plt.figure(self.figure.number)
plt.subplots_adjust(left=0.1, bottom=0.01, right=1, top=1, wspace=0.0 , hspace=0.0 )
self.axes = plt.subplot(1, 1, 1)
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
self.spacing = float(self.parent.e_spacing.text())
linewidth = float(self.parent.e_linewidth.text())
ts = int(win*(win_num) * self.Fs)
te = ts + int(win * self.Fs)
if te > len(self.t):
te=len(self.t)
for i in range(self.Sigs_dict.shape[0]):
line, = plt.plot(self.t[ts:te], gain*(self.Sigs_dict[i,ts:te]-np.mean(self.Sigs_dict[i,ts:te]))+i*self.spacing, linewidth=linewidth )


self.axes.autoscale(enable=True, axis='both', tight=True)
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))

self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])



self.canvas.setGeometry(0, 0, self.parent.width()-100, (self.parent.height()-100)*self.spacing)
self.canvas.draw_idle()


def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Viewer(app)
ex.showMaximized()
sys.exit(app.exec())


if __name__ == '__main__':
main()

更新

我做了一个新的实现,我尝试更新数据而不是每次都重新绘制所有图形( update_set_data 函数),我没有绘制曲线的所有点(例如,如果点数 > 10000 点,我只取其中的 50%)我使用了 decimate = len(self.t[ts:te]) // 10000 + 1计算抽取,最后当用户拖动 slider 时我不会重新绘制图形。

当我使用旧版本时,我有时间更新图形:
time old: 4.148899078369141
time old: 4.117990255355835
time old: 4.152893781661987

使用新版本,我得到:
time new: 2.0400094985961914
time new: 2.0248610973358154
time new: 2.0305933952331543

我不得不说,我预计会减少 50% 以上的时间。
有人有想法进一步优化吗?
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
import time

class Viewer(QMainWindow):
def __init__(self, parent=None):
super(Viewer, self).__init__()
self.parent = parent
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainVBOX_param_scene = QVBoxLayout()
self.mascene = plot(self)


self.paramPlotV = QVBoxLayout()
self.horizontalSliders = QScrollBar(Qt.Horizontal)
self.horizontalSliders.setFocusPolicy(Qt.StrongFocus)
self.horizontalSliders.valueChanged.connect(self.sliderReleasedfun)
self.horizontalSliders.sliderPressed.connect(self.sliderPressedfun)
self.horizontalSliders.sliderMoved.connect(self.sliderMovedfun)
self.horizontalSliders.sliderReleased.connect(self.sliderReleasedfun)
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(1)


self.paramPlot = QHBoxLayout()
l_gain = QLabel('Gain')
self.e_gain = QLineEdit('5')
l_win = QLabel('Window')
self.e_win = QLineEdit('10')
l_spacing = QLabel('vertical spacing')
self.e_spacing = QLineEdit('10')
l_linewidth = QLabel('linewidth')
self.e_linewidth = QLineEdit('1')

self.e_gain.returnPressed.connect(self.update_plot)
self.e_win.returnPressed.connect(self.udpate_plot_plus_slider)
self.e_spacing.returnPressed.connect(self.update_plot)
self.e_linewidth.returnPressed.connect(self.update_plot)

self.paramPlot.addWidget(l_gain)
self.paramPlot.addWidget(self.e_gain)
self.paramPlot.addWidget(l_win)
self.paramPlot.addWidget(self.e_win)
self.paramPlot.addWidget(l_spacing)
self.paramPlot.addWidget(self.e_spacing)
self.paramPlot.addWidget(l_linewidth)
self.paramPlot.addWidget(self.e_linewidth)

self.paramPlotV.addWidget(self.horizontalSliders)
self.paramPlotV.addLayout(self.paramPlot)

self.mainVBOX_param_scene.addWidget(self.mascene)
self.mainVBOX_param_scene.addLayout(self.paramPlotV)

self.centralWidget.setLayout(self.mainVBOX_param_scene)

self.Fs = 1024
self.Sigs_dict = np.random.rand(250,105*self.Fs)
self.t = np.arange(self.Sigs_dict.shape[1])/self.Fs
self.parent.processEvents()
self.update()

def sliderPressedfun(self):
self.horizontalSliders.valueChanged.disconnect()

def sliderMovedfun(self,e):
self.horizontalSliders.setValue(e)

def sliderReleasedfun(self):
self.horizontalSliders.valueChanged.connect(self.movesliderfun)
self.movesliderfun()

def movesliderfun(self):
t0 = time.time()

self.horizontalSliders.setEnabled(False)
self.update_data()
self.horizontalSliders.setEnabled(True)
print('time new:', time.time()-t0)

def updateslider(self):
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(np.ceil(self.t[-1]/int(self.e_win.text()))-1)
self.horizontalSliders.setPageStep(1)
self.horizontalSliders.update()

def udpate_plot_plus_slider(self):
self.updateslider()
self.mascene.update()

def update_plot(self):
self.mascene.update()

def update_data(self):
self.mascene.update_set_data()

def update(self):
self.updateslider()
self.mascene.modify_sigs()
self.mascene.update()

class plot(QGraphicsView):
def __init__(self, parent=None):
super(plot, self).__init__(parent)
self.parent = parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure(facecolor='white')#Figure()
self.canvas = FigureCanvas(self.figure)

self.widget = QWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.scroll = QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)

layout = QVBoxLayout()
layout.addWidget(self.scroll)
self.setLayout(layout)
self.win=10

def modify_sigs(self):
self.Sigs_dict = self.parent.Sigs_dict
self.t = self.parent.t
self.Fs= self.parent.Fs

def update_set_data(self):
win_num = self.parent.horizontalSliders.value()
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
if not self.spacing == float(self.parent.e_spacing.text()):
self.spacing = float(self.parent.e_spacing.text())
spacing = True
else:
spacing = False
self.linewidth = float(self.parent.e_linewidth.text())

ts = int(self.win * (win_num) * self.Fs)
te = ts + int(self.win * self.Fs)
if te > len(self.t):
diff = te - len(self.t)
ts = ts - diff
te = len(self.t)

decimate = len(self.t[ts:te]) // 10000 + 1

for i in range(self.Sigs_dict.shape[0]):
self.Lines[i].set_data(self.t[ts:te:decimate], gain*(self.Sigs_dict[i,ts:te:decimate]-np.mean(self.Sigs_dict[i,ts:te:decimate]))+i*self.spacing )
self.Lines[i].set_linewidth(self.linewidth)

if spacing:
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])



self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))
# self.canvas.draw_idle()
self.canvas.draw()

def update(self):
win_num = self.parent.horizontalSliders.value()
self.figure.clear()
plt.figure(self.figure.number)
plt.subplots_adjust(left=0.1, bottom=0.01, right=1, top=1, wspace=0.0 , hspace=0.0 )
self.axes = plt.subplot(1, 1, 1)
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
self.spacing = float(self.parent.e_spacing.text())
linewidth = float(self.parent.e_linewidth.text())
ts = int(self.win * (win_num) * self.Fs)
te = ts + int(self.win * self.Fs)
if te > len(self.t):
diff = te - len(self.t)
ts = ts - diff
te = len(self.t)
decimate = len(self.t[ts:te]) // 10000 + 1
self.Lines = []
for i in range(self.Sigs_dict.shape[0]):
line, = plt.plot(self.t[ts:te:decimate], gain*(self.Sigs_dict[i,ts:te:decimate]-np.mean(self.Sigs_dict[i,ts:te:decimate]))+i*self.spacing, linewidth=linewidth )
self.Lines.append(line)

self.axes.autoscale(enable=True, axis='both', tight=True)
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))

self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])



self.canvas.setGeometry(0, 0, self.parent.width()-100, (self.parent.height()-100)*self.spacing)
self.canvas.draw_idle()


def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Viewer(app)
ex.showMaximized()
sys.exit(app.exec())


if __name__ == '__main__':
main()

最佳答案

您可以尝试使用多线程,
这样您就可以在许多子代码中破坏整个代码
并且您的所有代码都将使用多线程同时运行

关于python - 如何在 Qt 环境中嵌入的 matplotlib 中更快地绘制大量信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58452078/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com