Визуализация на данни с Matplotlib и Seaborn в Python: Практическо ръководство

Научете как да визуализирате данни с Matplotlib и Seaborn в Python. Примери с код за линейни графики, scatter plots, heatmaps, box plots, pair plots и дашборди. Актуално за 2026 г.

Въведение: Защо визуализацията на данни има толкова голямо значение

Можете да имате перфектно почистен набор от данни и прецизно настроен модел за машинно обучение, но ако не успеете да покажете резултатите визуално — голяма част от работата ви просто остава невидима. Визуализацията не е просто „красиви графики". Честно казано, тя е може би най-важният инструмент за разбиране на закономерностите в данните, за представяне на резултати и за вземане на информирани решения.

В Python екосистемата две библиотеки доминират пейзажа: Matplotlib (версия 3.10.x към март 2026 г.) и Seaborn (версия 0.13.2). Първата дава пълен контрол върху всеки пиксел, а втората е елегантна надстройка за бърза статистическа визуализация с минимум код.

И така, нека се потопим. В това ръководство ще минем през всичко — от основните типове графики до по-напреднали техники. Ще работим с реални примери и код, който можете директно да копирате и адаптирате.

Инсталация и първоначална настройка

Инсталиране на библиотеките

Ако вече имате Python 3.10 или по-нова версия, инсталацията е елементарна:

pip install matplotlib seaborn pandas numpy

Seaborn автоматично инсталира Matplotlib като зависимост, но аз лично предпочитам да инсталирам двете изрично — така контролирам версиите по-добре.

Основен импорт и конфигурация

Ето стандартната настройка, която ще използваме навсякъде:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# Настройка на Seaborn темата
sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

# Настройка на размера на фигурите по подразбиране
plt.rcParams["figure.figsize"] = (10, 6)
plt.rcParams["figure.dpi"] = 100

Функцията sns.set_theme() задава глобален стил за всички графики — включително тези, направени с чист Matplotlib. Параметърът style приема стойности като "whitegrid", "darkgrid", "white", "dark" и "ticks".

Matplotlib: Фундаментът на визуализацията

Анатомия на фигурата в Matplotlib

Преди да скочите в кода, трябва да разберете йерархията на обектите. Това е нещо, което много начинаещи пропускат:

  • Figure — цялото „платно", което съдържа всичко
  • Axes — отделна графика (една фигура може да съдържа няколко Axes)
  • Axis — оста X или Y на конкретна графика
  • Artist — всеки визуален елемент (линия, текст, точка и т.н.)

Най-гъвкавият начин за създаване на графики е чрез обектно-ориентирания интерфейс:

fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 20, 25, 30])
ax.set_xlabel("Ос X")
ax.set_ylabel("Ос Y")
ax.set_title("Моята първа графика")
plt.show()

Линейни графики

Линейните графики са идеални за показване на тенденции във времето. Ето един конкретен пример с данни за продажби:

# Генериране на примерни данни за продажби
months = np.arange(1, 13)
sales_2025 = [45, 52, 48, 61, 55, 67, 72, 68, 75, 82, 79, 91]
sales_2026 = [50, 58, 53, 68, 62, 74, 80, 76, 83, 90, 87, 98]

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(months, sales_2025, marker="o", linewidth=2, label="2025")
ax.plot(months, sales_2026, marker="s", linewidth=2, label="2026")

ax.set_xlabel("Месец")
ax.set_ylabel("Продажби (хил. лв.)")
ax.set_title("Месечни продажби: 2025 срещу 2026")
ax.set_xticks(months)
ax.set_xticklabels(["Яну", "Фев", "Мар", "Апр", "Май", "Юни",
                     "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"])
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Стълбовидни диаграми

Когато трябва да сравните категории, стълбовидните диаграми са естественият избор:

categories = ["Python", "R", "SQL", "Julia", "Scala"]
usage = [77, 42, 65, 8, 12]

fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(categories, usage, color=sns.color_palette("muted", len(categories)))

# Добавяне на стойности върху стълбовете
for bar, val in zip(bars, usage):
    ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 1,
            f"{val}%", ha="center", va="bottom", fontweight="bold")

ax.set_ylabel("Процент на използване (%)")
ax.set_title("Използване на езици за Data Science (2026)")
ax.set_ylim(0, 95)
plt.tight_layout()
plt.show()

Точкови диаграми (Scatter Plots)

Scatter plot-овете показват връзката между две числови променливи. Доста полезни са, когато подозирате корелация:

