7

I want to "visually" animate Markov chains like here : http://markov.yoriz.co.uk/ but using Python instead of html css and javascript.

I don't know if there is any library that makes this easy, till now I managed to make a visual representation of Markov chains using Networkx library like in the figure below, but couldn't get it to be animated (or simulated)

Here is my code so far:

from networkx.drawing.nx_pydot import write_dot
import networkx as nx
import matplotlib.pyplot as plt

states = [(0, 0),
          (1, 0),
          (2, 0),]


Q = [[5, 5, 0.4],
     [1, 2, 3],
     [4, 0.7, 0]
     ]


G = nx.MultiDiGraph()
labels={}
edge_labels={}

for i, origin_state in enumerate(states):
    for j, destination_state in enumerate(states):
        rate = Q[i][j]
        if rate > 0:
            G.add_edge(origin_state, destination_state, weight=rate, label="{:.02f}".format(rate))
            edge_labels[(origin_state, destination_state)] = label="{:.02f}".format(rate)



plt.figure(figsize=(10,7))
node_size = 200
pos = {state:list(state) for state in states}
nx.draw_networkx_edges(G,pos,width=1.0,alpha=0.5)
nx.draw_networkx_labels(G, pos, font_weight=2)
nx.draw_networkx_edge_labels(G, pos, edge_labels)
plt.axis('off');
plt.show()

write_dot(G, 'mc.dot')

from subprocess import check_call
nfile = 'w.png' 
check_call(['dot', '-Tpng', 'mc.dot', '-o', nfile])

import matplotlib.image as mpimg
img = mpimg.imread(nfile)
plt.axis('off')
plt.imshow(img)
plt.show()

enter image description here

2

1 Answer 1

1

You can do that by sampling from your Markov chain over a certain number of steps (100 in the code below) and modifying the color of the selected node at each step (see more here on how to change color of the nodes with graphviz). You can then create a png file of your network for each step and use imageio to generate a GIF from the png images (see more details on how to do that here).

Below is the full code:

import networkx as nx
from networkx.drawing.nx_agraph import to_agraph
import numpy as np
import imageio

#Markov chain parameters
states = [(0, 0),
          (1, 0),
          (2, 0),]


Q = [[0.2, 0.3, 0.5],
     [0.1, 0.2, 0.7],
     [0.3, 0.7, 0]
     ]

#Sampling the markov chain over 100 steps
N_steps=100
node_ind=0
node_sel=[node_ind]
for i in range(N_steps):
  temp_ni=np.random.choice(3,p=Q[node_ind])
  node_sel.append(temp_ni)
  node_ind=temp_ni

#Setting up network
G = nx.MultiDiGraph()
[G.add_node(s,style='filled',fillcolor='white',shape='circle',fixedsize='true',width=0.5) for s in states]

labels={}
edge_labels={}

for i, origin_state in enumerate(states):
    for j, destination_state in enumerate(states):
        rate = Q[i][j]
        if rate > 0:
            G.add_edge(origin_state, destination_state, weight=rate, label="{:.02f}".format(rate),len=2)

#Setting up node color for each iteration     
for k in range(N_steps):
  for i,n in enumerate(G.nodes(data=True)):
    if i==node_sel[k]:
      n[1]['fillcolor']='blue'
    else:
      n[1]['fillcolor']='white'
    
  A = to_agraph(G)
  A.layout()
  A.draw('net_'+str(k)+'.png')

#Create gif with imageio
images = []
filenames=['net_'+str(k)+'.png' for k in range(N_steps)]
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('markov_chain.gif', images,fps=3)

And here is the result:

enter image description here

Not the answer you're looking for? Browse other questions tagged or ask your own question.