Reputation: 17111
My OptionsViz class is working on its own. However, when I throw in the asyncio stuff it doesn't show anything updating. The loop is needed for code that I have removed for brevity, so please don't throw that away.
import sys
import asyncio
from qasync import QEventLoop
from PyQt5.QtWidgets import QApplication, QMainWindow, QDockWidget
class OptionViz:
def __init__(self, app):
self.app = app
self.p = pg.plot()
self.p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
self.p.setRange(QtCore.QRectF(0, -10, 5000, 20))
self.p.setLabel("bottom", "Index", units="B")
self.curve = self.p.plot()
self.data = np.random.normal(size=(50,5000))
self.ptr = 0
self.lastTime = time()
self.fps = None
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(0)
def update(self):
self.curve.setData(self.data[self.ptr%10])
self.ptr += 1
now = time()
dt = now - self.lastTime
self.lastTime = now
if self.fps is None:
fps = 1.0/dt
else:
s = np.clip(dt*3., 0, 1)
self.fps = self.fps * (1-s) + (1.0/dt) * s
self.p.setTitle('%0.2f fps' % fps)
self.app.processEvents() ## force complete redraw for every plot
async def main(app):
# some await task here
viz = OptionViz(app)
# more await code here
if __name__ == '__main__':
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
loop.create_task(main(app))
loop.run_forever()
Upvotes: 1
Views: 797
Reputation: 243955
Qt is not compatible with asyncio so several libraries have been implemented such as quamash, asyncqt, qasync, etc. to make it compatible. In the case of quamash and asyncqt they have a bug that does not allow to execute but the qasync library so that it has solved it(execute pip install qasync
to install the package).
On the other hand, the main method is not awaitable since it does not execute a time-consuming task but it is executed instantly so I have had to restructure your project:
import sys
import asyncio
from qasync import QEventLoop
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
class OptionViz:
def __init__(self, app):
self.app = app
p = pg.plot()
p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
p.setRange(QtCore.QRectF(0, -10, 5000, 20))
p.setLabel("bottom", "Index", units="B")
self.curve = p.plot()
async def main(viz):
data = np.random.normal(size=(50, 5000))
ptr = 0
while True:
viz.curve.setData(data[ptr % 10])
await asyncio.sleep(0.1)
ptr += 1
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
viz = OptionViz(app)
loop.create_task(main(viz))
loop.run_forever()
Again, the "main" function only creates an "OptionViz" object that does not take a long time is not awaitable so it is absurd to use async in that case. It seems that the OP does not understand the operation of asyncio.
By restructuring your code we can make the function awaitable so OptionViz must be a QObject to use the asyncSlot decorator, in addition the QTimer must be a child of the QObject so that its life cycle increases.
import sys
import asyncio
from qasync import QEventLoop, asyncSlot
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
from time import time
class OptionViz(QtCore.QObject):
def __init__(self, app):
super().__init__()
self.app = app
self.p = pg.plot()
self.p.setWindowTitle("pyqtgraph example: PlotSpeedTest")
self.p.setRange(QtCore.QRectF(0, -10, 5000, 20))
self.p.setLabel("bottom", "Index", units="B")
self.curve = self.p.plot()
self.data = np.random.normal(size=(50, 5000))
self.ptr = 0
self.lastTime = time()
self.fps = None
timer = QtCore.QTimer(self)
timer.timeout.connect(self.update)
timer.start(0)
@asyncSlot()
async def update(self):
self.curve.setData(self.data[self.ptr % 10])
self.ptr += 1
now = time()
dt = now - self.lastTime
self.lastTime = now
if self.fps is None:
fps = 1.0 / dt
else:
s = np.clip(dt * 3.0, 0, 1)
self.fps = self.fps * (1 - s) + (1.0 / dt) * s
self.p.setTitle("%0.2f fps" % fps)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
viz = OptionViz(app)
loop.run_forever()
Upvotes: 1