如何进行 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.histogram2d
和 matplotlib.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),它实际上看起来不像是在下面那个位置结束的。
我需要做一个类似二维密度的图。但是我自己计算 "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.histogram2d
和 matplotlib.pyplot.imshow
的组合。
Let me start by a warning. With
imshow
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),它实际上看起来不像是在下面那个位置结束的。