Search code examples
pythonmatplotlibnetworkxmatplotlib-animation

animate network graph


I would like to draw a dynamic network to show how it changes over time as new observations are added. I've found how to animate a network given two single states (here called s_pos, t_pos), but what i'm looking for goes a little further, as I would like to populate my network row by row. I imagine that I need to update G by iterating through my dataframe within the function anim(t); which I struggle to achieve.

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# data
df = pd.DataFrame({'Date': ["2022-11-28", "2022-11-29", "2022-11-30", "2022-12-01"],
                   'ID' : ['A', 'B', 'C', 'A'],
                   'Value': ['X', 'Y', 'X', 'Z']})

# network
G = nx.from_pandas_edgelist(df, source='ID', target='Value')

# two states as an example
s_pos = nx.spring_layout(G)
t_pos = nx.circular_layout(G)

fig = plt.figure(figsize=(8, 8))

# animation function with smooth interpolation between states
def anim(t):
    global s_pos
    global t_pos
    interpolation = {i: s_pos[i]*(1-t/299) + t_pos[i] * t/299  for i in list(t_pos.keys())}
    plt.clf()
    plt.cla()
    nx.draw(G, pos=interpolation,
            with_labels=True,
            node_size = 5000)

    

# run and save
ani = animation.FuncAnimation(fig, anim, repeat=False, frames=300, interval=20)
f = r'path\network.gif'
writergif = animation.PillowWriter(fps=30) 
ani.save(f, writer=writergif)

Solution

  • If I understand your question correctly that you would like to have your network progressively (row by row) appear in your animation, one way to do that would be to create a new network Gt in the anim function based on the rows of the dataframe up to t. At each step of the animation, you can also clear the plot with ax.clear() as in this post.

    See example below:

    import pandas as pd
    import networkx as nx
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    # data
    df = pd.DataFrame({'Date': ["2022-11-28", "2022-11-29", "2022-11-30", "2022-12-01"],
                       'ID' : ['A', 'B', 'C', 'A'],
                       'Value': ['X', 'Y', 'X', 'Z']})
    
    G = nx.from_pandas_edgelist(df, source='ID', target='Value') # create full graph G for reference
    s_pos = nx.spring_layout(G)
    t_pos = nx.circular_layout(G)
    
    fig,ax = plt.subplots(figsize=(8, 8))
    
    # animation function with smooth interpolation between states
    def anim(t):
        Gt=nx.from_pandas_edgelist(df.iloc[0:t], source='ID', target='Value') #create graph based n the row of the data frame up to t
        interpolation = {i: s_pos[i]*(1-t/299) + t_pos[i] * t/299  for i in list(t_pos.keys())}
        ax.clear() #clear axes
        nx.draw(Gt, pos=interpolation,with_labels=True,node_size = 500,ax=ax)
        ax.set_xlim([-1.5,1.5])
        ax.set_ylim([-1.5,1.5])
        
    
    # run and save
    ani = animation.FuncAnimation(fig, anim, repeat=False, frames=300, interval=100)
    plt.show()
    

    enter image description here