Added python3 support for efficient method in arrayToQPath

This commit is contained in:
Luke Campagnola 2013-07-04 08:34:18 -04:00
parent 6e253e409b
commit 934e50ad55

View File

@ -1081,9 +1081,24 @@ def arrayToQPath(x, y, connect='all'):
## Create all vertices in path. The method used below creates a binary format so that all ## Create all vertices in path. The method used below creates a binary format so that all
## vertices can be read in at once. This binary format may change in future versions of Qt, ## vertices can be read in at once. This binary format may change in future versions of Qt,
## so the original (slower) method is left here for emergencies: ## so the original (slower) method is left here for emergencies:
#path.moveTo(x[0], y[0]) #path.moveTo(x[0], y[0])
#for i in range(1, y.shape[0]): #if connect == 'all':
# path.lineTo(x[i], y[i]) #for i in range(1, y.shape[0]):
#path.lineTo(x[i], y[i])
#elif connect == 'pairs':
#for i in range(1, y.shape[0]):
#if i%2 == 0:
#path.lineTo(x[i], y[i])
#else:
#path.moveTo(x[i], y[i])
#elif isinstance(connect, np.ndarray):
#for i in range(1, y.shape[0]):
#if connect[i] == 1:
#path.lineTo(x[i], y[i])
#else:
#path.moveTo(x[i], y[i])
#else:
#raise Exception('connect argument must be "all", "pairs", or array')
## Speed this up using >> operator ## Speed this up using >> operator
## Format is: ## Format is:
@ -1098,71 +1113,55 @@ def arrayToQPath(x, y, connect='all'):
path = QtGui.QPainterPath() path = QtGui.QPainterPath()
#prof = debug.Profiler('PlotCurveItem.generatePath', disabled=True) #prof = debug.Profiler('PlotCurveItem.generatePath', disabled=True)
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 arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')])
arr = np.empty(n+2, dtype=[('x', '>f8'), ('y', '>f8'), ('c', '>i4')]) # write first two integers
# write first two integers #prof.mark('allocate empty')
#prof.mark('allocate empty') byteview = arr.view(dtype=np.ubyte)
arr.data[12:20] = struct.pack('>ii', n, 0) byteview[:12] = 0
#prof.mark('pack header') byteview.data[12:20] = struct.pack('>ii', n, 0)
# Fill array with vertex values #prof.mark('pack header')
arr[1:-1]['x'] = x # Fill array with vertex values
arr[1:-1]['y'] = y arr[1:-1]['x'] = x
arr[1:-1]['y'] = y
# decide which points are connected by lines # decide which points are connected by lines
if connect == 'pairs': if connect == 'pairs':
connect = np.empty((n/2,2), dtype=np.int32) connect = np.empty((n/2,2), dtype=np.int32)
connect[:,0] = 1 connect[:,0] = 1
connect[:,1] = 0 connect[:,1] = 0
connect = connect.flatten() connect = connect.flatten()
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):
arr[1:-1]['c'] = connect arr[1:-1]['c'] = connect
else:
raise Exception('connect argument must be "all", "pairs", or array')
#prof.mark('fill array')
# write last 0
lastInd = 20*(n+1)
arr.data[lastInd:lastInd+4] = struct.pack('>i', 0)
#prof.mark('footer')
# create datastream object and stream into path
## Avoiding this method because QByteArray(str) leaks memory in PySide
#buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
path.strn = arr.data[12:lastInd+4] # make sure data doesn't run away
buf = QtCore.QByteArray.fromRawData(path.strn)
#prof.mark('create buffer')
ds = QtCore.QDataStream(buf)
ds >> path
#prof.mark('load')
#prof.finish()
else: else:
## This does exactly the same as above, but less efficiently (and more simply). raise Exception('connect argument must be "all", "pairs", or array')
path.moveTo(x[0], y[0])
if connect == 'all': #prof.mark('fill array')
for i in range(1, y.shape[0]): # write last 0
path.lineTo(x[i], y[i]) lastInd = 20*(n+1)
elif connect == 'pairs': byteview.data[lastInd:lastInd+4] = struct.pack('>i', 0)
for i in range(1, y.shape[0]): #prof.mark('footer')
if i%2 == 0: # create datastream object and stream into path
path.lineTo(x[i], y[i])
else: ## Avoiding this method because QByteArray(str) leaks memory in PySide
path.moveTo(x[i], y[i]) #buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here
elif isinstance(connect, np.ndarray):
for i in range(1, y.shape[0]): path.strn = byteview.data[12:lastInd+4] # make sure data doesn't run away
if connect[i] == 1: try:
path.lineTo(x[i], y[i]) buf = QtCore.QByteArray.fromRawData(path.strn)
else: except TypeError:
path.moveTo(x[i], y[i]) buf = QtCore.QByteArray(bytes(path.strn))
else: #prof.mark('create buffer')
raise Exception('connect argument must be "all", "pairs", or array') ds = QtCore.QDataStream(buf)
ds >> path
#prof.mark('load')
#prof.finish()
return path return path