Шпаргалка по Matplotlib: графики от простых до публикационных
Matplotlib — основа визуализации в Python. Два API: pyplot (быстрый, для скриптов) и OO-API (объектный, для контроля). Шпаргалка покрывает оба — от первой линии до публикационных графиков.
Два API: pyplot vs OO
Matplotlib предоставляет два способа рисовать графики. Pyplot (plt.plot()) — быстрый для скриптов и ноутбуков, неявно хранит состояние. OO-API (fig, ax = plt.subplots()) — явные объекты, полный контроль над каждой деталью. Для всего, кроме быстрой разведки данных, используйте OO-API — он предсказуем и не ломается при усложнении.
import matplotlib.pyplot as plt
import numpy as np
# Pyplot API — неявное состояние (быстро, но меньше контроля)
plt.plot([1, 2, 3], [1, 4, 9])
plt.title('График')
plt.show()
# OO-API — явные объекты (рекомендуется для всего кроме разведки)
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot([1, 2, 3], [1, 4, 9])
ax.set_title('График')
fig.savefig('plot.png', dpi=150)
plt.close() # освободить память
Основные типы графиков
Полный набор стандартных визуализаций: линии для трендов, scatter для корреляций, bar/barh для категорий, hist для распределений, pie для долей, boxplot для статистик, fill_between для диапазонов, imshow для матриц. Каждый тип решает свою задачу.
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# Линейный график
fig, ax = plt.subplots()
ax.plot(x, y1, label='sin', color='blue', linewidth=2, linestyle='--')
ax.plot(x, y2, label='cos', color='red', linewidth=1.5)
ax.legend(); ax.grid(True, alpha=0.3)
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_title('Синус и косинус')
# Точечный график (scatter)
fig, ax = plt.subplots()
colors = np.random.rand(50)
sizes = np.random.rand(50) * 200
ax.scatter(x[:50], y1[:50], c=colors, s=sizes, alpha=0.6,
cmap='viridis', edgecolors='black', linewidth=0.5)
plt.colorbar(ax.collections[0], ax=ax)
# Столбчатая диаграмма
categories = ['A', 'B', 'C', 'D']
values = [23, 45, 56, 78]
errors = [3, 5, 2, 4]
ax.bar(categories, values, yerr=errors, capsize=5,
color=['#2196F3', '#4CAF50', '#FF9800', '#F44336'],
edgecolor='black', linewidth=0.5)
# Добавить значения над столбцами
for bar, val in zip(ax.patches, values):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1,
str(val), ha='center', va='bottom')
# Горизонтальный bar
ax.barh(categories, values, color='steelblue')
# Гистограмма
data = np.random.randn(1000)
ax.hist(data, bins=30, density=True, alpha=0.7, edgecolor='black')
# Несколько распределений на одном графике
ax.hist(np.random.randn(1000), bins=30, alpha=0.5, label='Группа A')
ax.hist(np.random.randn(1000)+2, bins=30, alpha=0.5, label='Группа B')
ax.legend()
# Круговая диаграмма
sizes = [30, 25, 20, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0, 0.1, 0, 0, 0) # выдвинуть сектор B
ax.pie(sizes, labels=labels, explode=explode, autopct='%1.1f%%',
startangle=90, shadow=True)
ax.axis('equal') # круг, не эллипс
# Boxplot
data = [np.random.randn(100), np.random.randn(100)+1, np.random.randn(100)-1]
ax.boxplot(data, labels=['A', 'B', 'C'], patch_artist=True)
# Заливка между линиями (fill_between)
ax.fill_between(x, y1 - 0.1, y1 + 0.1, alpha=0.3, label='±0.1')
# График с ошибками (errorbar)
ax.errorbar(x[:10], y1[:10], yerr=0.1, fmt='o', capsize=3, capthick=1)
# Heatmap / imshow
matrix = np.random.rand(10, 10)
ax.imshow(matrix, cmap='viridis', aspect='auto')
plt.colorbar(ax.images[0], ax=ax)
Subplots и компоновка
Несколько графиков на одной фигуре. subplots — простая сетка N×M. GridSpec — гибкая: ячейки разного размера, spanning. subplot_mosaic — самая удобная (именованные ячейки через ASCII-схему). tight_layout() исправляет наложение подписей.
# Простая сетка
fig, axes = plt.subplots(2, 3, figsize=(15, 8))
axes = axes.flatten() # в плоский массив для итерации
for i, ax in enumerate(axes):
ax.plot(x, np.sin(x + i))
ax.set_title(f'Смещение {i}')
plt.tight_layout() # исправить наложение
# GridSpec — гибкая сетка
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 8))
gs = GridSpec(3, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, :]) # весь верхний ряд
ax2 = fig.add_subplot(gs[1, 0:2]) # левая часть среднего ряда
ax3 = fig.add_subplot(gs[1, 2]) # правый столбец среднего
ax4 = fig.add_subplot(gs[2, 0]) # левый нижний
ax5 = fig.add_subplot(gs[2, 1:]) # правые два нижних
# subplot_mosaic — ещё удобнее (Python 3.7+)
fig, axes = plt.subplot_mosaic([
['A', 'A', 'A'],
['A', 'A', 'A'],
['B', 'C', 'C'],
['B', 'D', 'E'],
], figsize=(12, 10))
axes['A'].plot(x, y1); axes['A'].set_title('Главный график')
axes['B'].bar(categories, values); axes['B'].set_title('Bar')
axes['C'].scatter(x, y2); axes['C'].set_title('Scatter')
axes['D'].hist(data); axes['D'].set_title('Hist')
axes['E'].pie(sizes); axes['E'].set_title('Pie')
Оформление
Внешний вид графика: размер, фон, сетка, легенда, подписи осей, тики, рамки. Хорошее оформление отличает «черновой» график от публикационного. Настройка через ax.set_* и ax.spines.
# Размер и фон
fig, ax = plt.subplots(figsize=(12, 6))
fig.patch.set_facecolor('white') # фон фигуры
ax.set_facecolor('#f5f5f5') # фон области графика
# Сетка
ax.grid(True, alpha=0.3, linestyle='--', linewidth=0.5)
ax.grid(axis='y', which='major', color='gray', alpha=0.2)
# Легенда
ax.legend(loc='upper right', frameon=True, fancybox=True, shadow=True)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left') # за пределами
# Подписи осей
ax.set_xlabel('Время (сек)', fontsize=12, fontweight='bold')
ax.set_ylabel('Значение', fontsize=12)
ax.set_title('Заголовок', fontsize=14, fontweight='bold', pad=15)
# Пределы и масштаб
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
ax.set_xscale('log') # логарифмическая шкала
ax.set_yscale('symlog') # симметричная логарифмическая
ax.set_aspect('equal') # одинаковый масштаб по осям
# Тики (деления)
ax.set_xticks([0, np.pi, 2*np.pi])
ax.set_xticklabels(['0', 'π', '2π'], fontsize=10)
ax.tick_params(axis='both', which='major', labelsize=10, rotation=45)
# Настройка тиков через locator/formatter
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
ax.xaxis.set_major_locator(MultipleLocator(0.5))
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
# Спрятать рамки (классический стиль)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
Двойные оси (twin axes)
Два графика с разными шкалами Y на одном поле. Например: температура (левая ось, °C) и влажность (правая ось, %). twinx() создаёт вторую ось Y с общим X. Легенду нужно собирать вручную из обеих осей.
fig, ax1 = plt.subplots(figsize=(10, 6))
# Первая ось (левая)
ax1.plot(x, y1, 'b-', label='Температура')
ax1.set_xlabel('Время')
ax1.set_ylabel('Температура (°C)', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')
# Вторая ось (правая)
ax2 = ax1.twinx()
ax2.plot(x, y2*100, 'r-', label='Влажность')
ax2.set_ylabel('Влажность (%)', color='red')
ax2.tick_params(axis='y', labelcolor='red')
# Объединённая легенда
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
Стили и темы
Готовые наборы оформления: ggplot (как в R), seaborn-v0_8 (чистый современный), fivethirtyeight (блоговый), dark_background. Можно комбинировать, временно применять (with plt.style.context) и настраивать глобально через rcParams.
# Встроенные стили
print(plt.style.available) # ['ggplot', 'seaborn-v0_8', 'fivethirtyeight', ...]
plt.style.use('ggplot')
plt.style.use('seaborn-v0_8-darkgrid')
plt.style.use('fivethirtyeight')
# Временный стиль (контекстный менеджер)
with plt.style.context('dark_background'):
fig, ax = plt.subplots()
ax.plot(x, y1)
# Комбинация стилей
plt.style.use(['seaborn-v0_8', 'seaborn-v0_8-pastel'])
# Кастомные настройки через rcParams
plt.rcParams.update({
'figure.figsize': (10, 6),
'font.size': 12,
'axes.titlesize': 14,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'lines.linewidth': 2,
'figure.dpi': 100,
'savefig.dpi': 150,
'savefig.bbox': 'tight',
})
# Временные rcParams
with plt.rc_context({'lines.linewidth': 3, 'font.size': 16}):
fig, ax = plt.subplots()
ax.plot(x, y1)
Colormaps (цветовые карты)
Цветовые схемы для визуализации третьего измерения: sequential (от светлого к тёмному), diverging (двухцветные, для отклонений), qualitative (разные цвета для категорий). Выбор правильной colormap критичен для восприятия данных.
# Типы colormaps:
# Sequential: 'viridis', 'plasma', 'inferno', 'magma', 'cividis'
# Diverging: 'RdBu', 'coolwarm', 'seismic', 'Spectral'
# Qualitative: 'tab10', 'Set1', 'Pastel1', 'Dark2'
# Cyclic: 'twilight', 'hsv'
# Применение
sc = ax.scatter(x, y, c=values, cmap='coolwarm')
plt.colorbar(sc, ax=ax, label='Значение')
# Реверс cmap
ax.scatter(x, y, c=values, cmap='coolwarm_r') # суффикс _r
Аннотации и текст
Текст, стрелки, линии-указатели на графике. text() — произвольный текст в координатах данных или осей. annotate() — текст со стрелкой (идеально для «вот здесь пик»). axhline/axvline — горизонтальные/вертикальные линии-ориентиры.
# Текст в координатах данных
ax.text(5, 0.5, 'Максимум', fontsize=12, ha='center')
# Текст в координатах осей (0-1)
ax.text(0.95, 0.95, '(a)', transform=ax.transAxes,
fontsize=14, fontweight='bold', va='top', ha='right')
# Аннотация со стрелкой
ax.annotate('Пик', xy=(np.pi/2, 1.0), xytext=(np.pi/2+2, 0.5),
arrowprops=dict(arrowstyle='->', color='red', lw=1.5),
fontsize=12, color='red')
# Горизонтальные/вертикальные линии
ax.axhline(y=0, color='black', linewidth=0.5) # y=0
ax.axvline(x=np.pi, color='red', linestyle='--') # x=π
ax.axhspan(-0.5, 0.5, alpha=0.2, color='blue') # заливка полосы
3D-графики
Трёхмерные визуализации через mpl_toolkits.mplot3d: поверхности (plot_surface), контуры (contour), scatter и линии в 3D. Требуют projection='3d' при создании осей. Хороши для визуализации функций двух переменных.
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# Поверхность
X = np.linspace(-5, 5, 50)
Y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(X, Y)
Z = np.sin(np.sqrt(X**2 + Y**2))
surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
fig.colorbar(surf, ax=ax, shrink=0.5, aspect=10)
# Линии уровня (контуры)
ax.contour(X, Y, Z, zdir='z', offset=-1, cmap='viridis', alpha=0.5)
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
ax.set_title('3D поверхность')
Сохранение
Экспорт графика в файл: PNG (растр, для веба/презентаций), PDF/SVG (вектор, для статей/печати). Ключевые параметры: dpi (качество растра), bbox_inches='tight' (обрезать поля), transparent=True (прозрачный фон). Для многостраничных отчётов — PdfPages.
# PNG (растровый) — для веба, презентаций
fig.savefig('plot.png', dpi=150, bbox_inches='tight')
# PNG с прозрачным фоном
fig.savefig('plot.png', dpi=150, bbox_inches='tight', transparent=True)
# PDF (векторный) — для статей, печати
fig.savefig('plot.pdf', bbox_inches='tight')
# SVG (векторный) — для веба, редактирования
fig.savefig('plot.svg', bbox_inches='tight')
# Многостраничный PDF
from matplotlib.backends.backend_pdf import PdfPages
with PdfPages('report.pdf') as pdf:
for i in range(5):
fig, ax = plt.subplots()
ax.plot(x, np.sin(x + i))
pdf.savefig(fig)
plt.close(fig)
# Высокое качество для публикаций
fig.savefig('plot.png', dpi=300, bbox_inches='tight', pad_inches=0.1)
Анимация
Анимированные графики через FuncAnimation: функция animate(i) вызывается для каждого кадра, возвращая обновлённые данные. Сохранение в GIF (pillow writer) или MP4 (ffmpeg). blit=True ускоряет отрисовку, перерисовывая только изменившиеся элементы.
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
line, = ax.plot([], [], lw=2)
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1.5, 1.5)
def init():
line.set_data([], [])
return line,
def animate(i):
line.set_data(x, np.sin(x + i*0.1))
return line,
anim = FuncAnimation(fig, animate, init_func=init,
frames=200, interval=50, blit=True)
# Сохранить как GIF
anim.save('animation.gif', writer='pillow', fps=30)
# Сохранить как MP4 (нужен ffmpeg)
# anim.save('animation.mp4', writer='ffmpeg', fps=30)
Интерактивность
Реакция на действия пользователя: клики мыши (button_press_event), нажатия клавиш (key_press_event). Через fig.canvas.mpl_connect() можно добавить свои обработчики — например, ставить точки по клику или переключать данные по клавише.
# Обработчик кликов
def on_click(event):
if event.inaxes: # клик внутри области графика
ax.plot(event.xdata, event.ydata, 'ro')
fig.canvas.draw()
fig.canvas.mpl_connect('button_press_event', on_click)
# Обработчик клавиш
def on_key(event):
if event.key == 'r':
ax.clear()
ax.plot(x, y1)
fig.canvas.draw()
fig.canvas.mpl_connect('key_press_event', on_key)
Производительность
Для больших данных (>10k точек) стандартный scatter тормозит. Решения: plot(..., 'o') вместо scatter, растеризация (rasterized=True), blitting для анимаций. Выбор правильного подхода важен, когда график строится не в ноутбуке, а в production-пайплайне.
# Для больших данных (>10k точек)
# Использовать plot вместо scatter
ax.plot(x_big, y_big, 'o', markersize=1) # быстрее чем scatter
# Растеризация scatter (векторная сетка + растровые точки)
ax.scatter(x_big, y_big, s=1, rasterized=True)
# Blitting для анимаций
anim = FuncAnimation(fig, animate, init_func=init,
frames=200, interval=50, blit=True) # быстрее
Публикационный чек-лист
Готовый шаблон для создания графика, который не стыдно показать: информативный заголовок, подписанные оси, сетка, легенда, чистый фон без лишних рамок, высокое разрешение при сохранении. Пройдитесь по пунктам — получите публикационное качество.
fig, ax = plt.subplots(figsize=(10, 6))
# 1. Данные
ax.plot(x, y1, label='Ваш график', color='#2196F3', linewidth=2)
# 2. Заголовок и подписи
ax.set_title('Информативный заголовок', fontsize=14, fontweight='bold')
ax.set_xlabel('Ось X (единицы)', fontsize=12)
ax.set_ylabel('Ось Y (единицы)', fontsize=12)
# 3. Сетка
ax.grid(True, alpha=0.3, linestyle='--')
# 4. Легенда
ax.legend(loc='upper right', frameon=True, fontsize=11)
# 5. Оформление
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
fig.patch.set_facecolor('white')
# 6. Сохранить
fig.savefig('publication_plot.png', dpi=300, bbox_inches='tight')
Частые ошибки
| Ошибка | Правильно |
|---|---|
plt.show() в цикле без plt.close() |
Утечка памяти! Закрывай фигуры |
plt.show() очищает фигуру |
Сохраняй ДО show() |
Забыт plt.tight_layout() |
Подписи обрезаются |
ax.set_xlim() после ax.plot() |
OK, но до savefig() |
Не тот transform= в аннотации |
ax.transData / ax.transAxes |
| pyplot в функциях/циклах | Используй OO-API |
| Китайские/русские символы — квадраты | Настрой шрифт: plt.rcParams['font.family'] = 'DejaVu Sans' |
Ресурсы
- Сайт Matplotlib — документация, галерея, шпаргалки
- Matplotlib на GitHub — исходный код
Что дальше
- Шпаргалка по Seaborn: статистическая визуализация
- Шпаргалка по Pandas: DataFrame, groupby, временные ряды
- Шпаргалка по NumPy: массивы, операции, линейная алгебра
- Шпаргалка по Python: от основ до профи
- Шпаргалка по Scikit-learn: машинное обучение на Python
- Data Science инструменты: стек, roadmap, с чего начать
Связанные шпаргалки: Python, NumPy, Pandas, Seaborn, SQL для начинающих