np.random.seed(42)
x = np.random.normal(50, 15, 200)
y = 2.5 * x + np.random.normal(0, 20, 200)
colors = np.random.choice(["A", "B", "C"], 200)

fig, ax = plt.subplots(figsize=(8, 6))
for label, color in zip(["A", "B", "C"], ["#4C72B0", "#DD8452", "#55A868"]):
    mask = colors == label
    ax.scatter(x[mask], y[mask], c=color, label=f"Група {label}",
               alpha=0.6, edgecolors="white", s=60)

ax.set_xlabel("Променлива X")
ax.set_ylabel("Променлива Y")
ax.set_title("Scatter Plot с групиране")
ax.legend()
plt.tight_layout()
plt.show()

Хистограми

Хистограмите показват разпределението на една числова променлива. Ето пример с бимодално разпределение (две „гърбици"):

np.random.seed(42)
data = np.concatenate([
    np.random.normal(50, 10, 500),
    np.random.normal(80, 5, 300)
])

fig, ax = plt.subplots(figsize=(8, 5))
ax.hist(data, bins=40, color="#4C72B0", edgecolor="white",
        alpha=0.7, density=True)
ax.set_xlabel("Стойност")
ax.set_ylabel("Плътност")
ax.set_title("Хистограма на бимодално разпределение")
plt.tight_layout()
plt.show()

Подграфики (Subplots)

Често се налага да показвате няколко графики наведнъж. Matplotlib прави това сравнително лесно:

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

# Горе ляво — линейна графика
axes[0, 0].plot(months, sales_2026, marker="o", color="#4C72B0")
axes[0, 0].set_title("Линейна графика")

# Горе дясно — стълбовидна
axes[0, 1].bar(categories, usage, color="#DD8452")
axes[0, 1].set_title("Стълбовидна диаграма")

# Долу ляво — scatter
axes[1, 0].scatter(x[:50], y[:50], color="#55A868", alpha=0.6)
axes[1, 0].set_title("Scatter Plot")

# Долу дясно — хистограма
axes[1, 1].hist(data, bins=30, color="#C44E52", edgecolor="white")
axes[1, 1].set_title("Хистограма")

for ax in axes.flat:
    ax.grid(True, alpha=0.3)

plt.suptitle("Четири типа графики с Matplotlib", fontsize=14, fontweight="bold")
plt.tight_layout()
plt.show()

Seaborn: Статистическа визуализация с минимум код

Защо Seaborn е толкова популярен

Seaborn е изграден върху Matplotlib, но предлага три основни предимства: работи директно с Pandas DataFrames, има вградени статистически изчисления и визуално е много по-привлекателен по подразбиране. Вместо ръчно да извличате колони и да ги подавате, просто давате целия DataFrame и задавате имената на колоните. Просто е и бързо.

Графики за разпределения

Нека заредим реален набор от данни и да видим какво можем:

# Зареждане на вграден набор от данни
tips = sns.load_dataset("tips")

# Хистограма с оценка на плътност на ядрото (KDE)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

sns.histplot(data=tips, x="total_bill", kde=True, ax=axes[0],
             color="#4C72B0")
axes[0].set_title("Разпределение на сметките")

sns.histplot(data=tips, x="total_bill", hue="time", kde=True,
             ax=axes[1], palette="muted")
axes[1].set_title("Разпределение по време на деня")

plt.tight_layout()
plt.show()

Параметърът kde=True добавя крива на KDE (Kernel Density Estimation) върху хистограмата — много удобно за визуализиране формата на разпределението.

Box Plot и Violin Plot

Тези два типа графики са незаменими за сравняване на разпределения между категории. Лично аз обичам да ги показвам едно до друго:

fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# Box Plot
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex",
            ax=axes[0], palette="Set2")
axes[0].set_title("Box Plot: Сметки по дни и пол")

# Violin Plot
sns.violinplot(data=tips, x="day", y="total_bill", hue="sex",
               split=True, ax=axes[1], palette="Set2",
               inner="quart")
axes[1].set_title("Violin Plot: Сметки по дни и пол")

plt.tight_layout()
plt.show()

Violin Plot е по-информативен от Box Plot, защото показва цялото разпределение, а не само квартилите. Параметърът split=True позволява директно сравняване на две групи в едно поле — доста елегантно решение.

Корелационна топлинна карта (Heatmap)

Топлинните карти са един от любимите ми инструменти за бързо идентифициране на връзки между променливи:

# Зареждане на набор от данни с повече числови колони
penguins = sns.load_dataset("penguins").dropna()

# Изчисляване на корелационна матрица
corr_matrix = penguins.select_dtypes(include="number").corr()

