Search code examples
pythonpyqtgraph

Display 3D Matrix with colors Pyqtgraph


I want to display a 3D matrix in Pyqtgraph using GLVolumeItem (with x, y and z axis) with the specific colors corresponding to the input data.

How can I proceed with my code ?

import numpy as np

import pyqtgraph as pg
import pyqtgraph.opengl as gl
from pyqtgraph import functions as fn

app = pg.mkQApp("GLVolumeItem Example")
w = gl.GLViewWidget()
w.show()
w.setWindowTitle('pyqtgraph example: GLVolumeItem')
w.setCameraPosition(distance=200)

g = gl.GLGridItem()
g.scale(10, 10, 1)
w.addItem(g)

x = np.linspace(0,10,11)
y = np.linspace(0,10,11)
z = np.linspace(0,10,11)

data = np.zeros((10,10,10))
data[1,:,:] = 10
data[3,:,:] = 10

d2 = np.empty(data.shape + (4,), dtype=np.ubyte)

v = gl.GLVolumeItem(d2)
w.addItem(v)

ax = gl.GLAxisItem()
w.addItem(ax)

if __name__ == '__main__':
    pg.exec()

The goal is to get a 3D representation with different colors corresponding to the levels of the data.


Solution

  • I think something like this is what you are looking for:

    import numpy as np
    
    import pyqtgraph as pg
    import pyqtgraph.opengl as gl
    from pyqtgraph import functions as fn
    from pyqtgraph.opengl import GLScatterPlotItem
    
    app = pg.mkQApp("GLVolumeItem Example")
    w = gl.GLViewWidget()
    w.show()
    w.setWindowTitle('pyqtgraph example: GLVolumeItem')
    w.setCameraPosition(distance=40)
    
    g = gl.GLGridItem()
    # g.scale(10, 10, 1)
    w.addItem(g)
    
    N_x = 10
    N_y = 10
    N_z = 10
    
    x = np.arange(N_x)
    y = np.arange(N_y)
    z = np.arange(N_z)
    
    data = np.zeros((N_x, N_y, N_z))
    data[1, :, :] = 10
    data[3, :, :] = 10
    
    d2 = np.zeros(data.shape + (4,), dtype=np.ubyte)
    print(data.shape)
    print(d2.shape)
    
    d2[:, :, :, 0] = 255*data/np.max(data)      # only works if minimum is 0
    d2[:, :, :, 1] = 0
    d2[:, :, :, 2] = 0
    d2[:, :, :, 3] = 50
    
    v = gl.GLVolumeItem(d2)
    # v.translate(10, 10, 10)
    w.addItem(v)
    
    ax = gl.GLAxisItem()
    w.addItem(ax)
    
    curve = GLScatterPlotItem()
    w.addItem(curve)
    
    # pos = np.array((10, 10, 10)).T
    # curve.setData(pos=pos, pxMode=False, color=(255, 255, 255, 100), size=0.2)        # I use these for checking positions
    
    if __name__ == '__main__':
        pg.exec()
    

    The data has shape (N_x, N_y, N_z), but the data for a volume item should be shape (N_x, N_y, N_z, 4), where the 4 stands for the colour. The line d2[:, :, :, 3] = 50 sets the opacity to 50 at every place. The line d2[:, :, :, 0] = 255*data/np.max(data) sets the red part of the colour depending on the data of your array.