📉 Matplotlib

Полный справочник: Figure и Axes, типы графиков, оформление, подписи, оси, цвета, subplots и GridSpec, аннотации, стили, 3D, анимации, сохранение и рецепты для данных.

Шпаргалки · ИИ · #matplotlib #python #visualization #plots #data-science

Идея и установка

Matplotlib строит графики в Python. Иерархия: Figure (холст) → Axes (область графика с осями) → артисты (линии, текст, подписи). Два стиля: быстрый plt.plot(...) (pyplot, неявное состояние) и объектно-ориентированный (fig, ax = plt.subplots()): используйте его, он предсказуем.

pip install matplotlib
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline          # в Jupyter;  %matplotlib widget — интерактивно

Первый график

x = np.linspace(0, 10, 200)
fig, ax = plt.subplots(figsize=(8, 4), dpi=120, layout="constrained")     # constrained — автоматическая раскладка
ax.plot(x, np.sin(x), label="sin", color="tab:blue", linestyle="--", linewidth=2, marker="o", markevery=20)
ax.plot(x, np.cos(x), label="cos", color="#e11d48")
ax.set(title="Синус и косинус", xlabel="x", ylabel="y", xlim=(0, 10), ylim=(-1.2, 1.2))
ax.grid(True, alpha=.3)
ax.legend(loc="upper right", frameon=False)
fig.savefig("plot.png", dpi=200, bbox_inches="tight", transparent=False)
plt.show()

Типы графиков

Тип Код
Линия ax.plot(x, y), ax.step(x, y), ax.stairs
Точки ax.scatter(x, y, c=z, s=sizes, cmap="viridis", alpha=.7)
Столбцы ax.bar(labels, values, yerr=err), ax.barh(...); группы: сдвиг по x + width
Гистограмма ax.hist(data, bins=30, density=True, alpha=.6), ax.hist2d
Круговая ax.pie(vals, labels=labs, autopct="%1.0f%%", startangle=90)
«Ящик с усами» ax.boxplot([a, b], labels=["A", "B"]), ax.violinplot
Тепловая карта im = ax.imshow(M, cmap="coolwarm"); fig.colorbar(im, ax=ax), ax.pcolormesh
Область ax.fill_between(x, y1, y2, alpha=.3), ax.stackplot(x, ys)
Ошибки ax.errorbar(x, y, yerr=e, fmt="o-", capsize=3)
Контуры, векторы ax.contourf(X, Y, Z), ax.quiver, ax.streamplot
Другое ax.hexbin, ax.stem, ax.polar, ax.table, ax.axhline / axvline / axhspan / axvspan
# сгруппированные столбцы
w = .38; i = np.arange(len(cats))
ax.bar(i - w/2, a, w, label="A"); ax.bar(i + w/2, b, w, label="B"); ax.set_xticks(i, cats)

Несколько графиков

fig, axes = plt.subplots(2, 2, figsize=(10, 6), sharex=True, sharey="row", layout="constrained")
axes[0, 0].plot(x, y); axes[0, 1].hist(data); axes[1, 0].scatter(x, y); axes[1, 1].imshow(M)
for ax in axes.flat: ax.grid(alpha=.3)
fig.suptitle("Общий заголовок")

fig = plt.figure(figsize=(9, 5))
gs = fig.add_gridspec(2, 3)                                   # произвольные ячейки
ax1 = fig.add_subplot(gs[0, :]); ax2 = fig.add_subplot(gs[1, :2]); ax3 = fig.add_subplot(gs[1, 2])
fig, axd = plt.subplot_mosaic([["main", "side"], ["main", "bottom"]])      # по именам
ax_twin = ax.twinx()                                            # вторая ось Y
inset = ax.inset_axes([.6, .6, .35, .35])                       # врезка

Оформление и подписи

ax.set_title("Заголовок", fontsize=14, loc="left"); ax.set_xlabel("x", fontsize=12); ax.set_ylabel("y")
ax.set_xticks([0, 5, 10], labels=["a", "b", "c"]); ax.tick_params(axis="x", rotation=45, labelsize=9)
ax.set_xscale("log"); ax.set_yscale("symlog"); ax.invert_yaxis(); ax.set_aspect("equal")
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda v, _: f"{v:,.0f}".replace(",", " ")))
from matplotlib.ticker import MaxNLocator, PercentFormatter; ax.yaxis.set_major_formatter(PercentFormatter(1.0))
ax.spines[["top", "right"]].set_visible(False)
ax.text(2, .5, "текст", fontsize=10, ha="center", va="bottom", bbox=dict(boxstyle="round", fc="w", ec="gray"))
ax.annotate("пик", xy=(1.57, 1), xytext=(3, .6), arrowprops=dict(arrowstyle="->", color="k"))
ax.bar_label(bars, fmt="%.1f", padding=2)                       # значения над столбцами
ax.legend(title="Серии", ncol=2, bbox_to_anchor=(1.02, 1), loc="upper left")      # легенда снаружи

