Animate graph diffusion with NetworkX

2020-04-16 19:56发布

问题:

I want to animate a process on a graph (preferably in NetworkX). I have already seen this question. However, when I run the code given in the solution, I just see the final output. Also, that doesn't save the animation in some usable format.

Suppose we have the following graph:

import networkx as nx

g = nx.Graph()
g.add_edges_from([(1, 2), (2, 3), (1, 3), (1, 4), (3, 4), (4, 5), (5, 9), (4, 9)])

Also, we have an initial set of nodes which we call active:

active = {1, 3}

Intuitively, what I want to do is to animate how each active node will cause other nodes in the graph to become active in time. So, if we assume a model where each node gets active if at least two of its neighbors become active, in the second iteration the set of active nodes will be:

active = {1, 3, 2, 4}

In the next iteration, the set of active nodes will be:

active = {1, 3, 2, 4, 5}.

In the final iteration, all the nodes in the graph will become active:

active = {1, 3, 2, 4, 5, 9}

This process, which is called the tipping process, is an example of information diffusion in networks. You can see a very simple implementation of the algorithm below.

def tipping(graph, seed_set, thr=2):
    active = seed_set
    has_changed = False
    for n in filter(lambda n: n not in active, graph.nodes()):
        if len(filter(lambda nei: nei in active, graph.neighbors(n))) >= thr:
            active.add(n)
            has_changed = True
    if has_changed:
        return tipping(graph, active, thr) | active
    return active

I want to know if there is any way that I can visualize this process. I know I can draw the network with the nx.draw() function in networkX. However, I haven't seen any function which produces animations or any other useful output for this scenario.

One possible solution might be to plot the graph in each step of the process with different node colors, save each of them and make a gif animation with all the saved pictures.

How can I animate the diffusion using Networkx? Preferably the animation would run in an IPython notebook.

回答1:

Here is a simplified, stripped down animation example that should be useful to anyone looking for networkx animations. And it actually works if you run it.

import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import animation


def simple_update(num, n, layout, G, ax):
    ax.clear()

    # Draw the graph with random node colors
    random_colors = np.random.randint(2, size=n)
    nx.draw(G, pos=layout, node_color=random_colors, ax=ax)

    # Set the title
    ax.set_title("Frame {}".format(num))


def simple_animation():

    # Build plot
    fig, ax = plt.subplots(figsize=(6,4))

    # Create a graph and layout
    n = 30 # Number of nodes
    m = 70 # Number of edges
    G = nx.gnm_random_graph(n, m)
    layout = nx.spring_layout(G)

    ani = animation.FuncAnimation(fig, simple_update, frames=10, fargs=(n, layout, G, ax))
    ani.save('animation_1.gif', writer='imagemagick')

    plt.show()

simple_animation()

You need one function, simple_animation to setup and run the animation, and one function, simple_update to update the animation. fargs lets you pass in arguments to the simple_update function.

This animation just sets random colors, you should be able to adapt it to any other purpose.



回答2:

I implemented a animated Networkx heat diffusion using matplotlib animation framework. If you install the JSAnimation plugin for IPython notebooks, you can even visualize the animation in your notebook!

The algorithm should be something like this:

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

# Optionnal if you want to animate in your notebook
from JSAnimation import IPython_display

def update_func(step, data, nodes):
    # the step parameter is mandatory for matplotlib
    # Set new value for figure data
    # update node color here
    new_data = data + 1
    nodes.set_array(new_data)
    return nodes

def diffuse_anim(inputs, G, data, nb_frames=50):
    fig = plt.figure()
    nodes = nx.draw_networkx_nodes(G, pos, node_size=30, node_color='b')
    return animation.FuncAnimation(fig, update_func, frames=xrange(nb_frames), fargs=(data, nodes))

In my application you could see heat diffusion propagating from different sources in a nice animation in an IPython notebook.