Draw Graphs proportional to weight of edges using networkx - python-3.x

I'm having a Graph to display, but it should be displayed where edges are proportional to the weight. I used networkx library to draw the graph but it draw nodes randomly.
Here is the part of my code to display graph:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
# Added nodes and Edges
pos = nx.spring_layout(G)
nx.draw(graph, pos=pos, nodelist=nodes, with_labels=True)
plt.show()
How can I create a graph where the edge length is weighted?
If it helps I'm also open to use a different library than matplotlib.

The graphviz force directed algorithm outputs what I want. (But I am not sure why it is different than the spring layout from networkx)
import networkx as nx
import pylab as plt
from networkx.drawing.nx_agraph import graphviz_layout
G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_edge(1,2, len=4.5)
G.add_edge(2,3, len=2.5)
G.add_edge(3,4, len=7)
G.add_edge(4,1, len=10)
G.add_edge(3,1, len=4.5)
G.add_edge(4,2, len=9)
pos=graphviz_layout(G)
nx.draw(G, pos, node_size=1600, node_color=range(len(G)), with_labels=True, cmap=plt.cm.Dark2)
plt.show()

Related

Networkx: how to add edge labels from csv file in a graph

How can I add Edge label from csv/excel file to networkx directed graph
I want to add labels to my networkx graph from column Edge_label present in csv file
import pandas as pd
import matplotlib.pyplot as plt
#%matplotlib inline
import networkx as nx
df = pd.read_csv('Trail_data.csv')
g = nx.from_pandas_edgelist(df,
'Source',
'Target',
create_using=nx.DiGraph() # For Directed Route arrows
)
plt.figure( figsize=(40, 40)
)
nx.draw(g,
with_labels=True,
node_size= 3000,#k=200,
node_color='#82CAFF',##00b4d9
font_size=16,
font_weight ='bold',
font_color='black',
edge_color = ('#E55451','#810541','#00FF00'),
node_shape='o',
width=4 ,
arrows=True, #Show arrow From and To
pos=nx.random_layout(g),iterations=20,
connectionstyle='arc3, rad =0.11' #To avoid overlapping edgs
)
plt.savefig('Visualization.jpeg',
dpi = (100)
)
** Also I wanted to convert this directed graph to interactive graph with python-dash **
According to the documentation of from_pandas_edgelist you can simply specify a list of columns with edge_attr.
In your case, you get the desired graph with:
g = nx.from_pandas_edgelist(df,
'Source',
'Target',
edge_attr=`Edge_label`,
create_using=nx.DiGraph(),)
For drawing you currently only draw node labels. You can add edge labels with draw_networkx_edge_labels
pos = nx.random_layout(g)
nx.draw(g,
pos=pos, ...) # add other parameters
edge_labels = nx.get_edge_attributes(g, "Edge_label")
nx.draw_networkx_edge_labels(g, pos, edge_labels)

Renaming a Graph in Networkx

