Directional graphs, multigraphs and visualization in Networkx

In

import networkx as nx

 

edges = [( 1 , 2 ), ( 1 , 6 ), ( 2 , 3 ), ( 2 , 4 ), ( 2 , 6 ), 

( 3 , 4 ), ( 3 , 5 ), ( 4 , 8 ), ( 4 , 9 ), ( 6 , 7 )]

 
G.add_edges_from ( edges)

nx.draw_networkx (G, with_label = True )

  

print ( "Total number of nodes:" , int (G.number_of_nodes ()))

print ( "Total number of edges:" , int (G.number_of_edges ()))

print ( " List of all nodes: " , list (G.nodes ()))

print ( "List of all edges:" , list (G.edges (data = True )))

print ( "Degree for all nodes:" , dict (G.degree ()))

 

print ( "Total number of self-loops:" , int (G.number_of_selfloops ()))

print ( "List of all nodes with self-loops:" ,

  list (G.nodes_with_selfloops ()))

 

print ( " List of all nodes we can go to in a singl e step from node 2: " ,

  list (G.neighbors ( 2 )))

Output:

Total number of nodes: 9
Total number of edges: 10
List of all nodes: [1, 2, 3, 4, 5, 6, 7, 8, 9]
List of all edges: [(1, 2, {}), (1, 6, {} ), (2, 3, {}), (2, 4, {}), (2, 6, {}), (3, 4, {}), (3, 5, {}), (4, 8, {}), (4, 9, {}), (6, 7, {})]
Degree for all nodes: {1: 2, 2: 4, 3: 3, 4: 4, 5: 1, 6: 3, 7: 1, 8: 1, 9: 1}
Total number of self-loops: 0
List of all nodes with self-loops: []
List of all nodes we can go to in a single step from node 2: [1, 3, 4, 6]

Create a weighted undirected graph —

Add with a list of all edges along with different weights —

import networkx as nx

G = nx.Graph ()

 

edges = [( 1 , 2 , 19 ), ( 1 , 6 , 15 ), ( 2 , 3 , 6 ), ( 2 , 4 , 10 ), 

( 2 , 6 , 22 ), ( 3 , 4 , 51 ), ( 3 , 5 , 14 ), ( 4 , 8 , 20 ),

  ( 4 , 9 , 42 ), ( 6 , 7 , 30 )]

 
G.add_weighted_edges_from (edges)

nx.draw_networkx (G, with_labels = True )

We can add edges using the Edge List, which needs to be saved in .txt format (for example edge_list.txt)

G = nx.read_edgelist ( `edge_list.txt` , data = [( ` Weight` , int )])

 1 2 19 1 6 15 2 3 6 2 4 10 2 6 22 3 4 51 3 5 14 4 8 20 4 9 42 6 7 30 

The border list can also be read through the Pandas Dataframe —

import pandas as pd

 

df = pd.read_csv ( `edge_list.txt` , delim_whitespace = True

header = None , names = [ `n1` , `n2` , ` weight` ])

 

G = nx.from_pandas_dataframe (df, `n1` , `n2` , edge_attr = ` weight ` )

  
# Chart The chart does not show edge weights.
# However, we can get the weight by printing all
# edges along with weights by the command below

print ( list (G.edges (data = True )))

Exit:

 [(1, 2 , {`weight`: 19}), (1, 6, {` weight`: 15}), (2, 3, {`weight`: 6}), (2, 4, {` weight`: 10} ), (2, 6, {`weight`: 22}), (3, 4, {` weight`: 51}), (3, 5, {`weight`: 14}), (4, 8, { `weight`: 20}), (4, 9, {` weight`: 42}), (6, 7, {`weight`: 30})] 

Now we will look at various methods of graph rendering .

To do this, we created a dataset for various Indian cities and distances between them and saved it in a file .txt , edge_list.txt .

 Kolkata Mumbai 2031 Mumbai Pune 155 Mumbai Goa 571 Ko lkata Delhi 1492 Kolkata Bhubaneshwar 444 Mumbai Delhi 1424 Delhi Chandigarh 243 Delhi Surat 1208 Kolkata Hyderabad 1495 Hyderabad Chennai 626 Chennai Thiruvananthapuram 773 Thiruvananthapuram Hyderabad 1299 Kolkata Varanasi p> Now we will make a graph using the following code. We will also add a node attribute to all the cities that will be the population of each city. 

import networkx as nx

 

G = nx.read_weighted_edgelist ( `edge_list.txt` , delimiter = "" )

 

