numpy plot_surface中的x,y,z如何工作

1yjd4xko  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(126)

我试图弄清楚如何使用pyplot的plot_surface的输入数据,因为它非常令人困惑。首先,y轴并不代表高度,因为我习惯于几何。有一些文档,但对我来说没有意义。
ax.plot_surface()的一般格式如下。

>> ax.plot_surface(X, Y, Z)

其中X和Y是x和y点的二维数组,Z是高度的二维数组。
我注意到在示例中,数据通常是这样构建的:

import numpy as np
import matplotlib.pyplot as plt

tx = np.linspace(0, 1, nx)
ty = np.linspace(0, 1, ny)
X, Y = np.meshgrid(tx, ty)
Z = ((X**2-1)**2) # or some other pseudo-random generated data

plt.figure(figsize=(10,10))
plt.plot_surface(X, Y, Z)
plt.show()

因此,从我可以计算出的所有变量都是2D数组,其中:

  • X是将x坐标Map到一行y坐标的数组。
  • Y是将y坐标Map到y坐标列的数组。
  • Z是一个包含所有高度值的2D数组。但我不确定是x优先还是y优先。

我不确定这些假设是否正确。
有没有人知道一个地方,在那里这些事情是描述在一个更好地理解的方式,或者有人可以解释/哑巴这对我来说有点?

v64noz0r

v64noz0r1#

3个阵列X、Y、Z彼此相关,所得图如下:

  • X、Y、Z都需要具有相同的(二维)形状
  • 在任何索引(i,j)处:X[i,j]指定x坐标,Y[i,j]指定y坐标,Z[i,j]是xy点上表面的高度(X[i,j],Y[i,j])
  • 为了兼容地设置X和Y数组以及向量化函数f,f(X,Y)将产生合适的Z数组
  • 曲面将通过连接阵列中彼此相邻的点来构建曲面。子阵X[i:i+2,j:j+2],Y[i:i+2,j:j +2],Z[i:i +2,j:j+2]的每个“正方形”集合对应于所得到的表面网格内的四边形。数组X[i:i+2,j:j+2],Y[i:i+2,j:j+2]中的坐标可以看作这个四边形在xy平面上的“阴影

mesharray命令旨在以直观的方式利用这一点:在每个阵列内,在阵列内“水平”移动对应于改变x坐标,同时保持y坐标恒定。相反,在阵列内“垂直”移动对应于改变y坐标,同时保持x坐标不变。
虽然阵列中的接近度与空间中的接近度之间的对应关系是重要的,但是阵列内的移动与3-D空间中的移动之间的这种特定对应关系纯粹是为了用户的方便和直觉而遵循的惯例。
所有这一切的一个(可能违反直觉)结果是,可以在不改变结果曲面的情况下置换X,Y阵列(以及由此产生的Z阵列)。举个简单的例子,如果你应用转置

X, Y = X.T, Y.T

则得到的图形将是相同的,但是阵列中的水平移动现在对应于y坐标的变化,反之亦然。
另一个结果是,正如您所怀疑的,可以在非矩形区域上绘制曲面!这里有一个快速演示。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

nx = 11
ny = 11

tx = np.linspace(-1, 1, nx)
ty = np.linspace(-1, 1, ny)
X, Y = np.meshgrid(tx, ty)

#
# Reduce X,Y,Z to a diagonal strip
#
def diag_strip(M):
    return np.vstack([np.diag(M,k=-1),np.diag(M)[:-1],np.diag(M,k=1)])
X = diag_strip(X)
Y = diag_strip(Y)

#
# evaluate Z-array
#
Z = 1/(1 + X**2 + Y**2/2 + X*Y/2) 

fig, ax = plt.subplots(1,2, figsize = (20,10), subplot_kw={"projection": "3d"})
ax[0].plot_surface(X, Y, Z, cmap = cm.jet)
ax[1].view_init(elev = 90, azim = 0)
ax[1].plot_surface(X, Y, Z, cmap = cm.jet)

如果我们注解掉倒数第三个块(它将X,Y简化为对角线上的坐标),那么我们最终会得到[-1,1] x [-1,1]上的预期图。

左边的图是您期望的标准曲面图,右边的图是相同的图,但从“鸟瞰”视图(相机从z轴“向下”看)呈现,x,y轴以标准水平和垂直配置定向。
另一方面,按原样运行代码会导致以下结果:

如右图所示,网格的四边形在xy平面上不再有矩形“阴影”。
简化的X和Y数组如下:

[[-1.  -0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8]
 [-1.  -0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8]
 [-0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8  1. ]]

