2011-06-30 18 views
15

Chciałbym przekonwertować polecenie surfowania z MATLAB na polecenie plot_surface w matplotlib.Polecenie color matplotlib plot_surface z gradientem powierzchni

Wyzwaniem, przed którym stoję, jest użycie funkcji cmap w komendzie plot_surface w celu pokolorowania powierzchni gradientem.

Oto Matlab skrypt

% Matlab Commands 
x = -5:.25:5; y = x 
[x,y] = meshgrid(x); 
R = sqrt(x.^2 + y.^2); 
Z = sin(R) 
surf(x,y,Z,gradient(Z)) 

Postać z takiego polecenia można znaleźć tutaj. (http://www.mathworks.com/help/techdoc/visualize/f0-18164.html#f0-46458)

Oto pyton skrypcie Przy użyciu Python i matplotlib stworzyć podobną funkcję jestem niezdolny do barwienia powierzchni z gradientem.

# Python-matplotlib Commands 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib import cm 
import matplotlib.pyplot as plt 
import numpy as np 

fig = plt.figure() 
ax = fig.gca(projection='3d') 
X = np.arange(-5, 5, 0.25) 
Y = np.arange(-5, 5, 0.25) 
X, Y = np.meshgrid(X, Y) 
R = np.sqrt(X**2 + Y**2) 
Z = np.sin(R) 
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=gradient(Z), linewidth=0, antialiased=False) 
plt.show() 

pojawia się następujący komunikat o błędzie:

Traceback (most recent call last): 
    File "<ipython console>", line 1, in <module> 
    File "C:\Python26\lib\site-packages\spyderlib\widgets\externalshell\startup.py", line 122, in runfile 
    execfile(filename, glbs) 
    File "C:\Documents and Settings\mramacha\My Documents\Python\Candela\tmp.py", line 13, in <module> 
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=gradient(Z), linewidth=0, antialiased=False) 
    File "C:\Python26\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 729, in plot_surface 
    polyc = art3d.Poly3DCollection(polys, *args, **kwargs) 
    File "C:\Python26\lib\site-packages\mpl_toolkits\mplot3d\art3d.py", line 344, in __init__ 
    PolyCollection.__init__(self, verts, *args, **kwargs) 
    File "C:\Python26\lib\site-packages\matplotlib\collections.py", line 570, in __init__ 
    Collection.__init__(self,**kwargs) 
    File "C:\Python26\lib\site-packages\matplotlib\collections.py", line 86, in __init__ 
    cm.ScalarMappable.__init__(self, norm, cmap) 
    File "C:\Python26\lib\site-packages\matplotlib\cm.py", line 155, in __init__ 
    self.cmap = get_cmap(cmap) 
    File "C:\Python26\lib\site-packages\matplotlib\cm.py", line 126, in get_cmap 
    if name in cmap_d: 
TypeError: unhashable type: 'list' 

Jakiekolwiek wejścia byłoby pomocne.

Praboo

Odpowiedz

38

Po pierwsze, wygląda na to, chcesz kolory odwzorowane od wielkości gradientu. Próbujesz użyć wektorów gradientowych, dlatego pojawia się błąd "listy".

Po drugie, możesz podać cmap, ale definiuje tylko, jak chcesz, aby wartości Z były odwzorowane na kolor. Jeśli chcesz uzyskać nowe kolory twarzy, użyj facecolors argument.

Po trzecie, należy znormalizować wartości do 0..1, a następnie mapować je poprzez mapę kolorów. (Myślę, że istnieje inny sposób, ale podzielenie wielkości przez max jest dość prosty)

Oto kod:

# Python-matplotlib Commands 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib import cm 
import matplotlib.pyplot as plt 
import numpy as np 

fig = plt.figure() 
ax = fig.gca(projection='3d') 
X = np.arange(-5, 5, .25) 
Y = np.arange(-5, 5, .25) 
X, Y = np.meshgrid(X, Y) 
R = np.sqrt(X**2 + Y**2) 
Z = np.sin(R) 
Gx, Gy = np.gradient(Z) # gradients with respect to x and y 
G = (Gx**2+Gy**2)**.5 # gradient magnitude 
N = G/G.max() # normalize 0..1 
surf = ax.plot_surface(
    X, Y, Z, rstride=1, cstride=1, 
    facecolors=cm.jet(N), 
    linewidth=0, antialiased=False, shade=False) 
plt.show() 

A wynik:

enter image description here

+0

Fantastic. Dziękuję Paul. – praboo

+0

Jak dodać pasek kolorów do tego wykresu, aby odzwierciedlić zmianę w mapie kolorów. – praboo

+2

@praboo Musisz utworzyć instancję ScalarMappable. Jest to ciekawy i nietrywialny temat, a społeczność będzie dobrze obsługiwana, jeśli zostanie przedstawiona jako osobne pytanie. – Paul

Powiązane problemy