# Source:
# https://networkx.org/documentation/stable/auto_examples/drawing/plot_weighted_graph.html#sphx-glr-auto-examples-drawing-plot-weighted-graph-py
import matplotlib.pyplot as plt
import networkx as nx
G = nx.Graph()
G.add_edge("a", "b", weight=0.6)
G.add_edge("a", "c", weight=0.2)
G.add_edge("c", "d", weight=0.1)
G.add_edge("c", "e", weight=0.7)
G.add_edge("c", "f", weight=0.9)
G.add_edge("a", "d", weight=0.3)
elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] <= 0.5]
pos = nx.spring_layout(G, seed=7) # positions for all nodes - seed for reproducibility
# nodes
nx.draw_networkx_nodes(G, pos, node_size=700)
# edges
nx.draw_networkx_edges(G, pos, edgelist=elarge, width=6)
nx.draw_networkx_edges(
G, pos, edgelist=esmall, width=6, alpha=0.5, edge_color="b", style="dashed"
)
# node labels
nx.draw_networkx_labels(G, pos, font_size=20, font_family="sans-serif")
# edge weight labels
edge_labels = nx.get_edge_attributes(G, "weight")
nx.draw_networkx_edge_labels(G, pos, edge_labels)
ax = plt.gca()
ax.margins(0.08)
plt.axis("off")
plt.tight_layout()
plt.show()NetworkX is a pure-Python library for graphs: sets of nodes joined by edges. A node can be any hashable Python object, such as a string, a number or a tuple, and nodes and edges can carry attributes such as a weight. NetworkX has algorithms for shortest paths, centrality, connected components and communities, and it draws graphs with matplotlib. People use it to study social networks, road maps and dependency graphs. This page is an online NetworkX compiler: the code runs in your browser, so you can try it without installing anything. Run the example first, then paste any snippet below into a new cell to try it.
nx.Graph() creates an empty undirected graph. G.add_edge() adds
both nodes if they are new, so the six calls give six nodes, a to f,
and six edges, each with a weight attribute. G.edges(data=True)
yields every edge with its attributes, and the two list comprehensions
split the edges at 0.5: three heavy and three light.
nx.spring_layout(G, seed=7) places the nodes with a force-directed
algorithm, in which edges pull nodes together and all nodes push each
other apart. The seed gives the same layout on every run. The
draw_networkx_* functions then draw onto a matplotlib figure: the
nodes, heavy edges as solid lines, light edges dashed and half
transparent, the node names, and the weights that
nx.get_edge_attributes(G, "weight") collects into a dictionary.
nx.shortest_path() counts edges unless you pass weight, so the first
two calls disagree. The road from Home to School is one edge but 10 km
long, while the route through the Park is 3.5 km:
import networkx as nx
roads = nx.Graph()
roads.add_weighted_edges_from([ # (from, to, distance in km)
("Home", "School", 10.0),
("Home", "Park", 2.0), ("Park", "School", 1.5),
("Park", "Mall", 3.0), ("Mall", "School", 1.0),
])
print(nx.shortest_path(roads, "Home", "School")) # fewest edges
print(nx.shortest_path(roads, "Home", "School", weight="weight")) # shortest distance
print(nx.shortest_path_length(roads, "Home", "School", weight="weight"))
print(nx.single_source_dijkstra_path_length(roads, "Home")) # distance to every node
nx.karate_club_graph() ships with NetworkX: Zachary's karate club, 34
members and the 78 ties between them. Degree counts a node's
neighbours. Betweenness is the share of shortest paths between other
nodes that pass through a node, so it picks out the go-betweens:
import networkx as nx
G = nx.karate_club_graph()
print(G.number_of_nodes(), "nodes,", G.number_of_edges(), "edges")
degree = dict(G.degree())
betweenness = nx.betweenness_centrality(G)
top = sorted(betweenness, key=betweenness.get, reverse=True)[:3]
for node in top:
print(f"node {node}: {degree[node]} ties, betweenness {betweenness[node]:.3f}")
print("connected:", nx.is_connected(G), "density:", round(nx.density(G), 3))
In a nx.DiGraph, every edge has a direction. Here an edge points from
a task to a task that needs it. nx.topological_sort() lists the tasks
in an order that respects every edge, and raises NetworkXUnfeasible
if the graph has a cycle:
import networkx as nx
tasks = nx.DiGraph()
tasks.add_edges_from([
("download data", "clean data"),
("clean data", "train model"),
("clean data", "make charts"),
("train model", "write report"),
("make charts", "write report"),
])
print(nx.is_directed_acyclic_graph(tasks))
print(list(nx.topological_sort(tasks)))
print(list(tasks.predecessors("write report")))
print(sorted(nx.ancestors(tasks, "train model")))
louvain_communities() splits a graph into groups with many edges
inside and few between them. It is randomized, so pass a seed to get
the same groups every time. nx.draw() then colours each node by its
group:
import matplotlib.pyplot as plt
import networkx as nx
G = nx.karate_club_graph()
groups = nx.community.louvain_communities(G, seed=42)
print(len(groups), "communities, sizes", [len(g) for g in groups])
print("modularity", round(nx.community.modularity(G, groups), 3))
group_of = {node: i for i, group in enumerate(groups) for node in group}
pos = nx.spring_layout(G, seed=3)
nx.draw(G, pos, node_color=[group_of[n] for n in G], cmap=plt.cm.tab10,
with_labels=True, node_size=300, font_size=8, edge_color="gray")
plt.show()
Graph keeps one edge per pair of nodes. Adding the same edge again
only updates its attributes. Use nx.MultiGraph for parallel edges.nx.from_pandas_edgelist(df, "source", "target", edge_attr="weight")
builds a graph from a pandas table of edges.betweenness_centrality() took about 30 times
as long as the same calculation in igraph.