pythonnetworkx

How to label multigraph edges with different weights in networkx?


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:

graph

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.


Solution

  • 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.