在Matplotlib/Python中在等高线图上绘制数据点

8

我想使用Matplotlib在等高线图上绘制一些点。

我有一个标量场,想要在上面绘制等高线。 但是我的ndarray的维度是0 x 20,而我的实际空间变化范围从-4到4。

我可以使用以下代码来绘制等高线:

x, y = numpy.mgrid[-4:4:20*1j, -4:4:20*1j]

# Draw the scalar field level curves
cs = plt.contour(scalar_field, extent=[-4, 4, -4, 4])
plt.clabel(cs, inline=1, fontsize=10)

问题是我需要在这个图中绘制一些点,而这些点是使用ndarray获得的,即,我获取随着该数组维度变化而变化的点。我尝试使用以下代码绘制这些点:
def plot_singularities(x_dim, y_dim, steps, scalar_field, min_points, max_points, file_path):
    """
    :param x_dim : the x dimension of the scalar field
    :param y_dim : the y dimension of the scalar field
    :param steps : the discretization of the scalar field
    :param file_path : the path to save the data
    :param scalar_field : the scalar_field to be plot
    :param min_points : a set (x, y) of min points of the scalar field
    :param max_points : a set (x, y) of max points of the scalar field
    """
    min_points_x = min_points[0]
    min_points_y = min_points[1]
    max_points_x = max_points[0]
    max_points_y = max_points[1]

    plt.figure()

    x, y = numpy.mgrid[-x_dim:x_dim:steps*1j, -y_dim:y_dim:steps*1j]

    # Draw the scalar field level curves
    cs = plt.contour(scalar_field, extent=[-x_dim, x_dim, -y_dim, y_dim])
    plt.clabel(cs, inline=1, fontsize=10)

    # Draw the min points
    plt.plot(min_points_x, min_points_y, 'ro')

    # Draw the max points
    plt.plot(max_points_x, max_points_y, 'bo')

    plt.savefig(file_path + '.png', dpi=100)
    plt.close()

但是我得到了这个图片:

在此输入图片描述

这张图片是不正确的。

如果我改变这一行:

cs = plt.contour(scalar_field, extent=[-x_dim, x_dim, -y_dim, y_dim])

对于这个问题:

cs = plt.contour(scalar_field)

在此输入图片描述

我得到了期望的结果,但是范围没有显示出我的真实数据空间,而是ndarray的维度。

最后,如果我不绘制这些点(注释掉plot()行),我可以得到想要的范围:

在此输入图片描述

但我必须绘制这些点。 两个数据都在相同的空间中。 但是contour()函数允许我指定网格。 我找到了一种方法来在绘制点时完成这个操作。

如何正确地设置范围?


知道您的期望会有所帮助。 "数据空间" 应该是什么? 点和轮廓都不正确,还是只有轮廓不正确? - amd
如果您查看第二张图片,它是正确的(图表)。然而,它显示的范围是ndarray的维度(从0到20)。我想要显示它变化从我的数据空间(以0,0为中心,从-4到4变化)。我将我的“数据空间”称为类比于CG概念的图像空间(ndarray)和世界空间(我的真实数据空间)。 - pceccon
2个回答

5
如果您没有提供与标量场对应的x和y数据,则contour使用整数值,最高达到数组的大小。这就是为什么轴显示数组的维数。参数extent应该给出最小和最大的x和y值;我认为这就是您所说的“数据空间”。因此,对contour的调用将如下所示:
contour(scalar_field,extent=[-4,4,-4,4])

通过指定xy数据可以重现此问题:

contour(numpy.linspace(-4,4,20),numpy.linspace(-4,4,20),scalar_field)

然后等高线看起来与您的第一个图完全相同。我认为这是不正确的原因是最小值和最大值不在正确的位置。根据您提供的信息,这是因为您传递给函数的 min_pointsmax_points 是数组scalar_field中的索引,因此它们对应于整数,而不是实际的 xy 值。尝试通过定义来使用这些索引访问 xy 点:
x=numpy.linspace(-4,4,20)
y=numpy.linspace(-4,4,20)

例如,如果你有一个最小点(0,1),它将对应于(x[0], y[1])。我认为使用mgrid也可以做类似的事情,但我自己从未使用过。

谢谢!我刚刚为@Ajean写了一篇文章,我知道这些是索引,这就是问题所在(如果我表达得不好,对不起)。我正在寻找在Matplolib/Python中进行此转换的聪明方法。非常感谢! - pceccon

0
你想在真实数据空间中绘制等高线和点,是吗?plt.contour将使用与您拥有的2D数组相关联的x和y值,并在坐标轴上正确绘制。
xvals = -x_dim:x_dim:step  # I'm not sure about these ... but you get the idea
yvals = -y_dim:y_dim_step
plt.contour(xvals, yvals, scalar_field)

如果我只是这样做,我会得到第一张图像,它不符合我绘制点时想要的空间。 - pceccon
你确定你正在绘制正确的空间中的点吗?看起来你正在用一种方式绘制实际值,而用另一种方式绘制索引。 - Ajean
它们都在同一个空间中。当我绘制轮廓时,我将我的范围更改为参数,但是当我绘制点时,我不知道该怎么做。 - pceccon
我认为这里存在一个根本性的误解...当你绘制点时,它们是(x,y)值,并且绘图将把它们放在它们所在的位置,无论如何。要显示的2D数组(通过等高线)没有固有的与之关联的(x,y)位置,这就是为什么您需要指定它们(通过范围或上面的xvals和yvals)。如果您用plot绘制的x-y点确实在x_dim/y_dim空间中(-4到4),那么这将起作用。看起来它们是索引 - Ajean
请注意,4个最大点位于0-0、0-19、19-0、19-19,而您的数组长度为20。 - Ajean
是的,确实如此。我在想是否需要手动进行空格转换,逐个诱导,或者是否有一些Matplotlib/Python的“魔法”,例如定义网格和调整点,我不知道。 - pceccon

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