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
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
import pyqtgraph.opengl as gl
|
import pyqtgraph.opengl as gl
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
app = QtGui.QApplication([])
|
app = QtGui.QApplication([])
|
||||||
w = gl.GLViewWidget()
|
w = gl.GLViewWidget()
|
||||||
@ -14,18 +15,47 @@ w.show()
|
|||||||
g = gl.GLGridItem()
|
g = gl.GLGridItem()
|
||||||
w.addItem(g)
|
w.addItem(g)
|
||||||
|
|
||||||
pts = [
|
#pos = np.empty((53, 3))
|
||||||
{'pos': (1,0,0), 'size':0.5, 'color':(1.0, 0.0, 0.0, 0.5)},
|
#size = np.empty((53))
|
||||||
{'pos': (0,1,0), 'size':0.2, 'color':(0.0, 0.0, 1.0, 0.5)},
|
#color = np.empty((53, 4))
|
||||||
{'pos': (0,0,1), 'size':2./3., 'color':(0.0, 1.0, 0.0, 0.5)},
|
#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)
|
||||||
z = 0.5
|
#pos[2] = (0,0,1); size[2] = 2./3.; color[2] = (0.0, 1.0, 0.0, 0.5)
|
||||||
d = 6.0
|
|
||||||
for i in range(50):
|
#z = 0.5
|
||||||
pts.append({'pos': (0,0,z), 'size':2./d, 'color':(0.0, 1.0, 0.0, 0.5)})
|
#d = 6.0
|
||||||
z *= 0.5
|
#for i in range(3,53):
|
||||||
d *= 2.0
|
#pos[i] = (0,0,z)
|
||||||
sp = gl.GLScatterPlotItem(pts)
|
#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)
|
w.addItem(sp)
|
||||||
|
|
||||||
## Start Qt event loop unless running in interactive mode.
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
@ -8,31 +8,47 @@ __all__ = ['GLScatterPlotItem']
|
|||||||
class GLScatterPlotItem(GLGraphicsItem):
|
class GLScatterPlotItem(GLGraphicsItem):
|
||||||
"""Draws points at a list of 3D positions."""
|
"""Draws points at a list of 3D positions."""
|
||||||
|
|
||||||
def __init__(self, data=None):
|
def __init__(self, **kwds):
|
||||||
GLGraphicsItem.__init__(self)
|
GLGraphicsItem.__init__(self)
|
||||||
self.data = []
|
self.pos = []
|
||||||
if data is not None:
|
self.size = 10
|
||||||
self.setData(data)
|
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
|
pos (N,3) array of floats specifying point locations.
|
||||||
color (r,g,b,a) tuple of floats (0.0-1.0) or QColor
|
color (N,4) array of floats (0.0-1.0) specifying
|
||||||
size (float) diameter of spot
|
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.
|
||||||
==================== ==================================================
|
==================== ==================================================
|
||||||
"""
|
"""
|
||||||
|
args = ['pos', 'color', 'size', 'pxMode']
|
||||||
|
for k in kwds.keys():
|
||||||
self.data = data
|
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()
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
def initializeGL(self):
|
def initializeGL(self):
|
||||||
|
|
||||||
|
## Generate texture for rendering points
|
||||||
w = 64
|
w = 64
|
||||||
def fn(x,y):
|
def fn(x,y):
|
||||||
r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5
|
r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5
|
||||||
@ -73,19 +89,40 @@ class GLScatterPlotItem(GLGraphicsItem):
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
||||||
|
|
||||||
for pt in self.data:
|
if self.pxMode:
|
||||||
pos = pt['pos']
|
glVertexPointerf(self.pos)
|
||||||
try:
|
if isinstance(self.color, np.ndarray):
|
||||||
color = pt['color']
|
glColorPointerf(self.color)
|
||||||
except KeyError:
|
else:
|
||||||
color = (1,1,1,1)
|
if isinstance(self.color, QtGui.QColor):
|
||||||
try:
|
glColor4f(*fn.glColor(self.color))
|
||||||
size = pt['size']
|
else:
|
||||||
except KeyError:
|
glColor4f(*self.color)
|
||||||
size = 10
|
|
||||||
|
|
||||||
if isinstance(color, QtGui.QColor):
|
if isinstance(self.size, np.ndarray):
|
||||||
color = fn.glColor(color)
|
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))
|
pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user