diff --git a/__init__.py b/__init__.py index 4256c0e3..398aa020 100644 --- a/__init__.py +++ b/__init__.py @@ -9,7 +9,19 @@ from Qt import QtGui #if QtGui.QApplication.instance() is None: #app = QtGui.QApplication([]) +## in general openGL is poorly supported in Qt. +## we only enable it where the performance benefit is critical. +## Note this only applies to 2D graphics; 3D graphics always use OpenGL. +import sys +if 'linux' in sys.platform: ## linux has numerous bugs in opengl implementation + useOpenGL = False +elif 'darwin' in sys.platform: ## openGL greatly speeds up display on mac + useOpenGL = True +else: + useOpenGL = True ## on windows there's a more even performance / bugginess tradeoff. + CONFIG_OPTIONS = { + 'useOpenGL': None, ## by default, this is platform-dependent (see widgets/GraphicsView). Set to True or False to explicitly enable/disable opengl. 'leftButtonPan': True ## if false, left button drags a rubber band for zooming in viewbox } diff --git a/functions.py b/functions.py index 7a582c4a..de94295b 100644 --- a/functions.py +++ b/functions.py @@ -409,12 +409,12 @@ def affineSlice(data, shape, origin, vectors, axes, **kargs): -def makeARGB(data, lut=None, levels=None): +def makeARGB(data, lut=None, levels=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. - Returns the ARGB array and a boolean indicating whether there is alpha channel data. + Returns the ARGB array (values 0-255) and a boolean indicating whether there is alpha channel data. Arguments: data - 2D or 3D numpy array of int/float types @@ -433,9 +433,10 @@ def makeARGB(data, lut=None, levels=None): 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. The default is + False, which returns in BGRA order for use with QImage. - """ - + """ prof = debug.Profiler('functions.makeARGB', disabled=True) ## sanity checks @@ -580,7 +581,11 @@ def makeARGB(data, lut=None, levels=None): prof.mark('4') - + if useRGBA: + order = [0,1,2,3] ## array comes out RGBA + else: + order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image. + order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image. if data.shape[2] == 1: for i in xrange(3): @@ -732,6 +737,84 @@ def rescaleData(data, scale, offset): #return facets +def isocurve(data, level): + """ + Generate isocurve from 2D data using marching squares algorithm. + + *data* 2D numpy array of scalar values + *level* The level at which to generate an isosurface + + This function is SLOW; plenty of room for optimization here. + """ + + sideTable = [ + [], + [0,1], + [1,2], + [0,2], + [0,3], + [1,3], + [0,1,2,3], + [2,3], + [2,3], + [0,1,2,3], + [1,3], + [0,3], + [0,2], + [1,2], + [0,1], + [] + ] + + edgeKey=[ + [(0,1),(0,0)], + [(0,0), (1,0)], + [(1,0), (1,1)], + [(1,1), (0,1)] + ] + + + lines = [] + + ## mark everything below the isosurface level + mask = data < level + + ### make four sub-fields and compute indexes for grid cells + index = np.zeros([x-1 for x in data.shape], dtype=np.ubyte) + fields = np.empty((2,2), dtype=object) + slices = [slice(0,-1), slice(1,None)] + for i in [0,1]: + for j in [0,1]: + fields[i,j] = mask[slices[i], slices[j]] + #vertIndex = i - 2*j*i + 3*j + 4*k ## this is just to match Bourk's vertex numbering scheme + vertIndex = i+2*j + #print i,j,k," : ", fields[i,j,k], 2**vertIndex + index += fields[i,j] * 2**vertIndex + #print index + #print index + + ## add lines + for i in xrange(index.shape[0]): # data x-axis + for j in xrange(index.shape[1]): # data y-axis + sides = sideTable[index[i,j]] + for l in range(0, len(sides), 2): ## faces for this grid cell + edges = sides[l:l+2] + pts = [] + for m in [0,1]: # points in this face + p1 = edgeKey[edges[m]][0] # p1, p2 are points at either side of an edge + p2 = edgeKey[edges[m]][1] + v1 = data[i+p1[0], j+p1[1]] # v1 and v2 are the values at p1 and p2 + v2 = data[i+p2[0], j+p2[1]] + f = (level-v1) / (v2-v1) + fi = 1.0 - f + p = ( ## interpolate between corners + p1[0]*fi + p2[0]*f + i + 0.5, + p1[1]*fi + p2[1]*f + j + 0.5 + ) + pts.append(p) + lines.append(pts) + + return lines ## a list of pairs of points def isosurface(data, level): diff --git a/graphicsItems/VTickGroup.py b/graphicsItems/VTickGroup.py index 214c57b0..bec74633 100644 --- a/graphicsItems/VTickGroup.py +++ b/graphicsItems/VTickGroup.py @@ -63,6 +63,9 @@ class VTickGroup(UIGraphicsItem): #pass self.rebuildTicks() #self.valid = False + + def dataBounds(self, *args, **kargs): + return None ## item should never affect view autoscaling #def viewRangeChanged(self): ### called when the view is scaled diff --git a/graphicsItems/ViewBox/ViewBox.py b/graphicsItems/ViewBox/ViewBox.py index e83ff9e6..2a7d58a2 100644 --- a/graphicsItems/ViewBox/ViewBox.py +++ b/graphicsItems/ViewBox/ViewBox.py @@ -820,13 +820,13 @@ class ViewBox(GraphicsWidget): frac = (1.0, 1.0) xr = item.dataBounds(0, frac=frac[0]) yr = item.dataBounds(1, frac=frac[1]) - if xr is None: + if xr is None or xr == (None, None): useX = False xr = (0,0) - if yr is None: + if yr is None or yr == (None, None): useY = False yr = (0,0) - + bounds = QtCore.QRectF(xr[0], yr[0], xr[1]-xr[0], yr[1]-yr[0]) #print " item real:", bounds else: diff --git a/parametertree/parameterTypes.py b/parametertree/parameterTypes.py index a286f4f0..6d93470a 100644 --- a/parametertree/parameterTypes.py +++ b/parametertree/parameterTypes.py @@ -405,7 +405,7 @@ class ListParameterItem(WidgetParameterItem): #return vals[key] #else: #return key - print key, self.forward + #print key, self.forward return self.forward[key] def setValue(self, val): diff --git a/widgets/GraphicsView.py b/widgets/GraphicsView.py index 22c5736a..3d3be2da 100644 --- a/widgets/GraphicsView.py +++ b/widgets/GraphicsView.py @@ -16,6 +16,7 @@ from FileDialog import FileDialog from pyqtgraph.GraphicsScene import GraphicsScene import numpy as np import pyqtgraph.functions as fn +import pyqtgraph __all__ = ['GraphicsView'] @@ -38,20 +39,14 @@ class GraphicsView(QtGui.QGraphicsView): autoPixelRange=False. The exact visible range can be set with setRange(). The view can be panned using the middle mouse button and scaled using the right mouse button if - enabled via enableMouse().""" + enabled via enableMouse() (but ordinarily, we use ViewBox for this functionality).""" self.closed = False QtGui.QGraphicsView.__init__(self, parent) - ## in general openGL is poorly supported in Qt. - ## we only enable it where the performance benefit is critical. if useOpenGL is None: - if 'linux' in sys.platform: ## linux has numerous bugs in opengl implementation - useOpenGL = False - elif 'darwin' in sys.platform: ## openGL greatly speeds up display on mac - useOpenGL = True - else: - useOpenGL = False + useOpenGL = pyqtgraph.getConfigOption('useOpenGL') + self.useOpenGL(useOpenGL) self.setCacheMode(self.CacheBackground)