Перейти к содержанию

192 уроков, 14 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 2 из 10 Начальный 40 мин 100 XP

Линейные графики в Matplotlib: plot, цвета, стили и подписи

plt.plot() под микроскопом: цвета, маркеры, стили линий, легенды, диапазоны осей и кейс с двумя температурными кривыми за месяц.

Редакция Питоники

Синоптики дали прогноз на месяц: минимум и максимум на каждый день. Таблица из 60 чисел читается мучительно, а две линии на одном графике рассказывают всё за секунду: виден и разрыв между ночью и днём, и волны потеплений, и жара к концу месяца. Линейный график — рабочая лошадка аналитики: курсы валют, метрики продукта, температура, трафик. Сегодня разберём plt.plot() до винтика.

Как построить линейный график в Python: базовый plot

Одна линия — курс доллара за пять дней
import matplotlib.pyplot as plt

# Курс доллара за 5 дней, рублей
usd = [89.1, 90.3, 90.0, 91.2, 92.5]

plt.plot(usd)
plt.show()
Вывод
График отображается под редактором
Первый запуск загружает библиотеку — это займёт до минуты

Мы передали только один список — Matplotlib принял его за значения по оси Y, а по X проставил индексы: 0, 1, 2, 3, 4. Если нужен свой X — передайте два списка одинаковой длины: plt.plot(x, y).

Что происходит под капотом

plot() берёт пары точек и соединяет соседние отрезками. Никакого сглаживания: линия между двумя точками — всегда прямая. Хотите плавную кривую — давайте больше точек. Отсюда и правило: график из двух точек — это отрезок, а «красивый» график — это обычно много точек, а не особый параметр.

Вторая деталь: plot() возвращает список объектов Line2D, а не рисует сразу — отрисовка происходит в show(). Мы уже видели это в первом уроке по Matplotlib; сейчас важнее другое — один вызов plot() с одним набором данных даёт ровно одну линию.

Свой X: строки вместо чисел

Вдоль оси X не обязаны стоять числа — подойдут и строки, Matplotlib расставит их как категории. Так удобно подписывать дни, месяцы и каналы продаж:

Строки по оси X
import matplotlib.pyplot as plt

dates = ["01.07", "02.07", "03.07", "04.07", "05.07"]
usd = [89.1, 90.3, 90.0, 91.2, 92.5]

fig, ax = plt.subplots()
ax.plot(dates, usd, marker="o")
ax.set_title("Курс доллара, руб.")
ax.set_ylabel("Рублей за доллар")
plt.show()
Вывод
График отображается под редактором

Ловушка здесь одна: строки не знают, что они даты, — при пропуске дня график его просто не покажет, а интервал между делениями станет неравным. Для настоящих временных рядов даты держат в pandas как datetime — а данные из DataFrame превращаются в графики без пересыпания в списки: см. раздел Pandas самоучителя.

Цвет линии, маркеры и стиль: параметры plot

Всё оформление линии задаётся именованными параметрами. Вот те, что вы будете использовать каждый день:

ПараметрЧто задаётПримеры значений
colorЦвет линии"red", "#2E86AB", "tab:blue"
linestyleТип линии"-" сплошная, "--" пунктир, ":" точки, "-." штрих-точка
markerМаркер в точках данных"o" круг, "s" квадрат, "^" треугольник
linewidthТолщина линии в пунктах1 — тонкая, 2.5 — акцентная
markersizeРазмер маркера6 по умолчанию, 10 — крупный
alphaПрозрачность от 0 до 10.5 — полупрозрачная линия

Цвет задаётся тремя способами: именем ("tomato"), HEX-кодом ("#2E86AB") или короткой строкой "r", "g", "b", "k". HEX — самый гибкий вариант, если нужно попасть в фирменные цвета отчёта. Стили линий несут смысл: сплошная — факт, пунктир — прогноз. Готовые палитры и целостный стиль графика — в уроке про оформление графиков.

Две линии с разным оформлением
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]

fig, ax = plt.subplots()
ax.plot(x, [10, 12, 11, 15, 14], color="#2E86AB", linewidth=2.5, label="hex-цвет")
ax.plot(x, [8, 9, 12, 10, 13], color="tomato", linestyle="--", label="имя цвета")
ax.legend()
plt.show()
Вывод
График отображается под редактором

