├── net-karate-club-visualization.py ├── net-read-adjlist.py ├── pde-plot-imshow.py ├── net-read-adjlist-directed.py ├── pde-plot-vector-field.py ├── pde-plot-contour.py ├── ds-phasespace-drawing-streamplot.py ├── net-percolation.py ├── net-networkx-test2.py ├── pde-plot-surface-3D.py ├── net-degree-correlation.py ├── ds-bifurcation-diagram-saddlenode.py ├── ds-exponential-growth.py ├── net-shortest-path.py ├── net-percolation-plot.py ├── ds-chaotic-behavior.py ├── ds-graph-based-phasespace-exercise.py ├── ds-chaotic-behavior-logistic-map.py ├── ds-graph-based-phasespace.py ├── ds-bifurcation-diagram-hysteresis.py ├── ds-bifurcation-diagram-transcritical.py ├── ds-oscillation-wrong.py ├── ds-chaotic-behavior-butterfly-effect.py ├── net-attack.py ├── ds-oscillation-correct-phasespace.py ├── ds-bifurcation-diagram-pitchfork-subcritical.py ├── ds-bifurcation-diagram-pitchfork-supercritical.py ├── ds-exponential-growth-time.py ├── ds-oscillation-correct.py ├── interactive-template.py ├── ds-logisticgrowth-continuous.py ├── net-small-world-experiment.py ├── net-random-graphs.py ├── ds-period-doubling-bifurcation.py ├── ds-bifurcation-diagram-numerical.py ├── ds-predator-prey.py ├── ds-phasespace-drawing-Fibonacci.py ├── net-communities.py ├── net-degree-distributions-loglog.py ├── ds-phasespace-drawing.py ├── ds-Lyapunov-exponent.py ├── ds-phasespace-drawing-bad.py ├── ds-bifurcation-diagram-numerical-logistic-map.py ├── dynamic-randomwalk.py ├── ca-graph-based-phasespace-pie.py ├── net-LDR.py ├── net-randomwalk.py ├── dynamic-randomwalk-standalone.py ├── ds-predator-prey-continuous.py ├── ds-SIR-continuous.py ├── net-voter.py ├── net-networkx-test1.py ├── ds-phasespace-drawing-exercise.py ├── net-ccdfs-loglog.py ├── ds-cobweb-plot-exercise.py ├── net-exponent-estimation.py ├── abm-randomwalk.py ├── ds-van-der-Pol-Hopf-bifurcation.py ├── net-layouts.py ├── ca-graph-based-phasespace.py ├── net-percolation-experiment-animated.py ├── ca-cobweb-plot-for-rga.py ├── ca-cobweb-plot-for-mfa.py ├── net-drawing-options.py ├── ds-cobweb-plot.py ├── ds-FitzHugh-Nagumo-bifurcation.py ├── net-small-world-exercise.py ├── ca-panic.py ├── ds-phasespace-drawing-3D.py ├── net-diffusion.py ├── net-Barabasi-Albert.py ├── net-SIS.py ├── net-majority.py ├── net-Kuramoto.py ├── net-RBN.py ├── net-Kuramoto-desync.py ├── dynamic-randomwalk-pSetter.py ├── net-small-world.py ├── ds-period-doubling-bifurcation-cobweb.py ├── abm-swarm.py ├── ds-SIR-continuous-multiple-strains.py ├── net-SIS-synchronous-update.py ├── net-SIS-adaptive.py ├── abm-segregation-continuous.py ├── ds-Lorenz-equations-Poincare-section.py ├── net-Hopfield.py ├── pde-transport-imshow.py ├── ds-Lorenz-equations.py ├── net-sync-analysis.py ├── net-small-world-experiment-animated.py ├── net-Kuramoto-with-phase.py ├── pde-population-economy.py ├── ca-gameoflife.py ├── pde-transport.py ├── pde-transport-error.py ├── ca-majority.py ├── ca-excitablemedia.py ├── ca-forestfire.py ├── ca-Turing.py ├── net-diffusion-adaptive.py ├── net-networkx-demo2.py ├── net-cascade-of-failure.py ├── pde-transport-escaping.py ├── ds-Hodgkin-Huxley-equations.py ├── ca-hostpathogen.py ├── pde-Turing.py ├── abm-segregation-discrete.py ├── abm-ants.py ├── abm-DLA.py ├── net-SIS-large-graph.py ├── abm-Keller-Segel.py ├── abm-Vicsek.py ├── pde-BZ-reaction.py ├── net-RBN-with-phasespace.py ├── LICENSE ├── net-SIS-large-graph-adaptive.py ├── abm-DLA-faster-neighbor-detection.py ├── net-SIS-large-graph-parametersweep.py ├── abm-ants-pheromone.py ├── abm-predator-prey.py ├── abm-epidemics.py ├── abm-predator-prey-evolvable.py ├── net-networkx-demo1.py ├── abm-predator-prey-with-plot.py ├── abm-predator-prey-old.py ├── abm-epidemics-virulence-evolution.py ├── abm-predator-prey-old-withplot.py ├── abm-sugarscape.py ├── README.md └── pycxsimulator.py /net-karate-club-visualization.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.karate_club_graph() 5 | nx.draw(g) 6 | show() 7 | -------------------------------------------------------------------------------- /net-read-adjlist.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.read_adjlist('myNetworkData.csv', delimiter = ',') 5 | nx.draw(g, with_labels = True) 6 | show() 7 | -------------------------------------------------------------------------------- /pde-plot-imshow.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | xvalues, yvalues = meshgrid(arange(-5, 5.5, 0.05), arange(-5, 5.5, 0.05)) 4 | zvalues = sin(sqrt(xvalues**2 + yvalues**2)) 5 | 6 | imshow(zvalues) 7 | 8 | show() 9 | -------------------------------------------------------------------------------- /net-read-adjlist-directed.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.read_adjlist('myNetworkData.csv', delimiter = ',', 5 | create_using = nx.DiGraph()) 6 | nx.draw(g, with_labels = True) 7 | show() 8 | -------------------------------------------------------------------------------- /pde-plot-vector-field.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | xvalues, yvalues = meshgrid(arange(-3, 3.1, 0.1), arange(-3, 3.1, 0.1)) 4 | 5 | vx = 2 * xvalues 6 | vy = yvalues - xvalues 7 | 8 | streamplot(xvalues, yvalues, vx, vy) 9 | 10 | show() 11 | -------------------------------------------------------------------------------- /pde-plot-contour.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | xvalues, yvalues = meshgrid(arange(-5, 5.5, 0.05), arange(-5, 5.5, 0.05)) 4 | zvalues = sin(sqrt(xvalues**2 + yvalues**2)) 5 | 6 | cp = contour(xvalues, yvalues, zvalues) 7 | clabel(cp) 8 | 9 | show() 10 | -------------------------------------------------------------------------------- /ds-phasespace-drawing-streamplot.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | xvalues, yvalues = meshgrid(arange(0, 3, 0.1), arange(0, 3, 0.1)) 4 | 5 | xdot = xvalues - xvalues * yvalues 6 | ydot = - yvalues + xvalues * yvalues 7 | 8 | streamplot(xvalues, yvalues, xdot, ydot) 9 | 10 | show() 11 | -------------------------------------------------------------------------------- /net-percolation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | for i, p in [(1, 0.0001), (2, 0.001), (3, 0.01), (4, 0.1)]: 5 | subplot(1, 4, i) 6 | title('p = ' + str(p)) 7 | g = nx.erdos_renyi_graph(100, p) 8 | nx.draw(g, node_size = 10) 9 | axis('image') 10 | 11 | tight_layout() 12 | show() 13 | -------------------------------------------------------------------------------- /net-networkx-test2.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | 3 | # complete graph made of 5 nodes 4 | g1 = nx.complete_graph(5) 5 | 6 | # complete (fully connected) bipartite graph 7 | # made of group of 3 nodes and group of 4 nodes 8 | g2 = nx.complete_bipartite_graph(3, 4) 9 | 10 | # Zachary's Karate Club graph 11 | g3 = nx.karate_club_graph() 12 | -------------------------------------------------------------------------------- /pde-plot-surface-3D.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | from mpl_toolkits.mplot3d import Axes3D 3 | 4 | xvalues, yvalues = meshgrid(arange(-5, 5.5, 0.05), arange(-5, 5.5, 0.05)) 5 | zvalues = sin(sqrt(xvalues**2 + yvalues**2)) 6 | 7 | fig = gcf() 8 | ax = fig.add_subplot(111, projection='3d') 9 | 10 | ax.plot_surface(xvalues, yvalues, zvalues) 11 | 12 | show() 13 | -------------------------------------------------------------------------------- /net-degree-correlation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | n = 1000 5 | ba = nx.barabasi_albert_graph(n, 5) 6 | 7 | xdata = [] 8 | ydata = [] 9 | for i, j in ba.edges: 10 | xdata.append(ba.degree(i)); ydata.append(ba.degree(j)) 11 | xdata.append(ba.degree(j)); ydata.append(ba.degree(i)) 12 | 13 | plot(xdata, ydata, 'o', alpha = 0.05) 14 | show() 15 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-saddlenode.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def xeq1(r): 4 | return sqrt(r) 5 | 6 | def xeq2(r): 7 | return -sqrt(r) 8 | 9 | domain = linspace(0, 10) 10 | plot(domain, xeq1(domain), 'b-', linewidth = 3) 11 | plot(domain, xeq2(domain), 'r--', linewidth = 3) 12 | plot([0], [0], 'go') 13 | axis([-10, 10, -5, 5]) 14 | xlabel('r') 15 | ylabel('x_eq') 16 | 17 | show() 18 | -------------------------------------------------------------------------------- /ds-exponential-growth.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = 1.1 4 | 5 | def initialize(): 6 | global x, result 7 | x = 1. 8 | result = [x] 9 | 10 | def observe(): 11 | global x, result 12 | result.append(x) 13 | 14 | def update(): 15 | global x, result 16 | x = a * x 17 | 18 | initialize() 19 | for t in range(30): 20 | update() 21 | observe() 22 | 23 | plot(result) 24 | show() 25 | -------------------------------------------------------------------------------- /net-shortest-path.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.karate_club_graph() 5 | positions = nx.spring_layout(g) 6 | 7 | path = nx.shortest_path(g, 16, 25) 8 | edges = [(path[i], path[i+1]) for i in range(len(path) - 1)] 9 | 10 | nx.draw_networkx_edges(g, positions, edgelist = edges, 11 | edge_color = 'r', width = 10) 12 | nx.draw(g, positions, with_labels = True) 13 | show() 14 | -------------------------------------------------------------------------------- /net-percolation-plot.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | p = 0.0001 5 | pdata = [] 6 | gdata = [] 7 | 8 | while p < 0.1: 9 | pdata.append(p) 10 | g = nx.erdos_renyi_graph(100, p) 11 | ccs = nx.connected_components(g) 12 | gdata.append(max(len(cc) for cc in ccs)) 13 | p *= 1.1 14 | 15 | loglog(pdata, gdata) 16 | xlabel('p') 17 | ylabel('size of largest connected component') 18 | show() 19 | -------------------------------------------------------------------------------- /ds-chaotic-behavior.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = x + r - x**2 15 | 16 | r = 1.8 17 | initialize() 18 | for t in range(100): 19 | update() 20 | observe() 21 | plot(result) 22 | title('r = ' + str(r)) 23 | show() 24 | -------------------------------------------------------------------------------- /ds-graph-based-phasespace-exercise.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.DiGraph() 5 | 6 | for x in range(100): 7 | g.add_edge(x, x ** x % 100) 8 | 9 | ccs = list(nx.connected_components(g.to_undirected())) 10 | n = len(ccs) 11 | w = ceil(sqrt(n)) 12 | h = ceil(n / w) 13 | for i in range(n): 14 | subplot(int(h), int(w), i + 1) 15 | nx.draw(nx.subgraph(g, ccs[i]), with_labels = True) 16 | 17 | show() 18 | -------------------------------------------------------------------------------- /ds-chaotic-behavior-logistic-map.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = r * x * (1 - x) 15 | 16 | r = 4.0 17 | initialize() 18 | for t in range(100): 19 | update() 20 | observe() 21 | plot(result) 22 | title('r = ' + str(r)) 23 | show() 24 | -------------------------------------------------------------------------------- /ds-graph-based-phasespace.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.DiGraph() 5 | 6 | for x in range(6): 7 | for y in range(6): 8 | g.add_edge((x, y), ((x * y) % 6, x)) 9 | 10 | ccs = list(nx.connected_components(g.to_undirected())) 11 | n = len(ccs) 12 | w = ceil(sqrt(n)) 13 | h = ceil(n / w) 14 | for i in range(n): 15 | subplot(int(h), int(w), i + 1) 16 | nx.draw(nx.subgraph(g, ccs[i]), with_labels = True) 17 | 18 | show() 19 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-hysteresis.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def r(x): 4 | return -x + x**3 5 | 6 | range1 = linspace(-1.3, -1./sqrt(3)) 7 | range2 = linspace(-1./sqrt(3), 1./sqrt(3)) 8 | range3 = linspace(1./sqrt(3), 1.3) 9 | plot(r(range1), range1, 'b-', linewidth = 3) 10 | plot(r(range2), range2, 'r--', linewidth = 3) 11 | plot(r(range3), range3, 'b-', linewidth = 3) 12 | plot([r(-1./sqrt(3)), r(1./sqrt(3))], [-1./sqrt(3), 1./sqrt(3)], 'go') 13 | xlabel('r') 14 | ylabel('x_eq') 15 | 16 | show() 17 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-transcritical.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def xeq1(r): 4 | return r-r 5 | 6 | def xeq2(r): 7 | return r 8 | 9 | domain1 = linspace(-10, 0) 10 | domain2 = linspace(0, 10) 11 | plot(domain1, xeq1(domain1), 'b-', linewidth = 3) 12 | plot(domain1, xeq2(domain1), 'r--', linewidth = 3) 13 | plot(domain2, xeq1(domain2), 'r--', linewidth = 3) 14 | plot(domain2, xeq2(domain2), 'b-', linewidth = 3) 15 | plot([0], [0], 'go') 16 | axis([-10, 10, -10, 10]) 17 | xlabel('r') 18 | ylabel('x_eq') 19 | 20 | show() 21 | -------------------------------------------------------------------------------- /ds-oscillation-wrong.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, y, xresult, yresult 5 | x = 1. 6 | y = 1. 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | x = 0.5 * x + y 18 | y = -0.5 * x + y 19 | 20 | initialize() 21 | for t in range(30): 22 | update() 23 | observe() 24 | 25 | plot(xresult, 'b-') 26 | plot(yresult, 'g--') 27 | show() 28 | -------------------------------------------------------------------------------- /ds-chaotic-behavior-butterfly-effect.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(x0): 4 | global x, result 5 | x = x0 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = x + r - x**2 15 | 16 | r = 1.8 17 | initialize(0.1) 18 | for t in range(100): 19 | update() 20 | observe() 21 | plot(result, 'b-') 22 | initialize(0.100001) 23 | for t in range(100): 24 | update() 25 | observe() 26 | plot(result, 'g--') 27 | title('r = ' + str(r)) 28 | show() 29 | -------------------------------------------------------------------------------- /net-attack.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | for _ in range(10): 5 | g = nx.barabasi_albert_graph(300, 4) 6 | data = [] 7 | for t in range(299): 8 | 9 | # targeting highest degree node 10 | i = max(dict(g.degree()).items(), key = lambda x:x[1])[0] 11 | 12 | g.remove_node(i) 13 | lcc = max(nx.connected_components(g), key=len) 14 | data.append(len(lcc)) 15 | plot(data) 16 | 17 | xlabel('Number of removed nodes') 18 | ylabel('Size of largest connected component') 19 | show() 20 | -------------------------------------------------------------------------------- /ds-oscillation-correct-phasespace.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, y, xresult, yresult 5 | x = 1. 6 | y = 1. 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = 0.5 * x + y 18 | nexty = -0.5 * x + y 19 | x, y = nextx, nexty 20 | 21 | initialize() 22 | for t in range(30): 23 | update() 24 | observe() 25 | 26 | plot(xresult, yresult) 27 | show() 28 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-pitchfork-subcritical.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def xeq1(r): 4 | return r-r 5 | 6 | def xeq2(r): 7 | return sqrt(-r) 8 | 9 | def xeq3(r): 10 | return -sqrt(-r) 11 | 12 | domain1 = linspace(-10, 0) 13 | domain2 = linspace(0, 10) 14 | plot(domain1, xeq1(domain1), 'b-', linewidth = 3) 15 | plot(domain1, xeq2(domain1), 'r--', linewidth = 3) 16 | plot(domain1, xeq3(domain1), 'r--', linewidth = 3) 17 | plot(domain2, xeq1(domain2), 'r--', linewidth = 3) 18 | plot([0], [0], 'go') 19 | axis([-10, 10, -5, 5]) 20 | xlabel('r') 21 | ylabel('x_eq') 22 | 23 | show() 24 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-pitchfork-supercritical.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def xeq1(r): 4 | return r-r 5 | 6 | def xeq2(r): 7 | return sqrt(r) 8 | 9 | def xeq3(r): 10 | return -sqrt(r) 11 | 12 | domain1 = linspace(-10, 0) 13 | domain2 = linspace(0, 10) 14 | plot(domain1, xeq1(domain1), 'b-', linewidth = 3) 15 | plot(domain2, xeq1(domain2), 'r--', linewidth = 3) 16 | plot(domain2, xeq2(domain2), 'b-', linewidth = 3) 17 | plot(domain2, xeq3(domain2), 'b-', linewidth = 3) 18 | plot([0], [0], 'go') 19 | axis([-10, 10, -5, 5]) 20 | xlabel('r') 21 | ylabel('x_eq') 22 | 23 | show() 24 | -------------------------------------------------------------------------------- /ds-exponential-growth-time.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = 1.1 4 | 5 | def initialize(): 6 | global x, result, t, timesteps ### 7 | x = 1. 8 | result = [x] 9 | t = 0. ### 10 | timesteps = [t] ### 11 | 12 | def observe(): 13 | global x, result, t, timesteps ### 14 | result.append(x) 15 | timesteps.append(t) ### 16 | 17 | def update(): 18 | global x, result, t, timesteps ### 19 | x = a * x 20 | t = t + 0.1 ### 21 | 22 | initialize() 23 | while t < 3.: ### 24 | update() 25 | observe() 26 | 27 | plot(timesteps, result) ### 28 | show() 29 | -------------------------------------------------------------------------------- /ds-oscillation-correct.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, y, xresult, yresult 5 | x = 1. 6 | y = 1. 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = 0.5 * x + y 18 | nexty = -0.5 * x + y 19 | x, y = nextx, nexty 20 | 21 | initialize() 22 | for t in range(30): 23 | update() 24 | observe() 25 | 26 | plot(xresult, 'b-') 27 | plot(yresult, 'g--') 28 | show() 29 | -------------------------------------------------------------------------------- /interactive-template.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | # import necessary modules 5 | # define model parameters 6 | 7 | def initialize(): 8 | global # list global variables 9 | # initialize system states 10 | 11 | def observe(): 12 | global # list global variables 13 | cla() # to clear the visualization space 14 | # visualize system states 15 | 16 | def update(): 17 | global # list global variables 18 | # update system states for one discrete time step 19 | 20 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 21 | -------------------------------------------------------------------------------- /ds-logisticgrowth-continuous.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | r = 0.2 4 | K = 1.0 5 | Dt = 0.01 6 | 7 | def initialize(): 8 | global x, result, t, timesteps 9 | x = 0.1 10 | result = [x] 11 | t = 0. 12 | timesteps = [t] 13 | 14 | def observe(): 15 | global x, result, t, timesteps 16 | result.append(x) 17 | timesteps.append(t) 18 | 19 | def update(): 20 | global x, result, t, timesteps 21 | x = x + r * x * (1 - x / K) * Dt 22 | t = t + Dt 23 | 24 | initialize() 25 | while t < 50.: 26 | update() 27 | observe() 28 | 29 | plot(timesteps, result) 30 | show() 31 | -------------------------------------------------------------------------------- /net-small-world-experiment.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | pdata = [] 5 | Ldata = [] 6 | Cdata = [] 7 | 8 | g0 = nx.watts_strogatz_graph(1000, 10, 0) 9 | L0 = nx.average_shortest_path_length(g0) 10 | C0 = nx.average_clustering(g0) 11 | 12 | p = 0.0001 13 | while p < 1.0: 14 | g = nx.watts_strogatz_graph(1000, 10, p) 15 | pdata.append(p) 16 | Ldata.append(nx.average_shortest_path_length(g) / L0) 17 | Cdata.append(nx.average_clustering(g) / C0) 18 | p *= 1.5 19 | 20 | semilogx(pdata, Ldata, label = 'L / L0') 21 | semilogx(pdata, Cdata, label = 'C / C0') 22 | xlabel('p') 23 | legend() 24 | show() 25 | -------------------------------------------------------------------------------- /net-random-graphs.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | subplot(2, 2, 1) 5 | nx.draw(nx.gnm_random_graph(10, 20)) 6 | title('random graph with\n10 nodes, 20 edges') 7 | 8 | subplot(2, 2, 2) 9 | nx.draw(nx.gnp_random_graph(20, 0.1)) 10 | title('random graph with\n 20 nodes, 10% edge probability') 11 | 12 | subplot(2, 2, 3) 13 | nx.draw(nx.random_regular_graph(3, 10)) 14 | title('random regular graph with\n10 nodes of degree 3') 15 | 16 | subplot(2, 2, 4) 17 | nx.draw(nx.random_degree_sequence_graph([3,3,3,3,4,4,4,4,5,5])) 18 | title('random graph with\n degree sequence\n[3,3,3,3,4,4,4,4,5,5]') 19 | 20 | tight_layout() 21 | show() 22 | -------------------------------------------------------------------------------- /ds-period-doubling-bifurcation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = x + r - x**2 15 | 16 | def plot_phase_space(): 17 | initialize() 18 | for t in range(30): 19 | update() 20 | observe() 21 | plot(result) 22 | ylim(0, 2) 23 | title('r = ' + str(r)) 24 | 25 | rs = [0.1, 0.5, 1.0, 1.1, 1.5, 1.6] 26 | for i in range(len(rs)): 27 | subplot(2, 3, i + 1) 28 | r = rs[i] 29 | plot_phase_space() 30 | 31 | tight_layout() 32 | show() 33 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-numerical.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = x + r - x**2 15 | 16 | def plot_asymptotic_states(): 17 | initialize() 18 | for t in range(100): # first 100 steps are discarded 19 | update() 20 | for t in range(100): # second 100 steps are collected 21 | update() 22 | observe() 23 | plot([r] * 100, result, 'b.', alpha = 0.3) 24 | 25 | for r in arange(0, 2, 0.01): 26 | plot_asymptotic_states() 27 | 28 | xlabel('r') 29 | ylabel('x') 30 | show() 31 | -------------------------------------------------------------------------------- /ds-predator-prey.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, y, xresult, yresult 5 | x = 1. 6 | y = 1. 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | r = 1. 18 | b = 1. 19 | d = 1. 20 | c = 1. 21 | K = 5. 22 | nextx = x + r * x * (1 - x / K) - (1 - 1 / (b * y + 1)) * x 23 | nexty = y - d * y + c * x * y 24 | x, y = nextx, nexty 25 | 26 | initialize() 27 | for t in range(100): 28 | update() 29 | observe() 30 | 31 | plot(xresult, 'b-') 32 | plot(yresult, 'g--') 33 | show() 34 | -------------------------------------------------------------------------------- /ds-phasespace-drawing-Fibonacci.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(x0, y0): ### 4 | global x, y, xresult, yresult 5 | x = x0 ### 6 | y = y0 ### 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = x + y 18 | nexty = x 19 | x, y = nextx, nexty 20 | 21 | for x0 in arange(-2, 2.5, .5): ### 22 | for y0 in arange(-2, 2.5, .5): ### 23 | initialize(x0, y0) ### 24 | for t in range(3): 25 | update() 26 | observe() 27 | plot(xresult, yresult, 'b') ### 28 | 29 | show() 30 | -------------------------------------------------------------------------------- /net-communities.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.Graph() 5 | 6 | imin, imax = 0, 9 7 | for i in range(30): 8 | a, b = choice(range(imin, imax + 1), 2, replace = False) 9 | g.add_edge(a, b) 10 | 11 | imin, imax = 10, 24 12 | for i in range(40): 13 | a, b = choice(range(imin, imax + 1), 2, replace = False) 14 | g.add_edge(a, b) 15 | 16 | imin, imax = 25, 49 17 | for i in range(50): 18 | a, b = choice(range(imin, imax + 1), 2, replace = False) 19 | g.add_edge(a, b) 20 | 21 | imin, imax = 0, 49 22 | for i in range(10): 23 | a, b = choice(range(imin, imax + 1), 2, replace = False) 24 | g.add_edge(a, b) 25 | 26 | nx.draw(g, pos = nx.kamada_kawai_layout(g)) 27 | show() 28 | -------------------------------------------------------------------------------- /net-degree-distributions-loglog.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | n = 1000 5 | er = nx.erdos_renyi_graph(n, 0.01) 6 | ws = nx.watts_strogatz_graph(n, 10, 0.01) 7 | ba = nx.barabasi_albert_graph(n, 5) 8 | 9 | Pk = [float(x) / n for x in nx.degree_histogram(er)] 10 | domain = range(len(Pk)) 11 | loglog(domain, Pk, '-', label = 'Erdos-Renyi') 12 | 13 | Pk = [float(x) / n for x in nx.degree_histogram(ws)] 14 | domain = range(len(Pk)) 15 | loglog(domain, Pk, '--', label = 'Watts-Strogatz') 16 | 17 | Pk = [float(x) / n for x in nx.degree_histogram(ba)] 18 | domain = range(len(Pk)) 19 | loglog(domain, Pk, ':', label = 'Barabasi-Albert') 20 | 21 | xlabel('$k$') 22 | ylabel('$P(k)$') 23 | legend() 24 | show() 25 | -------------------------------------------------------------------------------- /ds-phasespace-drawing.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(x0, y0): ### 4 | global x, y, xresult, yresult 5 | x = x0 ### 6 | y = y0 ### 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = 0.5 * x + y 18 | nexty = -0.5 * x + y 19 | x, y = nextx, nexty 20 | 21 | for x0 in arange(-2, 2, .5): ### 22 | for y0 in arange(-2, 2, .5): ### 23 | initialize(x0, y0) ### 24 | for t in range(30): 25 | update() 26 | observe() 27 | plot(xresult, yresult, 'b') ### 28 | 29 | show() 30 | -------------------------------------------------------------------------------- /ds-Lyapunov-exponent.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [logdFdx(x)] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(logdFdx(x)) 11 | 12 | def update(r): 13 | global x, result 14 | x = x + r - x**2 15 | 16 | def logdFdx(x): 17 | return log(abs(1 - 2*x)) 18 | 19 | def lyapunov_exponent(r): 20 | initialize() 21 | for t in range(100): 22 | update(r) 23 | observe() 24 | return mean(result) 25 | 26 | rvalues = arange(0, 2, 0.01) 27 | lambdas = [lyapunov_exponent(r) for r in rvalues] 28 | plot(rvalues, lambdas) 29 | plot([0, 2], [0, 0]) 30 | 31 | xlabel('r') 32 | ylabel('Lyapunov exponent') 33 | show() 34 | -------------------------------------------------------------------------------- /ds-phasespace-drawing-bad.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(x0, y0): ### 4 | global x, y, xresult, yresult 5 | x = x0 ### 6 | y = y0 ### 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = - 0.5 * x - 0.7 * y 18 | nexty = x - 0.5 * y 19 | x, y = nextx, nexty 20 | 21 | for x0 in arange(-2, 2, .5): ### 22 | for y0 in arange(-2, 2, .5): ### 23 | initialize(x0, y0) ### 24 | for t in range(30): 25 | update() 26 | observe() 27 | plot(xresult, yresult, 'b') ### 28 | 29 | show() 30 | -------------------------------------------------------------------------------- /ds-bifurcation-diagram-numerical-logistic-map.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def update(): 13 | global x, result 14 | x = r * x * (1 - x) 15 | 16 | def plot_asymptotic_states(): 17 | initialize() 18 | for t in range(100): # first 100 steps are discarded 19 | update() 20 | for t in range(100): # second 100 steps are collected 21 | update() 22 | observe() 23 | plot([r] * 100, result, 'b.', alpha = 0.3) 24 | 25 | for r in arange(0, 4, 0.01): 26 | plot_asymptotic_states() 27 | 28 | xlabel('r') 29 | ylabel('x') 30 | show() 31 | -------------------------------------------------------------------------------- /dynamic-randomwalk.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of particles 5 | sd = 0.1 # standard deviation of Gaussian noise 6 | 7 | def initialize(): 8 | global xlist, ylist 9 | xlist = [] 10 | ylist = [] 11 | for i in range(n): 12 | xlist.append(normal(0, 1)) 13 | ylist.append(normal(0, 1)) 14 | 15 | def observe(): 16 | global xlist, ylist 17 | cla() 18 | plot(xlist, ylist, '.', alpha = 0.2) 19 | axis('image') 20 | axis([-20, 20, -20, 20]) 21 | 22 | def update(): 23 | global xlist, ylist 24 | for i in range(n): 25 | xlist[i] += normal(0, sd) 26 | ylist[i] += normal(0, sd) 27 | 28 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 29 | -------------------------------------------------------------------------------- /ca-graph-based-phasespace-pie.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.DiGraph() 5 | 6 | r = 2 7 | L = 9 8 | 9 | def config(x): 10 | return [1 if x & 2**i > 0 else 0 for i in range(L - 1, -1, -1)] 11 | 12 | def cf_number(cf): 13 | return sum([cf[L - 1 - i] * 2**i for i in range(L)]) 14 | 15 | def update(cf): 16 | nextcf = [0] * L 17 | for x in range(L): 18 | count = 0 19 | for dx in range(-r, r + 1): 20 | count += cf[(x + dx) % L] 21 | nextcf[x] = 1 if count > (2 * r + 1) * 0.5 else 0 22 | return nextcf 23 | 24 | for x in range(2**L): 25 | g.add_edge(x, cf_number(update(config(x)))) 26 | 27 | ccs = list(nx.connected_components(g.to_undirected())) 28 | pie([len(cc) for cc in ccs]) 29 | 30 | show() 31 | -------------------------------------------------------------------------------- /net-LDR.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.karate_club_graph() 5 | n = g.number_of_nodes() 6 | m = g.number_of_edges() 7 | L = nx.average_shortest_path_length(g) 8 | D = nx.diameter(g) 9 | R = nx.radius(g) 10 | 11 | Ldiffs = [] 12 | Ddiffs = [] 13 | Rdiffs = [] 14 | 15 | for i in range(500): 16 | g2 = nx.gnm_random_graph(n, m) 17 | if nx.is_connected(g2): 18 | Ldiffs.append(nx.average_shortest_path_length(g2) - L) 19 | Ddiffs.append(nx.diameter(g2) - D) 20 | Rdiffs.append(nx.radius(g2) - R) 21 | 22 | subplot(1, 3, 1) 23 | hist(Ldiffs) 24 | title('L diff') 25 | 26 | subplot(1, 3, 2) 27 | hist(Ddiffs) 28 | title('D diff') 29 | 30 | subplot(1, 3, 3) 31 | hist(Rdiffs) 32 | title('R diff') 33 | 34 | tight_layout() 35 | show() 36 | -------------------------------------------------------------------------------- /net-randomwalk.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, loc 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['count'] = 0 12 | loc = 0 13 | g.nodes[loc]['count'] += 1 14 | 15 | def observe(): 16 | global g, loc 17 | cla() 18 | nx.draw(g, pos = g.pos, node_color = [g.nodes[i]['count'] for i in g.nodes], 19 | cmap = cm.binary, edgecolors = 'k') 20 | nx.draw_networkx_nodes(g, pos = g.pos, nodelist = [loc], node_color = 'r') 21 | 22 | def update(): 23 | global g, loc 24 | loc = choice(list(g.neighbors(loc))) 25 | g.nodes[loc]['count'] += 1 26 | 27 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 28 | -------------------------------------------------------------------------------- /dynamic-randomwalk-standalone.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | n = 1000 # number of particles 4 | sd = 0.1 # standard deviation of Gaussian noise 5 | 6 | def initialize(): 7 | global xlist, ylist 8 | xlist = [] 9 | ylist = [] 10 | for i in range(n): 11 | xlist.append(normal(0, 1)) 12 | ylist.append(normal(0, 1)) 13 | 14 | def observe(): 15 | global xlist, ylist 16 | cla() 17 | plot(xlist, ylist, '.', alpha = 0.2) 18 | axis('image') 19 | axis([-20, 20, -20, 20]) 20 | savefig(str(t) + '.png') 21 | 22 | def update(): 23 | global xlist, ylist 24 | for i in range(n): 25 | xlist[i] += normal(0, sd) 26 | ylist[i] += normal(0, sd) 27 | 28 | t = 0 29 | initialize() 30 | observe() 31 | for t in range(1, 100): 32 | update() 33 | observe() 34 | -------------------------------------------------------------------------------- /ds-predator-prey-continuous.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = b = c = d = 1.0 4 | Dt = 0.001 5 | 6 | def initialize(): 7 | global x, xresult, y, yresult, t, timesteps 8 | x = y = 0.1 9 | xresult = [x] 10 | yresult = [y] 11 | t = 0. 12 | timesteps = [t] 13 | 14 | def observe(): 15 | global x, xresult, y, yresult, t, timesteps 16 | xresult.append(x) 17 | yresult.append(y) 18 | timesteps.append(t) 19 | 20 | def update(): 21 | global x, xresult, y, yresult, t, timesteps 22 | nextx = x + (a * x - b * x * y) * Dt 23 | nexty = y + (- c * y + d * x * y) * Dt 24 | x, y = nextx, nexty 25 | t = t + Dt 26 | 27 | initialize() 28 | while t < 50.: 29 | update() 30 | observe() 31 | 32 | plot(timesteps, xresult, 'b') 33 | plot(timesteps, yresult, 'g:') 34 | show() 35 | -------------------------------------------------------------------------------- /ds-SIR-continuous.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = 1.0 # infection rate 4 | b = 0.2 # recovery rate 5 | 6 | Dt = 0.001 7 | 8 | def initialize(): 9 | global S, I, t, Sdata, Idata, tdata 10 | S, I, t = 0.999, 0.001, 0. 11 | Sdata, Idata, tdata = [S], [I], [t] 12 | 13 | def observe(): 14 | global S, I, t, Sdata, Idata, tdata 15 | Sdata.append(S) 16 | Idata.append(I) 17 | tdata.append(t) 18 | 19 | def update(): 20 | global S, I, t, Sdata, Idata, tdata 21 | nextS = S + (- a * S * I) * Dt 22 | nextI = I + (a * S * I - b * I) * Dt 23 | S, I = nextS, nextI 24 | t = t + Dt 25 | 26 | initialize() 27 | while t < 50.: 28 | update() 29 | observe() 30 | 31 | plot(tdata, Sdata, 'c', label = 'Susceptible') 32 | plot(tdata, Idata, 'r', label = 'Infected') 33 | legend() 34 | show() 35 | -------------------------------------------------------------------------------- /net-voter.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | k = 4 7 | 8 | def initialize(): 9 | global g 10 | g = nx.karate_club_graph() 11 | g.pos = nx.spring_layout(g) 12 | for i in g.nodes: 13 | g.nodes[i]['state'] = choice(range(k)) 14 | 15 | def observe(): 16 | global g 17 | cla() 18 | nx.draw(g, cmap = cm.rainbow, vmin = 0, vmax = k - 1, 19 | node_color = [g.nodes[i]['state'] for i in g.nodes], 20 | pos = g.pos) 21 | 22 | def update(): 23 | global g 24 | listener = choice(list(g.nodes)) 25 | nbs = list(g.neighbors(listener)) 26 | if nbs != []: 27 | speaker = choice(nbs) 28 | g.nodes[listener]['state'] = g.nodes[speaker]['state'] 29 | 30 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 31 | -------------------------------------------------------------------------------- /net-networkx-test1.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | 3 | # creating a new empty Graph object 4 | g = nx.Graph() 5 | 6 | # adding a node named 'John' 7 | g.add_node('John') 8 | 9 | # adding a bunch of nodes at once 10 | g.add_nodes_from(['Josh', 'Jane', 'Jess', 'Jack']) 11 | 12 | # adding an edge between 'John' and 'Jane' 13 | g.add_edge('John', 'Jane') 14 | 15 | # adding a bunch of edges at once 16 | g.add_edges_from([('Jess', 'Josh'), ('John', 'Jack'), ('Jack', 'Jane')]) 17 | 18 | # adding more edges 19 | # undefined nodes will be created automatically 20 | g.add_edges_from([('Jess', 'Jill'), ('Jill', 'Jeff'), ('Jeff', 'Jane')]) 21 | 22 | # removing the edge between 'John' and 'Jane' 23 | g.remove_edge('John', 'Jane') 24 | 25 | # removing the node 'John' 26 | # all edges connected to that node will be removed too 27 | g.remove_node('John') 28 | -------------------------------------------------------------------------------- /ds-phasespace-drawing-exercise.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(x0, y0): 4 | global x, y, xresult, yresult 5 | x = x0 6 | y = y0 7 | xresult = [x] 8 | yresult = [y] 9 | 10 | def observe(): 11 | global x, y, xresult, yresult 12 | xresult.append(x) 13 | yresult.append(y) 14 | 15 | def update(): 16 | global x, y, xresult, yresult 17 | nextx = x + 0.1 * (x - x * y) 18 | nexty = y + 0.1 * (y - x * y) 19 | x, y = nextx, nexty 20 | 21 | for x0 in arange(0, 2, .1): 22 | for y0 in arange(0, 2, .1): 23 | initialize(x0, y0) 24 | for t in range(30): 25 | update() 26 | observe() 27 | plot(xresult, yresult, 'b') 28 | 29 | axis([0, 2, 0, 2]) ### added to zoom in the area within which 30 | ### initial states were varied 31 | show() 32 | -------------------------------------------------------------------------------- /net-ccdfs-loglog.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | n = 1000 5 | er = nx.erdos_renyi_graph(n, 0.01) 6 | ws = nx.watts_strogatz_graph(n, 10, 0.01) 7 | ba = nx.barabasi_albert_graph(n, 5) 8 | 9 | Pk = [float(x) / n for x in nx.degree_histogram(er)] 10 | domain = range(len(Pk)) 11 | ccdf = [sum(Pk[k:]) for k in domain] 12 | loglog(domain, ccdf, '-', label = 'Erdos-Renyi') 13 | 14 | Pk = [float(x) / n for x in nx.degree_histogram(ws)] 15 | domain = range(len(Pk)) 16 | ccdf = [sum(Pk[k:]) for k in domain] 17 | loglog(domain, ccdf, '--', label = 'Watts-Strogatz') 18 | 19 | Pk = [float(x) / n for x in nx.degree_histogram(ba)] 20 | domain = range(len(Pk)) 21 | ccdf = [sum(Pk[k:]) for k in domain] 22 | loglog(domain, ccdf, ':', label = 'Barabasi-Albert') 23 | 24 | xlabel("$k'$") 25 | ylabel("$P(k \geq k')$") 26 | legend() 27 | show() 28 | -------------------------------------------------------------------------------- /ds-cobweb-plot-exercise.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | r = 2.5 4 | K = 1. 5 | 6 | def initialize(): 7 | global N, result 8 | N = 0.1 9 | result = [N] 10 | 11 | def observe(): 12 | global N, result 13 | result.append(N) 14 | 15 | def f(N): 16 | return N + r * N * (1. - N / K) 17 | 18 | def update(): 19 | global N, result 20 | N = f(N) 21 | 22 | initialize() 23 | for t in range(30): 24 | update() 25 | observe() 26 | 27 | Nmin, Nmax = 0, 1.4 28 | plot([Nmin, Nmax], [Nmin, Nmax], 'k') 29 | 30 | rng = linspace(Nmin, Nmax, 101) 31 | plot(rng, [f(N) for N in rng], 'k') 32 | 33 | horizontal = [result[0]] 34 | vertical = [result[0]] 35 | for N in result[1:]: 36 | horizontal.append(vertical[-1]) 37 | vertical.append(N) 38 | horizontal.append(N) 39 | vertical.append(N) 40 | plot(horizontal, vertical, 'b') 41 | 42 | show() 43 | -------------------------------------------------------------------------------- /net-exponent-estimation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | from scipy import stats as st 4 | 5 | n = 10000 6 | ba = nx.barabasi_albert_graph(n, 5) 7 | Pk = [float(x) / n for x in nx.degree_histogram(ba)] 8 | domain = range(len(Pk)) 9 | ccdf = [sum(Pk[k:]) for k in domain] 10 | 11 | logkdata = [] 12 | logPdata = [] 13 | prevP = ccdf[0] 14 | for k in domain: 15 | P = ccdf[k] 16 | if P != prevP: 17 | logkdata.append(log(k)) 18 | logPdata.append(log(P)) 19 | prevP = P 20 | 21 | a, b, r, p, err = st.linregress(logkdata, logPdata) 22 | print("Estimated CCDF: P(k >= k') =", exp(b), "* k'^", a) 23 | print('r =', r) 24 | print('p-value =', p) 25 | 26 | plot(logkdata, logPdata, 'o') 27 | kmin, kmax = xlim() 28 | plot([kmin, kmax],[a * kmin + b, a * kmax + b]) 29 | xlabel("$\log \, k'$") 30 | ylabel("$\log \, P(k \geq k')$") 31 | show() 32 | -------------------------------------------------------------------------------- /abm-randomwalk.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | populationSize = 100 5 | noiseLevel = 1 6 | 7 | def initialize(): 8 | global time, agents 9 | 10 | time = 0 11 | 12 | agents = [] 13 | for i in range(populationSize): 14 | newAgent = [normal(0, 1), normal(0, 1)] 15 | agents.append(newAgent) 16 | 17 | def observe(): 18 | cla() 19 | x = [ag[0] for ag in agents] 20 | y = [ag[1] for ag in agents] 21 | plot(x, y, 'bo', alpha = 0.2) 22 | axis('scaled') 23 | axis([-100, 100, -100, 100]) 24 | title('t = ' + str(time)) 25 | 26 | def update(): 27 | global time, agents 28 | 29 | time += 1 30 | 31 | for ag in agents: 32 | ag[0] += normal(0, noiseLevel) 33 | ag[1] += normal(0, noiseLevel) 34 | 35 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 36 | -------------------------------------------------------------------------------- /ds-van-der-Pol-Hopf-bifurcation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | Dt = 0.01 4 | 5 | def initialize(): 6 | global x, xresult, y, yresult 7 | x = y = 0.1 8 | xresult = [x] 9 | yresult = [y] 10 | 11 | def observe(): 12 | global x, xresult, y, yresult 13 | xresult.append(x) 14 | yresult.append(y) 15 | 16 | def update(): 17 | global x, xresult, y, yresult 18 | nextx = x + y * Dt 19 | nexty = y + (-r * (x**2 - 1) * y - x) * Dt 20 | x, y = nextx, nexty 21 | 22 | def plot_phase_space(): 23 | initialize() 24 | for t in range(10000): 25 | update() 26 | observe() 27 | plot(xresult, yresult) 28 | axis('image') 29 | axis([-3, 3, -3, 3]) 30 | title('r = ' + str(r)) 31 | 32 | rs = [-1, -0.1, 0, .1, 1] 33 | for i in range(len(rs)): 34 | subplot(1, len(rs), i + 1) 35 | r = rs[i] 36 | plot_phase_space() 37 | 38 | tight_layout() 39 | show() 40 | -------------------------------------------------------------------------------- /net-layouts.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.karate_club_graph() 5 | 6 | subplot(2, 3, 1) 7 | nx.draw_spring(g) 8 | axis('image') 9 | title('spring layout') 10 | 11 | subplot(2, 3, 2) 12 | nx.draw_random(g) 13 | axis('image') 14 | title('random layout') 15 | 16 | subplot(2, 3, 3) 17 | nx.draw_circular(g) 18 | axis('image') 19 | title('circular layout') 20 | 21 | subplot(2, 3, 4) 22 | nx.draw_spectral(g) 23 | axis('image') 24 | title('spectral layout') 25 | 26 | subplot(2, 3, 5) 27 | shells = [[0, 1, 2, 32, 33], 28 | [3, 5, 6, 7, 8, 13, 23, 27, 29, 30, 31], 29 | [4, 9, 10, 11, 12, 14, 15, 16, 17, 18, 30 | 19, 20, 21, 22, 24, 25, 26, 28]] 31 | nx.draw_shell(g, nlist = shells) 32 | axis('image') 33 | title('shell layout') 34 | 35 | subplot(2, 3, 6) 36 | nx.draw_kamada_kawai(g) 37 | axis('image') 38 | title('Kamada-Kawai layout') 39 | 40 | tight_layout() 41 | show() 42 | -------------------------------------------------------------------------------- /ca-graph-based-phasespace.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.DiGraph() 5 | 6 | r = 2 7 | L = 9 8 | 9 | def config(x): 10 | return [1 if x & 2**i > 0 else 0 for i in range(L - 1, -1, -1)] 11 | 12 | def cf_number(cf): 13 | return sum([cf[L - 1 - i] * 2**i for i in range(L)]) 14 | 15 | def update(cf): 16 | nextcf = [0] * L 17 | for x in range(L): 18 | count = 0 19 | for dx in range(-r, r + 1): 20 | count += cf[(x + dx) % L] 21 | nextcf[x] = 1 if count > (2 * r + 1) * 0.5 else 0 22 | return nextcf 23 | 24 | for x in range(2**L): 25 | g.add_edge(x, cf_number(update(config(x)))) 26 | 27 | ccs = list(nx.connected_components(g.to_undirected())) 28 | n = len(ccs) 29 | w = ceil(sqrt(n)) 30 | h = ceil(n / w) 31 | for i in range(n): 32 | subplot(int(h), int(w), i + 1) 33 | nx.draw(nx.subgraph(g, ccs[i]), with_labels = True) 34 | 35 | show() 36 | -------------------------------------------------------------------------------- /net-percolation-experiment-animated.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | n = 1000 7 | 8 | def initialize(): 9 | global g, lcc 10 | g = nx.empty_graph(n) 11 | g.pos = nx.random_layout(g) 12 | lcc = [len(max(nx.connected_components(g), key = len))] 13 | 14 | def observe(): 15 | subplot(1, 2, 1) 16 | cla() 17 | nx.draw(g, g.pos, node_size = 1) 18 | axis('image') 19 | subplot(1, 2, 2) 20 | cla() 21 | plot(lcc) 22 | xlabel('# of edges added') 23 | ylabel('Size of LCC') 24 | tight_layout() 25 | 26 | def update(): 27 | global g, lcc 28 | i, j = choice(g.nodes, 2, replace = False) 29 | g.add_edge(i, j) 30 | g.pos = nx.spring_layout(g, pos = g.pos, iterations = 2) 31 | lcc.append(len(max(nx.connected_components(g), key = len))) 32 | 33 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 34 | -------------------------------------------------------------------------------- /ca-cobweb-plot-for-rga.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.5 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def f(x): 13 | return x**4 + 4*x**3*(1-x) + 4*x**2*(1-x)**2 14 | 15 | def update(): 16 | global x, result 17 | x = f(x) 18 | 19 | initialize() 20 | for t in range(30): 21 | update() 22 | observe() 23 | 24 | ### drawing diagonal line 25 | xmin, xmax = 0, 1 26 | plot([xmin, xmax], [xmin, xmax], 'k') 27 | 28 | ### drawing curve 29 | rng = linspace(xmin, xmax, 101) 30 | plot(rng, [f(x) for x in rng], 'k') 31 | 32 | ### drawing trajectory 33 | horizontal = [result[0]] 34 | vertical = [result[0]] 35 | for x in result[1:]: 36 | horizontal.append(vertical[-1]) 37 | vertical.append(x) 38 | horizontal.append(x) 39 | vertical.append(x) 40 | plot(horizontal, vertical, 'b') 41 | 42 | show() 43 | -------------------------------------------------------------------------------- /ca-cobweb-plot-for-mfa.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.4 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def f(x): 13 | return 70*x**9 - 315*x**8 + 540*x**7 - 420*x**6 + 126*x**5 14 | 15 | def update(): 16 | global x, result 17 | x = f(x) 18 | 19 | initialize() 20 | for t in range(30): 21 | update() 22 | observe() 23 | 24 | ### drawing diagonal line 25 | xmin, xmax = 0, 1 26 | plot([xmin, xmax], [xmin, xmax], 'k') 27 | 28 | ### drawing curve 29 | rng = linspace(xmin, xmax, 101) 30 | plot(rng, [f(x) for x in rng], 'k') 31 | 32 | ### drawing trajectory 33 | horizontal = [result[0]] 34 | vertical = [result[0]] 35 | for x in result[1:]: 36 | horizontal.append(vertical[-1]) 37 | vertical.append(x) 38 | horizontal.append(x) 39 | vertical.append(x) 40 | plot(horizontal, vertical, 'b') 41 | 42 | show() 43 | -------------------------------------------------------------------------------- /net-drawing-options.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | import networkx as nx 3 | 4 | g = nx.karate_club_graph() 5 | positions = nx.spring_layout(g) 6 | 7 | subplot(3, 2, 1) 8 | nx.draw(g, positions, with_labels = True) 9 | title('showing node names') 10 | 11 | subplot(3, 2, 2) 12 | nx.draw(g, positions, node_shape = '>') 13 | title('using different node shape') 14 | 15 | subplot(3, 2, 3) 16 | nx.draw(g, positions, 17 | node_size = [g.degree(i) * 50 for i in g.nodes]) 18 | title('changing node sizes') 19 | 20 | subplot(3, 2, 4) 21 | nx.draw(g, positions, edge_color = 'pink', 22 | node_color = ['yellow' if i < 17 else 'green' for i in g.nodes]) 23 | title('coloring nodes and edges') 24 | 25 | subplot(3, 2, 5) 26 | nx.draw_networkx_nodes(g, positions) 27 | axis('auto') 28 | title('nodes only') 29 | 30 | subplot(3, 2, 6) 31 | nx.draw_networkx_edges(g, positions) 32 | axis('auto') 33 | title('edges only') 34 | 35 | tight_layout() 36 | show() 37 | -------------------------------------------------------------------------------- /ds-cobweb-plot.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = 1.1 4 | 5 | def initialize(): 6 | global x, result 7 | x = 1. 8 | result = [x] 9 | 10 | def observe(): 11 | global x, result 12 | result.append(x) 13 | 14 | def f(x): ### iterative map is now defined as f(x) 15 | return a * x 16 | 17 | def update(): 18 | global x, result 19 | x = f(x) 20 | 21 | initialize() 22 | for t in range(30): 23 | update() 24 | observe() 25 | 26 | ### drawing diagonal line 27 | xmin, xmax = 0, 20 28 | plot([xmin, xmax], [xmin, xmax], 'k') 29 | 30 | ### drawing curve 31 | rng = linspace(xmin, xmax, 101) 32 | plot(rng, [f(x) for x in rng], 'k') 33 | 34 | ### drawing trajectory 35 | horizontal = [result[0]] 36 | vertical = [result[0]] 37 | for x in result[1:]: 38 | horizontal.append(vertical[-1]) 39 | vertical.append(x) 40 | horizontal.append(x) 41 | vertical.append(x) 42 | plot(horizontal, vertical, 'b') 43 | 44 | show() 45 | -------------------------------------------------------------------------------- /ds-FitzHugh-Nagumo-bifurcation.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a, b, c = 0.7, 0.8, 3. 4 | 5 | Dt = 0.01 6 | 7 | def initialize(): 8 | global x, xresult, y, yresult 9 | x = y = 1. 10 | xresult = [x] 11 | yresult = [y] 12 | 13 | def observe(): 14 | global x, xresult, y, yresult 15 | xresult.append(x) 16 | yresult.append(y) 17 | 18 | def update(): 19 | global x, xresult, y, yresult 20 | nextx = x + c * (x - x**3 / 3 + y + z) * Dt 21 | nexty = y - (x - a + b * y) / c * Dt 22 | x, y = nextx, nexty 23 | 24 | def plot_phase_space(): 25 | initialize() 26 | for t in range(10000): 27 | update() 28 | observe() 29 | plot(xresult, yresult) 30 | axis('image') 31 | axis([-3, 3, -3, 3]) 32 | title('z = ' + str(z)) 33 | 34 | zs = [-2, -1.5, -1., -0.5, 0] 35 | for i in range(len(zs)): 36 | subplot(1, len(zs), i + 1) 37 | z = zs[i] 38 | plot_phase_space() 39 | 40 | tight_layout() 41 | show() 42 | -------------------------------------------------------------------------------- /net-small-world-exercise.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g 8 | g = nx.convert_node_labels_to_integers(nx.grid_2d_graph(10, 10)) 9 | g.pos = nx.spring_layout(g, k = 0.1) 10 | g.count = 0 11 | 12 | def observe(): 13 | global g 14 | cla() 15 | nx.draw(g, pos = g.pos) 16 | 17 | def update(): 18 | global g 19 | g.count += 1 20 | if g.count % 20 == 0: # rewiring once in every 20 steps 21 | nds = list(g.nodes) 22 | i = choice(nds) 23 | if g.degree(i) > 0: 24 | g.remove_edge(i, choice(list(g.neighbors(i)))) 25 | nds.remove(i) 26 | for j in g.neighbors(i): 27 | nds.remove(j) 28 | g.add_edge(i, choice(nds)) 29 | 30 | # simulation of node movement 31 | g.pos = nx.spring_layout(g, pos = g.pos, iterations = 3, k = 0.1) 32 | 33 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 34 | -------------------------------------------------------------------------------- /ca-panic.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 100 # size of space: n x n 5 | p = 0.26 # probability of initially panicky individuals 6 | 7 | def initialize(): 8 | global config, nextconfig 9 | config = zeros([n, n]) 10 | for x in range(n): 11 | for y in range(n): 12 | config[x, y] = 1 if random() < p else 0 13 | nextconfig = zeros([n, n]) 14 | 15 | def observe(): 16 | global config, nextconfig 17 | cla() 18 | imshow(config, vmin = 0, vmax = 1, cmap = cm.binary) 19 | 20 | def update(): 21 | global config, nextconfig 22 | for x in range(n): 23 | for y in range(n): 24 | count = 0 25 | for dx in [-1, 0, 1]: 26 | for dy in [-1, 0, 1]: 27 | count += config[(x + dx) % n, (y + dy) % n] 28 | nextconfig[x, y] = 1 if count >= 4 else 0 29 | config, nextconfig = nextconfig, config 30 | 31 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 32 | -------------------------------------------------------------------------------- /ds-phasespace-drawing-3D.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | from mpl_toolkits.mplot3d import Axes3D 3 | 4 | def initialize(x0, y0, z0): 5 | global x, y, z, xresult, yresult, zresult 6 | x = x0 7 | y = y0 8 | z = z0 9 | xresult = [x] 10 | yresult = [y] 11 | zresult = [z] 12 | 13 | def observe(): 14 | global x, y, z, xresult, yresult, zresult 15 | xresult.append(x) 16 | yresult.append(y) 17 | zresult.append(z) 18 | 19 | def update(): 20 | global x, y, z 21 | nextx = 0.5 * x + y 22 | nexty = -0.5 * x + y 23 | nextz = - x - y + z 24 | x, y, z = nextx, nexty, nextz 25 | 26 | fig = figure() 27 | ax = fig.add_subplot(111, projection='3d') 28 | 29 | for x0 in arange(-2, 2, 1): 30 | for y0 in arange(-2, 2, 1): 31 | for z0 in arange(-2, 2, 1): 32 | initialize(x0, y0, z0) 33 | for t in range(30): 34 | update() 35 | observe() 36 | ax.plot(xresult, yresult, zresult, 'b') 37 | 38 | show() 39 | -------------------------------------------------------------------------------- /net-diffusion.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['state'] = 1 if random() < .5 else 0 12 | nextg = g.copy() 13 | nextg.pos = g.pos 14 | 15 | def observe(): 16 | global g, nextg 17 | cla() 18 | nx.draw(g, cmap = cm.Spectral, vmin = 0, vmax = 1, 19 | node_color = [g.nodes[i]['state'] for i in g.nodes], 20 | pos = g.pos) 21 | 22 | alpha = 1 # diffusion constant 23 | Dt = 0.01 # Delta t 24 | 25 | def update(): 26 | global g, nextg 27 | for i in g.nodes: 28 | ci = g.nodes[i]['state'] 29 | nextg.nodes[i]['state'] = ci + alpha * ( \ 30 | sum([g.nodes[j]['state'] for j in g.neighbors(i)]) \ 31 | - ci * g.degree(i)) * Dt 32 | g, nextg = nextg, g 33 | 34 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 35 | -------------------------------------------------------------------------------- /net-Barabasi-Albert.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | m = 2 # number of edges per new node 7 | 8 | def initialize(): 9 | global g 10 | g = nx.complete_graph(m) 11 | g.pos = nx.spring_layout(g) 12 | 13 | def observe(): 14 | global g 15 | cla() 16 | nx.draw(g, pos = g.pos) 17 | 18 | def update(): 19 | global g 20 | 21 | n = g.number_of_nodes() 22 | degs = dict(g.degree()) 23 | nds = list(degs.keys()) 24 | weights = list(degs.values()) 25 | s = float(sum(weights)) 26 | weights = [w / s for w in weights] if s > 0 else [1. / n for i in range(n)] 27 | targets = choice(nds, size = m, p = weights, replace = False) 28 | 29 | newcomer = max(nds) + 1 30 | for j in targets: 31 | g.add_edge(newcomer, j) 32 | g.pos[newcomer] = (normal(0, 0.1), normal(0, 0.1)) 33 | 34 | g.pos = nx.spring_layout(g, pos = g.pos, iterations = 2) 35 | 36 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 37 | -------------------------------------------------------------------------------- /net-SIS.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['state'] = 1 if random() < .5 else 0 12 | 13 | def observe(): 14 | global g 15 | cla() 16 | nx.draw(g, cmap = cm.Wistia, vmin = 0, vmax = 1, 17 | node_color = [g.nodes[i]['state'] for i in g.nodes], 18 | pos = g.pos) 19 | 20 | p_i = 0.5 # infection probability 21 | p_r = 0.1 # recovery probability 22 | 23 | def update(): 24 | global g 25 | a = choice(list(g.nodes)) 26 | if g.nodes[a]['state'] == 0: # if susceptible 27 | b = choice(list(g.neighbors(a))) 28 | if g.nodes[b]['state'] == 1: # if neighbor b is infected 29 | g.nodes[a]['state'] = 1 if random() < p_i else 0 30 | else: # if infected 31 | g.nodes[a]['state'] = 0 if random() < p_r else 1 32 | 33 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 34 | -------------------------------------------------------------------------------- /net-majority.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['state'] = 1 if random() < .5 else 0 12 | nextg = g.copy() 13 | nextg.pos = g.pos 14 | 15 | def observe(): 16 | global g, nextg 17 | cla() 18 | nx.draw(g, cmap = cm.bwr, vmin = 0, vmax = 1, 19 | node_color = [g.nodes[i]['state'] for i in g.nodes], 20 | pos = g.pos) 21 | 22 | def update(): 23 | global g, nextg 24 | for i in g.nodes: 25 | count = g.nodes[i]['state'] 26 | for j in g.neighbors(i): 27 | count += g.nodes[j]['state'] 28 | ratio = count / (g.degree(i) + 1.0) 29 | nextg.nodes[i]['state'] = 1 if ratio > .5 \ 30 | else 0 if ratio < .5 \ 31 | else 1 if random() < .5 else 0 32 | g, nextg = nextg, g 33 | 34 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 35 | -------------------------------------------------------------------------------- /net-Kuramoto.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['theta'] = 2 * pi * random() 12 | g.nodes[i]['omega'] = 1. + uniform(-0.05, 0.05) 13 | nextg = g.copy() 14 | nextg.pos = g.pos 15 | 16 | def observe(): 17 | global g, nextg 18 | cla() 19 | nx.draw(g, cmap = cm.hsv, vmin = -1, vmax = 1, 20 | node_color = [sin(g.nodes[i]['theta']) for i in g.nodes], 21 | pos = g.pos) 22 | 23 | alpha = 1 # coupling strength 24 | Dt = 0.01 # Delta t 25 | 26 | def update(): 27 | global g, nextg 28 | for i in g.nodes: 29 | theta_i = g.nodes[i]['theta'] 30 | nextg.nodes[i]['theta'] = theta_i + (g.nodes[i]['omega'] + alpha * ( \ 31 | sum([sin(g.nodes[j]['theta'] - theta_i) for j in g.neighbors(i)]) \ 32 | / g.degree(i))) * Dt 33 | g, nextg = nextg, g 34 | 35 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 36 | -------------------------------------------------------------------------------- /net-RBN.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | n = 30 # number of nodes 7 | k = 2 # number of inputs of each node 8 | 9 | def initialize(): 10 | global g 11 | g = nx.DiGraph() 12 | for i in range(n): 13 | for j in choice(range(n), k, replace = False): 14 | g.add_edge(j, i) 15 | g.nodes[i]['state'] = 1 if random() < .5 else 0 16 | lookuptable = choice([0, 1], 2**k) 17 | g.nodes[i]['rule'] = lambda nbs:lookuptable[int("".join(str(x) for x in nbs), 2)] 18 | g.pos = nx.kamada_kawai_layout(g) 19 | 20 | def observe(): 21 | global g 22 | cla() 23 | nx.draw(g, vmin = 0, vmax = 1, pos = g.pos, node_color = [g.nodes[i]['state'] for i in g.nodes]) 24 | 25 | def update(): 26 | global g 27 | for i in g.nodes: 28 | nbs = [g.nodes[j]['state'] for j in g.predecessors(i)] 29 | g.nodes[i]['nextstate'] = g.nodes[i]['rule'](nbs) 30 | for i in g.nodes: 31 | g.nodes[i]['state'] = g.nodes[i]['nextstate'] 32 | 33 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 34 | -------------------------------------------------------------------------------- /net-Kuramoto-desync.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['theta'] = 0.01 * random() 12 | g.nodes[i]['omega'] = 1. + uniform(-0.05, 0.05) 13 | nextg = g.copy() 14 | nextg.pos = g.pos 15 | 16 | def observe(): 17 | global g, nextg 18 | cla() 19 | nx.draw(g, cmap = cm.hsv, vmin = -1, vmax = 1, 20 | node_color = [sin(g.nodes[i]['theta']) for i in g.nodes], 21 | pos = g.pos) 22 | 23 | alpha = 1 # coupling strength 24 | Dt = 0.01 # Delta t 25 | 26 | def update(): 27 | global g, nextg 28 | for i in g.nodes: 29 | theta_i = g.nodes[i]['theta'] 30 | nextg.nodes[i]['theta'] = theta_i + (g.nodes[i]['omega'] + alpha * ( \ 31 | sum([-sin(g.nodes[j]['theta'] - theta_i) for j in g.neighbors(i)]) \ 32 | / g.degree(i))) * Dt 33 | g, nextg = nextg, g 34 | 35 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 36 | -------------------------------------------------------------------------------- /dynamic-randomwalk-pSetter.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of particles 5 | sd = 0.1 # standard deviation of Gaussian noise 6 | 7 | def initialize(): 8 | global xlist, ylist 9 | xlist = [] 10 | ylist = [] 11 | for i in range(n): 12 | xlist.append(normal(0, 1)) 13 | ylist.append(normal(0, 1)) 14 | 15 | def observe(): 16 | global xlist, ylist 17 | cla() 18 | plot(xlist, ylist, '.', alpha = 0.2) 19 | axis('image') 20 | axis([-20, 20, -20, 20]) 21 | 22 | def update(): 23 | global xlist, ylist 24 | for i in range(n): 25 | xlist[i] += normal(0, sd) 26 | ylist[i] += normal(0, sd) 27 | 28 | def num_particles (val = n): 29 | ''' 30 | Number of particles. 31 | Make sure you change this parameter while the simulation is not running, 32 | and reset the simulation before running it. Otherwise it causes an error! 33 | ''' 34 | global n 35 | n = int(val) 36 | return val 37 | 38 | import pycxsimulator 39 | pycxsimulator.GUI(parameterSetters = [num_particles]).start(func=[initialize, observe, update]) 40 | -------------------------------------------------------------------------------- /net-small-world.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | n = 30 # number of nodes 7 | k = 4 # number of neighbors of each node 8 | 9 | def initialize(): 10 | global g 11 | g = nx.Graph() 12 | for i in range(n): 13 | for j in range(1, int(k/2) + 1): 14 | g.add_edge(i, (i + j) % n) 15 | g.add_edge(i, (i - j) % n) 16 | g.pos = nx.spring_layout(g) 17 | g.count = 0 18 | 19 | def observe(): 20 | global g 21 | cla() 22 | nx.draw(g, pos = g.pos) 23 | 24 | def update(): 25 | global g 26 | g.count += 1 27 | if g.count % 20 == 0: # rewiring once in every 20 steps 28 | nds = list(g.nodes) 29 | i = choice(nds) 30 | if g.degree(i) > 0: 31 | g.remove_edge(i, choice(list(g.neighbors(i)))) 32 | nds.remove(i) 33 | for j in g.neighbors(i): 34 | nds.remove(j) 35 | g.add_edge(i, choice(nds)) 36 | 37 | # simulation of node movement 38 | g.pos = nx.spring_layout(g, pos = g.pos, iterations = 3) 39 | 40 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 41 | -------------------------------------------------------------------------------- /ds-period-doubling-bifurcation-cobweb.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | def initialize(): 4 | global x, result 5 | x = 0.1 6 | result = [x] 7 | 8 | def observe(): 9 | global x, result 10 | result.append(x) 11 | 12 | def f(x): 13 | return x + r - x**2 14 | 15 | def update(): 16 | global x, result 17 | x = f(x) 18 | 19 | def plot_phase_space(): 20 | initialize() 21 | for t in range(100): 22 | update() 23 | observe() 24 | xmin = 0 25 | xmax = 2 26 | plot([xmin, xmax], [xmin, xmax], 'k') 27 | 28 | rng = linspace(xmin, xmax, 101) 29 | plot(rng, [f(x) for x in rng], 'k') 30 | 31 | horizontal = [result[0]] 32 | vertical = [result[0]] 33 | for x in result: 34 | horizontal.append(vertical[-1]) 35 | vertical.append(x) 36 | horizontal.append(x) 37 | vertical.append(x) 38 | plot(horizontal, vertical, 'b') 39 | axis('image') 40 | axis([0, 2, 0, 2]) 41 | title('r = ' + str(r)) 42 | 43 | rs = [0.1, 0.5, 1.0, 1.1, 1.5, 1.6] 44 | for i in range(len(rs)): 45 | subplot(2, 3, i + 1) 46 | r = rs[i] 47 | plot_phase_space() 48 | 49 | tight_layout() 50 | show() 51 | -------------------------------------------------------------------------------- /abm-swarm.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | class agent: 5 | def __init__(self): 6 | self.x = rand(2) 7 | self.v = rand(2) - array([0.5, 0.5]) 8 | self.xs = [self.x[0]] 9 | self.ys = [self.x[1]] 10 | def accelerate(self): 11 | c = mean([a.x for a in agents]) 12 | f = 0.5 * (c - self.x) / norm(c - self.x) 13 | self.v += f # accelerating toward the center of mass 14 | def move(self): 15 | self.x += self.v 16 | self.xs.append(self.x[0]) 17 | self.ys.append(self.x[1]) 18 | if len(self.xs) > 10: 19 | del self.xs[0] 20 | del self.ys[0] 21 | 22 | def initialize(): 23 | global agents 24 | agents = [agent() for _ in range(50)] 25 | 26 | def observe(): 27 | cla() 28 | for a in agents: 29 | plot([a.x[0]], [a.x[1]], 'g.') # drawing current position 30 | plot(a.xs, a.ys, 'b', alpha = 0.1) # drawing trajectory as well 31 | axis('scaled') 32 | 33 | def update(): 34 | global agents 35 | for a in agents: 36 | a.accelerate() 37 | for a in agents: 38 | a.move() 39 | 40 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 41 | -------------------------------------------------------------------------------- /ds-SIR-continuous-multiple-strains.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | a = [1.1, 1.2, 1.3] # infection rates 4 | b = [0.5, 0.4, 0.3] # recovery rates 5 | m = 0.00001 # mutation rate 6 | 7 | Dt = 0.001 8 | 9 | def initialize(): 10 | global S, I, t, Sdata, Idata, tdata 11 | S, I, t = [0.999, 1., 1.], [0.001, 0., 0.], 0. 12 | Sdata, Idata, tdata = [S], [I], [t] 13 | 14 | def observe(): 15 | global S, I, t, Sdata, Idata, tdata 16 | Sdata.append(S) 17 | Idata.append(I) 18 | tdata.append(t) 19 | 20 | def update(): 21 | global S, I, t, Sdata, Idata, tdata 22 | nextS = [S[k] - a[k] * S[k] * I[k] * Dt for k in range(3)] 23 | nextI = [I[k] + (a[k] * S[k] * I[k] - b[k] * I[k] + (m * I[k-1] if k > 0 else 0) - (m * I[k] if k < 2 else 0)) * Dt for k in range(3)] 24 | S, I = nextS, nextI 25 | t = t + Dt 26 | 27 | initialize() 28 | while t < 50.: 29 | update() 30 | observe() 31 | 32 | plot(tdata, mean(array(Sdata), axis = 1), 'c', label = 'Susceptible') 33 | plot(tdata, array(Idata)[:, 0], 'r', label = 'Infected: Strain 1') 34 | plot(tdata, array(Idata)[:, 1], 'm', label = 'Infected: Strain 2') 35 | plot(tdata, array(Idata)[:, 2], 'g', label = 'Infected: Strain 3') 36 | legend() 37 | show() 38 | -------------------------------------------------------------------------------- /net-SIS-synchronous-update.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['state'] = 1 if random() < .5 else 0 12 | nextg = g.copy() 13 | nextg.pos = g.pos 14 | 15 | def observe(): 16 | global g 17 | cla() 18 | nx.draw(g, cmap = cm.Wistia, vmin = 0, vmax = 1, 19 | node_color = [g.nodes[i]['state'] for i in g.nodes], 20 | pos = g.pos) 21 | 22 | p_i = 0.5 # infection probability 23 | p_r = 0.5 # recovery probability 24 | 25 | def update(): 26 | global g, nextg 27 | for a in g.nodes: 28 | if g.nodes[a]['state'] == 0: # if susceptible 29 | nextg.nodes[a]['state'] = 0 30 | for b in g.neighbors(a): 31 | if g.nodes[b]['state'] == 1: # if neighbor b is infected 32 | if random() < p_i: 33 | nextg.nodes[a]['state'] = 1 34 | else: # if infected 35 | nextg.nodes[a]['state'] = 0 if random() < p_r else 1 36 | nextg, g = g, nextg 37 | 38 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 39 | -------------------------------------------------------------------------------- /net-SIS-adaptive.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['state'] = 1 if random() < .5 else 0 12 | 13 | def observe(): 14 | global g 15 | cla() 16 | nx.draw(g, cmap = cm.Wistia, vmin = 0, vmax = 1, 17 | node_color = [g.nodes[i]['state'] for i in g.nodes], 18 | pos = g.pos) 19 | 20 | p_i = 0.5 # infection probability 21 | p_r = 0.1 # recovery probability 22 | p_s = 0.5 # severance probability 23 | 24 | def update(): 25 | global g 26 | a = choice(list(g.nodes)) 27 | if g.nodes[a]['state'] == 0: # if susceptible 28 | if g.degree(a) > 0: 29 | b = choice(list(g.neighbors(a))) 30 | if g.nodes[b]['state'] == 1: # if neighbor b is infected 31 | if random() < p_s: 32 | g.remove_edge(a, b) 33 | else: 34 | g.nodes[a]['state'] = 1 if random() < p_i else 0 35 | else: # if infected 36 | g.nodes[a]['state'] = 0 if random() < p_r else 1 37 | 38 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 39 | -------------------------------------------------------------------------------- /abm-segregation-continuous.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of agents 5 | r = 0.1 # neighborhood radius 6 | th = 0.5 # threshold for moving 7 | 8 | class agent: 9 | pass 10 | 11 | def initialize(): 12 | global agents 13 | agents = [] 14 | for i in range(n): 15 | ag = agent() 16 | ag.type = randint(2) 17 | ag.x = random() 18 | ag.y = random() 19 | agents.append(ag) 20 | 21 | def observe(): 22 | global agents 23 | cla() 24 | red = [ag for ag in agents if ag.type == 0] 25 | blue = [ag for ag in agents if ag.type == 1] 26 | plot([ag.x for ag in red], [ag.y for ag in red], 'ro') 27 | plot([ag.x for ag in blue], [ag.y for ag in blue], 'bo') 28 | axis('image') 29 | axis([0, 1, 0, 1]) 30 | 31 | def update(): 32 | global agents 33 | ag = choice(agents) 34 | neighbors = [nb for nb in agents 35 | if (ag.x - nb.x)**2 + (ag.y - nb.y)**2 < r**2 and nb != ag] 36 | if len(neighbors) > 0: 37 | q = len([nb for nb in neighbors if nb.type == ag.type]) \ 38 | / float(len(neighbors)) 39 | if q < th: 40 | ag.x, ag.y = random(), random() 41 | 42 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 43 | -------------------------------------------------------------------------------- /ds-Lorenz-equations-Poincare-section.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | s = 10. 4 | r = 30. 5 | b = 3. 6 | Dt = 0.01 7 | 8 | def initialize(): 9 | global x, xresult, y, yresult, z, zresult, t, timesteps 10 | x = y = z = 1. 11 | xresult = [x] 12 | yresult = [y] 13 | zresult = [z] 14 | t = 0. 15 | timesteps = [t] 16 | 17 | def observe(): 18 | global x, xresult, y, yresult, z, zresult, t, timesteps 19 | xresult.append(x) 20 | yresult.append(y) 21 | zresult.append(z) 22 | timesteps.append(t) 23 | 24 | def update(): 25 | global x, xresult, y, yresult, z, zresult, t, timesteps 26 | nextx = x + (s * (y - x)) * Dt 27 | nexty = y + (r * x - y - x * z) * Dt 28 | nextz = z + (x * y - b * z) * Dt 29 | x, y, z = nextx, nexty, nextz 30 | t = t + Dt 31 | 32 | initialize() 33 | while t < 100.: 34 | update() 35 | observe() 36 | 37 | sectionY = [] 38 | sectionZ = [] 39 | for i in range(len(xresult) - 1): 40 | x0 = xresult[i] 41 | x1 = xresult[i+1] 42 | if x0 * x1 < 0: 43 | sectionY.append((yresult[i] + yresult[i+1]) / 2) 44 | sectionZ.append((zresult[i] + zresult[i+1]) / 2) 45 | 46 | plot(sectionY, sectionZ, 'bo', alpha = 0.5) 47 | xlabel('y') 48 | ylabel('z') 49 | title('Poincare section at x = 0') 50 | show() 51 | -------------------------------------------------------------------------------- /net-Hopfield.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | memorized_letters = [ 7 | # Letter 'C' 8 | [-1, 1, 1, 1, 9 | 1, -1, -1, -1, 10 | 1, -1, -1, -1, 11 | -1, 1, 1, 1], 12 | # Letter 'P' 13 | [1, 1, 1, -1, 14 | 1, -1, -1, 1, 15 | 1, 1, 1, -1, 16 | 1, -1, -1, -1] 17 | ] 18 | 19 | def initialize(): 20 | global g 21 | g = nx.complete_graph(4 * 4) 22 | g.pos = {} 23 | for x in range(4): 24 | for y in range(4): 25 | g.pos[y * 4 + x] = (x, -y) 26 | for i, j in g.edges: 27 | g.edges[i, j]['weight'] = sum([letter[i] * letter[j] for letter in memorized_letters]) 28 | for i in g.nodes: 29 | g.nodes[i]['state'] = choice([-1, 1]) 30 | 31 | def observe(): 32 | global g 33 | cla() 34 | nx.draw(g, pos = g.pos, cmap = cm.winter, vmin = -1, vmax = 1, 35 | node_color = [g.nodes[i]['state'] for i in g.nodes]) 36 | axis('image') 37 | 38 | def update(): 39 | global g 40 | i = choice(list(g.nodes)) 41 | s = sum([g.edges[i, j]['weight'] * g.nodes[j]['state'] for j in g.neighbors(i)]) 42 | g.nodes[i]['state'] = 1 if s > 0 else -1 if s < 0 else g.nodes[i]['state'] 43 | 44 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 45 | -------------------------------------------------------------------------------- /pde-transport-imshow.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 100 # size of grid: n * n 5 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 6 | Dt = 0.01 # temporal resolution 7 | 8 | wx, wy = -0.01, 0.03 # constant velocity of movement 9 | 10 | xvalues, yvalues = meshgrid(arange(0, 1, Dh), arange(0, 1, Dh)) 11 | 12 | def initialize(): 13 | global config, nextconfig 14 | # initial configuration 15 | config = exp(-((xvalues - 0.5)**2 + (yvalues - 0.5)**2) / (0.2**2)) 16 | nextconfig = zeros([n, n]) 17 | 18 | def observe(): 19 | global config, nextconfig 20 | cla() 21 | imshow(config, vmin = 0, vmax = 1) 22 | 23 | def update(): 24 | global config, nextconfig 25 | for x in range(n): 26 | for y in range(n): 27 | # state-transition function 28 | nextconfig[x, y] = config[x, y] - ( wx * config[(x+1)%n, y] 29 | - wx * config[(x-1)%n, y] 30 | + wy * config[x, (y+1)%n] 31 | - wy * config[x, (y-1)%n])\ 32 | * Dt/(2*Dh) 33 | 34 | config, nextconfig = nextconfig, config 35 | 36 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 37 | -------------------------------------------------------------------------------- /ds-Lorenz-equations.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | from mpl_toolkits.mplot3d import Axes3D 3 | 4 | s = 10. 5 | r = 30. 6 | b = 3. 7 | Dt = 0.01 8 | 9 | def initialize(): 10 | global x, xresult, y, yresult, z, zresult, t, timesteps 11 | x = y = z = 1. 12 | xresult = [x] 13 | yresult = [y] 14 | zresult = [z] 15 | t = 0. 16 | timesteps = [t] 17 | 18 | def observe(): 19 | global x, xresult, y, yresult, z, zresult, t, timesteps 20 | xresult.append(x) 21 | yresult.append(y) 22 | zresult.append(z) 23 | timesteps.append(t) 24 | 25 | def update(): 26 | global x, xresult, y, yresult, z, zresult, t, timesteps 27 | nextx = x + (s * (y - x)) * Dt 28 | nexty = y + (r * x - y - x * z) * Dt 29 | nextz = z + (x * y - b * z) * Dt 30 | x, y, z = nextx, nexty, nextz 31 | t = t + Dt 32 | 33 | initialize() 34 | while t < 30.: 35 | update() 36 | observe() 37 | 38 | subplot(3, 1, 1) 39 | plot(timesteps, xresult) 40 | xlabel('t') 41 | ylabel('x') 42 | 43 | subplot(3, 1, 2) 44 | plot(timesteps, yresult) 45 | xlabel('t') 46 | ylabel('y') 47 | 48 | subplot(3, 1, 3) 49 | plot(timesteps, zresult) 50 | xlabel('t') 51 | ylabel('z') 52 | 53 | tight_layout() 54 | 55 | fig = figure() 56 | ax = fig.add_subplot(111, projection='3d') 57 | ax.plot(xresult, yresult, zresult, 'b') 58 | 59 | show() 60 | -------------------------------------------------------------------------------- /net-sync-analysis.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['theta'] = random() 12 | nextg = g.copy() 13 | nextg.pos = g.pos 14 | 15 | def observe(): 16 | global g, nextg 17 | subplot(1, 2, 1) 18 | cla() 19 | nx.draw(g, cmap = cm.hsv, vmin = -1, vmax = 1, 20 | node_color = [sin(g.nodes[i]['theta']) for i in g.nodes], 21 | pos = g.pos) 22 | axis('image') 23 | 24 | subplot(1, 2, 2) 25 | cla() 26 | plot([cos(g.nodes[i]['theta']) for i in g.nodes], 27 | [sin(g.nodes[i]['theta']) for i in g.nodes], '.') 28 | axis('image') 29 | axis([-1.1, 1.1, -1.1, 1.1]) 30 | 31 | tight_layout() 32 | 33 | alpha = 2 # coupling strength 34 | beta = 1 # acceleration rate 35 | Dt = 0.001 # Delta t 36 | 37 | def update(): 38 | global g, nextg 39 | for i in g.nodes: 40 | theta_i = g.nodes[i]['theta'] 41 | nextg.nodes[i]['theta'] = theta_i + (beta * theta_i + alpha * \ 42 | sum([g.nodes[j]['theta'] - theta_i for j in g.neighbors(i)]) \ 43 | ) * Dt 44 | g, nextg = nextg, g 45 | 46 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 47 | -------------------------------------------------------------------------------- /net-small-world-experiment-animated.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | n = 500 7 | r = 3 8 | 9 | def initialize(): 10 | global g, aspl, acc 11 | g = nx.empty_graph(n) 12 | for i in g.nodes: 13 | for j in range(-r, r+1): 14 | if j != 0: 15 | g.add_edge(i, (i+j)%n) 16 | aspl = [nx.average_shortest_path_length(g)] 17 | acc = [nx.average_clustering(g)] 18 | 19 | def observe(): 20 | subplot(1, 3, 1) 21 | cla() 22 | nx.draw_circular(g, node_size = 0) 23 | axis('image') 24 | subplot(1, 3, 2) 25 | cla() 26 | plot(aspl) 27 | xlabel('# of rewiring') 28 | ylabel('Average shortest path length') 29 | subplot(1, 3, 3) 30 | cla() 31 | plot(acc) 32 | xlabel('# of rewiring') 33 | ylabel('Average clustering coefficient') 34 | tight_layout() 35 | 36 | def update(): 37 | global g, aspl, acc 38 | i = choice(g.nodes) 39 | j = choice(list(g.neighbors(i))) 40 | g.remove_edge(i, j) 41 | while True: 42 | j = choice(g.nodes) 43 | if j != i and not g.has_edge(i, j): 44 | break 45 | g.add_edge(i, j) 46 | 47 | aspl.append(nx.average_shortest_path_length(g)) 48 | acc.append(nx.average_clustering(g)) 49 | 50 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 51 | -------------------------------------------------------------------------------- /net-Kuramoto-with-phase.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | g.pos = nx.spring_layout(g) 10 | for i in g.nodes: 11 | g.nodes[i]['theta'] = 2 * pi * random() 12 | g.nodes[i]['omega'] = 1. + uniform(-0.05, 0.05) 13 | nextg = g.copy() 14 | nextg.pos = g.pos 15 | 16 | def observe(): 17 | global g, nextg 18 | 19 | subplot(1, 2, 1) 20 | cla() 21 | nx.draw(g, cmap = cm.hsv, vmin = -1, vmax = 1, 22 | node_color = [sin(g.nodes[i]['theta']) for i in g.nodes], 23 | pos = g.pos) 24 | 25 | subplot(1, 2, 2) 26 | cla() 27 | plot([cos(g.nodes[i]['theta']) for i in g.nodes], 28 | [sin(g.nodes[i]['theta']) for i in g.nodes], '.') 29 | axis('image') 30 | axis([-1.1, 1.1, -1.1, 1.1]) 31 | 32 | tight_layout() 33 | 34 | alpha = 1 # coupling strength 35 | Dt = 0.01 # Delta t 36 | 37 | def update(): 38 | global g, nextg 39 | for i in g.nodes: 40 | theta_i = g.nodes[i]['theta'] 41 | nextg.nodes[i]['theta'] = theta_i + (g.nodes[i]['omega'] + alpha * ( \ 42 | sum([sin(g.nodes[j]['theta'] - theta_i) for j in g.neighbors(i)]) \ 43 | / g.degree(i))) * Dt 44 | g, nextg = nextg, g 45 | 46 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 47 | -------------------------------------------------------------------------------- /pde-population-economy.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | L = 5000. 5 | k = 100. 6 | n = int(L/k) 7 | Dt = 0.1 8 | 9 | def initialize(): 10 | global P, P2, E, E2 11 | P = zeros([n, n]) 12 | E = zeros([n, n]) 13 | for x in range(n): 14 | for y in range(n): 15 | P[x,y] = 0.5 + uniform(-0.1, 0.1) 16 | P2 = zeros([n, n]) 17 | E2 = zeros([n, n]) 18 | 19 | def observe(): 20 | global P, E 21 | 22 | subplot(1, 2, 1) 23 | cla() 24 | imshow(P, vmin = 0, vmax = 1) 25 | title('Population') 26 | 27 | subplot(1, 2, 2) 28 | cla() 29 | imshow(E, vmin = 0, vmax = 5) 30 | title('Economy') 31 | 32 | tight_layout() 33 | 34 | Dp, De, a, b, c = 1250, 250, 600, 1., 0.2 35 | 36 | def update(): 37 | global P, P2, E, E2 38 | for x in range(n): 39 | for y in range(n): 40 | Pc,Pr,Pl,Pt,Pb = P[x,y], P[(x+1)%n,y], P[(x-1)%n,y], P[x,(y+1)%n], P[x,(y-1)%n] 41 | Ec,Er,El,Et,Eb = E[x,y], E[(x+1)%n,y], E[(x-1)%n,y], E[x,(y+1)%n], E[x,(y-1)%n] 42 | lapP = (Pr+Pl+Pt+Pb-4*Pc) / (k**2) 43 | lapE = (Er+El+Et+Eb-4*Ec) / (k**2) 44 | P2[x, y] = Pc + (Dp*lapP - a*(Pc*lapE + (Pr-Pl)*(Er-El)/(4*k**2) + (Pt-Pb)*(Et-Eb)/(4*k**2))) * Dt 45 | E2[x, y] = Ec + (De*lapE + b*Pc - c*Ec) * Dt 46 | P, P2, E, E2 = P2, P, E2, E 47 | 48 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 49 | -------------------------------------------------------------------------------- /ca-gameoflife.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | initProb = 0.2 7 | 8 | def initialize(): 9 | global time, config, nextConfig 10 | 11 | time = 0 12 | 13 | config = zeros([height, width]) 14 | for x in range(width): 15 | for y in range(height): 16 | if random() < initProb: 17 | state = 1 18 | else: 19 | state = 0 20 | config[y, x] = state 21 | 22 | nextConfig = zeros([height, width]) 23 | 24 | def observe(): 25 | cla() 26 | imshow(config, vmin = 0, vmax = 1, cmap = cm.binary) 27 | axis('image') 28 | title('t = ' + str(time)) 29 | 30 | def update(): 31 | global time, config, nextConfig 32 | 33 | time += 1 34 | 35 | for x in range(width): 36 | for y in range(height): 37 | state = config[y, x] 38 | numberOfAlive = 0 39 | for dx in range(-1, 2): 40 | for dy in range(-1, 2): 41 | numberOfAlive += config[(y+dy)%height, (x+dx)%width] 42 | if state == 0 and numberOfAlive == 3: 43 | state = 1 44 | elif state == 1 and (numberOfAlive < 3 or numberOfAlive > 4): 45 | state = 0 46 | nextConfig[y, x] = state 47 | 48 | config, nextConfig = nextConfig, config 49 | 50 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 51 | -------------------------------------------------------------------------------- /pde-transport.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | from mpl_toolkits.mplot3d import Axes3D 5 | 6 | n = 100 # size of grid: n * n 7 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 8 | Dt = 0.01 # temporal resolution 9 | 10 | wx, wy = -0.01, 0.03 # constant velocity of movement 11 | 12 | xvalues, yvalues = meshgrid(arange(0, 1, Dh), arange(0, 1, Dh)) 13 | 14 | def initialize(): 15 | global config, nextconfig 16 | # initial configuration 17 | config = exp(-((xvalues - 0.5)**2 + (yvalues - 0.5)**2) / (0.2**2)) 18 | nextconfig = zeros([n, n]) 19 | 20 | def observe(): 21 | global config, nextconfig 22 | fig = gcf() 23 | ax = fig.add_subplot(111, projection='3d') 24 | ax.cla() 25 | ax.plot_surface(xvalues, yvalues, config, rstride = 5, cstride = 5) 26 | ax.grid(False) 27 | ax.set_zlim(0, 1) 28 | 29 | def update(): 30 | global config, nextconfig 31 | for x in range(n): 32 | for y in range(n): 33 | # state-transition function 34 | nextconfig[x, y] = config[x, y] - ( wx * config[(x+1)%n, y] 35 | - wx * config[(x-1)%n, y] 36 | + wy * config[x, (y+1)%n] 37 | - wy * config[x, (y-1)%n])\ 38 | * Dt/(2*Dh) 39 | 40 | config, nextconfig = nextconfig, config 41 | 42 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 43 | -------------------------------------------------------------------------------- /pde-transport-error.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | from mpl_toolkits.mplot3d import Axes3D 5 | 6 | n = 100 # size of grid: n * n 7 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 8 | Dt = 0.1 # temporal resolution 9 | 10 | wx, wy = -0.01, 0.03 # constant velocity of movement 11 | 12 | xvalues, yvalues = meshgrid(arange(0, 1, Dh), arange(0, 1, Dh)) 13 | 14 | def initialize(): 15 | global config, nextconfig 16 | # initial configuration 17 | config = exp(-((xvalues - 0.5)**2 + (yvalues - 0.5)**2) / (0.2**2)) 18 | nextconfig = zeros([n, n]) 19 | 20 | def observe(): 21 | global config, nextconfig 22 | fig = gcf() 23 | ax = fig.add_subplot(111, projection='3d') 24 | ax.cla() 25 | ax.plot_surface(xvalues, yvalues, config, rstride = 5, cstride = 5) 26 | ax.grid(False) 27 | ax.set_zlim(0, 1) 28 | 29 | def update(): 30 | global config, nextconfig 31 | for x in range(n): 32 | for y in range(n): 33 | # state-transition function 34 | nextconfig[x, y] = config[x, y] - ( wx * config[(x+1)%n, y] 35 | - wx * config[(x-1)%n, y] 36 | + wy * config[x, (y+1)%n] 37 | - wy * config[x, (y-1)%n])\ 38 | * Dt/(2*Dh) 39 | 40 | config, nextconfig = nextconfig, config 41 | 42 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 43 | -------------------------------------------------------------------------------- /ca-majority.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | numberOfStates = 2 7 | r = 1 8 | 9 | def initialize(): 10 | global time, config, nextConfig 11 | 12 | time = 0 13 | 14 | config = zeros([height, width]) 15 | for x in range(width): 16 | for y in range(height): 17 | config[y, x] = randint(numberOfStates) 18 | 19 | nextConfig = zeros([height, width]) 20 | 21 | def observe(): 22 | cla() 23 | imshow(config, vmin = 0, vmax = numberOfStates - 1, cmap = cm.winter) 24 | axis('image') 25 | title('t = ' + str(time)) 26 | 27 | def update(): 28 | global time, config, nextConfig 29 | 30 | time += 1 31 | 32 | for x in range(width): 33 | for y in range(height): 34 | state = config[y, x] 35 | counts = [0] * numberOfStates 36 | for dx in range(- r, r + 1): 37 | for dy in range(- r, r + 1): 38 | s = int(config[(y+dy)%height, (x+dx)%width]) 39 | counts[s] += 1 40 | maxCount = max(counts) 41 | maxStates = [] 42 | for i in range(numberOfStates): 43 | if counts[i] == maxCount: 44 | maxStates.append(i) 45 | state = choice(maxStates) 46 | nextConfig[y, x] = state 47 | 48 | config, nextConfig = nextConfig, config 49 | 50 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 51 | -------------------------------------------------------------------------------- /ca-excitablemedia.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 100 5 | height = 100 6 | initProb = 0.1 7 | maxState = 6 8 | 9 | def initialize(): 10 | global time, config, nextConfig 11 | 12 | time = 0 13 | 14 | config = zeros([height, width]) 15 | for x in range(width): 16 | for y in range(height): 17 | if random() < initProb: 18 | state = maxState 19 | else: 20 | state = 0 21 | config[y, x] = state 22 | 23 | nextConfig = zeros([height, width]) 24 | 25 | def observe(): 26 | cla() 27 | imshow(config, vmin = 0, vmax = maxState, cmap = cm.binary) 28 | axis('image') 29 | title('t = ' + str(time)) 30 | 31 | def update(): 32 | global time, config, nextConfig 33 | 34 | time += 1 35 | 36 | for x in range(width): 37 | for y in range(height): 38 | state = config[y, x] 39 | if state == 0: 40 | num = 0 41 | for dx in range(-1, 2): 42 | for dy in range(-1, 2): 43 | if config[(y+dy)%height, (x+dx)%width] == maxState: 44 | num += 1 45 | if random() * 3 < num: 46 | state = maxState 47 | else: 48 | state = 0 49 | else: 50 | state -= 1 51 | nextConfig[y, x] = state 52 | 53 | config, nextConfig = nextConfig, config 54 | 55 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 56 | -------------------------------------------------------------------------------- /ca-forestfire.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 100 5 | height = 100 6 | initProb = 0.4 7 | empty, tree, fire, char = range(4) 8 | 9 | def initialize(): 10 | global time, config, nextConfig 11 | 12 | time = 0 13 | 14 | config = zeros([height, width]) 15 | for x in range(width): 16 | for y in range(height): 17 | if random() < initProb: 18 | state = tree 19 | else: 20 | state = empty 21 | config[y, x] = state 22 | 23 | height_half = int(height / 2) # added by toshi 24 | width_half = int(width / 2) # added by toshi 25 | config[height_half, width_half] = fire 26 | 27 | nextConfig = zeros([height, width]) 28 | 29 | def observe(): 30 | cla() 31 | imshow(config, vmin = 0, vmax = 3, cmap = cm.binary) 32 | axis('image') 33 | title('t = ' + str(time)) 34 | 35 | def update(): 36 | global time, config, nextConfig 37 | 38 | time += 1 39 | 40 | for x in range(width): 41 | for y in range(height): 42 | state = config[y, x] 43 | if state == fire: 44 | state = char 45 | elif state == tree: 46 | for dx in range(-1, 2): 47 | for dy in range(-1, 2): 48 | if config[(y+dy)%height, (x+dx)%width] == fire: 49 | state = fire 50 | nextConfig[y, x] = state 51 | 52 | config, nextConfig = nextConfig, config 53 | 54 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 55 | -------------------------------------------------------------------------------- /ca-Turing.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | initProb = 0.5 7 | 8 | Ra = 1 9 | Ri = 5 10 | Wa = 1 11 | Wi = 0.1 12 | 13 | def initialize(): 14 | global time, config, nextConfig 15 | 16 | time = 0 17 | 18 | config = zeros([height, width]) 19 | for x in range(width): 20 | for y in range(height): 21 | if random() < initProb: 22 | state = 1 23 | else: 24 | state = 0 25 | config[y, x] = state 26 | 27 | nextConfig = zeros([height, width]) 28 | 29 | def observe(): 30 | cla() 31 | imshow(config, vmin = 0, vmax = 1, cmap = cm.binary) 32 | axis('image') 33 | title('t = ' + str(time)) 34 | 35 | def update(): 36 | global time, config, nextConfig 37 | 38 | time += 1 39 | 40 | for x in range(width): 41 | for y in range(height): 42 | state = config[y, x] 43 | na = ni = 0 44 | for dx in range(- Ra, Ra + 1): 45 | for dy in range(- Ra, Ra + 1): 46 | na += config[(y+dy)%height, (x+dx)%width] 47 | for dx in range(- Ri, Ri + 1): 48 | for dy in range(- Ri, Ri + 1): 49 | ni += config[(y+dy)%height, (x+dx)%width] 50 | if na * Wa - ni * Wi > 0: 51 | state = 1 52 | else: 53 | state = 0 54 | nextConfig[y, x] = state 55 | 56 | config, nextConfig = nextConfig, config 57 | 58 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 59 | -------------------------------------------------------------------------------- /net-diffusion-adaptive.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | def initialize(): 7 | global g, nextg 8 | g = nx.karate_club_graph() 9 | for i, j in g.edges: 10 | g.edges[i, j]['weight'] = 0.5 11 | g.pos = nx.spring_layout(g) 12 | for i in g.nodes: 13 | g.nodes[i]['state'] = 1 if g.nodes[i]['club'] == 'Mr. Hi' else 0 14 | nextg = g.copy() 15 | nextg.pos = g.pos 16 | 17 | def observe(): 18 | global g, nextg 19 | cla() 20 | nx.draw(g, cmap = cm.Spectral, vmin = 0, vmax = 1, 21 | node_color = [g.nodes[i]['state'] for i in g.nodes], 22 | edge_cmap = cm.binary, edge_vmin = 0, edge_vmax = 1, 23 | edge_color = [g.edges[i, j]['weight'] for i, j in g.edges], 24 | pos = g.pos) 25 | 26 | alpha = 1 # diffusion constant 27 | beta = 3 # rate of adaptive edge weight change 28 | gamma = 3 # pickiness of nodes 29 | Dt = 0.01 # Delta t 30 | 31 | def update(): 32 | global g, nextg 33 | for i in g.nodes: 34 | ci = g.nodes[i]['state'] 35 | nextg.nodes[i]['state'] = ci + alpha * ( \ 36 | sum([(g.nodes[j]['state'] - ci) * g.edges[i, j]['weight'] 37 | for j in g.neighbors(i)])) * Dt 38 | for i, j in g.edges: 39 | wij = g.edges[i, j]['weight'] 40 | nextg.edges[i, j]['weight'] = wij + beta * wij * (1 - wij) * ( \ 41 | 1 - gamma * abs(g.nodes[i]['state'] - g.nodes[j]['state']) 42 | ) * Dt 43 | nextg.pos = nx.spring_layout(nextg, pos = g.pos, iterations = 5) 44 | g, nextg = nextg, g 45 | 46 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 47 | -------------------------------------------------------------------------------- /net-networkx-demo2.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | import networkx as nx 4 | 5 | ### creating complex networks 6 | 7 | er = nx.erdos_renyi_graph(200, 0.02) 8 | 9 | ws = nx.watts_strogatz_graph(200, 4, 0.03) 10 | 11 | ba = nx.barabasi_albert_graph(200, 4) 12 | 13 | ### visualizing networks 14 | 15 | subplot(1, 3, 1) 16 | nx.draw(er) 17 | axis('image') 18 | title('Erdos-Renyi') 19 | 20 | subplot(1, 3, 2) 21 | nx.draw(ws) 22 | axis('image') 23 | title('Watts-Strogatz') 24 | 25 | subplot(1, 3, 3) 26 | nx.draw(ba) 27 | axis('image') 28 | title('Barabasi-Albert') 29 | 30 | tight_layout() 31 | show() 32 | 33 | ### obtaining degree distributions 34 | print('Degrees of all nodes in ba are:') 35 | print(dict(ba.degree)) 36 | 37 | # original degree distribution 38 | hist = nx.degree_histogram(ba) 39 | print('When binned:') 40 | print(hist) 41 | 42 | # complementary cummulative distribution function (CCDF) 43 | ccdf = [sum(hist[k:]) for k in range(len(hist))] 44 | print('Its CCDF:') 45 | print(ccdf) 46 | 47 | print('See figures for log-log plots') 48 | 49 | subplot(1, 2, 1) 50 | loglog(hist) 51 | title('Original degree distribution') 52 | 53 | subplot(1, 2, 2) 54 | loglog(ccdf) 55 | title('CCDF') 56 | 57 | tight_layout() 58 | show() 59 | 60 | ### finding important structures 61 | 62 | # minimum spanning tree 63 | mst = nx.minimum_spanning_tree(ba) 64 | title('Minimum spanning tree of ba') 65 | nx.draw(mst) 66 | show() 67 | 68 | # k-core 69 | kc = nx.k_core(er) 70 | print('Nodes in the k-core of er are:') 71 | print(kc.nodes) 72 | print('Size of the k-core: ', kc.number_of_nodes()) 73 | 74 | title('k-core of er') 75 | nx.draw(kc) 76 | 77 | show() 78 | -------------------------------------------------------------------------------- /net-cascade-of-failure.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | functioning = 1 7 | failed = 0 8 | 9 | capacity = 1.0 10 | maxInitialLoad = 0.6 11 | 12 | def initialize(): 13 | global time, network, positions 14 | 15 | time = 0 16 | 17 | network = nx.watts_strogatz_graph(200, 4, 0.02) 18 | for nd in network.nodes: 19 | network.nodes[nd]['state'] = functioning 20 | network.nodes[nd]['load'] = random() * maxInitialLoad 21 | network.nodes[choice(list(network.nodes))]['load'] = 2.0 * capacity 22 | 23 | positions = nx.circular_layout(network) 24 | 25 | def observe(): 26 | cla() 27 | nx.draw(network, with_labels = False, pos = positions, 28 | cmap = cm.jet, vmin = 0, vmax = capacity, 29 | node_color = [network.nodes[nd]['load'] for nd in network.nodes]) 30 | axis('image') 31 | title('t = ' + str(time)) 32 | 33 | def update(): 34 | global time, network 35 | 36 | time += 1 37 | 38 | node_IDs = list(network.nodes) 39 | shuffle(node_IDs) 40 | for nd in node_IDs: 41 | if network.nodes[nd]['state'] == functioning: 42 | ld = network.nodes[nd]['load'] 43 | if ld > capacity: 44 | network.nodes[nd]['state'] = failed 45 | nbs = [nb for nb in network.neighbors(nd) if network.nodes[nb]['state'] == functioning] 46 | if len(nbs) > 0: 47 | loadDistributed = ld / len(nbs) 48 | for nb in nbs: 49 | network.nodes[nb]['load'] += loadDistributed 50 | 51 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 52 | -------------------------------------------------------------------------------- /pde-transport-escaping.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 100 # size of grid: n * n 5 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 6 | Dt = 0.01 # temporal resolution 7 | 8 | mu_a = 0.001 # mobility of species a 9 | mu_b = 0.001 # mobility of species b 10 | 11 | xvalues, yvalues = meshgrid(arange(0, 1, Dh), arange(0, 1, Dh)) 12 | 13 | def initialize(): 14 | global a, b, nexta, nextb 15 | # initial configuration 16 | a = exp(-((xvalues - 0.45)**2 + (yvalues - 0.45)**2) / (0.3**2)) 17 | b = exp(-((xvalues - 0.55)**2 + (yvalues - 0.55)**2) / (0.1**2)) 18 | nexta = zeros([n, n]) 19 | nextb = zeros([n, n]) 20 | 21 | def observe(): 22 | global a, b, nexta, nextb 23 | subplot(1, 2, 1) 24 | cla() 25 | imshow(a, vmin = 0, vmax = 1) 26 | title('a') 27 | subplot(1, 2, 2) 28 | cla() 29 | imshow(b, vmin = 0, vmax = 1) 30 | title('b') 31 | tight_layout() 32 | 33 | def update(): 34 | global a, b, nexta, nextb 35 | for x in range(n): 36 | for y in range(n): 37 | # state-transition function 38 | aC, aR, aL, aU, aD = a[x,y], a[(x+1)%n,y], a[(x-1)%n,y], \ 39 | a[x,(y+1)%n], a[x,(y-1)%n] 40 | bC, bR, bL, bU, bD = b[x,y], b[(x+1)%n,y], b[(x-1)%n,y], \ 41 | b[x,(y+1)%n], b[x,(y-1)%n] 42 | bLapNum = bR + bL + bU + bD - 4 * bC 43 | nexta[x,y] = aC + mu_a * ((aR-aL)*(bR-bL)+(aU-aD)*(bU-bD) 44 | +4*aC*bLapNum) * Dt/(4*Dh**2) 45 | nextb[x,y] = bC + mu_b * bLapNum * Dt/(Dh**2) 46 | 47 | a, nexta = nexta, a 48 | b, nextb = nextb, b 49 | 50 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 51 | -------------------------------------------------------------------------------- /ds-Hodgkin-Huxley-equations.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | I = 10. # injected current 4 | 5 | C = 1. 6 | ENa = 115. 7 | gNa = 120. 8 | EK = -12. 9 | gK = 36. 10 | EL = 10.6 11 | gL = 0.3 12 | 13 | Dt = 0.01 14 | 15 | def initialize(): 16 | global V, Vdata, n, ndata, m, mdata, h, hdata, t, tdata 17 | V, n, m, h = 0., 0., 0., 0. 18 | Vdata = [V] 19 | ndata = [n] 20 | mdata = [m] 21 | hdata = [h] 22 | t = 0. 23 | tdata = [t] 24 | 25 | def observe(): 26 | global V, Vdata, n, ndata, m, mdata, h, hdata, t, tdata 27 | Vdata.append(V) 28 | ndata.append(n) 29 | mdata.append(m) 30 | hdata.append(h) 31 | tdata.append(t) 32 | 33 | def an(V): 34 | return (0.1 - 0.01 * V) / (exp(1 - 0.1 * V) - 1) 35 | 36 | def am(V): 37 | return (2.5 - 0.1 * V) / (exp(2.5 - 0.1 * V) - 1) 38 | 39 | def ah(V): 40 | return 0.07 * exp(- V / 20.) 41 | 42 | def bn(V): 43 | return 0.125 * exp(-V / 80.) 44 | 45 | def bm(V): 46 | return 4. * exp(-V / 18.) 47 | 48 | def bh(V): 49 | return 1. / (exp(3 - 0.1 * V) + 1) 50 | 51 | def update(): 52 | global V, Vdata, n, ndata, m, mdata, h, hdata, t, tdata 53 | nextV = V + (I - (gNa * (m**3) * h * (V - ENa) + gK * (n**4) * (V-EK) + gL * (V - EL))) / C * Dt 54 | nextn = n + (an(V) * (1 - n) - bn(V) * n) * Dt 55 | nextm = m + (am(V) * (1 - m) - bm(V) * m) * Dt 56 | nexth = h + (ah(V) * (1 - h) - bh(V) * h) * Dt 57 | V, n, m, h = nextV, nextn, nextm, nexth 58 | t = t + Dt 59 | 60 | initialize() 61 | while t < 100.: 62 | update() 63 | observe() 64 | 65 | subplot(2, 1, 1) 66 | plot(tdata, Vdata, label = 'V') 67 | legend() 68 | 69 | subplot(2, 1, 2) 70 | plot(tdata, ndata, label = 'n') 71 | plot(tdata, mdata, label = 'm') 72 | plot(tdata, hdata, label = 'h') 73 | legend() 74 | 75 | tight_layout() 76 | show() -------------------------------------------------------------------------------- /ca-hostpathogen.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | initProb = 0.01 7 | infectionRate = 0.85 8 | regrowthRate = 0.15 9 | 10 | def initialize(): 11 | global time, config, nextConfig 12 | 13 | time = 0 14 | 15 | config = zeros([height, width]) 16 | for x in range(width): 17 | for y in range(height): 18 | if random() < initProb: 19 | state = 2 20 | else: 21 | state = 1 22 | config[y, x] = state 23 | 24 | nextConfig = zeros([height, width]) 25 | 26 | def observe(): 27 | cla() 28 | imshow(config, vmin = 0, vmax = 2, cmap = cm.jet) 29 | axis('image') 30 | title('t = ' + str(time)) 31 | 32 | def update(): 33 | global time, config, nextConfig 34 | 35 | time += 1 36 | 37 | for x in range(width): 38 | for y in range(height): 39 | state = config[y, x] 40 | if state == 0: 41 | for dx in range(-1, 2): 42 | for dy in range(-1, 2): 43 | if config[(y+dy)%height, (x+dx)%width] == 1: 44 | if random() < regrowthRate: 45 | state = 1 46 | elif state == 1: 47 | for dx in range(-1, 2): 48 | for dy in range(-1, 2): 49 | if config[(y+dy)%height, (x+dx)%width] == 2: 50 | if random() < infectionRate: 51 | state = 2 52 | else: 53 | state = 0 54 | 55 | nextConfig[y, x] = state 56 | 57 | config, nextConfig = nextConfig, config 58 | 59 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 60 | -------------------------------------------------------------------------------- /pde-Turing.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 100 # size of grid: n * n 5 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 6 | Dt = 0.02 # temporal resolution 7 | 8 | a, b, c, d, h, k = 1., -1., 2., -1.5, 1., 1. # parameter values 9 | 10 | Du = 0.0001 # diffusion constant of u 11 | Dv = 0.0006 # diffusion constant of v 12 | 13 | def initialize(): 14 | global u, v, nextu, nextv 15 | u = zeros([n, n]) 16 | v = zeros([n, n]) 17 | for x in range(n): 18 | for y in range(n): 19 | u[x, y] = 1. + uniform(-0.03, 0.03) # small noise is added 20 | v[x, y] = 1. + uniform(-0.03, 0.03) # small noise is added 21 | nextu = zeros([n, n]) 22 | nextv = zeros([n, n]) 23 | 24 | def observe(): 25 | global u, v, nextu, nextv 26 | subplot(1, 2, 1) 27 | cla() 28 | imshow(u, vmin = 0, vmax = 2) 29 | title('u') 30 | subplot(1, 2, 2) 31 | cla() 32 | imshow(v, vmin = 0, vmax = 2) 33 | title('v') 34 | tight_layout() 35 | 36 | def update(): 37 | global u, v, nextu, nextv 38 | for x in range(n): 39 | for y in range(n): 40 | # state-transition function 41 | uC, uR, uL, uU, uD = u[x,y], u[(x+1)%n,y], u[(x-1)%n,y], \ 42 | u[x,(y+1)%n], u[x,(y-1)%n] 43 | vC, vR, vL, vU, vD = v[x,y], v[(x+1)%n,y], v[(x-1)%n,y], \ 44 | v[x,(y+1)%n], v[x,(y-1)%n] 45 | uLap = (uR + uL + uU + uD - 4 * uC) / (Dh**2) 46 | vLap = (vR + vL + vU + vD - 4 * vC) / (Dh**2) 47 | nextu[x,y] = uC + (a*(uC-h) + b*(vC-k) + Du * uLap) * Dt 48 | nextv[x,y] = vC + (c*(uC-h) + d*(vC-k) + Dv * vLap) * Dt 49 | 50 | u, nextu = nextu, u 51 | v, nextv = nextv, v 52 | 53 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 54 | -------------------------------------------------------------------------------- /abm-segregation-discrete.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | density = 0.8 7 | threshold = 0.7 8 | 9 | def initialize(): 10 | global time, config, agents, empty 11 | 12 | agents = [] 13 | empty = [] 14 | 15 | time = 0 16 | 17 | config = zeros([height, width]) 18 | for x in range(width): 19 | for y in range(height): 20 | if random() < density: 21 | agents.append((y, x)) 22 | if random() < 0.5: 23 | config[y, x] = 1 24 | else: 25 | config[y, x] = -1 26 | else: 27 | empty.append((y, x)) 28 | 29 | def observe(): 30 | cla() 31 | imshow(config, vmin = -1, vmax = 1, cmap = cm.bwr) 32 | axis('image') 33 | title('t = ' + str(time)) 34 | 35 | def update(): 36 | global time, config, agents, empty 37 | 38 | time += 1 39 | 40 | sequence = list(range(len(agents))) 41 | shuffle(sequence) 42 | for i in sequence: 43 | y, x = agents[i] 44 | state = config[y, x] 45 | similar = 0 46 | total = 0 47 | for dx in range(-1, 2): 48 | for dy in range(-1, 2): 49 | if not ((dx == 0) and (dy == 0)): 50 | v = config[(y + dy) % height, (x+dx) % width] 51 | if (v != 0): 52 | total += 1 53 | if (v == state): 54 | similar += 1 55 | if (similar < threshold * total): 56 | j = randint(len(empty)) 57 | new_y, new_x = empty[j] 58 | agents[i] = (new_y, new_x) 59 | config[new_y, new_x] = state 60 | empty[j] = (y, x) 61 | config[y, x] = 0 62 | 63 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 64 | -------------------------------------------------------------------------------- /abm-ants.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | populationSize = 50 7 | 8 | free = 0 9 | carrying = 1 10 | 11 | garbageProb = 0.8 12 | 13 | def initialize(): 14 | global time, agents, envir 15 | 16 | time = 0 17 | 18 | agents = [] 19 | for i in range(populationSize): 20 | newAgent = [randint(width), randint(height), free] 21 | agents.append(newAgent) 22 | 23 | envir = zeros([height, width]) 24 | for y in range(height): 25 | for x in range(width): 26 | if random() < garbageProb: 27 | state = 1 28 | else: 29 | state = 0 30 | envir[y, x] = state 31 | 32 | def observe(): 33 | cla() 34 | imshow(envir, cmap = cm.YlOrRd, vmin = 0, vmax = 5) 35 | axis('image') 36 | x = [ag[0] for ag in agents] 37 | y = [ag[1] for ag in agents] 38 | s = [ag[2] for ag in agents] 39 | scatter(x, y, c = s, cmap = cm.bwr) 40 | title('t = ' + str(time)) 41 | 42 | def clip(a, amin, amax): 43 | if a < amin: return amin 44 | elif a > amax: return amax 45 | else: return a 46 | 47 | def update(): 48 | global time, agents, envir 49 | 50 | time += 1 51 | 52 | for ag in agents: 53 | 54 | # simulate random motion 55 | ag[0] += randint(-1, 2) 56 | ag[1] += randint(-1, 2) 57 | ag[0] = clip(ag[0], 0, width - 1) 58 | ag[1] = clip(ag[1], 0, height - 1) 59 | 60 | # simulate interaction between ants and environment 61 | if envir[ag[1], ag[0]] > 0: 62 | if ag[2] == free: 63 | envir[ag[1], ag[0]] -= 1 64 | ag[2] = carrying 65 | else: 66 | envir[ag[1], ag[0]] += 1 67 | ag[2] = free 68 | 69 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 70 | -------------------------------------------------------------------------------- /abm-DLA.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 100 5 | height = 100 6 | populationSize = 1000 7 | 8 | noiseLevel = 1 9 | collisionDistance = 2 10 | CDsquared = collisionDistance ** 2 11 | 12 | toBeRemoved = -1 13 | 14 | def initialize(): 15 | global time, free, fixed 16 | 17 | time = 0 18 | 19 | free = [] 20 | for i in range(populationSize - 1): 21 | free.append([uniform(0, width), uniform(0, height)]) 22 | 23 | fixed = [] 24 | fixed.append([width / 2, height / 2]) 25 | 26 | def observe(): 27 | cla() 28 | if free != []: 29 | x = [ag[0] for ag in free] 30 | y = [ag[1] for ag in free] 31 | scatter(x, y, color = 'cyan') 32 | if fixed != []: 33 | x = [ag[0] for ag in fixed] 34 | y = [ag[1] for ag in fixed] 35 | scatter(x, y, color = 'blue') 36 | axis('scaled') 37 | axis([0, width, 0, height]) 38 | title('t = ' + str(time)) 39 | 40 | def clip(a, amin, amax): 41 | if a < amin: return amin 42 | elif a > amax: return amax 43 | else: return a 44 | 45 | def update(): 46 | global time, free, fixed 47 | 48 | time += 1 49 | 50 | # simulate random motion 51 | for ag in free: 52 | ag[0] += normal(0, noiseLevel) 53 | ag[1] += normal(0, noiseLevel) 54 | ag[0] = clip(ag[0], 0, width) 55 | ag[1] = clip(ag[1], 0, height) 56 | 57 | # detect collision and change state 58 | for i in range(len(free)): 59 | for j in range(len(fixed)): 60 | if (free[i][0]-fixed[j][0])**2 + (free[i][1]-fixed[j][1])**2 < CDsquared: 61 | fixed.append(free[i]) 62 | free[i] = toBeRemoved 63 | break 64 | 65 | # remove "toBeRemoved" free particles 66 | while toBeRemoved in free: 67 | free.remove(toBeRemoved) 68 | 69 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 70 | -------------------------------------------------------------------------------- /net-SIS-large-graph.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | populationSize = 500 7 | linkProbability = 0.01 8 | initialInfectedRatio = 0.01 9 | infectionProb = 0.2 10 | recoveryProb = 0.5 11 | 12 | susceptible = 0 13 | infected = 1 14 | 15 | def initialize(): 16 | global time, network, positions, nextNetwork 17 | 18 | time = 0 19 | 20 | network = nx.erdos_renyi_graph(populationSize, linkProbability) 21 | 22 | positions = nx.random_layout(network) 23 | 24 | for i in network.nodes: 25 | if random() < initialInfectedRatio: 26 | network.nodes[i]['state'] = infected 27 | else: 28 | network.nodes[i]['state'] = susceptible 29 | 30 | nextNetwork = network.copy() 31 | 32 | def observe(): 33 | cla() 34 | nx.draw(network, 35 | pos = positions, 36 | node_color = [network.nodes[i]['state'] for i in network.nodes], 37 | cmap = cm.Wistia, 38 | vmin = 0, 39 | vmax = 1) 40 | axis('image') 41 | title('t = ' + str(time)) 42 | 43 | def update(): 44 | global time, network, nextNetwork 45 | 46 | time += 1 47 | 48 | for i in network.nodes: 49 | if network.nodes[i]['state'] == susceptible: 50 | nextNetwork.nodes[i]['state'] = susceptible 51 | for j in network.neighbors(i): 52 | if network.nodes[j]['state'] == infected: 53 | if random() < infectionProb: 54 | nextNetwork.nodes[i]['state'] = infected 55 | break 56 | else: 57 | if random() < recoveryProb: 58 | nextNetwork.nodes[i]['state'] = susceptible 59 | else: 60 | nextNetwork.nodes[i]['state'] = infected 61 | 62 | network, nextNetwork = nextNetwork, network 63 | 64 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 65 | -------------------------------------------------------------------------------- /abm-Keller-Segel.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of agents 5 | w = 100 # number of rows/columns in spatial array 6 | 7 | k = 1 # rate of cAMP decay 8 | Dc = 0.001 # diffusion constant of cAMP 9 | Dh = 0.01 # spatial resolution for cAMP simulation 10 | Dt = 0.01 # time resolution for cAMP simulation 11 | 12 | f = 1 # rate of cAMP secretion by an agent 13 | 14 | class agent: 15 | pass 16 | 17 | def initialize(): 18 | global agents, env, nextenv 19 | 20 | agents = [] 21 | for i in range(n): 22 | ag = agent() 23 | ag.x = randint(w) 24 | ag.y = randint(w) 25 | agents.append(ag) 26 | 27 | env = zeros([w, w]) 28 | nextenv = zeros([w, w]) 29 | 30 | def observe(): 31 | global agents, env, nextenv 32 | cla() 33 | imshow(env, cmap = cm.binary, vmin = 0, vmax = 1) 34 | axis('image') 35 | x = [ag.x for ag in agents] 36 | y = [ag.y for ag in agents] 37 | plot(y, x, 'b.') # x and y are swapped to match the orientation of env 38 | 39 | def update(): 40 | global agents, env, nextenv 41 | 42 | # simulating diffusion and evaporation of cAMP 43 | for x in range(w): 44 | for y in range(w): 45 | C, R, L, U, D = env[x,y], env[(x+1)%w,y], env[(x-1)%w,y], \ 46 | env[x,(y+1)%w], env[x,(y-1)%w] 47 | lap = (R + L + U + D - 4 * C) / (Dh**2) 48 | nextenv[x,y] = env[x,y] + (- k * C + Dc * lap) * Dt 49 | env, nextenv = nextenv, env 50 | 51 | # simulating secretion of cAMP by agents 52 | for ag in agents: 53 | env[ag.x, ag.y] += f * Dt 54 | 55 | # simulating chemotaxis of agents 56 | for ag in agents: 57 | newx, newy = (ag.x + randint(-1, 2)) % w, (ag.y + randint(-1, 2)) % w 58 | diff = (env[newx, newy] - env[ag.x, ag.y]) / 0.1 59 | if random() < exp(diff) / (1 + exp(diff)): 60 | ag.x, ag.y = newx, newy 61 | 62 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 63 | -------------------------------------------------------------------------------- /abm-Vicsek.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 500 # number of agents 5 | v = 1 # speed of agent movement 6 | r = 0.05 # perception range 7 | r2 = r**2 # perception range squared 8 | k = int(1 / r) # number of bins in each spatial dimension 9 | Dt = 0.01 # time interval for updates 10 | 11 | eta = 0.1 # noise level 12 | 13 | class agent: 14 | def __init__(self): 15 | self.x = rand(2) 16 | self.th = random() * 2 * pi 17 | def move(self): 18 | self.x += v * array([cos(self.th), sin(self.th)]) * Dt 19 | if self.x[0] < 0: self.x[0] += 1 20 | if self.x[1] < 0: self.x[1] += 1 21 | if self.x[0] >= 1: self.x[0] -= 1 22 | if self.x[1] >= 1: self.x[1] -= 1 23 | 24 | def initialize(): 25 | global agents 26 | agents = [agent() for i in range(n)] 27 | 28 | def observe(): 29 | global agents 30 | cla() 31 | plot([a.x[0] for a in agents], [a.x[1] for a in agents], 'bo') 32 | axis('image') 33 | axis([0, 1, 0, 1]) 34 | 35 | def bin(a): 36 | return int(floor(a.x[0] / r)), int(floor(a.x[1] / r)) 37 | 38 | def update(): 39 | global agents 40 | 41 | map = [[[] for i in range(k)] for j in range(k)] 42 | for a in agents: 43 | i, j = bin(a) 44 | map[i][j].append(a) 45 | 46 | for a in agents: 47 | i, j = bin(a) 48 | nbs = [] 49 | for di in [-1, 0, 1]: 50 | for dj in [-1, 0, 1]: 51 | nbs.extend(map[(i+di)%k][(j+dj)%k]) 52 | for b in list(nbs): 53 | dx, dy = abs(a.x - b.x) 54 | if min(dx, 1 - dx)**2 + min(dy, 1 - dy)**2 >= r2: 55 | nbs.remove(b) 56 | av = mean([[cos(b.th), sin(b.th)] for b in nbs], axis = 0) 57 | a.nth = arctan2(av[1], av[0]) + uniform(- eta / 2, eta / 2) 58 | 59 | for a in agents: 60 | a.th = a.nth 61 | a.move() 62 | 63 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 64 | -------------------------------------------------------------------------------- /pde-BZ-reaction.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 100 # size of grid: n * n 5 | Dh = 1. / n # spatial resolution, assuming space is [0,1] * [0,1] 6 | Dt = 0.001 # temporal resolution 7 | 8 | Du = 1e-5 9 | Dv = 1e-5 10 | eps = 0.2 11 | q = 1.0e-3 12 | f = 1 13 | 14 | xvalues, yvalues = meshgrid(arange(0, 1, Dh), arange(0, 1, Dh)) 15 | 16 | def initialize(): 17 | global u, v, nextu, nextv 18 | # initial configuration 19 | u = zeros([n, n]) 20 | v = zeros([n, n]) 21 | for x in range(1, n - 1): 22 | for y in range(1, n - 1): 23 | u[x,y] = 1 if 0 < 8 * (xvalues[x,y] - 0.5) < yvalues[x,y] - 0.5 else 0 24 | v[x,y] = 1 if -(yvalues[x,y] - 0.5) < 8 * (xvalues[x,y] - 0.5) < 0 else 0 25 | nextu = zeros([n, n]) 26 | nextv = zeros([n, n]) 27 | 28 | def observe(): 29 | global u, v, nextu, nextv 30 | subplot(1, 2, 1) 31 | cla() 32 | imshow(u, vmin = 0, vmax = 1) 33 | title("u") 34 | subplot(1, 2, 2) 35 | cla() 36 | imshow(v, vmin = 0, vmax = 1) 37 | title("v") 38 | tight_layout() 39 | 40 | def update(): 41 | global u, v, nextu, nextv 42 | for x in range(1, n - 1): 43 | for y in range(1, n - 1): 44 | # state-transition function 45 | uC, uR, uL, uU, uD = u[x,y], u[(x+1)%n,y], u[(x-1)%n,y], \ 46 | u[x,(y+1)%n], u[x,(y-1)%n] 47 | vC, vR, vL, vU, vD = v[x,y], v[(x+1)%n,y], v[(x-1)%n,y], \ 48 | v[x,(y+1)%n], v[x,(y-1)%n] 49 | uLapNum = (uR + uL + uU + uD - 4 * uC) / (Dh**2) 50 | vLapNum = (vR + vL + vU + vD - 4 * vC) / (Dh**2) 51 | nextu[x,y] = uC + (uC*(1-uC) - f*vC*(uC-q)/(uC+q) + Du*uLapNum) * Dt/eps 52 | nextv[x,y] = vC + (uC - vC + Dv * vLapNum) * Dt 53 | 54 | u, nextu = nextu, u 55 | v, nextv = nextv, v 56 | 57 | pycxsimulator.GUI(stepSize = 50).start(func=[initialize, observe, update]) 58 | 59 | ''' 60 | initialize() 61 | t = 0 62 | observe() 63 | savefig(str(t) + '.png') 64 | for t in range(1, 100001): 65 | update() 66 | if t % 1000 == 0: 67 | print(t) 68 | observe() 69 | savefig(str(t) + '.png') 70 | ''' 71 | -------------------------------------------------------------------------------- /net-RBN-with-phasespace.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | n = 30 # number of nodes 7 | k = 2 # number of inputs of each node 8 | 9 | def initialize(): 10 | global g, ph 11 | 12 | g = nx.DiGraph() 13 | for i in range(n): 14 | for j in choice(range(n), k, replace = False): 15 | g.add_edge(j, i) 16 | g.nodes[i]['state'] = 1 if random() < .5 else 0 17 | lookuptable = choice(range(2), 2**k) 18 | g.nodes[i]['rule'] = lambda nbs:lookuptable[int("".join(str(x) for x in nbs), 2)] 19 | g.pos = nx.kamada_kawai_layout(g) 20 | 21 | ph = nx.DiGraph() 22 | ph.add_node(tuple(g.nodes[i]['state'] for i in g.nodes)) 23 | ph.pos = nx.spring_layout(ph) 24 | ph.count = 0 25 | 26 | def observe(): 27 | global g, ph 28 | subplot(1, 2, 1) 29 | cla() 30 | nx.draw(g, vmin = 0, vmax = 1, pos = g.pos, node_color = [g.nodes[i]['state'] for i in g.nodes]) 31 | title('Network state') 32 | axis('image') 33 | subplot(1, 2, 2) 34 | cla() 35 | nx.draw(ph, pos = ph.pos, node_size = 10) 36 | title('Phase space') 37 | axis('image') 38 | tight_layout() 39 | 40 | def update(): 41 | global g, ph 42 | 43 | s1 = tuple(g.nodes[i]['state'] for i in g.nodes) 44 | for i in g.nodes: 45 | nbs = [g.nodes[j]['state'] for j in g.predecessors(i)] 46 | g.nodes[i]['nextstate'] = g.nodes[i]['rule'](nbs) 47 | for i in g.nodes: 48 | g.nodes[i]['state'] = g.nodes[i]['nextstate'] 49 | s2 = tuple(g.nodes[i]['state'] for i in g.nodes) 50 | 51 | if s2 in ph.nodes: 52 | ph.add_edge(s1, s2) 53 | ph.count += 1 54 | if ph.count > 20: 55 | # re-initialization of network state 56 | ph.count = 0 57 | for i in range(n): 58 | g.nodes[i]['state'] = 1 if random() < .5 else 0 59 | s2 = tuple(g.nodes[i]['state'] for i in g.nodes) 60 | ph.add_node(s2) 61 | ph.pos[s2] = array([0, 0]) 62 | else: 63 | ph.add_edge(s1, s2) 64 | 65 | ph.pos = nx.spring_layout(ph, pos = ph.pos, iterations = 2) 66 | 67 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | PyCX 1.2 2 | Python-based sample code repository for complex systems research and education 3 | 4 | https://github.com/hsayama/PyCX 5 | 6 | 2008-2025 (c) Copyright by Hiroki Sayama 7 | sayama@binghamton.edu 8 | 9 | 2012 (c) Copyright by Chun Wong & Hiroki Sayama 10 | Original GUI module and simulation models 11 | 2013 (c) Copyright by Przemyslaw Szufel & Bogumil Kaminski 12 | Extensions to GUI module, some revisions 13 | 2025 (c) Copyright by Dheeraj Tommandru 14 | The code for the SugarScape model 15 | All rights reserved. 16 | 17 | 18 | This software is being distributed under the following Simplified BSD 19 | (FreeBSD) license. 20 | 21 | 22 | Redistribution and use in source and binary forms, with or without 23 | modification, are permitted provided that the following conditions are met: 24 | 25 | 1. Redistributions of source code must retain the above copyright notice, this 26 | list of conditions and the following disclaimer. 27 | 2. Redistributions in binary form must reproduce the above copyright notice, 28 | this list of conditions and the following disclaimer in the documentation 29 | and/or other materials provided with the distribution. 30 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 32 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 33 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 34 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 35 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 36 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 38 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 40 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | 42 | The views and conclusions contained in the software and documentation are those 43 | of the authors and should not be interpreted as representing official policies, 44 | either expressed or implied, of the FreeBSD Project. 45 | -------------------------------------------------------------------------------- /net-SIS-large-graph-adaptive.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | populationSize = 500 7 | linkProbability = 0.01 8 | initialInfectedRatio = 0.01 9 | infectionProb = 0.2 10 | recoveryProb = 0.5 11 | linkCuttingProb = 0.1 12 | 13 | susceptible = 0 14 | infected = 1 15 | 16 | def initialize(): 17 | global time, network, positions, nextNetwork 18 | 19 | time = 0 20 | 21 | network = nx.erdos_renyi_graph(populationSize, linkProbability) 22 | 23 | positions = nx.random_layout(network) 24 | 25 | for i in network.nodes: 26 | if random() < initialInfectedRatio: 27 | network.nodes[i]['state'] = infected 28 | else: 29 | network.nodes[i]['state'] = susceptible 30 | 31 | nextNetwork = network.copy() 32 | 33 | def observe(): 34 | cla() 35 | nx.draw(network, 36 | pos = positions, 37 | node_color = [network.nodes[i]['state'] for i in network.nodes], 38 | cmap = cm.Wistia, 39 | vmin = 0, 40 | vmax = 1) 41 | axis('image') 42 | title('t = ' + str(time)) 43 | 44 | def update(): 45 | global time, network, nextNetwork 46 | 47 | time += 1 48 | 49 | for i in network.nodes: 50 | if network.nodes[i]['state'] == susceptible: 51 | nextNetwork.nodes[i]['state'] = susceptible 52 | for j in network.neighbors(i): 53 | if network.nodes[j]['state'] == infected: 54 | if random() < infectionProb: 55 | nextNetwork.nodes[i]['state'] = infected 56 | break 57 | else: # adaptive link cutting behavior 58 | if random() < linkCuttingProb: 59 | if nextNetwork.has_edge(i, j): 60 | nextNetwork.remove_edge(i, j) 61 | else: 62 | if random() < recoveryProb: 63 | nextNetwork.nodes[i]['state'] = susceptible 64 | else: 65 | nextNetwork.nodes[i]['state'] = infected 66 | 67 | del network 68 | network = nextNetwork.copy() 69 | 70 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 71 | -------------------------------------------------------------------------------- /abm-DLA-faster-neighbor-detection.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 200 5 | height = 200 6 | populationSize = 5000 7 | 8 | noiseLevel = 1 9 | collisionDistance = 2 10 | CDsquared = collisionDistance ** 2 11 | 12 | kw = int(width / collisionDistance) + 1 13 | kh = int(height / collisionDistance) + 1 14 | 15 | toBeRemoved = -1 16 | 17 | def bin(a): 18 | return int(floor(a[0] / collisionDistance)), int(floor(a[1] / collisionDistance)) 19 | 20 | def initialize(): 21 | global time, free, fixed, map 22 | 23 | time = 0 24 | 25 | free = [] 26 | for i in range(populationSize - 1): 27 | free.append([uniform(0, width), uniform(0, height)]) 28 | 29 | fixed = [] 30 | fixed.append([width / 2, height / 2]) 31 | 32 | map = [[[] for i in range(kh)] for j in range(kw)] 33 | for a in fixed: 34 | i, j = bin(a) 35 | map[i][j].append(a) 36 | 37 | def observe(): 38 | cla() 39 | if free != []: 40 | x = [ag[0] for ag in free] 41 | y = [ag[1] for ag in free] 42 | scatter(x, y, color = 'cyan') 43 | if fixed != []: 44 | x = [ag[0] for ag in fixed] 45 | y = [ag[1] for ag in fixed] 46 | scatter(x, y, color = 'blue') 47 | axis('scaled') 48 | axis([0, width, 0, height]) 49 | title('t = ' + str(time)) 50 | 51 | def clip(a, amin, amax): 52 | if a < amin: return amin 53 | elif a > amax: return amax 54 | else: return a 55 | 56 | def update(): 57 | global time, free, fixed, map 58 | 59 | time += 1 60 | 61 | # simulate random motion 62 | for ag in free: 63 | ag[0] += normal(0, noiseLevel) 64 | ag[1] += normal(0, noiseLevel) 65 | ag[0] = clip(ag[0], 0, width) 66 | ag[1] = clip(ag[1], 0, height) 67 | 68 | # detect collision and change state 69 | for i in range(len(free)): 70 | ii, jj = bin(free[i]) 71 | nbs = [] 72 | for di in [-1, 0, 1]: 73 | for dj in [-1, 0, 1]: 74 | if 0 <= ii+di < kw and 0 <= jj+dj < kh: 75 | nbs.extend(map[ii+di][jj+dj]) 76 | for nb in nbs: 77 | if (free[i][0]-nb[0])**2 + (free[i][1]-nb[1])**2 < CDsquared: 78 | fixed.append(free[i]) 79 | map[ii][jj].append(free[i]) 80 | free[i] = toBeRemoved 81 | break 82 | 83 | # remove "toBeRemoved" free particles 84 | while toBeRemoved in free: 85 | free.remove(toBeRemoved) 86 | 87 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 88 | -------------------------------------------------------------------------------- /net-SIS-large-graph-parametersweep.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import networkx as nx 5 | 6 | populationSize = 2000 7 | numberOfLinks = 5000 8 | initialInfectedRatio = 0.01 9 | maxTime = 200 10 | 11 | susceptible = 0 12 | infected = 1 13 | 14 | er_network = 0 15 | ba_network = 1 16 | 17 | def networksimulation(networkType, infectionProb, recoveryProb): 18 | 19 | if networkType == er_network: 20 | linkProbability = float(numberOfLinks) / float(populationSize * (populationSize - 1) / 2) 21 | network = nx.erdos_renyi_graph(populationSize, linkProbability) 22 | else: 23 | network = nx.barabasi_albert_graph(populationSize, int(numberOfLinks / populationSize)) 24 | 25 | for i in network.nodes: 26 | if random() < initialInfectedRatio: 27 | network.nodes[i]['state'] = infected 28 | else: 29 | network.nodes[i]['state'] = susceptible 30 | 31 | nextNetwork = network.copy() 32 | 33 | for time in range(maxTime): 34 | 35 | for i in network.nodes: 36 | if network.nodes[i]['state'] == susceptible: 37 | nextNetwork.nodes[i]['state'] = susceptible 38 | for j in network.neighbors(i): 39 | if network.nodes[j]['state'] == infected: 40 | if random() < infectionProb: 41 | nextNetwork.nodes[i]['state'] = infected 42 | break 43 | else: 44 | if random() < recoveryProb: 45 | nextNetwork.nodes[i]['state'] = susceptible 46 | else: 47 | nextNetwork.nodes[i]['state'] = infected 48 | 49 | network, nextNetwork = nextNetwork, network 50 | 51 | return [network.nodes[i]['state'] for i in network.nodes].count(infected) 52 | 53 | infectionRates = arange(0, 0.3, 0.01) 54 | 55 | result = [] 56 | print('Starting simulations on Erdos-Renyi networks...') 57 | for i in infectionRates: 58 | print('Infection rate =', i) 59 | s = 0 60 | for k in range(5): 61 | s += networksimulation(er_network, i, 0.5) 62 | s /= 5.0 63 | result.append(s) 64 | subplot(1, 2, 1) 65 | plot(infectionRates, result) 66 | title("Erdos-Renyi Network") 67 | 68 | result = [] 69 | print('Starting simulations on Barabasi-Albert networks...') 70 | for i in infectionRates: 71 | print('Infection rate =', i) 72 | s = 0 73 | for k in range(5): 74 | s += networksimulation(ba_network, i, 0.5) 75 | s /= 5.0 76 | result.append(s) 77 | subplot(1, 2, 2) 78 | plot(infectionRates, result) 79 | title("Barabasi-Albert Network") 80 | 81 | tight_layout() 82 | show() 83 | -------------------------------------------------------------------------------- /abm-ants-pheromone.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 50 5 | height = 50 6 | populationSize = 3000 7 | 8 | evaporationRate = 0.02 9 | diffusionCoefficient = 0.8 10 | hillClimbingProb = 0.95 11 | 12 | def initialize(): 13 | global time, agents, envir, nextenvir 14 | 15 | time = 0 16 | 17 | agents = [] 18 | for i in range(populationSize): 19 | newAgent = [randint(width), randint(height)] 20 | agents.append(newAgent) 21 | 22 | envir = zeros([height, width]) 23 | for y in range(height): 24 | for x in range(width): 25 | envir[y, x] = random() 26 | 27 | nextenvir = zeros([height, width]) 28 | 29 | def observe(): 30 | cla() 31 | imshow(envir, cmap = cm.YlOrRd, vmin = 0, vmax = 3) 32 | axis('image') 33 | x = [ag[0] for ag in agents] 34 | y = [ag[1] for ag in agents] 35 | scatter(x, y, cmap = cm.bone, alpha = 0.2) 36 | title('t = ' + str(time)) 37 | 38 | def clip(a, amin, amax): 39 | if a < amin: return amin 40 | elif a > amax: return amax 41 | else: return a 42 | 43 | def update(): 44 | global time, agents, envir, nextenvir 45 | 46 | time += 1 47 | 48 | # diffusion and evaporation of phenomones 49 | for x in range(width): 50 | for y in range(height): 51 | localAv = 0 52 | for dx in range(-1, 2): 53 | for dy in range(-1, 2): 54 | localAv += envir[(y+dy) % height, (x+dx) % width] 55 | localAv /= 9.0 56 | nextenvir[y, x] = envir[y, x] + (localAv - envir[y, x]) * diffusionCoefficient 57 | nextenvir[y, x] *= (1.0 - evaporationRate) 58 | 59 | envir, nextenvir = nextenvir, envir 60 | 61 | for ag in agents: 62 | 63 | if random() < hillClimbingProb: 64 | # simulate hill-climbing motion 65 | maxph = 0 66 | maxdx = 0 67 | maxdy = 0 68 | for dx in range(-1, 2): 69 | for dy in range(-1, 2): 70 | tempx = (ag[0]+dx) % width 71 | tempy = (ag[1]+dy) % height 72 | if maxph < envir[tempy, tempx]: 73 | maxph = envir[tempy, tempx] 74 | maxdx = dx 75 | maxdy = dy 76 | ag[0] += maxdx 77 | ag[1] += maxdy 78 | else: 79 | ag[0] += randint(-1, 2) 80 | ag[1] += randint(-1, 2) 81 | 82 | ag[0] = clip(ag[0], 0, width - 1) 83 | ag[1] = clip(ag[1], 0, height - 1) 84 | 85 | # production of pheromones 86 | envir[ag[1], ag[0]] += 0.01 87 | 88 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 89 | 90 | -------------------------------------------------------------------------------- /abm-predator-prey.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import copy as cp 5 | 6 | nr = 500. # carrying capacity of rabbits 7 | 8 | r_init = 100 # initial rabbit population 9 | mr = 0.03 # magnitude of movement of rabbits 10 | dr = 1.0 # death rate of rabbits when it faces foxes 11 | rr = 0.1 # reproduction rate of rabbits 12 | 13 | f_init = 30 # initial fox population 14 | mf = 0.05 # magnitude of movement of foxes 15 | df = 0.1 # death rate of foxes when there is no food 16 | rf = 0.5 # reproduction rate of foxes 17 | 18 | cd = 0.02 # radius for collision detection 19 | cdsq = cd ** 2 20 | 21 | class agent: 22 | pass 23 | 24 | def initialize(): 25 | global agents 26 | agents = [] 27 | for i in range(r_init + f_init): 28 | ag = agent() 29 | ag.type = 'r' if i < r_init else 'f' 30 | ag.x = random() 31 | ag.y = random() 32 | agents.append(ag) 33 | 34 | def observe(): 35 | global agents 36 | cla() 37 | rabbits = [ag for ag in agents if ag.type == 'r'] 38 | if len(rabbits) > 0: 39 | x = [ag.x for ag in rabbits] 40 | y = [ag.y for ag in rabbits] 41 | plot(x, y, 'b.') 42 | foxes = [ag for ag in agents if ag.type == 'f'] 43 | if len(foxes) > 0: 44 | x = [ag.x for ag in foxes] 45 | y = [ag.y for ag in foxes] 46 | plot(x, y, 'ro') 47 | axis('image') 48 | axis([0, 1, 0, 1]) 49 | 50 | def update_one_agent(): 51 | global agents 52 | if agents == []: 53 | return 54 | 55 | ag = choice(agents) 56 | 57 | # simulating random movement 58 | m = mr if ag.type == 'r' else mf 59 | ag.x += uniform(-m, m) 60 | ag.y += uniform(-m, m) 61 | ag.x = 1 if ag.x > 1 else 0 if ag.x < 0 else ag.x 62 | ag.y = 1 if ag.y > 1 else 0 if ag.y < 0 else ag.y 63 | 64 | # detecting collision and simulating death or birth 65 | neighbors = [nb for nb in agents if nb.type != ag.type 66 | and (ag.x - nb.x)**2 + (ag.y - nb.y)**2 < cdsq] 67 | 68 | if ag.type == 'r': 69 | if len(neighbors) > 0: # if there are foxes nearby 70 | if random() < dr: 71 | agents.remove(ag) 72 | return 73 | if random() < rr*(1-sum([1 for x in agents if x.type == 'r'])/nr): 74 | agents.append(cp.copy(ag)) 75 | else: 76 | if len(neighbors) == 0: # if there are no rabbits nearby 77 | if random() < df: 78 | agents.remove(ag) 79 | return 80 | else: # if there are rabbits nearby 81 | if random() < rf: 82 | agents.append(cp.copy(ag)) 83 | 84 | def update(): 85 | global agents 86 | t = 0. 87 | while t < 1. and len(agents) > 0: 88 | t += 1. / len(agents) 89 | update_one_agent() 90 | 91 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 92 | -------------------------------------------------------------------------------- /abm-epidemics.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of agents 5 | v = 0.01 # speed of agent movement 6 | f = 0.01 # repulsion force constant 7 | r = 0.02 # perception range 8 | k = int(1 / r) + 1 # number of bins in each spatial dimension 9 | 10 | p_inf = 0.5 # infection probability 11 | p_rec = 0.05 # recovery probability 12 | 13 | class agent: 14 | def __init__(self): 15 | self.x = rand(2) 16 | self.v = rand(2) - array([0.5, 0.5]) 17 | self.v *= v / norm(self.v) 18 | self.s = 0 19 | def move(self): 20 | self.x += self.v 21 | if self.x[0] < 0: self.x[0] = 0; self.v[0] *= -1 22 | if self.x[1] < 0: self.x[1] = 0; self.v[1] *= -1 23 | if self.x[0] > 1: self.x[0] = 1; self.v[0] *= -1 24 | if self.x[1] > 1: self.x[1] = 1; self.v[1] *= -1 25 | 26 | def initialize(): 27 | global agents, Scount, Icount, Rcount 28 | agents = [agent() for i in range(n)] 29 | agents[0].s = 1 30 | Scount = [n - 1] 31 | Icount = [1] 32 | Rcount = [0] 33 | 34 | def observe(): 35 | global agents, Scount, Icount, Rcount 36 | subplot(1, 2, 1) 37 | cla() 38 | scatter([a.x[0] for a in agents], [a.x[1] for a in agents], c = [{0: 'c', 1: 'r', 2: 'g'}[a.s] for a in agents]) 39 | axis('image') 40 | axis([0, 1, 0, 1]) 41 | subplot(1, 2, 2) 42 | cla() 43 | plot(Scount, label = 'Susceptible') 44 | plot(Icount, label = 'Infected') 45 | plot(Rcount, label = 'Recovered') 46 | legend() 47 | tight_layout() 48 | 49 | def bin(a): 50 | return int(floor(a.x[0] / r)), int(floor(a.x[1] / r)) 51 | 52 | def update(): 53 | global agents, Scount, Icount, Rcount 54 | 55 | map = [[[] for i in range(k)] for j in range(k)] 56 | for a in agents: 57 | i, j = bin(a) 58 | map[i][j].append(a) 59 | 60 | for a in agents: 61 | i, j = bin(a) 62 | nbs = [] 63 | for di in [-1, 0, 1]: 64 | for dj in [-1, 0, 1]: 65 | if 0 <= i+di < k and 0 <= j+dj < k: 66 | nbs.extend(map[i+di][j+dj]) 67 | 68 | a.a = array([0., 0.]) 69 | a.ns = a.s 70 | for b in nbs: 71 | if a != b: 72 | d = norm(a.x - b.x) 73 | if d < r: 74 | a.a += f * (a.x - b.x) / d 75 | if a.s == 0 and b.s == 1: 76 | if random() < p_inf: 77 | a.ns = 1 78 | 79 | for a in agents: 80 | a.v += a.a 81 | a.v *= v / norm(a.v) 82 | a.move() 83 | if a.s == 1: 84 | if random() < p_rec: 85 | a.s = 2 86 | else: 87 | a.s = a.ns 88 | 89 | Scount.append(len([a for a in agents if a.s == 0])) 90 | Icount.append(len([a for a in agents if a.s == 1])) 91 | Rcount.append(len([a for a in agents if a.s == 2])) 92 | 93 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 94 | -------------------------------------------------------------------------------- /abm-predator-prey-evolvable.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import copy as cp 5 | 6 | nr = 500. # carrying capacity of rabbits 7 | 8 | r_init = 100 # initial rabbit population 9 | mr = 0.03 # magnitude of movement of rabbits 10 | dr = 1.0 # death rate of rabbits when it faces foxes 11 | rr = 0.1 # reproduction rate of rabbits 12 | 13 | f_init = 30 # initial fox population 14 | mf = 0.05 # magnitude of movement of foxes 15 | df = 0.1 # death rate of foxes when there is no food 16 | rf = 0.5 # reproduction rate of foxes 17 | 18 | cd = 0.02 # radius for collision detection 19 | cdsq = cd ** 2 20 | 21 | class agent: 22 | pass 23 | 24 | def initialize(): 25 | global agents 26 | agents = [] 27 | for i in range(r_init + f_init): 28 | ag = agent() 29 | ag.type = 'r' if i < r_init else 'f' 30 | ag.m = mr if i < r_init else mf ### 31 | ag.x = random() 32 | ag.y = random() 33 | agents.append(ag) 34 | 35 | def observe(): 36 | global agents 37 | cla() 38 | rabbits = [ag for ag in agents if ag.type == 'r'] 39 | if len(rabbits) > 0: 40 | x = [ag.x for ag in rabbits] 41 | y = [ag.y for ag in rabbits] 42 | plot(x, y, 'b.') 43 | foxes = [ag for ag in agents if ag.type == 'f'] 44 | if len(foxes) > 0: 45 | x = [ag.x for ag in foxes] 46 | y = [ag.y for ag in foxes] 47 | plot(x, y, 'ro') 48 | axis('image') 49 | axis([0, 1, 0, 1]) 50 | 51 | def update_one_agent(): 52 | global agents 53 | if agents == []: 54 | return 55 | 56 | ag = choice(agents) 57 | 58 | # simulating random movement 59 | m = ag.m ### 60 | ag.x += uniform(-m, m) 61 | ag.y += uniform(-m, m) 62 | ag.x = 1 if ag.x > 1 else 0 if ag.x < 0 else ag.x 63 | ag.y = 1 if ag.y > 1 else 0 if ag.y < 0 else ag.y 64 | 65 | # detecting collision and simulating death or birth 66 | neighbors = [nb for nb in agents if nb.type != ag.type 67 | and (ag.x - nb.x)**2 + (ag.y - nb.y)**2 < cdsq] 68 | 69 | if ag.type == 'r': 70 | if len(neighbors) > 0: # if there are foxes nearby 71 | if random() < dr: 72 | agents.remove(ag) 73 | return 74 | if random() < rr*(1-sum([1 for x in agents if x.type == 'r'])/nr): 75 | newborn = cp.copy(ag) ### 76 | newborn.m += uniform(-0.01, 0.01) ### 77 | agents.append(newborn) ### 78 | else: 79 | if len(neighbors) == 0: # if there are no rabbits nearby 80 | if random() < df: 81 | agents.remove(ag) 82 | return 83 | else: # if there are rabbits nearby 84 | if random() < rf: 85 | newborn = cp.copy(ag) ### 86 | newborn.m += uniform(-0.01, 0.01) ### 87 | agents.append(newborn) ### 88 | 89 | def update(): 90 | global agents 91 | t = 0. 92 | while t < 1. and len(agents) > 0: 93 | t += 1. / len(agents) 94 | update_one_agent() 95 | 96 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 97 | -------------------------------------------------------------------------------- /net-networkx-demo1.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | 3 | import networkx as nx 4 | 5 | ### creating networks 6 | 7 | # manual construction 8 | g = nx.Graph() 9 | g.add_edge(1, 2) 10 | g.add_edge(2, 3) 11 | g.add_edge(1, 3) 12 | g.add_edge(1, 4) 13 | g.add_node(5) 14 | g.remove_node(4) 15 | g.remove_edge(1, 2) 16 | 17 | # complete graph with 10 nodes 18 | K10 = nx.complete_graph(10) 19 | 20 | # from adjacency matrix 21 | mat = nx.from_numpy_array(array([[0,1,0,1,1], 22 | [1,0,0,1,0], 23 | [0,0,0,0,1], 24 | [1,1,0,0,0], 25 | [1,0,1,0,0]])) 26 | 27 | ### visualizing networks 28 | 29 | subplot(1, 3, 1) 30 | nx.draw(g) 31 | axis('image') 32 | title('g') 33 | 34 | subplot(1, 3, 2) 35 | nx.draw_circular(K10) 36 | axis('image') 37 | title('K10') 38 | 39 | subplot(1, 3, 3) 40 | nx.draw_random(mat) 41 | axis('image') 42 | title('mat') 43 | 44 | tight_layout() 45 | show() 46 | 47 | ### obtaining basic information about networks 48 | 49 | print('Number of nodes in K10 is', K10.number_of_nodes()) 50 | 51 | print('List of nodes in K10:') 52 | print(K10.nodes) 53 | 54 | print('Number of edges in K10 is', K10.number_of_edges()) 55 | 56 | print('List of edges in K10:') 57 | print(K10.edges) 58 | 59 | print("") 60 | 61 | print('Adjacency matrix of K10 in numpy array format:') 62 | print(nx.to_numpy_array(K10)) 63 | 64 | print("") 65 | 66 | # connected components 67 | cc = list(nx.connected_components(g)) # fixed by toshi 68 | print('There are', len(cc), 'connected components in g') 69 | print('They are:') 70 | print(cc) 71 | 72 | print("") 73 | 74 | # shortest paths and characteristic path lengths 75 | print('Shortest path from 1 to 4 in mat is:') 76 | print(nx.shortest_path(mat, 1, 4)) 77 | print('whose length is', nx.shortest_path_length(mat, 1, 4)) 78 | print('Diameter (maximum of shortest path lengths) of mat is', nx.diameter(mat)) 79 | print('Average shortest path length of mat is', nx.average_shortest_path_length(mat)) 80 | 81 | print("") 82 | 83 | # clustering coefficients 84 | print('Clustering coefficients of nodes in mat are:') 85 | print(nx.clustering(mat)) 86 | print('whose average is', nx.average_clustering(mat)) 87 | 88 | print("") 89 | 90 | # degrees and degree distribution 91 | print('Neighbors of node 0 in mat is:') 92 | print(list(mat.neighbors(0))) 93 | print('Its degree is', mat.degree(0)) 94 | 95 | print("") 96 | 97 | print('Degrees of all nodes in mat are:') 98 | print(dict(mat.degree())) 99 | 100 | hist = nx.degree_histogram(mat) 101 | print('When binned:') 102 | print(hist) 103 | print('See figure for its histogram') 104 | 105 | plot(hist) 106 | xlabel('Degree (k)') 107 | ylabel('# of nodes (P(k))') 108 | title("Degree distribution of the network 'mat'") 109 | 110 | show() 111 | 112 | print("") 113 | 114 | # centralities 115 | print('Betweenness centralities of all nodes in mat are:') 116 | print(nx.betweenness_centrality(mat)) 117 | print('Closeness centralities of all nodes in mat are:') 118 | print(nx.closeness_centrality(mat)) 119 | print('Eigenvector centralities of all nodes in mat are:') 120 | print(nx.eigenvector_centrality(mat)) 121 | -------------------------------------------------------------------------------- /abm-predator-prey-with-plot.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | import copy as cp 5 | 6 | nr = 500. # carrying capacity of rabbits 7 | 8 | r_init = 100 # initial rabbit population 9 | mr = 0.03 # magnitude of movement of rabbits 10 | dr = 1.0 # death rate of rabbits when it faces foxes 11 | rr = 0.1 # reproduction rate of rabbits 12 | 13 | f_init = 30 # initial fox population 14 | mf = 0.05 # magnitude of movement of foxes 15 | df = 0.1 # death rate of foxes when there is no food 16 | rf = 0.5 # reproduction rate of foxes 17 | 18 | cd = 0.02 # radius for collision detection 19 | cdsq = cd ** 2 20 | 21 | class agent: 22 | pass 23 | 24 | def initialize(): 25 | global agents, rdata, fdata 26 | agents = [] 27 | rdata = [] 28 | fdata = [] 29 | for i in range(r_init + f_init): 30 | ag = agent() 31 | ag.type = 'r' if i < r_init else 'f' 32 | ag.x = random() 33 | ag.y = random() 34 | agents.append(ag) 35 | 36 | def observe(): 37 | global agents, rdata, fdata 38 | 39 | subplot(2, 1, 1) 40 | cla() 41 | rabbits = [ag for ag in agents if ag.type == 'r'] 42 | if len(rabbits) > 0: 43 | x = [ag.x for ag in rabbits] 44 | y = [ag.y for ag in rabbits] 45 | plot(x, y, 'b.') 46 | foxes = [ag for ag in agents if ag.type == 'f'] 47 | if len(foxes) > 0: 48 | x = [ag.x for ag in foxes] 49 | y = [ag.y for ag in foxes] 50 | plot(x, y, 'ro') 51 | axis('image') 52 | axis([0, 1, 0, 1]) 53 | 54 | subplot(2, 1, 2) 55 | cla() 56 | plot(rdata, label = 'prey') 57 | plot(fdata, label = 'predator') 58 | legend() 59 | 60 | tight_layout() 61 | 62 | def update_one_agent(): 63 | global agents 64 | if agents == []: 65 | return 66 | 67 | ag = choice(agents) 68 | 69 | # simulating random movement 70 | m = mr if ag.type == 'r' else mf 71 | ag.x += uniform(-m, m) 72 | ag.y += uniform(-m, m) 73 | ag.x = 1 if ag.x > 1 else 0 if ag.x < 0 else ag.x 74 | ag.y = 1 if ag.y > 1 else 0 if ag.y < 0 else ag.y 75 | 76 | # detecting collision and simulating death or birth 77 | neighbors = [nb for nb in agents if nb.type != ag.type 78 | and (ag.x - nb.x)**2 + (ag.y - nb.y)**2 < cdsq] 79 | 80 | if ag.type == 'r': 81 | if len(neighbors) > 0: # if there are foxes nearby 82 | if random() < dr: 83 | agents.remove(ag) 84 | return 85 | if random() < rr*(1-sum([1 for x in agents if x.type == 'r'])/nr): 86 | agents.append(cp.copy(ag)) 87 | else: 88 | if len(neighbors) == 0: # if there are no rabbits nearby 89 | if random() < df: 90 | agents.remove(ag) 91 | return 92 | else: # if there are rabbits nearby 93 | if random() < rf: 94 | agents.append(cp.copy(ag)) 95 | 96 | def update(): 97 | global agents, rdata, fdata 98 | t = 0. 99 | while t < 1. and len(agents) > 0: 100 | t += 1. / len(agents) 101 | update_one_agent() 102 | 103 | rdata.append(sum([1 for x in agents if x.type == 'r'])) 104 | fdata.append(sum([1 for x in agents if x.type == 'f'])) 105 | 106 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 107 | -------------------------------------------------------------------------------- /abm-predator-prey-old.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 100 5 | height = 100 6 | 7 | initialRabbitPopulation = 100 8 | rabbitReproductionRate = 0.1 9 | rabbitPopulationLimit = 500 10 | rabbitNoiseLevel = 2 11 | 12 | initialFoxPopulation = 30 13 | foxReproductionRate = 0.5 14 | foxPopulationLimit = 500 15 | foxNoiseLevel = 3 16 | foxHungerLimit = 10 17 | 18 | collisionDistance = 2 19 | CDsquared = collisionDistance ** 2 20 | toBeRemoved = -1 21 | 22 | def initialize(): 23 | global time, rabbits, foxes 24 | 25 | time = 0 26 | 27 | rabbits = [] 28 | for i in range(initialRabbitPopulation): 29 | rabbits.append([uniform(0, width), uniform(0, height)]) 30 | 31 | foxes = [] 32 | for i in range(initialFoxPopulation): 33 | foxes.append([uniform(0, width), uniform(0, height), 0]) 34 | 35 | def observe(): 36 | cla() 37 | if rabbits != []: 38 | x = [ag[0] for ag in rabbits] 39 | y = [ag[1] for ag in rabbits] 40 | scatter(x, y, color = 'pink') 41 | if foxes != []: 42 | x = [ag[0] for ag in foxes] 43 | y = [ag[1] for ag in foxes] 44 | scatter(x, y, color = 'brown') 45 | axis('scaled') 46 | axis([0, width, 0, height]) 47 | title('t = ' + str(time)) 48 | 49 | def clip(a, amin, amax): 50 | if a < amin: return amin 51 | elif a > amax: return amax 52 | else: return a 53 | 54 | def update(): 55 | global time, rabbits, foxes 56 | 57 | time += 1 58 | 59 | # simulate random motion 60 | for ag in rabbits: 61 | ag[0] += normal(0, rabbitNoiseLevel) 62 | ag[1] += normal(0, rabbitNoiseLevel) 63 | ag[0] = clip(ag[0], 0, width) 64 | ag[1] = clip(ag[1], 0, height) 65 | for ag in foxes: 66 | ag[0] += normal(0, foxNoiseLevel) 67 | ag[1] += normal(0, foxNoiseLevel) 68 | ag[0] = clip(ag[0], 0, width) 69 | ag[1] = clip(ag[1], 0, height) 70 | 71 | # detect collision and change state 72 | for i in range(len(foxes)): 73 | foxes[i][2] += 1 # fox's hunger level increasing 74 | for j in range(len(rabbits)): 75 | if rabbits[j] != toBeRemoved: 76 | if (foxes[i][0]-rabbits[j][0])**2 + (foxes[i][1]-rabbits[j][1])**2 < CDsquared: 77 | foxes[i][2] = 0 # fox ate rabbit and hunger level reset to 0 78 | rabbits[j] = toBeRemoved # rabbit eaten by fox 79 | if foxes[i][2] > foxHungerLimit: 80 | foxes[i] = toBeRemoved # fox died due to hunger 81 | 82 | # remove "toBeRemoved" agents 83 | while toBeRemoved in rabbits: 84 | rabbits.remove(toBeRemoved) 85 | while toBeRemoved in foxes: 86 | foxes.remove(toBeRemoved) 87 | 88 | # count survivors' populations 89 | rabbitPopulation = len(rabbits) 90 | foxPopulation = len(foxes) 91 | 92 | # produce offspring 93 | for i in range(len(rabbits)): 94 | if random() < rabbitReproductionRate * (1.0 - float(rabbitPopulation) / float(rabbitPopulationLimit)): 95 | rabbits.append(rabbits[i][:]) # making and adding a copy of the parent 96 | for i in range(len(foxes)): 97 | if foxes[i][2] == 0 and random() < foxReproductionRate * (1.0 - float(foxPopulation) / float(foxPopulationLimit)): 98 | foxes.append(foxes[i][:]) # making and adding a copy of the parent 99 | 100 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 101 | -------------------------------------------------------------------------------- /abm-epidemics-virulence-evolution.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | n = 1000 # number of agents 5 | v = 0.01 # speed of agent movement 6 | f = 0.01 # repulsion force constant 7 | r = 0.02 # perception range 8 | k = int(1 / r) + 1 # number of bins in each spatial dimension 9 | 10 | p_inf = 0.5 # infection probability 11 | p_rec = 0.05 # recovery probability 12 | 13 | class agent: 14 | def __init__(self): 15 | self.x = rand(2) 16 | self.v = rand(2) - array([0.5, 0.5]) 17 | self.v *= v / norm(self.v) 18 | self.s = 0 19 | self.virulence = 0 20 | def move(self): 21 | self.x += self.v 22 | if self.x[0] < 0: self.x[0] = 0; self.v[0] *= -1 23 | if self.x[1] < 0: self.x[1] = 0; self.v[1] *= -1 24 | if self.x[0] > 1: self.x[0] = 1; self.v[0] *= -1 25 | if self.x[1] > 1: self.x[1] = 1; self.v[1] *= -1 26 | 27 | def initialize(): 28 | global agents, Scount, Icount, Rcount, Vmean 29 | agents = [agent() for i in range(n)] 30 | agents[0].s = 1 31 | agents[0].virulence = 0.1 32 | Scount = [n - 1] 33 | Icount = [1] 34 | Rcount = [0] 35 | Vmean = [agents[0].virulence] 36 | 37 | def observe(): 38 | global agents, Scount, Icount, Rcount, Vmean 39 | subplot(1, 3, 1) 40 | cla() 41 | scatter([a.x[0] for a in agents], [a.x[1] for a in agents], c = [{0: 'c', 1: 'r', 2: 'g'}[a.s] for a in agents]) 42 | axis('image') 43 | axis([0, 1, 0, 1]) 44 | subplot(1, 3, 2) 45 | cla() 46 | plot(Scount, label = 'Susceptible') 47 | plot(Icount, label = 'Infected') 48 | plot(Rcount, label = 'Recovered') 49 | legend() 50 | subplot(1, 3, 3) 51 | cla() 52 | plot(Vmean, label = 'Mean virulence') 53 | legend() 54 | tight_layout() 55 | 56 | def bin(a): 57 | return int(floor(a.x[0] / r)), int(floor(a.x[1] / r)) 58 | 59 | def update(): 60 | global agents, Scount, Icount, Rcount, Vmean 61 | 62 | map = [[[] for i in range(k)] for j in range(k)] 63 | for a in agents: 64 | i, j = bin(a) 65 | map[i][j].append(a) 66 | 67 | for a in agents: 68 | i, j = bin(a) 69 | nbs = [] 70 | for di in [-1, 0, 1]: 71 | for dj in [-1, 0, 1]: 72 | if 0 <= i+di < k and 0 <= j+dj < k: 73 | nbs.extend(map[i+di][j+dj]) 74 | 75 | a.a = array([0., 0.]) 76 | a.ns = a.s 77 | for b in nbs: 78 | if a != b: 79 | d = norm(a.x - b.x) 80 | if d < r: 81 | a.a += f * (a.x - b.x) / d 82 | if a.s == 0 and b.s == 1: 83 | if random() < p_inf: 84 | a.ns = 1 85 | a.virulence = b.virulence + normal(0, 0.02) 86 | if a.virulence < 0: a.virulence = 0 87 | if a.virulence > 1: a.virulence = 1 88 | 89 | for a in agents: 90 | a.v += a.a 91 | a.v *= v / norm(a.v) 92 | a.move() 93 | if a.s == 1: 94 | if random() < p_rec: 95 | a.s = 2 96 | elif random() < a.virulence: 97 | a.s = -1 # numerical label indicating that the agent is to be removed due to death 98 | else: 99 | a.s = a.ns 100 | 101 | agents = [a for a in agents if a.s != -1] # removing dead agents 102 | 103 | for i in range(n - len(agents)): # replenish new agents 104 | agents.append(agent()) 105 | 106 | Scount.append(len([a for a in agents if a.s == 0])) 107 | Icount.append(len([a for a in agents if a.s == 1])) 108 | Rcount.append(len([a for a in agents if a.s == 2])) 109 | virs = [a.virulence for a in agents if a.s == 1] 110 | if len(virs) > 0: 111 | Vmean.append(mean(virs)) 112 | else: 113 | Vmean.append(0) 114 | 115 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 116 | -------------------------------------------------------------------------------- /abm-predator-prey-old-withplot.py: -------------------------------------------------------------------------------- 1 | import pycxsimulator 2 | from pylab import * 3 | 4 | width = 100 5 | height = 100 6 | 7 | initialRabbitPopulation = 100 8 | rabbitReproductionRate = 0.1 9 | rabbitPopulationLimit = 500 10 | rabbitNoiseLevel = 2 11 | 12 | initialFoxPopulation = 30 13 | foxReproductionRate = 0.5 14 | foxPopulationLimit = 500 15 | foxNoiseLevel = 3 16 | foxHungerLimit = 10 17 | 18 | collisionDistance = 2 19 | CDsquared = collisionDistance ** 2 20 | toBeRemoved = -1 21 | 22 | def initialize(): 23 | global time, rabbits, foxes, rabbitData, foxData 24 | 25 | time = 0 26 | 27 | rabbits = [] 28 | for i in range(initialRabbitPopulation): 29 | rabbits.append([uniform(0, width), uniform(0, height)]) 30 | 31 | foxes = [] 32 | for i in range(initialFoxPopulation): 33 | foxes.append([uniform(0, width), uniform(0, height), 0]) 34 | 35 | rabbitData = [initialRabbitPopulation] 36 | foxData = [initialFoxPopulation] 37 | 38 | def observe(): 39 | subplot(1, 2, 1) 40 | cla() 41 | if rabbits != []: 42 | x = [ag[0] for ag in rabbits] 43 | y = [ag[1] for ag in rabbits] 44 | scatter(x, y, color = 'pink') 45 | if foxes != []: 46 | x = [ag[0] for ag in foxes] 47 | y = [ag[1] for ag in foxes] 48 | scatter(x, y, color = 'brown') 49 | axis('scaled') 50 | axis([0, width, 0, height]) 51 | title('t = ' + str(time)) 52 | 53 | subplot(1, 2, 2) 54 | cla() 55 | plot(rabbitData, color = 'pink') 56 | plot(foxData, color = 'brown') 57 | title('Populations') 58 | 59 | tight_layout() 60 | 61 | def clip(a, amin, amax): 62 | if a < amin: return amin 63 | elif a > amax: return amax 64 | else: return a 65 | 66 | def update(): 67 | global time, rabbits, foxes, rabbitData, foxData 68 | 69 | time += 1 70 | 71 | # simulate random motion 72 | for ag in rabbits: 73 | ag[0] += normal(0, rabbitNoiseLevel) 74 | ag[1] += normal(0, rabbitNoiseLevel) 75 | ag[0] = clip(ag[0], 0, width) 76 | ag[1] = clip(ag[1], 0, height) 77 | 78 | for ag in foxes: 79 | ag[0] += normal(0, foxNoiseLevel) 80 | ag[1] += normal(0, foxNoiseLevel) 81 | ag[0] = clip(ag[0], 0, width) 82 | ag[1] = clip(ag[1], 0, height) 83 | 84 | # detect collision and change state 85 | for i in range(len(foxes)): 86 | foxes[i][2] += 1 # fox's hunger level increasing 87 | for j in range(len(rabbits)): 88 | if rabbits[j] != toBeRemoved: 89 | if (foxes[i][0]-rabbits[j][0])**2 + (foxes[i][1]-rabbits[j][1])**2 < CDsquared: 90 | foxes[i][2] = 0 # fox ate rabbit and hunger level reset to 0 91 | rabbits[j] = toBeRemoved # rabbit eaten by fox 92 | if foxes[i][2] > foxHungerLimit: 93 | foxes[i] = toBeRemoved # fox died due to hunger 94 | 95 | # remove "toBeRemoved" agents 96 | while toBeRemoved in rabbits: 97 | rabbits.remove(toBeRemoved) 98 | while toBeRemoved in foxes: 99 | foxes.remove(toBeRemoved) 100 | 101 | # count survivors' populations 102 | rabbitPopulation = len(rabbits) 103 | foxPopulation = len(foxes) 104 | 105 | # produce offspring 106 | for i in range(len(rabbits)): 107 | if random() < rabbitReproductionRate * (1.0 - float(rabbitPopulation) / float(rabbitPopulationLimit)): 108 | rabbits.append(rabbits[i][:]) # making and adding a copy of the parent 109 | for i in range(len(foxes)): 110 | if foxes[i][2] == 0 and random() < foxReproductionRate * (1.0 - float(foxPopulation) / float(foxPopulationLimit)): 111 | foxes.append(foxes[i][:]) # making and adding a copy of the parent 112 | 113 | rabbitData.append(len(rabbits)) 114 | foxData.append(len(foxes)) 115 | 116 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 117 | -------------------------------------------------------------------------------- /abm-sugarscape.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author Name: Dheeraj Tommandru 3 | E-mail: dtomman1@binghamton.edu/dheerajtls1234@gmail.com 4 | Description: 5 | This is implementation of Rob Axtell's and Joshua Epstein's basic Sugarscape Model. 6 | 7 | Slightly updated by Hiroki Sayama 8 | """ 9 | 10 | import pycxsimulator 11 | from pylab import * 12 | from itertools import product 13 | import random 14 | from scipy.stats import multivariate_normal 15 | from scipy.stats import randint as rd 16 | 17 | distancing_ratio = 0. 18 | x_lim, y_lim = 50, 50 19 | num_agents = 150 20 | 21 | class agent: 22 | pass 23 | 24 | def initialize(): 25 | global sugar, agents, wealth, deathcount, available_positions, sugar_positions, wealth,acount 26 | 27 | agents = [agent() for i in range(num_agents)] 28 | sugar = [] 29 | a,b = arange(x_lim), arange(y_lim) 30 | available_positions = set(product(a, b)) 31 | # assign genetic properties and initial positions to agents 32 | for ag in agents: 33 | element = random.randrange(0, len(available_positions)) 34 | ap = {i:key for i, key in enumerate(available_positions)} 35 | available_positions.discard(ap[element]) 36 | ag.x, ag.y = ap[element] 37 | ag.metabolism = random.randint(1, 5) 38 | ag.sugar = random.randint(50, 100) 39 | ag.vision = random.randint(1, 4) 40 | ag.life = rd.rvs(50, 100, size=1)[0] 41 | ag.age = 0 42 | ap = None 43 | 44 | sugar_positions = {} 45 | 46 | for x in range(x_lim): 47 | for y in range(y_lim): 48 | sugar.append(agent()) 49 | sugar[-1].x, sugar[-1].y = x, y 50 | sugar_positions[(x,y)] = len(sugar) - 1 51 | sugar[-1].max_capacity = random.randint(2, 10) 52 | sugar[-1].growth_rate = random.randint(1, 5) 53 | if x <= 24 and y <= 24: 54 | rv = multivariate_normal([12, 12], [[24, 0], [0, 24]]) 55 | sugar[-1].available_sugar =int(round(rv.pdf([x, y])*100000, 0)) 56 | sugar[-1].max_capacity = sugar[-1].available_sugar + 40 57 | elif x > 24 and y <= 24: 58 | sugar[-1].available_sugar = rd.rvs(0, 5, size=1)[0] 59 | sugar[-1].max_capacity = sugar[-1].available_sugar + 40 60 | elif x <= 24 and y > 24: 61 | sugar[-1].available_sugar = rd.rvs(0, 4, size=1)[0] 62 | sugar[-1].max_capacity = sugar[-1].available_sugar + 40 63 | else: 64 | rv = multivariate_normal([37, 37], [[24, 0], [0, 24]]) 65 | sugar[-1].available_sugar =int(round(rv.pdf([x,y]) * 100000, 0)) 66 | sugar[-1].max_capacity = sugar[-1].available_sugar + 40 67 | 68 | wealth = [a.sugar for a in agents] 69 | deathcount = [0] 70 | acount = [len(agents)] 71 | 72 | def observe(): 73 | global sugar, agents, wealth, deathcount, available_positions, wealth, sugar_positions, acount 74 | subplot(2, 2, 1) 75 | cla() 76 | scatter([a.x for a in agents], [a.y for a in agents],c = [a.sugar for a in agents]) 77 | axis('image') 78 | xlim([0, 49]) 79 | ylim([0, 49]) 80 | subplot(2, 2, 2) 81 | cla() 82 | scatter([s.x for s in sugar], [s.y for s in sugar], c = [s.available_sugar for s in sugar], alpha = 0.5) 83 | axis('image') 84 | subplot(2, 2, 3) 85 | cla() 86 | plot(deathcount, label = 'agents expired') 87 | xlabel("Time") 88 | ylabel("Number of agents") 89 | legend() 90 | subplot(2, 2, 4) 91 | cla() 92 | hist(wealth, label = 'wealth distribution') 93 | xlabel("Sugar") 94 | ylabel("Number of agents") 95 | legend() 96 | tight_layout() 97 | 98 | def update(): 99 | global sugar, agents, wealth, deathcount, available_positions, wealth, sugar_positions, acount 100 | 101 | dcount = 0 102 | for a in agents[:]: 103 | if (a.sugar < 0) or (a.age >= a.life): 104 | current_position = (a.x, a.y) 105 | agents.remove(a) 106 | new_agent = agent() 107 | new_agent.x, new_agent.y = current_position 108 | new_agent.metabolism = random.randint(1, 5) 109 | new_agent.sugar = random.randint(50, 100) 110 | new_agent.vision = random.randint(1, 4) 111 | new_agent.life = rd.rvs(50, 100, size=1)[0] 112 | new_agent.age = 0 113 | agents.append(new_agent) 114 | dcount = dcount+1 115 | else: 116 | current_position = (a.x, a.y) 117 | neighbourhood_sugar_availability = {} 118 | neighbourhood_sugar_availability[current_position] = sugar[sugar_positions[(a.x, a.y)]].available_sugar 119 | for prospective_x in range(current_position[0] - a.vision, current_position[0] + a.vision + 1): 120 | for prospective_y in range(current_position[1] - a.vision, current_position[1] + a.vision + 1): 121 | if prospective_x > x_lim-1: 122 | prospective_x = prospective_x - x_lim 123 | if prospective_y > y_lim-1: 124 | prospective_y = prospective_y - x_lim 125 | if prospective_x < 0: 126 | prospective_x = x_lim - prospective_x 127 | if prospective_y < 0: 128 | prospective_y = y_lim - prospective_y 129 | if ((prospective_x, prospective_y) in available_positions) and ((prospective_x == current_position[0]) or (prospective_y == current_position[1])): 130 | neighbourhood_sugar_availability[(prospective_x,prospective_y)] = sugar[sugar_positions[(prospective_x, prospective_y)]].available_sugar 131 | 132 | max_sugar_index = list(neighbourhood_sugar_availability.values()).index(max(list(neighbourhood_sugar_availability.values()))) 133 | max_sugar_position = list(neighbourhood_sugar_availability.keys())[max_sugar_index] 134 | available_positions.discard(max_sugar_position) 135 | a.x, a.y = max_sugar_position 136 | available_positions.add(current_position) 137 | a.sugar = a.sugar - a.metabolism 138 | sugar[sugar_positions[max_sugar_position]].available_sugar = sugar[sugar_positions[max_sugar_position]].available_sugar - 10 139 | a.sugar = a.sugar + 10 140 | a.age = a.age + 1 141 | 142 | wealth = [a.sugar for a in agents] 143 | deathcount.append(dcount) 144 | acount.append(len(agents)) 145 | 146 | for s in sugar: 147 | s.available_sugar = min(s.available_sugar + s.growth_rate, s.max_capacity) 148 | 149 | pycxsimulator.GUI().start(func=[initialize, observe, update]) 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyCX 2 | 3 | PyCX is a Python-based sample code repository for complex systems 4 | research and education. 5 | 6 | _Current version: 1.2 (July 2025)_ 7 | 8 | Sample codes are freely available from the **[Project 9 | website](http://github.com/hsayama/PyCX/)**. 10 | 11 | ## What is PyCX? 12 | 13 | The PyCX project aims to develop an online repository of simple, 14 | crude, yet easy-to-understand Python sample codes for dynamic complex 15 | systems modeling and simulation, including iterative maps, ordinary 16 | and partial differential equations, cellular automata, network 17 | analysis, dynamical networks, and agent-based models. You can run, 18 | read and modify any of its codes to learn the basics of complex 19 | systems modeling and simulation in Python. 20 | 21 | The target audiences of PyCX are researchers and students who are 22 | interested in developing their own computer codes to study complex 23 | systems using a general-purpose programming language but do not have 24 | much experience in computer programming. 25 | 26 | The core philosophy of PyCX is therefore placed on the simplicity, 27 | readability, generalizability, and pedagogical values of sample 28 | codes. This is often achieved even at the cost of computational speed, 29 | efficiency, or maintainability. For example, PyCX does not use 30 | object-oriented programming paradigms so much; it does not use 31 | sophisticated but complicated algorithm or data structure; it *does* 32 | use global variables frequently; and so on. These choices were 33 | intentionally made based on the author's experience in teaching 34 | complex systems modeling and simulation to non-computer scientists 35 | coming from a wide variety of domains. 36 | 37 | For more details of its philosophy and background, see the following 38 | open-access article: Sayama, H. (2013) PyCX: A Python-based simulation 39 | code repository for complex systems education. Complex Adaptive 40 | Systems Modeling 1:2. http://www.casmodeling.com/content/1/1/2 41 | 42 | ## How to use it? 43 | 44 | 1. Install Python 3 (or 2, if you want), numpy, scipy, matplotlib, and 45 | NetworkX. 46 | 47 | Installers are available from the following websites: 48 | * http://python.org/ 49 | * http://scipy.org/ 50 | * http://matplotlib.org/ 51 | * http://networkx.github.io/ 52 | 53 | Alternatively, you can use prepackaged Python distributions, such as: 54 | * [Anaconda Distribution](https://www.anaconda.com/download) 55 | 56 | The codes were tested using Anaconda Distribution of Python 3.13.5 57 | and 2.7.18. 58 | 59 | 2. Choose a PyCX sample code of your interest. 60 | 61 | 3. Run it. To run a dynamic, interactive simulation, make sure you have [pycxsimulator.py](https://github.com/hsayama/PyCX/blob/master/pycxsimulator.py) located in the same folder where your code exists. 62 | 63 | 4. Read the code to learn how the model was implemented. 64 | 65 | 5. Change the code as you like. 66 | 67 | *Note for Jupyter Notebook users:* You can run PyCX codes by entering "%run sample-code-name" or "!python sample-code-name.py" in your notebook. 68 | 69 | *Note for Spyder users:* Dynamic simulations may cause a conflict with Spyder's own graphics backend. In such a case, go to "Run" -> "Configuration per file" and select "External terminal". 70 | 71 | ## Revision history 72 | 73 | ### What's new in version 1.2? 74 | 75 | * Various minor updates and improvements have been applied to the codes so that they work robustly with the most up-to-date modules (in both Python 3.13 and Python 2.7). 76 | 77 | * Several new models have been added: 78 | * Dynamical systems -- SIR models (single strain, multiple strains), Poincare section of the Lorenz equations, Hodgkin-Huxley equations, FitzHugh-Nagumo equations 79 | * Networks -- random walk on a network, random Boolean networks (without and with phase space), animation of percolation experiments, animation of small-world experiments 80 | * Agent-based models -- epidemics in a moving crowd (without and with virulence evolution), the Vicsek model, the SugarScape model (contributed by Dheeraj Tommandru) 81 | - An example of an efficient neighbor detection method has been implemented in the above epidemics and Vicsek models (and a larger-scale DLA model with this neighbor detection method has also been added). 82 | 83 | * The issue with MatplotlibDeprecationWarning has been resolved by Will Deter and Guiherme Brondani. 84 | 85 | * The Matplotlib's backend issue has been resolved for Linux users by Felipe Xavier Costa. 86 | 87 | ### What's new in version 1.1? 88 | 89 | * Matplotlib's backend issue has been resolved for Mac users by Steve Morgan. 90 | 91 | * MatplotlibDeprecationWarning has been suppressed (particularly for examples that use subplots). 92 | 93 | * NetworkX's "node" attribute of a Graph object has been renamed as "nodes" to be compatible with NetworkX 2. 94 | 95 | ### What's new in version 1.0? 96 | 97 | * All the codes, including pycxsimulator.py, were updated to be compatible with both Python 2.7 and Python 3.7. They can run in both languages with no modification. Special thanks to [Prof. Toshi Tanizawa](http://www.ee.kochi-ct.ac.jp/~tanizawa/) at the National Institute of Technology, Kochi College! 98 | 99 | * Several bug fixes were applied to pycxsimulator.py's GUI so that it works more robustly within the IPython environment. 100 | 101 | * Codes for network modeling and analysis were updated to be compatible with NetworkX 2. 102 | 103 | * The coding style was simplified to be more readable and more consistent with the author's [OpenSUNY Textbook](http://tinyurl.com/imacsbook) style. 104 | 105 | * The file names of sample codes were updated so that all codes start with the following prefix: 106 | * "ds-": for low-dimensional dynamical systems 107 | * "dynamic-": for demonstration of how to use pycxsimulator.py 108 | * "ca-": for cellular automata 109 | * "pde-": for partial differential equations 110 | * "net-": for network models 111 | * "abm-": for agent-based models 112 | 113 | * Some new examples were added, including: Hopfield networks, simple swarming, network attack experiment, and population-economy interactions. 114 | 115 | * Minor bug fixes were applied to examples of cascading failure, network communities, etc. 116 | 117 | ### What was in previous versions 0.3/0.31/0.32? 118 | 119 | * Ver. 0.3: 120 | - Przemyslaw Szufel and Bogumil Kaminski at the Warsaw School of 121 | Economics made a substantial improvement to pycxsimulator.py, implementing interactive control of model and 122 | visualization parameters. 123 | - Several additional sample codes were added. 124 | 125 | * Ver. 0.31: 126 | - ttk was used as a graphics backend instead of Tix, so that Mac 127 | users could run the sample codes without installing Tix. 128 | 129 | * Ver. 0.32: 130 | - pycxsimulator.py's GUI was updated with several bug 131 | fixes by Toshi Tanizawa and Alex Hill. 132 | - Sample codes used in the author's [OpenSUNY Textbook](http://tinyurl.com/imacsbook) were included in the 133 | "textbook-sample-codes" subfolder. 134 | 135 | ## Questions? Comments? Send them to sayama@binghamton.edu. 136 | 137 | * [Old project website](http://pycx.sourceforge.net/) 138 | 139 | ## Notes for MacOS M1 users 140 | (Special thanks to Ivan Cheung @ivanmkc, Christian Lemp @clemp and Vison (Xin) Wang @xin-wang-kr for the following) 141 | 142 | Some changes need to be made for the PyQt backend to work properly with the Mac M1 chip architecture. Assuming using VSCode, here are the steps to configure: 143 | 144 | 1. Set `QT_API` environment variable in `launch.json` to 145 | 146 | ``` 147 | { 148 | // Use IntelliSense to learn about possible attributes. 149 | // Hover to view descriptions of existing attributes. 150 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 151 | "version": "0.2.0", 152 | "configurations": [ 153 | { 154 | "name": "Python: Current File", 155 | "type": "python", 156 | "request": "launch", 157 | "program": "${file}", 158 | "console": "integratedTerminal", 159 | "justMyCode": false, 160 | "env": { 161 | "QT_API": "pyqt5" 162 | } 163 | } 164 | ] 165 | } 166 | ``` 167 | 168 | 2. Install `PyQt6` into your virtual environment 169 | 170 | `pip3 install PyQt6` 171 | 172 | 3. At the top of `pycxsimulator.py` add 173 | 174 | `import PyQt6.QtCore` 175 | 176 | Now the visualization component should run on your MacOS M1 chip device. 177 | 178 | (Added on March 8th, 2023) 179 | Here is another easy-to-follow instruction for Jupyter notebook users by Vision (Xin) Wang @xin-wang-kr: 180 | https://github.com/xin-wang-kr/xin-wang-kr.github.io/blob/master/_posts/2023-03-07-PyCX.md 181 | -------------------------------------------------------------------------------- /pycxsimulator.py: -------------------------------------------------------------------------------- 1 | ## "pycxsimulator.py" 2 | ## Dynamic, interactive simulation GUI for PyCX 3 | ## 4 | ## Project website: 5 | ## https://github.com/hsayama/PyCX 6 | ## 7 | ## Initial development by: 8 | ## Chun Wong 9 | ## email@chunwong.net 10 | ## 11 | ## Revisions by: 12 | ## Hiroki Sayama 13 | ## sayama@binghamton.edu 14 | ## 15 | ## Copyright 2012 Chun Wong 16 | ## Copyright 2012-2019 Hiroki Sayama 17 | ## 18 | ## Simulation control & GUI extensions 19 | ## Copyright 2013 Przemyslaw Szufel & Bogumil Kaminski 20 | ## {pszufe, bkamins}@sgh.waw.pl 21 | ## 22 | ## Fixing errors due to "the grid and pack problem" by: 23 | ## Toshihiro Tanizawa 24 | ## tanizawa@ee.kochi-ct.ac.jp 25 | ## began at 2016-06-15(Wed) 17:10:17 26 | ## fixed grid() and pack() problem on 2016-06-21(Tue) 18:29:40 27 | ## 28 | ## various bug fixes and updates by Steve Morgan on 3/28/2020 29 | 30 | import matplotlib 31 | 32 | #System check added by Steve Morgan 33 | import platform #SM 3/28/2020 34 | if platform.system() == 'Windows' or platform.system() == 'Linux': #SM 3/28/2020, rev HS 7/20/2025 35 | backend = 'TkAgg' #SM 3/28/2020 36 | else: #SM 3/28/2020 37 | backend = 'Qt5Agg' #SM 3/28/2020 38 | matplotlib.use(backend) #SM 3/28/2020 39 | 40 | import matplotlib.pyplot as plt #SM 3/28/2020 41 | 42 | ## version check added by Hiroki Sayama on 01/08/2019 43 | import sys 44 | if sys.version_info[0] == 3: # Python 3 45 | from tkinter import * 46 | from tkinter.ttk import Notebook 47 | else: # Python 2 48 | from Tkinter import * 49 | from ttk import Notebook 50 | 51 | ## suppressing matplotlib deprecation warnings (especially with subplot) by Hiroki Sayama on 06/29/2020 52 | ## bug fixes by Will Deter and Guiherme Brondani (merged on 7/18/2025) 53 | import warnings 54 | try: warnings.filterwarnings("ignore", category = matplotlib.cbook.MatplotlibDeprecationWarning) 55 | except: warnings.filterwarnings("ignore", category = matplotlib.MatplotlibDeprecationWarning) 56 | 57 | class GUI: 58 | 59 | # Constructor 60 | def __init__(self, title='PyCX Simulator', interval=0, stepSize=1, parameterSetters=[]): 61 | 62 | ## all GUI variables moved to inside constructor by Hiroki Sayama 10/09/2018 63 | 64 | self.titleText = title 65 | self.timeInterval = interval 66 | self.stepSize = stepSize 67 | self.parameterSetters = parameterSetters 68 | self.varEntries = {} 69 | self.statusStr = "" 70 | 71 | self.running = False 72 | self.modelFigure = None 73 | self.currentStep = 0 74 | 75 | # initGUI() removed by Hiroki Sayama 10/09/2018 76 | 77 | #create root window 78 | self.rootWindow = Tk() 79 | self.statusText = StringVar(self.rootWindow, value=self.statusStr) # at this point, statusStr = "" 80 | # added "self.rootWindow" above by Hiroki Sayama 10/09/2018 81 | self.setStatusStr("Simulation not yet started") 82 | 83 | self.rootWindow.wm_title(self.titleText) # titleText = 'PyCX Simulator' 84 | self.rootWindow.protocol('WM_DELETE_WINDOW', self.quitGUI) 85 | self.rootWindow.geometry('450x300') 86 | self.rootWindow.columnconfigure(0, weight=1) 87 | self.rootWindow.rowconfigure(0, weight=1) 88 | 89 | self.notebook = Notebook(self.rootWindow) 90 | # self.notebook.grid(row=0,column=0,padx=2,pady=2,sticky='nswe') # commented out by toshi on 2016-06-21(Tue) 18:30:25 91 | self.notebook.pack(side=TOP, padx=2, pady=2) 92 | 93 | # added "self.rootWindow" by Hiroki Sayama 10/09/2018 94 | self.frameRun = Frame(self.rootWindow) 95 | self.frameSettings = Frame(self.rootWindow) 96 | self.frameParameters = Frame(self.rootWindow) 97 | self.frameInformation = Frame(self.rootWindow) 98 | 99 | self.notebook.add(self.frameRun,text="Run") 100 | self.notebook.add(self.frameSettings,text="Settings") 101 | self.notebook.add(self.frameParameters,text="Parameters") 102 | self.notebook.add(self.frameInformation,text="Info") 103 | self.notebook.pack(expand=NO, fill=BOTH, padx=5, pady=5 ,side=TOP) 104 | # self.notebook.grid(row=0, column=0, padx=5, pady=5, sticky='nswe') # commented out by toshi on 2016-06-21(Tue) 18:31:02 105 | 106 | self.status = Label(self.rootWindow, width=40,height=3, relief=SUNKEN, bd=1, textvariable=self.statusText) 107 | # self.status.grid(row=1,column=0,padx=5,pady=5,sticky='nswe') # commented out by toshi on 2016-06-21(Tue) 18:31:17 108 | self.status.pack(side=TOP, fill=X, padx=5, pady=5, expand=NO) 109 | 110 | # ----------------------------------- 111 | # frameRun 112 | # ----------------------------------- 113 | # buttonRun 114 | self.runPauseString = StringVar(self.rootWindow) # added "self.rootWindow" by Hiroki Sayama 10/09/2018 115 | self.runPauseString.set("Run") 116 | self.buttonRun = Button(self.frameRun,width=30,height=2,textvariable=self.runPauseString,command=self.runEvent) 117 | self.buttonRun.pack(side=TOP, padx=5, pady=5) 118 | self.showHelp(self.buttonRun,"Runs the simulation (or pauses the running simulation)") 119 | 120 | # buttonStep 121 | self.buttonStep = Button(self.frameRun,width=30,height=2,text='Step Once',command=self.stepOnce) 122 | self.buttonStep.pack(side=TOP, padx=5, pady=5) 123 | self.showHelp(self.buttonStep,"Steps the simulation only once") 124 | 125 | # buttonReset 126 | self.buttonReset = Button(self.frameRun,width=30,height=2,text='Reset',command=self.resetModel) 127 | self.buttonReset.pack(side=TOP, padx=5, pady=5) 128 | self.showHelp(self.buttonReset,"Resets the simulation") 129 | 130 | # ----------------------------------- 131 | # frameSettings 132 | # ----------------------------------- 133 | can = Canvas(self.frameSettings) 134 | 135 | lab = Label(can, width=25,height=1,text="Step size ", justify=LEFT, anchor=W,takefocus=0) 136 | lab.pack(side='left') 137 | 138 | self.stepScale = Scale(can,from_=1, to=50, resolution=1,command=self.changeStepSize,orient=HORIZONTAL, width=25,length=150) 139 | self.stepScale.set(self.stepSize) 140 | self.showHelp(self.stepScale,"Skips model redraw during every [n] simulation steps\nResults in a faster model run.") 141 | self.stepScale.pack(side='left') 142 | 143 | can.pack(side='top') 144 | 145 | can = Canvas(self.frameSettings) 146 | lab = Label(can, width=25,height=1,text="Step visualization delay in ms ", justify=LEFT, anchor=W,takefocus=0) 147 | lab.pack(side='left') 148 | self.stepDelay = Scale(can,from_=0, to=max(2000,self.timeInterval), 149 | resolution=10,command=self.changeStepDelay,orient=HORIZONTAL, width=25,length=150) 150 | self.stepDelay.set(self.timeInterval) 151 | self.showHelp(self.stepDelay,"The visualization of each step is delays by the given number of milliseconds.") 152 | self.stepDelay.pack(side='left') 153 | 154 | can.pack(side='top') 155 | 156 | # -------------------------------------------- 157 | # frameInformation 158 | # -------------------------------------------- 159 | scrollInfo = Scrollbar(self.frameInformation) 160 | self.textInformation = Text(self.frameInformation, width=45,height=13,bg='lightgray',wrap=WORD,font=("Courier",10)) 161 | scrollInfo.pack(side=RIGHT, fill=Y) 162 | self.textInformation.pack(side=LEFT,fill=BOTH,expand=YES) 163 | scrollInfo.config(command=self.textInformation.yview) 164 | self.textInformation.config(yscrollcommand=scrollInfo.set) 165 | 166 | # -------------------------------------------- 167 | # ParameterSetters 168 | # -------------------------------------------- 169 | for variableSetter in self.parameterSetters: 170 | can = Canvas(self.frameParameters) 171 | 172 | lab = Label(can, width=25,height=1,text=variableSetter.__name__+" ",anchor=W,takefocus=0) 173 | lab.pack(side='left') 174 | 175 | ent = Entry(can, width=11) 176 | ent.insert(0, str(variableSetter())) 177 | 178 | if variableSetter.__doc__ != None and len(variableSetter.__doc__) > 0: 179 | self.showHelp(ent,variableSetter.__doc__.strip()) 180 | 181 | ent.pack(side='left') 182 | 183 | can.pack(side='top') 184 | 185 | self.varEntries[variableSetter]=ent 186 | 187 | if len(self.parameterSetters) > 0: 188 | self.buttonSaveParameters = Button(self.frameParameters,width=50,height=1, 189 | command=self.saveParametersCmd,text="Save parameters to the running model",state=DISABLED) 190 | self.showHelp(self.buttonSaveParameters, 191 | "Saves the parameter values.\nNot all values may take effect on a running model\nA model reset might be required.") 192 | self.buttonSaveParameters.pack(side='top',padx=5,pady=5) 193 | self.buttonSaveParametersAndReset = Button(self.frameParameters,width=50,height=1, 194 | command=self.saveParametersAndResetCmd,text="Save parameters to the model and reset the model") 195 | self.showHelp(self.buttonSaveParametersAndReset,"Saves the given parameter values and resets the model") 196 | self.buttonSaveParametersAndReset.pack(side='top',padx=5,pady=5) 197 | 198 | # <<<<< Init >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 199 | 200 | def setStatusStr(self,newStatus): 201 | self.statusStr = newStatus 202 | self.statusText.set(self.statusStr) 203 | 204 | # model control functions for changing parameters 205 | def changeStepSize(self,val): 206 | self.stepSize = int(val) 207 | 208 | def changeStepDelay(self,val): 209 | self.timeInterval= int(val) 210 | 211 | def saveParametersCmd(self): 212 | for variableSetter in self.parameterSetters: 213 | variableSetter(float(self.varEntries[variableSetter].get())) 214 | self.setStatusStr("New parameter values have been set") 215 | 216 | def saveParametersAndResetCmd(self): 217 | self.saveParametersCmd() 218 | self.resetModel() 219 | 220 | # <<<< runEvent >>>>> 221 | # This event is envoked when "Run" button is clicked. 222 | def runEvent(self): 223 | self.running = not self.running 224 | if self.running: 225 | self.rootWindow.after(self.timeInterval,self.stepModel) 226 | self.runPauseString.set("Pause") 227 | self.buttonStep.configure(state=DISABLED) 228 | self.buttonReset.configure(state=DISABLED) 229 | if len(self.parameterSetters) > 0: 230 | self.buttonSaveParameters.configure(state=NORMAL) 231 | self.buttonSaveParametersAndReset.configure(state=DISABLED) 232 | else: 233 | self.runPauseString.set("Continue Run") 234 | self.buttonStep.configure(state=NORMAL) 235 | self.buttonReset.configure(state=NORMAL) 236 | if len(self.parameterSetters) > 0: 237 | self.buttonSaveParameters.configure(state=NORMAL) 238 | self.buttonSaveParametersAndReset.configure(state=NORMAL) 239 | 240 | def stepModel(self): 241 | if self.running: 242 | self.modelStepFunc() 243 | self.currentStep += 1 244 | self.setStatusStr("Step "+str(self.currentStep)) 245 | self.status.configure(foreground='black') 246 | if (self.currentStep) % self.stepSize == 0: 247 | self.drawModel() 248 | self.rootWindow.after(int(self.timeInterval*1.0/self.stepSize),self.stepModel) 249 | 250 | def stepOnce(self): 251 | self.running = False 252 | self.runPauseString.set("Continue Run") 253 | self.modelStepFunc() 254 | self.currentStep += 1 255 | self.setStatusStr("Step "+str(self.currentStep)) 256 | self.drawModel() 257 | if len(self.parameterSetters) > 0: 258 | self.buttonSaveParameters.configure(state=NORMAL) 259 | 260 | def resetModel(self): 261 | self.running = False 262 | self.runPauseString.set("Run") 263 | self.modelInitFunc() 264 | self.currentStep = 0; 265 | self.setStatusStr("Model has been reset") 266 | self.drawModel() 267 | 268 | def drawModel(self): 269 | plt.ion() #SM 3/26/2020 270 | if self.modelFigure == None or self.modelFigure.canvas.manager.window == None: 271 | self.modelFigure = plt.figure() #SM 3/26/2020 272 | self.modelDrawFunc() 273 | self.modelFigure.canvas.manager.window.update() 274 | plt.show() # bug fix by Hiroki Sayama in 2016 #SM 3/26/2020 275 | 276 | def start(self,func=[]): 277 | if len(func)==3: 278 | self.modelInitFunc = func[0] 279 | self.modelDrawFunc = func[1] 280 | self.modelStepFunc = func[2] 281 | if (self.modelStepFunc.__doc__ != None and len(self.modelStepFunc.__doc__)>0): 282 | self.showHelp(self.buttonStep,self.modelStepFunc.__doc__.strip()) 283 | if (self.modelInitFunc.__doc__ != None and len(self.modelInitFunc.__doc__)>0): 284 | self.textInformation.config(state=NORMAL) 285 | self.textInformation.delete(1.0, END) 286 | self.textInformation.insert(END, self.modelInitFunc.__doc__.strip()) 287 | self.textInformation.config(state=DISABLED) 288 | 289 | self.modelInitFunc() 290 | self.drawModel() 291 | self.rootWindow.mainloop() 292 | 293 | def quitGUI(self): 294 | self.running = False # HS 06/29/2020 295 | self.rootWindow.quit() 296 | plt.close('all') # HS 06/29/2020 297 | self.rootWindow.destroy() 298 | 299 | def showHelp(self, widget,text): 300 | def setText(self): 301 | self.statusText.set(text) 302 | self.status.configure(foreground='blue') 303 | def showHelpLeave(self): 304 | self.statusText.set(self.statusStr) 305 | self.status.configure(foreground='black') 306 | widget.bind("", lambda e : setText(self)) 307 | widget.bind("", lambda e : showHelpLeave(self)) 308 | --------------------------------------------------------------------------------