首页 > 解决方案 > 动态更新 QChart

问题描述

我有一个类为给定数据绘制烛台。我正在尝试在收到新数据后立即动态更新绘图。以不规则的间隔接收数据。

我可以使用什么机制让班级知道是时候更新绘图并在使用新收到的数据点更新绘图时采取行动?

类函数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))

标签: pythonpyqt5candlestick-chartqchart

解决方案


Qt 使用事件循环来处理 gui 的事件和任务,即代码“app.exec_()”,因此该行之后的所有代码都不会执行,如果将其添加到它则使用 sys .exit() 将使应用程序在 Qt 事件循环结束时终止。

解决方案是使用事件循环来更新 gui,例如使用 QTimer:

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

推荐阅读