[[-0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8  1. ]
 [-1.  -0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8]
 [-1.  -0.8 -0.6 -0.4 -0.2  0.   0.2  0.4  0.6  0.8]]

每个阵列的第一行对应于真实对角线“上方”的平行线,第二行对应于矩形网格的对角线,第三行对应于真实对角线“下方”的平行线。
另一方面,在X和Y值周围混合太多会扰乱网格的四边形构造方式。例如,将diag_strip线

X = diag_strip(X).reshape([-1,3]).T
Y = diag_strip(Y).reshape([-1,3]).T

生成以下内容:

如果我们使用低透明度曲面图和线框图来绘制上面的图,那么可以更容易地看到上面发生了什么:

下面是X和Y矩阵现在的样子:

[[-1.  -0.4  0.2  0.8 -0.6  0.   0.6 -0.6  0.   0.6]
 [-0.8 -0.2  0.4 -1.  -0.4  0.2  0.8 -0.4  0.2  0.8]
 [-0.6  0.   0.6 -0.8 -0.2  0.4 -0.8 -0.2  0.4  1. ]]

[[-0.8 -0.2  0.4  1.  -0.6  0.   0.6 -0.8 -0.2  0.4]
 [-0.6  0.   0.6 -1.  -0.4  0.2  0.8 -0.6  0.   0.6]
 [-0.4  0.2  0.8 -0.8 -0.2  0.4 -1.  -0.4  0.2  0.8]]

说到非矩形区域上的曲面,这里有两种方法可以在圆形区域上绘制曲面。一种方法是使用Booalean掩码将点过滤到(x,y)坐标位于所需区域内的点。请注意,设置Z数组(或X数组或Y数组)的条目将导致不绘制点。这里是一个快速演示

nx = 51
ny = 51

tx = np.linspace(-1, 1, nx)
ty = np.linspace(-1, 1, ny)
X, Y = np.meshgrid(tx, ty)

Z = X**2 - Y**2

fig, ax = plt.subplots(2,2, figsize = (20,20), subplot_kw={"projection": "3d"})
ax[0,0].plot_surface(X, Y, Z, cmap = cm.jet)
ax[0,1].view_init(elev = 90, azim = 0)
ax[0,1].plot_surface(X, Y, Z, cmap = cm.jet)

mask = (X**2 + Y**2) > 1
Z[mask] = np.nan

ax[1,0].plot_surface(X, Y, Z, cmap = cm.jet)
ax[1,1].view_init(elev = 90, azim = 0)
ax[1,1].plot_surface(X, Y, Z, cmap = cm.jet)

结果图:

这种方法可以很容易地适用于其他类型的区域。不幸的是,这可能导致边界附近的不期望的伪影。对于圆形区域,我特别喜欢的一种方法是使用极坐标建立网格:

nr = 11
nth = 31

r_vals = np.linspace(0, 1, nr)
th_vals = np.linspace(0, 2*np.pi, nth)
R, Th = np.meshgrid(r_vals, th_vals)
X, Y = R*np.cos(Th), R*np.sin(Th)

Z = X**2 - Y**2

fig, ax = plt.subplots(1,2, figsize = (20,20), subplot_kw={"projection": "3d"})
ax[0].plot_surface(X, Y, Z, cmap = cm.jet)
ax[1].view_init(elev = 90, azim = 0)
ax[1].plot_surface(X, Y, Z, cmap = cm.jet)

结果:

由于meshgrid函数的工作方式,在结果X,Y,Z内水平移动对应于“r”((x,y)坐标与(0,0)的距离)的变化,垂直移动对应于“theta”(与正x轴的逆时针Angular )的变化。
这里有一个脚本,可以用半透明的表面和线框绘制同样的东西:

nr = 11
nth = 31

r_vals = np.linspace(0, 1, nr)
th_vals = np.linspace(0, 2*np.pi, nth)
R, Th = np.meshgrid(r_vals, th_vals)
X,Y = R*np.cos(Th), R*np.sin(Th)

Z = X**2 - Y**2

fig, ax = plt.subplots(1,2, figsize = (20,20), subplot_kw={"projection": "3d"})
ax[0].plot_surface(X, Y, Z, cmap = cm.jet, alpha = 0.1)
ax[0].plot_wireframe(X, Y, Z)
ax[1].view_init(elev = 90, azim = 0)
ax[1].plot_surface(X, Y, Z, cmap = cm.jet, alpha = 0.1)
ax[1].plot_wireframe(X, Y, Z)

结果:

相关问题