Specify absolute colour for 3D points in MayaVi

2019-01-23 06:21发布

I am using the MayaVi Python library to plot 3d points, using the points3d class. The documentation specifies that the colour of each point is specified through a fourth argument, s:

In addition, you can pass a fourth array s of the same shape as x, y, and z giving an associated scalar value for each point, or a function f(x, y, z) returning the scalar value. This scalar value can be used to modulate the color and the size of the points.

This specifies a scalar value for each point, which maps the point to a colourmap, such as copper, jet or hsv. E.g. from their documentation:

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)

Gives:

enter image description here

Instead, I would like to specify the actual value for each point as an (r, g, b) tuple. Is this possible in MayaVi? I have tried replacing the s with an array of tuples, but an error is thrown.

4条回答
再贱就再见
2楼-- · 2019-01-23 06:48

You can use a rgb look up table and map your rgb values to it using whatever logic you want. Here's a simple example:

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()

I have no idea what color scheme you want, but you can evaluate the positions of x,y,z and return whatever scalar corresponds to the rgb value you are seeking.

查看更多
Ridiculous、
3楼-- · 2019-01-23 06:51

I've found a better way to set the colors directly.

You can create your own direct LUT pretty easily. Let's say we want 256**3 granularity:

#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
查看更多
The star\"
4楼-- · 2019-01-23 07:03

This can now simply be done with the color argument

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()

enter image description here

查看更多
再贱就再见
5楼-- · 2019-01-23 07:06

After struggling with this for most of today, I found a relatively simple way to do exactly what the question asks -- specify an RGB tuple for each point. The trick is just to define a color map with exactly the same number of entries as there are points to plot, and then set the argument to be a list of indices:

# 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()
查看更多
登录 后发表回答