【问题标题】:Matplotlib: Plot matrix in a loop while updating colorbar value rangeMatplotlib:在更新颜色条值范围时循环绘制矩阵
【发布时间】:2020-03-11 17:03:29
【问题描述】:

我想在循环中使用matplotlib 逐平面绘制 3D 张量平面。 然而,在这个例子中,matplotlib 继续在图中添加颜色条:

data = np.random.rand(100,100,10)
for i in range(10):
    plt.imshow(np.squeeze(data[:, :, i]))
    plt.colorbar()
    plt.pause(2)
    print(i)

警告:对于这个简单的问题,我已经看到了一些复杂的答案,但没有奏效。这个问题可能听起来很简单,但我认为可能有一个简单(简短)的解决方案。

【问题讨论】:

  • 首先您需要确保对所有图像使用相同的标准化,否则颜色条会出错。然后您可以决定只添加一次颜色条。最后考虑更新单个图像,而不是在另一个之上绘制 10 个图像。我应该认为这个问题的现有解决方案可以正常工作,但如果您想指出任何不可行的解决方案,我很乐意看看它们。
  • 我宁愿让颜色条适应每个新图像,因为每个 2D 地图都可能有不同的范围。
  • 在这种情况下,只需使用the official example?
  • 对我来说重要的部分是彩条。它应该即时适应每个新的 2D 地图的数据范围。无论如何,我已经放弃了寻找“短解决方案”。我在 Matlab 中使用了这个功能一百万次,并认为使用 matplotlib 会类似

标签: python matplotlib


【解决方案1】:

所以这里有一个解决方案。不幸的是,它一点也不短。如果有人知道如何使这变得不那么复杂,请随时发布另一个答案。

这是this answer的略微修改版

import matplotlib.pyplot as plt
import numpy as np


def visualize_tensor(data, delay=0.5):
    """ data must be 3 dimensional array and
    have format:
    [height x width x channels]"""
    assert(np.ndim(data) == 3)

    # Get number of channels from last dimension
    num_channels = np.shape(data)[-1]

    # Plot data of first channel
    fig = plt.figure()
    ax = fig.add_subplot(111)
    data_first_channel = data[:, :, 0]
    plot = ax.imshow(data_first_channel)

    # Create colorbar
    cbar = plt.colorbar(plot)
    plt.show(block=False)

    # Iterate over all channels
    for i in range(num_channels):
        print(f"channel = {i}")
        data_nth_channel = np.squeeze(data[:, :, i])
        plot.set_data(data_nth_channel)
        plot.autoscale()
        vmin = np.min(data_nth_channel.view())  # get minimum of nth channel
        vmax = np.max(data_nth_channel.view())  # get maximum of nth channel
        cbar.set_clim(vmin=vmin, vmax=vmax)     
        cbar_ticks = np.linspace(vmin, vmax, num=11, endpoint=True)
        cbar.set_ticks(cbar_ticks)
        cbar.draw_all()
        plt.draw()
        plt.pause(delay)

示例执行:

data = np.random.rand(20,20,10)
visualize_tensor(data)

更新: 使用plot.autoscale() 强制颜色条动态适应,参见this answer

【讨论】:

  • 酷答案@mcExchange!你强迫我在文档中挖掘一点,也检查我的 hacky 方式 ;-)!
【解决方案2】:

简单的解决方案

在每次循环运行中清除数字。

import numpy as np
import matplotlib.pyplot as plt

data = np.random.rand(100,100,10) * np.linspace(1,7,10)

fig = plt.figure()

for i in range(10):
    plt.clf()
    plt.imshow(np.squeeze(data[:, :, i]))
    plt.colorbar()
    plt.pause(2)

plt.show()

高效的解决方案

使用相同的图像并仅更新数据。还可以使用FuncAnimation 而不是循环来运行 GUI 事件循环中的所有内容。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

data = np.random.rand(100,100,10) * np.linspace(1,7,10)

fig, ax = plt.subplots()
im = ax.imshow(np.squeeze(data[:, :, 0]))
cbar = fig.colorbar(im, ax=ax)

def update(i):
    im.set_data(data[:, :, i])
    im.autoscale()

ani = FuncAnimation(fig, update, frames=data.shape[2], interval=2000)
plt.show()

【讨论】:

    【解决方案3】:

    这个问题引起了我的兴趣,因为在matplotlib 进行黑客攻击是我的爱好。在@mcExchange 提出的解决方案旁边,可以使用这个

    from matplotlib.pyplot import subplots 
    import numpy as np
    
    %matplotlib notebook
    d = np.random.rand(10, 10)
    fig, ax = subplots(figsize = (2,2))
    # create mappable
    h = ax.imshow(d)
    # create colorbar
    cb = fig.colorbar(h)
    # show non-blocking
    fig.show(0)
    for i in range(100):
        # generate new data
        h.set_data(np.random.randn(*d.shape) + 1)
        h.autoscale()
        # flush events update time 
        ax.set_title(f't = {i}')
        fig.canvas.draw(); fig.canvas.flush_events(); 
    

    我是如何得到这个解决方案的?

    文档声明colorbar.update_normal 仅在可映射对象上的规范与以前不同时才会更新。设置数据不会改变这一点。因此,必须调用手动函数来注册此更新。 在幕后发生了以下事情:

        # rescale data for cb trigger
        h.norm.autoscale(h._A) #h._A is the representation of the data
        # update mappable
        h.colorbar.update_normal(h.colorbar.mappable)
    

    【讨论】:

    • 也可以。虽然我觉得阅读起来有点困难。 mappable 是什么data 的同义词? h._Ah.norm 在我看来也有点神秘。
    • 查看编辑。神秘变量是数据的私有表示。 Norm 是将数据标准化以适应 clim 范围的函数。
    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    相关资源
    最近更新 更多