# Маска за горния триъгълник (за избягване на дублиране)
mask = np.triu(np.ones_like(corr_matrix, dtype=bool))

fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr_matrix, mask=mask, annot=True, fmt=".2f",
            cmap="coolwarm", center=0, square=True,
            linewidths=1, cbar_kws={"shrink": 0.8},
            vmin=-1, vmax=1, ax=ax)
ax.set_title("Корелационна матрица — Palmer Penguins")
plt.tight_layout()
plt.show()

Ключови параметри на sns.heatmap():

  • annot=True — показва числовите стойности върху клетките
  • mask — скрива горния триъгълник (той е огледален)
  • cmap="coolwarm" — цветова схема с различни цветове за положителна и отрицателна корелация
  • center=0 — центрира цветовата скала около нулата

Pair Plot за бърз преглед

Когато искате бързо да прегледате връзките между всички числови променливи, sns.pairplot() е незаменим. Буквално един ред код ви дава матрица от графики:

sns.pairplot(penguins, hue="species", palette="muted",
             diag_kind="kde",
             plot_kws={"alpha": 0.6, "s": 40, "edgecolor": "white"})
plt.suptitle("Pair Plot — Palmer Penguins", y=1.02, fontsize=14)
plt.show()

Pair Plot генерира матрица от scatter plots за всяка двойка числови променливи, а по диагонала — разпределението на всяка от тях. Параметърът hue оцветява точките по категория и веднага разкрива клъстери.

Регресионни графики

Seaborn може автоматично да добавя линия на регресия заедно с доверителен интервал, което е изключително полезно при бърз анализ:

fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# Линейна регресия
sns.regplot(data=tips, x="total_bill", y="tip", ax=axes[0],
            scatter_kws={"alpha": 0.5}, color="#4C72B0")
axes[0].set_title("Линейна регресия: Сметка vs Бакшиш")

# Регресия по категории
sns.lmplot(data=tips, x="total_bill", y="tip", hue="smoker",
           palette="Set1", height=6, aspect=1.2,
           scatter_kws={"alpha": 0.5, "s": 40})
plt.title("Регресия по групи: Пушачи vs Непушачи")
plt.show()

Комбиниране на Matplotlib и Seaborn

Финна настройка на Seaborn графики с Matplotlib

Тъй като всяка Seaborn графика е Matplotlib обект отдолу, можете свободно да ги комбинирате. Това е нещо, което аз правя постоянно:

fig, ax = plt.subplots(figsize=(10, 6))

# Seaborn за основната графика
sns.boxplot(data=tips, x="day", y="total_bill", palette="pastel", ax=ax)

# Matplotlib за допълнителни елементи
ax.axhline(y=tips["total_bill"].mean(), color="red", linestyle="--",
           linewidth=1.5, label=f"Средна стойност: {tips['total_bill'].mean():.2f}")
ax.legend(fontsize=11)

# Добавяне на анотация
ax.annotate("Най-високи сметки",
            xy=(2, 50), xytext=(0.5, 48),
            arrowprops=dict(arrowstyle="->", color="gray"),
            fontsize=11, color="gray")

ax.set_title("Разпределение на сметките по ден от седмицата",
             fontsize=13, fontweight="bold")
ax.set_xlabel("Ден")
ax.set_ylabel("Обща сметка ($)")
plt.tight_layout()
plt.show()

Дашборд с множество графики

А ето и нещо по-сериозно — пълен дашборд, комбиниращ различни типове визуализации. GridSpec на Matplotlib позволява доста гъвкав layout:

fig = plt.figure(figsize=(16, 12))

# Дефиниране на layout с GridSpec
gs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.3)

# Голяма графика отляво (scatter + регресия)
ax1 = fig.add_subplot(gs[0:2, 0:2])
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time",
                style="smoker", palette="muted", s=60, ax=ax1)
ax1.set_title("Сметка vs Бакшиш", fontsize=13, fontweight="bold")

# Малка графика горе дясно (box plot)
ax2 = fig.add_subplot(gs[0, 2])
sns.boxplot(data=tips, y="tip", x="time", palette="pastel", ax=ax2)
ax2.set_title("Бакшиш по време")

# Малка графика средата дясно (histogram)
ax3 = fig.add_subplot(gs[1, 2])
sns.histplot(data=tips, x="tip", kde=True, color="#55A868", ax=ax3)
ax3.set_title("Разпределение на бакшиша")

# Долен ред — три bar plots
ax4 = fig.add_subplot(gs[2, 0])
sns.countplot(data=tips, x="day", palette="muted", ax=ax4)
ax4.set_title("Брой записи по ден")

