我正在尝试在python中绘制表面。我有一张N x N值的表格。我创建了两个向量X和Y,每个元素N个。当我尝试绘制此图时,出现错误:

ValueError: total size of new array must be unchanged

我检查了示例,然后看到对于Z的N个元素,对于X和Y有N个元素。

这对我来说没有任何意义。为什么我需要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)

最佳答案

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

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

如果您阅读plot_surface的文档,则可以清楚地看到X,Y和Z应该是2D数组。

这样一来,您就可以通过固有地定义点之间的连通性来绘制更复杂的曲面(例如球体)。 (例如,从matplotlib库中查看此示例:http://matplotlib.sourceforge.net/examples/mplot3d/surface3d_demo2.html)

如果您具有一维X和Y数组,并且希望从2D网格中获得一个简单的曲面,请使用numpy.meshgridnumpy.mgrid生成适当的X和Y 2D数组。

编辑:
只是为了解释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]]])

因此,它返回形状为2x5x5的单个3D数组,但将其更容易地视为两个2D数组。一个代表5x5网格上任何点的i坐标,而另一个代表j坐标。

由于python解压缩的工作方式,我们可以这样写:
xx, yy = np.mgrid[:5, :5]

Python并不在乎mgrid返回什么,它只会尝试将其解压缩为两个项目。因为numpy数组会在其第一个轴的切片上进行迭代,所以如果解压缩形状为(2x5x5)的数组,我们将得到2个,5x5数组。同样,我们可以做类似的事情:
xx, yy, zz = np.mgrid[:5, :5, :5]

...并获得3个3D 5x5x5索引数组。同样,如果我们使用不同的范围进行切片(例如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之间的数字递增),但让我们跳过ozt_code一秒钟。
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]]))
mgrid实际上恰好返回一个2、5x5 2D数组的元组,但是区别并不重要。关键区别在于指标不必在特定方向上增加。它只是平铺给定的数组。举个例子:
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()

关于python - 使用python进行3d绘图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8841827/

10-12 19:53