I'm trying to figure out how to use the Queue system in python. In the code below I'm trying to use two threads, one that begins an update function feeds data into a put() and one that takes data from the put() with get() and updates the chart with that data.
However, using print statements show that it is putting "None" into put() and the get() seems to get some data somehow but only twice, and only the same data. However, the rest of the thread() function is certainly adding more and more data to the data list
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtWidgets, QtCore, QtGui
from pyqtgraph import PlotWidget, plot, QtCore, QtGui
import sys
import os
from random import randint
import time
import threading
import os
import queue
import random
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 = QtWidgets.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')
q = queue.Queue()
def update():
global item, data
while True:
data_len = len(data)
rand = random.randint(0, len(data)-1)
new_bar = data[rand][:]
new_bar[0] = data_len
data.append(new_bar)
q.put(data)
print("putting data " str(q.put(data)))
# print(data)
time.sleep(1)
# app.processEvents()
def startTheThread():
t = threading.Thread(target = update, args = ())
t.start()
def startTheThread_2():
t2 = threading.Thread(target = thread, args = ())
t2.start()
def thread():
while not q.empty():
i = q.get()
print("getting data " str(i))
print(i)
item.set_data(i)
# CandlestickItem(i)
q.task_done()
startTheThread()
startTheThread_2()
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtWidgets.QApplication.instance().exec_()
This is the output of this code until I stop it's execution.
putting data Nonegetting data [[1.0, 10, 13, 5, 15], [2.0, 13, 17, 9,
20], [3.0, 17, 14, 11, 23], [4.0, 14, 15, 5, 19], [5.0, 15, 9, 8, 22], [6.0, 9, 15, 8, 16], [6, 17, 14, 11, 23]]
[[1.0, 10, 13, 5, 15], [2.0, 13, 17, 9, 20], [3.0, 17, 14, 11, 23], [4.0, 14, 15, 5, 19], [5.0, 15, 9, 8, 22], [6.0, 9, 15, 8, 16], [6, 17, 14, 11, 23]]
getting data [[1.0, 10, 13, 5, 15], [2.0, 13, 17, 9, 20], [3.0, 17, 14, 11, 23], [4.0, 14, 15, 5, 19], [5.0, 15, 9, 8, 22], [6.0, 9, 15, 8, 16], [6, 17, 14, 11, 23]]
[[1.0, 10, 13, 5, 15], [2.0, 13, 17, 9, 20], [3.0, 17, 14, 11, 23], [4.0, 14, 15, 5, 19], [5.0, 15, 9, 8, 22], [6.0, 9, 15, 8, 16], [6, 17, 14, 11, 23]]
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
putting data None
CodePudding user response:
There are a variety of issues in your code. But the main issue is very simple, your thread
function that gets data from the queue exits as soon as the queue is empty. It loops with while not q.empty():
, which will only last until it's consumed all the currently available data. Then it quits and never checks again.
Likely you want to to loop indefinitely. Just a simple while True
will do that for you, as q.get
will block for as long as necessary, if there's no data currently available.
Among the other issues in your code:
Every time you do
q.put(data)
, you're putting a reference to the same list of lists,data
. This is problematic if you want the unchanged data to be processed first, before the updated data gets processed in a later step. If the queue is actually holding several updates at once, you'd then see the most recent version of the data processed several times. Copyingdata
before putting it into the queue should fix this.The
print
call you have inupdate
causes you toput
to the queue twice. And sinceput
doesn't return anything, you always getNone
in your output. Probably you want to be printingdata
instead of the return value fromput
(and certainly not calling it twice).