Функция plot для построения и оформления двумерных графиков

Начнем изучение пакета matplotlib с наиболее часто используемой функции plot(). На предыдущем занятии мы с ее помощью построили простой двумерный график:

import matplotlib.pyplot as plt
 
plt.plot([1, 2, -6, 0, 4])
plt.show()

Также обратите внимание, что мы обращаемся к ветке matplotlib.pyplot для вызова этой функции. В целом, именно модуль pyplot отвечает за отображение разных графиков – это «рабочая лошадка» пакета matplotlib.

Давайте первым делом разберемся, что на вход принимает эта функция и что она, фактически, делает. В нашей программе мы передаем ей обычный список языка Python. В действительности же, все входные данные должны соответствовать массивам пакета numpy, то есть, иметь тип:

numpy.array

Поэтому, указанный список можно сначала преобразовать в массив numpy:

import numpy as np
 
y = np.array([1, 2, -6, 0, 4])

А, затем, передать его функции plot():

plt.plot(y)

Визуально, результат будет тем же. Вообще, почти все функции пакета matplotlib работают именно с массивами numpy: принимают их в качестве аргументов или возвращают. Поэтому при работе с matplotlib желательно знать основы numpy. Если у вас есть пробелы в этих знаниях, то смотрите плейлист по этой теме:

https://www.youtube.com/watch?v=eDuuKvIWzew&list=PLA0M1Bcd0w8zmegfAUfFMiACPKfdW4ifD

Итак, указывая всего один аргумент в функции plot() он интерпретируется как множество точек по ординате (координате Oy). Соответственно, координата x формируется автоматически как индексы элементов массива y:

Но мы можем значения по абсциссе указывать и самостоятельно, например, так:

x = np.array([4, 5, 6, 7, 8])
y = np.array([1, 2, -6, 0, 4])
plt.plot(x, y)

Теперь значения по оси Ox будут лежать в диапазоне от 4 до 8. Причем, функция plot() при отображении этих данных делает одну простую вещь – она соединяет прямыми линиями точки с указанными координатами:

 

Но это значит, если указать точки в узлах квадрата, то будет нарисован квадрат на плоскости? Давайте проверим. Запишем следующие координаты:

x = np.array([1, 1, 5, 5, 1])
y = np.array([1, 5, 5, 1, 1])
plt.plot(x, y)

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

y = np.arange(0, 5, 1)             # [0, 1, 2, 3, 4]
x = np.array([a*a for a in y])   # [ 0,  1,  4,  9, 16]
plt.plot(x, y)

В результате, мы увидим не прямую линию, а изогнутую:

Вот так гибко и интуитивно понятно обрабатывает функция plot() входные данные.

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

plt.grid()

Далее, если нам нужно в этих же осях отобразить еще один график, то это можно сделать так:

y = np.arange(0, 5, 1)
x = np.array([a*a for a in y])
y2 = [0, 1, 2, 3]
x2 = [i+1 for i in y2]
plt.plot(x, y, x2, y2)

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

Это потрясающая гибкость пакета matplotlib значительно облегчает жизнь инженерам-программистам. Здесь не надо задумываться о таких мелочах, как согласованность данных. Все будет показано так, как сформировано.

Соответственно, указывая следующие пары в функции plot(), будут отображаться все новые и новые графики в текущих координатах. Но можно сделать и по-другому. Вызвать функцию plot() несколько раз подряд, например:

plt.plot(x, y)
plt.plot(x2, y2)

Получим аналогичный эффект – два графика в одних координатах. Такая реализация возможна благодаря объектно-ориентированной архитектуре пакета matplotlib. Здесь координатные оси – это объект Axes. Соответственно, вызывая функцию plot() снова и снова, в этот объект помещают новые и новые данные для каждого отдельного графика:

Но откуда взялся объект Axes, если мы его нигде не создавали? Все просто. Он создается автоматически при первом вызове функции plot(), если ранее, до этого не было создано ни одного Axes. А раз создается система координат, то создается и объект Figure, на котором размещаются оси. Поэтому в нашей программе, при первом вызове функции plot() было создано два объекта:

  • Figure – объект для отображения всех данных, связанных с графиком;
  • Axes – двумерная координатная ось декартовой системы.

Позже мы увидим, как можно самостоятельно создавать эти объекты и использовать при оформлении графиков. А пока продолжим рассмотрение базовых возможностей функции plot().

Изменение стилей линий у графиков

Если третьим параметром в plot() указать строку с двумя дефисами:

plt.plot(x, y, '--')

то график будет изображен не сплошной линией, а штрихами. Какие еще варианты типа линий возможны? Они приведены в следующей таблице:

Обозначение типа линии

Описание

'-'

Непрерывная линия (используется по умолчанию)

'--'

Штриховая линия

'-.'

Штрихпунктирная линия

':'

Пунктирная линия

'None' или ' '

Без рисования линии

Например, для второго графика мы можем указать пунктирную линию:

plt.plot(x2, y2, ':')

Функция plot возвращает список на объекты Line2D. Если записать вызов в виде:

lines = plt.plot(x, y, '--')
print(lines)

то в консоли увидим список из одного объекта, так как функция отображает один график. Через этот объект можно непосредственно управлять графиком, например, поменять тип линии:

plt.setp(lines, linestyle='-.')

Здесь используется еще одна функция setp() для настройки свойств объектов, в данном случае линейного графика.

Если же мы отобразим два графика одной функцией plot():

lines = plt.plot(x, y, '--', x2, y2, ':')

то коллекция lines будет содержать два объекта Line2D. Далее, назначим им стиль:

