使用三个一维数组制作等高线图

9

正如标题所示,我想使用三个1D数组制作轮廓图。假设:

x = np.array([1,2,3])

并且

y = np.array([1,2,3])

并且。
z = np.array([20,21,45])

要在matplotlib中绘制等高线图,我需要将x和y坐标网格化为X,Y = meshgrid(x,y)。但是z数组也必须是2D数组。那么我该如何将z转换为2D数组以便使用呢?

2
看起来NP8的答案是唯一回答你所问的x、y和z值列表的答案。我发现那个非常有用。我不明白你为什么更喜欢标记为正确的那个答案。 - DrM
4个回答

20

虽然 OP 意识到使用问题中的数据无法绘制轮廓图,但在数据可以被视为 3D 表面的情况下,这仍然是一个相关的问题。

绘制三个 1D 数组的轮廓图选项

基本上有三个选项:

  1. 如果您不一定要使用常规的 contourf 函数,则可以使用 tricontourf 进行绘制。适用于网格化和非网格化数据。
  2. 如果您的数据 已经网格化,但是在三个单独的 1D 数组中,您可以将它们分成两个 1D 数组和一个 2D 数组,并使用 contourf 绘制。
  3. 如果您的数据 没有网格化,并且您不想使用 tricontourf,则可以将数据插值到网格中,并使用 contourf 绘制。有许多关于 3D 插值的问题可以帮助您解决此问题。在插值数据之后,您可以使用 Option 2 中展示的技术。

选项 1:tricontourf

这个非常简单。只需像这样使用 plt.tricontourf 函数即可(请参见附录中示例数据的创建)。

from matplotlib import pyplot as plt

plt.tricontourf(xdata, ydata, zdata)
plt.show()

输出

tricontourf

选项2:网格化的1D数组和contourf

如果有存储在三个1D数组中的网格化数据,且由于某种原因不想使用tricontourf,则可以使用以下方法制作contourf图。 (附录中提供示例数据)

import pandas as pd
from matplotlib import pyplot as plt 

df = pd.DataFrame(dict(x=xdata, y=ydata, z=zdata))
xcol, ycol, zcol = "x", "y", "z"
df = df.sort_values(by=[xcol, ycol])
xvals = df[xcol].unique()
yvals = df[ycol].unique()
zvals = df[zcol].values.reshape(len(xvals), len(yvals)).T
plt.contourf(xvals, yvals, zvals)
plt.show()

输出

contourf

解释Idea

  • 首先,数据必须被网格化,因为这是plt.contour绘图的工作方式。如果没有,您可以将其插值到新网格中。
  • 然后,创建pandas.DataFrame df 作为中间介质。
  • 然后,使用df.sort_values()方法对x和y数据进行排序。这使得在下一步中由unique()给出的值被排序。
  • 使用unique()获取x和y数据的所有唯一值。这有点像“meshgrid”操作的反向操作。
  • 由于pandas dataframe列的值只是numpy数组,因此可以调用reshape()方法来创建所需的2d数组。
  • 现在,如果x有N个唯一值,y有M个唯一值,则zvals将是一个(N,M) 2d数组,可以提供给plt.contour。

附录:示例数据

import numpy as np
import pandas as pd

xs, ys = np.linspace(-4, 4), np.linspace(-4, 4)
xgrid, ygrid = np.meshgrid(xs, ys)
xdata, ydata = np.ravel(xgrid), np.ravel(ygrid)
zdata = (
    2.3 * (1 - xdata) ** 2 * np.exp(-(ydata ** 2) - (xdata + 0.9) ** 2)
    - 13.3
    * (ydata / 2.2 - ydata ** 3 - xdata ** 4)
    * np.exp(-(ydata ** 2) - xdata ** 2)
    - 0.8 * np.exp(-((ydata + 1) ** 2) - xdata ** 2)
)


3
到目前为止,这是唯一一个正确回答并且回答了提出的问题,而且它非常全面和清晰易懂。 - DrM

2

如果我使用已经ravel的数据进行操作,我会频繁遇到这个问题。在raveled数据中,2-D数组被压平了。

原始数据包含每个坐标的x、y和z值:

x = [0, 1, 2; 0, 1, 2]

y = [0, 0, 0; 1, 1, 1]

z = [0.1 , 0.2, 0.3 ; 0.2, 0.3, 0.4]

使用 np.ravel() 对这三个数组进行操作,可以将它们变成一个长度为6的一维数组。
xx = np.ravel(x); yy = np.ravel(y) ; zz = np.ravel(z)

现在xx = ([0, 1, 2, 0, 1, 2]),yy和zz同理。

如果您正在处理此类数据并且数据已经充分采样,则可以使用散点图模拟contourf绘图。这仅在数据集被充分采样以填充所有空间时才有效。

plt.scatter(xx,yy,c=zz,cmap=cm.Reds)

enter image description here


0

在我看来,你描述的是空间中的一维曲线而不是一个表面。我这样说是因为我假设x[i]y[i]z[i]是一个点的坐标。你无法用这些点轻松地定义一个表面,因为你的点只依赖于一个变量i,所以只描述了一个自由度形状。请考虑到你可以将列表中的每个点连接到下一个点,并且这只会给你一个一维点链。为了从三个数组创建一个表面,你必须定义9个z值,而不是3个。

很抱歉这不是一个有帮助的答案,但我没有足够的声望来发布评论。


我明白你的意思。谢谢。 - David Halley

-2

你的z是错误的。它需要在网格的每个点上给出值。如果zxy的函数,请计算下面我所称的X_grid处的z

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return (x[:,0]**2 + x[:,1]**2)

x = np.array([1,2,3])
y = np.array([1,2,3])
xx, yy = np.meshgrid(x, y)
X_grid = np.c_[ np.ravel(xx), np.ravel(yy) ]
z = f(X_grid)

z = z.reshape(xx.shape)

plt.contour(xx, yy, z)

请注意 z = "values at ...",因为这里你正在将一个字符串赋值给 z。除此之外,我还遇到了以下错误:ValueError: total size of new array must be unchanged。 - David Halley
@SmailKozarcanin,每个网格点都需要一个z值,但是您没有提供这个值,因此除非您告诉我们如何找到缺失的z值,否则您的问题实际上无法回答...请参考Theo的答案,那更像是一条评论。 - jotasi
2
这个问题询问如何从一组z值生成图形。它没有询问如何从函数生成图形。因为用例完全不同,所以答案对于所提出的问题是无用的。也就是说,你没有回答这个问题。 - DrM
它“某种程度上”被视为正确,因为OP接受它作为答案-表明他发现这些信息对他的问题有用。没有人强迫他或试图说服他这样做。我想真正令人沮丧的是被封锁的无聊,这是可以理解的。 - id5h
2
也许@NP8的正确答案是在他错误地将您标记为正确之后发布的。因为OP选择它并不意味着它是正确的。如果OP是这样的专家,他就不需要提问了。 - DrM
显示剩余3条评论

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