In Part 2 we introduced the 'language' in which a system must be described in order for it to be interpretable by cadCAD and some of the basic concepts of the library:
In the previous example, we observed how two robotic arms acting in parallel could result in counterintuitive system level behavior despite the simplicity of the individual robotic arm policies. In this notebook we'll introduce the concept of networks. This done by extending from two boxes of marbles to n boxes which are the nodes in our network. Furthermore, there are are going to be arms between some of the boxes but not others forming a network where the arms are the edges.
The robot and the marbles
balls
) with an integer number of marbles in each; a network of robotic arms is capable of taking a marble from their one of their boxes and dropping it into the other one.from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from cadCAD.configuration import Configuration
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline
T = 50 #iterations in our simulation
n=3 #number of boxes in our network
m= 2 #for barabasi graph type number of edges is (n-2)*m
G = nx.barabasi_albert_graph(n, m)
k = len(G.edges)
balls = np.zeros(n,)
for node in G.nodes:
rv = np.random.randint(1,25)
G.nodes[node]['initial_balls'] = rv
balls[node] = rv
G.nodes[node]['balls'] = rv
scale=100
nx.draw_kamada_kawai(G, node_size=balls*scale,labels=nx.get_node_attributes(G,'initial_balls'))
/anaconda3/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number) if cb.is_numlike(alpha):
initial_conditions = {'balls':balls, 'network':G}
#input the deltas along the edges and update the boxes
#mechanism: edge by node dimensional operator
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# We make the state update functions less "intelligent",
# ie. they simply add the number of marbles specified in _input
# (which, per the policy function definition, may be negative)
def update_balls(params, step, sL, s, _input):
delta_balls = _input['delta']
new_balls = s['balls']
graph = s['network']
for e in graph.edges:
move_ball = delta_balls[e]
src = e[0]
dst = e[1]
if (new_balls[src] >= move_ball) and (new_balls[dst] >= -move_ball):
new_balls[src] = new_balls[src]-move_ball
new_balls[dst] = new_balls[dst]+move_ball
key = 'balls'
value = new_balls
return (key, value)
def update_network(params, step, sL, s, _input):
new_nodes = _input['nodes']
new_edges = _input['edges']
new_balls = _input['quantity']
graph = s['network']
for node in new_nodes:
graph.add_node(node)
graph.nodes[node]['initial_balls'] = new_balls[node]
graph.nodes[node]['balls'] = new_balls[node]
graph.nodes[node]['strat'] = _input['node_strats'][node]
for edge in new_edges:
graph.add_edge(edge[0], edge[1])
graph.edges[edge]['strat'] = _input['edge_strats'][edge]
key = 'network'
value = graph
return (key, value)
def update_network_balls(params, step, sL, s, _input):
new_nodes = _input['nodes']
new_balls = _input['quantity']
balls = np.zeros(len(s['balls'])+len(new_nodes))
for node in s['network'].nodes:
balls[node] = s['balls'][node]
for node in new_nodes:
balls[node] = new_balls[node]
key = 'balls'
value = balls
return (key, value)
def update_balls_in_network(params, step, sL, s, _input):
graph = s['network']
for node in graph.nodes:
graph.nodes[node]['balls'] = s['balls'][node]
key = 'network'
value = graph
return (key, value)
# this time lets make three kinds of robots
def greedy_robot(src_balls, dst_balls):
#robot wishes to accumlate balls at its source
#takes half of its neighbors balls
if src_balls < dst_balls:
delta = np.floor(dst_balls/2)
else:
delta = 0
return delta
def fair_robot(src_balls, dst_balls):
#robot follows the simple balancing rule
delta = np.sign(src_balls-dst_balls)
return delta
def giving_robot(src_balls, dst_balls):
#robot wishes to gice away balls one at a time
if src_balls > 0:
delta = -1
else:
delta = 0
return delta
#in the previous version the robots were assigned to the edges
#moving towards an agent based model formulation we assign the stratgies
#instead to the nodes
robot_strategies = [greedy_robot,fair_robot, giving_robot]
for node in G.nodes:
nstrats = len(robot_strategies)
rv = np.random.randint(0,nstrats)
G.nodes[node]['strat'] = robot_strategies[rv]
for e in G.edges:
owner_node = e[0]
G.edges[e]['strat'] = G.nodes[owner_node]['strat']
#Policy: node by edge dimensional operator
#input the states of the boxes output the deltas along the edges
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# We specify the robotic networks logic in a Policy Function
# unlike previous examples our policy controls a vector valued action, defined over the edges of our network
def robotic_network(params, step, sL, s):
graph = s['network']
delta_balls = {}
for e in graph.edges:
src = e[0]
src_balls = s['balls'][src]
dst = e[1]
dst_balls = s['balls'][dst]
#transfer balls according to specific robot strat
strat = graph.edges[e]['strat']
delta_balls[e] = strat(src_balls,dst_balls)
return_dict = {'nodes': [],'edges': {}, 'quantity': {}, 'node_strats':{},'edge_strats':{},'delta': delta_balls}
return(return_dict)
def agent_arrival(params, step, sL, s):
node= len(s['network'].nodes)
node_list = [e[1] for e in s['network'].edges]
#choose a m random edges without replacement
m=2
new = set(np.random.choice(node_list,m))
#new = [0, 1]#tester
nodes = [node]
edges = [(node,new_node) for new_node in new]
initial_balls = {node:np.random.randint(1,25) }
rv = np.random.randint(0,nstrats)
node_strat = {node: robot_strategies[rv]}
edge_strats = {e: robot_strategies[rv] for e in edges}
return_dict = {'nodes': nodes,
'edges': edges,
'quantity':initial_balls,
'node_strats':node_strat,
'edge_strats':edge_strats,
'delta': np.zeros(node+1)
}
return(return_dict)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# In the Partial State Update Blocks, the user specifies if state update functions will be run in series or in parallel
partial_state_update_blocks = [
{
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
'p1': robotic_network
},
'variables': { # The following state variables will be updated simultaneously
'balls': update_balls
}
},
{
'policies': {
},
'variables': { # The following state variables will be updated simultaneously
'network': update_balls_in_network
}
},
{
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
'p1': agent_arrival
},
'variables': { # The following state variables will be updated simultaneously
'network': update_network,
'balls': update_network_balls
}
}
]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Settings of general simulation parameters, unrelated to the system itself
# `T` is a range with the number of discrete units of time the simulation will run for;
# `N` is the number of times the simulation will be run (Monte Carlo runs)
# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps
# We'll cover the `M` key in a future article. For now, let's leave it empty
from cadCAD.configuration.utils import config_sim
simulation_parameters = config_sim({
'T': range(T),
'N': 1,
'M': {'p':[0]}
})
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# The configurations above are then packaged into a `Configuration` object
from cadCAD.configuration import append_configs
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# The configurations above are then packaged into a `Configuration` object
append_configs(
initial_state=initial_conditions, #dict containing variable names and initial values
partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions
sim_configs=simulation_parameters #dict containing simulation parameters
)
from tabulate import tabulate
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from cadCAD import configs
import pandas as pd
exec_mode = ExecutionMode()
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
run = Executor(exec_context=multi_proc_ctx, configs=configs)
i = 0
verbose = False
results = {}
for raw_result, tensor_field in run.execute():
result = pd.DataFrame(raw_result)
if verbose:
print()
print(f"Tensor Field: {type(tensor_field)}")
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
print(f"Output: {type(result)}")
print(tabulate(result, headers='keys', tablefmt='psql'))
print()
results[i] = {}
results[i]['result'] = result
results[i]['simulation_parameters'] = simulation_parameters[i]
i += 1
multi_proc: [<cadCAD.configuration.Configuration object at 0x1019c24f28>] [<cadCAD.configuration.Configuration object at 0x1019c24f28>]
df = pd.DataFrame(raw_result)
balls_list = [b for b in df.balls]
df.head(13)
balls | network | run | substep | timestep | |
---|---|---|---|---|---|
0 | [4.0, 20.0, 20.0] | (0, 1, 2) | 1 | 0 | 0 |
1 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 1 | 1 |
2 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 2 | 1 |
3 | [5.0, 20.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 3 | 1 |
4 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 1 | 2 |
5 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 2 | 2 |
6 | [6.0, 19.0, 19.0, 14.0, 5.0] | (0, 1, 2, 3, 4) | 1 | 3 | 2 |
7 | [7.0, 19.0, 18.0, 13.0, 6.0] | (0, 1, 2, 3, 4) | 1 | 1 | 3 |
8 | [7.0, 19.0, 18.0, 13.0, 6.0] | (0, 1, 2, 3, 4) | 1 | 2 | 3 |
9 | [7.0, 19.0, 18.0, 13.0, 6.0, 10.0] | (0, 1, 2, 3, 4, 5) | 1 | 3 | 3 |
10 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | (0, 1, 2, 3, 4, 5) | 1 | 1 | 4 |
11 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | (0, 1, 2, 3, 4, 5) | 1 | 2 | 4 |
12 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0, 9.0] | (0, 1, 2, 3, 4, 5, 6) | 1 | 3 | 4 |
df['balls_from_graph'] = df.network.apply(lambda rec: [rec.nodes[node]['balls'] for node in rec.nodes])
df.head(13)
balls | network | run | substep | timestep | balls_from_graph | |
---|---|---|---|---|---|---|
0 | [4.0, 20.0, 20.0] | (0, 1, 2) | 1 | 0 | 0 | [4, 20, 20] |
1 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 1 | 1 | [4, 20, 20] |
2 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 2 | 1 | [5.0, 20.0, 19.0] |
3 | [5.0, 20.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 3 | 1 | [5.0, 20.0, 19.0, 14] |
4 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 1 | 2 | [5.0, 20.0, 19.0, 14] |
5 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 2 | 2 | [6.0, 19.0, 19.0, 14.0] |
6 | [6.0, 19.0, 19.0, 14.0, 5.0] | (0, 1, 2, 3, 4) | 1 | 3 | 2 | [6.0, 19.0, 19.0, 14.0, 5] |
7 | [7.0, 19.0, 18.0, 13.0, 6.0] | (0, 1, 2, 3, 4) | 1 | 1 | 3 | [6.0, 19.0, 19.0, 14.0, 5] |
8 | [7.0, 19.0, 18.0, 13.0, 6.0] | (0, 1, 2, 3, 4) | 1 | 2 | 3 | [7.0, 19.0, 18.0, 13.0, 6.0] |
9 | [7.0, 19.0, 18.0, 13.0, 6.0, 10.0] | (0, 1, 2, 3, 4, 5) | 1 | 3 | 3 | [7.0, 19.0, 18.0, 13.0, 6.0, 10] |
10 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | (0, 1, 2, 3, 4, 5) | 1 | 1 | 4 | [7.0, 19.0, 18.0, 13.0, 6.0, 10] |
11 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | (0, 1, 2, 3, 4, 5) | 1 | 2 | 4 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] |
12 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0, 9.0] | (0, 1, 2, 3, 4, 5, 6) | 1 | 3 | 4 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0, 9] |
#select the record
r = 10 #in this case r=3 is run 1, substep 3, timestep 4
#select a specific node index in graph:
i = 2
print(df.iloc[r].network.nodes[i]['balls'])
print(df.balls[r][i])
18.0 17.0
df['sync_check'] = df.balls - df.balls_from_graph
df.head()
balls | network | run | substep | timestep | balls_from_graph | sync_check | |
---|---|---|---|---|---|---|---|
0 | [4.0, 20.0, 20.0] | (0, 1, 2) | 1 | 0 | 0 | [4, 20, 20] | [0.0, 0.0, 0.0] |
1 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 1 | 1 | [4, 20, 20] | [1.0, 0.0, -1.0] |
2 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 2 | 1 | [5.0, 20.0, 19.0] | [0.0, 0.0, 0.0] |
3 | [5.0, 20.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 3 | 1 | [5.0, 20.0, 19.0, 14] | [0.0, 0.0, 0.0, 0.0] |
4 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 1 | 2 | [5.0, 20.0, 19.0, 14] | [1.0, -1.0, 0.0, 0.0] |
nets = df[df.substep==1].network.values
pos = nx.spring_layout(nets[-1])
nx.draw(nets[-1],pos=pos, node_size=ns, node_color=c)
axes = plt.axis()
maxL = df['sync_check'].apply(len).max()
counter = 0
for i in range(len(nets)):
ns = [10*b for b in rdf.balls.values[i]]
m = len(ns)
nx.draw(nets[i],pos=pos, node_size=ns, node_color=c[:m])
plt.title("Update: $G_{"+str(i)+"}$ to $G_{"+str(i+1)+"}$")
plt.axis(axes)
if counter <10:
st = 'fig0'
else:
st = 'fig'
plt.savefig(st+str(counter)+'.png')
counter = counter+1
plt.show()
def pad(vec, length,fill=True):
if fill:
padded = np.zeros(length,)
else:
padded = np.empty(length,)
padded[:] = np.nan
for i in range(len(vec)):
padded[i]= vec[i]
return padded
def make2D(key, data, fill=False):
maxL = data[key].apply(len).max()
newkey = 'padded_'+key
data[newkey] = data[key].apply(lambda x: pad(x,maxL,fill))
reshaped = np.array([a for a in data[newkey].values])
return reshaped
pad([1,2,3], 6, False)
array([ 1., 2., 3., nan, nan, nan])
df['padded_sync_check'] = df['sync_check'].apply(lambda x: pad(x,maxL))
np.array([a for a in df.padded_sync_check.values]).shape
(151, 53)
make2D('balls', df,True).max(axis=1)
array([20., 20., 20., 20., 19., 19., 19., 19., 19., 19., 18., 18., 18., 17., 17., 17., 16., 16., 16., 15., 15., 15., 14., 14., 16., 17., 17., 17., 15., 15., 15., 15., 15., 15., 17., 17., 17., 17., 17., 17., 17., 17., 17., 19., 19., 19., 17., 17., 23., 21., 21., 23., 23., 23., 23., 22., 22., 22., 21., 21., 21., 30., 30., 30., 29., 29., 29., 28., 28., 28., 27., 27., 27., 26., 26., 26., 25., 25., 25., 24., 24., 24., 30., 30., 30., 29., 29., 29., 28., 28., 28., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 32., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42., 42.])
rdf = df[df.substep==2].copy()
last_net = rdf.network.values[-1]
strats = ["Agent #"+str(i)+": "+str(last_net.nodes[i]['strat']).split(" ")[1].split("_")[0] for i in last_net.nodes ]
strats
['Agent #0: fair', 'Agent #1: fair', 'Agent #2: greedy', 'Agent #3: greedy', 'Agent #4: fair', 'Agent #5: fair', 'Agent #6: fair', 'Agent #7: fair', 'Agent #8: giving', 'Agent #9: greedy', 'Agent #10: giving', 'Agent #11: fair', 'Agent #12: greedy', 'Agent #13: fair', 'Agent #14: greedy', 'Agent #15: fair', 'Agent #16: fair', 'Agent #17: fair', 'Agent #18: fair', 'Agent #19: greedy', 'Agent #20: fair', 'Agent #21: greedy', 'Agent #22: fair', 'Agent #23: giving', 'Agent #24: giving', 'Agent #25: greedy', 'Agent #26: greedy', 'Agent #27: greedy', 'Agent #28: greedy', 'Agent #29: fair', 'Agent #30: greedy', 'Agent #31: fair', 'Agent #32: greedy', 'Agent #33: fair', 'Agent #34: fair', 'Agent #35: greedy', 'Agent #36: greedy', 'Agent #37: fair', 'Agent #38: greedy', 'Agent #39: greedy', 'Agent #40: greedy', 'Agent #41: fair', 'Agent #42: fair', 'Agent #43: greedy', 'Agent #44: giving', 'Agent #45: greedy', 'Agent #46: greedy', 'Agent #47: fair', 'Agent #48: fair', 'Agent #49: fair', 'Agent #50: fair', 'Agent #51: greedy']
M = len(last_net.nodes)
Mgr = len([s for s in strats if s.split(" ")[-1]=='greedy' ])
Mf = len([s for s in strats if s.split(" ")[-1]=='fair' ])
Mgv = len([s for s in strats if s.split(" ")[-1]=='giving' ])
cm_fair = plt.get_cmap('PuBu')
cm_giving = plt.get_cmap('YlGn')
cm_greedy = plt.get_cmap('RdPu')
c=np.empty((M,4))
gr=Mgr
f=Mf
gv=Mgv
for j in range(M):
s = strats[j]
if s.split(" ")[-1]=='greedy':
c[j]= cm_greedy(1.*gr/Mgr/2)
gr +=1
elif s.split(" ")[-1]=='fair':
c[j]= cm_fair(1.*f/Mf/2)
f +=1
elif s.split(" ")[-1]=='giving':
c[j]= cm_giving(1.*gv/Mgv/2)
gv +=1
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,6))
for j in range(M):
ax1.plot(rdf.index,make2D('balls', rdf)[:,j], '--',color=c[j])
ax1.legend(strats, ncol = 5,loc='upper left', bbox_to_anchor=(-.05, -0.15))
ax1.set_title('Marbles Held by Each Agent Over Time')
ax1.set_ylabel('Marbles')
ax1.set_xlabel('time')
nc = {j:c[j] for j in range(M)}
ns = [10*b for b in rdf.balls.values[-1]]
nx.draw_spring(last_net,node_color=c, node_size=ns, ax=ax2)
ax2.set_title("Network of Relations Between Agents")
Text(0.5, 1.0, 'Network of Relations Between Agents')
df.columns
Index(['balls', 'network', 'run', 'substep', 'timestep', 'balls_from_graph', 'sync_check', 'padded_sync_check', 'padded_balls'], dtype='object')
plt.plot(df.index,make2D('sync_check', df))
[<matplotlib.lines.Line2D at 0x101a2a36a0>, <matplotlib.lines.Line2D at 0x101a2a3940>, <matplotlib.lines.Line2D at 0x101a2a3ac8>, <matplotlib.lines.Line2D at 0x101a2a3c50>, <matplotlib.lines.Line2D at 0x101a2a3dd8>, <matplotlib.lines.Line2D at 0x101a2a3f60>, <matplotlib.lines.Line2D at 0x101a2d9128>, <matplotlib.lines.Line2D at 0x101a2d92b0>, <matplotlib.lines.Line2D at 0x101a2d9438>, <matplotlib.lines.Line2D at 0x101a2d95c0>, <matplotlib.lines.Line2D at 0x101af79b38>, <matplotlib.lines.Line2D at 0x101a2d9898>, <matplotlib.lines.Line2D at 0x101a2d9a20>, <matplotlib.lines.Line2D at 0x101a2d9ba8>, <matplotlib.lines.Line2D at 0x101a2d9d30>, <matplotlib.lines.Line2D at 0x101a2d9eb8>, <matplotlib.lines.Line2D at 0x101b207080>, <matplotlib.lines.Line2D at 0x101b207208>, <matplotlib.lines.Line2D at 0x101b207390>, <matplotlib.lines.Line2D at 0x101b207518>, <matplotlib.lines.Line2D at 0x101b2076a0>, <matplotlib.lines.Line2D at 0x101b207828>, <matplotlib.lines.Line2D at 0x101b2079b0>, <matplotlib.lines.Line2D at 0x101b207b38>, <matplotlib.lines.Line2D at 0x101b207cc0>, <matplotlib.lines.Line2D at 0x101b207e48>, <matplotlib.lines.Line2D at 0x101b207fd0>, <matplotlib.lines.Line2D at 0x101b1ea198>, <matplotlib.lines.Line2D at 0x101b1ea320>, <matplotlib.lines.Line2D at 0x101b1ea4a8>, <matplotlib.lines.Line2D at 0x101b1ea630>, <matplotlib.lines.Line2D at 0x101b1ea7b8>, <matplotlib.lines.Line2D at 0x101b1ea940>, <matplotlib.lines.Line2D at 0x101b1eaac8>, <matplotlib.lines.Line2D at 0x101b1eac50>, <matplotlib.lines.Line2D at 0x101b1eadd8>, <matplotlib.lines.Line2D at 0x101b1eaf60>, <matplotlib.lines.Line2D at 0x101b1d1128>, <matplotlib.lines.Line2D at 0x101b1d12b0>, <matplotlib.lines.Line2D at 0x101b1d1438>, <matplotlib.lines.Line2D at 0x101b1d15c0>, <matplotlib.lines.Line2D at 0x101b1d1748>, <matplotlib.lines.Line2D at 0x101b1d18d0>, <matplotlib.lines.Line2D at 0x101b1d1a58>, <matplotlib.lines.Line2D at 0x101b1d1be0>, <matplotlib.lines.Line2D at 0x101b1d1d68>, <matplotlib.lines.Line2D at 0x101b1d1ef0>, <matplotlib.lines.Line2D at 0x101b2060b8>, <matplotlib.lines.Line2D at 0x101b206240>, <matplotlib.lines.Line2D at 0x101b2063c8>, <matplotlib.lines.Line2D at 0x101b206550>, <matplotlib.lines.Line2D at 0x101b2066d8>, <matplotlib.lines.Line2D at 0x101b206860>]
import collections
for G in rdf.network.values:
degree_sequence = sorted([d for n, d in G.degree()], reverse=True) # degree sequence
# print "Degree sequence", degree_sequence
degreeCount = collections.Counter(degree_sequence)
deg, cnt = zip(*degreeCount.items())
fig, ax = plt.subplots()
plt.bar(deg, cnt, width=0.80, color='b')
plt.title("Degree Histogram")
plt.ylabel("Count")
plt.xlabel("Degree")
ax.set_xticks([d + 0.4 for d in deg])
ax.set_xticklabels(deg)
# draw graph in inset
plt.axes([0.4, 0.4, 0.5, 0.5])
Gcc = sorted(nx.connected_component_subgraphs(G), key=len, reverse=True)[0]
plt.axis('off')
nx.draw_networkx_nodes(G, pos, node_size=20)
nx.draw_networkx_edges(G, pos, alpha=0.4)
plt.show()
r1df = df[df.substep==1].copy()
plt.plot(r1df.index,make2D('sync_check',r1df ))
[<matplotlib.lines.Line2D at 0x101a003b38>, <matplotlib.lines.Line2D at 0x101a003d30>, <matplotlib.lines.Line2D at 0x101a003eb8>, <matplotlib.lines.Line2D at 0x1019fe4080>, <matplotlib.lines.Line2D at 0x1019fe4208>, <matplotlib.lines.Line2D at 0x1019fe4390>, <matplotlib.lines.Line2D at 0x1019fe4518>, <matplotlib.lines.Line2D at 0x1019fe46a0>, <matplotlib.lines.Line2D at 0x1019fe4828>, <matplotlib.lines.Line2D at 0x1019fe49b0>, <matplotlib.lines.Line2D at 0x101a9326d8>, <matplotlib.lines.Line2D at 0x1019fe4c88>, <matplotlib.lines.Line2D at 0x1019fe4e10>, <matplotlib.lines.Line2D at 0x1019fe4f98>, <matplotlib.lines.Line2D at 0x101a649160>, <matplotlib.lines.Line2D at 0x101a6492e8>, <matplotlib.lines.Line2D at 0x101a649470>, <matplotlib.lines.Line2D at 0x101a6495f8>, <matplotlib.lines.Line2D at 0x101a649780>, <matplotlib.lines.Line2D at 0x101a649908>, <matplotlib.lines.Line2D at 0x101a649a90>, <matplotlib.lines.Line2D at 0x101a649c18>, <matplotlib.lines.Line2D at 0x101a649da0>, <matplotlib.lines.Line2D at 0x101a649f28>, <matplotlib.lines.Line2D at 0x101a6310f0>, <matplotlib.lines.Line2D at 0x101a631278>, <matplotlib.lines.Line2D at 0x101a631400>, <matplotlib.lines.Line2D at 0x101a631588>, <matplotlib.lines.Line2D at 0x101a631710>, <matplotlib.lines.Line2D at 0x101a631898>, <matplotlib.lines.Line2D at 0x101a631a20>, <matplotlib.lines.Line2D at 0x101a631ba8>, <matplotlib.lines.Line2D at 0x101a631d30>, <matplotlib.lines.Line2D at 0x101a631eb8>, <matplotlib.lines.Line2D at 0x101a40e080>, <matplotlib.lines.Line2D at 0x101a40e208>, <matplotlib.lines.Line2D at 0x101a40e390>, <matplotlib.lines.Line2D at 0x101a40e518>, <matplotlib.lines.Line2D at 0x101a40e6a0>, <matplotlib.lines.Line2D at 0x101a40e828>, <matplotlib.lines.Line2D at 0x101a40e9b0>, <matplotlib.lines.Line2D at 0x101a40eb38>, <matplotlib.lines.Line2D at 0x101a40ecc0>, <matplotlib.lines.Line2D at 0x101a40ee48>, <matplotlib.lines.Line2D at 0x101a40efd0>, <matplotlib.lines.Line2D at 0x101a431198>, <matplotlib.lines.Line2D at 0x101a431320>, <matplotlib.lines.Line2D at 0x101a4314a8>, <matplotlib.lines.Line2D at 0x101a431630>, <matplotlib.lines.Line2D at 0x101a4317b8>, <matplotlib.lines.Line2D at 0x101a431940>, <matplotlib.lines.Line2D at 0x101a431ac8>]
r2df = df[df.substep==2].copy()
r2df.head()
balls | network | run | substep | timestep | balls_from_graph | sync_check | padded_sync_check | padded_balls | |
---|---|---|---|---|---|---|---|---|---|
2 | [5.0, 20.0, 19.0] | (0, 1, 2) | 1 | 2 | 1 | [5.0, 20.0, 19.0] | [0.0, 0.0, 0.0] | [0.0, 0.0, 0.0, nan, nan, nan, nan, nan, nan, ... | [5.0, 20.0, 19.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0... |
5 | [6.0, 19.0, 19.0, 14.0] | (0, 1, 2, 3) | 1 | 2 | 2 | [6.0, 19.0, 19.0, 14.0] | [0.0, 0.0, 0.0, 0.0] | [0.0, 0.0, 0.0, 0.0, nan, nan, nan, nan, nan, ... | [6.0, 19.0, 19.0, 14.0, 0.0, 0.0, 0.0, 0.0, 0.... |
8 | [7.0, 19.0, 18.0, 13.0, 6.0] | (0, 1, 2, 3, 4) | 1 | 2 | 3 | [7.0, 19.0, 18.0, 13.0, 6.0] | [0.0, 0.0, 0.0, 0.0, 0.0] | [0.0, 0.0, 0.0, 0.0, 0.0, nan, nan, nan, nan, ... | [7.0, 19.0, 18.0, 13.0, 6.0, 0.0, 0.0, 0.0, 0.... |
11 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | (0, 1, 2, 3, 4, 5) | 1 | 2 | 4 | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0] | [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] | [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, nan, nan, nan, ... | [8.0, 18.0, 17.0, 11.0, 7.0, 12.0, 0.0, 0.0, 0... |
14 | [9.0, 17.0, 15.0, 11.0, 9.0, 12.0, 9.0] | (0, 1, 2, 3, 4, 5, 6) | 1 | 2 | 5 | [9.0, 17.0, 15.0, 11.0, 9.0, 12.0, 9.0] | [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] | [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, nan, nan, ... | [9.0, 17.0, 15.0, 11.0, 9.0, 12.0, 9.0, 0.0, 0... |
plt.plot(r2df.index,make2D('sync_check',r2df ))
[<matplotlib.lines.Line2D at 0x101a30a630>, <matplotlib.lines.Line2D at 0x101a30a828>, <matplotlib.lines.Line2D at 0x101a30a9b0>, <matplotlib.lines.Line2D at 0x101a30ab38>, <matplotlib.lines.Line2D at 0x101a30acc0>, <matplotlib.lines.Line2D at 0x101a30ae48>, <matplotlib.lines.Line2D at 0x101a30afd0>, <matplotlib.lines.Line2D at 0x101a31c198>, <matplotlib.lines.Line2D at 0x101a31c320>, <matplotlib.lines.Line2D at 0x101a31c4a8>, <matplotlib.lines.Line2D at 0x101ad402e8>, <matplotlib.lines.Line2D at 0x101a31c780>, <matplotlib.lines.Line2D at 0x101a31c908>, <matplotlib.lines.Line2D at 0x101a31ca90>, <matplotlib.lines.Line2D at 0x101a31cc18>, <matplotlib.lines.Line2D at 0x101a31cda0>, <matplotlib.lines.Line2D at 0x101a31cf28>, <matplotlib.lines.Line2D at 0x101a2ff0f0>, <matplotlib.lines.Line2D at 0x101a2ff278>, <matplotlib.lines.Line2D at 0x101a2ff400>, <matplotlib.lines.Line2D at 0x101a2ff588>, <matplotlib.lines.Line2D at 0x101a2ff710>, <matplotlib.lines.Line2D at 0x101a2ff898>, <matplotlib.lines.Line2D at 0x101a2ffa20>, <matplotlib.lines.Line2D at 0x101a2ffba8>, <matplotlib.lines.Line2D at 0x101a2ffd30>, <matplotlib.lines.Line2D at 0x101a2ffeb8>, <matplotlib.lines.Line2D at 0x101a2f2080>, <matplotlib.lines.Line2D at 0x101a2f2208>, <matplotlib.lines.Line2D at 0x101a2f2390>, <matplotlib.lines.Line2D at 0x101a2f2518>, <matplotlib.lines.Line2D at 0x101a2f26a0>, <matplotlib.lines.Line2D at 0x101a2f2828>, <matplotlib.lines.Line2D at 0x101a2f29b0>, <matplotlib.lines.Line2D at 0x101a2f2b38>, <matplotlib.lines.Line2D at 0x101a2f2cc0>, <matplotlib.lines.Line2D at 0x101a2f2e48>, <matplotlib.lines.Line2D at 0x101a2f2fd0>, <matplotlib.lines.Line2D at 0x101a2e0198>, <matplotlib.lines.Line2D at 0x101a2e0320>, <matplotlib.lines.Line2D at 0x101a2e04a8>, <matplotlib.lines.Line2D at 0x101a2e0630>, <matplotlib.lines.Line2D at 0x101a2e07b8>, <matplotlib.lines.Line2D at 0x101a2e0940>, <matplotlib.lines.Line2D at 0x101a2e0ac8>, <matplotlib.lines.Line2D at 0x101a2e0c50>, <matplotlib.lines.Line2D at 0x101a2e0dd8>, <matplotlib.lines.Line2D at 0x101a2e0f60>, <matplotlib.lines.Line2D at 0x101a882ef0>, <matplotlib.lines.Line2D at 0x101a8824e0>, <matplotlib.lines.Line2D at 0x101a882c88>, <matplotlib.lines.Line2D at 0x101a882b70>]