1

I have a directed multigraph that I want to represent as a (complete) directed graph with edge meta-data such that if there are e number of edges from node A to node B (in the original multigraph) then I save e as the meta-data for the edge (A,B) in the new (not-multi) directed graph.

I can construct the graph as follows:

DG = nx.complete_graph(node_list, create_using= nx.DiGraph() )

where node_list = ['node_A', 'node_B', ....]

I can add the edges using:

DG.edges[('node_A', 'node_B')]['edge_count'] = 1

But how do I print this value (nicely) using the draw command? I tried the following

nx.draw(DG, with_labels = True)
plt.show()

But the edge values hide; what's more, I would need a nice way to show the meta-data associated with edge (A,B) and easily distinguishing it from edge (B,A).

Ben Grossmann
  • 4,387
  • 1
  • 12
  • 16
Squirtle
  • 129
  • 8

1 Answers1

1

You should be able to do the following:

edge_labels = nx.get_edge_attributes(G,'edge_count')

pos = nx.spring_layout(G)
nx.draw(G, pos = pos, with_labels=True)
nx.draw_networkx_edge_labels(G, pos=pos, edge_labels = edge_labels)
plt.show()

Here's an approach that uses curved arrows to avoid overlapping labels

import networkx as nx
import matplotlib.pyplot as plt

G = nx.DiGraph()

G.add_nodes_from(range(4))

G.add_edge(0,1,edge_count = 1)
G.add_edge(1,0,edge_count = 2)
G.add_edge(1,2,edge_count = 2)
G.add_edge(2,3,edge_count = 3)
G.add_edge(3,0,edge_count = 2)

def offset(d, pos, dist = .1):
    for (u,v),obj in d.items():
        par = dist*(pos[v] - pos[u])
        dx,dy = par[1],-par[0]
        x,y = obj.get_position()
        obj.set_position((x+dx,y+dy))

edge_labels = nx.get_edge_attributes(G,'edge_count')
pos = nx.spring_layout(G)
nx.draw(G, pos = pos, with_labels=True, connectionstyle = 'arc3,rad=0.2', node_color = 'orange')
d = nx.draw_networkx_edge_labels(G, pos=pos, edge_labels = edge_labels)
offset(d,pos)
plt.gca().set_aspect('equal')
plt.show()

Result from the above:

enter image description here

Ben Grossmann
  • 4,387
  • 1
  • 12
  • 16
  • ValueError: Received invalid argument(s): edge_labels Is this because I only gave one edge a value? I only gave one edge a value to quickly test it. – Squirtle Nov 17 '22 at 19:06
  • @Squirtle No, I made a mistake; see my latest edit. This should work now – Ben Grossmann Nov 17 '22 at 19:24
  • it "works" but the issue I'm having now is what I was afraid of... If G.edges[('A', 'B')]['edge_count'] = 1 and G.edges[('B', 'A')]['edge_count'] = 2 then it is only showing "2" between the edges, but I want to somehow have both pairs of numbers.... ideally in a way that is very clear and neat. By the way, the total number of nodes is 6, so that would mean there are 6*(6-1)/2 "bi-edges" or 6*(6-1) edges.... which is just at the limit of what is visually not overwhelming. But again, the issue is that I can only get one number to show between the edges. – Squirtle Nov 17 '22 at 19:36
  • @Squirtle Interesting... you might find [this post](https://stackoverflow.com/a/72184427/2476977) to be useful – Ben Grossmann Nov 17 '22 at 20:07
  • @Squirtle I came up with another approach using curved edges; see my edit – Ben Grossmann Nov 17 '22 at 21:52
  • @Squirtle For proper placement, the `dist` argument of the offset function should be half of the value from `'arc3,rad=___'` – Ben Grossmann Nov 17 '22 at 21:54
  • thank you for this fine answer. I hope it helps many in the future. Cheers! – Squirtle Nov 20 '22 at 17:51