Python 如何进行matshow或imshow,但将轴值显示为面元边界(即,与2d频率/密度图上的一样)

Python 如何进行matshow或imshow,但将轴值显示为面元边界(即,与2d频率/密度图上的一样),python,matplotlib,plot,histogram2d,Python,Matplotlib,Plot,Histogram2d,我需要做一个二维密度图。然而,我自己计算“密度”。所以本质上我有一个NxM值数组,我只能用plt.matshow(或imshow)来绘制 但是,在本例中,轴值是绘图中的像素,而我确实希望它显示一些用户定义的值。因此,我手动更改勾号标签,如上所述 这仍然留下了一个问题matshow仍然认为记号标签在标记图像中的“像素”,因此记号标签打印在每个像素方块的“中间”。然而,正如我所说,我真正想要绘制的更像是密度图,所以每个“像素正方形”代表x,y空间中的一个箱子。将刻度标签打印在正方形边缘上会更有意义,

我需要做一个二维密度图。然而,我自己计算“密度”。所以本质上我有一个
NxM
值数组,我只能用
plt.matshow
(或imshow)来绘制

但是,在本例中,轴值是绘图中的像素,而我确实希望它显示一些用户定义的值。因此,我手动更改勾号标签,如上所述

这仍然留下了一个问题
matshow
仍然认为记号标签在标记图像中的“像素”,因此记号标签打印在每个像素方块的“中间”。然而,正如我所说,我真正想要绘制的更像是密度图,所以每个“像素正方形”代表x,y空间中的一个箱子。将刻度标签打印在正方形边缘上会更有意义,就像通常对直方图和频率图所做的那样


我应该继续使用matshow吗?还是有其他函数可以这样做?例如,我是否可以使用
plt.hist2d
手动设置“高度”,而不将数据作为一组样本输入?否则,我如何才能使
plt.matshow
以我想要的方式放置记号标签?

我不确定我是否正确理解您的意思。我的理解是,您希望获取数据的二维柱状图,并希望使用颜色显示每个箱子的计数/密度,同时保留箱子边缘的真实坐标

实际上,您可以结合使用
numpy.historogram2d
matplotlib.pyplot.imshow

让我从一个警告开始。使用
imshow
可以显示像素。因此,隐式地假设容器沿每个轴的大小是一致的。它们可能具有不同的宽度和高度,但每个箱子的宽度/高度必须相等,以使表示公平

要实现我认为您想要的目标,您必须使用以下内容:

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
    show的输出具有形状
    (nx,ny)
    :沿x轴的值对应于行
  • 您可能必须更改纵横比,请参见

作为@TomdeGeus答案的补充,这里有一些东西可能会有所帮助。由于我需要绘制一个图形,其中y轴从0.5延伸到3.5,而x轴从0延伸到40,因此在图像中非常压缩,我可能不得不强制执行纵横比,这不起作用。它显示的滴答声也有问题

但是在确定纵横比后,我绝对建议您遵循Tom de Geus的答案,这是正确的方法。

因此,我仍然在“像素”坐标上绘制图像,即选择范围,以便x轴和y轴计算像素,但从0开始,而不是像
plt.imshow()的默认行为那样从-0.5开始

其中
len(y_边)-1
统计我希望在y轴上显示的像素数(而
y_边
是一个列表,其中包含我希望在y轴上显示的存储单元边界值,如前所述

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

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)上放置一个点,它实际上看起来不会在下面的位置结束


imshow
extent
选项吗?@TomdeGeus我不这么认为。据我所知,extent只会影响图像的范围(如xlim或ylim),虽然我可能误解了它的工作原理。基本上,在关于范围的文档中,你可以在图中看到,轴实际上从-0.5开始,到6.5,而刻度标签位于像素的中心,在0.0、1.0等处。因此,如果我可以将刻度位置偏移0.5,它可以做我想要的事情(或者最好将整个图像移动-0.5像素)。谢谢你的回答,我认为它可以工作,但我仍然有一些问题(同时我正在使用matshow以防它有所不同)首先,我的x轴范围从0到40,y轴范围从0.5到3.5,所以就像你的照片一样,绘图在垂直方向上是非常压缩的。这是预期的吗?我应该尝试使用一些图形参数拉伸吗?第二:我不确定我做错了什么,但它没有在y轴上放置完整的值范围(也就是说,我手动设置了刻度标签,但它每秒钟就有一个刻度,总的来说,它的范围是我预期的一半)@关于LimokPalantaemon的纵横比:我已经更新了我的答案,包括<代码> SETIONGOND 。对于滴答声,很难说不看到实际的代码和问题。你可以考虑打开一个新的问题吗?嘿,我一直在寻找设置这个方面,但是它不适用于一个简单的<代码> Stasyaspe。ct(‘相等’).
此外,我开始相信这是一个比我最初想象的更复杂的问题。设置范围和您的答案很有帮助,但我认为在此之后还有另一步要做。我正在考虑在范围中保留“像素”的概念,而不是拉伸图形;相反,我将尝试重新标记刻度我将在下面发布一个答案(仍然保留你的答案)。两者的结合可能对其他人有所帮助
fig, ax = plt.subplots()

im = ax.matshow(value_grid, origin='lower', extent=(0, len(x_edges)-1, 0, len(y_edges)-1)
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)