Various improvements

Make an example displaying more clearly the Item capability.
Correct few bugs in the Item class.
Improve overall comments.
This commit is contained in:
Etienne Dumur 2020-06-28 14:49:20 +02:00
parent 3cbe65d46d
commit d32d61a1e2
2 changed files with 86 additions and 50 deletions

View File

@ -21,40 +21,45 @@ view = win.addViewBox()
## Create data ## Create data
x = np.array([[1,1,1,1],
[2,2,2,2], # x and y being the coordinates of the polygons, they share the same shape
[3,3,3,3], # However the shape can be different in both dimension
[4,4,4,4], xn = 50 # nb points along x
[5,5,5,5]]) yn = 40 # nb points along y
y = np.array([[4,8,12,16], x = np.repeat(np.arange(1, xn+1), yn).reshape(xn, yn)
[2,4,6,8], y = np.tile(np.arange(1, yn+1), xn).reshape(xn, yn)
[3,6,9,12],
[5,10,15,20], # z being the color of the polygons its shape must be decreased by one in each dimension
[6,12,18,24]]) z = np.exp(-(x*xn)**2/1000)[:-1,:-1]
z = np.array([[1,2,3],
[5,6,7],
[9,10,11],
[13,14,15]])
## Create image item ## Create image item
pcmi = pg.PColorMeshItem(x, y, z) pcmi = pg.PColorMeshItem()
view.addItem(pcmi) view.addItem(pcmi)
## Set the animation
fps = 25 # Frame per second of the animation
fps = 1 # Wave parameters
i = 0 wave_amplitude = 3
wave_speed = 0.3
wave_length = 10
color_speed = 0.3
i=0
def updateData(): def updateData():
global pcmi, x, y, z, i global i
## Display the data ## Display the new data set
pcmi.setData(x-i, y, z) new_x = x
new_y = y+wave_amplitude*np.cos(x/wave_length+i)
QtCore.QTimer.singleShot(fps*1000, updateData) new_z = np.exp(-(x-np.cos(i*color_speed)*xn)**2/1000)[:-1,:-1]
i += 1 pcmi.setData(new_x,
print(i) new_y,
new_z)
i += wave_speed
QtCore.QTimer.singleShot(1000/fps, updateData)
updateData() updateData()

View File

@ -23,66 +23,97 @@ class PColorMeshItem(GraphicsObject):
""" """
**Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>` **Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>`
TODO Create a pseudocolor plot with convex polygons.
""" """
sigImageChanged = QtCore.Signal() sigImageChanged = QtCore.Signal()
sigRemoveRequested = QtCore.Signal(object) # self; emitted when 'remove' is selected from context menu sigRemoveRequested = QtCore.Signal(object) # self; emitted when 'remove' is selected from context menu
def __init__(self, x=None, y=None, z=None, cmap='viridis'): def __init__(self, x=None, y=None, z=None,
cmap='viridis'):
""" """
See :func:`setImage <pyqtgraph.ImageItem.setImage>` for all allowed initialization arguments.
Parameters
----------
x, y : np.ndarray
2D array containing the coordinates of the polygons
z : np.ndarray
2D array containing the value which will be maped into the polygons
colors.
cmap : str, default 'viridis
Colormap used to map the z value to colors.
""" """
GraphicsObject.__init__(self) GraphicsObject.__init__(self)
self.x = x self.x = x
self.y = y self.y = y
self.z = z self.z = z
self.qpicture = None ## rendered image for display self.qpicture = None ## rendered image for display
self.axisOrder = getConfigOption('imageAxisOrder') self.axisOrder = getConfigOption('imageAxisOrder')
if cmap in list(Gradients.keys()): if cmap in Gradients.keys():
self.cmap = cmap self.cmap = cmap
else: else:
raise NameError('Undefined colormap') raise NameError('Undefined colormap')
# If some data have been sent we directly display it
if x is not None and y is not None and z is not None: if x is not None and y is not None and z is not None:
self.setData(x, y, z) self.setData(x, y, z)
def setData(self, x, y, z): def setData(self, x, y, z):
## pre-computing a QPicture object allows paint() to run much more quickly,
## rather than re-drawing the shapes every time.
# We test of the view has changed
if np.any(self.x != x) or np.any(self.y != y) or np.any(self.z != z):
self.informViewBoundsChanged()
# Replace data
self.x = x
self.y = y
self.z = z
profile = debug.Profiler() profile = debug.Profiler()
self.qpicture = QtGui.QPicture() self.qpicture = QtGui.QPicture()
p = QtGui.QPainter(self.qpicture) p = QtGui.QPainter(self.qpicture)
p.setPen(fn.mkPen('w'))
# We set the pen of all polygons once
p.setPen(QtGui.QColor(0, 0, 0, 0))
# Prepare colormap ## Prepare colormap
pos = [i[0] for i in Gradients[self.cmap]['ticks']] # First we get the LookupTable
pos = [i[0] for i in Gradients[self.cmap]['ticks']]
color = [i[1] for i in Gradients[self.cmap]['ticks']] color = [i[1] for i in Gradients[self.cmap]['ticks']]
cmap = ColorMap(pos, color) cmap = ColorMap(pos, color)
lut = cmap.getLookupTable(0.0, 1.0, 256) lut = cmap.getLookupTable(0.0, 1.0, 256)
norm = ((z - z.min())/z.max()*len(lut)).astype(int) # Second we associate each z value, that we normalize, to the lut
norm = z - z.min()
norm = norm/norm.max()
norm = (norm*(len(lut)-1)).astype(int)
xfn = z.shape[0] # Go through all the data and draw the polygons accordingly
yfn = z.shape[1] for xi in range(z.shape[0]):
for xi in range(xfn): for yi in range(z.shape[1]):
for yi in range(yfn):
# Set the color of the polygon first
# print(xi, yi, norm[xi][yi])
c = lut[norm[xi][yi]]
p.setBrush(QtGui.QColor(c[0], c[1], c[2]))
# DrawConvexPlygon is faster
p.drawConvexPolygon(QtCore.QPointF(x[xi][yi], y[xi][yi]), p.drawConvexPolygon(QtCore.QPointF(x[xi][yi], y[xi][yi]),
QtCore.QPointF(x[xi+1][yi], y[xi+1][yi]), QtCore.QPointF(x[xi+1][yi], y[xi+1][yi]),
QtCore.QPointF(x[xi+1][yi+1], y[xi+1][yi+1]), QtCore.QPointF(x[xi+1][yi+1], y[xi+1][yi+1]),
QtCore.QPointF(x[xi][yi+1], y[xi][yi+1])) QtCore.QPointF(x[xi][yi+1], y[xi][yi+1]))
c = lut[norm[xi][yi]]
p.setBrush(QtGui.QColor(c[0], c[1], c[2]))
p.end()
p.end()
self.update() self.update()
@ -106,14 +137,14 @@ class PColorMeshItem(GraphicsObject):
def width(self): def width(self):
if self.x is None: if self.x is None:
return None return None
return len(self.x) return np.max(self.x)
def height(self): def height(self):
if self.y is None: if self.y is None:
return None return None
return len(self.y) return np.max(self.y)