Matplotlib для самых маленьких: от пустого окна до красивого графика

от автора

1. Введение

Знакомство с визуализацией данных на Python почти всегда начинается с Matplotlib. И чаще всего это знакомство приносит боль.

Открываешь официальную документацию — перед тобой неповоротливый монстр. Идешь за быстрым решением на StackOverflow — и запутываешься окончательно. В одном ответе пишут plt.plot(), в другом используют какой-то ax.plot(). Почему синтаксиса два? Какой из них правильный? В итоге нужный график собирается методом Франкенштейна из кусков чужого кода, а малейшая попытка поменять цвет или добавить вторую ось всё ломает.

Цель этой статьи — раз и навсегда избавить вас от этой путаницы. Мы разберем философию библиотеки и саму «анатомию» графика. Я покажу, как работает Matplotlib под капотом, чтобы вы могли осознанно строить основные визуализации с нуля и больше не зависели от слепой копипасты.

Небольшой совет на полях: визуализацию редко делают ради самой визуализации — обычно это финал работы с таблицами. Если вы чувствуете, что пока плаваете в датафреймах, фильтрациях и группировках, очень рекомендую параллельно со статьей пробежаться по бесплатному курсу «Pandas для анализа данных: Полный курс». Правило тут простое: чем лучше вы подготовите данные до отрисовки, тем меньше костылей придется городить в самом Matplotlib.

2. Подготовка к работе

Установка библиотеки банальна до невозможности. Открываем терминал и пишем стандартную мантру:

pip install matplotlib

Теперь импорт. Если вы откроете любой чужой скрипт с визуализацией, то в 99.9% случаев увидите там такую строчку:

import matplotlib.pyplot as plt

Почему именно plt? Это не строгое требование самого языка, а негласное правило комьюнити аналитиков и разработчиков. Точно так же, как pandas всегда импортируют как pd, а numpy как np. Общепринятый алиас экономит кучу времени при наборе кода и позволяет другим людям мгновенно считывать ваши намерения. А pyplot — это тот самый подмодуль внутри огромного Matplotlib, в котором как раз и лежат все нужные нам инструменты для рисования.

Где писать код? Если вы попытаетесь строить графики в обычном .py файле через PyCharm или VS Code, то каждый новый график будет открываться в отдельном системном окне. Пока вы это окно не закроете, выполнение скрипта будет стоять на паузе. Это дико неудобно, когда нужно быстро поэкспериментировать с цветами или формой.

Именно поэтому для визуализации (и вообще для работы с данными) человечество придумало Jupyter Notebook и его облачного брата Google Colab. Их главная филлер-фича — интерактивность. Вы пишете код в ячейке, нажимаете Shift+Enter, и график появляется прямо под ней, сохраняясь в самом документе.

Часто в начале старых ноутбуков можно встретить такую строчку:

%matplotlib inlineimport matplotlib.pyplot as plt

Это так называемая «магическая команда» Jupyter. Она буквально приказывает среде: «Встраивай все нарисованные графики прямо сюда, в веб-страницу, а не пытайся открыть их в новом окне». Справедливости ради, современные версии Jupyter и встроенные среды в IDE поумнели и отлично рисуют графики и без этой команды, применяя её под капотом. Но знать о ней полезно, чтобы не пугаться, встретив в чужом коде.

Инструменты готовы. Теперь давайте разбираться, как эта штука вообще работает.

3. Самое важное: Анатомия графика (Figure и Axes)

Большинство новичков ломают зубы о Matplotlib именно здесь. Вся путаница со StackOverflow растет из непонимания того, из чего состоит график и какими способами к нему можно обращаться.

Давайте разберем простую аналогию с рисованием:

  • Figure (Фигура): Это ваш мольберт, чистый холст или окно программы. Сам по себе холст не содержит графиков, это просто пространство. На одном холсте (Figure) может располагаться как один рисунок, так и целая сетка из множества рисунков.

  • Axes (График): Это непосредственно сам рисунок на холсте. Именно здесь живут ваши данные, оси координат (X и Y), легенда и подписи.

    • Важное уточнение: слово «Axes» дословно переводится как «оси», но в терминологии Matplotlib это область графика целиком. Не путайте это с Axis (непосредственно математической осью).

Из-за того, что библиотека развивалась годами, в ней исторически сложилось два разных подхода к созданию этих самых холстов и графиков. И именно их вы постоянно видите вперемешку в интернете.

Подход 1: Процедурный (через plt)

