调整matplotlib imshow中的网格线和刻度

54

我想绘制一个数值矩阵,并希望添加网格线以使值之间的边界更清晰。不幸的是,imshow决定将刻度标记放在每个体素的中间位置。是否可能:

a) 删除刻度标记但保留标签在相同位置
b) 在像素边界之间添加网格线?

import matplotlib.pyplot as plt
import numpy as np

im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
                    interpolation='none', vmin=0, vmax=1, aspect='equal');
ax = plt.gca();
ax.set_xticks(np.arange(0, 10, 1));
ax.set_yticks(np.arange(0, 10, 1));
ax.set_xticklabels(np.arange(1, 11, 1));
ax.set_yticklabels(np.arange(1, 11, 1));

图像没有网格线,刻度标记位置不正确 输入图片描述

ax.grid(color='w', linestyle='-', linewidth=2)

错误位置的网格线图像:

在此输入图像描述


设置图像范围似乎可以解决问题;默认情况下,网格坐标系统会稍微偏离自然原点:plt.imshow(..., extent=(0, 10, 10, 0)); - psychemedia
5个回答

77

Serenity建议的解决方案代码:

plt.figure()
im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
                interpolation='none', vmin=0, vmax=1, aspect='equal')

ax = plt.gca();

# Major ticks
ax.set_xticks(np.arange(0, 10, 1))
ax.set_yticks(np.arange(0, 10, 1))

# Labels for major ticks
ax.set_xticklabels(np.arange(1, 11, 1))
ax.set_yticklabels(np.arange(1, 11, 1))

# Minor ticks
ax.set_xticks(np.arange(-.5, 10, 1), minor=True)
ax.set_yticks(np.arange(-.5, 10, 1), minor=True)

# Gridlines based on minor ticks
ax.grid(which='minor', color='w', linestyle='-', linewidth=2)

# Remove minor ticks
ax.tick_params(which='minor', bottom=False, left=False)

生成的图片: 在这里输入图片描述


31

使用plt.pcolorplt.pcolormesh更加简单:

data = np.random.rand(10, 10)
plt.pcolormesh(data, edgecolors='k', linewidth=2)
ax = plt.gca()
ax.set_aspect('equal')

enter image description here

虽然它们之间存在一些差异,和plt.imshow最明显的区别是图像被Y轴翻转了(你可以通过添加ax.invert_yaxis()来轻松地将其反转回来)。有关进一步讨论,请参见此处:何时使用imshow而不是pcolormesh?


1
这样做要简单得多,而且不需要手动处理刻度/标签。这应该是被接受的答案。 - Blademaster

28

尝试移动坐标轴刻度:

ax = plt.gca()
ax.set_xticks(np.arange(-.5, 10, 1))
ax.set_yticks(np.arange(-.5, 10, 1))
ax.set_xticklabels(np.arange(1, 12, 1))
ax.set_yticklabels(np.arange(1, 12, 1))

输入图像描述


1
谢谢,这对于网格线来说完美无缺。有没有办法同时将标签保持在像素中心? - Joe Bathelt
将主要刻度位置设置为每个带标签的正方形的中心。然后将次要刻度设置为每个不带标签的正方形的边缘。最后,显示网格仅在次要刻度上显示。 - Serenity
1
你可以将自己的代码作为新答案发布(带/不带图片),以供任何遇到类似问题的人参考。 - Serenity

10
您可以通过向 imshow 函数传递 extent 参数来移动像素。 extent 是一个由4个标量(left,right,bottom,top)组成的列表:
foo = np.random.rand(35).reshape(5, 7)
# This keeps the default orientation (origin at top left):
extent = (0, foo.shape[1], foo.shape[0], 0)
_, ax = plt.subplots()
ax.imshow(foo, extent=extent)
ax.grid(color='w', linewidth=2)
ax.set_frame_on(False)

enter image description here


不错的技巧,我使用plt.xticks的hava参数来微调刻度。 - CAV

4

这有点像一个技巧,但我喜欢使用它,因为它不需要我移动x轴刻度或y轴刻度。

import numpy as np
import matplotlib.pyplot as plt

plt.matshow(np.random.random(size=(10,10)))

plt.hlines(y=np.arange(0, 10)+0.5, xmin=np.full(10, 0)-0.5, xmax=np.full(10, 10)-0.5, color="black")
plt.vlines(x=np.arange(0, 10)+0.5, ymin=np.full(10, 0)-0.5, ymax=np.full(10, 10)-0.5, color="black")

plt.show()

enter image description here


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