I'm trying to write a script that prompts a user to input a transition probability matrix for a Markov chain, and then displays the associated transition diagram.
Here's the relevant code:
class markov_graph:
def __init__(self, state_num, prob_matrix):
self.state_num = state_num
self.prob_matrix = prob_matrix
def create_graph(self):
G = nx.DiGraph()
for i in range(self.state_num):
G.add_node(i)
for i in range(self.state_num):
for j in range(self.state_num):
w = self.prob_matrix[i][j]
if w != 0:
G.add_edge(i, j, weight=w)
pos = nx.spring_layout(G, seed=42)
plt.figure(figsize=(6, 5))
nx.draw_networkx_nodes(
G, pos,
node_size=500,
node_color="lightgray",
linewidths=1,
edgecolors="black"
)
nx.draw_networkx_labels(
G, pos,
font_size=12,
font_color="black"
)
nx.draw_networkx_edges(
G, pos,
arrowstyle="->",
arrowsize=12,
edge_color="gray",
width=1.5,
connectionstyle="arc3,rad=0.1"
)
edge_labels = {
(u, v): f"{G[u][v]['weight']:.2f}"
for (u, v) in G.edges()
}
nx.draw_networkx_edge_labels(
G, pos,
edge_labels=edge_labels,
font_size=10,
label_pos=0.5,
rotate=False
)
plt.title("Markov Chain (Zero-weight edges hidden)")
plt.axis("off")
plt.tight_layout()
plt.show()
The problem is that when there are two opposite directional edges between two nodes, it labels both with just one of the weights, see below:
The weight of the edge from 2 to 1 is indeed 0.33, but the weight of the edge from 1 to 2 is supposed to be 0.25. I think the problem is how I define edge_labels, but this is my first time working with networkx and I'm fairly lost.
The problem was that label_pos=0.5
makes the two weight labels overlap. Setting it to 0.7
and writing connectionstyle='arc3,rad=0.4'
in both nx.draw_networkx_edges()
and nx.draw_networkx_edge_labels()
fixed the issue.