Bugfixes and updates to functions.py:

- generalized makeARGB API: can now process arrays of arbitrary shape.
  - affineSlice automatically converts vector arguments to array
  - new function applyLookupTable taken from makeARGB
  - isosurface function returns array
Updated VideoSpeedTest example to follow new makeARGB API

LayoutWidget: row argument now accepts 'next' as value
ParameterTree bugfix: avoid infinite recursion when accessing non-existent attributes
ViewBox: avoid exit error caused when cleanup callback is invoked while python is shutting down
This commit is contained in:
Luke Campagnola 2012-11-23 16:01:25 -05:00
parent a5a40be8bb
commit e5f383fbb5
9 changed files with 273 additions and 184 deletions

View File

@ -61,37 +61,41 @@ ui.alphaCheck.toggled.connect(updateLUT)
def updateScale():
global ui
spins = [ui.minSpin1, ui.maxSpin1, ui.minSpin2, ui.maxSpin2, ui.minSpin3, ui.maxSpin3]
if ui.rgbCheck.isChecked():
if ui.rgbLevelsCheck.isChecked():
for s in spins[2:]:
s.setEnabled(True)
else:
for s in spins[2:]:
s.setEnabled(False)
ui.rgbCheck.toggled.connect(updateScale)
ui.rgbLevelsCheck.toggled.connect(updateScale)
cache = {}
def mkData():
global data, cache, ui
dtype = ui.dtypeCombo.currentText()
dtype = (ui.dtypeCombo.currentText(), ui.rgbCheck.isChecked())
if dtype not in cache:
if dtype == 'uint8':
if dtype[0] == 'uint8':
dt = np.uint8
loc = 128
scale = 64
mx = 255
elif dtype == 'uint16':
elif dtype[0] == 'uint16':
dt = np.uint16
loc = 4096
scale = 1024
mx = 2**16
elif dtype == 'float':
elif dtype[0] == 'float':
dt = np.float
loc = 1.0
scale = 0.1
data = np.random.normal(size=(20,512,512), loc=loc, scale=scale)
data = ndi.gaussian_filter(data, (0, 3, 3))
if dtype != 'float':
if ui.rgbCheck.isChecked():
data = np.random.normal(size=(20,512,512,3), loc=loc, scale=scale)
data = ndi.gaussian_filter(data, (0, 6, 6, 0))
else:
data = np.random.normal(size=(20,512,512), loc=loc, scale=scale)
data = ndi.gaussian_filter(data, (0, 6, 6))
if dtype[0] != 'float':
data = np.clip(data, 0, mx)
data = data.astype(dt)
cache[dtype] = data
@ -100,7 +104,7 @@ def mkData():
updateLUT()
mkData()
ui.dtypeCombo.currentIndexChanged.connect(mkData)
ui.rgbCheck.toggled.connect(mkData)
ptr = 0
lastTime = ptime.time()
@ -113,7 +117,7 @@ def update():
useLut = None
if ui.scaleCheck.isChecked():
if ui.rgbCheck.isChecked():
if ui.rgbLevelsCheck.isChecked():
useScale = [
[ui.minSpin1.value(), ui.maxSpin1.value()],
[ui.minSpin2.value(), ui.maxSpin2.value()],

View File

@ -25,7 +25,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<zorder>fpsLabel</zorder>
</widget>
</item>
<item row="0" column="1">
@ -84,7 +83,7 @@
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="rgbCheck">
<widget class="QCheckBox" name="rgbLevelsCheck">
<property name="text">
<string>RGB</string>
</property>
@ -218,6 +217,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="rgbCheck">
<property name="text">
<string>RGB</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file './examples/VideoTemplate.ui'
#
# Created: Sun Sep 9 14:41:31 2012
# Created: Sun Nov 4 18:24:20 2012
# by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!
@ -55,9 +55,9 @@ class Ui_MainWindow(object):
self.scaleCheck = QtGui.QCheckBox(self.centralwidget)
self.scaleCheck.setObjectName(_fromUtf8("scaleCheck"))
self.gridLayout_2.addWidget(self.scaleCheck, 3, 0, 1, 1)
self.rgbCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbCheck.setObjectName(_fromUtf8("rgbCheck"))
self.gridLayout_2.addWidget(self.rgbCheck, 3, 1, 1, 1)
self.rgbLevelsCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbLevelsCheck.setObjectName(_fromUtf8("rgbLevelsCheck"))
self.gridLayout_2.addWidget(self.rgbLevelsCheck, 3, 1, 1, 1)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.minSpin1 = SpinBox(self.centralwidget)
@ -124,6 +124,9 @@ class Ui_MainWindow(object):
self.fpsLabel.setAlignment(QtCore.Qt.AlignCenter)
self.fpsLabel.setObjectName(_fromUtf8("fpsLabel"))
self.gridLayout_2.addWidget(self.fpsLabel, 0, 0, 1, 4)
self.rgbCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbCheck.setObjectName(_fromUtf8("rgbCheck"))
self.gridLayout_2.addWidget(self.rgbCheck, 2, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
@ -138,12 +141,13 @@ class Ui_MainWindow(object):
self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(2, QtGui.QApplication.translate("MainWindow", "float", None, QtGui.QApplication.UnicodeUTF8))
self.scaleCheck.setText(QtGui.QApplication.translate("MainWindow", "Scale Data", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
self.rgbLevelsCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.lutCheck.setText(QtGui.QApplication.translate("MainWindow", "Use Lookup Table", None, QtGui.QApplication.UnicodeUTF8))
self.alphaCheck.setText(QtGui.QApplication.translate("MainWindow", "alpha", None, QtGui.QApplication.UnicodeUTF8))
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file './examples/VideoTemplate.ui'
#
# Created: Sun Sep 9 14:41:31 2012
# Created: Sun Nov 4 18:24:21 2012
# by: pyside-uic 0.2.13 running on PySide 1.1.0
#
# WARNING! All changes made in this file will be lost!
@ -50,9 +50,9 @@ class Ui_MainWindow(object):
self.scaleCheck = QtGui.QCheckBox(self.centralwidget)
self.scaleCheck.setObjectName("scaleCheck")
self.gridLayout_2.addWidget(self.scaleCheck, 3, 0, 1, 1)
self.rgbCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbCheck.setObjectName("rgbCheck")
self.gridLayout_2.addWidget(self.rgbCheck, 3, 1, 1, 1)
self.rgbLevelsCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbLevelsCheck.setObjectName("rgbLevelsCheck")
self.gridLayout_2.addWidget(self.rgbLevelsCheck, 3, 1, 1, 1)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.minSpin1 = SpinBox(self.centralwidget)
@ -119,6 +119,9 @@ class Ui_MainWindow(object):
self.fpsLabel.setAlignment(QtCore.Qt.AlignCenter)
self.fpsLabel.setObjectName("fpsLabel")
self.gridLayout_2.addWidget(self.fpsLabel, 0, 0, 1, 4)
self.rgbCheck = QtGui.QCheckBox(self.centralwidget)
self.rgbCheck.setObjectName("rgbCheck")
self.gridLayout_2.addWidget(self.rgbCheck, 2, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
@ -133,12 +136,13 @@ class Ui_MainWindow(object):
self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(2, QtGui.QApplication.translate("MainWindow", "float", None, QtGui.QApplication.UnicodeUTF8))
self.scaleCheck.setText(QtGui.QApplication.translate("MainWindow", "Scale Data", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
self.rgbLevelsCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("MainWindow", "<--->", None, QtGui.QApplication.UnicodeUTF8))
self.lutCheck.setText(QtGui.QApplication.translate("MainWindow", "Use Lookup Table", None, QtGui.QApplication.UnicodeUTF8))
self.alphaCheck.setText(QtGui.QApplication.translate("MainWindow", "alpha", None, QtGui.QApplication.UnicodeUTF8))
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget

View File

@ -434,8 +434,10 @@ def affineSlice(data, shape, origin, vectors, axes, order=1, returnCoords=False,
## make sure vectors are arrays
vectors = np.array(vectors)
origin = np.array(origin)
if not isinstance(vectors, np.ndarray):
vectors = np.array(vectors)
if not isinstance(origin, np.ndarray):
origin = np.array(origin)
origin.shape = (len(axes),) + (1,)*len(shape)
## Build array of sample locations.
@ -580,171 +582,247 @@ def solveBilinearTransform(points1, points2):
return matrix
def rescaleData(data, scale, offset, dtype=None):
"""Return data rescaled and optionally cast to a new dtype::
data => (data-offset) * scale
Uses scipy.weave (if available) to improve performance.
"""
global USE_WEAVE
if dtype is None:
dtype = data.dtype
try:
if not USE_WEAVE:
raise Exception('Weave is disabled; falling back to slower version.')
newData = np.empty((data.size,), dtype=dtype)
flat = np.ascontiguousarray(data).reshape(data.size)
size = data.size
code = """
double sc = (double)scale;
double off = (double)offset;
for( int i=0; i<size; i++ ) {
newData[i] = ((double)flat[i] - off) * sc;
}
"""
scipy.weave.inline(code, ['flat', 'newData', 'size', 'offset', 'scale'], compiler='gcc')
data = newData.reshape(data.shape)
except:
if USE_WEAVE:
debug.printExc("Error; disabling weave.")
USE_WEAVE = False
#p = np.poly1d([scale, -offset*scale])
#data = p(data).astype(dtype)
d2 = data-offset
d2 *= scale
data = d2.astype(dtype)
return data
def applyLookupTable(data, lut):
"""
Uses values in *data* as indexes to select values from *lut*.
The returned data has shape data.shape + lut.shape[1:]
Uses scipy.weave to improve performance if it is available.
Note: color gradient lookup tables can be generated using GradientWidget.
"""
global USE_WEAVE
if data.dtype.kind not in ('i', 'u'):
data = data.astype(int)
## using np.take appears to be faster than even the scipy.weave method and takes care of clipping as well.
return np.take(lut, data, axis=0, mode='clip')
### old methods:
#data = np.clip(data, 0, lut.shape[0]-1)
#try:
#if not USE_WEAVE:
#raise Exception('Weave is disabled; falling back to slower version.')
### number of values to copy for each LUT lookup
#if lut.ndim == 1:
#ncol = 1
#else:
#ncol = sum(lut.shape[1:])
### output array
#newData = np.empty((data.size, ncol), dtype=lut.dtype)
### flattened input arrays
#flatData = data.flatten()
#flatLut = lut.reshape((lut.shape[0], ncol))
#dataSize = data.size
### strides for accessing each item
#newStride = newData.strides[0] / newData.dtype.itemsize
#lutStride = flatLut.strides[0] / flatLut.dtype.itemsize
#dataStride = flatData.strides[0] / flatData.dtype.itemsize
### strides for accessing individual values within a single LUT lookup
#newColStride = newData.strides[1] / newData.dtype.itemsize
#lutColStride = flatLut.strides[1] / flatLut.dtype.itemsize
#code = """
#for( int i=0; i<dataSize; i++ ) {
#for( int j=0; j<ncol; j++ ) {
#newData[i*newStride + j*newColStride] = flatLut[flatData[i*dataStride]*lutStride + j*lutColStride];
#}
#}
#"""
#scipy.weave.inline(code, ['flatData', 'flatLut', 'newData', 'dataSize', 'ncol', 'newStride', 'lutStride', 'dataStride', 'newColStride', 'lutColStride'])
#newData = newData.reshape(data.shape + lut.shape[1:])
##if np.any(newData != lut[data]):
##print "mismatch!"
#data = newData
#except:
#if USE_WEAVE:
#debug.printExc("Error; disabling weave.")
#USE_WEAVE = False
#data = lut[data]
#return data
def makeRGBA(*args, **kwds):
"""Equivalent to makeARGB(..., useRGBA=True)"""
kwds['useRGBA'] = True
return makeARGB(*args, **kwds)
def makeARGB(data, lut=None, levels=None, useRGBA=False):
def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False):
"""
Convert a 2D or 3D array into an ARGB array suitable for building QImages
Will optionally do scaling and/or table lookups to determine final colors.
Convert an array of values into an ARGB array suitable for building QImages, OpenGL textures, etc.
Returns the ARGB array (values 0-255) and a boolean indicating whether there is alpha channel data.
This is a two stage process:
1) Rescale the data based on the values in the *levels* argument (min, max).
2) Determine the final output by passing the rescaled values through a lookup table.
Both stages are optional.
============ ==================================================================================
Arguments:
data - 2D or 3D numpy array of int/float types
For 2D arrays (x, y):
* The color will be determined using a lookup table (see argument 'lut').
* If levels are given, the data is rescaled and converted to int
before using the lookup table.
data numpy array of int/float types. If
levels List [min, max]; optionally rescale data before converting through the
lookup table. The data is rescaled such that min->0 and max->*scale*::
For 3D arrays (x, y, rgba):
* The third axis must have length 3 or 4 and will be interpreted as RGBA.
* The 'lut' argument is not allowed.
rescaled = (clip(data, min, max) - min) * (*scale* / (max - min))
lut - Lookup table for 2D data. May be 1D or 2D (N,rgba) and must have dtype=ubyte.
Values in data will be converted to color by indexing directly from lut.
Lookup tables can be built using GradientWidget.
levels - List [min, max]; optionally rescale data before converting through the
lookup table. rescaled = (data-min) * len(lut) / (max-min)
useRGBA - If True, the data is returned in RGBA order (useful for building OpenGL textures). The default is
False, which returns in BGRA order for use with QImage.
It is also possible to use a 2D (N,2) array of values for levels. In this case,
it is assumed that each pair of min,max values in the levels array should be
applied to a different subset of the input data (for example, the input data may
already have RGB values and the levels are used to independently scale each
channel). The use of this feature requires that levels.shape[0] == data.shape[-1].
scale The maximum value to which data will be rescaled before being passed through the
lookup table (or returned if there is no lookup table). By default this will
be set to the length of the lookup table, or 256 is no lookup table is provided.
For OpenGL color specifications (as in GLColor4f) use scale=1.0
lut Optional lookup table (array with dtype=ubyte).
Values in data will be converted to color by indexing directly from lut.
The output data shape will be input.shape + lut.shape[1:].
Note: the output of makeARGB will have the same dtype as the lookup table, so
for conversion to QImage, the dtype must be ubyte.
Lookup tables can be built using GradientWidget.
useRGBA If True, the data is returned in RGBA order (useful for building OpenGL textures).
The default is False, which returns in ARGB order for use with QImage
(Note that 'ARGB' is a term used by the Qt documentation; the _actual_ order
is BGRA).
============ ==================================================================================
"""
prof = debug.Profiler('functions.makeARGB', disabled=True)
if lut is not None and not isinstance(lut, np.ndarray):
lut = np.array(lut)
if levels is not None and not isinstance(levels, np.ndarray):
levels = np.array(levels)
## sanity checks
if data.ndim == 3:
if data.shape[2] not in (3,4):
raise Exception("data.shape[2] must be 3 or 4")
#if lut is not None:
#raise Exception("can not use lookup table with 3D data")
elif data.ndim != 2:
raise Exception("data must be 2D or 3D")
#if data.ndim == 3:
#if data.shape[2] not in (3,4):
#raise Exception("data.shape[2] must be 3 or 4")
##if lut is not None:
##raise Exception("can not use lookup table with 3D data")
#elif data.ndim != 2:
#raise Exception("data must be 2D or 3D")
if lut is not None:
if lut.ndim == 2:
if lut.shape[1] not in (3,4):
raise Exception("lut.shape[1] must be 3 or 4")
elif lut.ndim != 1:
raise Exception("lut must be 1D or 2D")
if lut.dtype != np.ubyte:
raise Exception('lookup table must have dtype=ubyte (got %s instead)' % str(lut.dtype))
#if lut is not None:
##if lut.ndim == 2:
##if lut.shape[1] :
##raise Exception("lut.shape[1] must be 3 or 4")
##elif lut.ndim != 1:
##raise Exception("lut must be 1D or 2D")
#if lut.dtype != np.ubyte:
#raise Exception('lookup table must have dtype=ubyte (got %s instead)' % str(lut.dtype))
if levels is not None:
levels = np.array(levels)
if levels.shape == (2,):
pass
elif levels.shape in [(3,2), (4,2)]:
if data.ndim == 3:
raise Exception("Can not use 2D levels with 3D data.")
if lut is not None:
raise Exception('Can not use 2D levels and lookup table together.')
if levels.ndim == 1:
if len(levels) != 2:
raise Exception('levels argument must have length 2')
elif levels.ndim == 2:
if lut is not None and lut.ndim > 1:
raise Exception('Cannot make ARGB data when bot levels and lut have ndim > 2')
if levels.shape != (data.shape[-1], 2):
raise Exception('levels must have shape (data.shape[-1], 2)')
else:
raise Exception("Levels must have shape (2,) or (3,2) or (4,2)")
print levels
raise Exception("levels argument must be 1D or 2D.")
#levels = np.array(levels)
#if levels.shape == (2,):
#pass
#elif levels.shape in [(3,2), (4,2)]:
#if data.ndim == 3:
#raise Exception("Can not use 2D levels with 3D data.")
#if lut is not None:
#raise Exception('Can not use 2D levels and lookup table together.')
#else:
#raise Exception("Levels must have shape (2,) or (3,2) or (4,2)")
prof.mark('1')
if lut is not None:
lutLength = lut.shape[0]
else:
lutLength = 256
## weave requires contiguous arrays
global USE_WEAVE
if (levels is not None or lut is not None) and USE_WEAVE:
data = np.ascontiguousarray(data)
if scale is None:
if lut is not None:
scale = lut.shape[0]
else:
scale = 255.
## Apply levels if given
if levels is not None:
try: ## use weave to speed up scaling
if not USE_WEAVE:
raise Exception('Weave is disabled; falling back to slower version.')
if levels.ndim == 1:
scale = float(lutLength) / (levels[1]-levels[0])
offset = float(levels[0])
data = rescaleData(data, scale, offset)
else:
if data.ndim == 2:
newData = np.empty(data.shape+(levels.shape[0],), dtype=np.uint32)
for i in range(levels.shape[0]):
scale = float(lutLength / (levels[i,1]-levels[i,0]))
offset = float(levels[i,0])
newData[...,i] = rescaleData(data, scale, offset)
elif data.ndim == 3:
newData = np.empty(data.shape, dtype=np.uint32)
for i in range(data.shape[2]):
scale = float(lutLength / (levels[i,1]-levels[i,0]))
offset = float(levels[i,0])
#print scale, offset, data.shape, newData.shape, levels.shape
newData[...,i] = rescaleData(data[...,i], scale, offset)
data = newData
except:
if USE_WEAVE:
debug.printExc("Error; disabling weave.")
USE_WEAVE = False
if levels.ndim == 1:
if data.ndim == 2:
levels = levels[np.newaxis, np.newaxis, :]
else:
levels = levels[np.newaxis, np.newaxis, np.newaxis, :]
else:
levels = levels[np.newaxis, np.newaxis, ...]
if data.ndim == 2:
data = data[..., np.newaxis]
data = ((data-levels[...,0]) * lutLength) / (levels[...,1]-levels[...,0])
if isinstance(levels, np.ndarray) and levels.ndim == 2:
## we are going to rescale each channel independently
if levels.shape[0] != data.shape[-1]:
raise Exception("When rescaling multi-channel data, there must be the same number of levels as channels (data.shape[-1] == levels.shape[0])")
newData = np.empty(data.shape, dtype=int)
for i in range(data.shape[-1]):
minVal, maxVal = levels[i]
if minVal == maxVal:
maxVal += 1e-16
newData[...,i] = rescaleData(data[...,i], scale/(maxVal-minVal), minVal, dtype=int)
data = newData
else:
minVal, maxVal = levels
if minVal == maxVal:
maxVal += 1e-16
data = rescaleData(data, scale/(maxVal-minVal), minVal, dtype=int)
prof.mark('2')
## apply LUT if given
if lut is not None and data.ndim == 2:
if data.dtype.kind not in ('i', 'u'):
data = data.astype(int)
data = np.clip(data, 0, lutLength-1)
try:
if not USE_WEAVE:
raise Exception('Weave is disabled; falling back to slower version.')
newData = np.empty((data.size,) + lut.shape[1:], dtype=np.uint8)
flat = data.reshape(data.size)
size = data.size
ncol = lut.shape[1]
newStride = newData.strides[0]
newColStride = newData.strides[1]
lutStride = lut.strides[0]
lutColStride = lut.strides[1]
flatStride = flat.strides[0] / flat.dtype.itemsize
#print "newData:", newData.shape, newData.dtype
#print "flat:", flat.shape, flat.dtype, flat.min(), flat.max()
#print "lut:", lut.shape, lut.dtype
#print "size:", size, "ncols:", ncol
#print "strides:", newStride, newColStride, lutStride, lutColStride, flatStride
code = """
for( int i=0; i<size; i++ ) {
for( int j=0; j<ncol; j++ ) {
newData[i*newStride + j*newColStride] = lut[flat[i*flatStride]*lutStride + j*lutColStride];
}
}
"""
scipy.weave.inline(code, ['flat', 'lut', 'newData', 'size', 'ncol', 'newStride', 'lutStride', 'flatStride', 'newColStride', 'lutColStride'])
data = newData.reshape(data.shape + lut.shape[1:])
except:
if USE_WEAVE:
debug.printExc("Error; disabling weave.")
USE_WEAVE = False
data = lut[data]
if lut is not None:
data = applyLookupTable(data, lut)
else:
if data.dtype is not np.ubyte:
data = np.clip(data, 0, 255).astype(np.ubyte)
@ -895,25 +973,6 @@ def imageToArray(img, copy=False, transpose=True):
return arr
def rescaleData(data, scale, offset):
newData = np.empty((data.size,), dtype=np.int)
flat = data.reshape(data.size)
size = data.size
code = """
double sc = (double)scale;
double off = (double)offset;
for( int i=0; i<size; i++ ) {
newData[i] = (int)(((double)flat[i] - off) * sc);
}
"""
scipy.weave.inline(code, ['flat', 'newData', 'size', 'offset', 'scale'], compiler='gcc')
data = newData.reshape(data.shape)
return data
#def isosurface(data, level):
#"""
#Generate isosurface from volumetric data using marching tetrahedra algorithm.
@ -1090,7 +1149,7 @@ def isosurface(data, level):
*data* 3D numpy array of scalar values
*level* The level at which to generate an isosurface
Returns a list of faces; each face is a list of three vertexes and each vertex is a tuple of three floats.
Returns an array of vertex coordinates (N, 3, 3);
This function is SLOW; plenty of room for optimization here.
"""
@ -1457,7 +1516,7 @@ def isosurface(data, level):
pts.append(p)
facets.append(pts)
return facets
return np.array(facets)

View File

@ -166,13 +166,15 @@ class GraphicsItem(object):
## attempt to re-scale direction vector to fit within the precision of the coordinate system
if direction.x() == 0:
r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
#r = 1.0/(abs(dt.m12()) + abs(dt.m22()))
elif direction.y() == 0:
r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
#r = 1.0/(abs(dt.m11()) + abs(dt.m21()))
else:
r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
direction = direction * r
directionr = direction * r
viewDir = Point(dt.map(direction) - dt.map(Point(0,0)))
viewDir = Point(dt.map(directionr) - dt.map(Point(0,0)))
if viewDir.manhattanLength() == 0:
return None, None ## pixel size cannot be represented on this scale
@ -182,7 +184,7 @@ class GraphicsItem(object):
normView = viewDir.norm() ## direction of one pixel orthogonal to line
normOrtho = orthoDir.norm()
except:
raise Exception("Invalid direction %s" %direction)
raise Exception("Invalid direction %s" %directionr)
dti = fn.invertQTransform(dt)

View File

@ -166,7 +166,7 @@ class ViewBox(GraphicsWidget):
ViewBox.NamedViews[name] = self
ViewBox.updateAllViewLists()
sid = id(self)
self.destroyed.connect(lambda: ViewBox.forgetView(sid, name) if ViewBox is not None else None)
self.destroyed.connect(lambda: ViewBox.forgetView(sid, name) if (ViewBox is not None and 'sid' in locals() and 'name' in locals()) else None)
#self.destroyed.connect(self.unregister)
def unregister(self):
@ -1154,7 +1154,7 @@ class ViewBox(GraphicsWidget):
if any(changed):
self.sigRangeChanged.emit(self, self.state['viewRange'])
self.sigTransformChanged.emit(self)
self.sigTransformChanged.emit(self) ## segfaults here: 1
def paint(self, p, opt, widget):
if self.border is not None:

View File

@ -460,7 +460,10 @@ class Parameter(QtCore.QObject):
self.childs.pop(self.childs.index(child))
child.parentChanged(None)
self.sigChildRemoved.emit(self, child)
child.sigTreeStateChanged.disconnect(self.treeStateChanged)
try:
child.sigTreeStateChanged.disconnect(self.treeStateChanged)
except TypeError: ## already disconnected
pass
def clearChildren(self):
"""Remove all child parameters."""
@ -550,6 +553,8 @@ class Parameter(QtCore.QObject):
def __getattr__(self, attr):
## Leaving this undocumented because I might like to remove it in the future..
#print type(self), attr
if 'names' not in self.__dict__:
raise AttributeError(attr)
if attr in self.names:
return self.param(attr)
else:

View File

@ -56,8 +56,13 @@ class LayoutWidget(QtGui.QWidget):
"""
Add a widget to the layout and place it in the next available cell (or in the cell specified).
"""
if row is None:
if row == 'next':
self.nextRow()
row = self.currentRow
elif row is None:
row = self.currentRow
if col is None:
col = self.nextCol(colspan)