Здесь заодно показан приём, без которого многослойные графики теряют смысл: у каждой линии есть label, а plt.legend() собирает подписи в легенду. Задали label, но забыли legend — подписи молча не появятся.

Форматная строка: короткая запись

Третий позиционный аргумент plot — компактный код из трёх символов: цвет, маркер, стиль. "ro--" означает red, круг, пунктир. Удобно для быстрых набросков:

Форматные строки
import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 6, 5], "g^-")      # зелёные треугольники, сплошная линия
plt.plot([1, 2, 3], [2, 3, 4], "rs:")      # красные квадраты, точечная линия
plt.show()
Вывод
График отображается под редактором

Несколько линий на одном графике

Вызывайте plot() несколько раз подряд — все линии лягут на одни оси. Цвета Matplotlib раздаёт сам по циклу из десяти цветов: первая линия получит tab:blue, вторая tab:orange, третья tab:green и так далее. Это спасает при двух-трёх линиях, но при шести цветной спагетти-график никто читать не будет — линии нужно подписывать легендой и выделять главную.

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

Кейс: температура за месяц, минимум и максимум
import numpy as np
import matplotlib.pyplot as plt

# Синтетические температуры за июль
np.random.seed(42)
days = np.arange(1, 31)
t_max = 24 + 4 * np.sin(days / 4) + np.random.normal(0, 1, 30)
t_min = 13 + 3 * np.sin(days / 4) + np.random.normal(0, 1, 30)

fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(days, t_max, color="#D62728", label="Максимум днём")
ax.plot(days, t_min, color="#1F77B4", label="Минимум ночью")
ax.set_title("Температура в июле: минимум и максимум")
ax.set_xlabel("День месяца")
ax.set_ylabel("Температура, C")
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()
Вывод
График отображается под редактором

Что читается мгновенно. Разрыв между линиями — суточный разброс: около десяти градусов, сужается к середине месяца. Волна на обеих линиях — циклы потеплений. Линии не пересекаются: ночи не бывают теплее дней, и если бы пересеклись, это был бы сигнал ошибки в данных. Ради такой картины таблицу и не показывают.

Выделяем главную линию: скользящее среднее

Дневные данные всегда шумят: пятницы отрываются, праздники проваливаются. Тренд тонет в зигзагах. Классический приём — наложить на сырой ряд скользящее среднее: сырые данные серым и полупрозрачно, среднее — яркой толстой линией.

Шум и тренд на одном графике
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
sales = np.cumsum(np.random.normal(5, 20, 60)) + 500  # дневные продажи
window = 7
smooth = np.convolve(sales, np.ones(window) / window, mode="valid")

fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(sales, color="gray", alpha=0.5, label="По дням")
ax.plot(range(window - 1, 60), smooth, color="#D62728", linewidth=2.5,
        label="Среднее за 7 дней")
ax.set_title("Шум и тренд: скользящее среднее")
ax.set_xlabel("День")
ax.set_ylabel("Продажи, тыс. руб.")
ax.legend()
plt.show()
Вывод
График отображается под редактором

np.convolve со скользящим окном — минимальный способ посчитать среднее без pandas. Смысл приёма шире конкретной функции: главная линия — толстая и яркая, контекст — серый и прозрачный. Глаз сам решает, что важнее, без единого слова в легенде.

Прогноз пунктиром: linestyle как смысл

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

Факт и прогноз
import matplotlib.pyplot as plt

fact_x = [1, 2, 3]
fact_y = [120, 135, 128]
forecast_x = [3, 4, 5, 6]
forecast_y = [128, 133, 140, 149]

fig, ax = plt.subplots()
ax.plot(fact_x, fact_y, color="#2E86AB", linewidth=2.5, label="Факт")
ax.plot(forecast_x, forecast_y, color="#2E86AB", linestyle="--",
        marker="o", label="Прогноз")
ax.set_title("Выручка: факт и прогноз")
ax.set_xlabel("Месяц")
ax.set_ylabel("Тыс. руб.")
ax.legend()
plt.show()
Вывод
График отображается под редактором

