Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Matplotlib и Seaborn

🎯 Цель

После прочтения этой главы:

  • Сможете управлять своими графиками на уровне figure, axes через Matplotlib
  • Сможете создавать статистические графики в 1-2 строки через Seaborn
  • Знаете все основные типы chart, нужные для ML-проектов
  • Сможете готовить красивую визуализацию для отчёта EDA (Exploratory Data Analysis)

Что нужно изучить

Matplotlib

  • Архитектура Figure и Axes
  • pyplot interface (простой) vs Object-oriented API (контроль)
  • Основные типы chart: plot, scatter, bar, hist, boxplot
  • Subplots: subplots(), GridSpec
  • Customization: title, labels, legend, ticks, colors
  • Сохранение: savefig (PNG, SVG, PDF)

Seaborn

  • Themes и styling (set_theme, set_palette)
  • Categorical plots: countplot, barplot, boxplot, violinplot
  • Distribution plots: histplot, kdeplot, displot
  • Relationship plots: scatterplot, lineplot, regplot
  • Matrix plots: heatmap, clustermap
  • Multi-plot grids: FacetGrid, PairGrid, pairplot

Библиотеки

pip install matplotlib seaborn

Альтернатива Plotly (для интерактивных графиков):

pip install plotly

Важные темы

Архитектура Matplotlib

Каждый график в Matplotlib состоит из 3 слоёв:

  1. Figure — весь “холст” (файл изображения)
  2. Axes — область одного chart (subplot)
  3. Элементы plot — линия, точка, bar, label и т.д.
import matplotlib.pyplot as plt

# Есть 2 interface:

# 1. Pyplot API (простой, но global state)
plt.plot([1, 2, 3], [4, 5, 6])
plt.title("Quick")
plt.show()

# 2. Object-oriented API (РЕКОМЕНДУЕТСЯ — для крупных проектов)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("Better")
ax.set_xlabel("X")
ax.set_ylabel("Y")
fig.savefig("plot.png", dpi=150, bbox_inches="tight")

Когда Matplotlib, когда Seaborn?

  • Matplotlib — когда нужен полный контроль, custom layout
  • Seaborn — статистические chart, прямая работа с DataFrame, “хорошо выглядящие default’ы”

В реальной работе обычно используют оба вместе:

fig, ax = plt.subplots(figsize=(10, 6))
sns.heatmap(corr_matrix, annot=True, ax=ax)
ax.set_title("My Correlation Matrix")

Примеры кода

Основные типы chart

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, y1, label="sin(x)", color="blue", linewidth=2)
ax.plot(x, y2, label="cos(x)", color="red", linestyle="--")
ax.set_title("Trigonometric Functions")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

Subplots

fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# Histogram
data = np.random.normal(0, 1, 1000)
axes[0, 0].hist(data, bins=30, color="steelblue", edgecolor="black")
axes[0, 0].set_title("Histogram")

# Scatter
x = np.random.rand(100)
y = x + np.random.normal(0, 0.1, 100)
axes[0, 1].scatter(x, y, alpha=0.6)
axes[0, 1].set_title("Scatter")

# Bar
categories = ["A", "B", "C", "D"]
values = [23, 45, 56, 78]
axes[1, 0].bar(categories, values, color=["red", "green", "blue", "orange"])
axes[1, 0].set_title("Bar")

# Box plot
data_groups = [np.random.normal(i, 1, 100) for i in range(3)]
axes[1, 1].boxplot(data_groups, labels=["Group 1", "Group 2", "Group 3"])
axes[1, 1].set_title("Box Plot")

plt.tight_layout()
plt.show()

Статистические chart в Seaborn

import seaborn as sns
import pandas as pd

# Загрузка Titanic dataset
df = sns.load_dataset("titanic")

# Установка темы
sns.set_theme(style="whitegrid", palette="muted")

# Categorical plot
fig, ax = plt.subplots(figsize=(8, 5))
sns.countplot(data=df, x="class", hue="survived", ax=ax)
ax.set_title("Survival by Class")
plt.show()

# Distribution
sns.histplot(data=df, x="age", hue="survived", multiple="stack", bins=30)
plt.title("Age distribution by survival")
plt.show()

# Pairplot — связь между всеми features
sns.pairplot(df[["age", "fare", "pclass", "survived"]].dropna(), hue="survived")
plt.show()

# Heatmap — correlation matrix
numeric_df = df.select_dtypes(include="number")
corr = numeric_df.corr()
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(corr, annot=True, cmap="coolwarm", center=0, fmt=".2f", ax=ax)
ax.set_title("Correlation Matrix")
plt.show()

