如何进行 matshow 或 imshow,但将轴值显示为 bin 边界(即,就像在 2d frequency/density 图上一样)

How to do a matshow or imshow, but display the axis values as bin boundaries (i.e as you would on a 2d frequency/density plot)

我需要做一个类似二维密度的图。但是我自己计算 "densities" 。所以基本上我有一个 NxM 值数组,我只能用 plt.matshow (或 imshow)绘制。

fig, ax = plt.subplots()
im = ax.matshow(value_array)
ax.set_xticklabels(x_edges - 2.5)
ax.set_yticklabels(y_edges - 0.25)

但是,在这种情况下,轴值是图中的像素,而我真的希望它显示一些用户定义的值。所以我手动更改了上面的刻度标签。

这里还有一个问题。 matshow 仍然认为刻度标签在标记图像中的 "pixels",因此刻度标签打印在每个像素方块的 "middle" 中。然而,就像我说的,我真正想要绘制的更像是一个密度图,所以每个 "pixel square" 代表 x,y space 中的一个 bin。在正方形边缘 打印刻度标签会更有意义,就像一般的直方图和频率图所做的那样。

我应该为此继续使用 matshow 还是有其他功能可以做到这一点?例如,我可以使用 plt.hist2d 但手动设置 "heights" 而不输入数据作为一堆样本吗?否则,我该如何 plt.matshow 以我想要的方式放置刻度标签?

我不确定我是否理解正确。我的理解是,您想获取数据的二维直方图,并希望使用颜色显示每个 bin 的 count/density,同时保留 bin 边缘的真实坐标。

您确实可以使用 numpy.histogram2dmatplotlib.pyplot.imshow 的组合。

Let me start by a warning. Withimshow you display pixels. Implicitly you therefore assume that bins are uniformly sized along each axis. They may have a different width and height, but the width/height of each bin has be equal for the representation to be fair.

要实现我认为您想要的效果,您必须使用这样的东西:

import matplotlib.pyplot as plt
import numpy as np

N = 100000
x = np.random.randn(N)
y = np.random.weibull(2.,N)

P, xedges, yedges = np.histogram2d(x, y, bins=(np.linspace(-4,+5,10), np.linspace(0,4,21)), density=True)

fig, ax = plt.subplots()

cax = ax.imshow(P.T, extent=(xedges[0], xedges[-1], yedges[0], yedges[-1]),
  origin='lower', interpolation='nearest', clim=(0,.4), cmap='afmhot_r')

cbar = fig.colorbar(cax,aspect=10)

ax.set_aspect('auto')

ax.set_xlabel('x')
ax.set_ylabel('y')

plt.savefig('test.png')
plt.show()

哪个地块

棘手的部分是要获得自然输出:

  • 您必须覆盖 imshow 将原点放在图像顶部的默认设置。如前所述,您可以使用 origin='lower' 选项。
  • 您必须绘制 numpy.histogram 的转置输出,因为 imshow 按原样显示矩阵,而 numpy.histogram 显示的输出具有 (nx, ny) 的形状: x 轴上的值对应于行。
  • 您可能需要更改纵横比,请参阅 this answer

作为对@TomdeGeus 回答的补充,这里有一些可以提供帮助的内容。因为我需要绘制一个图形,其中 y 轴从 0.5 延伸到 3.5,而 x 轴从 0 延伸到 40,它在图像中被压缩得很厉害,我可能不得不强制纵横比,这是'工作。它显示的报价也有问题。

但是在确定宽高比之后,我绝对会建议您按照 Tom de Geus 的回答进行操作,这是执行此操作的正确方法。

所以我仍然在 "pixel" 坐标上绘制图像,即选择范围以便 x 轴和 y 轴计算像素,但从 0 开始,而不是像plt.imshow()

fig, ax = plt.subplots()

im = ax.matshow(value_grid, origin='lower', extent=(0, len(x_edges)-1, 0, len(y_edges)-1)

其中 len(y_edges) - 1 计算我想要在 y 轴上的像素数(y_edges 是一个包含我想要在 y 轴上显示的 bin 边界值的列表之前。

然后我手动替换刻度标签,但我还需要将它们正确映射到正确的刻度。

ax.set_xticks(list(range(len(x_edges))))
ax.set_xticklabels(x_edges)
ax.set_yticks(list(range(len(y_edges))))
ax.set_yticklabels(y_edges)

这保留了 imshow 生成的像素的方形性质,但是您必须记住,基础轴仍然是根据像素定义的(即,如果我想在坐标 (25.0, 2.0),它实际上看起来不像是在下面那个位置结束的。