diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index d3aefa83..ed9e3357 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -54,6 +54,7 @@ CONFIG_OPTIONS = { 'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets 'useWeave': True, ## Use weave to speed up some operations, if it is available 'weaveDebug': False, ## Print full error message if weave compile fails + 'enableExperimental': False, ## Enable experimental features (the curious can search for this key in the code) } diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index 35a38ae7..c5a8ec3f 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -1,4 +1,10 @@ from pyqtgraph.Qt import QtGui, QtCore +try: + from pyqtgraph.Qt import QtOpenGL + HAVE_OPENGL = True +except: + HAVE_OPENGL = False + from scipy.fftpack import fft import numpy as np import scipy.stats @@ -370,12 +376,11 @@ class PlotCurveItem(GraphicsObject): prof = debug.Profiler('PlotCurveItem.paint '+str(id(self)), disabled=True) if self.xData is None: return - #if self.opts['spectrumMode']: - #if self.specPath is None: - - #self.specPath = self.generatePath(*self.getData()) - #path = self.specPath - #else: + + if HAVE_OPENGL and pg.getConfigOption('enableExperimental') and isinstance(widget, QtOpenGL.QGLWidget): + self.paintGL(p, opt, widget) + return + x = None y = None if self.path is None: @@ -385,7 +390,6 @@ class PlotCurveItem(GraphicsObject): self.path = self.generatePath(x,y) self.fillPath = None - path = self.path prof.mark('generate path') @@ -440,6 +444,65 @@ class PlotCurveItem(GraphicsObject): #p.setPen(QtGui.QPen(QtGui.QColor(255,0,0))) #p.drawRect(self.boundingRect()) + def paintGL(self, p, opt, widget): + p.beginNativePainting() + import OpenGL.GL as gl + + ## set clipping viewport + view = self.getViewBox() + if view is not None: + rect = view.mapRectToItem(self, view.boundingRect()) + #gl.glViewport(int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height())) + + #gl.glTranslate(-rect.x(), -rect.y(), 0) + + gl.glEnable(gl.GL_STENCIL_TEST) + gl.glColorMask(gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE) # disable drawing to frame buffer + gl.glDepthMask(gl.GL_FALSE) # disable drawing to depth buffer + gl.glStencilFunc(gl.GL_NEVER, 1, 0xFF) + gl.glStencilOp(gl.GL_REPLACE, gl.GL_KEEP, gl.GL_KEEP) + + ## draw stencil pattern + gl.glStencilMask(0xFF); + gl.glClear(gl.GL_STENCIL_BUFFER_BIT) + gl.glBegin(gl.GL_TRIANGLES) + gl.glVertex2f(rect.x(), rect.y()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()) + gl.glVertex2f(rect.x(), rect.y()+rect.height()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()+rect.height()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()) + gl.glVertex2f(rect.x(), rect.y()+rect.height()) + gl.glEnd() + + gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE) + gl.glDepthMask(gl.GL_TRUE) + gl.glStencilMask(0x00) + gl.glStencilFunc(gl.GL_EQUAL, 1, 0xFF) + + try: + x, y = self.getData() + pos = np.empty((len(x), 2)) + pos[:,0] = x + pos[:,1] = y + gl.glEnableClientState(gl.GL_VERTEX_ARRAY) + try: + gl.glVertexPointerf(pos) + pen = fn.mkPen(self.opts['pen']) + color = pen.color() + gl.glColor4f(color.red()/255., color.green()/255., color.blue()/255., color.alpha()/255.) + width = pen.width() + if pen.isCosmetic() and width < 1: + width = 1 + gl.glPointSize(width) + gl.glEnable(gl.GL_LINE_SMOOTH) + gl.glEnable(gl.GL_BLEND) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST); + gl.glDrawArrays(gl.GL_LINE_STRIP, 0, pos.size / pos.shape[-1]) + finally: + gl.glDisableClientState(gl.GL_VERTEX_ARRAY) + finally: + p.endNativePainting() def clear(self): self.xData = None ## raw values diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index a69131ef..84c05478 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -683,6 +683,9 @@ class ScatterPlotItem(GraphicsObject): rec = self.data[i] pos = QtCore.QPointF(pts[0,i], pts[1,i]) x,y,w,h = rec['fragCoords'] + if abs(w) > 10000 or abs(h) > 10000: + print self.data + raise Exception("fragment corrupt") rect = QtCore.QRectF(y, x, h, w) self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect)) diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index cf204007..654a12c9 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -1048,10 +1048,10 @@ class ViewBox(GraphicsWidget): xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0]) yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1]) pxPad = 0 if not hasattr(item, 'pixelPadding') else item.pixelPadding() - if xr is None or xr == (None, None): + if xr is None or xr == (None, None) or np.isnan(xr).any() or np.isinf(xr).any(): useX = False xr = (0,0) - if yr is None or yr == (None, None): + if yr is None or yr == (None, None) or np.isnan(yr).any() or np.isinf(yr).any(): useY = False yr = (0,0)