1

I'm trying to create a directed graph with weighted edges from the networkx library. The graph as shown in the picture is what im trying to achieve

Picture of 1 router and 2 nodes, communicating with known speeds

This is the code I've got so far

import networkx as nx
import matplotlib.pyplot as plt
import pandas as panda

df = panda.DataFrame({'from':['R','R','D04','D04','D06','D06'], 'to':['D04','D06','R','D06','R','D04']})
    G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.DiGraph()) 


    G['R']['D04']['weight'] = 243.0
    G['R']['D06']['weight'] = 150.0
    G['D06']['D04']['weight'] = 211.0
            

    pos = nx.spring_layout(G)
    labels = nx.get_edge_attributes(G,'weight')
    nx.draw_networkx_edge_labels(G,pos, edge_labels=labels)

    # Make the graph
    nx.draw(G, with_labels=True, node_size=1500, alpha=0.3, font_weight="bold", arrows=True)


    plt.axis('on')
    plt.show()

Pictures of what im getting:

Result1

Result2

I'm having a hard time figuring out how to enable the X/Y-axis. I don't know the placement of the different nodes, only that the Router node ('R') should be placed in (0,0). Furthermore my edge weights seem to be placed at random. Sometimes they are placed nicely, other times they go flying off. And lastly the directed edges seem to be straight, and not bent as wished. I've read there should be an attribute called 'connectionstyle', but just can't seem to get it working.

Quang Hoang
  • 146,074
  • 10
  • 56
  • 74

1 Answers1

2

The problem is that the spring layout is intended for much more complex networks, where you wouldn't want to control the positioning. In this case, you want to override the node placement algorithm (I think) by setting fixed positions, like this:

import networkx as nx
import matplotlib.pyplot as plt
import pandas as panda
df = panda.DataFrame({'from':['R','R','D04','D04','D06','D06'], 'to':['D04','D06','R','D06','R','D04']})
G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.DiGraph()) 
G['R']['D04']['weight'] = 243.0
G['R']['D06']['weight'] = 150.0
G['D06']['D04']['weight'] = 211.0
#pos = nx.spring_layout(G)
#instead of spring, set the positions yourself
labelPosDict = {'R':[0.1,0.3], 'D04':[0.5,.9], 'D06':[.9,.18]}
labels = nx.get_edge_attributes(G,'weight')
nx.draw_networkx_edge_labels(G,pos=labelPosDict, edge_labels=labels)
plt.axvline(.1, alpha=0.1, color='green')
plt.axhline(.3, alpha=0.1, color='green')
#Create a dict of fixed node positions
nodePosDict = {'R':[0.1,0.3], 'D04':[0.5,.9], 'D06':[.9,.18]}
# Make the graph - add the pos and connectionstyle arguments
nx.draw(G, k=5,with_labels=True, pos=nodePosDict,
        node_size=1500, alpha=0.3, font_weight="bold", arrows=True,
       connectionstyle='arc3, rad = 0.1')
plt.axis('on')
plt.show()

By controlling the pos dict, you can now place things exactly where you want them, and they won't change each time (spring uses a random starting point by default, that's why the layout changes each time)

enter image description here

James_SO
  • 1,169
  • 5
  • 11
  • Wow this seems awesome! I can see what you mean now by having to place the nodes myself. However this was only a thought I had as to have the nodes be placed correctly. The end goal wold be having the nodes be placed accordingly to how far they are away from each other via. the edge weights. Do you know how this would be done? – Peter Marcus Nov 27 '20 at 14:38
  • 1
    This answer seems to be on target for what you need to do, which is determine points based on distances. https://stackoverflow.com/questions/10963054/finding-the-coordinates-of-points-from-distance-matrix – James_SO Nov 27 '20 at 14:58
  • I'll have a look. Have a great day, thank you! – Peter Marcus Nov 27 '20 at 15:00
  • BTW. The nx.draw function complains about the 'k' variable. Deleting this makes your code run :) – Peter Marcus Nov 27 '20 at 15:17
  • 1
    Ah - I should have listed my versions - networkx: 2.4, matplotlib: 3.2.1 – James_SO Nov 27 '20 at 18:03