import math
import matplotlib.pyplot as plt
import networkx as nx
# Computer Modern fonts, as in LaTeX. The last setting avoids a warning about cmr10.
latex_style = {
"font.family": "cmr10",
"mathtext.fontset": "cm",
"axes.formatter.use_mathtext": True,
}
def draw_graph(G, pos, width, height):
"""Draw the directed graph G with the vertices at the positions pos.
A vertex "v1" is labeled $v_1$. An edge is drawn as an arrow, and its
weight as a number beside the edge.
"""
labels = {v: rf"$v_{v[1:]}$" if v.startswith("v") else rf"${v}$" for v in G}
with plt.rc_context(latex_style):
fig, ax = plt.subplots(figsize=(width, height))
nx.draw_networkx(
G,
pos,
labels=labels,
node_color="white",
edgecolors="black",
linewidths=1.0,
node_size=450,
font_size=12,
font_family="cmr10",
width=1.0,
arrowstyle="-|>",
arrowsize=12,
ax=ax,
)
# Each weight is placed beside its edge, on the side away from the center of the graph
weights = nx.get_edge_attributes(G, "weight")
cx = sum(x for x, y in pos.values()) / len(pos)
cy = sum(y for x, y in pos.values()) / len(pos)
for (v, u), w in weights.items():
(x1, y1), (x2, y2) = pos[v], pos[u]
mx, my = (x1 + x2) / 2, (y1 + y2) / 2 # midpoint of the edge
length = math.hypot(x2 - x1, y2 - y1)
px, py = (y1 - y2) / length, (x2 - x1) / length # unit vector perpendicular to the edge
if px * (mx - cx) + py * (my - cy) < 0:
px, py = -px, -py
ax.annotate(
str(w), (mx, my), xytext=(7 * px, 7 * py), textcoords="offset points",
ha="center", va="center", fontsize=10,
)
ax.set_aspect("equal")
ax.margins(0.12)
ax.axis("off")
plt.show()
G = nx.DiGraph()
G.add_weighted_edges_from([
("s", "v1", 2), ("s", "v2", 1), ("v1", "v2", 3), ("v1", "v3", 3),
("v2", "v4", 1), ("v3", "t", 2), ("v4", "v3", 2), ("v4", "t", 5),
])
pos = {
"s": (0, 1), "v1": (1.3, 2), "v2": (1.3, 0),
"v3": (2.6, 2), "v4": (2.6, 0), "t": (3.9, 1),
}
draw_graph(G, pos, 4.5, 2.4)