问题
I'm trying to plot candlesticks. I referred to this question and answer( The fastest way to add a new data bar with pyqtgraph )
I want my program to update and plot new candlesticks by receiving new values from a server, through calling update().
A problem that I have is that this example doesn't work without using QtCore.QTimer(). For example, if I manually call update() on the prompt or by apscheduler, candlesticks show no difference, but once I select the plot window, it shows new candlesticks at the same time. I don't understand why this happens.
Could anyone try testing this and tell me how to fix this problem?
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_()
回答1:
Many times non-native elements for Qt generate that behavior, Qt is a framework that has libraries for many tasks like the ones you want to do, a Qt-style solution would be to use QThreads and in that case we would use signals to update the data, but another solution but it is simple to use QRunnable and QThreadPool as I show below:
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_()
来源:https://stackoverflow.com/questions/47256835/how-can-i-automatically-update-data-in-pyqtgraph