0

After struggling for 2 days with the FuncAnimation of matplotlib, its documentation and its examples I am still quite clueless about how too solve the following:

What I am trying to do for the animation is to plot a graph, with nodes coloured with respect to a sum across some entries of a subset of a nested list. Then move the range of the subset one further (excluding the first list, appending another one at the end) and redraw the graph with nodes coloured according to the new subset.

Here is a minimal running example:

# graph
import networkx as nx

G=nx.Graph()
G.add_node(0)
G.add_node(1)

# list
from random import randint

l=[]

[l.append([randint(0,9),randint(0,9)]) for i in range(10)]

#functions for animation
def single_frame(dummy,interval,G,max_inv,ax):
    """plots a frame of the investment in given interval, 
    as interval a sniplet of self.l is expected"""
    import networkx as nx

    inv_into_node=[]
    for i in range(len(interval[0])): inv_into_node.append([])

    for i in interval:
        [inv_into_node[k].append(x) for k,x in enumerate(i)]

    sum_inv=[sum(x) for x in inv_into_node]
    col_list=[]
    for i in sum_inv:
        col_list.append([1-i/float(max_inv),1-i/float(max_inv),1])

    nx.draw_networkx(G,single_frame.pos,ax=ax,node_color=col_list,with_labels=True)


    ax.axis('off')
    return ax.get_children()

#this one produces the input list for the upper
def int_update():
        interval=int_update.i
        if int_update.counter:
            interval=interval[1:]
            interval.append(int_update.data[int_update.counter-1])
            int_update.i=interval
        int_update.counter+=1
        return interval

#animation
import matplotlib.animation as ani
import matplotlib.pyplot as plt

int_update.counter=0
int_update.i=[[9,9],[9,9]]
int_update.data=l

single_frame.pos=nx.graphviz_layout(G)
fig,ax=plt.subplots()

#import pdb;pdb.set_trace()
movie = ani.FuncAnimation(fig, single_frame,frames=9,fargs=(int_update(),G,20,ax))
movie.save('whatever.mp4')

Now there are several issues with this:

  1. the movie which is saved shows the nodes, but they have the color of the initial step and it is not changing

  2. It does not matter what i put in the return statement: ax, ax.get_children() or just nothing at all. I also tried to generate axes object inside of single_frame function and then return this as output, this led to a blank movie being returned.

So my first question is why isn't it working and how can I get it to work? And the second is what is FuncAnimation expecting as output of the function? I thought it should be taking whatever the function returns and putting it into fig, which is supplied to the FuncAnimation call. But that is obviously not the case...

Help is appreciated!

EDIT: thanks to the comments I solved the problem and just for the sake of completeness below the running version of the upper code

# graph
import networkx as nx

G=nx.Graph()
G.add_node(0)
G.add_node(1)

# list
from random import randint

l=[]

[l.append([randint(0,9),randint(0,9)]) for i in range(10)]

#functions for animation
def color_list(interval):
    """updating func"""



#             def rgb_to_hex(rgb):
#                 return '#%02x%02x%02x' % rgb


    #calculate color
    inv_into_node=[]
    for i in range(len(interval[0])): inv_into_node.append([])

    for i in interval:
        [inv_into_node[k].append(x) for k,x in enumerate(i)]

    sum_inv=[sum(x) for x in inv_into_node]
    col_list=[]
    for i in sum_inv:
        col_list.append((1-i/float(20),1-i/float(20),1))

    return col_list

def int_update():
    interval=int_update.i
    if int_update.counter:
        interval=interval[1:]
        interval.append(int_update.data[int_update.counter])
        int_update.i=interval
    int_update.counter+=1

    return interval

def update(n):

    col_list=color_list(int_update())
    nodes.set_facecolor(col_list)
    return nodes,

int_update.counter=0
int_update.i=[[0,0],[0,0]]
int_update.data=l

#animation
import matplotlib.animation as ani
import matplotlib.pyplot as plt

fig=plt.figure()
pos=nx.graphviz_layout(G)

nodes = nx.draw_networkx_nodes(G,pos,node_color=color_list([[0,0],[0,0]]))
edges = nx.draw_networkx_edges(G,pos)
labs=nx.draw_networkx_labels(G,pos)


#import pdb;pdb.set_trace()
movie = ani.FuncAnimation(fig, update,frames=len(l)-1)
movie.save('kex.mp4')
olga.bio
  • 281
  • 3
  • 15
  • `FuncAnimation` is for cases where you want update existing artists, the returned artists are those that have been changed, which is really only useful if you are showing it interactively and are using blitting. – tacaswell Nov 12 '14 at 13:14
  • See http://stackoverflow.com/questions/18229563/using-networkx-with-matplotlib-artistanimation/18232645#18232645 – tacaswell Nov 12 '14 at 13:15
  • ouch.... no idea how i missed this one. Guess the question is a duplicate; – olga.bio Nov 12 '14 at 13:24
  • The title is rather miss-leading. – tacaswell Nov 12 '14 at 13:37
  • Changed the title, hope it is better now. I still have one issue with the solution from the linked topic: there only one number defines the color (representing hue I guess), though I want to supply brightness as well. Using RGB color code gives me error: `Collections can only map rank 1 arrays` and hex code leads to `could not convert string to float: #010101`. Are there any ways around that? – olga.bio Nov 12 '14 at 14:42
  • Sorry, I meant the title on the _other_ question was misleading, not yours. Set the color directly, set_array is for doing color-mapping http://matplotlib.org/api/collections_api.html#matplotlib.collections.PatchCollection.set_color – tacaswell Nov 12 '14 at 15:36

0 Answers0