Description
Summary
TimedAnimation
resets the event timer at the end of its _step()
method:
matplotlib/lib/matplotlib/animation.py
Line 1446 in f7b3def
As far as I can tell, this is by design. The original commit included this comment:
matplotlib/lib/matplotlib/animation.py
Lines 314 to 318 in 70e401f
To me, this was suprising and it took me a while to get to the bottom of it. From the documentation I took that the event loop calls the animation target at exactly the interval
specified. However, the current implementation means that it actually calls it at interval + time_in_callback
. In case the callback does some heavy lifting, like processing data or communicating with an instrument, this can add significant overhead to the real interval between frames.
A MWE highlighting the effects of resetting the interval:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
def update(frame):
if len(frame) < 2:
return []
diff = np.diff(frame)
avg.set_text(avg_txt.format(diff.mean()*1e3))
cur.set_text(cur_txt.format(diff[-1]*1e3))
return [avg, cur]
def frame():
times = deque(maxlen=100)
while True:
time.sleep(0.1)
times.append(time.perf_counter())
yield times
fig, ax = plt.subplots(figsize=(1,1))
ax.axis('off')
avg_txt = 'avg: {:.3g} ms'
cur_txt = 'cur: {:.3g} ms'
avg = ax.text(0.5, 0.75, avg_txt.format(0), va='center', ha='center')
cur = ax.text(0.5, 0.25, cur_txt.format(0), va='center', ha='center')
anim = animation.FuncAnimation(fig, update, frame, repeat=False,
cache_frame_data=False, interval=200)
With the current behavior, this results in an effective interval of 300 ms. Commenting out the line resetting the interval results in the effective interval I would expect from interval=200
, 200 ms.
Proposed fix
There might be reasonable usecases for resetting the interval, but I cannot see any right now. Hence, I would propose to leave the timer running uninterrupted, i.e., dropping
matplotlib/lib/matplotlib/animation.py
Line 1446 in f7b3def