Perform finiteCheck on PlotCurveItem.setData

The check for NaN values in arrayToQPath is expensive, this change
attempts to do the check one time, and if no NaN values are present,
an optional flag is passed along telling arrayToQPath that the check
can be skipped
This commit is contained in:
Ogi Moore 2021-05-22 21:43:03 -07:00
parent f08d239578
commit 7860d641ab
3 changed files with 43 additions and 9 deletions

View File

@ -1678,7 +1678,7 @@ def downsample(data, n, axis=0, xvals='subsample'):
return MetaArray(d2, info=info)
def arrayToQPath(x, y, connect='all'):
def arrayToQPath(x, y, connect='all', finiteCheck=True):
"""Convert an array of x,y coordinats to QPainterPath as efficiently as possible.
The *connect* argument may be 'all', indicating that each point should be
connected to the next; 'pairs', indicating that each pair of points
@ -1735,7 +1735,7 @@ def arrayToQPath(x, y, connect='all'):
# Qt version 5.12.3; these must now be manually cleaned out.
isfinite = None
qtver = [int(x) for x in QtVersion.split('.')]
if qtver >= [5, 12, 3]:
if qtver >= [5, 12, 3] and finiteCheck:
isfinite = np.isfinite(x) & np.isfinite(y)
if not np.all(isfinite):
# credit: Divakar https://stackoverflow.com/a/41191127/643629

View File

@ -65,6 +65,7 @@ class PlotCurveItem(GraphicsObject):
'connect': 'all',
'mouseWidth': 8, # width of shape responding to mouse click
'compositionMode': None,
'skipFiniteCheck': True
}
if 'pen' not in kargs:
self.opts['pen'] = fn.mkPen('w')
@ -336,6 +337,11 @@ class PlotCurveItem(GraphicsObject):
connectivity, specify an array of boolean values.
compositionMode See :func:`setCompositionMode
<pyqtgraph.PlotCurveItem.setCompositionMode>`.
skipFiniteCheck Optimization parameter that can speed up plot time by
telling the painter to not check and compensate for NaN
values. If set to True, and NaN values exist, the data
may not be displayed or your plot will take a
significant performance hit. Defaults to False.
=============== ========================================================
If non-keyword arguments are used, they will be interpreted as
@ -373,6 +379,7 @@ class PlotCurveItem(GraphicsObject):
if data.dtype.kind == 'c':
raise Exception("Can not plot complex data types.")
profiler("data checks")
#self.setCacheMode(QtGui.QGraphicsItem.NoCache) ## Disabling and re-enabling the cache works around a bug in Qt 4.6 causing the cached results to display incorrectly
@ -421,6 +428,8 @@ class PlotCurveItem(GraphicsObject):
if 'antialias' in kargs:
self.opts['antialias'] = kargs['antialias']
self.opts['skipFiniteCheck'] = kargs.get('skipFiniteCheck', False)
profiler('set')
self.update()
profiler('update')
@ -458,10 +467,12 @@ class PlotCurveItem(GraphicsObject):
y[0] = self.opts['fillLevel']
y[-1] = self.opts['fillLevel']
path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
return path
return fn.arrayToQPath(
x,
y,
connect=self.opts['connect'],
finiteCheck=not self.opts['skipFiniteCheck']
)
def getPath(self):
if self.path is None:

View File

@ -140,6 +140,11 @@ class PlotDataItem(GraphicsObject):
at any time.
dynamicRangeLimit (float or None) Limit off-screen positions of data points at large
magnification to avoids display errors. Disabled if None.
skipFiniteCheck (bool) Optimization parameter that can speed up plot time by
telling the painter to not check and compensate for NaN
values. If set to True, and NaN values exist, the data
may not be displayed or your plot will take a
significant performance hit. Defaults to False.
identical *deprecated*
================= =====================================================================
@ -210,7 +215,7 @@ class PlotDataItem(GraphicsObject):
'clipToView': False,
'dynamicRangeLimit': 1e6,
'dynamicRangeHyst': 3.0,
'skipFiniteCheck': False,
'data': None,
}
self.setCurveClickable(kargs.get('clickable', False))
@ -605,11 +610,29 @@ class PlotDataItem(GraphicsObject):
scatterArgs = {}
if styleUpdate: # repeat style arguments only when changed
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillOutline', 'fillOutline'), ('fillBrush', 'brush'), ('antialias', 'antialias'), ('connect', 'connect'), ('stepMode', 'stepMode')]:
for k, v in [
('pen','pen'),
('shadowPen','shadowPen'),
('fillLevel','fillLevel'),
('fillOutline', 'fillOutline'),
('fillBrush', 'brush'),
('antialias', 'antialias'),
('connect', 'connect'),
('stepMode', 'stepMode'),
('skipFiniteCheck', 'skipFiniteCheck')
]:
if k in self.opts:
curveArgs[v] = self.opts[k]
for k,v in [('symbolPen','pen'), ('symbolBrush','brush'), ('symbol','symbol'), ('symbolSize', 'size'), ('data', 'data'), ('pxMode', 'pxMode'), ('antialias', 'antialias')]:
for k, v in [
('symbolPen','pen'),
('symbolBrush','brush'),
('symbol','symbol'),
('symbolSize', 'size'),
('data', 'data'),
('pxMode', 'pxMode'),
('antialias', 'antialias')
]:
if k in self.opts:
scatterArgs[v] = self.opts[k]