正确使用坐标与 Plotly 绘制表面数据?

Correct use of coordinates to plot surface data with Plotly?

假设我有一个 x 值数组 X 和 y 值数组 Y,以及一个字典 results,以便 results[x][y] 访问 z 值。我如何构造一个 z 变量才能正确匹配生成它的坐标?

例如:

X = [0,2,3]
Y = [-1,-2,-3]
results = {x:{y: x/y for y in Y} for x in X}

Z = np.array([[results[x][y] for y in Y] for x in X ])
fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y)])
fig.update_layout(title='Plot', autosize=False,
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))
fig.update_layout(scene = dict(xaxis_title='X',
                    yaxis_title='Y'
                              )
                 )
fig.show()

给出了错误的图表:

这个坐标系是怎么工作的?执行 Z = np.array([[results[x][y] for x in X] for y in Y ]) 给出了正确的结果,但这对我来说没有意义。为什么x是第二个坐标?

问题

您得到奇怪结果的原因是计算机表示矩阵的方式,即按行和列表示索引 0, 0 处的“第一个”元素位于左上角,而考虑以左下角为原点的 XY 平面更直观,这是在数学中查看图形的标准方式。

解决方案

首先,通过充分利用 numpy,您可以通过 np.divide.outer() 更快地计算 z。这给出了 z 的正确结果,没有不必要的 dict 和嵌套理解(并且对于更大的数组会更有效)。

x = np.array([0, 2, 3])
y = np.array([-1, -2, -3])
z = np.divide.outer(x, y)

现在,由于计算机看到的矩阵与直觉上看到的 z = f(x, y) 不同,您需要绘制 z 的转置:

fig = go.Figure(data=[go.Surface(z=z.T, x=x, y=y)])

结果:

稍微详细一点的解释

如果我们调整绘图的方向,使 x 轴方向与我们通常在 2D 图形上查看它的方式相同(从左到右增加):

你可以看到在表面的左边缘,z,所有的值都是零。但是请注意 z 是如何表示为数组的:

>>> np.round(z, 2)
array([[-0.  , -0.  , -0.  ],
       [-2.  , -1.  , -0.67],
       [-3.  , -1.5 , -1.  ]])

如果转置 z,您会看到矩阵的“左”边全为零:

>>> np.round(z.T, 2)
array([[-0.  , -2.  , -3.  ],
       [-0.  , -1.  , -1.5 ],
       [-0.  , -0.67, -1.  ]])

这有望帮助阐明 xy 坐标和数组的行列表示之间的差异。还需要注意的是,在上面重新定向的图中,y 轴是“反转”的。这是因为矩阵的顶行被认为是“第一个”元素,但在正常的 xy 坐标系中,y 轴垂直增加(即从底部开始)。

对多元函数使用网格

您可以使用 np.meshgrid():

来避免转置 z
>>> x_coords, y_coords = np.meshgrid(x, y, indexing="xy")
>>> z = x_coords / y_coords
>>> z
array([[-0.  , -2.  , -3.  ],
       [-0.  , -1.  , -1.5 ],
       [-0.  , -0.67, -1.  ]])

现在请注意,z 已经采用了正确的格式来绘制为曲面。请注意,这也摆脱了 np.outer() 的必要性。使用 meshgrid 也可以更好地评估坐标网格上的任意函数。