Merge pull request #1610 from j9ac9k/boost-plotline-performance

Boost plotline performance
This commit is contained in:
Ogi Moore 2021-07-18 13:44:01 -07:00 committed by GitHub
commit 66ec0996f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 45 deletions

View File

@ -3,47 +3,45 @@
""" """
Update a simple plot as rapidly as possible to measure speed. Update a simple plot as rapidly as possible to measure speed.
""" """
## Add path to library (just for examples; you do not need this)
import initExample import initExample
## Add path to library (just for examples; you do not need this)
from time import perf_counter
from collections import deque
from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Qt import QtGui, QtCore
import numpy as np import numpy as np
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.ptime import time
app = pg.mkQApp("Plot Speed Test") app = pg.mkQApp("Plot Speed Test")
p = pg.plot() p = pg.plot()
p.setWindowTitle('pyqtgraph example: PlotSpeedTest') p.setWindowTitle('pyqtgraph example: PlotSpeedTest')
p.setRange(QtCore.QRectF(0, -10, 5000, 20)) p.setRange(QtCore.QRectF(0, -10, 5000, 20))
p.setLabel('bottom', 'Index', units='B') p.setLabel('bottom', 'Index', units='B')
curve = p.plot() curve = p.plot()
#curve.setFillBrush((0, 0, 100, 100)) data = np.random.normal(size=(50, 5000))
#curve.setFillLevel(0)
#lr = pg.LinearRegionItem([100, 4900])
#p.addItem(lr)
data = np.random.normal(size=(50,5000))
ptr = 0 ptr = 0
lastTime = time() rollingAverageSize = 1000
fps = None
elapsed = deque(maxlen=rollingAverageSize)
def update(): def update():
global curve, data, ptr, p, lastTime, fps global curve, data, ptr, elapsed, ptr
curve.setData(data[ptr%10])
ptr += 1 ptr += 1
now = time() # Measure
dt = now - lastTime t_start = perf_counter()
lastTime = now curve.setData(data[ptr % 10])
if fps is None: app.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents)
fps = 1.0/dt elapsed.append(perf_counter() - t_start)
else:
s = np.clip(dt*3., 0, 1) # update display every 50-updates
fps = fps * (1-s) + (1.0/dt) * s if ptr % 50 == 0:
p.setTitle('%0.2f fps' % fps) average = np.mean(elapsed)
app.processEvents() ## force complete redraw for every plot fps = 1 / average
p.setTitle('%0.2f fps - %0.1f ms avg' % (fps, average * 1_000))
timer = QtCore.QTimer() timer = QtCore.QTimer()
timer.timeout.connect(update) timer.timeout.connect(update)
timer.start(0) timer.start(0)

View File

@ -279,20 +279,17 @@ class ViewBox(GraphicsWidget):
def implements(self, interface): def implements(self, interface):
return interface == 'ViewBox' return interface == 'ViewBox'
# removed due to https://bugreports.qt-project.org/browse/PYSIDE-86 def itemChange(self, change, value):
#def itemChange(self, change, value): ret = super().itemChange(change, value)
## Note: Calling QWidget.itemChange causes segv in python 3 + PyQt if change == self.GraphicsItemChange.ItemSceneChange:
##ret = QtGui.QGraphicsItem.itemChange(self, change, value) scene = self.scene()
#ret = GraphicsWidget.itemChange(self, change, value) if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
#if change == self.ItemSceneChange: scene.sigPrepareForPaint.disconnect(self.prepareForPaint)
#scene = self.scene() elif change == self.GraphicsItemChange.ItemSceneHasChanged:
#if scene is not None and hasattr(scene, 'sigPrepareForPaint'): scene = self.scene()
#scene.sigPrepareForPaint.disconnect(self.prepareForPaint) if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
#elif change == self.ItemSceneHasChanged: scene.sigPrepareForPaint.connect(self.prepareForPaint)
#scene = self.scene() return ret
#if scene is not None and hasattr(scene, 'sigPrepareForPaint'):
#scene.sigPrepareForPaint.connect(self.prepareForPaint)
#return ret
def prepareForPaint(self): def prepareForPaint(self):
#autoRangeEnabled = (self.state['autoRange'][0] is not False) or (self.state['autoRange'][1] is not False) #autoRangeEnabled = (self.state['autoRange'][0] is not False) or (self.state['autoRange'][1] is not False)
@ -426,7 +423,6 @@ class ViewBox(GraphicsWidget):
if scene is not None: if scene is not None:
scene.removeItem(item) scene.removeItem(item)
item.setParentItem(None) item.setParentItem(None)
self.updateAutoRange() self.updateAutoRange()
def clear(self): def clear(self):
@ -453,7 +449,6 @@ class ViewBox(GraphicsWidget):
self.sigStateChanged.emit(self) self.sigStateChanged.emit(self)
self.sigResized.emit(self) self.sigResized.emit(self)
def viewRange(self): def viewRange(self):
"""Return a the view's visible range as a list: [[xmin, xmax], [ymin, ymax]]""" """Return a the view's visible range as a list: [[xmin, xmax], [ymin, ymax]]"""
return [x[:] for x in self.state['viewRange']] ## return copy return [x[:] for x in self.state['viewRange']] ## return copy
@ -627,7 +622,6 @@ class ViewBox(GraphicsWidget):
self._autoRangeNeedsUpdate = True self._autoRangeNeedsUpdate = True
elif changed[1] and self.state['autoVisibleOnly'][0] and (self.state['autoRange'][1] is not False): elif changed[1] and self.state['autoVisibleOnly'][0] and (self.state['autoRange'][1] is not False):
self._autoRangeNeedsUpdate = True self._autoRangeNeedsUpdate = True
self.sigStateChanged.emit(self) self.sigStateChanged.emit(self)
def setYRange(self, min, max, padding=None, update=True): def setYRange(self, min, max, padding=None, update=True):
@ -1608,7 +1602,6 @@ class ViewBox(GraphicsWidget):
self.sigTransformChanged.emit(self) ## segfaults here: 1 self.sigTransformChanged.emit(self) ## segfaults here: 1
def paint(self, p, opt, widget): def paint(self, p, opt, widget):
self.prepareForPaint()
if self.border is not None: if self.border is not None:
bounds = self.shape() bounds = self.shape()
p.setPen(self.border) p.setPen(self.border)