Languages

Network Visualization with Matplotlib and NetworkX: A Complete Guide

JGJaya Gupta21 Mar 2023 Β· Updated 04 Oct 2026 Β· 8 min read
Network Visualization with Matplotlib and NetworkX: A Complete Guide

Quick answer: NetworkX builds and analyses graphs β€” nodes connected by edges β€” while Matplotlib draws them. Create a nx.Graph(), add nodes and edges (devices and links, people and friendships, pages and hyperlinks), pick a layout such as spring_layout, and call nx.draw_networkx() followed by plt.show(). In about ten lines you have a diagram, and with a few more you can colour nodes by role, size them by importance and highlight the shortest path between any two points.

This guide walks from the minimal example through a realistic network-topology visualisation, explains the layout algorithms and when to use each, shows how to load data from CSV and compute graph metrics, and lists the mistakes that make graph plots unreadable. The code targets Python 3.9+, NetworkX 3.x and Matplotlib 3.x.

Why visualise networks as graphs?

A spreadsheet of 200 links tells you nothing at a glance. The same data drawn as a graph instantly reveals hubs, isolated islands, redundant paths and single points of failure. Graph thinking applies far beyond computer networks: social connections, supply chains, citation networks, microservice dependencies, flight routes and recommendation systems are all graphs. Learning NetworkX gives you one mental model and one toolset for every one of them.

Installing the libraries

Both packages are pure Python and install in seconds with pip install networkx matplotlib.

If you work in Jupyter, plots render inline automatically. In a plain script, plt.show() opens a window and plt.savefig("graph.png", dpi=150) writes a file.

Hands-on 1: the minimal graph

Start with the core vocabulary β€” nodes, edges, layout, draw:

import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()                                   # undirected graph
G.add_nodes_from([1, 2, 3, 4])
G.add_edges_from([(1, 2), (1, 3), (1, 4), (3, 4)])

print("Nodes:", G.number_of_nodes(), "Edges:", G.number_of_edges())
print("Degree of node 1:", G.degree[1])        # how many links it has

pos = nx.spring_layout(G, seed=42)               # seed makes the picture reproducible
nx.draw_networkx(G, pos, node_color="lightblue", node_size=900, font_weight="bold")
plt.axis("off")
plt.show()

Three things to note. add_edges_from creates any nodes that do not exist yet, so you often skip add_nodes_from. spring_layout runs a physics simulation; without a seed the picture changes every run. And nx.draw_networkx is the convenient all-in-one call; the individual draw_networkx_nodes, draw_networkx_edges and draw_networkx_labels functions give fine control when you need it.

Hands-on 2: a realistic network topology

Now a small enterprise network: two core switches, three distribution switches, access switches and a firewall. Nodes carry a role attribute, edges carry link speed in Gbps, and the plot encodes both.

import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()

devices = {
    "fw1": "firewall", "core1": "core", "core2": "core",
    "dist1": "distribution", "dist2": "distribution", "dist3": "distribution",
    "acc1": "access", "acc2": "access", "acc3": "access", "acc4": "access",
}
for name, role in devices.items():
    G.add_node(name, role=role)

links = [
    ("fw1", "core1", 10), ("fw1", "core2", 10), ("core1", "core2", 40),
    ("core1", "dist1", 10), ("core1", "dist2", 10), ("core2", "dist2", 10),
    ("core2", "dist3", 10), ("dist1", "acc1", 1), ("dist1", "acc2", 1),
    ("dist2", "acc3", 1), ("dist3", "acc4", 1),
]
G.add_weighted_edges_from(links, weight="speed")

colours = {"firewall": "#d9534f", "core": "#f0ad4e",
           "distribution": "#5bc0de", "access": "#5cb85c"}
node_colours = [colours[G.nodes[n]["role"]] for n in G.nodes]
edge_widths = [G.edges[e]["speed"] / 5 for e in G.edges]   # 1G thin, 40G thick

# Place devices in tiers using a shell layout: centre outwards
tiers = [["fw1"], ["core1", "core2"],
         ["dist1", "dist2", "dist3"], ["acc1", "acc2", "acc3", "acc4"]]
pos = nx.shell_layout(G, nlist=tiers)

plt.figure(figsize=(9, 7))
nx.draw_networkx_edges(G, pos, width=edge_widths, edge_color="grey")
nx.draw_networkx_nodes(G, pos, node_color=node_colours, node_size=1400, edgecolors="black")
nx.draw_networkx_labels(G, pos, font_size=9, font_weight="bold")
nx.draw_networkx_edge_labels(G, pos, edge_labels={e: f'{G.edges[e]["speed"]}G' for e in G.edges},
                             font_size=7)

for role, colour in colours.items():
    plt.scatter([], [], c=colour, s=120, label=role, edgecolors="black")
plt.legend(loc="lower left", frameon=False)
plt.title("Campus network topology")
plt.axis("off")
plt.tight_layout()
plt.savefig("topology.png", dpi=150)
plt.show()

If you collect real inventory with SNMP or SSH, as shown in Network Monitoring with Python: Using PySNMP and Netmiko, you can feed the discovered neighbour table straight into G.add_edge() and generate this diagram automatically every night.

