3

特定のデータのローソク足をプロットするクラスがあります。新しいデータが受信されるとすぐにプロットを動的に更新しようとしています。不定期にデータを受信します。

クラスにプロットを更新する時が来たことを知らせ、新しく受信したデータ ポイントでプロットを更新するときにどのようなメカニズムを使用できますか?

クラス関数append_data_and_plot()はデータを追加しますが、プロットは更新されません。誰かが親切に問題が何であるかを明らかにすることができますか?

import sys
from PyQt5.QtChart import QCandlestickSeries, QChart, QChartView, QCandlestickSet
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import Qt, QPointF
from PyQt5 import QtChart as qc
import time

class myCandlestick():
    def __init__(self, data):
        self.data = data
        self.app = QApplication(sys.argv)

        self.series = QCandlestickSeries()
        self.series.setDecreasingColor(Qt.red)
        self.series.setIncreasingColor(Qt.green)

        self.ma5 = qc.QLineSeries() 
        self.tm = []

        for num, o, h, l, c, m in self.data:
            self.series.append(QCandlestickSet(o, h, l, c))
            self.ma5.append(QPointF(num, m))
            self.tm.append(str(num))

        self.chart = QChart()

        self.chart.addSeries(self.series)  # candle
        self.chart.addSeries(self.ma5)  # ma5 line

        self.chart.createDefaultAxes()
        self.chart.legend().hide()

        self.chart.axisX(self.series).setCategories(self.tm)
        self.chart.axisX(self.ma5).setVisible(False)

        self.chartview = QChartView(self.chart)
        self.ui = QMainWindow()
        self.ui.setGeometry(50, 50, 500, 300)
        self.ui.setCentralWidget(self.chartview)
        self.ui.show()
        sys.exit(self.app.exec_())

    def append_data_and_plot(self, d):
        '''Append and update the plot'''
        num, o, h, l, c, m = d
        self.series.append(QCandlestickSet(o, h, l, c))
        self.ui.show()
        #sys.exit(self.app.exec_())


data = ((1, 7380, 7520, 7380, 7510, 7324),
        (2, 7520, 7580, 7410, 7440, 7372),
        (3, 7440, 7650, 7310, 7520, 7434),
        (4, 7450, 7640, 7450, 7550, 7480),
        (5, 7510, 7590, 7460, 7490, 7502),
        (6, 7500, 7590, 7480, 7560, 7512),
        (7, 7560, 7830, 7540, 7800, 7584))

m = myCandlestick(data)

# Data is received at irregular intervals
time.sleep(1)
m.append_data_and_plot((8, 7560, 7830, 7540, 7800, 7584))

# Data is received at irregular intervals
time.sleep(0.1)
m.append_data_and_plot((9, 7450, 7640, 7450, 7550, 7480))

# Data is received at irregular intervals
time.sleep(2.5)
m.append_data_and_plot((10, 7380, 7520, 7380, 7510, 7324))
4

1 に答える 1

3

Qt はイベント ループを使用して GUI のイベントとタスクを処理します。これはコード「app.exec_ ()」であるため、その行の後のすべてのコードは実行されず、追加された場合は sys が使用されます。 .exit () は、Qt イベントループが終了したときにアプリケーションを終了させます。

解決策は、QTimer を使用するなど、eventloop を使用して GUI を更新することです。

import sys
from PyQt5.QtChart import QCandlestickSeries, QChart, QChartView, QCandlestickSet
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import Qt, QPointF, QObject, pyqtSignal, QTimer
from PyQt5 import QtChart as qc

import random


class MainWindow(QMainWindow):
    def __init__(self, data, parent=None):
        super().__init__(parent)
        self.data = data

        self.series = QCandlestickSeries()
        self.series.setDecreasingColor(Qt.red)
        self.series.setIncreasingColor(Qt.green)

        self.ma5 = qc.QLineSeries()
        self.tm = []

        self.chart = QChart()

        self.chart.addSeries(self.series)  # candle
        self.chart.addSeries(self.ma5)  # ma5 line

        self.chart.createDefaultAxes()
        self.chart.legend().hide()

        self.chart.axisX(self.series).setCategories(self.tm)
        self.chart.axisX(self.ma5).setVisible(False)

        self.chartview = QChartView(self.chart)
        self.setGeometry(50, 50, 500, 300)
        self.setCentralWidget(self.chartview)

    def append_data_and_plot(self, d):
        """Append and update the plot"""
        num, o, h, l, c, m = d

        ax1 = self.chart.axisX(self.ma5)
        ay1 = self.chart.axisY(self.ma5)

        xmin = xmax = num
        ymin = ymax = m

        step = 10
        offset = 100

        for p in self.ma5.pointsVector()[-step:]:
            xmin = min(p.x(), xmin)
            xmax = max(p.x(), xmax)

            ymin = min(p.y(), ymin) - offset
            ymax = max(p.y(), ymax) + offset

        xmin = max(0, xmax - step)

        ax1.setMin(xmin)
        ax1.setMax(xmax)
        ay1.setMin(ymin)
        ay1.setMax(ymax)

        self.ma5.append(QPointF(num, m))
        self.tm.append(str(num))

        self.series.append(QCandlestickSet(o, h, l, c))
        ax2 = self.chart.axisX(self.series)
        ax2.setCategories(self.tm)
        ax2.setMin(str(xmin))
        ax2.setMax(str(xmax))

        ay2 = self.chart.axisY(self.series)
        ay2.setMin(ymin)
        ay2.setMax(ymax)


def create_data():


    i = 1
    while True:
        i += 1
        yield (
            i,
            random.randint(7000, 8000),
            random.randint(7000, 8000),
            random.randint(7000, 8000),
            random.randint(7000, 8000),
            random.randint(7000, 8000),
        )


class Producer(QObject):
    dataChanged = pyqtSignal(list)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.iter = create_data()
        QTimer.singleShot(random.randint(0, 1500), self.send_data)

    def send_data(self):
        d = list(next(self.iter))
        self.dataChanged.emit(d)
        QTimer.singleShot(random.randint(0, 1500), self.send_data)


def main():
    app = QApplication(sys.argv)

    data = ((1, 7380, 7520, 7380, 7510, 7324),)
    w = MainWindow(data)
    w.show()

    p = Producer()
    p.dataChanged.connect(w.append_data_and_plot)

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
于 2020-07-08T18:43:37.453 に答える