Python imshow中一个错误关闭?

Python imshow中一个错误关闭?,python,matplotlib,Python,Matplotlib,我正在绘制PGM图像: 这是我正在使用的 问题是显示的一些像素是错误的。例如: 图像顶部附近的三个灰色框的值为11(因此它们应该是红色,而不是红色) 顶行中的两个黄色像素——它们的值为8,因此它们应该是黄绿色,而不是黄色 有人能解释这些差异以及如何解决它们吗 以下是我的消息来源: from pylab import * import numpy LABELS = range(13) NUM_MODES = len(LABELS) def read_ascii_pgm(fname):

我正在绘制PGM图像: 这是我正在使用的

问题是显示的一些像素是错误的。例如:

  • 图像顶部附近的三个灰色框的值为11(因此它们应该是红色,而不是红色)
  • 顶行中的两个黄色像素——它们的值为8,因此它们应该是黄绿色,而不是黄色
有人能解释这些差异以及如何解决它们吗

以下是我的消息来源:

from pylab import *
import numpy    
LABELS = range(13)
NUM_MODES = len(LABELS)
def read_ascii_pgm(fname):
    """
    Very fragile PGM reader.  It's OK since this is only for reading files
    output by my own app.
    """
    lines = open(fname).read().strip().split('\n')
    assert lines[0] == 'P2'
    width, height = map(int, lines[1].split(' '))
    assert lines[2] == '13'
    pgm = numpy.zeros((height, width), dtype=numpy.uint8)
    for i in range(height):
        cols = lines[3+i].split(' ')
        for j in range(width):
            pgm[i,j] = int(cols[j])
    return pgm
def main():
    import sys
    assert len(sys.argv) > 1
    fname = sys.argv[1]
    pgm = read_ascii_pgm(fname)
    # EDIT: HACK!
    pgm[0,0] = 12
    cmap = cm.get_cmap('spectral', NUM_MODES)
    imshow(pgm, cmap=cmap, interpolation='nearest')
    edit = True
    if edit:
        cb = colorbar()
    else:
        ticks = [ (i*11./NUM_MODES + 6./NUM_MODES) for i in range(NUM_MODES) ]
        cb = colorbar(ticks=ticks)
        cb.ax.set_yticklabels(map(str, LABELS))
    savefig('imshow.png')
if __name__ == '__main__':
    main()
编辑

我知道这里发生了什么。基本上,
imshow
似乎在这样做:

  • 确定动态范围(如
    [min(图像)、max(图像)]
  • 使用颜色映射中指定的颜色数(13种颜色)表示
我想让它做的是:

  • 使用我在创建颜色贴图时指定的动态范围(13)
  • 使用颜色贴图中的13种颜色来表示
我可以通过强制将图像的动态范围设置为13来验证这一点(请参见标有
HACK
)的行)。有更好的方法吗

以下是更新后的图像:

没有差异,您只需手动将刻度设置为使用与实际值不同的值进行标记

请注意,您的
标签
仅为
范围(13)
,而实际的记号位置(
记号
)不在0到12之间

因此,您正在手动将顶部刻度标记为12,其位置为10.6

试着取出行
cb.ax.set\u yticklabels(map(str,LABELS))
,你就会明白我的意思(同样,matplotlib会自动将它们转换为字符串。没有理由调用
map(str,LABELS)

也许您不应该使用一组静态数字作为标签,而应该将实际的刻度位置转换为标签?类似于
[刻度中刻度的圆形(刻度)]

编辑:对不起,这听起来比我想的更刺耳……我不是故意这么说的!:)

Edit2: 对于更新后的问题,是,
imshow
自动确定输入的最小值和最大值的范围。(我很困惑……它还能做什么?)

如果您想要无插值的直接颜色映射,请使用一个离散颜色映射,而不是
LinearSegmentedColormap
。但是,手动设置matplotlib的
LinearSegmentedColormap
s之一的限制是最简单的(这就是
matplotlib.cm.Spectrum
的功能)

如果要手动设置使用的颜色映射范围,只需在
imshow
返回的coloraxis对象上调用
set\u clim([0,12])

例如


解决方案是设置
im.set_clim(vmin,vmax)
。基本上,图像中的值被转换为覆盖整个颜色范围。例如,如果
3
是数据中的最大值,则将为其指定最大颜色值

相反,您需要告诉它
max\u nodes
是最高值(在您的情况下为13),即使它没有出现在数据中,例如
im.set\u clim(0,13)

我稍微更改了您的代码,以处理具有不同值的其他数据文件,用于
num\u模式

import numpy
from pylab import *

def read_ascii_pgm(fname):
    lines = open(fname).read().strip().split('\n')
    assert lines[0] == 'P2'
    width, height = map(int, lines[1].split(' '))
    num_modes = int(lines[2])
    pgm = numpy.zeros((height, width), dtype=numpy.uint8)
    for i in range(height):
        cols = lines[3+i].split(' ')
        for j in range(width):
            pgm[i,j] = int(cols[j])
    return pgm, num_modes + 1

if __name__ == '__main__':
    import sys
    assert len(sys.argv) > 1
    fname = sys.argv[1]
    pgm, num_modes = read_ascii_pgm(fname)
    labels = range(num_modes)
    cmap = cm.get_cmap('spectral', num_modes)
    im = imshow(pgm, cmap=cmap, interpolation='nearest')
    im.set_clim(0, num_modes)
    ticks = [(i + 0.5) for i in range(num_modes)]
    cb = colorbar(ticks=ticks)
    cb.ax.set_yticklabels(map(str, labels))
    savefig('imshow_new.png')
一些简单的测试数据来说明。请注意,
num_modes
值为10,但没有数据点达到该级别。这显示了值如何索引到colormap 1:1中:

P2
5 3
10
0 1 0 2 0
3 0 2 0 1
0 1 0 2 0
输出:


谢谢你的回答。首先,我不同意你的观点。我认为这是不一致的。颜色栏有13种颜色,其中灰色为最高值颜色,深红色为第二高,红色为第三高,等等。图像的最大强度为13(正如我在创建颜色贴图时指定的),其中12是最高值。我认为12应该被表示为灰色,11应该被表示为深红色,这是错误的吗?不要担心听起来刺耳。你刚才给了我一个问题的答案。请看我更新的问题。谢谢!Woops,没有注意到@samplebias的回答,这和我的回答完全一样。我花了太长时间编辑!:)不过,我会保持原样。@misha-这不是
ScalarMappable
(imshow返回的内容)在matplotlib中的工作方式。如果需要离散调色板,请设置
cax.norm=mpl.colors.NoNorm(0,12)
。或者(更容易),您可以设置
cax.set_clim(…)
,就像我和samplebias的答案一样。但是,为了澄清这一点,重要的是ScalarMappable对象(最容易由
plt.imshow
创建)如何缩放它,而不是使用什么颜色方案。除非您另外指定,否则matplotlib始终假定它使用的是连续数据。+1-这似乎是很多人可能遇到的问题,从而得到“几乎正确”的结果。我不想在出版后看到这个。是的,我在回来看你的答案之前看到了这个。实际上,我将min和max作为参数传递给
imshow
,但本质上是一样的。谢谢你写的易懂的文章!
P2
5 3
10
0 1 0 2 0
3 0 2 0 1
0 1 0 2 0