Networkx is a python library for creation, manipulation and understanding structure of complex networks. It supports the creation of graphs, digraphs & multigraphs. It also has various graph algorithms by default.
Networkx supports nodes like text, images, XML and edges like time-series, weight, etc.
It can be used to analyze the structure of social, biological, infrastructure and various other types of networks.
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import os
import sys
import networkx as nx
import scipy
print('Python Version : '+sys.version)
print('NetworkX version : '+nx.__version__)
Users can test networkx library by running its tests using the below statements. I have commented on it as of now as It'll take time to run.
#nx.test()
Undirected Graphs can be created using simple Graph constructor. The graph consists of a list of nodes and node pairs (edges). Any hashable object except None can be node of graph-like text, image, etc. including another graph as well.
It allows self-loop for node but it does not allow parallel edges (more than 1 edges between 2 nodes).
Graph constructor can be initialized in various ways mentioned below:
G = nx.Graph()
G1 = nx.Graph([(4,5),(6,7),(8,9), (5,7),(4,9), (9,7)]) ## Creating graphs from list of edges
G2 = nx.Graph(G1) ## Creating graph from existing graph
G3 = nx.Graph(dict([(4,[(6,7),(2,3)]),(6,(8,9)), (5,(5,7)),(7,(4,9)), (9,(9,7))])) ## Creating graph from dict of list
G4 = nx.Graph(dict([(4,{6:7}),(6,{10:11}), (5,{5: 7}),(7,{4: 9}), (9,{9:7})])) ## Creating graph from dict of dict
l = np.random.rand(5,5)
print(l)
G5 = nx.Graph(l) ## Creating graph from numpy 2-d array
row = [0,3,1,0]
col = [0,3,1,2]
data = [4,5,7,9]
sparse_mat = scipy.sparse.coo_matrix((data, (row, col)), shape=(4,4)) ## Creating graph from scipy sparse matrix
print(sparse_mat.toarray())
G6 = nx.Graph(sparse_mat)
plt.figure(figsize=(12,3))
plt.subplot(1,6,1)
nx.draw(G1, with_labels=True, font_weight='bold')
plt.title('G1')
plt.subplot(1,6,2)
nx.draw(G2, with_labels=True, font_weight='bold')
plt.title('G2')
plt.subplot(1,6,3)
nx.draw(G3, with_labels=True, font_weight='bold')
plt.title('G3')
plt.subplot(1,6,4)
nx.draw(G4, with_labels=True, font_weight='bold')
plt.title('G4')
plt.subplot(1,6,5)
nx.draw(G5, with_labels=True, font_weight='bold')
plt.title('G5')
plt.subplot(1,6,6)
nx.draw(G6, with_labels=True, font_weight='bold')
plt.title('G6')
None
Below we are analyzing properties of graphs created above using various methods.
for i, graph in enumerate([G1,G2,G3,G4,G5,G6], start=1):
print('Graph%d : '%i)
print('Nodes : %s'%graph.nodes,'Edges : %s'%graph.edges)
print('Attribute with first edge : %s'%graph.get_edge_data(*list(graph.edges)[0]))
print('Nodes with selfloops : %s'%list(graph.nodes_with_selfloops()))
print('Undirected : %s'%graph.is_directed())
print('Number of Edges : %s'%graph.number_of_edges())
print('Number of Nodes : %s'%graph.number_of_nodes())
print('Graph size : %s'%graph.size())
print('Graph adjacent nodes : %s'%graph.adj)
print('Degree of each node : %s'%graph.degree)
print(graph.name)
There are various methods available to add new nodes and edges to the graph. We have listed below a few of them. One can add any hashable python object as a node to the graph. One can add another graph as well as a node to an existing graph.
plt.figure(figsize=(8,4))
G = nx.Graph()
G.add_node(1), G.add_node(32), G.add_node('Node1'), G.add_node('Node2'), G.add_node('Node3')
G.add_nodes_from([2,3])
G.add_edge(1,3), G.add_edge('Node2','Node3'), G.add_edge(1,'Node1')
G.add_edges_from([(26,27, {'weight': 3.14}),(28,29, {'weight': 6.45})])
G.add_cycle([4,5,6,7,20,21,22,4])
G.add_star([8,9,10,11,12,13,25])
G.add_path([14,15,16,17])
print(G.get_edge_data(26,27), G.get_edge_data(28,29))
nx.draw(G, with_labels=True, font_weight='bold')
H = nx.path_graph(10)
G.add_nodes_from(H)
G.remove_node(32), G.remove_node('Node2'), G.remove_node(28) ## Removing node 'Node2' & 28 also removed edges associated with them
G.remove_edge(26,27) ## Though edge 26-27 is removed but node 26,27 will still be existing independent
nx.draw(G, with_labels=True, font_weight='bold')
nx.draw_shell(G, with_labels=True, font_weight='bold')
nx.draw_random(G, with_labels=True, font_weight='bold')
G = nx.dfs_tree(G)
nx.draw(G, with_labels=True, font_weight='bold')
G = nx.bfs_tree(G,source=8)
nx.draw(G, with_labels=True, font_weight='bold')
G = nx.dodecahedral_graph()
nx.draw(G, with_labels=True, font_weight='bold')
Di_G = nx.DiGraph(G)
nx.draw(Di_G, with_labels=True, font_weight='bold')
Di_G1 = nx.DiGraph(G1)
nx.draw(Di_G1, with_labels=True, font_weight='bold')