NetworkX is useful for building and analyzing graphs, while Plotly is useful for interactive visualization. Combining them gives you a practical workflow: use NetworkX to define nodes, edges, and layout positions, then use Plotly traces to render the graph in a flexible and interactive way. This tutorial shows how to build a basic graph, draw edges and nodes with Plotly, customize appearance, and create a more informative network chart. ### Basic NetworkX Graph in Plotly Let's start with a small graph and render it with Plotly.
import networkx as nx
import plotly.graph_objects as go
# Create a graph
G = nx.Graph()
G.add_edge("A", "B")
G.add_edge("A", "C")
G.add_edge("B", "D")
G.add_edge("C", "D")
# Compute node positions
pos = nx.spring_layout(G, seed=42)
edge_x = []
edge_y = []
for u, v in G.edges():
x0, y0 = pos[u]
x1, y1 = pos[v]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
node_x = []
node_y = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=edge_x,
y=edge_y,
mode="lines",
line=dict(width=1, color="gray"),
hoverinfo="none",
)
)
fig.add_trace(
go.Scatter(
x=node_x,
y=node_y,
mode="markers+text",
text=list(G.nodes()),
textposition="top center",
marker=dict(size=18, color="royalblue"),
)
)
fig.update_layout(title="Basic NetworkX Graph", showlegend=False)
fig.show()- **`nx.spring_layout(G, seed=42)`** calculates positions for the nodes. - Edges and nodes are drawn as separate Plotly scatter traces. - Using `None` between edge segments prevents unrelated edges from connecting visually. ### Drawing Weighted Edges If your graph has weighted relationships, you can use the edge weights to control the line width.
import networkx as nx
import plotly.graph_objects as go
# Create a weighted graph
G = nx.Graph()
G.add_edge("A", "B", weight=1)
G.add_edge("A", "C", weight=3)
G.add_edge("B", "D", weight=2)
G.add_edge("C", "D", weight=4)
pos = nx.spring_layout(G, seed=7)
fig = go.Figure()
for u, v, data in G.edges(data=True):
x0, y0 = pos[u]
x1, y1 = pos[v]
fig.add_trace(
go.Scatter(
x=[x0, x1],
y=[y0, y1],
mode="lines",
line=dict(width=data["weight"], color="gray"),
hoverinfo="text",
text=[f"{u} - {v}: weight {data['weight']}"] * 2,
showlegend=False,
)
)
for node in G.nodes():
x, y = pos[node]
fig.add_trace(
go.Scatter(
x=[x],
y=[y],
mode="markers+text",
text=[node],
textposition="top center",
marker=dict(size=18, color="seagreen"),
showlegend=False,
)
)
fig.update_layout(title="Weighted Network Graph")
fig.show()- **`data["weight"]`** is used to scale the edge line width. - Edge hover text makes the numeric relationship easier to inspect. ### Coloring Nodes by Degree A useful next step is to style nodes based on graph properties such as degree.
import networkx as nx
import plotly.graph_objects as go
G = nx.karate_club_graph()
pos = nx.spring_layout(G, seed=10)
node_x = []
node_y = []
node_color = []
node_text = []
for node in G.nodes():
x, y = pos[node]
degree = G.degree[node]
node_x.append(x)
node_y.append(y)
node_color.append(degree)
node_text.append(f"Node {node}<br>Degree: {degree}")
edge_x = []
edge_y = []
for u, v in G.edges():
x0, y0 = pos[u]
x1, y1 = pos[v]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=edge_x,
y=edge_y,
mode="lines",
line=dict(width=0.6, color="lightgray"),
hoverinfo="none",
)
)
fig.add_trace(
go.Scatter(
x=node_x,
y=node_y,
mode="markers",
hoverinfo="text",
text=node_text,
marker=dict(
size=10,
color=node_color,
colorscale="Viridis",
showscale=True,
colorbar=dict(title="Degree"),
),
)
)
fig.update_layout(title="Network Nodes Colored by Degree", showlegend=False)
fig.show()- **`G.degree[node]`** gives the number of connections for each node. - Mapping degree to marker color helps reveal central or highly connected nodes. ### Adding Custom Hover Labels and Node Sizes Interactive labels are one of Plotly's main advantages. You can also scale marker size to emphasize important nodes.
import networkx as nx
import plotly.graph_objects as go
G = nx.Graph()
G.add_edge("Parser", "Lexer")
G.add_edge("Parser", "AST")
G.add_edge("AST", "Optimizer")
G.add_edge("Optimizer", "Codegen")
G.add_edge("Parser", "Errors")
pos = nx.spring_layout(G, seed=12)
degrees = dict(G.degree())
node_x = []
node_y = []
node_sizes = []
node_labels = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
node_sizes.append(12 + degrees[node] * 6)
node_labels.append(f"{node}<br>Connections: {degrees[node]}")
edge_x = []
edge_y = []
for u, v in G.edges():
x0, y0 = pos[u]
x1, y1 = pos[v]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=edge_x,
y=edge_y,
mode="lines",
line=dict(color="#BBBBBB", width=1.5),
hoverinfo="none",
)
)
fig.add_trace(
go.Scatter(
x=node_x,
y=node_y,
mode="markers+text",
text=list(G.nodes()),
textposition="bottom center",
hoverinfo="text",
textfont=dict(size=12),
marker=dict(size=node_sizes, color="#F28E2B", line=dict(width=1, color="black")),
hovertext=node_labels,
)
)
fig.update_layout(title="Dependency Graph with Hover Details", showlegend=False)
fig.show()- Marker size is based on node degree, making more connected nodes stand out. - **`hovertext=node_labels`** provides richer interactive context without cluttering the chart. ### Practical Example: Team Collaboration Graph Here is a practical example showing a small collaboration network. This kind of plot helps show who works closely together and which people act as bridges between groups.
import networkx as nx
import plotly.graph_objects as go
G = nx.Graph()
G.add_edges_from(
[
("Alice", "Ben"),
("Alice", "Cara"),
("Ben", "Dina"),
("Cara", "Dina"),
("Cara", "Eva"),
("Eva", "Frank"),
("Dina", "Frank"),
]
)
pos = nx.spring_layout(G, seed=21)
degrees = dict(G.degree())
edge_x = []
edge_y = []
for u, v in G.edges():
x0, y0 = pos[u]
x1, y1 = pos[v]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
node_x = []
node_y = []
node_sizes = []
node_text = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
node_sizes.append(14 + degrees[node] * 5)
node_text.append(f"{node}<br>Collaborators: {degrees[node]}")
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=edge_x,
y=edge_y,
mode="lines",
line=dict(width=1.2, color="lightgray"),
hoverinfo="none",
)
)
fig.add_trace(
go.Scatter(
x=node_x,
y=node_y,
mode="markers+text",
text=list(G.nodes()),
textposition="top center",
hoverinfo="text",
hovertext=node_text,
marker=dict(
size=node_sizes,
color=list(degrees.values()),
colorscale="Blues",
showscale=True,
colorbar=dict(title="Collaborators"),
line=dict(width=1, color="navy"),
),
)
)
fig.update_layout(
title="Team Collaboration Network",
showlegend=False,
xaxis=dict(showgrid=False, zeroline=False, visible=False),
yaxis=dict(showgrid=False, zeroline=False, visible=False),
)
fig.show()- This visualization highlights both the structure of the collaboration network and the relative connectivity of each person. - Hiding the axes makes the chart feel more like a network diagram and less like a Cartesian plot. ### Conclusion Using NetworkX with Plotly gives you a flexible way to build interactive network diagrams in Python. NetworkX handles graph structure and analysis, while Plotly handles rendering, hover labels, color scales, and interactive exploration.