Как вернуть неизвестное количество объектов в функцию анимации Python - PullRequest
0 голосов
/ 28 ноября 2018

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

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

def plot_images(img1, img2, objects, ax):

    im1 = ax.imshow(img1)
    im2 = ax.imshow(img2 with transparency as an overlay)

    # plotting an ellipse for each object
    e = [None]*len(objects)
    for j in range(len(objects)):
        e[j] = Ellipse(xy=(objects['x'][j], objects['y'][j]),
                            width=6 * objects['a'][j],
                            height=6 * objects['b'][j],
                            angle=objects['theta'][j] * 180. / np.pi)
        e[j].set_facecolor('none')
        e[j].set_edgecolor('red')
        ax.add_artist(e[j])

    return im1, im2, e


def animate(j):

    # extracting objects
    im1, im2, objects = object_finder_function()

    imm1, imm2, e = plot_images(im1, im2, objects, axs)


    return imm1, imm2, e

fig, axs = plt.subplots()
ani = animation.FuncAnimation(fig, animate, frames=image_number, interval=50, blit=True)
plt.show()

Теперь, когда я пробую этот код, я получаю следующее сообщение об ошибке:

AttributeError: 'list' object has no attribute 'get_zorder'

Итак, я пробовал разные вещи, но в конечном итоге я обнаружил, что когдав качестве теста я вставляю функцию plot_images

return im1, im2, e[0], e[1], e[2]

, а также соответствующим образом изменяю функцию анимации, то есть

imm1, imm2, e0, e1, e2 = plot_images(im1, im2, objects, axs)

и

return imm1, imm2, e0, e1, e2

Донне появляется сообщение об ошибке, и эллипсы фактически отображаются в соответствующих кадрах, как я и предполагал.Теперь проблема в том, что для одного изображения я бы хотел построить много сотен эллипсов, поэтому мне пришлось бы вручную записать все это (т.е. e [0], e [1], e [2] -- e [k], и то же самое для живой функции), и это, кажется, не правильный путь.Другое дело, что, как я уже сказал, число эллипсов меняется для каждого изображения и ранее не было известно, поэтому я не могу соответствующим образом настроить функции.

Как я могу вернуть этот список эллипсов, чтобы анимация читала его так, как если бы я записал их все по отдельности, как это делается в рабочем примере?

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Ваш код немного не пифоничен, поэтому я немного его очистил для ясности.Ваш AttributeError имеет отношение к функции get_zorder, которая используется в matplotlib для выяснения того, как наложить слои на слои.С вещами, которые вы попробовали, я могу сказать, что вам просто нужно распаковать список list_of_ellipses в конце.

def plot_images(img1, img2, objects, ax):

    im1 = ax.imshow(img1)
    im2 = ax.imshow(img2 with transparency as an overlay)

    list_of_ellipses = []
    for j in range(len(objects)):
        my_ellipse = Ellipse(xy=(objects['x'][j], objects['y'][j]),
                        width=6 * objects['a'][j],
                        height=6 * objects['b'][j],
                        angle=objects['theta'][j] * 180. / np.pi)

        my_ellipse.set_facecolor('none')
        my_ellipse.set_edgecolor('red')
        ax.add_artist(e[j])
        list_of_ellipses.append(my_ellipse)
    return im1, im2, list_of_ellipses


def animate():
    im1, im2, objects = object_finder_function()
    imm1, imm2, list_of_ellipses = plot_images(im1, im2, objects, axs)
    return (imm1, imm2)+tuple(list_of_ellipses)

fig, axs = plt.subplots()
ani = animation.FuncAnimation(fig, animate, frames=image_number, interval=50, blit=True)
plt.show()
0 голосов
/ 28 ноября 2018

Предполагая, что вы используете matplotlib.animation , animate должен возвращать iterable, а вы возвращаете тот, который содержит три объекта.return imm1, imm2, e возвращает кортеж из трех экземпляров.Последний список.Вы должны иметь возможность вернуть list вместо tuple, изменив функцию animate на:

def animate(j):
    im1, im2, objects = object_finder_function()
    imm1, imm2, e = plot_images(im1, im2, objects, axs)

    return [imm1, imm2] + e

Тем не менее, я бы изменил plot_images, чтобы вместо нее возвращалось list.Может быть что-то вроде следующего:

def create_ellipse(objects, object_idx, artists):
    ellipse = Ellipse(
        xy=(objects['x'][object_idx], objects['y'][object_idx]),
        width=(6 * objects['a'][object_idx]),
        height=(6 * objects['b'][object_idx]),
        angle=(objects['theta'][object_idx] * 180.0 / np.pi))
    ellipse.set_facecolor('none')
    ellipse.set_edgecolor('red')
    artists.add_artists(ellipse)
    return ellipse

def plot_images(img1, img2, objects, ax):
    renderables = [ax.imshow(img1),
                   ax.imshow(img2 with transparency as an overlay)]
    renderables.extend(create_ellipse(objects, idx, ax)
                       for idx in range(len(objects)))
    return renderables
0 голосов
/ 28 ноября 2018

Звучит так, как будто вы хотите сгладить e.

Вы можете создать список с уже плоскими переменными и расширить его с помощью e:

    return tuple([im1, im2] + e)

или распакуйте e везде, где вы хотите его использовать.

...