Matplotlib FuncAnimation: How to gray out previous trajectory of in 3D pixel tracking?

We can keep track of the plotted lines and just change their color.

import matplotlib.pyplot as plt
import matplotlib.animation as anim
import numpy as np

fig = plt.figure()
ax = fig.gca(projection="3d")

#random data
np.random.seed(12345)
d3d = np.random.random((3, 12))

line_list = []
#number of line segments to retain in blue before greying them out
line_delay = 4    

def init():
    ax.clear()
    #you can omit the fixed scales, then they will be automatically updated
    ax.set_xlim3d(0, 1)
    ax.set_ylim3d(0, 1)
    ax.set_zlim3d(0, 1)        

def update(i):
    #initializing the plot, emptying the line list 
    if not i:
        init()
        line_list[:] = []
    
    #set line color to grey if delay number is exceeded
    if len(line_list)>=line_delay:
        line_list[-line_delay].set_color("grey")
    
    #plot new line segment
    newsegm, = ax.plot(*d3d[:, i:i+2], "blue") 
    line_list.append(newsegm)

ani = anim.FuncAnimation(fig, update, init_func=init, frames = np.arange(d3d.shape[1]), interval = 300, repeat=True)
plt.show()

enter image description here

This approach has the advantage that we can easily adapt it for better representation of the data – for instance, if we have a lot of data, we can make them fade and remove all invisible lines:

import matplotlib.pyplot as plt
import matplotlib.animation as anim
import numpy as np

fig = plt.figure()
ax = fig.gca(projection="3d")

#random data
np.random.seed(12345)
d3d = np.random.random((3, 40))

#defines the number of disappearing line segments
max_length = 20

line_list = []

def init():
    ax.clear()
    ax.set_xlim3d(0, 1)
    ax.set_ylim3d(0, 1)
    ax.set_zlim3d(0, 1)

def update(i): 
    if not i:
        init()
        line_list[:] = []   
             
    else:
        #if not the first line segment, change color to grey, 
        line_list[-1].set_color("grey")
        #then reduce gradually the alpha value for all line segments
        diff2max = max(0, max_length-len(line_list))
        [x.set_alpha((j+diff2max)/max_length) for j, x in enumerate(line_list)]
    
    #delete line segments that we don't see anymore to declutter the space
    if len(line_list)>max_length:
        del_line = line_list.pop(0)
        del_line.remove()    
        
    #plot new segment and append it to the list
    newsegm, = ax.plot(*d3d[:, i:i+2], "blue") 
    line_list.append(newsegm)

ani = anim.FuncAnimation(fig, update, init_func=init, frames = np.arange(d3d.shape[1]), interval = 300, repeat=True)
plt.show()

Sample output:
enter image description here

Leave a Comment