Красивый style для production

# Custom theme
plt.style.use("seaborn-v0_8-darkgrid")  # или "ggplot", "fivethirtyeight"

# Или полностью custom
plt.rcParams.update({
    "font.size": 11,
    "axes.titlesize": 14,
    "axes.titleweight": "bold",
    "figure.dpi": 100,
    "savefig.dpi": 200,
    "savefig.bbox": "tight",
})

Интеграция с backend

1. Chart endpoint в FastAPI (возврат PNG)

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import matplotlib
matplotlib.use("Agg")  # ВАЖНО: для backend нет GUI
import matplotlib.pyplot as plt
import io

app = FastAPI()

@app.get("/chart/sales.png")
async def sales_chart():
    df = pd.read_sql("SELECT date, sales FROM daily_sales ORDER BY date", engine)
    
    fig, ax = plt.subplots(figsize=(12, 5))
    ax.plot(df["date"], df["sales"], color="navy", linewidth=2)
    ax.fill_between(df["date"], df["sales"], alpha=0.3, color="navy")
    ax.set_title("Daily Sales")
    ax.set_xlabel("Date")
    ax.set_ylabel("Sales (USD)")
    
    buf = io.BytesIO()
    fig.savefig(buf, format="png", dpi=150, bbox_inches="tight")
    plt.close(fig)  # ВАЖНО: предотвращение memory leak
    buf.seek(0)
    
    return StreamingResponse(buf, media_type="image/png")

2. Background report generation

@celery_app.task
def generate_monthly_report(month: str):
    df = load_data(month)
    
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    
    # Revenue trend
    df.set_index("date")["revenue"].plot(ax=axes[0, 0], title="Revenue")
    
    # Top categories
    df.groupby("category")["revenue"].sum().nlargest(10).plot.barh(ax=axes[0, 1])
    
    # User growth
    df.groupby("date")["new_users"].sum().plot(ax=axes[1, 0])
    
    # Correlation
    sns.heatmap(df.corr(), ax=axes[1, 1], annot=True, fmt=".2f")
    
    plt.tight_layout()
    fig.savefig(f"/reports/{month}.pdf", format="pdf")
    plt.close(fig)
    
    send_email_with_attachment(f"/reports/{month}.pdf")

Важное замечание для server-side rendering

При использовании matplotlib в backend:

  1. Делайте matplotlib.use("Agg") — чтобы не загружать GUI backend
  2. **Вызывайте plt.close(fig)**— чтобы предотвратить memory leak
  3. Thread safety — matplotlib не thread-safe. Можно использовать Gunicorn workers, но в async-контексте выносите в отдельный поток (asyncio.to_thread)

Ресурсы

🏋️ Упражнения

🟢 Easy

  1. С NumPy создайте 1000 случайных чисел и нарисуйте их histogram (matplotlib).
  2. В Seaborn загрузите iris dataset и сделайте pairplot.
  3. Создайте 2x2 subplot, в каждом — свой тип chart.

🟡 Medium

  1. Нарисуйте correlation matrix Titanic dataset через heatmap с annot=True и custom colormap.
  2. Создайте custom theme: шрифт, цвета, стиль grid — сохраните его в модуле mlflow_style.py и импортируйте в других проектах.
  3. Создайте chart с 2 y-axis в одном Figure (twinx) — например, daily users и daily revenue на одном x-axis.

🔴 Hard

  1. FastAPI Dashboard: создайте endpoint /api/charts/{chart_type}.png. Пользователь передаёт query-параметры chart_type=line|bar|hist|scatter, data_source=..., title=... и получает красивый PNG. Добавьте caching (через Redis).
  2. PDF report: создайте multi-page PDF report из 10 страниц (используя matplotlib PdfPages): обложка, аналитика по разделам, итоговая summary.

Capstone

notebooks/month-01/03_visualization.ipynb:

  • Загрузите COVID-19 или любой public time-series dataset
  • Создайте EDA report с 6 разными типами chart (line, bar, hist, box, scatter, heatmap)
  • Всё в одном Figure, сделайте layout через GridSpec
  • Сохраните в PDF формате

✅ Чек-лист

  • Знаю разницу между API pyplot и OO API
  • Понимаю взаимосвязь Figure и Axes
  • Умею создавать subplots и управлять layout
  • Знаю, как использовать heatmap, pairplot, distplot в Seaborn
  • Умею создавать custom style/theme
  • Знаю, что в backend для matplotlib использую Agg и plt.close
  • Могу сохранить chart в PNG, SVG, PDF форматах

EDA Capstone проект — переходим к настоящей работе.