在 matplotlib imshow() 图形轴上更改数值

127

假设我有一些输入数据:

data = np.random.normal(loc=100, scale=10, size=(500,1,32))
hist = np.ones((32, 20)) # initialise hist
for z in range(32):
    hist[z], edges = np.histogram(data[:, 0, z], bins=np.arange(80, 122, 2))

我可以使用imshow()绘制它:

plt.imshow(hist, cmap='Reds')

获取:

第一次尝试

然而,x轴的值与输入数据不匹配(即平均值为100,范围从80到122)。因此,我想更改x轴以显示edges中的值。

我已经尝试过:

ax = plt.gca()
ax.set_xlabel([80,122]) # range of values in edges
...
# this shifts the plot so that nothing is visible

ax.set_xticklabels(edges)
...
# this labels the axis but does not centre around the mean:

second try

有什么想法可以改变轴的值以反映我正在使用的输入数据吗?


1
请使用 pcolor,而不是在这个答案中提到的 imshow - Nirmal
3个回答

202

如果可能的话,我会尽量避免更改xticklabels,否则当你将直方图与其他数据叠加时,情况可能会非常混乱。

定义网格的范围可能是最好的选择,并且可以通过添加extent关键字来在imshow中完成。这样,轴会自动调整。如果您想更改标签,我建议使用set_xticks和一些格式化程序。直接修改标签应该是最后的选择。

fig, ax = plt.subplots(figsize=(6,6))

ax.imshow(hist, cmap=plt.cm.Reds, interpolation='none', extent=[80,120,32,0])
ax.set_aspect(2) # you may also use am.imshow(..., aspect="auto") to restore the aspect ratio

输入图像描述


24
值得注意的是,这里使用了 interpolation="none",这更加准确地表示了真实数据。 - Hooked
6
非常有用的答案,我用它来绘制了一个二元函数(即地震数据)的彩色图。我还在imshow()函数中添加了选项“aspect='auto'”,这样我可以“拉伸和挤压”地震图像的显示效果。 - Kurt Peek

20

我之前遇到类似的问题,谷歌搜索引擎将我带到了这篇帖子。我的解决方案和原帖有些不同,且较为冗长,但希望对某些人有所帮助。

使用 matplotlib.pyplot.imshow 显示二维数据通常是一种快速的方式。但默认会在坐标轴上打印像素计数。如果你正在绘制的二维数据与由数组 x 和 y 定义的某个均匀网格相对应,则可以使用 matplotlib.pyplot.xticks 和 matplotlib.pyplot.yticks 标记 x 和 y 轴,使用这些值来打印实际的网格数据标签,而非像素计数。这样做比使用例如 pcolor 等方法要快得多。

以下是针对您的数据的尝试:

import matplotlib.pyplot as plt

# ... define 2D array hist as you did

plt.imshow(hist, cmap='Reds')
x = np.arange(80,122,2) # the grid to which your data corresponds
nx = x.shape[0]
no_labels = 7 # how many labels to see on axis x
step_x = int(nx / (no_labels - 1)) # step between consecutive labels
x_positions = np.arange(0,nx,step_x) # pixel count at label position
x_labels = x[::step_x] # labels you want to see
plt.xticks(x_positions, x_labels)
# in principle you can do the same for y, but it is not necessary in your case

4

extent=被设置为某个列表时,图像会沿着x-和y轴分别拉伸以填充框。但有时,最好仍然使用ax.setplt.xticks/plt.yticks显式地设置刻度标签(在我看来):

fig, ax = plt.subplots(figsize=(6,6))
ax.imshow(hist, cmap='Reds', interpolation='none', extent=[80, 120, 32, 0], aspect=2)
ax.set(xticks=np.arange(80, 122)[::10], xticklabels=np.arange(80, 122)[::10]);

由于extent=设置了图像大小,使用它来设置刻度标签有时不是理想的选择。例如,假设我们想要显示一张相对高但具有较小刻度标签的长图像,如下所示:

correct output

那么,

fig, ax = plt.subplots(1, figsize=(6, 6))
ax.imshow(np.arange(120)[None, :], cmap='Reds', extent=[0, 120, 1, 0]);

生成

错误输出

但是

fig, ax = plt.subplots(1, figsize=(6, 6))
ax.imshow(np.arange(120)[None, :], cmap='Reds', extent=[0, 120, 10, 0]);
ax.set(xticks=np.linspace(0, 120, 7), xticklabels=np.arange(0, 121, 20), yticks=[0, 10], yticklabels=[0, 1]);

生成正确的输出。这是因为extent=被设置为较大的值,但刻度标签被设置为较小的值,以便图像具有所需的标签。

N.B. ax.get_xticks()ax.get_yticks()是有用的方法,可以了解默认(或其他)刻度位置,而ax.get_xlim()ax.get_ylim()是有用的方法,可以了解轴限制。


即使在OP使用的方法中,没有任何extent=ax.get_xlim()仍会返回(-1.0, 19.5)。由于x轴刻度位置范围已经设置为这样,因此可以将x轴刻度标签设置为其他内容;只需将xticks设置为该范围内的某些值,并分配任何值给xticklabels即可。因此,以下内容呈现所需的图像。

fig, ax = plt.subplots(figsize=(6,6))
ax.imshow(hist, cmap='Reds', interpolation='none', aspect=2)
ax.set(xticks=np.arange(-1, 20, 5), xticklabels=np.arange(80, 122, 10));

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