使用表面渐变为Matplotlib的plot_surface命令上色

18

我想将 MATLAB 中的surf命令转换为 matplotlib 中的plot_surface命令。

我面临的挑战是在使用 plot_surface 命令中的 cmap 函数来用渐变色给表面着色时。

这里是 MATLAB 脚本:

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

此命令的图形可以在此处找到。 (http://www.mathworks.com/help/techdoc/visualize/f0-18164.html#f0-46458)

以下是Python脚本 使用Python和Matplotlib创建类似功能时,我无法使用渐变来着色表面。

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

我收到以下错误信息:

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'
任何输入都将有所帮助。
Praboo
1个回答

50
首先,看起来您想要从梯度幅度映射颜色。 您正在尝试使用梯度向量,这就是为什么会出现'list'错误。
其次,您可以提供一个cmap,但它只定义了您希望将Z值映射到的颜色。 如果您想要新的面颜色,请使用facecolors参数
第三,您需要将值归一化为0..1,然后通过colormap进行映射。 (我认为还有另一种方法,但将幅度除以最大值非常简单)
以下是代码:
# 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()

结果如下:

enter image description here


你如何在这个图中添加colorbar以反映colormap的变化? - praboo
2
@praboo 你需要实例化一个ScalarMappable。这是一个有趣且非常重要的话题,如果能将其作为一个单独的问题介绍给社区,那么大家都会受益。 - Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接