PyQt5 - кнопки становятся крайне безразличными при нажатии с большими наборами данных (10 КБ) - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь разработать небольшой сбор данных GUI, который изображен ниже, и все работает как предназначено для небольших наборов данных. Вот как это должно работать: нажмите «Пуск / Стоп», чтобы начать или остановить обновление графика траектории, а также гистограмм. Траектория получает данные из 2 текстовых файлов с 1 000 000 точек каждый с использованием генераторов python. После повторного нажатия этой же кнопки обновление просто прекращается. Вот и все. Проблема в том, что производительность начинает падать довольно быстро, приближаясь к 10 000 точкам в системе. Но это снижение производительности происходит только из-за реакции системы на нажатие кнопки, графики продолжают обновляться, как будто ничего не происходит. Как это может быть? Как я мог решить это? Ниже я опубликую часть кода, который может помочь поймать ошибку (я пропущу материал макета)

Извините за длинный пост. enter image description here

def read_file(file):
    for row in open(file, "r"):
        yield row

    while True:
        yield None


def gaussian(x, B, mu, sigma):
    return B * np.exp(-1.0 * (x - mu) ** 2 / (2 * sigma ** 2))


class Ui_MainWindow(object):
    counter = 0
    XDATA = read_file("xdata.txt")
    YDATA = read_file("ydata.txt")

    def setupUi(self, MainWindow):
        (...)

        self.map = pg.PlotWidget(self.centralwidget)
        (...)

        self.yhist = pg.PlotWidget(self.centralwidget)
        (...)
        self.xhist = pg.PlotWidget(self.centralwidget)
        (...)
        # Connect buttons to slots
        self.start_stop.clicked.connect(self.start)
        self.clear.clicked.connect(self.clear_data)
        self.fitButton.clicked.connect(self.fit)

        # Plot dummy data to map
        self.xdata = [0]
        self.ydata = [0]
        self.curve = pg.PlotDataItem(self.xdata, self.ydata)
        self.map.addItem(self.curve)

        # plot dummy data to xhist
        self.freqx, self.binsx = np.histogram(self.xdata)
        self.binscenters_x = np.array([0.5 * (self.binsx[i] + self.binsx[i + 1]) for i in range(len(self.binsx) - 1)])
        self.freqx = self.freqx / np.max(self.freqx)

        self.x_bar = pg.BarGraphItem(x=self.binscenters_x, height=self.freqx,
                                     width=self.binsx[2] - self.binsx[3],
                                     brush='r')

        pen = pg.mkPen(color=(255, 255, 0), width=2.5, style=QtCore.Qt.SolidLine)
        self.fitLine_x = pg.PlotDataItem([0], [0], pen=pen)
        self.xhist.addItem(self.x_bar)
        self.xhist.addItem(self.fitLine_x)

        # plot dummy data to yhist
        self.freqy, self.binsy = np.histogram(self.xdata)
        self.binscenters_y = np.array([0.5 * (self.binsy[i] + self.binsy[i + 1]) for i in range(len(self.binsy) - 1)])
        self.freqx = self.freqx / np.max(self.freqx)

        self.y_bar = pg.BarGraphItem(x=self.binscenters_y, height=self.freqy,
                                     width=self.binsx[2] - self.binsx[3],
                                     brush='r')
        self.fitLine_y = pg.PlotDataItem([0], [0], pen=pen)
        self.yhist.addItem(self.y_bar)
        self.yhist.addItem(self.fitLine_y)

        # Set a timer for the update
        # make QTimer
        self.qTimer = QtCore.QTimer()
        # set interval
        self.qTimer.setInterval(5)  # 1000 ms = 1 s
        # connect timeout signal to signal handler
        self.qTimer.timeout.connect(self.update)

    def start(self):
        start=0
        end=0
        current_counts=0
        if self.start_stop.isChecked():
            print("start")
            start=time()
            current_counts = self.counter
            self.qTimer.start()
            self.fitButton.setEnabled(False)
            self.clear.setEnabled(False)
        else:
            print("stop")
            self.qTimer.stop()
            self.fitButton.setEnabled(True)
            self.clear.setEnabled(True)
            end = time()
            print(end)
            print("FPS: ", (self.counter-current_counts) / (end - start))
            print("Total number of points read: ", self.counter)

    def clear_data(self):
        self.xdata = [0]
        self.ydata = [0]
        self.curve.setData(self.xdata, self.ydata)

    def fit(self):
        params_x, cov_x = curve_fit(gaussian, self.binscenters_x, self.freqx)
        params_y, cov_y = curve_fit(gaussian, self.binscenters_y, self.freqy)

        # plot it on the histograms
        data_range = np.linspace(-1, 1, 1000)

        self.fitLine_x.setData(data_range, gaussian(data_range, *params_x))
        self.fitLine_y.setData(data_range, gaussian(data_range, *params_y))

        # print the data to the tables
        (...)

    def update(self):
        # print(self.counter)
        self.counter += 1

        # update map
        if next(self.XDATA) is None:
            pass
        else:
            self.xdata.append(float(next(self.XDATA)))
            self.ydata.append(float(next(self.YDATA)))
            self.curve.setData(self.xdata, self.ydata)


            # update xhist
            self.freqx, self.binsx = np.histogram(self.xdata)
            self.binscenters_x = np.array([0.5 * (self.binsx[i] + self.binsx[i + 1]) for i in range(len(self.binsx) - 1)])
            self.freqx = self.freqx / np.max(self.freqx)
            self.x_bar.setOpts(x=self.binscenters_x, height=self.freqx, width=self.binsx[2] - self.binsx[3])
            self.fitLine_x.setData([0], [0])

            # update yhist
            self.freqy, self.binsy = np.histogram(self.ydata)
            self.binscenters_y = np.array([0.5 * (self.binsy[i] + self.binsy[i + 1]) for i in range(len(self.binsy) - 1)])
            self.freqy = self.freqy / np.max(self.freqy)
            self.y_bar.setOpts(x=self.binscenters_y, height=self.freqy, width=self.binsy[2] - self.binsy[3])
            self.fitLine_y.setData([0], [0])

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.fitButton.setText(_translate("MainWindow", "Fit Gaussian"))
        self.start_stop.setText(_translate("MainWindow", "Start/Stop"))
        self.clear.setText(_translate("MainWindow", "Clear data"))


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
...