17

I would like to animate a graph that grows over time.

This is what I have so far:

fig = plt.figure()
ims = []
graph = nx.Graph()
for i in range(50):
    // Code to modify Graph
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    im = plt.draw()
    self.ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True,repeat_delay=1000)
ani.save('dynamic_images.mp4')
plt.show()

However, I get the following error message:

 File "main.py", line 204, in <module>
    repeat_delay=1000)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 356, in __init__
    TimedAnimation.__init__(self, fig, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 304, in __init__
    Animation.__init__(self, fig, event_source=event_source, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 53, in __init__
    self._init_draw()
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 363, in _init_draw
    artist.set_visible(False)
AttributeError: 'NoneType' object has no attribute 'set_visible'
nicomoto@nicomoto-VirtualBox:~/Desktop/CS8903-SpecialProblem/Code/

What I want is an animation, where you can see the graph growing. I can save the graph at each stage, and might be able to create an animation outside matplotlib, but is there any way of getting it work like this?

tiago
  • 22,602
  • 12
  • 72
  • 88
Nicomoto
  • 473
  • 2
  • 7
  • 15
  • What is your backend? I've encountered some animation problems with some backends. Can you run matplotlib's [basic_example.py](http://matplotlib.org/examples/animation/basic_example.html)? – tiago Nov 18 '12 at 04:41
  • Yes, that works perfectly for me. As for the backend, I am just on ubuntu, python 2.7, numpy, scipy, networkx and matplotlib...all installed within the last few days, so they are the latest version... Im basically a student, and am trying out a few expereriments, It would be really helpful to animate these graphs, so i can see how they grow! – Nicomoto Nov 18 '12 at 04:42
  • I'm not familiar with networkx. Perhaps the issue is that `ArtistAnimation` expects a matplotlib artist and not a nx object? – tiago Nov 18 '12 at 04:45
  • Updated my answer, hopefully it's more helpful. – brentlance Nov 20 '12 at 16:14

3 Answers3

17

An improved version of bretlance's. Hope it will be helpful. It will show animations but not picture after picture.

Still don't know how the owner of the question Animate drawing networkx edges made use of matplotlib's animation

#!/usr/bin/env python
import random
import pylab
from matplotlib.pyplot import pause
import networkx as nx
pylab.ion()

graph = nx.Graph()
node_number = 0
graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))

def get_fig():
    global node_number
    node_number += 1
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(graph.nodes()))
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))

num_plots = 50;
pylab.show()

for i in range(num_plots):

    get_fig()
    pylab.draw()
    pause(2)
Community
  • 1
  • 1
sadhen
  • 462
  • 4
  • 14
  • exactly what I was looking for. Nice transition between one drawing to another. Decreasing the pause gives a smooth animation. Thanks. :) – mythicalcoder Sep 20 '15 at 19:22
10

Upon review, that code wasn't nearly as relevant to this problem as I'd thought. However, I was able to use this SO answer and this SO answer to cobble together an answer for you. Here's code that will create a graph, add 50 random nodes and 50 random edges to it, and display an image of the graph after every node and edge is added. A few of the key changes from your code:

  1. This code is based on using pylab.ion() (see here for more info).
  2. Your code tries to use one figure and change the image within it. This code creates a new figure for each frame.
  3. This code doesn't write out to .mp4. If you really need to do that, I would suggest writing the figures out to .png file while rendering them, and converting to mp4 after the fact.
  4. Note that this code uses matplotlib.pyplot.pause() instead of time.sleep(). The figures won't render if you use time.sleep().

Good luck!

import random
import pylab
from matplotlib.pyplot import pause
import networkx as nx
pylab.ion()

graph = nx.Graph()
node_number = 0
graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))

def get_fig():
    global node_number
    node_number += 1
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(graph.nodes()))
    fig = pylab.figure()
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    return fig

num_plots = 50;
pylab.show()

for i in range(num_plots):

    fig = get_fig()
    fig.canvas.draw()
    pylab.draw()
    pause(2)
    pylab.close(fig)
Community
  • 1
  • 1
brentlance
  • 2,189
  • 1
  • 19
  • 25
  • Well sorry for the delay, either way, your suggestion is what got me thinking, here is what I did first, I plotted the graph and stored individual png's and then stiched them together outside... I also did an implementation with ion, the only problem is I cant save these as gif files, but it is rather cool as you can see changes in run time – Nicomoto Dec 01 '12 at 18:51
  • Thanks! I meant to try an alternative solution using matplotlib.animation.FuncAnimation (see http://matplotlib.org/api/animation_api.html for more info), but I just haven't had the time. – brentlance Dec 01 '12 at 19:13
  • @Skyler This code is quite old and libraries have evolved. A simple workaround is using `random.choice(list(graph.nodes()))` instead of `random.choice(graph.nodes())`. I just added a new answer with how the code could look like nowadays. – JohanC May 29 '20 at 22:00
6

As the existing answers are quite old, here is a version of how the code could look like with current versions of matplotlib and networkx.

import random
import networkx as nx
import matplotlib.pyplot as plt

graph = nx.Graph()
num_plots = 50
for node_number in range(num_plots):
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(list(graph.nodes())))
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    plt.pause(0.5)
JohanC
  • 71,591
  • 8
  • 33
  • 66