Hands-on 3: load from CSV, analyse, highlight a path

Most real data lives in files or databases. This example reads an edge list, computes centrality to find the most important nodes, and highlights the shortest path between two devices in red.

import csv
import networkx as nx
import matplotlib.pyplot as plt

# links.csv has a header: source,target,latency_ms
G = nx.Graph()
with open("links.csv", newline="") as fh:
    for row in csv.DictReader(fh):
        G.add_edge(row["source"], row["target"], weight=float(row["latency_ms"]))

# --- analysis ---
centrality = nx.betweenness_centrality(G, weight="weight")
top = sorted(centrality, key=centrality.get, reverse=True)[:3]
print("Most critical nodes (betweenness):", top)
print("Connected components:", nx.number_connected_components(G))

path = nx.shortest_path(G, "siteA", "siteF", weight="weight")
print("Lowest-latency path:", " -> ".join(path),
      f'({nx.path_weight(G, path, "weight"):.1f} ms)')

# --- visualisation ---
pos = nx.kamada_kawai_layout(G)
sizes = [300 + 4000 * centrality[n] for n in G.nodes]     # bigger = more central
path_edges = list(zip(path, path[1:]))

nx.draw_networkx_nodes(G, pos, node_size=sizes, node_color="lightsteelblue", edgecolors="black")
nx.draw_networkx_edges(G, pos, edge_color="lightgrey")
nx.draw_networkx_edges(G, pos, edgelist=path_edges, edge_color="red", width=3)
nx.draw_networkx_labels(G, pos, font_size=8)
plt.title("Lowest-latency path from siteA to siteF")
plt.axis("off")
plt.show()

Betweenness centrality measures how many shortest paths pass through a node; a high value flags a device whose failure would hurt the most. That one metric alone often justifies learning NetworkX.

Choosing a layout algorithm

Layout How it positions nodes Use it when
spring_layout Force-directed physics; connected nodes attract General purpose, up to a few hundred nodes
kamada_kawai_layout Minimises distance error; often cleaner than spring Small to medium graphs where clarity matters
shell_layout Concentric circles you define Hierarchies: core/distribution/access
circular_layout All nodes on one circle Showing every connection evenly, ring topologies
multipartite_layout Columns by a node attribute Layered systems, bipartite data
spectral_layout Eigenvectors of the graph Laplacian Revealing clusters in larger graphs

For true tree-like hierarchies, install Graphviz and use nx.nx_agraph.graphviz_layout(G, prog="dot"), which produces the cleanest top-down diagrams.

Seven visualisation mistakes to avoid

  1. Drawing hundreds of labelled nodes. It becomes a hairball. Filter to a subgraph, aggregate, or label only the top-k nodes by centrality.
  2. No seed on spring_layout. Your diagram changes shape on every run and screenshots never match.
  3. Forgetting plt.axis("off"). Axis ticks are meaningless on a graph and clutter the image.
  4. Using Graph when direction matters. Traffic flows, dependencies and hyperlinks need nx.DiGraph; otherwise shortest paths and in/out degree are wrong.
  5. Encoding data in colour alone. Combine colour with size or shape so the plot survives greyscale printing and colour-blindness.
  6. Calling plt.show() before savefig(). After show() the figure is cleared, so the saved file is blank. Save first.
  7. Treating a drawing as analysis. Compute degree, centrality and components in code; the picture confirms, it does not prove.

Frequently asked questions

How large a graph can NetworkX handle?

Analysis works comfortably to hundreds of thousands of nodes; drawing with Matplotlib becomes unreadable past a few hundred. For big interactive graphs use PyVis, Plotly or Gephi, or export with nx.write_gexf().

Can I make the plot interactive?

Yes. pyvis converts a NetworkX graph into an HTML page with drag-and-zoom in two lines, and Plotly can render the node positions from any NetworkX layout.

What is the difference between nx.draw and nx.draw_networkx?

nx.draw is a bare-bones call with no labels and no axes. nx.draw_networkx adds labels by default and accepts every styling keyword. Prefer the latter.

Key takeaways

  • NetworkX models the structure; Matplotlib renders it. Build the graph, choose a layout, draw, then style.
  • Use node attributes for colour, edge weights for width, and centrality for size to make plots carry real information.
  • Pick the layout for the shape of your data: shell for hierarchies, kamada-kawai for clarity, Graphviz dot for trees.
  • Always seed layouts, turn axes off, save before showing, and use DiGraph when direction matters.

Visualisation is a core skill in every data role. The Techknowledgehub Data Science course covers Python, pandas, Matplotlib, graph analysis and machine learning through guided projects, with mentor support and placement assistance. For free step-by-step videos, subscribe to our YouTube channel.

JG
Written byJaya Gupta

Part of the Techknowledgehub team of industry mentors, writing practical guides to help you build a job-ready tech career.

More articles by Jaya Gupta β†’
Keep reading

Related articles

M# Programming Language
Languages

M# Programming Language

What the M# programming language really is, how its declarative models generate C# and ASP.NET Core code, who uses it,…

01 Apr 2023Β· 8 min read

Leave a Reply