Русский язык и шрифты: plt.rcParams["font.family"] = "DejaVu Sans" (поддерживает кириллицу), либо шрифт системы. Знак минуса: plt.rcParams["axes.unicode_minus"] = False.

Цвета и карты

Именованные ("tab:blue", "crimson"), hex, RGB-кортежи, серый "0.5". Цикл цветов: plt.rcParams["axes.prop_cycle"]. Карты: последовательные (viridis, plasma, Blues), расходящиеся (coolwarm, RdBu) для данных вокруг нуля, качественные (tab10, Set2) для категорий. Избегайте jet. Для людей с нарушением цветового зрения подходят viridis, cividis.

cmap = plt.get_cmap("viridis"); colors = cmap(np.linspace(0, 1, 5))
from matplotlib.colors import Normalize, LogNorm, TwoSlopeNorm
im = ax.imshow(M, norm=TwoSlopeNorm(vcenter=0))

Стили и настройки

plt.style.use("seaborn-v0_8-whitegrid")     # print(plt.style.available): ggplot, bmh, dark_background, fivethirtyeight
with plt.style.context("dark_background"): ...
plt.rcParams.update({"font.size": 12, "axes.titlesize": 14, "figure.dpi": 120, "axes.spines.top": False, "axes.spines.right": False})

Свой стиль: файл .mplstyle и plt.style.use("my.mplstyle").

Работа с данными

df.plot(x="date", y=["a", "b"], kind="line", ax=ax)                  # pandas строит через Matplotlib
ax.plot(df["date"], df["value"]); fig.autofmt_xdate()                 # даты на оси
import matplotlib.dates as mdates; ax.xaxis.set_major_formatter(mdates.DateFormatter("%d.%m")); ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.fill_between(df.index, df.lo, df.hi, alpha=.2)                      # доверительный интервал
ax.scatter(x, y, c=group.map(color_map))                               # цвет по категории

Для статистических графиков удобнее Seaborn (sns.histplot, sns.boxplot, sns.heatmap, sns.pairplot, sns.lmplot) поверх Matplotlib.

3D и анимация

ax = fig.add_subplot(projection="3d"); ax.plot_surface(X, Y, Z, cmap="viridis"); ax.scatter(x, y, z); ax.view_init(30, 45)

from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(); line, = ax.plot([], [])
def update(frame): line.set_data(x[:frame], y[:frame]); return line,
ani = FuncAnimation(fig, update, frames=len(x), interval=30, blit=True)
ani.save("anim.gif", writer="pillow", fps=30)                           # mp4: writer="ffmpeg"

Сохранение

fig.savefig("a.png", dpi=200, bbox_inches="tight"), форматы png, jpg, svg, pdf, eps. Для публикаций векторные (svg, pdf), для веба png/webp. Размер в дюймах: ширина колонки журнала ~3.5 дюйма. plt.close(fig) освобождает память в циклах.

Интерактивность

Окна plt.show(), виджеты (matplotlib.widgets.Slider, Button), события (fig.canvas.mpl_connect("button_press_event", f)). Для интерактива в вебе: Plotly, Bokeh, Altair, Dash.

Хорошие практики визуализации

  • Подписывайте оси и единицы измерения, заголовок говорит вывод.
  • Начинайте столбцы с нуля; не используйте 3D и круговые диаграммы без нужды.
  • Минимум линий и цветов, сортируйте категории, подписывайте напрямую вместо легенды, где можно.
  • Подбирайте тип графика под вопрос: сравнение (столбцы), динамика (линия), распределение (гистограмма, ящик), связь (scatter), состав (stacked bar).
  • Одинаковые шкалы при сравнении панелей (sharey=True).

Частые ошибки

  • Смешение стилей plt.plot и объектного: путаница с текущими осями.
  • Накопление графиков в цикле без plt.close.
  • Наложение подписей: layout="constrained", поворот меток, fig.tight_layout().
  • Кириллица квадратиками: нет подходящего шрифта.
  • plt.show() блокирует в скриптах; в серверной среде используйте бэкенд Agg (matplotlib.use("Agg")).
  • Огромные данные: прореживание, hexbin, datashader, rasterized=True.