【问题标题】:Changing colours of pixels of plt.imshow() image改变 plt.imshow() 图像像素的颜色
【发布时间】:2020-12-21 19:18:19
【问题描述】:

我需要使用 matplotlib 的 imshow() 绘制图像,然后用不同颜色标记一些像素。只是在初始数组中更改它们的值是行不通的,因为我需要使用我正在使用的颜色图中不存在的颜色。所以我最初的意图是在第一张图像上方绘制第二个生成的数组,其中大部分被遮盖,所需的像素没有被遮盖,并且具有一些值(可能不同的值用于不同的坐标使用不同的颜色)。它与 matplotlib 的交互式查看器配合得很好,但是当保存到文件中时,一切都可能因为这个错误而失真,我在同样的情况下报告了这个错误:https://github.com/matplotlib/matplotlib/issues/3057

是否有任何其他选项可以更改某些像素的颜色?

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    您已经建议了最简单的方法(在顶部叠加另一张图片),但如果这不是您想要的效果,还有其他选择。


    方法 #1 - 手动渲染和合成图像


    最直接的方法是使用颜色图将数组渲染为 RGB,然后更改所需的像素。

    举个简单的例子:

    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.arange(100).reshape(10, 10)
    
    cmap = plt.cm.gray
    norm = plt.Normalize(data.min(), data.max())
    rgba = cmap(norm(data))
    
    # Set the diagonal to red...
    rgba[range(10), range(10), :3] = 1, 0, 0
    
    plt.imshow(rgba, interpolation='nearest')
    plt.show()
    

    此方法的一个缺点是您不能只调用fig.colorbar(im),因为您正在传递预渲染的 rgb 图像。因此,如果您需要颜色条,则必须使用代理艺术家。最简单的方法是使用imshow(data, visible=False) 添加一个额外的、不可见的(不是绘制的,而不是透明的)艺术家,然后将颜色图基于该艺术家。举个简单的例子:

    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.arange(100).reshape(10, 10)
    
    cmap = plt.cm.gray
    norm = plt.Normalize(data.min(), data.max())
    rgba = cmap(norm(data))
    
    # Set the diagonal to red
    rgba[range(10), range(10), :3] = 1, 0, 0
    
    fig, ax = plt.subplots()
    ax.imshow(rgba, interpolation='nearest')
    
    # Add the colorbar using a fake (not shown) image.
    im = ax.imshow(data, visible=False, cmap=cmap)
    fig.colorbar(im)
    
    plt.show()
    

    使用不可见的imshow 是为此目的制作代理艺术家的最简单方法,但如果速度是一个问题(或者如果它以某种方式触发了您提到的渲染错误),您也可以使用任何ScalarMappableScalarMappable 是一个抽象基类,通常仅用于继承自颜色条支持。因为我们不需要绘制任何东西,所以我们可以直接使用它。

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.cm import ScalarMappable
    
    data = np.arange(100).reshape(10, 10)
    
    cmap = plt.cm.gray
    norm = plt.Normalize(data.min(), data.max())
    rgba = cmap(norm(data))
    
    # Set the diagonal to red
    rgba[range(10), range(10), :3] = 1, 0, 0
    
    fig, ax = plt.subplots()
    ax.imshow(rgba, interpolation='nearest')
    
    # Add the colorbar using a ScalarMappable
    im = ScalarMappable(norm, cmap)
    im.set_array(data)
    fig.colorbar(im)
    
    plt.show()
    

    方法 #2 - 滥用 set_badset_overset_under


    颜色图的set_badset_overset_under 方法允许您标记NaN 或颜色图指定范围之外的像素。

    因此,另一种做你想做的事情的方法是将这些值设置为 NaN 并指定 NaN 颜色应该是什么(set_bad.. 默认情况下,它对大多数颜色图都是透明的。)。

    如果你有一个整数数组或者已经需要透明的 NaN 像素,你可以类似地滥用set_overset_under。在这种情况下,您需要在调用imshow 时手动指定vminvmax

    作为使用/滥用set_bad 的快速示例:

    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.arange(100).reshape(10, 10).astype(float)
    
    cmap = plt.cm.gray
    cmap.set_bad((1, 0, 0, 1))
    
    # Set the diagonal to NaN
    data[range(10), range(10)] = np.nan
    
    plt.imshow(data, cmap=cmap, interpolation='nearest')
    plt.show()
    

    与第一种方法相比,此方法的一个优点是绘制颜色条更容易一些。 (缺点是这种方法不够灵活。):

    import numpy as np
    import matplotlib.pyplot as plt
    
    data = np.arange(100).reshape(10, 10).astype(float)
    
    cmap = plt.cm.gray
    cmap.set_bad((1, 0, 0, 1))
    
    # Set the diagonal to NaN
    data[range(10), range(10)] = np.nan
    
    plt.imshow(data, cmap=cmap, interpolation='nearest')
    plt.colorbar()
    plt.show()
    

    【讨论】:

    • 谢谢你的建议,乔,它们看起来很合理。在这些情况下,这些像素会显示在颜色条上吗?我在那里不需要它们。
    • 在尝试了第一个选项后,我发现颜色条以及整个图像的颜色显然受到了极大的影响。可能会发生这种情况,因为在渲染为 rgb 后值的范围下降到仅 (0, 1),至少这是我在颜色条的标签上看到的,而且我之前的范围要高得多。因此,图像某些部分的颜色变得无法区分,尽管如果我只对原始数据调用 imshow(),它们显然会有所不同。
    • 并且使用set_badset_underset_over 不是一个很好的选择,因为我希望有可能用不同的颜色标记不同的像素,这将它们的数量限制为3 . 而且我可能还需要将vminvmax 用于其他目的。
    • 默认情况下,添加的颜色不会显示在颜色栏上。但是,为第一种方法制作颜色条需要几个额外的步骤,而第二种方法不需要做任何额外的事情。
    • 哦,如果我按照您对第一个选项的建议进行标准化,那么我会得到一个蓝色方块而不是我的图像,没有它它看起来更像它应该。
    【解决方案2】:

    为了补充 Joe 非常好的答案,当向 imshow 提供 rgba 值数组时,鼠标光标读出的 z 值现在显示 rgba 值的元组,而不是原来的 data 值。

    要解决这个问题,我们可以在原始图像上叠加一张透明图像。 然后我们可以同时使用这个透明图像来为图形附加一个颜色条:

    import numpy as np
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots()
    
    data = np.arange(100).reshape(10, 10)
    
    cmap = plt.cm.gray
    norm = plt.Normalize(data.min(), data.max())
    rgba = cmap(norm(data))
    
    # Set the diagonal to red...
    rgba[range(10), range(10), :3] = 1, 0, 0
    
    im = ax.imshow(rgba, interpolation='nearest')
    im2 = ax.imshow(data, cmap='gray')
    cbar = plt.colorbar(im2, ax=ax)
    im2.set_alpha(0.0)
    

    请注意,在这种情况下,在调用 im2.set_alpha(0.0) 之前创建颜色条很重要。 如果不是,颜色栏中的颜色也将是透明的(它们遵循图像的当前 alpha)。

    在无法遵守创建顺序的情况下,可以使用将颜色栏中颜色的不透明度设置回 1

    cbar.set_alpha(1.0)
    cbar.draw_all()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-26
      • 1970-01-01
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      相关资源
      最近更新 更多