Search code examples
pythonnumpymatplotlibplotmatplotlib-animation

Animating a line plot in python with mathplotlib


So I'm trying to animate a line that gradually goes through plot points and I can't seem to figure out a way to do so. I've tried using FuncAnimation with no success and similar questions on Stackoverflow haven't helped me. Any suggestions? Here's my code:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import math
import csv
import sys
import numpy

towns=[['Orleans', '1.750115', '47.980822'],
 ['Bordeaux', '-0.644905', '44.896839'],
 ['Bayonne', '-1.380989', '43.470961'],
 ['Toulouse', '1.376579', '43.662010'],
 ['Marseille', '5.337151', '43.327276'],
 ['Nice', '7.265252', '43.745404'],
 ['Nantes', '-1.650154', '47.385427'],
 ['Rennes', '-1.430427', '48.197310'],
 ['Paris', '2.414787', '48.953260'],
 ['Lille', '3.090447', '50.612962'],
 ['Dijon', '5.013054', '47.370547'],
 ['Valence', '4.793327', '44.990153'],
 ['Aurillac', '2.447746', '44.966838'],
 ['Clermont-Ferrand', '3.002556', '45.846117'],
 ['Reims', '4.134148', '49.323421'],
 ['Strasbourg', '7.506950', '48.580332'],
 ['Limoges', '1.233757', '45.865246'],
 ['Troyes', '4.047255', '48.370925'],
 ['Le Havre', '0.103163', '49.532415'],
 ['Cherbourg', '-1.495348', '49.667704'],
 ['Brest', '-4.494615', '48.447500'],
 ['Niort', '-0.457140', '46.373545']]

order=[0,
 8,
 17,
 14,
 9,
 18,
 19,
 7,
 6,
 21,
 1,
 2,
 3,
 12,
 13,
 16,
 11,
 4,
 5,
 10,
 15,
 20,
 0]

fig=plt.figure()
fig.patch.set_facecolor('#ffffff')
fig.patch.set_alpha(0.7)
ax = plt.axes()
ax.set_facecolor('grey')
plt.axis('off')   



for i in range(len(order)):
    plt.plot(float(towns[order[i]][1]), float(towns[order[i]][2]), 'o', color='black')
    try:
        line = plt.Line2D((float(towns[order[i]][1]), float(towns[order[i+1]][1])), (float(towns[order[i]][2]), float(towns[order[i+1]][2])), lw=2)
        plt.gca().add_line(line)
    except IndexError:
        pass

towns[order[i]][1] are x values towns[order[i]][2] are y values

How can I make it look like this:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

x_data = []
y_data = []

fig, ax = plt.subplots()
ax.set_xlim(0, 105)
ax.set_ylim(0, 12)
line, = ax.plot(0, 0)

def animation_frame(i):
    x_data.append(i * 10)
    y_data.append(i)

    line.set_xdata(x_data)
    line.set_ydata(y_data)
    return line, 

animation = FuncAnimation(fig, func=animation_frame, frames=np.arange(0, 10, 0.1), interval=10)
plt.show()

Thank you


Solution

  • There are a few ways to do this, but one option is to expand the data using list comprehension and passed it to a function to show it in a controlled manner. With all the data ready (t, x, y, l) use the animate function to place all cities in the graph with ax.plot(x, y,...) and the cities names with ax.annotate. Then, pass to the Matplotlib function FuncAnimation a function (update in the code below) to call at each frame update to refresh the line segment being displayed.

    def animate(t, x, y, l):
        fig, ax = plt.subplots()
    
        # fit the labels inside the plot
        ax.set_xlim(min(x)-1, max(x)+3)
        ax.set_ylim(min(y)-1, max(y)+1)
    
        # place all cities on the graph
        cities, = ax.plot(x, y, marker = "o", color = "black", ls = "", markersize = 5)
        line_1, = ax.plot([], [], marker = "", color = "blue", ls ="-", lw = 2)
    
        LABEL_OFFSET = 1.003 # text label offset from marker
        for i in t:
            ax.annotate(f'{l[i]}', xy=(x[i]*LABEL_OFFSET,y[i]*LABEL_OFFSET))
    
        def update(i):
            line_1.set_data(x[:i], y[:i])
            return line_1
    
        anim = FuncAnimation(fig, update, frames=len(t)+1, interval=300, repeat=True)
        return anim
    
    t = range(len(order))
    x = [float(towns[order[i]][1]) for i in t]
    y = [float(towns[order[i]][2]) for i in t]
    l = [towns[order[i]][0] for i in t]
    
    cities_travel = animate(t, x, y, l)
    cities_travel.save("cities_travel.gif", writer = PillowWriter(fps = 2))
    

    cities_travel