avatarWei-Meng Lee

Summary

This article provides a comprehensive guide on using the NetworkX package in Python to create and visualize network graphs, including both undirected and directed graphs, with customizable layouts, labels, and styling options.

Abstract

The article titled "Plotting Network Graphs using Python" serves as a tutorial for utilizing the NetworkX package to visualize complex networks. It begins by explaining the concept of network graphs and their utility in analyzing relationships, illustrated by an example from Wikipedia. The author then guides readers through the process of installing NetworkX, understanding basic graph terminologies, creating a graph, adding nodes and edges, and visualizing the graph with various layouts and labels. The article emphasizes the importance of customizing nodes and edges for better clarity and aesthetic appeal, demonstrating how to set node colors, sizes, and outlines, as well as label edges. The tutorial culminates in the creation of a directed graph, showcasing the versatility of NetworkX for different types of network analysis. The author concludes by hinting at a follow-up article that will delve into visualizing connections between airports using a Flights Delay dataset.

Opinions

  • The author believes that a graph without labels is not very useful, highlighting the necessity of clear labeling for practical applications.
  • The article suggests that using different layouts can provide unique insights into the structure of a network graph, with the circular layout being particularly useful for certain types of analysis.
  • The author expresses a preference for the NetworkX package as a tool for network graph visualization due to its ease of use and flexibility in customization.
  • The use of color palettes and manual color specification is recommended for distinguishing nodes, with the author providing examples using the Spectral palette from Bokeh.
  • The author encourages readers to support their work by becoming Medium members, indicating that such support enables the creation of more content like the current article.
  • The article concludes with a teaser for future content, suggesting that the author values continuous learning and application of network analysis in real-world datasets.

Plotting Network Graphs using Python

Learn how to use the NetworkX package to visualize complex networks

Photo by Alina Grubnyak on Unsplash

A network graph is a form of visualization that enables you to visualize and analyze the relationships between entities. For example, the following figure shows the contribution of Wikipedia editors to the various Wikipedia language versions during one month in the summer of 2013.

Source: https://en.wikipedia.org/wiki/Graph_theory#/media/File:Wikipedia_multilingual_network_graph_July_2013.svg

From the network graph, you can gather a few observations:

  • English (en) is the dominant language where all the other languages are translated into; at the same time, a lot of English materials are also translated into other languages
  • Chinese (zh) is translated into Japanese (ja), but not the other way
  • Both Chinese and Japanese materials are translated into English, and vice versa

In this article, I will show you the basics of plotting network graphs using the NetworkX package.

Installing NetworkX

To install the NetworkX package, use the pip command:

!pip install networkx

Some Graph Terminologies

Before you start plotting your network graph, it is useful to understand some basic network graph terminologies.

The following figure shows a directed graph (also known as a digraph; a graph in which the edges have a direction as indicated by the arrows):

All images by author
  • The nodes are the fundamental units in a graph. Nodes are also commonly known as vertices.
  • The edges are the connections between two nodes in the graph.

An undirected graph, on the other hand, has no directions between nodes (and hence no arrows) and the edges are bidrectional.

Creating a Graph

Let’s now get to work to create a network graph. We shall do this step-by-step.

First, create a networkx.classes.graph.Graph object:

import networkx as nx

G = nx.Graph()
print(G)

# Graph with 0 nodes and 0 edges

The nx.Graph() class creates a undirected graph. If you want to create a directed graph, use nx.DiGraph(directed=True), which returns an networkx.classes.digraph.DiGraph object.

We will talk about directed graph later in this article.

Adding Nodes

With the graph created (G), you now need to add some nodes to it:

G.add_node("Singapore")
G.add_node("San Francisco")
G.add_node("Tokyo")

print(G)
# Graph with 3 nodes and 0 edges

The above code snippet added three nodes to the graph, with no edges defined (yet). Besides using the add_node() function to add individual nodes, you can also add multiple nodes in one go using the add_nodes_from() function:

G.add_nodes_from(["Riga", "Copenhagen"])
print(G)
# Graph with 5 nodes and 0 edges

Your graph has five nodes at this moment.

Adding Edges

With the nodes defined, you can now add the edges to connect them:

G.add_edge("Singapore","San Francisco")
G.add_edge("San Francisco","Tokyo")
G.add_edges_from(
    [
        ("Riga","Copenhagen"),
        ("Copenhagen","Singapore"),
        ("Singapore","Tokyo"),
        ("Riga","San Francisco"),
        ("San Francisco","Singapore"),
    ]
)

print(G)
# Graph with 5 nodes and 6 edges

Like nodes, you can add individual edge using the add_edge() function, or add multiple edges using the add_edges_from() function (just supply a list of tuples representing each edge).

Drawing the Graph

With the nodes and edges added to the graph, you are now ready to visualize the graph using the draw() function:

nx.draw(G)

You should see something like this:

Note that you will get a different graph every time you call the draw() function.

Here is another variation of the same graph:

Displaying the labels

Apparently, a graph without labels is not very useful (if useable at all!). So let’s draw the graph with the nodes labelled:

nx.draw(G, with_labels = True)

The above draw() function with the with_labels parameter is equivalent to calling the following functions:

  • nx.draw_networkx_nodes() — draws all the nodes in the graph
  • nx.draw_networkx_labels() — draws the labels on each node
  • nx.draw_networkx_edges() — draws the edges connecting the nodes

So what are the advantages of using the draw() function vs the other functions? Well, drawing using the individual functions allow you to customize the look and feel of individual nodes, labels, and edges.

You can now see the label for each node:

Using layouts