Обратите внимание на точку стыка: факт и прогноз сходятся в месяце 3 — без этого разрыв между линиями выглядит как ошибка данных. Стили линий — не украшение, а система обозначений; договоритесь о ней один раз и держитесь во всём отчёте.

Подписи осей и заголовок: xlabel, ylabel, title

График без подписей — как график без данных: непонятно, что вообще изображено. Три метода закрывают вопрос: ax.set_title() для заголовка, ax.set_xlabel() и ax.set_ylabel() для осей (в pyplot-стиле — plt.title(), plt.xlabel(), plt.ylabel()). Единственный навык, который здесь нужен, — дисциплина: подписи пишем с единицами измерения.

Подписи с единицами измерения
import matplotlib.pyplot as plt

months = ["Март", "Апр", "Май", "Июн"]
sales = [120, 135, 128, 150]

fig, ax = plt.subplots()
ax.plot(months, sales, marker="o")
ax.set_title("Продажи по месяцам", fontsize=14, fontweight="bold")
ax.set_xlabel("Месяц")
ax.set_ylabel("Сумма, тыс. руб.")
plt.show()
Вывод
График отображается под редактором

У заголовка и подписей есть свои параметры: fontsize, fontweight, color, позиция loc. И ещё один редакторский приём, который отличает график «на показать» от графика «в отчёт»: заголовок должен нести вывод, а не описание. «Продажи выросли на 25% за квартал» работает лучше, чем «График продаж по кварталам» — читатель сразу понимает, зачем смотреть.

  • «График продаж» — пусто; «Продажи выросли на 25% за квартал» — вывод.
  • «Температура» — пусто; «Вторая половина июля теплее первой на 3 градуса» — вывод.
  • «Динамика курса» — пусто; «Курс доллара вырос на 3.4% за неделю» — вывод.

Наезжают подписи оси X: rotation

Длинные подписи категорий наезжают друг на друга, и ось превращается в кашу. Лечение — повернуть подписи: plt.xticks(rotation=45) наклоняет их на 45 градусов.

Поворот подписей оси X
import matplotlib.pyplot as plt

months = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь"]
sales = [120, 135, 128, 150, 141, 160]

fig, ax = plt.subplots()
ax.plot(months, sales, marker="o")
plt.xticks(rotation=45)                 # наклоняем подписи
ax.set_title("Продажи по месяцам, тыс. руб.")
ax.set_ylabel("Тыс. руб.")
plt.show()
Вывод
График отображается под редактором

Если и после поворота тесно — сокращайте подписи или переходите на горизонтальные столбцы barh: о них и о подписи значений на столбцах — в следующем уроке.

Диапазон осей: xlim, ylim и сетка

Matplotlib сам подбирает диапазон осей с небольшим запасом — и обычно это хорошо. Свой диапазон нужен в двух случаях: выровнять масштаб у нескольких графиков для честного сравнения или оставить воздух вокруг пиков. За границы отвечают ax.set_xlim() и ax.set_ylim():

Свой диапазон и сетка
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 40, 35, 42], marker="o")

ax.set_xlim(0, 5)          # ось X от 0 до 5
ax.set_ylim(0, 60)         # ось Y от 0 до 60 — виден уровень нуля
ax.grid(True, linestyle=":", alpha=0.6)
plt.show()
Вывод
График отображается под редактором

Сетка ax.grid(True) помогает глазу сверять значения с делениями; alpha=0.3–0.6 делает её ненавязчивой. В отчётах чаще всего включают сетку только по Y: ax.grid(True, axis="y") — горизонтальные направляющие читаются чище, чем клетка.

Частые ошибки и как их исправить

  • X и Y разной длины: plt.plot([1, 2, 3], [5, 6]) падает с ValueError: x and y must have same first dimension. Проверьте len(x) == len(y) — чаще всего лишний или потерянный элемент.
  • label задан, но plt.legend() не вызван — подписи линий не появятся. label работает только в паре с легендой.
  • Десять линий на одном холсте — «спагетти». Оставьте на графике одну-две главные линии, остальные унесите на отдельные панели — приём из урока про subplots и несколько графиков.
  • Подписи осей без единиц: «Выручка» вместо «Выручка, тыс. руб.» — читатель гадает, рубли это или миллионы.

Чек-лист: график готов к отправке?

