FuncAnimation не обновляется с пользовательским источником события в блокноте Jupyter - PullRequest
2 голосов
/ 09 января 2020

Я пытаюсь построить некоторые кривые по мере того, как они генерируются другим процессом (представьте, что тренировочные кривые для нейронной сети настраиваются, а не апостериори). В идеале я хотел бы, чтобы сюжет обновлялся довольно часто, поэтому важна скорость обновления.

У меня есть метод, работающий с ax.plot, но он не очень быстрый, что ограничивает мою способность часто вызывать его. Заглядывая в do c, я заинтересовался FuncAnimation специально для части blit (чтобы получить некоторую скорость). В коде FuncAnimation я заметил, что он наследуется от TimedAnimation, который может принимать параметр event_source. На самом деле я не вижу в коде ничего, что требовало бы, чтобы этот параметр event_source был основан на времени. Поэтому я решил создать свой собственный объект, похожий на «event_source». Каждый раз, когда мой основной код генерировал новые данные, он вызывал обновление моего EventSource, рисуя новый кадр в FuncAnimation.

Кажется, у меня есть некоторые логики c в приведенном ниже коде (он работает, и отпечатки отображаются во времени). Однако график не обновляется в реальном времени, он обновляется только один раз, после того, как основной вызов сделан (это делается в Jupyter Notebook с %matplotlib notebook). У вас есть идеи, почему сюжет не обновляется в прямом эфире?

from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np # really just here to fake data 
from time import sleep
from typing import List, Callable

# %matplotlib notebook

def my_large_function(callbacks: List[Callable]):
    """
    This is assumed to be the main calling function, like some neural network training curves. We cannot 
    assume that each iteration is taking the same time (some may be considerably longer than others)

    callbacks are the functions to be called when some criteria is met
    """
    for i in range(50):
        if i%5==0:
            for c in callbacks:
                c()
            print("Update")
        else:
            print("Not update")

        sleep(0.5)

class MyVeryOwnEvent:
    """
    This is an implementation of the event_source interface used by FuncAnimation. 
    The function are actually copied from TimerBase
    https://matplotlib.org/3.1.1/_modules/matplotlib/backend_bases.html#TimerBase
    """
    def __init__(self):
        self.callbacks = list()

    def add_callback(self, func, *args, **kwargs):
        self.callbacks.append((func, args, kwargs))
        return func

    def start(self):
        pass

    def stop(self):
        pass

    def _on_timer(self):
        print(f"In _on_timer {len(self.callbacks)}")
        for func, args, kwargs in self.callbacks:
            ret = func(*args, **kwargs)
            # docstring above explains why we use `if ret == 0` here,
            # instead of `if not ret`.
            # This will also catch `ret == False` as `False == 0`
            # but does not annoy the linters
            # https://docs.python.org/3/library/stdtypes.html#boolean-values
            if ret == 0:
                self.callbacks.remove((func, args, kwargs))

        if len(self.callbacks) == 0:
            self.stop()


# This is the simple_anim example 
# https://matplotlib.org/2.0.2/examples/animation/simple_anim.html
fig, ax = plt.subplots()

x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))


def animate(i):
    line.set_ydata(np.sin(x + i/10.0))  # update the data
    return line,


# Init only required for blitting to give a clean slate.
def init():
    line.set_ydata(np.ma.array(x, mask=True))
    return line,

# !!!!! tweaked here
event_source = MyVeryOwnEvent()

ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init,
                              interval=25, blit=True,
                             event_source= event_source) # !!! and here 
plt.show()


my_large_function([event_source._on_timer]) 
# The above line you can see the prints, but the plot does not seem to refresh
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...