Этот подход достался Matplotlib в наследство от языка MATLAB. Вы просто говорите библиотеке «рисуй», а она сама невидимо создает Figure, создает Axes и помещает туда данные.

# Быстро, просто, но не гибкоplt.plot([1, 2, 3], [4, 5, 2])plt.title("Мой первый график")

В чем минус? Это так называемый state-based (основанный на состояниях) подход. Все ваши команды (добавить заголовок, поменять цвет) применяются к «текущему активному» графику. Если у вас на холсте три графика, управлять тем, куда именно добавится заголовок через plt, становится очень больно. Это как рисовать картину с завязанными глазами, надеясь, что кисть попадет куда надо.

Подход 2: Объектно-ориентированный (через fig, ax)

Это современный, явный и самый правильный способ взаимодействия с Matplotlib. Мы сразу своими руками создаем объекты мольберта (fig) и рисунка (ax), а потом обращаемся напрямую к ним.

# Создаем холст (fig) и один график на нем (ax)fig, ax = plt.subplots()# Обращаемся напрямую к конкретному графикуax.plot([1, 2, 3], [4, 5, 2])ax.set_title("Мой первый график")

В чем плюс? У вас появляется абсолютный контроль. Если графиков будет десять, у вас будет десять независимых переменных ax, и вы никогда не запутаетесь, к какому из них применяется настройка.

Золотое правило Matplotlib: Забудьте про plt.plot(). Возьмите за привычку всегда начинать построение с fig, ax = plt.subplots() и работать через объект ax. Это спасет вам тысячи нервных клеток.

Дальше в статье (и вообще в жизни) мы будем использовать только этот, второй подход. Поехали строить графики!

4. Поехали: Строим базовые графики

С теорией покончено, переходим к практике. Чтобы нам было с чем работать, сгенерируем немного фейковых данных. Для этого будем использовать списки и библиотеку numpy — стандартный инструмент для работы с числами в Python.

Не забудьте выполнить import numpy as np перед запуском кода.

1. Линейный график (ax.plot)

Зачем нужен: Идеален для показа динамики во времени. Как менялась температура за неделю, курс валют за год или ваш пульс во время дедлайна.

import numpy as npimport matplotlib.pyplot as plt# Данные: дни недели и температураdays = np.arange(1, 8) # Массив от 1 до 7temperature = [20, 22, 21, 25, 28, 26, 24]fig, ax = plt.subplots() # Создаем холст и графикax.plot(days, temperature) # Рисуем линиюplt.show() # Отрисовываем результат

Обратите внимание: plot по умолчанию просто соединяет точки прямыми линиями в том порядке, в котором они идут в массивах.

2. Диаграмма рассеяния (ax.scatter)

Зачем нужна: Для поиска зависимостей (корреляций) между двумя разными параметрами. Например, зависит ли вес человека от его роста? Каждая точка на графике — это один объект.

# Генерируем 50 случайных значений: рост (в районе 170) и вес (в районе 70)height = np.random.normal(170, 10, 50) weight = height * 0.4 + np.random.normal(0, 5, 50) # Вес немного зависит от ростаfig, ax = plt.subplots()ax.scatter(height, weight) # Строим точкиplt.show()

Если точки выстраиваются в четкую линию — связь есть. Если разбросаны как попало — параметры друг от друга не зависят.

3. Столбчатая диаграмма (ax.bar)

Зачем нужна: Для сравнения разных категорий. Кто продал больше айфонов, какой язык программирования популярнее и так далее. По оси X идут имена категорий, по оси Y — их значения.

categories = ['Янв', 'Фев', 'Мар', 'Апр']sales = [120, 90, 150, 200]fig, ax = plt.subplots()ax.bar(categories, sales) # Строим столбцыplt.show()

4. Гистограмма (ax.hist)

Зачем нужна: Чтобы посмотреть, как распределены данные внутри одного параметра. Важно: Новички часто путают bar и hist. Столбчатая диаграмма (bar) сравнивает разные категории. Гистограмма (hist) берет один набор чисел (например, возраст тысячи пользователей), разбивает его на корзины (от 10 до 20 лет, от 20 до 30 и т.д.) и показывает, сколько человек попало в каждую корзину.

# Генерируем возраст 1000 пользователей (в среднем 30 лет)ages = np.random.normal(30, 8, 1000)fig, ax = plt.subplots()# bins=20 означает, что мы разобьем все возраста на 20 "корзин"ax.hist(ages, bins=20) plt.show()

Отлично! Мы научились строить «скелеты» графиков. Но пока они выглядят так, будто их нарисовал робот из 90-х. В следующем разделе будем наводить красоту.

