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:
the movie which is saved shows the nodes, but they have the color of the initial step and it is not changing
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 ofsingle_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')