diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 3f0c6a3e..14e4e076 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -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): diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index 742c73ef..2fea3d33 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -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 diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py index f9f2febe..1e525f83 100644 --- a/pyqtgraph/graphicsItems/PlotDataItem.py +++ b/pyqtgraph/graphicsItems/PlotDataItem.py @@ -58,6 +58,8 @@ class PlotDataItem(GraphicsObject): **Line style keyword arguments:** ========== ================================================ + connect Specifies how / whether vertexes should be connected. + See :func:`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() ` @@ -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([]) diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index 3070d15a..97f5aa8f 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -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):