5. Наводим красоту: Кастомизация

Базовые графики — это отлично для быстрого анализа «на коленке». Но если вы принесете дефолтный синий график без подписей на презентацию, коллеги вас не поймут. Что это за цифры? К чему они относятся?

Давайте возьмем наш линейный график и превратим его во что-то осмысленное. Заодно построим сразу две линии, чтобы было что сравнивать.

В объектно-ориентированном подходе (через ax) большинство команд для добавления текста начинаются с приставки set_. Это важное отличие от устаревшего процедурного подхода, где писали просто plt.title().

# Данные для двух линийdays = np.arange(1, 8)expected = [20, 25, 30, 40, 50, 70, 90]actual = [20, 22, 28, 35, 45, 55, 100]# figsize задает размер холста в дюймах (ширина, высота)fig, ax = plt.subplots(figsize=(8, 5)) # 1. Настраиваем внешний вид линий и добавляем label для легендыax.plot(days, expected, color='gray', linestyle='--', linewidth=2, label='Ожидания')ax.plot(days, actual, color='crimson', marker='o', markersize=6, linewidth=2.5, label='Реальность')# 2. Добавляем заголовки и подписи осейax.set_title('Прогресс понимания Matplotlib по дням', fontsize=14, fontweight='bold')ax.set_xlabel('День недели', fontsize=12)ax.set_ylabel('Уровень просветления (%)', fontsize=12)# 3. Включаем сетку для удобства чтения# alpha делает сетку полупрозрачной, чтобы она не перетягивала вниманиеax.grid(True, linestyle=':', alpha=0.6)# 4. Выводим легенду (она автоматически подхватит аргументы label из ax.plot)ax.legend()plt.show()

Давайте разберем основные параметры, которые мы использовали внутри ax.plot():

  • color — цвет. Можно писать базовые названия ('red', 'green'), расширенные ('crimson', 'teal') или вообще HEX-коды ('#FF5733').

  • linewidth — толщина линии.

  • linestyle — стиль линии. Например, '--' для пунктира или ':' для точек.

  • marker — маркеры на пересечении данных. 'o' нарисует кружочки, '*' — звездочки, 's' — квадраты (от слова square).

Лайфхак: если вы вызвали ax.legend(), но легенда не появилась, проверьте, задали ли вы параметр label="..." при отрисовке самих графиков. Нет ярлыков — нет легенды!

6. Несколько графиков на одном холсте (Subplots)

Часто одного графика недостаточно. Представьте, что вам нужно сравнить динамику продаж, конверсию, распределение пользователей и еще что-нибудь, и всё это должно поместиться на одном экране или слайде. Строить четыре отдельных окна — плохая идея. Лучше разбить один большой холст на сетку из нескольких графиков.

Вспомните нашу главную команду: fig, ax = plt.subplots(). По умолчанию она создает сетку размером 1х1. Но если передать в нее количество строк и столбцов, мы получим матрицу графиков.

Давайте построим сетку 2х2 и выведем в ней все четыре типа графиков, которые мы изучили ранее:

# Создаем холст и сетку графиков 2х2# figsize=(10, 8) сделает холст побольше, чтобы графикам не было тесноfig, ax = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))# Генерируем немного простых данных для примеровx = np.arange(1, 6)y1 = [1, 4, 9, 16, 25]y2 = [2, 3, 5, 7, 11]# 1. Верхний левый график (строка 0, столбец 0)ax[0, 0].plot(x, y1, color='blue')ax[0, 0].set_title('Линейный график')# 2. Верхний правый график (строка 0, столбец 1)ax[0, 1].scatter(x, y2, color='red')ax[0, 1].set_title('Диаграмма рассеяния')# 3. Нижний левый график (строка 1, столбец 0)ax[1, 0].bar(x, y1, color='green')ax[1, 0].set_title('Столбчатая диаграмма')# 4. Нижний правый график (строка 1, столбец 1)ax[1, 1].hist(np.random.randn(100), bins=15, color='purple')ax[1, 1].set_title('Гистограмма')plt.tight_layout() plt.show()

Как работать с массивом ax? Когда вы создаете сетку больше чем 1х1, переменная ax перестает быть одним графиком и превращается в массив (список) графиков. Поскольку у нас сетка 2х2, это двумерный массив. Мы обращаемся к каждому конкретному квадратику по его индексам: ax[индекс_строки, индекс_столбца]. Помним, что в Python счет начинается с нуля, поэтому левый верхний угол — это [0, 0], а правый нижний — [1, 1].

