Ошибка при попытке анимировать несколько наборов данных с использованием методов класса для запуска matplotlib - PullRequest
0 голосов
/ 21 октября 2019

Я написал код для симуляции n-body, который хотел бы оживить. Есть много вопросов о том, как использовать matplotlib для создания анимации;некоторые из них ( как этот и этот ) упоминают более сложный случай одновременной анимации нескольких наборов данных. Я пытаюсь включить вещи из этих ответов в методы класса, чтобы я мог создать статическое изображение или анимацию. Я сделал статичное изображение, но не могу понять свою ошибку при попытке создать анимацию. Мой вопрос касается только аспекта анимации;предыдущие позиции каждого тела хранятся в виде массивов. Как пример:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation

class Body():

    def __init__(self, identifier, facecolor, position, previous_positions):
        """ """
        self.identifier = identifier
        self.facecolor = facecolor
        self.position = position
        self.previous_positions = previous_positions

    def __str__(self):
        res = ''
        keys = ('identifier', 'facecolor', 'position', 'previous_positions')
        values = (self.identifier, self.facecolor, self.position, self.previous_positions)
        for key, value in zip(keys, values):
            res += '\n .. {}:\n{}\n'.format(key, value)
        return res


nmoments, ndim = 10, 2
ts = np.arange(nmoments)
apos = np.array([np.cos(ts), np.sin(ts)]).T
bpos = np.array([-np.sin(ts), np.cos(ts)]).T
cpos = np.array([np.zeros(ts.shape), np.cos(np.pi * ts)]).T
A = Body('A', 'red', position=apos[-1], previous_positions=apos)
B = Body('B', 'blue', position=bpos[-1], previous_positions=bpos)
C = Body('C', 'orange', position=cpos[-1], previous_positions=cpos)
bodies = (A, B, C)
# for body in bodies:
#     print(body)

Теперь у нас есть 3 набора данных (A, B и C), каждый из которых имеет свои собственные позиции в зависимости от времени ts. Так как мой код, содержащий симуляцию nbody, имеет class NBody, я хотел бы дать ему метод, который я мог бы вызвать как:

NB = NBody(bodies, ...) # initialize instance of class
NB.simulate(...) # update positions as time updates
NB.animate(...) # use updated positions to create animation

Я могу сделать это, если у меня есть класс Visualizer, чья единственнаяцелью является создание изображений и анимации;затем разбейте его на подклассы, как показано ниже:

class NBody(Visualizer):

    super().__init__(...)

Моя попытка на основе SO вопросов и ответов создать анимацию с использованием этого подхода приведена ниже:

class Visualizer():

    def __init__(self, bodies, nmoments):
        """ """
        self.bodies = bodies
        self.ndim = bodies[0].position.shape[0]
        self.nmoments = nmoments

    def get_figure_and_axes(self, **kwargs):
        """ """
        if self.ndim == 2:
            fig, ax = plt.subplots(**kwargs)
        elif self.ndim == 3:
            fig = plt.figure(**kwargs)
            ax = fig.add_subplot(1, 1, 1, projection='3d')
        else:
            raise ValueError("invalid ndim: {}; ndim = 2 or 3".format(self.ndim))
        return fig, ax

    def initialize_animation_axes(self, ax):
        """ """
        lines = [ax.plot(*ibody.position, color=ibody.facecolor)[0] for ibody in self.bodies]
        ax.set_xlim([-2, 2])
        ax.set_ylim([-2, 2])
        self.lines = lines

    def animate(self, ith_moment):
        """ """
        for ith_body, ibody in enumerate(self.bodies):
            coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
            self.lines[ith_body].set_data(*coords)
        return self.lines


V = Visualizer(bodies, nmoments)
fig, ax = V.get_figure_and_axes()
V.initialize_animation_axes(ax)
anim = matplotlib.animation.FuncAnimation(fig, V.animate)
plt.show()
plt.close(fig)

Фигура изначально выглядит пустой,и затем для каждого кадра возникает новая ошибка, пока анимация не будет завершена / закрыта. Ошибка обратной трассировки показана ниже для первых нескольких итераций;Главное, на что нужно обратить внимание: IndexError: index ii is out of bounds for axis 0 with size 10, где ii начинается с 10.

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 10 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 11 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 12 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 13 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 14 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 15 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 16 is out of bounds for axis 0 with size 10
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1236, in _draw_next_frame
    self._draw_frame(framedata)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/matplotlib/animation.py", line 1772, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "soq1.py", line 66, in animate
    coords = ibody.previous_positions[ith_moment] # [ith_moment, :]
IndexError: index 17 is out of bounds for axis 0 with size 10

Я не до конца понимаю, что делает matplotlib в фоновом режиме (несмотря на просмотр их документов). Что я здесь не так делаю?

...