population = {

`Kolkata` : 4486679 ,

  ` Delhi` : 11007835 ,

`Mumbai` : 12442373 ,

`Guwahati` : 957352 ,

`Bangalore` : 8436675 ,

  ` Pune` : 3124458 ,

`Hyderabad` : 6809970 ,

`Chennai` : 4681087 ,

  ` Thiruvananthapuram` : 460468 ,

`Bhubaneshwar` : 837737 ,

`Varanasi` : 1198491 ,

`Surat` : 4467797 ,

`Goa` : 40017 ,

` Chandigarh` : 961587

}

  
# We need to set the population attribute for each of the 14 nodes

for i in list (G.nodes ()):

G.nodes [i] [ `population` ] = population [i]

 

nx.draw_networkx (G, with_label = Tru e )

# This line allows us to render the graph

Output:

But we can configure the network to provide additional information visually by doing the following:

  1. The size of the node is proportional to the population of the city.
  2. The intensity of the color of the node is directly proportional to the degree of the node.
  3. The width of the edge is directly proportional to the weight of the edge, in this case the distance between cities.
  4. # fix figure size

    plt.figure (figsize = ( 10 , 7 ))

     

    node_color = [G.degree (v) for v in G]

    # node color - list of node degrees

      

    node_size = [ 0.0005 * nx.get_node_attributes (G, `population` ) [v] for v in G]

    # node size - list of city population

     

    ed ge_width = [ 0.0015 * G [u] [v] [ ` weight` ] for u, v in G.edges ()]

    # edge width - list of edge weights

     

    nx.draw_networkx (G, node_size = node_size, 

    node_color = node_color, alpha = 0.7 ,

    with_labels = True , width = edge_width,

    edge_color = `.4` , cmap = plt.cm.Blues)

     

    plt.axis ( `off` )

    plt.tight_layout ( );

    Output:

    As you can see from the above code, we have specified the layout type as rigid. You can find different layout methods and try some of them, as shown in the code below:

    print ( "The various layout options are:" )

    print ([x for x in nx .__ dir __ () if x .endswith ( `_layout` )])

    # prints a list of all layout options

      

    node_color = [G.degree (v) for v in G]

    node_size = [ 0.0005 * nx.get_node_attributes (G, ` population` ) [v] for v in G]

    edge_width = [ 0.0015 * G [u] [v] [ `weight` ] for u, v in G.edges ()]

     

    plt.figure (figsize = ( 10 , 9 ))

    pos = nx.random_layout (G)

    print ( "Random Layout:" )

     
    # random layout demonstration

    nx. draw_networkx (G, pos, node_size = node_size, 

      node_color = node_color, alpha = 0.7

      with_labels = True , width = edge_width,

    edge_color = ` .4` , cmap = plt.cm.Blues)

     

     

    plt.figure (figsize = ( 10 , 9 ))

    pos = nx.circular_layout (G)

    print ( "Circular Layout" )

     
    # circular layout demonstration

    nx.draw_networkx (G, pos, node_size = node_size, 

    node_color = node_color, alpha = 0.7

      with_labels = True , width = edge_width, 

    edge_color = `.4` , cmap = plt.cm.Blues)

    Exit:

     The various layout options are: [`rescale_layout`,` random_layout`, `shell_layout`,` fruchterman_reingold_layout`, `spectral_layout`,` kamada_kawai_layout`, `spring_layout `,` circular_layout`] Random Layout:   Circular Layout:   

    Networkx allows us to create a Path Path, that is, a straight line connecting multiple nodes as follows:

    G2 = nx.path_graph ( 5 )

    nx.draw_networkx (G2, with_labels = True )

    We can rename the nodes —

    G2 = nx.path_graph ( 5 )

     

    new = { 0 : "Germany" , 1 : "Austria" , 2 : "France" , 3 : "Poland" , 4 : "Italy" }

    G2 = nx.relabel_nodes (G2, new)

    nx.draw_networkx (G2, with_labels = True )

    Creating a directed graph —

    Networkx allows us to work with directed graphs. Creating them, adding nodes, edges, etc. is exactly the same as creating an undirected graph as discussed here .

    The following code shows the basic operations on a Directed Graph.

    import networkx as nx

    G = nx.DiGraph ()

    G.add_edges_from ([( 1 , 1 ), ( 1 , 7 ), ( 2 , 1 ), ( 2 , 2 ), ( 2 , 3 ), 

    ( 2 , 6 ), ( 3 , 5 ), ( 4 , 3 ), ( 5 , 4 ), ( 5 , 8 ),