Commit 58048a70 authored by Luke Campagnola's avatar Luke Campagnola
Browse files

- Removed inf/nan checking from PlotDataItem and PlotCurveItem; improved performance

- Added 'connect' option to PlotDataItem and PlotCurveItem to affect which line segments are drawn
- arrayToQPath() added 'finite' connection mode which omits non-finite values from connections
parent 5ad39c25
......@@ -1133,7 +1133,9 @@ def arrayToQPath(x, y, connect='all'):
connect[:,0] = 1
connect[:,1] = 0
connect = connect.flatten()
if connect == 'finite':
connect = np.isfinite(x) & np.isfinite(y)
arr[1:-1]['c'] = connect
if connect == 'all':
arr[1:-1]['c'] = 1
elif isinstance(connect, np.ndarray):
......
......@@ -71,7 +71,8 @@ class PlotCurveItem(GraphicsObject):
'brush': None,
'stepMode': False,
'name': None,
'antialias': pg.getConfigOption('antialias'),
'antialias': pg.getConfigOption('antialias'),\
'connect': 'all',
}
self.setClickable(kargs.get('clickable', False))
self.setData(*args, **kargs)
......@@ -119,10 +120,12 @@ class PlotCurveItem(GraphicsObject):
## Get min/max (or percentiles) of the requested data range
if frac >= 1.0:
b = (d.min(), d.max())
b = (np.nanmin(d), np.nanmax(d))
elif frac <= 0.0:
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
else:
mask = np.isfinite(d)
d = d[mask]
b = (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
## adjust for fill level
......@@ -264,6 +267,12 @@ class PlotCurveItem(GraphicsObject):
stepMode If True, two orthogonal lines are drawn for each sample
as steps. This is commonly used when drawing histograms.
Note that in this case, len(x) == len(y) + 1
connect Argument specifying how vertexes should be connected
by line segments. Default is "all", indicating full
connection. "pairs" causes only even-numbered segments
to be drawn. "finite" causes segments to be omitted if
they are attached to nan or inf values. For any other
connectivity, specify an array of boolean values.
============== ========================================================
If non-keyword arguments are used, they will be interpreted as
......@@ -326,7 +335,8 @@ class PlotCurveItem(GraphicsObject):
if 'name' in kargs:
self.opts['name'] = kargs['name']
if 'connect' in kargs:
self.opts['connect'] = kargs['connect']
if 'pen' in kargs:
self.setPen(kargs['pen'])
if 'shadowPen' in kargs:
......@@ -365,7 +375,7 @@ class PlotCurveItem(GraphicsObject):
y[0] = self.opts['fillLevel']
y[-1] = self.opts['fillLevel']
path = fn.arrayToQPath(x, y, connect='all')
path = fn.arrayToQPath(x, y, connect=self.opts['connect'])
return path
......
......@@ -58,6 +58,8 @@ class PlotDataItem(GraphicsObject):
**Line style keyword arguments:**
========== ================================================
connect Specifies how / whether vertexes should be connected.
See :func:`arrayToQPath() <pyqtgraph.arrayToQPath>`
pen Pen to use for drawing line between points.
Default is solid grey, 1px width. Use None to disable line drawing.
May be any single argument accepted by :func:`mkPen() <pyqtgraph.mkPen>`
......@@ -119,7 +121,7 @@ class PlotDataItem(GraphicsObject):
self.yData = None
self.xDisp = None
self.yDisp = None
self.dataMask = None
#self.dataMask = None
#self.curves = []
#self.scatters = []
self.curve = PlotCurveItem()
......@@ -133,6 +135,8 @@ class PlotDataItem(GraphicsObject):
#self.clear()
self.opts = {
'connect': 'all',
'fftMode': False,
'logMode': [False, False],
'alphaHint': 1.0,
......@@ -386,6 +390,8 @@ class PlotDataItem(GraphicsObject):
if 'name' in kargs:
self.opts['name'] = kargs['name']
if 'connect' in kargs:
self.opts['connect'] = kargs['connect']
## if symbol pen/brush are given with no symbol, then assume symbol is 'o'
......@@ -445,7 +451,7 @@ class PlotDataItem(GraphicsObject):
def updateItems(self):
curveArgs = {}
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillBrush', 'brush'), ('antialias', 'antialias')]:
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillBrush', 'brush'), ('antialias', 'antialias'), ('connect', 'connect')]:
curveArgs[v] = self.opts[k]
scatterArgs = {}
......@@ -454,7 +460,7 @@ class PlotDataItem(GraphicsObject):
scatterArgs[v] = self.opts[k]
x,y = self.getData()
scatterArgs['mask'] = self.dataMask
#scatterArgs['mask'] = self.dataMask
if curveArgs['pen'] is not None or (curveArgs['brush'] is not None and curveArgs['fillLevel'] is not None):
self.curve.setData(x=x, y=y, **curveArgs)
......@@ -473,20 +479,20 @@ class PlotDataItem(GraphicsObject):
if self.xData is None:
return (None, None)
if self.xClean is None:
nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
if nanMask.any():
self.dataMask = ~nanMask
self.xClean = self.xData[self.dataMask]
self.yClean = self.yData[self.dataMask]
else:
self.dataMask = None
self.xClean = self.xData
self.yClean = self.yData
#if self.xClean is None:
#nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
#if nanMask.any():
#self.dataMask = ~nanMask
#self.xClean = self.xData[self.dataMask]
#self.yClean = self.yData[self.dataMask]
#else:
#self.dataMask = None
#self.xClean = self.xData
#self.yClean = self.yData
if self.xDisp is None:
x = self.xClean
y = self.yClean
x = self.xData
y = self.yData
#ds = self.opts['downsample']
......@@ -500,14 +506,14 @@ class PlotDataItem(GraphicsObject):
x = np.log10(x)
if self.opts['logMode'][1]:
y = np.log10(y)
if any(self.opts['logMode']): ## re-check for NANs after log
nanMask = np.isinf(x) | np.isinf(y) | np.isnan(x) | np.isnan(y)
if any(nanMask):
self.dataMask = ~nanMask
x = x[self.dataMask]
y = y[self.dataMask]
else:
self.dataMask = None
#if any(self.opts['logMode']): ## re-check for NANs after log
#nanMask = np.isinf(x) | np.isinf(y) | np.isnan(x) | np.isnan(y)
#if any(nanMask):
#self.dataMask = ~nanMask
#x = x[self.dataMask]
#y = y[self.dataMask]
#else:
#self.dataMask = None
ds = self.opts['downsample']
if not isinstance(ds, int):
......@@ -640,8 +646,8 @@ class PlotDataItem(GraphicsObject):
#self.scatters = []
self.xData = None
self.yData = None
self.xClean = None
self.yClean = None
#self.xClean = None
#self.yClean = None
self.xDisp = None
self.yDisp = None
self.curve.setData([])
......
......@@ -626,11 +626,13 @@ class ScatterPlotItem(GraphicsObject):
d2 = d2[mask]
if frac >= 1.0:
self.bounds[ax] = (d.min() - self._maxSpotWidth*0.7072, d.max() + self._maxSpotWidth*0.7072)
self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
return self.bounds[ax]
elif frac <= 0.0:
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
else:
mask = np.isfinite(d)
d = d[mask]
return (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
def pixelPadding(self):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment