Updated GLScatterPlotItem for performance.
This commit is contained in:
parent
8551a990c6
commit
bbba3f1f78
@ -5,6 +5,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
import pyqtgraph.opengl as gl
|
||||
import numpy as np
|
||||
|
||||
app = QtGui.QApplication([])
|
||||
w = gl.GLViewWidget()
|
||||
@ -14,18 +15,47 @@ w.show()
|
||||
g = gl.GLGridItem()
|
||||
w.addItem(g)
|
||||
|
||||
pts = [
|
||||
{'pos': (1,0,0), 'size':0.5, 'color':(1.0, 0.0, 0.0, 0.5)},
|
||||
{'pos': (0,1,0), 'size':0.2, 'color':(0.0, 0.0, 1.0, 0.5)},
|
||||
{'pos': (0,0,1), 'size':2./3., 'color':(0.0, 1.0, 0.0, 0.5)},
|
||||
]
|
||||
z = 0.5
|
||||
d = 6.0
|
||||
for i in range(50):
|
||||
pts.append({'pos': (0,0,z), 'size':2./d, 'color':(0.0, 1.0, 0.0, 0.5)})
|
||||
z *= 0.5
|
||||
d *= 2.0
|
||||
sp = gl.GLScatterPlotItem(pts)
|
||||
#pos = np.empty((53, 3))
|
||||
#size = np.empty((53))
|
||||
#color = np.empty((53, 4))
|
||||
#pos[0] = (1,0,0); size[0] = 0.5; color[0] = (1.0, 0.0, 0.0, 0.5)
|
||||
#pos[1] = (0,1,0); size[1] = 0.2; color[1] = (0.0, 0.0, 1.0, 0.5)
|
||||
#pos[2] = (0,0,1); size[2] = 2./3.; color[2] = (0.0, 1.0, 0.0, 0.5)
|
||||
|
||||
#z = 0.5
|
||||
#d = 6.0
|
||||
#for i in range(3,53):
|
||||
#pos[i] = (0,0,z)
|
||||
#size[i] = 2./d
|
||||
#color[i] = (0.0, 1.0, 0.0, 0.5)
|
||||
#z *= 0.5
|
||||
#d *= 2.0
|
||||
|
||||
#sp = gl.GLScatterPlotItem(pos=pos, sizes=size, colors=color, pxMode=False)
|
||||
|
||||
|
||||
pos = (np.random.random(size=(100000,3)) * 10) - 5
|
||||
color = np.ones((pos.shape[0], 4))
|
||||
d = (pos**2).sum(axis=1)**0.5
|
||||
color[:,3] = np.clip(-np.cos(d*2) * 0.2, 0, 1)
|
||||
sp = gl.GLScatterPlotItem(pos=pos, color=color, size=5)
|
||||
phase = 0.
|
||||
|
||||
def update():
|
||||
global phase, color, sp, d
|
||||
s = -np.cos(d*2+phase)
|
||||
color[:,3] = np.clip(s * 0.2, 0, 1)
|
||||
color[:,0] = np.clip(s * 3.0, 0, 1)
|
||||
color[:,1] = np.clip(s * 1.0, 0, 1)
|
||||
color[:,2] = np.clip(s ** 3, 0, 1)
|
||||
|
||||
sp.setData(color=color)
|
||||
phase -= 0.1
|
||||
|
||||
t = QtCore.QTimer()
|
||||
t.timeout.connect(update)
|
||||
t.start(50)
|
||||
|
||||
w.addItem(sp)
|
||||
|
||||
## Start Qt event loop unless running in interactive mode.
|
||||
|
@ -8,31 +8,47 @@ __all__ = ['GLScatterPlotItem']
|
||||
class GLScatterPlotItem(GLGraphicsItem):
|
||||
"""Draws points at a list of 3D positions."""
|
||||
|
||||
def __init__(self, data=None):
|
||||
def __init__(self, **kwds):
|
||||
GLGraphicsItem.__init__(self)
|
||||
self.data = []
|
||||
if data is not None:
|
||||
self.setData(data)
|
||||
self.pos = []
|
||||
self.size = 10
|
||||
self.color = [1.0,1.0,1.0,0.5]
|
||||
self.pxMode = True
|
||||
self.setData(**kwds)
|
||||
|
||||
def setData(self, data):
|
||||
def setData(self, **kwds):
|
||||
"""
|
||||
Data may be either a list of dicts (one dict per point) or a numpy record array.
|
||||
Update the data displayed by this item. All arguments are optional;
|
||||
for example it is allowed to update spot positions while leaving
|
||||
colors unchanged, etc.
|
||||
|
||||
==================== ==================================================
|
||||
Allowed fields are:
|
||||
Arguments:
|
||||
------------------------------------------------------------------------
|
||||
pos (x,y,z) tuple of coordinate values or QVector3D
|
||||
color (r,g,b,a) tuple of floats (0.0-1.0) or QColor
|
||||
size (float) diameter of spot
|
||||
pos (N,3) array of floats specifying point locations.
|
||||
color (N,4) array of floats (0.0-1.0) specifying
|
||||
spot colors OR a tuple of floats specifying
|
||||
a single color for all spots.
|
||||
size (N,) array of floats specifying spot sizes or
|
||||
a single value to apply to all spots.
|
||||
pxMode If True, spot sizes are expressed in pixels.
|
||||
Otherwise, they are expressed in item coordinates.
|
||||
==================== ==================================================
|
||||
"""
|
||||
|
||||
|
||||
self.data = data
|
||||
args = ['pos', 'color', 'size', 'pxMode']
|
||||
for k in kwds.keys():
|
||||
if k not in args:
|
||||
raise Exception('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))
|
||||
self.pos = kwds.get('pos', self.pos)
|
||||
self.color = kwds.get('color', self.color)
|
||||
self.size = kwds.get('size', self.size)
|
||||
self.pxMode = kwds.get('pxMode', self.pxMode)
|
||||
self.update()
|
||||
|
||||
|
||||
def initializeGL(self):
|
||||
|
||||
## Generate texture for rendering points
|
||||
w = 64
|
||||
def fn(x,y):
|
||||
r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5
|
||||
@ -73,28 +89,49 @@ class GLScatterPlotItem(GLGraphicsItem):
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
||||
|
||||
for pt in self.data:
|
||||
pos = pt['pos']
|
||||
try:
|
||||
color = pt['color']
|
||||
except KeyError:
|
||||
color = (1,1,1,1)
|
||||
try:
|
||||
size = pt['size']
|
||||
except KeyError:
|
||||
size = 10
|
||||
|
||||
if isinstance(color, QtGui.QColor):
|
||||
color = fn.glColor(color)
|
||||
|
||||
pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))
|
||||
if self.pxMode:
|
||||
glVertexPointerf(self.pos)
|
||||
if isinstance(self.color, np.ndarray):
|
||||
glColorPointerf(self.color)
|
||||
else:
|
||||
if isinstance(self.color, QtGui.QColor):
|
||||
glColor4f(*fn.glColor(self.color))
|
||||
else:
|
||||
glColor4f(*self.color)
|
||||
|
||||
glPointSize(size / pxSize)
|
||||
glBegin( GL_POINTS )
|
||||
glColor4f(*color) # x is blue
|
||||
#glNormal3f(size, 0, 0)
|
||||
glVertex3f(*pos)
|
||||
glEnd()
|
||||
if isinstance(self.size, np.ndarray):
|
||||
raise Exception('Array size not yet supported in pxMode (hopefully soon)')
|
||||
|
||||
glPointSize(self.size)
|
||||
glEnableClientState(GL_VERTEX_ARRAY)
|
||||
glEnableClientState(GL_COLOR_ARRAY)
|
||||
glDrawArrays(GL_POINTS, 0, len(self.pos))
|
||||
else:
|
||||
|
||||
|
||||
for i in range(len(self.pos)):
|
||||
pos = self.pos[i]
|
||||
|
||||
if isinstance(self.color, np.ndarray):
|
||||
color = self.color[i]
|
||||
else:
|
||||
color = self.color
|
||||
if isinstance(self.color, QtGui.QColor):
|
||||
color = fn.glColor(self.color)
|
||||
|
||||
if isinstance(self.size, np.ndarray):
|
||||
size = self.size[i]
|
||||
else:
|
||||
size = self.size
|
||||
|
||||
pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))
|
||||
|
||||
glPointSize(size / pxSize)
|
||||
glBegin( GL_POINTS )
|
||||
glColor4f(*color) # x is blue
|
||||
#glNormal3f(size, 0, 0)
|
||||
glVertex3f(*pos)
|
||||
glEnd()
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user