I am new on Python and I am trying to learn Networkx ( https://networkx.github.io/ )
I am trying to run a basic a code:
import networkx as nx
import matplotlib.pyplot as plt
G=nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
G.add_node(6)
G.add_node(7)
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(3,4)
G.add_edge(4,5)
G.add_edge(5,6)
G.add_edge(6,7)
G.add_edge(7,1)
G.add_edge(1,3)
G.add_edge(1,4)
G.add_edge(1,5)
G.add_edge(1,6)
G.add_edge(1,7)
G.add_edge(2,4)
G.add_edge(2,5)
G.add_edge(2,6)
G.add_edge(2,7)
G.add_edge(3,5)
G.add_edge(3,6)
G.add_edge(3,7)
G.add_edge(4,6)
G.add_edge(4,7)
G.add_edge(5,7)
nx.draw(G)
plt.savefig("graph1.png")
plt.show()
and this is the graph generated:
The problem comes when trying to add names to the nodes. I am running the next code:
import networkx as nx
import matplotlib.pyplot as plt
G=nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
G.add_node(6)
G.add_node(7)
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(3,4)
G.add_edge(4,5)
G.add_edge(5,6)
G.add_edge(6,7)
G.add_edge(7,1)
G.add_edge(1,3)
G.add_edge(1,4)
G.add_edge(1,5)
G.add_edge(1,6)
G.add_edge(1,7)
G.add_edge(2,4)
G.add_edge(2,5)
G.add_edge(2,6)
G.add_edge(2,7)
G.add_edge(3,5)
G.add_edge(3,6)
G.add_edge(3,7)
G.add_edge(4,6)
G.add_edge(4,7)
G.add_edge(5,7)
names = {1:"Central",2:"South",3:"North",4:"East",5:"West",6:"Up",7:"Down"}
H=nx.relabel_nodes(G,names)
nx.draw(H)
plt.savefig("graph1.png")
plt.show()
and the resulted graph is this one:
How can I add names to the nodes? I am using python 3.8 and Networkx 2.4
You can either use nx.draw(H, with_labels=True),
Or nx.draw_networkx(H), which has with_labels=True as default.
documentation of nx.draw:
draw(G, pos=None, ax=None, **kwds)
[...]
kwds (optional keywords) – See networkx.draw_networkx() for a description of optional keywords.
documentation of nx.draw_networkx
draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)
[...]
with_labels (bool, optional (default=True)) – Set to True to draw labels on the nodes.
edit:
draw edges with different colors:
check out the function nx.draw_networkx_edges
relevant attributes:
edge_color (color string, or array of floats) – Edge color. Can be a single color
format string (default=’r’), or a sequence of colors with the same length as edgelist. If numeric values are specified they will be mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters.
style (string) – Edge line style (default=’solid’) (solid|dashed|dotted,dashdot)
alpha (float) – The edge transparency (default=1.0)
cmap (edge) – Colormap for mapping intensities of edges (default=None)
edge_vmin,edge_vmax (floats) – Minimum and maximum for edge colormap scaling (default=None)
So, you can make a list of strings:
colors = ['red'] * len(G.edges()
pos = nx.spring(layout(G))
nx.draw_networkx_nodes(G, pos=pos)
nx.draw_networkx_edges(G, pos=pos, edge_color=colors)
or use numbers and a colormap:
colors = [np.random.rand() for e in G.edges()]
pos = nx.spring(layout(G))
nx.draw_networkx_nodes(G, pos=pos)
nx.draw_networkx_edges(G, pos=pos, edge_color=colors, cmap='viridis')

How can i get Networkx to show both weights on an edge that is going in 2 directions?

I have a text file with the following data:
192.168.12.22 192.168.12.21 23
192.168.12.21 192.168.12.22 26
192.168.12.23 192.168.12.22 56
There are three nodes and two of them are sending packets to each other. I want to be able to show both weights on two different edges, but it only shows one with a single weight.
This is my code:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.read_weighted_edgelist('test.txt', create_using=nx.DiGraph())
pos = nx.spring_layout(G)
print(nx.info(G))
nx.draw(G, pos, with_labels=True)
nx.draw_networkx_edge_labels(G, pos)
plt.show()
You can use the label_pos parameter (see draw_networkx_edge_labels):
import networkx as nx
import matplotlib.pyplot as plt
edges = [["192.168.12.22", "192.168.12.21", 23],
["192.168.12.21", "192.168.12.22", 26],
["192.168.12.23", "192.168.12.22", 56]]
graph = nx.DiGraph()
graph.add_weighted_edges_from(edges)
pos = nx.spring_layout(graph)
nx.draw(graph, pos, with_labels=True)
nx.draw_networkx_edge_labels(graph,
pos,
edge_labels={(u, v): d for u, v, d in graph.edges(data="weight")},
label_pos=.66)
plt.show()
You may also want to take a look at this answer.

North polar stereographic projection is not working

I am trying to create a stereographic plot using Basemap offset from the north pole, but the west-east directions are apparently reversed. Is this an error in my implementation, or a bug?
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
m = Basemap(projection='stere',
lat_0=90, lon_0=270, lat_ts=(90.+35.)/2.,
llcrnrlon=150,urcrnrlon=-60,llcrnrlat=50,urcrnrlat=50)
m.drawmeridians(np.arange(0,360,30),labels=[1,1,1,0])
m.drawparallels(np.arange(-90,90,5))
m.drawcoastlines()
m.shadedrelief()
plt.show()
Here is the result:
result from script
How might I reproduce the following map (which is offset-centred, and rotated?)
Restricted map
Using an azimuthal type of map projection always requires a set of proper parameters to get a good result. In this case, Stereographic projection centered at the north pole, its proper parameters are not what you usually use when implement with PlateCaree projection which is often used. Here is a working code that you may try.
# Stereographic projection coverage
# should be specified less than half of a hemisphere
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
m = Basemap(projection='stere', resolution='c',
lat_0=90, lon_0=270, lat_ts=(90.+35.)/2., width=15000000, height=10000000)
# (width, height) is the plot extents in meters
m.drawmeridians(np.arange(0, 360, 30), labels=[1,1,1,0])
m.drawparallels(np.arange(0, 90, 10), labels=[0,0,0,1])
m.drawcoastlines()
m.shadedrelief()
plt.show()
The resulting plot (map 1):
To get other part of the world into the plotting area is achieved by recentering the map.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
# projection center point
lon0 = 180
lat0 = 60
m = Basemap(projection='stere', resolution='c',
lat_0=lat0, lon_0=lon0, lat_ts=lat0, width=15000000, height=10000000)
m.drawmeridians(np.arange(0, 360, 30), labels=[1,0,0,1]) # left, right, top, bottom
m.drawparallels(np.arange(0, 90, 10), labels=[0,1,1,0])
m.drawcoastlines()
m.shadedrelief()
plt.show()
The output plot (map 2):
By specifying proper values of llcrnrlon, urcrnrlon, llcrnrlat, urcrnrlat, in Basemap() one can get the map extents as required. Here is another example of plot as requested by the OP.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(8,8))
m = Basemap(projection='stere', resolution='c',
lat_0=90, lon_0=-90, lat_ts=(90.+35.)/2.,
llcrnrlon=-142, urcrnrlon=78, llcrnrlat=19, urcrnrlat=45)
m.drawmeridians(np.arange(0, 360, 30), labels=[1,0,1,0]) # left, right, top, bottom
m.drawparallels(np.arange(0, 90, 10), labels=[0,1,0,1])
m.drawcoastlines()
m.shadedrelief()
plt.show()
The resulting plot (map 3):