ax5 = fig.add_subplot(gs[2, 1])
sns.barplot(data=tips, x="day", y="total_bill", estimator=np.mean,
            palette="muted", ax=ax5)
ax5.set_title("Средна сметка по ден")

ax6 = fig.add_subplot(gs[2, 2])
sns.barplot(data=tips, x="day", y="tip", estimator=np.mean,
            palette="muted", ax=ax6)
ax6.set_title("Среден бакшиш по ден")

plt.suptitle("Дашборд за анализ на ресторантски данни",
             fontsize=16, fontweight="bold", y=1.01)
plt.show()

Практически проект: EDA визуализация стъпка по стъпка

Нека приложим наученото върху реален сценарий — пълен визуален Exploratory Data Analysis на набора от данни „Palmer Penguins". Тук е, където нещата стават наистина интересни.

Стъпка 1: Зареждане и първоначален преглед

penguins = sns.load_dataset("penguins")

print(f"Размер: {penguins.shape}")
print(f"\nЛипсващи стойности:\n{penguins.isnull().sum()}")
print(f"\nОписателна статистика:\n{penguins.describe()}")

# Почистване на липсващите стойности
penguins_clean = penguins.dropna()

Стъпка 2: Разпределение на целевата променлива

fig, axes = plt.subplots(1, 3, figsize=(16, 5))

# Брой по вид
sns.countplot(data=penguins_clean, x="species", palette="muted",
              ax=axes[0], order=penguins_clean["species"].value_counts().index)
axes[0].set_title("Брой пингвини по вид")
for container in axes[0].containers:
    axes[0].bar_label(container, fontweight="bold")

# По остров
sns.countplot(data=penguins_clean, x="island", hue="species",
              palette="muted", ax=axes[1])
axes[1].set_title("Разпределение по остров")

# По пол
sns.countplot(data=penguins_clean, x="sex", hue="species",
              palette="muted", ax=axes[2])
axes[2].set_title("Разпределение по пол")

plt.tight_layout()
plt.show()

Стъпка 3: Числови разпределения

numeric_cols = ["bill_length_mm", "bill_depth_mm",
                "flipper_length_mm", "body_mass_g"]

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

for ax, col in zip(axes.flat, numeric_cols):
    sns.histplot(data=penguins_clean, x=col, hue="species",
                 kde=True, palette="muted", alpha=0.5, ax=ax)
    ax.set_title(f"Разпределение: {col}")
    ax.legend(title="Вид")

plt.suptitle("Числови разпределения по вид пингвин",
             fontsize=14, fontweight="bold")
plt.tight_layout()
plt.show()

Стъпка 4: Корелации и взаимовръзки

# Pair plot
g = sns.pairplot(penguins_clean, hue="species", palette="muted",
                 diag_kind="kde",
                 plot_kws={"alpha": 0.6, "s": 30, "edgecolor": "white"},
                 corner=True)
g.fig.suptitle("Pair Plot — Всички числови променливи",
               y=1.02, fontsize=14)
plt.show()

# Корелационна матрица по видове
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
species_list = penguins_clean["species"].unique()

for ax, species in zip(axes, species_list):
    subset = penguins_clean[penguins_clean["species"] == species]
    corr = subset[numeric_cols].corr()
    sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm",
                center=0, vmin=-1, vmax=1, ax=ax, square=True)
    ax.set_title(f"Корелации — {species}")

plt.suptitle("Корелационни матрици по вид",
             fontsize=14, fontweight="bold")
plt.tight_layout()
plt.show()

Стъпка 5: Ключов инсайт

fig, ax = plt.subplots(figsize=(10, 7))

sns.scatterplot(data=penguins_clean, x="bill_length_mm",
                y="bill_depth_mm", hue="species", style="sex",
                palette="muted", s=80, alpha=0.7, ax=ax)

ax.set_xlabel("Дължина на клюна (mm)", fontsize=12)
ax.set_ylabel("Дълбочина на клюна (mm)", fontsize=12)
ax.set_title("Парадокс на Симпсън: Дължина vs Дълбочина на клюна",
             fontsize=13, fontweight="bold")
ax.legend(title="Вид / Пол", bbox_to_anchor=(1.05, 1), loc="upper left")
plt.tight_layout()
plt.show()

Тази графика илюстрира класически пример за парадокса на Симпсън. Без разделяне по видове, изглежда че дължината и дълбочината на клюна са отрицателно корелирани. Но когато разделим данните по видове — изненада! — виждаме положителна корелация във всяка отделна група. Това е чудесно напомняне винаги да сегментирате данните си.

