2013-08-30 10 views
11

Ich verwende die MayaVi Python-Bibliothek, um 3D-Punkte zu plotten, unter Verwendung der points3d Klasse. The documentation gibt an, dass die Farbe jeden Punkt durch ein viertes Argument angegeben, s:Angeben der absoluten Farbe für 3D-Punkte in MayaVi

Darüber hinaus kann man ein viertes Array s von der gleichen Form wie x, y, und z passiert einen zugehörigen Skalarwert geben für jeden Punkt oder eine Funktion f (x, y, z), die den Skalarwert zurückgibt. Dieser skalare Wert kann verwendet werden, um die Farbe und die Größe der Punkte zu modulieren.

dies für jeden Punkt einen skalaren Wert gibt, die den Punkt an einen colourmap wie copper, jet oder hsv abbildet. Z.B. aus ihrer Dokumentation:

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) 

Gewährt:

enter image description here

Stattdessen würde ich den Ist-Wert für jeden Punkt als (r, g, b) tuple angeben mag. Ist das in MayaVi möglich? Ich habe versucht, die s mit einem Array von Tupeln zu ersetzen, aber ein Fehler wird ausgelöst.

Antwort

1

Dies kann nun einfach mit der getan werden 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

3

Sie können eine rgb-Nachschlagetabelle verwenden und Ihre rgb-Werte mit der von Ihnen gewünschten Logik zuordnen. Hier ist ein einfaches Beispiel:

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

Ich habe keine Ahnung, was Farbschema Sie wollen, aber Sie können die Positionen von x, y, z zu bewerten und zurück, was Skalar zu den RGB-Wert entspricht, die Sie suchen.

+0

gibt es eine Möglichkeit, dies zu tun, einen beliebigen 0-255 RGB-Wert zu erzeugen, ohne eine eindeutige colormap mit 256x256x256 Werten zu spezifizieren? Anders ausgedrückt, gibt es in Ihrer Lösung eine Möglichkeit zur Charakterisierung der inversen Spectral() - Funktion, wobei Spectral() eine Funktion mit der Domäne [0,1] und dem Bereich 0-255,0-255,0- ist. 255? Dieses Verhalten hat mich immer verärgert, und ich habe gesehen, dass einige Anwendungen es umgehen (zum Beispiel das vtk-Programm trackvis, dessen Besitzer abgelehnt hat, die Quelle zu mir zu veröffentlichen, damit ich sehen kann, wie er es macht). – aestrivex

+0

Sie können mayavi.core.lut_manager, insbesondere pylab_luts in mayavi.core.lut_manager erkunden, um zu sehen, wie diese gebaut werden (und vermutlich bauen Sie Ihre eigenen und zuweisen, was Sie wollen, Verhalten) – Chrismit

+0

Ich habe mit diesen gespielt. Das Arbeiten mit benutzerdefinierten Luts zum Angeben eines gewünschten Farbschemas ist weitaus weniger allgemein als das Angeben eines eindeutigen RGB-Werts für jeden Vertex, für den ein Skalar angegeben ist. Rechnerisch ist das nicht wahr, weil es möglich ist, eine LUT mit 256x256x256 Werten anzugeben, die das RGB-Farbspektrum eindeutig definiert. Aber es wäre ein außerordentlicher Schmerz, dies tatsächlich zu tun. Ich denke, die richtige Antwort auf diese Frage ist "Entschuldigung, es gibt keinen richtigen Weg, dies zu tun." – aestrivex

3

Ich habe einen besseren Weg gefunden, die Farben direkt einzustellen.

Sie können Ihre eigene direkte LUT ganz einfach erstellen. Sagen wir, wir wollen 256 ** 3 Granularität:

#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 
7

Nachdem für die meisten heute kämpfen mit diesem, habe ich eine relativ einfache Art und Weise gefunden zu tun genau das, was die Frage stellt - Geben Sie für jeden Punkt ein RGB-Tupel. Der Trick ist, nur mit genau der gleichen Anzahl von Einträgen eine Farbkarte zu definieren, wie es Punkte zu zeichnen, und dann das Argument gesetzt eine Liste von Indizes zu sein:

# 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() 
+0

dies funktioniert gut und ist die einfachste Antwort. – chris

+0

Für alle, die dies auf anderen Grundstücken als Köcher tun möchten; es ist die vorletzte Zeile, die wichtig ist; Das heißt, Sie können 'surf.module_manager.scalar_lut_manager.lut.table = colors' auch tun. – RolKau