Перед тем как вставлять линейный график в отчёт, прогоните его по короткому списку — он экономит больше времени, чем любая настройка из этого урока:

  1. Заголовок отвечает на вопрос читателя, а не описывает тип графика.
  2. Обе оси подписаны, у величин есть единицы измерения.
  3. У каждой линии есть подпись, легенда выведена и не закрывает данные.
  4. Цвета различимы и не спорят: главная линия акцентная, контекст приглушён.
  5. Диапазон осей осознанный: вы либо доверились автоматике, либо задали его сами.

Последний пункт самый коварный: автоматический диапазон удобен, но когда вы сравниваете два графика рядом, «автоматика» у каждого своя — и сравнение получается нечестным. Выравнивайте оси через set_xlim и set_ylim, как показано выше.

Что дальше

Вы умеете строить линии, красить их, ставить маркеры, подписывать оси, управлять диапазоном и собирать несколько серий на одних осях. В реальной работе данные не вписывают руками, а читают из файлов — связка read_csv и plot разобрана в гайде про график из CSV. Следующий урок — про сравнение категорий: столбчатые диаграммы plt.bar() и гистограммы plt.hist(). Продажи по регионам, план против факта, распределение цен — всё это там, в уроке про bar и hist. Весь курс — десять уроков, а маршрут целиком — самоучитель Matplotlib.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

import matplotlib.pyplot as plt

lines = plt.plot([1, 3, 5], [2, 2, 2], color="red")
print(len(lines))
import matplotlib.pyplot as plt

x = [1, 2, 3]
y = [10, 20]
plt.plot(x, y)
Проверь себя
0 / 5

1. Как сделать линию пунктирной?

2. Что означает форматная строка "ro--" в plt.plot(x, y, "ro--")?

3. Линиям задан label, но подписи в легенде не появились. В чём причина?

4. Какие цвета получат первые две линии, если не указывать color?

5. Что делает ax.grid(True, axis="y")?

Карточки терминов
Запомнено: 0 / 6
Практика

Даны цены на билеты за пять недель: эконом 4200, 4500, 4300, 4800, 5200; бизнес 9800, 10200, 9900, 11000, 12500 рублей. Постройте обе линии на одном графике: эконом — сплошная синяя линия с круглыми маркерами, бизнес — пунктирная красная линия. Добавьте легенду с подписями «Эконом» и «Бизнес», заголовок «Динамика цен на билеты», подписи осей и сетку.

practice.py
Вопросы и ответы по уроку

Как поменять цвет и стиль линии графика в Matplotlib?

Параметрами plt.plot(): color="red" или color="#2E86AB" для цвета, linestyle="--" для стиля. Есть короткая запись — форматная строка: "r--" означает красный пунктир.

Как подписать оси на графике Python?

ax.set_xlabel("...") и ax.set_ylabel("...") в объектном стиле, plt.xlabel() и plt.ylabel() в pyplot-стиле. В подписи стоит включать единицы измерения: «Выручка, тыс. руб.».

Как добавить легенду matplotlib?

Дайте каждой линии label="..." при вызове plot() и один раз вызовите plt.legend(). Позицию настраивает параметр loc, например loc="upper left".

Как сделать сетку на графике matplotlib?

ax.grid(True). Полезные параметры: linestyle=":" и alpha=0.4 для ненавязчивого вида, axis="y", чтобы сетка была только по значениям Y.

Как нарисовать несколько линий на одном графике matplotlib?

Вызовите plot() несколько раз подряд — все линии лягут на одни оси, цвета возьмутся из стандартного цикла (tab:blue, tab:orange и далее). Каждой линии дайте label и один раз вызовите plt.legend(). Отдельные панели под каждую серию — это уже subplots, тема урока про несколько графиков.

Понравился урок? Сошлитесь на него

«Стили линий — не украшение, а система обозначений; договоритесь о ней один раз и держитесь во всём отчёте.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.

Проверьте знания по Matplotlib / Seaborn

В челлендже — 20 задач по Matplotlib / Seaborn, по 2 из каждого урока этого раздела. Формат: фрагмент кода и четыре варианта — что напечатает. После ответа — вердикт и объяснение со ссылкой на урок-источник.

Тест по Matplotlib / Seaborn: 20 задач