2025, Oct 06 13:16
Как убрать горизонтальные отступы в Matplotlib: различаем поля Axes и внешнюю компоновку Figure
Пошагово убираем горизонтальные отступы в Matplotlib: margins(x=0), set_xlim, subplots_adjust, tight_layout и constrained_layout. Разница Axes и Figure.
Иногда графики Matplotlib оказываются с нежелательными горизонтальными отступами: содержимое самих Axes как будто сжато лишним пространством по бокам. Если вы хотите, чтобы данные плотнее занимали доступную ширину, важно различать поля внутри Axes и пустое пространство вокруг Axes внутри Figure.
Минимальный пример, демонстрирующий проблему
Следующий фрагмент создает линейный график и вызывает tight_layout, но всё же оставляет заметные горизонтальные отступы между графиком и окном.
import numpy as np, matplotlib.pyplot as plt
series = np.random.rand(100)
plt.figure(figsize=(12, 6), dpi=100)
plt.tight_layout()
plt.plot(series)
plt.show()Немного иная настройка, где DPI и размер задаются для пары Figure и Axes, дает тот же визуальный результат.
import numpy as np, matplotlib.pyplot as plt
series = np.random.rand(100)
board, axes = plt.subplots()
board.set_dpi(100)
board.set_size_inches(12, 6)
axes.autoscale_view('tight')
axes.plot(series)
plt.show()Что на самом деле происходит
У проблемы с расстояниями два уровня. Во‑первых, Axes могут резервировать поля вокруг самих данных; это пространство и управляется методом margins. Во‑вторых, Figure держит внешние отступы вокруг Axes; ими управляют параметры компоновки и subplots_adjust. Изменение полей Axes уменьшает пустоту внутри области построения, но не затрагивает пустую полоску между рамкой Axes и границей Figure. Поэтому вызов вроде axes.margins(x=0) может не дать видимого эффекта на зазор между графиком и окном, хотя немного «подрежет» пространство внутри Axes.
Есть и нюанс по времени: движки компоновки должны запускаться после добавления элементов. Перенос вызовов компоновки в конец помогает корректно посчитать размеры.
Переместите вызов tight_layout после вызова plot. Еще лучше — использовать более современный constrained layout.
Решения, нацеленные на нужный уровень
Если цель — убрать горизонтальные отступы внутри Axes, задайте нулевые поля по оси x или явно установите пределы x по диапазону данных.
import numpy as np, matplotlib.pyplot as plt
vals = np.random.rand(100)
frame, art = plt.subplots(figsize=(12, 6), dpi=100)
art.plot(vals)
art.margins(x=0)  # убирает горизонтальные пустоты внутри Axes
# Эквивалентный эффект с явными пределами:
# art.set_xlim(0, len(vals) - 1)
plt.tight_layout()  # вызывайте после добавления элементов
plt.show()Если нужно убрать пространство между Axes и границей Figure, настройте область подграфиков или включите constrained layout. Уменьшение полей напрямую влияет на внешние отступы.
import numpy as np, matplotlib.pyplot as plt
values = np.random.rand(100)
fig_box, ax_obj = plt.subplots(figsize=(12, 6), dpi=100)
ax_obj.plot(values)
ax_obj.margins(x=0)  # необязательно: плотная подгонка данных внутри Axes
fig_box.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.05)
plt.show()Либо поручите это движку компоновки, который автоматически управляет внешними отступами.
import numpy as np, matplotlib.pyplot as plt
seq = np.random.rand(100)
sheet, pane = plt.subplots(figsize=(12, 6), dpi=100, constrained_layout=True)
pane.plot(seq)
pane.margins(x=0)  # необязательно для плотной подгонки по данным
plt.show()Почему это важно
Точный контроль над полями помогает графикам передавать сигнал, а не тратить пиксели на пустоту. Так панели остаются компактными, экспорт — единообразным, а сравнения бок о бок — выровненными. Если отдельно управлять компоновкой и полями данных, вы не будете крутить «не ту ручку» и будете получать предсказуемый результат.
Итоги
Решите, хотите ли вы уменьшить пустоту внутри Axes или внешние отступы вокруг них. Используйте axes.margins(x=0) или явные пределы вроде axes.set_xlim(0, len(data) - 1), чтобы плотнее уложить данные по горизонтали. Применяйте fig.subplots_adjust, чтобы сузить зазор между Axes и Figure, или включайте constrained_layout для современного автоматического размещения. Размещайте tight_layout после всех команд построения, чтобы процедура компоновки видела финальную сцену.
Статья основана на вопросе на StackOverflow от Paul Jurczak и ответе Subir Chowdhury.