Search code examples
pythonpython-3.xmatplotlibmatplotlib-animation

Plot signal data and skip frame with missing information using Matplotlib FuncAnimation


I am imitating getting stream of data where not each "message" line has the information I want to plot in live mode. Since each line will still be read, how can I skip one iteration (frame) and therefore skip plot update for 1 frame until next iteration that returns data comes along. My code has the following structure:

fig, ax = plt.subplots()
line, = ax.plot([], [])

lap_stat = []
file = open(path + 'file.log', 'r')

def update(lap_stat):

    #Plot lap number on x-axis, lap time on y-axis from lap_stat list that 
    #contains a tuple

    line.set_data(lap_stat[0], lap_stat[1])
    return line,
    
def data_gen():

    while True:
        line = file.readline()

        #Get data from line
        #Apply conditions, if line doesn't contain relevant information nothing happens
        #If data is present in line, save data as tuple [lap, lap_time] to lap_stat

        yield lap_stat

ani = FuncAnimation(fig, update, data_gen, interval=100, blit=True)
plt.show() 

Not each line has the relevant information, so if at current frame no information was appended the input list at update(lap_stat) function is empty, nothing gets plotted and the process dies. How can I modify my code to only plot information when it is returned? Plotting 0's also not an option, if I plot lap times from lap 0-10 and the then next data point is lap 15, I want the point from lap 10 to be connected to point 15. Hope it makes, thank you!


Solution

  • you made me sweat, I dont think this is the right way to approach the problem, but given your layout, here what I got working:

    input file file.log :

    1 10
    2 20
    3 10
    4 50
    5 80
    6 10
    7 70
    8
    9
    10 55
    11 40
    12 66
    

    my code:

    import matplotlib.animation as animation #to save animation
    
    from matplotlib.animation import FuncAnimation
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots()
    
    ax.set_xlim([0,12])
    ax.set_ylim([0,100])
    
    line, = ax.plot([],[], marker="o", markersize=10,markeredgecolor="red", markerfacecolor="green")
    
    path = ''
    
    file = open(path + 'file.log', 'r')
    
    
    def zero():
        line = ax.plot(0,0)
        return line 
    
    
    def update(lap_stat):
        #Plot lap number on x-axis, lap time on y-axis from lap_stat list that 
        #contains a tuple
        line.set_data(lap_stat[0], lap_stat[1])
        return line,
    
        
    def data_gen():
        line = 'pippo'
        
        while line:
            line = file.readline()
            print('line : ', line)
            
            try:
                    lap_stat = (int(line.split()[0]),int( line.split()[1]))
                    print('lap_stat : ', lap_stat)    
                #Get data from line
                #Apply conditions, if line doesn't contain relevant information nothing happens
                #If data is present in line, save data as tuple [lap, lap_time] to lap_stat
                    yield lap_stat
                    
            except:
                    continue
            
    ani = FuncAnimation(fig, update, data_gen(), init_func=zero ,  interval=2000, blit=True)
    # ani = FuncAnimation(fig, update, data_gen(), interval=1000) # need first frame, doesnt clear previous points
    # ani.save('animation.gif' , writer=animation.PillowWriter(fps=1)) #save animation
    
    plt.show() 
    
    
    

    output :

    enter image description here

    as per OP, modified code on same input to get animation below:

    import matplotlib.animation as animation #to save animation
    
    from matplotlib.animation import FuncAnimation
    import matplotlib.pyplot as plt
    
    
    
    fig, ax = plt.subplots()
    
    ax.set_xlim([0,1])
    ax.set_ylim([0,1])
    
    line, = ax.plot([],[], marker="o", markersize=10,markeredgecolor="red", markerfacecolor="green")
    
    path = ''
    
    file = open(path + 'file.log', 'r')
    
    
    def zero():
        line = ax.plot(0,0)
        return line 
    
    x_points = [0]
    y_points = [0]
    def update(lap_stat):
        #Plot lap number on x-axis, lap time on y-axis from lap_stat list that 
        #contains a tuple
        
        x_points.append(lap_stat[0])
        
        y_points.append(lap_stat[1])
        
        ax.set_xlim([0,max(x_points)])
        ax.set_ylim([0,max(y_points)])
        
        # line.set_data(lap_stat[0], lap_stat[1])
        
        line.set_data(x_points, y_points)
        
        print(x_points, y_points)
        
        return line,
    
        
    def data_gen():
        line = 'pippo'
        
        while line:
            line = file.readline()
            print('line : ', line)
            
            try:
                    lap_stat = (int(line.split()[0]),int( line.split()[1]))
                    print('lap_stat : ', lap_stat)    
                #Get data from line
                #Apply conditions, if line doesn't contain relevant information nothing happens
                #If data is present in line, save data as tuple [lap, lap_time] to lap_stat
                    yield lap_stat
                    
            except:
                    continue
            
    # ani = FuncAnimation(fig, update, data_gen(), init_func=zero ,  interval=2000, blit=True)
    
    ani = FuncAnimation(fig, update, data_gen(), init_func=zero ,  interval=2000, blit=False, repeat = False)
    
    # ani = FuncAnimation(fig, update, data_gen(), interval=1000) # need first frame, doesnt clear previous points
    # ani.save('animation_line.gif' , writer=animation.PillowWriter(fps=1)) #save animation
    
    plt.show() 
    
    print(x_points, y_points)
    
    

    output:

    enter image description here