Зачем нужен plt.tight_layout()? Это главный лайфхак, о котором новички узнают слишком поздно. Если вы закомментируете эту строчку и запустите код, то с вероятностью 99% увидите неприятную картину: заголовок нижнего графика налезет на ось X верхнего графика. Они буквально «слипнутся».

Команда plt.tight_layout() автоматически пересчитывает отступы между графиками так, чтобы никакие тексты, легенды и оси не перекрывали друг друга. Просто возьмите за правило всегда писать эту команду перед plt.show(), если у вас больше одного графика на холсте.

7. Сохранение результата

Итак, шедевр готов. Вы настроили цвета, подобрали идеальную толщину линий, и график выглядит великолепно. Теперь его нужно вставить в презентацию, отчет или отправить коллеге в мессенджер.

Делать скриншот экрана — это путь в никуда (особенно если вам нужно прозрачное окно или высокое разрешение). У нашего объекта fig (холста) есть специальный метод для сохранения картинки на диск.

# ... здесь был ваш код отрисовки графика ...# Сохраняем холст в файлfig.savefig('my_awesome_plot.png', dpi=300, bbox_inches='tight')plt.show()

Давайте разберем параметры:

  • 'my_awesome_plot.png' — имя файла. Matplotlib достаточно умен, чтобы понять по расширению, в каком формате сохранять. Можно написать .jpg, .pdf или даже .svg (для векторной графики).

  • dpi=300 — количество точек на дюйм (Dots Per Inch). 300 — это золотой стандарт для печати и четких презентаций. Без этого параметра картинка может получиться мыльной.

  • bbox_inches='tight' — еще один полезный бонус. Он гарантирует, что все подписи осей и заголовки, которые могли случайно вылезти за край холста, будут аккуратно вписаны в итоговую картинку.

Главная ловушка новичка: Синдром белого квадрата

Рано или поздно вы столкнетесь с ситуацией: вы пишете код, видите в Jupyter Notebook красивый график, открываете сохраненный PNG-файл, а там… просто абсолютно белый пустой квадрат.

Это происходит из-за одной классической ошибки — вызова сохранения после показа:

# КАК ДЕЛАТЬ НЕЛЬЗЯ:ax.plot([1, 2, 3], [4, 5, 2])plt.show() # Отрисовали и "сбросили" холстfig.savefig('plot.png') # Сохраняем пустоту! ❌

Почему так происходит? Когда вы вызываете plt.show(), Matplotlib рендерит ваш холст на экран, а затем неявно очищает текущую фигуру (чтобы освободить память для следующих графиков). К моменту, когда интерпретатор доходит до savefig, рисовать уже нечего — холст чист.

Запомните правило: Сначала сохраняем (fig.savefig), и только в самом конце показываем (plt.show()).

8. Заключение

Вот и всё! Мы проделали путь от пугающей документации до уверенной работы с базой Matplotlib. Давайте кратко подытожим, что мы сегодня узнали:

  • Поняли анатомию: разделили понятие холста (Figure) и самого рисунка (Axes).

  • Выяснили, почему объектно-ориентированный подход (fig, ax = plt.subplots()) — это лучший друг разработчика и аналитика.

  • Научились строить четыре базовых типа графиков: линии, точки, столбцы и гистограммы.

  • Посмотрели, как наводить красоту, настраивать цвета и аккуратно выводить графики сеткой.

  • Узнали, как правильно сохранять картинки на диск, навсегда забыв про ошибку «белого квадрата».

Куда двигаться дальше?

Matplotlib — это надежный, проверенный временем фундамент. Но в мире Python есть и другие инструменты, которые могут сильно упростить вам жизнь. Когда вы освоите базу, настоятельно рекомендую посмотреть в сторону этих двух библиотек:

  1. Seaborn. Это библиотека, которая написана поверх Matplotlib. Ее главная фишка — она делает всё красиво прямо «из коробки» и идеально подходит для сложного статистического анализа. Там, где в Matplotlib нужно написать цикл и десять строк кода, в Seaborn часто хватает одной изящной команды.

  2. Plotly. Если в какой-то момент вам станет мало статичных картинок и захочется интерактива (чтобы пользователь мог навести мышку на точку и увидеть цифры, приблизить нужный участок графика или скрыть лишние линии кликом по легенде) — смело берите Plotly. Это стандарт для современных дашбордов.

Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.

ссылка на оригинал статьи https://habr.com/ru/articles/1028868/