Blit Behaviour in FuncAnimate -Want to keep previous data

693 views Asked by At

I'm trying to animate a figure using matplotlib->FuncAnimate function. However, I'm having trouble understanding how Blit works. With each frame, I want to draw only the new data point on top of the old one. It says that using Blit it should automatically update only the values that changed. Thus, if I turn it on (blit=True) the previous data points should remain in my figure. But this is not the case. The previous data get deleted and the figure gets redraw from scratch.

In the documentation, it says that I have to return "iterable_of_artists" and the algorithm will know which data has changed. I want to just pass the new data and just plot on top of the old one. By the way, what is an "iterable_of_artists", is that just a list of objects that can be drawn? if someone could point me out to the definition, I would appreciate it.

Anyway, I have worked several base examples that show the odd behavior. In the first example, I'm turning Blit=True and drawing only the new data using the animate function. This in theory should draw on top of the old ones, but is not the case, only the new data is drawn.

import time
import random
import numpy
import matplotlib 
import matplotlib.pyplot as pyplot
from matplotlib.animation import FuncAnimation

def livePlot():
     
    fig, ax = pyplot.subplots(1,1)
    ax = pyplot.axes(xlim=(0, 2), ylim=(0, 100))
    line, = ax.plot([], [], 'ro') #ax.plot will return a tupple

    def init():
        line.set_data(0, 50)
        return line,  #Return is not necessary when blit=False

    def animate(frame):
        x = frame
        y = random.randint(0, 100)
        line.set_data(x,y)
        return line, #Return is not necessary when blit=False
        
    animation = FuncAnimation(
        fig, animate, 
        init_func = init, 
        frames= [0.5, 1, 1.5, 2.0], 
        interval=1000, 
        repeat=False, 
        blit=True, # Turning on Blit
        cache_frame_data = True) 
    
    pyplot.show()

if __name__ == "__main__":
    livePlot()

I was able to achieve my goal by tricking the FuncAnimate method. I can use the ax and plot in each frame the new data. If I do that, the old data remains and only the new data is drawn. However, I can do that with Blit=True or Blit=False, it has no effect. So, I'm so confused on how Blit works and what would be the correct way to plot only the new data without having to create a list with all the data to plot. Passing a large list will create a large variable in memory if I have a long set of data points. Here is my workaround but I'm not sure if this is the correct way to do it or if there is a better ways of using Blit=True and just redraw the new data.

import time
import random
import numpy
import matplotlib 
import matplotlib.pyplot as pyplot
from matplotlib.animation import FuncAnimation

def livePlot():
     
    fig, ax = pyplot.subplots(1,1)
    ax = pyplot.axes(xlim=(0, 2), ylim=(0, 100))

    def init():
        ax.plot(0, 50, 'ro')
        return []

    def animate(frame):
        x = frame
        y = random.randint(0, 100)
        ax.plot(x, y, 'ro') # plotting directly on the axis. This keeps the old data
        return [] # fooling the blit algorithm with an empty stream
        
    animation = FuncAnimation(
        fig, animate, 
        init_func = init, 
        frames= [0.5, 1, 1.5, 2.0], 
        interval=1000, 
        repeat=False, 
        blit=True,
        cache_frame_data = True) 
        
    pyplot.show() 

if __name__ == "__main__":
    livePlot()
0

There are 0 answers