如何自动更新pyqtgraph中的数据?
How can I automatically update data in pyqtgraph?
我正在尝试绘制烛台。我参考了这个问答(The fastest way to add a new data bar with pyqtgraph)
我希望我的程序通过调用 update() 从服务器接收新值来更新和绘制新的烛台。
我遇到的一个问题是,如果不使用 QtCore.QTimer(),此示例将无法运行。例如,如果我在提示上或通过 apscheduler 手动调用 update(),烛台显示没有区别,但是一旦我 select 绘图 window,它会同时显示新的烛台。我不明白为什么会这样。
谁能尝试测试一下并告诉我如何解决这个问题?
import pyqtgraph as pg
from pyqtgraph import QtCore, QtGui
import random
import numpy as np
from apscheduler.schedulers.background import BackgroundScheduler
class CandlestickItem(pg.GraphicsObject):
def __init__(self):
pg.GraphicsObject.__init__(self)
self.flagHasData = False
def set_data(self, data):
self.data = data
self.flagHasData = True
self.generatePicture()
self.informViewBoundsChanged()
def generatePicture(self):
self.picture = QtGui.QPicture()
p = QtGui.QPainter(self.picture)
p.setPen(pg.mkPen('w'))
w = (self.data[1][0] - self.data[0][0]) / 3.
for (t, open, close, min, max) in self.data:
p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
if open > close:
p.setBrush(pg.mkBrush('r'))
else:
p.setBrush(pg.mkBrush('g'))
p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open))
p.end()
def paint(self, p, *args):
if self.flagHasData:
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
return QtCore.QRectF(self.picture.boundingRect())
app = QtGui.QApplication([])
data = [
[1., 10, 13, 5, 15],
[2., 13, 17, 9, 20],
[3., 17, 14, 11, 23],
[4., 14, 15, 5, 19],
[5., 15, 9, 8, 22],
[6., 9, 15, 8, 16],
]
item = CandlestickItem()
item.set_data(data)
plt = pg.plot()
plt.addItem(item)
plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
def update():
global item, data
data_len = len(data)
rand = random.randint(0, len(data)-1)
new_bar = data[rand][:]
new_bar[0] = data_len
data.append(new_bar)
item.set_data(data)
app.processEvents()
## DOESN'T SHOW NEW CANDLESTICKS UNLESS YOU SELECT THE PLOT WINDOW
#sched = BackgroundScheduler()
#sched.start()
#sched.add_job(update, trigger='cron', second='*/1')
## WORKS FINE WITH THIS PARAGRAPH.
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1000)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
很多时候 Qt 的非原生元素会产生这种行为,Qt 是一个框架,它有许多任务的库,比如你想做的任务,Qt 风格的解决方案是使用 QThreads,在这种情况下我们会使用信号来更新数据,但是另一种解决方案但是使用 QRunnable 和 QThreadPool 很简单,如下所示:
class PlotRunnable(QtCore.QRunnable):
def __init__(self, it):
QtCore.QRunnable.__init__(self)
self.it = it
def run(self):
while True:
data = self.it.data
data_len = len(data)
rand = random.randint(0, len(data)-1)
new_bar = data[rand][:]
new_bar[0] = data_len
data.append(new_bar)
QtCore.QMetaObject.invokeMethod(self.it, "set_data",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(list, data))
QtCore.QThread.msleep(1000)
class CandlestickItem(pg.GraphicsObject):
def __init__(self):
pg.GraphicsObject.__init__(self)
self.flagHasData = False
@QtCore.pyqtSlot(list)
def set_data(self, data):
self.data = data
self.flagHasData = True
self.generatePicture()
self.informViewBoundsChanged()
def generatePicture(self):
[...]
app = QtGui.QApplication([])
data = [
[1., 10, 13, 5, 15],
[2., 13, 17, 9, 20],
[3., 17, 14, 11, 23],
[4., 14, 15, 5, 19],
[5., 15, 9, 8, 22],
[6., 9, 15, 8, 16],
]
item = CandlestickItem()
item.set_data(data)
plt = pg.plot()
plt.addItem(item)
plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
runnable = PlotRunnable(item)
QtCore.QThreadPool.globalInstance().start(runnable)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
我正在尝试绘制烛台。我参考了这个问答(The fastest way to add a new data bar with pyqtgraph)
我希望我的程序通过调用 update() 从服务器接收新值来更新和绘制新的烛台。
我遇到的一个问题是,如果不使用 QtCore.QTimer(),此示例将无法运行。例如,如果我在提示上或通过 apscheduler 手动调用 update(),烛台显示没有区别,但是一旦我 select 绘图 window,它会同时显示新的烛台。我不明白为什么会这样。
谁能尝试测试一下并告诉我如何解决这个问题?
import pyqtgraph as pg
from pyqtgraph import QtCore, QtGui
import random
import numpy as np
from apscheduler.schedulers.background import BackgroundScheduler
class CandlestickItem(pg.GraphicsObject):
def __init__(self):
pg.GraphicsObject.__init__(self)
self.flagHasData = False
def set_data(self, data):
self.data = data
self.flagHasData = True
self.generatePicture()
self.informViewBoundsChanged()
def generatePicture(self):
self.picture = QtGui.QPicture()
p = QtGui.QPainter(self.picture)
p.setPen(pg.mkPen('w'))
w = (self.data[1][0] - self.data[0][0]) / 3.
for (t, open, close, min, max) in self.data:
p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
if open > close:
p.setBrush(pg.mkBrush('r'))
else:
p.setBrush(pg.mkBrush('g'))
p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open))
p.end()
def paint(self, p, *args):
if self.flagHasData:
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
return QtCore.QRectF(self.picture.boundingRect())
app = QtGui.QApplication([])
data = [
[1., 10, 13, 5, 15],
[2., 13, 17, 9, 20],
[3., 17, 14, 11, 23],
[4., 14, 15, 5, 19],
[5., 15, 9, 8, 22],
[6., 9, 15, 8, 16],
]
item = CandlestickItem()
item.set_data(data)
plt = pg.plot()
plt.addItem(item)
plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
def update():
global item, data
data_len = len(data)
rand = random.randint(0, len(data)-1)
new_bar = data[rand][:]
new_bar[0] = data_len
data.append(new_bar)
item.set_data(data)
app.processEvents()
## DOESN'T SHOW NEW CANDLESTICKS UNLESS YOU SELECT THE PLOT WINDOW
#sched = BackgroundScheduler()
#sched.start()
#sched.add_job(update, trigger='cron', second='*/1')
## WORKS FINE WITH THIS PARAGRAPH.
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1000)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
很多时候 Qt 的非原生元素会产生这种行为,Qt 是一个框架,它有许多任务的库,比如你想做的任务,Qt 风格的解决方案是使用 QThreads,在这种情况下我们会使用信号来更新数据,但是另一种解决方案但是使用 QRunnable 和 QThreadPool 很简单,如下所示:
class PlotRunnable(QtCore.QRunnable):
def __init__(self, it):
QtCore.QRunnable.__init__(self)
self.it = it
def run(self):
while True:
data = self.it.data
data_len = len(data)
rand = random.randint(0, len(data)-1)
new_bar = data[rand][:]
new_bar[0] = data_len
data.append(new_bar)
QtCore.QMetaObject.invokeMethod(self.it, "set_data",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(list, data))
QtCore.QThread.msleep(1000)
class CandlestickItem(pg.GraphicsObject):
def __init__(self):
pg.GraphicsObject.__init__(self)
self.flagHasData = False
@QtCore.pyqtSlot(list)
def set_data(self, data):
self.data = data
self.flagHasData = True
self.generatePicture()
self.informViewBoundsChanged()
def generatePicture(self):
[...]
app = QtGui.QApplication([])
data = [
[1., 10, 13, 5, 15],
[2., 13, 17, 9, 20],
[3., 17, 14, 11, 23],
[4., 14, 15, 5, 19],
[5., 15, 9, 8, 22],
[6., 9, 15, 8, 16],
]
item = CandlestickItem()
item.set_data(data)
plt = pg.plot()
plt.addItem(item)
plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
runnable = PlotRunnable(item)
QtCore.QThreadPool.globalInstance().start(runnable)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()