Remember that the draw() function uses a different layout for your graph every time you plot it? Well, you can specify the layout you want to use for your graph. Here is an example:

pos = nx.circular_layout(G)
nx.draw(G, pos, with_labels = True)

All the nodes will now be arranged in a circular manner:

Alternatively, you can also draw the graph using the circular layout through the nx.draw_circular() function (instead of the nx.draw() function):

nx.draw_circular(G, with_labels = True)

You can try the other layouts:

  • nx.draw_kamada_kawai(G, with_labels = True)
  • nx.draw_planar(G, with_labels = True)
  • nx.draw_random(G, with_labels = True)
  • nx.draw_spectral(G, with_labels = True)
  • nx.draw_spring(G, with_labels = True)
  • nx.draw_shell(G, with_labels = True)

Labelling the edges

With the nodes labelled, you might also want to label the edges. You can do so via the nx.draw_networkx_edge_labels() function.

pos = nx.circular_layout(G)
nx.draw(G, pos, with_labels = True)
nx.draw_networkx_edge_labels(
    G, 
    pos,
    edge_labels={
        ("Singapore","Tokyo"): '2 flights daily', 
        ("San Francisco","Singapore"): '5 flights daily',
    },
    font_color='red'
)

The above code snippets labels the two edges for the three nodes:

Directed Graph

So far our graph is undirected. In some cases it might be useful to plot a directed graph. For instance, in our example the edges might represent the flights between two cities. Using a directed graph allows us to visually inspect which are the flights going from one city to another. The following code snippet shows our example now plotted as a directed graph:

import networkx as nx

#---directed graph---
G = nx.DiGraph(directed=True)

# add nodes
G.add_node("Singapore")
G.add_node("San Francisco")
G.add_node("Tokyo")
G.add_nodes_from(["Riga", "Copenhagen"])

# add edges
G.add_edge("Singapore","San Francisco")
G.add_edge("San Francisco","Tokyo")
G.add_edges_from(
    [
        ("Riga","Copenhagen"),
        ("Copenhagen","Singapore"),
        ("Singapore","Tokyo"),
        ("Riga","San Francisco"),
        ("San Francisco","Singapore"),
    ]
)
# set layout
pos = nx.circular_layout(G)

# draw graph
nx.draw(G, pos, with_labels = True)

# draw edge labels
nx.draw_networkx_edge_labels(
    G, pos,
    edge_labels={
        ("Singapore","Tokyo"): '2 flights daily', 
        ("San Francisco","Singapore"): '5 flights daily',
    },
    font_color='red'
)

You can now observe that there are flights from Singapore to San Francisco, and vice versa. On the other hand, there is flights from Riga to San Francisco, but not the other way round.

Customizing the Nodes

By default, the nodes are blue in color and the size is pretty small. You can customize the nodes as well as the edge color by passing a dictionary to the draw() function:

options = {
    'node_color': 'yellow',     # color of node
    'node_size': 3500,          # size of node
    'width': 1,                 # line width of edges
    'arrowstyle': '-|>',        # array style for directed graph
    'arrowsize': 18,            # size of arrow
    'edge_color':'blue',        # edge color
}

nx.draw(G, pos, with_labels = True, arrows=True, **options)

The nodes are now in yellow (and bigger) and the edges are in blue:

Outlining the Nodes

If you want to outline the nodes, you need to manually do it using matplotlib. The following code snippet sets the figure size to 10 inches by 10 inches (width x height) and then use the set_edgecolor() function to draw a black outline for each node:

import matplotlib.pyplot as plt

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

pos = nx.circular_layout(G)

options = {
    'node_color': 'yellow',
    'node_size': 8500,
    'width': 1,
    'arrowstyle': '-|>',
    'arrowsize': 18,
}

nx.draw(G, pos, with_labels = True, arrows=True, **options)

ax = plt.gca()
ax.collections[0].set_edgecolor("#000000")

Each of the nodes now have a black outline:

If you did not set the figure size, your graph may look like this:

Setting Node Colors

To give each node a different color, you can specify a color palette, such as from bokeh, and set the color in the node_color key in the dictionary to be passed into the draw() function:

from networkx import *
import matplotlib.pyplot as plt
from bokeh.palettes import Spectral

plt.figure(figsize=(8, 8))

pos = nx.circular_layout(G)

options = {
    'node_color': Spectral[5],  # first 5 colors from the Spectral palette
    'node_size': 8500,
    'width': 1,
    'arrowstyle': '-|>',
    'arrowsize': 18,
}

nx.draw(G, pos=pos, with_labels = True, arrows=True, **options)

ax = plt.gca()
ax.collections[0].set_edgecolor("#000000")

The graph will now have different colors for each node:

If you want to specify your own colors, you can set them manually in the dictionary:

options = {
    'node_color': ['yellow','magenta','lightblue','lightgreen','pink'],
    'node_size': 8500,
    'width': 1,
    'arrowstyle': '-|>',
    'arrowsize': 18,
}

Related Articles

If you like reading my articles and that it helped your career/study, please consider signing up as a Medium member. It is $5 a month, and it gives you unlimited access to all the articles (including mine) on Medium. If you sign up using the following link, I will earn a small commission (at no additional cost to you). Your support means that I will be able to devote more time on writing articles like this.

Summary

In this article, I discussed the basics of network graph and how it is useful to let you visualize the relationships between different entities in your dataset. For this article, my focus is on how to use the NetworkX package to plot the graph. In my next article, I will make use of the Flights Delay dataset and visualize the connections between different airports. Stay tuned!

Networkx
Network Graph
Directed Graph
Undirected Graph
Editors Pick
Recommended from ReadMedium