plt.setp(lines, linestyle='-.')

Теперь они оба будут отображены штрихпунктирной линией.

Изменение цвета линий графиков

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

<p align=center>{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}

Цвет можно понять по английскому названию указанной первой буквы. Например,

b = blue, r = red, g = green, c = cyan, w = white, и т.д.

Давайте изменим цвет у наших графиков, указав символы g и m:

lines = plt.plot(x, y, '--g', x2, y2, ':m')

Как видите, все предельно просто. Или же можно использовать именованный параметр color (или просто букву c) для более точной настройки цвета:

lines = plt.plot(x, y, '--g', x2, y2, ':m', color='r')

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

lines = plt.plot(x, y, '--g', x2, y2, ':m', color='#0000CC')

Или в виде кортежей формата:

         RGB и RGBA

lines = plt.plot(x, y, '--g', x2, y2, ':m', color=(0, 0, 0))
lines = plt.plot(x, y, '--g', x2, y2, ':m', c=(0, 0, 0, 0.5))

В последней строчке использовано второе имя параметра color. Это основные способы задания цветов. Причем, не только для типов линий графиков, но и при работе с другими объектами пакета matplotlib. Так что эта информация в дальнейшем нам еще пригодится.

Изменение маркеров точек у графиков

Наконец, можно поменять тип маркеров у точек. Для этого в форматную строку достаточно прописать один из предопределенных символов. Например, вот такая запись:

plt.plot(x2, y2, ':o')

отображает график с круглыми точками:

Какие типы маркеров еще могут быть? Они перечислены в таблице ниже:

Обозначение

Описание маркера

'o'

'v'

'^'

'<'

'>'

'2'

'3'

'4'

's'

'p'

'*'

'h'

'H'

'+'

'x'

'D'

'd'

'|'

'_'

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

lines = plt.plot(x, y, '-go', x2, y2, 's:m')

отобразится следующий график:

Другой способ определения маркера – использование параметра marker:

lines = plt.plot(x, y, '-go', x2, y2, 's:m', marker='d')

В этом случае для обоих графиков будет присвоен один и тот же маркер типа 'd'. Для задания цвета маркера, отличного от цвета линии, применяется параметр markerfacecolor:

lines = plt.plot(x, y, '-go', x2, y2, 's:m', marker='d', markerfacecolor='w')

Здесь мы выбрали белый цвет заливки и графики теперь выглядят так:

Именованные параметры функций setp() и plot()

Все эти же действия по оформлению графика можно выполнять и с помощью функции setp(). Например, записав следующую строчку:

plt.setp(lines[0], linestyle='-.', marker='s', markerfacecolor='b', linewidth=4)

получим отображение графика штрихпунктирной линией, квадратным маркером с синей заливкой и толщиной линии, равной 4 пиксела. Какие еще именованные параметры есть у функций setp() и plot()? В таблице ниже я привел основные из них:

Параметр

Описание

alpha

Степень прозрачности графика (значение от 0 до 1)

color или c

Цвет линии

dash_capstyle

Стиль штриховых конечных точек ['butt' | 'round' | 'projecting']

dash_joinstyle

Стиль штриховых соединительных точек ['miter' | 'round' | 'bevel']

data

Данные графика в формате (x, y), где x, y – массивы numpy

linestyle или ls

Стиль линии [ '-' | '--' | '-.' | ':' | 'steps' | ...]

linewidth или lw

Толщина линии (вещественное число)

marker

Маркер точек

markeredgecolor или mec

Цвет границ маркеров

markeredgewidth или

mew

Толщина границы маркеров (вещественное число)

markerfacecolor или mfc

Цвет заливки маркеров

markersize или ms

Размер маркеров

solid_capstyle

Стиль конечных точек непрерывной линии ['butt' | 'round' | 'projecting']

solid_joinstyle

Стиль соединительных точек непрерывной линии ['miter' | 'round' | 'bevel']

visible

Показать/скрыть график [True | False]

xdata

Значения для оси абсцисс (массив numpy)

ydata

Значения для оси ординат (массив numpy)

Более подробную информацию о параметрах для оформления графиков смотрите в документации по matplotlib.

Заливка областей графика

Наконец, можно делать заливку областей графика с помощью функции:

fill_between(x,  y1,  y2=0,  where=None,  interpolate=False,  step=None,  *, data=None, **kwargs)

Основные параметры здесь следующие:

  • x, y1 – массивы значений координат x и функции y1;
  • y2 – массив (или число) для второй кривой, до которой производится заливка;
  • where – массив булевых элементов, который определяет области для заливки.

В самом простом случае эту функцию можно использовать так:

x = np.arange(-2*np.pi, 2*np.pi, 0.1)
y = np.cos(x)
plt.plot(x, y)
plt.fill_between(x, y)
plt.show()

У нас получилась косинусоида с заливкой между значениями функции y и осью абсцисс y2 = 0. Если третьим параметром указать другое число, отличное от нуля, например, 0,5:

plt.fill_between(x, y, 0.5)

то получим следующий эффект:

А если дополнительно еще сделать ограничение на выбор заливаемого региона, когда y < 0:

plt.fill_between(x, y, 0.5, where=(y < 0))

то получим такую картину:

Также можно вызвать эту функцию два раза подряд:

plt.fill_between(x, y, where=(y < 0), color='r', alpha=0.5)
plt.fill_between(x, y, where=(y > 0), color='g', alpha=0.5)

и сформировать следующее оформление графика косинусоиды:

Вот так можно с помощью функции plot() отображать графики в координатных осях и делать их простое оформление.