- 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
This commit is contained in:
parent
5ad39c2509
commit
58048a703c
@ -1133,7 +1133,9 @@ def arrayToQPath(x, y, connect='all'):
|
|||||||
connect[:,0] = 1
|
connect[:,0] = 1
|
||||||
connect[:,1] = 0
|
connect[:,1] = 0
|
||||||
connect = connect.flatten()
|
connect = connect.flatten()
|
||||||
|
if connect == 'finite':
|
||||||
|
connect = np.isfinite(x) & np.isfinite(y)
|
||||||
|
arr[1:-1]['c'] = connect
|
||||||
if connect == 'all':
|
if connect == 'all':
|
||||||
arr[1:-1]['c'] = 1
|
arr[1:-1]['c'] = 1
|
||||||
elif isinstance(connect, np.ndarray):
|
elif isinstance(connect, np.ndarray):
|
||||||
|
@ -71,7 +71,8 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
'brush': None,
|
'brush': None,
|
||||||
'stepMode': False,
|
'stepMode': False,
|
||||||
'name': None,
|
'name': None,
|
||||||
'antialias': pg.getConfigOption('antialias'),
|
'antialias': pg.getConfigOption('antialias'),\
|
||||||
|
'connect': 'all',
|
||||||
}
|
}
|
||||||
self.setClickable(kargs.get('clickable', False))
|
self.setClickable(kargs.get('clickable', False))
|
||||||
self.setData(*args, **kargs)
|
self.setData(*args, **kargs)
|
||||||
@ -119,10 +120,12 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
|
|
||||||
## Get min/max (or percentiles) of the requested data range
|
## Get min/max (or percentiles) of the requested data range
|
||||||
if frac >= 1.0:
|
if frac >= 1.0:
|
||||||
b = (d.min(), d.max())
|
b = (np.nanmin(d), np.nanmax(d))
|
||||||
elif frac <= 0.0:
|
elif frac <= 0.0:
|
||||||
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
|
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
|
||||||
else:
|
else:
|
||||||
|
mask = np.isfinite(d)
|
||||||
|
d = d[mask]
|
||||||
b = (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
|
b = (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
|
||||||
|
|
||||||
## adjust for fill level
|
## adjust for fill level
|
||||||
@ -264,6 +267,12 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
stepMode If True, two orthogonal lines are drawn for each sample
|
stepMode If True, two orthogonal lines are drawn for each sample
|
||||||
as steps. This is commonly used when drawing histograms.
|
as steps. This is commonly used when drawing histograms.
|
||||||
Note that in this case, len(x) == len(y) + 1
|
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
|
If non-keyword arguments are used, they will be interpreted as
|
||||||
@ -326,7 +335,8 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
|
|
||||||
if 'name' in kargs:
|
if 'name' in kargs:
|
||||||
self.opts['name'] = kargs['name']
|
self.opts['name'] = kargs['name']
|
||||||
|
if 'connect' in kargs:
|
||||||
|
self.opts['connect'] = kargs['connect']
|
||||||
if 'pen' in kargs:
|
if 'pen' in kargs:
|
||||||
self.setPen(kargs['pen'])
|
self.setPen(kargs['pen'])
|
||||||
if 'shadowPen' in kargs:
|
if 'shadowPen' in kargs:
|
||||||
@ -365,7 +375,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
y[0] = self.opts['fillLevel']
|
y[0] = self.opts['fillLevel']
|
||||||
y[-1] = 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
|
return path
|
||||||
|
|
||||||
|
@ -58,6 +58,8 @@ class PlotDataItem(GraphicsObject):
|
|||||||
|
|
||||||
**Line style keyword arguments:**
|
**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.
|
pen Pen to use for drawing line between points.
|
||||||
Default is solid grey, 1px width. Use None to disable line drawing.
|
Default is solid grey, 1px width. Use None to disable line drawing.
|
||||||
May be any single argument accepted by :func:`mkPen() <pyqtgraph.mkPen>`
|
May be any single argument accepted by :func:`mkPen() <pyqtgraph.mkPen>`
|
||||||
@ -119,7 +121,7 @@ class PlotDataItem(GraphicsObject):
|
|||||||
self.yData = None
|
self.yData = None
|
||||||
self.xDisp = None
|
self.xDisp = None
|
||||||
self.yDisp = None
|
self.yDisp = None
|
||||||
self.dataMask = None
|
#self.dataMask = None
|
||||||
#self.curves = []
|
#self.curves = []
|
||||||
#self.scatters = []
|
#self.scatters = []
|
||||||
self.curve = PlotCurveItem()
|
self.curve = PlotCurveItem()
|
||||||
@ -133,6 +135,8 @@ class PlotDataItem(GraphicsObject):
|
|||||||
|
|
||||||
#self.clear()
|
#self.clear()
|
||||||
self.opts = {
|
self.opts = {
|
||||||
|
'connect': 'all',
|
||||||
|
|
||||||
'fftMode': False,
|
'fftMode': False,
|
||||||
'logMode': [False, False],
|
'logMode': [False, False],
|
||||||
'alphaHint': 1.0,
|
'alphaHint': 1.0,
|
||||||
@ -386,6 +390,8 @@ class PlotDataItem(GraphicsObject):
|
|||||||
|
|
||||||
if 'name' in kargs:
|
if 'name' in kargs:
|
||||||
self.opts['name'] = kargs['name']
|
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'
|
## if symbol pen/brush are given with no symbol, then assume symbol is 'o'
|
||||||
|
|
||||||
@ -445,7 +451,7 @@ class PlotDataItem(GraphicsObject):
|
|||||||
def updateItems(self):
|
def updateItems(self):
|
||||||
|
|
||||||
curveArgs = {}
|
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]
|
curveArgs[v] = self.opts[k]
|
||||||
|
|
||||||
scatterArgs = {}
|
scatterArgs = {}
|
||||||
@ -454,7 +460,7 @@ class PlotDataItem(GraphicsObject):
|
|||||||
scatterArgs[v] = self.opts[k]
|
scatterArgs[v] = self.opts[k]
|
||||||
|
|
||||||
x,y = self.getData()
|
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):
|
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)
|
self.curve.setData(x=x, y=y, **curveArgs)
|
||||||
@ -473,20 +479,20 @@ class PlotDataItem(GraphicsObject):
|
|||||||
if self.xData is None:
|
if self.xData is None:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
if self.xClean is None:
|
#if self.xClean is None:
|
||||||
nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
|
#nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
|
||||||
if nanMask.any():
|
#if nanMask.any():
|
||||||
self.dataMask = ~nanMask
|
#self.dataMask = ~nanMask
|
||||||
self.xClean = self.xData[self.dataMask]
|
#self.xClean = self.xData[self.dataMask]
|
||||||
self.yClean = self.yData[self.dataMask]
|
#self.yClean = self.yData[self.dataMask]
|
||||||
else:
|
#else:
|
||||||
self.dataMask = None
|
#self.dataMask = None
|
||||||
self.xClean = self.xData
|
#self.xClean = self.xData
|
||||||
self.yClean = self.yData
|
#self.yClean = self.yData
|
||||||
|
|
||||||
if self.xDisp is None:
|
if self.xDisp is None:
|
||||||
x = self.xClean
|
x = self.xData
|
||||||
y = self.yClean
|
y = self.yData
|
||||||
|
|
||||||
|
|
||||||
#ds = self.opts['downsample']
|
#ds = self.opts['downsample']
|
||||||
@ -500,14 +506,14 @@ class PlotDataItem(GraphicsObject):
|
|||||||
x = np.log10(x)
|
x = np.log10(x)
|
||||||
if self.opts['logMode'][1]:
|
if self.opts['logMode'][1]:
|
||||||
y = np.log10(y)
|
y = np.log10(y)
|
||||||
if any(self.opts['logMode']): ## re-check for NANs after log
|
#if any(self.opts['logMode']): ## re-check for NANs after log
|
||||||
nanMask = np.isinf(x) | np.isinf(y) | np.isnan(x) | np.isnan(y)
|
#nanMask = np.isinf(x) | np.isinf(y) | np.isnan(x) | np.isnan(y)
|
||||||
if any(nanMask):
|
#if any(nanMask):
|
||||||
self.dataMask = ~nanMask
|
#self.dataMask = ~nanMask
|
||||||
x = x[self.dataMask]
|
#x = x[self.dataMask]
|
||||||
y = y[self.dataMask]
|
#y = y[self.dataMask]
|
||||||
else:
|
#else:
|
||||||
self.dataMask = None
|
#self.dataMask = None
|
||||||
|
|
||||||
ds = self.opts['downsample']
|
ds = self.opts['downsample']
|
||||||
if not isinstance(ds, int):
|
if not isinstance(ds, int):
|
||||||
@ -640,8 +646,8 @@ class PlotDataItem(GraphicsObject):
|
|||||||
#self.scatters = []
|
#self.scatters = []
|
||||||
self.xData = None
|
self.xData = None
|
||||||
self.yData = None
|
self.yData = None
|
||||||
self.xClean = None
|
#self.xClean = None
|
||||||
self.yClean = None
|
#self.yClean = None
|
||||||
self.xDisp = None
|
self.xDisp = None
|
||||||
self.yDisp = None
|
self.yDisp = None
|
||||||
self.curve.setData([])
|
self.curve.setData([])
|
||||||
|
@ -626,11 +626,13 @@ class ScatterPlotItem(GraphicsObject):
|
|||||||
d2 = d2[mask]
|
d2 = d2[mask]
|
||||||
|
|
||||||
if frac >= 1.0:
|
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]
|
return self.bounds[ax]
|
||||||
elif frac <= 0.0:
|
elif frac <= 0.0:
|
||||||
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
|
raise Exception("Value for parameter 'frac' must be > 0. (got %s)" % str(frac))
|
||||||
else:
|
else:
|
||||||
|
mask = np.isfinite(d)
|
||||||
|
d = d[mask]
|
||||||
return (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
|
return (scipy.stats.scoreatpercentile(d, 50 - (frac * 50)), scipy.stats.scoreatpercentile(d, 50 + (frac * 50)))
|
||||||
|
|
||||||
def pixelPadding(self):
|
def pixelPadding(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user