Matplotlib: графики в Python
Библиотека Matplotlib в Python: установка, линейный график plot, bar, hist, scatter, subplots, подписи и кириллица, сохранение через savefig и backend Agg.
Содержание · 13 разделов
- Установка Matplotlib
- pyplot и объектный стиль: fig, ax
- Линейный график: plot
- Столбчатая диаграмма: bar
- Гистограмма: hist
- Диаграмма рассеяния: scatter
- Несколько графиков: subplots
- Подписи и кириллица
- Сохранение: savefig
- Backend Agg: графики на сервере без экрана
- Частые ошибки
- Окно с графиком не появляется
- Сохранилась пустая картинка
- Подписи обрезаны или наезжают друг на друга
- Квадраты вместо русских букв
- Графики накладываются друг на друга
- Частые вопросы
- Как подписать даты на оси X?
- Как построить два графика с разными осями Y?
- Как сделать логарифмическую шкалу?
- Как отдать график в веб-приложение без сохранения на диск?
- Как анимировать график?
- Итог
Matplotlib — основная библиотека Python для построения графиков: линейных, столбчатых, гистограмм и диаграмм рассеяния. Она сохраняет картинки в PNG, SVG и PDF и показывает их в окне или в Jupyter. Минимальный пример matplotlib на Python:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])
plt.title("Квадраты чисел")
plt.savefig("quick.png") # сохранить в файл
plt.show() # открыть окно с графиком
Ниже — установка, два стиля работы с библиотекой, основные типы графиков, несколько графиков на одной картинке, подписи и кириллица, сохранение в файл и работа на сервере без экрана. Примеры проверены на Matplotlib 3.11 и Python 3.12.
Установка Matplotlib
Matplotlib ставится через pip, лучше в виртуальное окружение проекта. NumPy установится автоматически как зависимость:
# Windows
py -m pip install matplotlib
# macOS / Linux
python3 -m pip install matplotlib
Проверка:
import matplotlib
print(matplotlib.__version__) # → 3.11.2 (у вас может быть другая версия)
Пакет называется matplotlib; команды вроде pip install matplotlib.pyplot или pip install pyplot не сработают — pyplot это модуль внутри пакета. Если импорт падает с ModuleNotFoundError: No module named 'matplotlib', библиотека установлена в другой интерпретатор: см. разбор ModuleNotFoundError и установку библиотек Python.
pyplot и объектный стиль: fig, ax
У Matplotlib два способа рисовать.
- Через
plt(модульpyplot) — функцииplt.plot(),plt.title()работают с «текущим» графиком. Удобно для быстрых проверок. - Объектный стиль — вы явно создаёте фигуру
fig(вся картинка) и осиax(одна область с графиком) и вызываете методы у них. Такой код проще читать и поддерживать, особенно когда графиков несколько.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots(figsize=(8, 4)) # размер в дюймах
ax.plot(x, np.sin(x), label="sin(x)", color="tab:blue", linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", color="tab:orange", linestyle="--")
ax.set_title("Синус и косинус")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend() # легенда из параметров label
ax.grid(True) # сетка
fig.savefig("sin_cos.png", dpi=150, bbox_inches="tight")
Сопоставление функций двух стилей:
| pyplot | Объектный стиль |
|---|---|
plt.title() | ax.set_title() |
plt.xlabel() | ax.set_xlabel() |
plt.ylabel() | ax.set_ylabel() |
plt.xlim() | ax.set_xlim() |
plt.legend() | ax.legend() |
plt.savefig() | fig.savefig() |
Массивы для осей удобно готовить с помощью NumPy: np.linspace(0, 10, 100) даёт 100 равномерных точек от 0 до 10.
Линейный график: plot
ax.plot(x, y) соединяет точки линией. Внешний вид задают параметры:
color— цвет:"red","tab:green","#1f77b4";linestyle— стиль линии:"-","--",":","-.";linewidth— толщина;marker— маркер точек:"o","s","^";label— подпись для легенды.
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 15, 13, 18], marker="o", color="tab:red", label="Выручка")
ax.legend()
Столбчатая диаграмма: bar
ax.bar() строит вертикальные столбцы, ax.barh() — горизонтальные. По оси X можно передать строки — Matplotlib сам расставит подписи:
months = ["Янв", "Фев", "Мар", "Апр"]
sales = [120, 95, 140, 160]
fig, ax = plt.subplots()
bars = ax.bar(months, sales, color="tab:green")
ax.bar_label(bars) # значения над столбцами
ax.set_ylabel("Продажи, шт.")
fig.savefig("bar.png")
Гистограмма: hist
Гистограмма показывает распределение значений: диапазон делится на интервалы (bins), и для каждого считается число попавших в него значений.
rng = np.random.default_rng(0)
data = rng.normal(loc=170, scale=10, size=1000) # 1000 значений роста
fig, ax = plt.subplots()
counts, edges, patches = ax.hist(data, bins=20, edgecolor="black")
ax.set_xlabel("Рост, см")
ax.set_ylabel("Количество")
fig.savefig("hist.png")
print(len(counts), counts.sum()) # → 20 1000.0
hist() возвращает количество значений в каждом интервале, границы интервалов и сами столбцы — их можно использовать в дальнейших расчётах.
Диаграмма рассеяния: scatter
ax.scatter() рисует точки без линий — так видна связь двух величин. Размер (s) и цвет (c) точек могут зависеть от данных:
rng = np.random.default_rng(0)
x = rng.random(50)
y = x * 2 + rng.normal(0, 0.2, 50)
fig, ax = plt.subplots()
sc = ax.scatter(x, y, s=60, c=y, cmap="viridis", alpha=0.7)
fig.colorbar(sc, ax=ax, label="y") # шкала цветов
fig.savefig("scatter.png")
Для долей подойдёт круговая диаграмма ax.pie([40, 35, 25], labels=["A", "B", "C"], autopct="%1.0f%%").
Несколько графиков: subplots
plt.subplots(строки, столбцы) создаёт сетку осей. Для сетки 2×2 переменная axes — массив NumPy формы (2, 2), к осям обращаются по индексам:
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
axes[0, 0].plot([1, 2, 3], [3, 1, 2])
axes[0, 0].set_title("plot")
axes[0, 1].bar(["A", "B"], [3, 5])
axes[0, 1].set_title("bar")
axes[1, 0].hist(data, bins=15)
axes[1, 0].set_title("hist")
axes[1, 1].scatter([1, 2, 3], [3, 1, 2])
axes[1, 1].set_title("scatter")
fig.suptitle("Четыре типа графиков") # общий заголовок
fig.tight_layout() # убрать наложение подписей
fig.savefig("subplots.png")
Если сетка в одну строку, например plt.subplots(1, 3), то axes одномерный: axes[0], axes[1], axes[2]. Параметры sharex=True и sharey=True делают общие оси для всех графиков.
Подписи и кириллица
Заголовки и подписи осей задают методы set_title(), set_xlabel(), set_ylabel(), а легенду — параметр label плюс ax.legend(). Метод ax.text(x, y, "текст") добавляет надпись в точку с координатами данных.
Шрифт по умолчанию в Matplotlib — DejaVu Sans, в нём есть кириллица, поэтому русские подписи из примеров выше отображаются без настроек. Проблема появляется, если в настройках выбран шрифт без русских букв: вместо текста выводятся пустые квадраты, а в консоли — предупреждение:
UserWarning: Glyph 1055 (\N{CYRILLIC CAPITAL LETTER PE}) missing from font(s) cmsy10.
Решение — указать шрифт с кириллицей в начале скрипта:
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "DejaVu Sans" # или "Arial" на Windows
Если шрифта нет в системе, Matplotlib напишет findfont: Font family 'Имя' not found. и подставит шрифт по умолчанию.
Сохранение: savefig
fig.savefig() определяет формат по расширению файла:
fig.savefig("chart.png", dpi=150, bbox_inches="tight") # растровая картинка
fig.savefig("chart.svg") # вектор для сайта
fig.savefig("chart.pdf") # вектор для печати
dpi— разрешение (по умолчанию берётся изfigure.dpi, это 100);bbox_inches="tight"— обрезать лишние поля, чтобы подписи не срезались;transparent=True— прозрачный фон.
Вызывайте savefig() до plt.show(): после закрытия окна фигура удаляется, и сохранится пустая картинка. Если в цикле строится много графиков, закрывайте каждую фигуру через plt.close(fig) — иначе они копятся в памяти.
Backend Agg: графики на сервере без экрана
Backend — это механизм, который отрисовывает график: в окне (TkAgg, QtAgg, MacOSX) или только в файл. На сервере, в Docker или в CI экрана нет, поэтому используйте неинтерактивный backend Agg — он рисует PNG в память и в файлы:
import matplotlib
matplotlib.use("Agg") # до первого построения графика
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [2, 4, 1])
fig.savefig("report.png")
plt.close(fig)
Без кода backend можно выбрать переменной окружения: MPLBACKEND=Agg python script.py (Linux, macOS). С Agg вызов plt.show() ничего не открывает и выдаёт предупреждение:
UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
Так же графики строят внутри веб-приложений, например в админке Django: картинка сохраняется в файл или буфер и отдаётся пользователю.
Частые ошибки
Окно с графиком не появляется
В обычном скрипте график показывается только после plt.show(). Если вызов есть, а окна нет — проверьте, не выбран ли backend Agg (через matplotlib.use() или MPLBACKEND). В Jupyter графики выводятся в ячейке автоматически.
Сохранилась пустая картинка
savefig() вызван после plt.show(). Поменяйте порядок или сохраняйте через fig.savefig(), держа ссылку на фигуру.
Подписи обрезаны или наезжают друг на друга
Вызовите fig.tight_layout() перед сохранением или передайте bbox_inches="tight" в savefig().
Квадраты вместо русских букв
Выбран шрифт без кириллицы — задайте plt.rcParams["font.family"] со шрифтом, в котором она есть (см. раздел выше).
Графики накладываются друг на друга
В стиле plt все вызовы рисуют на текущей фигуре. Начинайте каждый новый график с fig, ax = plt.subplots() и закрывайте старые через plt.close(fig).
Частые вопросы
Как подписать даты на оси X?
Передайте в plot() список дат (datetime или столбец дат pandas) — Matplotlib сам расставит деления. Формат подписей задаёт DateFormatter, а autofmt_xdate() наклоняет подписи, чтобы они не наезжали друг на друга:
from datetime import date, timedelta
import matplotlib.dates as mdates
days = [date(2026, 1, 1) + timedelta(days=i) for i in range(30)]
fig, ax = plt.subplots()
ax.plot(days, range(30))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m")) # 01.01, 05.01 …
fig.autofmt_xdate()
Если даты хранятся строками, сначала преобразуйте их в даты (pd.to_datetime()): строки Matplotlib рисует как категории в том порядке, в каком они пришли.
Как построить два графика с разными осями Y?
Метод twinx() создаёт вторую ось Y справа с общей осью X — так на одной картинке помещаются величины разного масштаба:
fig, ax1 = plt.subplots()
ax1.plot([1, 2, 3], [10, 20, 15], color="tab:blue")
ax1.set_ylabel("Выручка, тыс. руб.", color="tab:blue")
ax2 = ax1.twinx()
ax2.plot([1, 2, 3], [0.5, 0.7, 0.6], color="tab:red")
ax2.set_ylabel("Конверсия", color="tab:red")
Как сделать логарифмическую шкалу?
Вызовите ax.set_yscale("log") (или ax.set_xscale("log") для оси X). Это нужно, когда значения отличаются на порядки: на обычной шкале маленькие значения сливаются с нулём. Отрицательные значения и ноль на логарифмической шкале не отображаются.
Как отдать график в веб-приложение без сохранения на диск?
Сохраните фигуру в буфер в памяти и отдайте байты как ответ с типом image/png или встройте в HTML через base64:
import base64
import io
buf = io.BytesIO()
fig.savefig(buf, format="png")
plt.close(fig)
png_bytes = buf.getvalue() # для HTTP-ответа
encoded = base64.b64encode(png_bytes).decode() # для <img src="data:image/png;base64,...">
На сервере используйте backend Agg, как в разделе выше.
Как анимировать график?
FuncAnimation вызывает функцию для каждого кадра и обновляет данные линии. Готовую анимацию можно сохранить в GIF через PillowWriter (Pillow ставится вместе с Matplotlib):
from matplotlib.animation import FuncAnimation, PillowWriter
x = np.linspace(0, 2 * np.pi, 200)
fig, ax = plt.subplots()
(line,) = ax.plot(x, np.sin(x))
def update(frame):
line.set_ydata(np.sin(x + frame / 10))
return (line,)
anim = FuncAnimation(fig, update, frames=60, interval=50)
anim.save("wave.gif", writer=PillowWriter(fps=20))
Для показа в окне вместо save() вызовите plt.show() и держите ссылку anim до конца работы — иначе объект удалится сборщиком мусора и анимация остановится.
Итог
Для большинства задач достаточно fig, ax = plt.subplots(), одного из методов plot, bar, hist или scatter, подписей осей и fig.savefig(); на сервере добавьте backend Agg. Данные для графиков обычно готовят в NumPy или pandas — у DataFrame есть метод plot(), который рисует через Matplotlib. Другие пакеты для данных и графики — в обзоре библиотек Python, а примеры всех типов графиков — в галерее Matplotlib.
- #Python
- #Matplotlib
- #Графики
- #Визуализация
- #NumPy