PlotCurveItem now has 'step' mode for drawing histograms
Added function for generating pseudo-scatter plots (points stack in a histogram-like manner)
This commit is contained in:
parent
16434272c2
commit
15d9c1b351
49
functions.py
49
functions.py
@ -1469,3 +1469,52 @@ def invertQTransform(tr):
|
|||||||
return QtGui.QTransform(inv[0,0], inv[0,1], inv[0,2], inv[1,0], inv[1,1], inv[1,2], inv[2,0], inv[2,1])
|
return QtGui.QTransform(inv[0,0], inv[0,1], inv[0,2], inv[1,0], inv[1,1], inv[1,2], inv[2,0], inv[2,1])
|
||||||
|
|
||||||
|
|
||||||
|
def pseudoScatter(data, spacing=None, shuffle=True):
|
||||||
|
"""
|
||||||
|
Used for examining the distribution of values in a set.
|
||||||
|
|
||||||
|
Given a list of x-values, construct a set of y-values such that an x,y scatter-plot
|
||||||
|
will not have overlapping points (it will look similar to a histogram).
|
||||||
|
"""
|
||||||
|
inds = np.arange(len(data))
|
||||||
|
if shuffle:
|
||||||
|
np.random.shuffle(inds)
|
||||||
|
|
||||||
|
data = data[inds]
|
||||||
|
|
||||||
|
if spacing is None:
|
||||||
|
spacing = 2.*np.std(data)/len(data)**0.5
|
||||||
|
s2 = spacing**2
|
||||||
|
|
||||||
|
yvals = np.empty(len(data))
|
||||||
|
yvals[0] = 0
|
||||||
|
for i in range(1,len(data)):
|
||||||
|
x = data[i] # current x value to be placed
|
||||||
|
x0 = data[:i] # all x values already placed
|
||||||
|
y0 = yvals[:i] # all y values already placed
|
||||||
|
y = 0
|
||||||
|
|
||||||
|
dx = (x0-x)**2 # x-distance to each previous point
|
||||||
|
xmask = dx < s2 # exclude anything too far away
|
||||||
|
|
||||||
|
if xmask.sum() > 0:
|
||||||
|
dx = dx[xmask]
|
||||||
|
dy = (s2 - dx)**0.5
|
||||||
|
limits = np.empty((2,len(dy))) # ranges of y-values to exclude
|
||||||
|
limits[0] = y0[xmask] - dy
|
||||||
|
limits[1] = y0[xmask] + dy
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# ignore anything below this y-value
|
||||||
|
mask = limits[1] >= y
|
||||||
|
limits = limits[:,mask]
|
||||||
|
|
||||||
|
# are we inside an excluded region?
|
||||||
|
mask = (limits[0] < y) & (limits[1] > y)
|
||||||
|
if mask.sum() == 0:
|
||||||
|
break
|
||||||
|
y = limits[:,mask].max()
|
||||||
|
|
||||||
|
yvals[i] = y
|
||||||
|
|
||||||
|
return yvals[np.argsort(inds)] ## un-shuffle values before returning
|
@ -64,6 +64,7 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
'shadowPen': None,
|
'shadowPen': None,
|
||||||
'fillLevel': None,
|
'fillLevel': None,
|
||||||
'brush': None,
|
'brush': None,
|
||||||
|
'stepMode': False,
|
||||||
}
|
}
|
||||||
self.setClickable(kargs.get('clickable', False))
|
self.setClickable(kargs.get('clickable', False))
|
||||||
self.setData(*args, **kargs)
|
self.setData(*args, **kargs)
|
||||||
@ -223,7 +224,14 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
|
|
||||||
prof.mark('copy')
|
prof.mark('copy')
|
||||||
|
|
||||||
if self.xData.shape != self.yData.shape:
|
if 'stepMode' in kargs:
|
||||||
|
self.opts['stepMode'] = kargs['stepMode']
|
||||||
|
|
||||||
|
if self.opts['stepMode'] is True:
|
||||||
|
if len(self.xData) != len(self.yData)+1: ## allow difference of 1 for step mode plots
|
||||||
|
raise Exception("len(X) must be len(Y)+1 since stepMode=True (got %s and %s)" % (str(x.shape), str(y.shape)))
|
||||||
|
else:
|
||||||
|
if self.xData.shape != self.yData.shape: ## allow difference of 1 for step mode plots
|
||||||
raise Exception("X and Y arrays must be the same shape--got %s and %s." % (str(x.shape), str(y.shape)))
|
raise Exception("X and Y arrays must be the same shape--got %s and %s." % (str(x.shape), str(y.shape)))
|
||||||
|
|
||||||
self.path = None
|
self.path = None
|
||||||
@ -267,6 +275,29 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
## 0(i4)
|
## 0(i4)
|
||||||
##
|
##
|
||||||
## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')
|
## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')
|
||||||
|
|
||||||
|
if self.opts['stepMode']:
|
||||||
|
## each value in the x/y arrays generates 2 points.
|
||||||
|
x2 = np.empty((len(x),2), dtype=x.dtype)
|
||||||
|
x2[:] = x[:,np.newaxis]
|
||||||
|
if self.opts['fillLevel'] is None:
|
||||||
|
x = x2.reshape(x2.size)[1:-1]
|
||||||
|
y2 = np.empty((len(y),2), dtype=y.dtype)
|
||||||
|
y2[:] = y[:,np.newaxis]
|
||||||
|
y = y2.reshape(y2.size)
|
||||||
|
else:
|
||||||
|
## If we have a fill level, add two extra points at either end
|
||||||
|
x = x2.reshape(x2.size)
|
||||||
|
y2 = np.empty((len(y)+2,2), dtype=y.dtype)
|
||||||
|
y2[1:-1] = y[:,np.newaxis]
|
||||||
|
y = y2.reshape(y2.size)[1:-1]
|
||||||
|
y[0] = self.opts['fillLevel']
|
||||||
|
y[-1] = self.opts['fillLevel']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[0] == 2: ## So this is disabled for python 3... why??
|
if sys.version_info[0] == 2: ## So this is disabled for python 3... why??
|
||||||
n = x.shape[0]
|
n = x.shape[0]
|
||||||
# create empty array, pad with extra space on either end
|
# create empty array, pad with extra space on either end
|
||||||
@ -324,11 +355,20 @@ class PlotCurveItem(GraphicsObject):
|
|||||||
pixels = self.pixelVectors()
|
pixels = self.pixelVectors()
|
||||||
if pixels == (None, None):
|
if pixels == (None, None):
|
||||||
pixels = [Point(0,0), Point(0,0)]
|
pixels = [Point(0,0), Point(0,0)]
|
||||||
xmin = x.min() - pixels[0].x() * lineWidth
|
|
||||||
xmax = x.max() + pixels[0].x() * lineWidth
|
|
||||||
ymin = y.min() - abs(pixels[1].y()) * lineWidth
|
|
||||||
ymax = y.max() + abs(pixels[1].y()) * lineWidth
|
|
||||||
|
|
||||||
|
xmin = x.min()
|
||||||
|
xmax = x.max()
|
||||||
|
ymin = y.min()
|
||||||
|
ymax = y.max()
|
||||||
|
|
||||||
|
if self.opts['fillLevel'] is not None:
|
||||||
|
ymin = min(ymin, self.opts['fillLevel'])
|
||||||
|
ymax = max(ymax, self.opts['fillLevel'])
|
||||||
|
|
||||||
|
xmin -= pixels[0].x() * lineWidth
|
||||||
|
xmax += pixels[0].x() * lineWidth
|
||||||
|
ymin -= abs(pixels[1].y()) * lineWidth
|
||||||
|
ymax += abs(pixels[1].y()) * lineWidth
|
||||||
|
|
||||||
return QtCore.QRectF(xmin, ymin, xmax-xmin, ymax-ymin)
|
return QtCore.QRectF(xmin, ymin, xmax-xmin, ymax-ymin)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user