如何以交互方式更新matplotlib的imshow()窗口?

hyp*_*not 36 python numpy matplotlib spyder

我正在研究一些计算机视觉算法,我想展示一个numpy数组在每一步中如何变化.

现在有用的是,如果imshow( array )我的代码末尾有一个简单的,窗口会显示并显示最终的图像.

然而,我想要做的是更新并显示imshow窗口,因为图像在每次迭代中都会发生变化.

例如,我想做:

import numpy as np
import matplotlib.pyplot as plt
import time

array = np.zeros( (100, 100), np.uint8 )

for i in xrange( 0, 100 ):
    for j in xrange( 0, 50 ):
        array[j, i] = 1

        #_show_updated_window_briefly_
        plt.imshow( array )
        time.sleep(0.1)
Run Code Online (Sandbox Code Playgroud)

问题是这样,只有整个计算完成后,Matplotlib窗口才会被激活.

我已经尝试了原生matplotlib和pyplot,但结果是一样的.为了绘制命令我找到了一个.ion()开关,但在这里它似乎不起作用.

Q1.连续显示numpy数组更新的最佳方法是什么(实际上是uint8灰度图像)?

Q2.是否可以使用动画功能执行此操作,如动态图像示例中所示?我想在循环中调用一个函数,因此我不知道如何使用动画函数来实现它.

tia*_*ago 36

你不需要一直打电话imshow.使用对象的set_data方法要快得多:

myobj = imshow(first_image)
for pixel in pixels:
    addpixel(pixel)
    myobj.set_data(segmentedimg)
    draw()
Run Code Online (Sandbox Code Playgroud)

draw()应确保后端更新图像.

更新:您的问题已得到显着修改.在这种情况下,最好再问一个问题.这是处理第二个问题的方法:

Matplotlib的动画只处理一个增加的维度(时间),所以你的双循环不会.您需要将索引转换为单个索引.这是一个例子:

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

nx = 150
ny = 50

fig = plt.figure()
data = np.zeros((nx, ny))
im = plt.imshow(data, cmap='gist_gray_r', vmin=0, vmax=1)

def init():
    im.set_data(np.zeros((nx, ny)))

def animate(i):
    xi = i // ny
    yi = i % ny
    data[xi, yi] = 1
    im.set_data(data)
    return im

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=nx * ny,
                               interval=50)
Run Code Online (Sandbox Code Playgroud)

  • 只是试图修改你的例子,我认为`im = imshow(data,...)`应该读成`im = plt.imshow(data,...)`.另外,为了运行动画,你需要`plt.show()`.干杯 (2认同)

Cam*_*ion 9

我努力让它工作,因为很多帖子都在谈论这个问题,但似乎没有人关心提供一个有效的例子。然而,在这种情况下,原因是不同的:

  • 我不能使用 Tiago 或 Bily 的答案,因为它们与问题的范式不同。在这个问题中,刷新是由算法本身安排的,而对于 funcanimation 或 videofig,我们处于事件驱动的范式中。事件驱动编程对于现代用户界面编程是不可避免的,但是当您从复杂的算法开始时,可​​能很难将其转换为事件驱动方案 - 我也希望能够在经典的过程范式中做到这一点。
  • Bub Espinja 回复遇到了另一个问题:我没有在 jupyter notebooks 的上下文中尝试过,但是重复 imshow 是错误的,因为它每次都会重新创建新的数据结构,这会导致重要的内存泄漏并减慢整个显示过程。

Tiago 还提到了调用draw(),但没有指定从哪里获取它 - 顺便说一下,你不需要它。您真正需要调用的函数是flush_event(). 有时它可以在没有的情况下工作,但这是因为它是从其他地方触发的。你不能指望它。真正棘手的一点是,如果你调用imshow()一个空表,你需要指定 vmin 和 vmax 否则它将无法初始化它的颜色映射并且 set_data 也会失败。

这是一个有效的解决方案:

IMAGE_SIZE = 500
import numpy as np
import matplotlib.pyplot as plt


plt.ion()

fig1, ax1 = plt.subplots()
fig2, ax2 = plt.subplots()
fig3, ax3 = plt.subplots()

# this example doesn't work because array only contains zeroes
array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
axim1 = ax1.imshow(array)

# In order to solve this, one needs to set the color scale with vmin/vman
# I found this, thanks to @jettero's comment.
array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
axim2 = ax2.imshow(array, vmin=0, vmax=99)

# alternatively this process can be automated from the data
array[0, 0] = 99 # this value allow imshow to initialise it's color scale
axim3 = ax3.imshow(array)

del array

for _ in range(50):
    print(".", end="")
    matrix = np.random.randint(0, 100, size=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8)
    
    axim1.set_data(matrix)
    fig1.canvas.flush_events()
    
    axim2.set_data(matrix)
    fig1.canvas.flush_events()
    
    axim3.set_data(matrix)
    fig1.canvas.flush_events()
print()
Run Code Online (Sandbox Code Playgroud)

更新:我根据@Jettero 的评论添加了 vmin/vmax 解决方案(我一开始错过了)。


Bub*_*nja 7

如果您使用的是 Jupyter,也许这个答案会让您感兴趣。我在这个网站上读到的 emmbebed 功能clear_output可以解决这个问题:

%matplotlib inline
from matplotlib import pyplot as plt
from IPython.display import clear_output

plt.figure()
for i in range(len(list_of_frames)):
    plt.imshow(list_of_frames[i])
    plt.title('Frame %d' % i)
    plt.show()
    clear_output(wait=True)
Run Code Online (Sandbox Code Playgroud)

这种方法确实很慢,但它可以用于测试目的。