2012-01-12 111 views
10

我试图在python中绘制曲面。我有一个N乘N值的表格。我创建了N个元素中的两个向量X和Y。当我尝试绘图本,我得到一个错误:python的3D绘图

ValueError: total size of new array must be unchanged 

我检查了例子,我看到那里,对于z的N个元素存在于X N个元素和Y

这没有按”对我来说没有任何意义。我怎么需要N个元素而不是N个N?

这里是一个示例代码:

进口随机 进口数学

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 
import numpy as np 

bignum = 100 

mat = [] 
X = [] 
Y = [] 

for x in range(0,bignum): 
    mat.append([]) 
    X.append(x); 
    for y in range (0,bignum): 
     mat[x].append(random.random()) 
     Y.append(y) 

fig = plt.figure(figsize=plt.figaspect(2.)) 
ax = fig.add_subplot(1,1,1, projection='3d') 
surf = ax.plot_surface(X,Y,mat) 
+0

你能后的代码抛出错误的线路? – NoBugs 2012-01-12 20:31:27

回答

20

首先,永远不要做这样的事情:

mat = [] 
X = [] 
Y = [] 

for x in range(0,bignum): 
    mat.append([]) 
    X.append(x); 
    for y in range (0,bignum): 
     mat[x].append(random.random()) 
     Y.append(y) 

这相当于:

mat = np.random.random((bignum, bignum)) 
X, Y = np.mgrid[:bignum, :bignum] 

...但它的速度要快几个数量级,并且使用一部分使用列表然后转换为数组的内存。

但是,您的示例完美地工作。

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 
import numpy as np 

bignum = 100 
mat = np.random.random((bignum, bignum)) 
X, Y = np.mgrid[:bignum, :bignum] 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1, projection='3d') 
surf = ax.plot_surface(X,Y,mat) 
plt.show() 

enter image description here

如果你读了plot_surface的文档,它清楚地说,X,Y和Z预计将二维数组。

这样就可以通过固有地定义点之间的连接来绘制更复杂的曲面(例如球体)。 (例如,参照这个例子从matplotlib库:http://matplotlib.sourceforge.net/examples/mplot3d/surface3d_demo2.html

如果你有1D X和Y阵列,并且希望从2D网格简单的表面,然后用numpy.meshgridnumpy.mgrid产生适当的X和Y二维数组。

编辑: 只是为了解释什么mgridmeshgrid呢,让我们来看看它们的输出:

print np.mgrid[:5, :5] 

产量:

array([[[0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1], 
     [2, 2, 2, 2, 2], 
     [3, 3, 3, 3, 3], 
     [4, 4, 4, 4, 4]], 

     [[0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4]]]) 

因此,它返回一个单一的,3D阵列的形状为2x5x5,但更容易将其视为两个2D阵列。其中一个代表5×5网格上任意点的坐标,其他坐标代表j坐标。

由于蟒蛇的方式拆包作品中,我们可以这样写:

xx, yy = np.mgrid[:5, :5] 

Python并不关心到底是什么mgrid回报,它只是尝试将其解压缩到两个项目。由于numpy数组迭代其第一轴的切片,因此如果我们用(2x5x5)的形状对数组进行解压缩,则会得到2,5x5数组。同样,我们可以做这样的事情:

xx, yy, zz = np.mgrid[:5, :5, :5] 

...并获得3,三维5×5×indicies的阵列。此外,如果我们使用不同的范围切片(例如xx, yy = np.mgrid[10:15, 3:8],它将平铺显示从10到14(含)和3到7(含)的指​​示

还有一点mgrid(它可能需要复杂的步骤参数模仿linspace,如xx, yy = np.mgrid[0:1:10j, 0:5:5j]将返回2个10x5阵列,分别为0-1和0-5之间越来越多),但是让我们跳过来meshgrid一秒钟。

meshgrid需要两个阵列和瓷砖它们以类似的方式例如:

x = np.arange(5) 
y = np.arange(5) 
xx, yy = np.meshgrid(x, y) 
print xx, yy 

产量:

(array([[0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4]]), 

array([[0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1], 
     [2, 2, 2, 2, 2], 
     [3, 3, 3, 3, 3], 
     [4, 4, 4, 4, 4]])) 

meshgrid实际发生的返回2,5x5的二维数组的一个元组,但这种区别并不重要。关键的区别在于指示不必在特定方向上增加。它只是平铺它给出的数组。举个例子:

x = [0.1, 2.4, -5, 19] 
y = [-4.3, 2, -1, 18.4] 
xx, yy = np.meshgrid(x, y) 

产量:

(array([[ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ]]), 
array([[ -4.3, -4.3, -4.3, -4.3], 
     [ 2. , 2. , 2. , 2. ], 
     [ -1. , -1. , -1. , -1. ], 
     [ 18.4, 18.4, 18.4, 18.4]])) 

正如你会发现,它只是平铺,我们给它的值。

基本上,当您需要使用与输入网格相同形状的标记时,可以使用这些标记。当你想要评估一个网格值的函数时,它非常有用。

例如

import numpy as np 
import matplotlib.pyplot as plt 

x, y = np.mgrid[-10:10, -10:10] 
dist = np.hypot(x, y) # Linear distance from point 0, 0 
z = np.cos(2 * dist/np.pi) 

plt.title(r'$\cos(\frac{2*\sqrt{x^2 + y^2}}{\pi})$', size=20) 
plt.imshow(z, origin='lower', interpolation='bicubic', 
      extent=(x.min(), x.max(), y.min(), y.max())) 
plt.colorbar() 
plt.show() 

enter image description here

+2

Joe你完全正确,但如果在第二个循环中移动了'X.append(x)'',它将在这个例子中起作用。如果你有一个NxN长的一维数组,plot_surface仍然可以工作。错误是说matplotlib无法重塑一维数组,因此它是一个N×N二维数组。你也太快了。 – Yann 2012-01-12 20:47:57

+0

谢谢。这只是一个测试,看看我理解的曲线图。实际上,我打算做类似傅里叶变换的事情,我不知道如何在python中以单行方式进行复杂的操作或条件操作。我会为此发布一个新问题。 – Yotam 2012-01-12 20:50:29

+0

@Yann - 啊,对!我没有真正运行他的代码,因为它被张贴...猜猜我应该有!那么,你似乎真的回答了他的问题。 ...无论它值多少钱,你都会更频繁地击败我。 :) – 2012-01-12 20:52:13