Assign edge weights to a networkx graph using pandas dataframe

I am contructing a networkx graph in python 3. I am using a pandas dataframe to supply the edges and nodes to the graph. Here is what I have done :
test = pd.read_csv("/home/Desktop/test_call1", delimiter = ';')
g_test = nx.from_pandas_edgelist(test, 'number', 'contactNumber', edge_attr='callDuration')
What I want is that the "callDuration" column of the pandas dataframe act as the weight of the edges for the networkx graph and the thickness of the edges also change accordingly.
I also want to get the 'n' maximum weighted edges.
Let's try:
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
df = pd.DataFrame({'number':['123','234','345'],'contactnumber':['234','345','123'],'callduration':[1,2,4]})
df
G = nx.from_pandas_edgelist(df,'number','contactnumber', edge_attr='callduration')
durations = [i['callduration'] for i in dict(G.edges).values()]
labels = [i for i in dict(G.nodes).keys()]
labels = {i:i for i in dict(G.nodes).keys()}
fig, ax = plt.subplots(figsize=(12,5))
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, ax = ax, labels=True)
nx.draw_networkx_edges(G, pos, width=durations, ax=ax)
_ = nx.draw_networkx_labels(G, pos, labels, ax=ax)
Output:
Do not agree with what has been said. In the calcul of different metrics that takes into account the weight of each edges like the pagerank or the betweeness centrality your weight would not be taking into account if is store as an edge attributes.
Use graph.
Add_edges(source, target, weight, *attrs)

Resources