Especifique color absoluto para puntos 3D en MayaVi

Estoy usando la biblioteca Python de MayaVi para trazar puntos 3d, usando la clase points3d . La documentación especifica que el color de cada punto se especifica a través de un cuarto argumento, s :

Además, puede pasar una cuarta matriz s de la misma forma que x, y, yz, dando un valor escalar asociado para cada punto, o una función f (x, y, z) que devuelve el valor escalar. Este valor escalar se puede utilizar para modular el color y el tamaño de los puntos.

Esto especifica un valor escalar para cada punto, que asigna el punto a un mapa de colores, como copper , jet o hsv . Por ejemplo, de su documentación:

 import numpy from mayavi.mlab import * def test_points3d(): t = numpy.linspace(0, 4*numpy.pi, 20) cos = numpy.cos sin = numpy.sin x = sin(2*t) y = cos(t) z = cos(2*t) s = 2+sin(t) return points3d(x, y, z, s, colormap="copper", scale_factor=.25) 

Da:

introduzca la descripción de la imagen aquí

En su lugar, me gustaría especificar el valor real para cada punto como una tupla (r, g, b). ¿Es esto posible en MayaVi? He intentado reemplazar las s con una matriz de tuplas, pero se produce un error.

Esto ahora se puede hacer simplemente con el argumento del color

 from mayavi import mlab import numpy as np c = np.random.rand(200, 3) r = np.random.rand(200) / 10. mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=(0.2, 0.4, 0.5)) mlab.show() 

introduzca la descripción de la imagen aquí

Después de luchar con esto durante la mayor parte del día, encontré una forma relativamente simple de hacer exactamente lo que la pregunta plantea: especifique una tupla RGB para cada punto. El truco consiste simplemente en definir un mapa de color con exactamente el mismo número de entradas, ya que hay puntos para trazar, y luego establecer el argumento para que sea una lista de índices:

 # Imports import numpy as np from mayavi.mlab import quiver3d, draw # Primitives N = 200 # Number of points ones = np.ones(N) scalars = np.arange(N) # Key point: set an integer for each point # Define color table (including alpha), which must be uint8 and [0,255] colors = (np.random.random((N, 4))*255).astype(np.uint8) colors[:,-1] = 255 # No transparency # Define coordinates and points x, y, z = colors[:,0], colors[:,1], colors[:,2] # Assign x, y, z values to match color pts = quiver3d(x, y, z, ones, ones, ones, scalars=scalars, mode='sphere') # Create points pts.glyph.color_mode = 'color_by_scalar' # Color by scalar # Set look-up table and redraw pts.module_manager.scalar_lut_manager.lut.table = colors draw() 

Puede usar una tabla de consulta de rgb y asignar sus valores de rgb a ella usando la lógica que desee. Aquí hay un ejemplo simple:

 import numpy, random from mayavi.mlab import * def cMap(x,y,z): #whatever logic you want for colors return [random.random() for i in x] def test_points3d(): t = numpy.linspace(0, 4*numpy.pi, 20) cos = numpy.cos sin = numpy.sin x = sin(2*t) y = cos(t) z = cos(2*t) s = cMap(x,y,z) return points3d(x, y, z, s, colormap="spectral", scale_factor=0.25) test_points3d() 

No tengo idea de qué esquema de color desea, pero puede evaluar las posiciones de x, y, z y devolver el escalar que corresponda al valor rgb que está buscando.

He encontrado una mejor manera de configurar los colores directamente.

Puede crear su propia LUT directa con bastante facilidad. Digamos que queremos 256 ** 3 granularidad:

 #create direct grid as 256**3 x 4 array def create_8bit_rgb_lut(): xl = numpy.mgrid[0:256, 0:256, 0:256] lut = numpy.vstack((xl[0].reshape(1, 256**3), xl[1].reshape(1, 256**3), xl[2].reshape(1, 256**3), 255 * numpy.ones((1, 256**3)))).T return lut.astype('int32') # indexing function to above grid def rgb_2_scalar_idx(r, g, b): return 256**2 *r + 256 * g + b #N x 3 colors colors = numpy.array([_.color for _ in points]) #N scalars scalars = numpy.zeros((colors.shape[0],)) for (kp_idx, kp_c) in enumerate(colors): scalars[kp_idx] = rgb_2_scalar_idx(kp_c[0], kp_c[1], kp_c[2]) rgb_lut = create_8bit_rgb_lut() points_mlab = mayavi.mlab.points3d(x, y, z keypoint_scalars, mode = 'point') #magic to modify lookup table points_mlab.module_manager.scalar_lut_manager.lut._vtk_obj.SetTableRange(0, rgb_lut.shape[0]) points_mlab.module_manager.scalar_lut_manager.lut.number_of_colors = rgb_lut.shape[0] points_mlab.module_manager.scalar_lut_manager.lut.table = rgb_lut