2025, Dec 23 12:02

Как растянуть граф NetworkX на весь холст matplotlib без лишних полей

Графы NetworkX часто сжимаются в центре при выводе в matplotlib. Узнайте, как убрать пустые поля: axis off, tight_layout, margins(0) и bbox_inches='tight'.

При отрисовке больших графов NetworkX с помощью matplotlib.pyplot нередко получается крошечный кластер в центре огромного изображения и масса неиспользованного пустого пространства вокруг. Увеличение размера фигуры или DPI почти не помогает и лишь порождает тяжёлые файлы, которые просмотрщики с трудом открывают. Задача в том, чтобы растянуть граф на весь холст, чтобы подписи узлов оставались читаемыми, не взрывая размер вывода.

Воспроизведение «сжатого» графика

Следующий пример строит граф, вычисляет пружинную раскладку и выводит его. Итоговый PNG собирает граф у центра и оставляет по краям широкое кольцо пустоты — даже если увеличить ширину, высоту и DPI.

import networkx as netx
import matplotlib.pyplot as mpl
print("Building graph...")
net_graph = netx.Graph()
"""
цикл for для заполнения узлов и рёбер графа...
"""
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}")

Откуда берутся пустые поля на самом деле

Визуальная скученность — это не только про параметры раскладки. Даже при большем числе итераций или повышенном значении k итоговая фигура может сохранять отступы и поля по умолчанию, а сохранённая граница кадра может включать лишнее пространство вокруг нарисованного содержания. Поэтому простое увеличение размера фигуры или DPI даёт лишь более крупную картинку, но не лучшее использование области.

Решение: tight layout, нулевые поля и tight bounding box

Лишние пробелы убираются сочетанием трёх шагов при рендеринге. Сначала выключите оси. Затем примените плотную компоновку (tight layout), чтобы сократить отступы, и задайте нулевые поля. Наконец, сохраняйте с плотной рамкой (tight bounding box), чтобы захватывалось только нарисованное. Каждый шаг подрезает немного «воздуха», а вместе они полностью устраняют излишки.

import networkx as netx
import matplotlib.pyplot as mpl
print("Building graph...")
net_graph = netx.Graph()
"""
цикл for для заполнения узлов и рёбер графа...
"""
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}")

Так сохраняются те же раскладка и параметры отрисовки, но устраняется неиспользуемое пространство по периметру графа.

Почему это важно для больших графов

Для крупных графов простое масштабирование холста приводит к громоздким файлам — порой на десятки мегабайт — и некоторые просмотрщики их даже не открывают. Удалив пустые поля, вы позволяете визуализации занять весь холст: подписи становятся разборчивее без экстремальных размеров фигуры или DPI. В итоге — более ясное изображение при разумном размере файла.

Итоги

Если ваш график NetworkX скомкан в центре, не гонитесь за всё большими фигурами. Спрячьте оси, примените tight layout, установите нулевые поля и сохраняйте с tight bounding box. Эта комбинация убирает мёртвое пространство, и граф действительно использует выделенные ему пиксели, повышая читаемость и сохраняя практичные размеры вывода.