2025, Dec 06 03:00

How to Remove Whitespace in NetworkX Matplotlib Plots: Tight Layout, Zero Margins, and Tight Bounding Box

Fix cramped NetworkX graphs in matplotlib: remove margins via tight_layout, margins(0) and bbox_inches='tight' to fill the canvas and reduce file size.

When drawing large NetworkX graphs with matplotlib.pyplot, it’s common to end up with a tiny cluster in the middle of a huge image and a lot of unused whitespace around it. Increasing figure size or DPI doesn’t help much and just creates massive files that image viewers struggle to open. The core need is to make the graph expand to the full canvas so node labels stay readable without exploding the output size.

Reproducing the compressed plot

The following example builds a graph, computes a spring layout, and renders it. The resulting PNG concentrates the graph near the center with a thick ring of empty space around it, even when width, height, and DPI are increased.

import networkx as netx
import matplotlib.pyplot as mpl
print("Building graph...")
net_graph = netx.Graph()
"""
for loop to populate graph nodes and edges...
"""
print(f"Graph has {len(net_graph.nodes)} nodes and {len(net_graph.edges)} edges")
print("Generating layout...")
style_cfg = {"node_size": 10, "node_color": "blue", "font_color": "red"}
k_scale = 1
iter_total = 30
fig_w = 60
fig_h = 60
fig_dpi = 60
layout_xy = netx.spring_layout(net_graph, k=k_scale, iterations=iter_total, seed=63)
_ = mpl.figure(1, figsize=(fig_w, fig_h), dpi=fig_dpi)
netx.draw_networkx(net_graph, layout_xy, **style_cfg)
print("Rendering graph...")
mpl.axis("off")
out_path = f"graph_{k_scale}_{iter_total}_{fig_w}_{fig_h}_{fig_dpi}.png"
mpl.savefig(out_path, format="png")
print(f"Wrote to {out_path}")

What actually causes the empty margins

The visual crowding isn’t only about the layout parameters. Even with more iterations or a higher k value, the rendered figure may still include default padding and margins, and the saved bounding box can keep extra space that surrounds the drawn content. That’s why dialing up figure size or DPI alone yields a bigger image but not a better use of space.

The fix: use tight layout, zero margins, tight bounding box

The whitespace can be removed by combining three steps during rendering. First, turn off the axis. Then, apply a tight layout to reduce padding and set plot margins to zero. Finally, save using a tight bounding box so only the drawn content is captured. Each of these trims a bit of unused area, and together they eliminate the excess entirely.

import networkx as netx
import matplotlib.pyplot as mpl
print("Building graph...")
net_graph = netx.Graph()
"""
for loop to populate graph nodes and edges...
"""
print(f"Graph has {len(net_graph.nodes)} nodes and {len(net_graph.edges)} edges")
print("Generating layout...")
style_cfg = {"node_size": 10, "node_color": "blue", "font_color": "red"}
k_scale = 1
iter_total = 30
fig_w = 60
fig_h = 60
fig_dpi = 60
layout_xy = netx.spring_layout(net_graph, k=k_scale, iterations=iter_total, seed=63)
_ = mpl.figure(1, figsize=(fig_w, fig_h), dpi=fig_dpi)
netx.draw_networkx(net_graph, layout_xy, **style_cfg)
print("Rendering graph...")
mpl.axis("off")
mpl.tight_layout()
mpl.margins(0.0)
out_path = f"graph_{k_scale}_{iter_total}_{fig_w}_{fig_h}_{fig_dpi}.png"
mpl.savefig(out_path, format="png", bbox_inches="tight")
print(f"Wrote to {out_path}")

This keeps the same layout and drawing configuration while removing the unused perimeter space around the graph.

Why this matters for large graphs

For sizable graphs, simply scaling up the canvas leads to unwieldy files, often tens of megabytes, and some viewers won’t even open them. Eliminating blank margins allows the visualization to occupy the full canvas, which means labels become more legible without resorting to extreme figure dimensions or DPI. The result is a clearer image at a sane file size.

Closing thoughts

If your NetworkX plot looks cramped in the center, don’t chase it with ever-larger figures. Keep the axis hidden, apply a tight layout, set margins to zero, and save with a tight bounding box. This combination trims the dead space so the graph actually uses the pixels you allocate to it, improving readability and keeping output sizes practical.