Is there an easy way to animate a scrolling vertical line in matplotlib?

Viewed 2150

I would like to have what I would describe as a progress marker that seems pretty common in audio playback utilites. I would think in matplotlib this amounts to left/right animated plt.vlines. My code takes a 2 second array of data and creates an audio time series visualization. I'm struggling to create an animated vertical line that would move across the plot linearly for 2 seconds from 0 to 2.

import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt

font = {'weight': 'bold', 'size': 15}
plt.rc('font',**font)
sns.set_style("darkgrid")

testSeries = np.random.randint(-10, 20, 12000)
testSeries = testSeries - testSeries.mean()


fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(18,5),sharex=True)
sns.lineplot(range(0,len(testSeries)),testSeries,  color='#007294')
plt.xlim(0, len(testSeries))
axis.set_xlabel("Time (s)", fontsize='large', fontweight='bold')
axis.set_ylabel("Amplitude", fontsize='large', fontweight='bold')
axis.set_xticklabels(['0', '0.3', '0.6', '1', '1.3', '1.6', '2'],fontsize=15)
fig.tight_layout(rect=[0,0,.8,1]) 
plt.subplots_adjust(bottom=-0.01)
sns.despine()
plt.show()
2 Answers

axvline() simply returns a Line2D object, so you can update its position by using Line2D.set_xdata()

duration = 2 # in sec
refreshPeriod = 100 # in ms

fig,ax = plt.subplots()
vl = ax.axvline(0, ls='-', color='r', lw=1, zorder=10)
ax.set_xlim(0,duration)

def animate(i,vl,period):
    t = i*period / 1000
    vl.set_xdata([t,t])
    return vl,

ani = animation.FuncAnimation(fig, animate, frames=int(duration/(refreshPeriod/1000)), fargs=(vl,refreshPeriod), interval=refreshPeriod)
plt.show()

enter image description here

Note that the refresh rate is not guaranteed, it depends on the time it takes to redraw the figure. You may have to play around with the refreshPeriod.

Interactive mode of matplotlib might be useful to you. Here's how you could set it up:

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


testSeries = np.random.randint(-10, 20, 1000)
testSeries = testSeries - testSeries.mean()

x = range(0,len(testSeries))
fig,ax = plt.subplots(nrows=1,ncols=1)

line = ax.plot((x[0], x[0]), (0, testSeries[0]), 'k-',linewidth=4)

plt.xlim(0, len(testSeries))
plt.ion()   # set interactive mode
plt.show()

ax.set_xlabel("Time (s)", fontsize='large', fontweight='bold')
ax.set_ylabel("Amplitude", fontsize='large', fontweight='bold')
ax.set_xticklabels(['0', '0.3', '0.6', '1', '1.3', '1.6', '2'],fontsize=15)

for i,serie in enumerate(testSeries):
#comment the following three lines if you don't want to remove previous lines

    for l in line:
        l.remove()
        del l

    line = ax.plot((x[i], x[i]), (0, testSeries[i]), 'k-',linewidth=4)
    plt.gcf().canvas.draw()
    plt.pause(0.01)

Output (with previous lines kept):

example

Output (with previous lines deleted): example2

Related