Matplotlib срещу Seaborn: Кога кое да използвате

Изборът между двете не е „кое е по-добро", а „кое е по-подходящо за конкретния случай".

Използвайте Matplotlib когато:

  • Имате нужда от пълен контрол над всеки визуален елемент
  • Създавате нестандартни или сложни layout-и с GridSpec
  • Работите с 3D визуализации
  • Правите анимации с matplotlib.animation
  • Подготвяте графики за научни публикации с точни изисквания

Използвайте Seaborn когато:

  • Работите с Pandas DataFrames и искате бърза визуализация
  • Имате нужда от статистически графики (box plot, violin plot, pair plot)
  • Правите Exploratory Data Analysis (EDA)
  • Искате привлекателни графики с минимум код
  • Работите с категориални данни

Комбинирайте двете когато:

  • Започвате с Seaborn за бърз прототип и после финно настройвате с Matplotlib
  • Създавате дашборд с различни типове графики
  • Искате Seaborn естетика с Matplotlib анотации и допълнителни елементи

Често допускани грешки при визуализация

1. Прекалено много информация в една графика

Добавянето на твърде много серии, цветове и анотации прави графиката нечетима. Имам едно просто правило: ако не можете да обясните графиката за 10 секунди, тя е прекалено сложна. Разделете я на няколко по-прости.

2. Неподходящ тип графика

Кръговите диаграми (pie charts) рядко са правилният избор. Човешкото око просто не е добро в сравняването на ъгли. Предпочитайте стълбовидни диаграми за сравнение на категории — много по-лесно се четат.

3. Липсващи надписи и заглавия

Всяка графика трябва да има ясно заглавие, надписи на осите и легенда (ако показвате повече от една серия). Без тях графиката губи целия си контекст.

4. Неподходяща цветова палитра

Избягвайте палитри с твърде близки цветове. И помислете за достъпност — около 8% от мъжете имат далтонизъм. Seaborn предлага специална палитра за целта:

sns.set_palette("colorblind")

5. Липса на plt.tight_layout()

Без plt.tight_layout() елементите често се припокриват. Винаги слагайте този ред преди plt.show(). Сериозно, спасява толкова главоболия.

Запазване на графики за публикация

Когато сте готови да експортирате графиките си:

# PNG с висока резолюция
fig.savefig("grafika.png", dpi=300, bbox_inches="tight",
            facecolor="white", edgecolor="none")

# SVG за уеб
fig.savefig("grafika.svg", format="svg", bbox_inches="tight")

# PDF за печат
fig.savefig("grafika.pdf", format="pdf", bbox_inches="tight")

Параметърът bbox_inches="tight" гарантира, че нищо не се отрязва. А dpi=300 е стандартът за графики, предназначени за печат или презентации.

Често задавани въпроси

Каква е разликата между Matplotlib и Seaborn?

Matplotlib е нисконивова библиотека с пълен контрол върху всеки елемент, но изисква повече код. Seaborn е високонивова надстройка, която опростява статистическите графики и изглежда по-добре по подразбиране. Тъй като всяка Seaborn графика е Matplotlib обект отдолу, двете се комбинират безпроблемно.

Мога ли да използвам Seaborn без Matplotlib?

Не точно — Seaborn зависи от Matplotlib за рендериране на графиките. Инсталира се автоматично като зависимост. За прости визуализации обаче можете да работите предимно със Seaborn функции и да използвате Matplotlib само за plt.show() и plt.savefig().

Кой инструмент е по-добър за начинаещи?

Seaborn определено. Изисква по-малко код и резултатите изглеждат добре от самото начало. Но всъщност си заслужава да научите и основите на Matplotlib — това ви дава разбиране какво се случва „под капака" и ви позволява да правите финни настройки, когато Seaborn не стига.

Как да избера правилния тип графика за моите данни?

Зависи от типа данни и целта: за тенденции във времето — линейни графики; за сравнение на категории — стълбовидни диаграми; за връзки между две числови променливи — scatter plot; за разпределения — хистограми или violin plot; за корелации между множество променливи — heatmap.

Как да направя графиките достъпни за хора с далтонизъм?

Използвайте палитрата "colorblind" в Seaborn (sns.set_palette("colorblind")), избягвайте комбинации от червено и зелено, добавяйте различни маркери и стилове линии (не разчитайте само на цвета) и включвайте текстови анотации за ключовите стойности.

За Автора Editorial Team

Our team of expert writers and editors.