集成在 QScrollArea 中的 Matplotlib 无法在 mac OS 上正确刷新曲线

Matplotlib integrated in a QScrollArea isn't refresh curves properly on mac OS

我在 pyqt5 QScrollArea 中嵌入的 matplotlib 图有问题。 我的问题是当我向下滚动时,好像只更新了 matplotlib 的顶部。 例如,在下图中,曲线编号 35 以下的曲线未正确更新。

这只发生在 mac OS 但它 运行 在 Windows 10 上很好。 我没有在代码中找到问题。

更新

在我看来,matplotlib 图与 QSrollBar 不匹配。我试着解释更多。当我使用 Qsrollbar 向下滚动时,Matplotlib 图正在下降但没有滚动条那么快。当我向下滚动时,我看到曲线的数量在增加。就好像 Qscrollbar 相对于 matplotlib 图更新太快了。

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.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(50,20*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):
        t0 = time.time()
        self.mascene.update()
        print('time old:', time.time()-t0)

    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()


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


if __name__ == '__main__':
    main()

我将我的 matplotlib 模块的版本从 3.1.1 更新到 3.2.0rc1,它解决了这个问题。