Как оживить упорядоченную по времени последовательность графиков matplotlib - программирование
Подтвердить что ты не робот

Как оживить упорядоченную по времени последовательность графиков matplotlib

Я хочу построить последовательность изображений .png в matplotlib. Цель состоит в том, чтобы быстро отобразить их, чтобы имитировать эффект фильма, но у меня есть дополнительные причины, чтобы избежать фактического создания файла .avi или сохранения фигур matplotlib, а затем просмотра их последовательно за пределами Python.

Я специально пытаюсь просматривать файлы изображений последовательно внутри цикла for на Python. Предполагая, что я правильно импортировал matplotlib, и у меня есть свои собственные функции new_image() и new_rect(), здесь приведен пример кода примера, который не работает из-за блокирующего эффекта вызова функции show() в GUI mainloop:

 for index in index_list:
     img = new_image(index)
     rect = new_rect(index)

     plt.imshow(img)
     plt.gca().add_patch(rect)
     plt.show()

     #I also tried pausing briefly and then closing, but this doesn't
     #get executed due to the GUI mainloop from show()
     time.sleep(0.25)
     plt.close()

Вышеприведенный код работает, чтобы показать только первое изображение, но затем программа просто зависает и ждет, когда я вручную закрою окно результатов. Как только я завершу его, программа затем просто зависает и не переделывает с новыми данными изображения. Что мне делать? Также обратите внимание, что я попытался заменить команду plt.show() командой plt.draw(), а затем добавить plt.show() вне цикла for. Это ничего не отображает и просто зависает.

4b9b3361

Ответ 1

Лучший способ, который я нашел для этого, - с командой pylab.ion() после импорта pylab.

Вот script, который использует show(), но который отображает разные графики каждый раз, когда вызывается pylab.draw(), и который оставляет окна графика бесконечно. Он использует простую логику ввода, чтобы решить, когда закрыть фигуры (поскольку использование show() означает, что pylab не будет обрабатывать клики на кнопке Windows x), но это должно быть просто добавить в ваш gui в качестве другой кнопки или в виде текстового поля.

import numpy as np
import pylab
pylab.ion()

def get_fig(fig_num, some_data, some_labels):

    fig = pylab.figure(fig_num,figsize=(8,8),frameon=False)
    ax = fig.add_subplot(111)
    ax.set_ylim([0.1,0.8]); ax.set_xlim([0.1, 0.8]);
    ax.set_title("Quarterly Stapler Thefts")
    ax.pie(some_data, labels=some_labels, autopct='%1.1f%%', shadow=True);
    return fig

my_labels = ("You", "Me", "Some guy", "Bob")

# To ensure first plot is always made.
do_plot = 1; num_plots = 0;

while do_plot:
    num_plots = num_plots + 1;
    data = np.random.rand(1,4).tolist()[0]

    fig = get_fig(num_plots,data,my_labels)
    fig.canvas.draw()
    pylab.draw()

    print "Close any of the previous plots? If yes, enter its number, otherwise enter 0..."
    close_plot = raw_input()

    if int(close_plot) > 0:
        pylab.close(int(close_plot))

    print "Create another random plot? 1 for yes; 0 for no."
    do_plot = raw_input();

    # Don't allow plots to go over 10.
    if num_plots > 10:
        do_plot = 0

pylab.show()

Модифицируя основную логику здесь, я могу закрыть окна и графически отображать изображения для имитации воспроизведения фильма, или я могу поддерживать контроль над тем, как он проходит через фильм.

Примечание.. Это работало для меня на разных платформах и, по-видимому, строго превосходит подход к управлению холстом окна выше и не требует опции "TkAgg".

Ответ 2

На основе http://matplotlib.sourceforge.net/examples/animation/simple_anim_tkagg.html:

import time
import numpy as np
import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)

def animate():
    tstart = time.time()                   # for profiling
    data=np.random.randn(10,10)
    im=plt.imshow(data)

    for i in np.arange(1,200):
        data=np.random.randn(10,10)
        im.set_data(data)
        fig.canvas.draw()                         # redraw the canvas
    print 'FPS:' , 200/(time.time()-tstart)

win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()

plt.imshow может принимать массив с плавающей точкой, массив uint8 или изображение PIL. Поэтому, если у вас есть каталог PNG файлов, вы можете открыть их как изображения PIL и оживить их следующим образом:

import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab
import matplotlib.pyplot as plt
import Image
import glob

fig = plt.figure()
ax = fig.add_subplot(111)

def animate():
    filenames=sorted(glob.glob('*.png'))
    im=plt.imshow(Image.open(filenames[0]))
    for filename in filenames[1:]:
        image=Image.open(filename)
        im.set_data(image)
        fig.canvas.draw() 

win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()

Ответ 3

Я реализовал удобный script, который вам подходит. Попробуйте здесь

Ниже приведен пример, показывающий изображения вместе с его ограничивающим прямоугольником:

import os
import glob
from scipy.misc import imread
from matplotlib.pyplot import Rectangle

video_dir = 'YOUR-VIDEO-DIRECTORY'

img_files = glob.glob(os.path.join(video_dir, '*.jpg'))
box_files = glob.glob(os.path.join(video_dir, '*.txt'))

def redraw_fn(f, axes):
    img = imread(img_files[f])
    box = bbread(box_files[f])  # Define your own bounding box reading utility
    x, y, w, h = box
    if not redraw_fn.initialized:
        im = axes.imshow(img, animated=True)
        bb = Rectangle((x, y), w, h,
                       fill=False,  # remove background
                       edgecolor="red")
        axes.add_patch(bb)
        redraw_fn.im = im
        redraw_fn.bb = bb
        redraw_fn.initialized = True
    else:
        redraw_fn.im.set_array(img)
        redraw_fn.bb.set_xy((x, y))
        redraw_fn.bb.set_width(w)
        redraw_fn.bb.set_height(h)
redraw_fn.initialized = False

videofig(len(img_files), redraw_fn, play_fps=30)