Функция plot для построения и оформления двумерных графиков
Начнем изучение пакета matplotlib с наиболее часто используемой функции plot(). На предыдущем занятии мы с ее помощью построили простой двумерный график:
import matplotlib.pyplot as plt plt.plot([1, 2, -6, 0, 4]) plt.show()
Также обратите внимание, что мы обращаемся к ветке matplotlib.pyplot для вызова этой функции. В целом, именно модуль pyplot отвечает за отображение разных графиков – это «рабочая лошадка» пакета matplotlib.
Давайте первым делом разберемся, что на вход принимает эта функция и что она, фактически, делает. В нашей программе мы передаем ей обычный список языка Python. В действительности же, все входные данные должны соответствовать массивам пакета numpy, то есть, иметь тип:
Поэтому, указанный список можно сначала преобразовать в массив numpy:
import numpy as np y = np.array([1, 2, -6, 0, 4])
А, затем, передать его функции plot():
Визуально, результат будет тем же. Вообще, почти все функции пакета matplotlib работают именно с массивами numpy: принимают их в качестве аргументов или возвращают. Поэтому при работе с matplotlib желательно знать основы numpy. Если у вас есть пробелы в этих знаниях, то смотрите плейлист по этой теме:
Итак, указывая всего один аргумент в функции 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() входные данные.
Давайте сразу на график наложим сетку, чтобы он выглядел более информативно. Для этого достаточно прописать строчку:
Далее, если нам нужно в этих же осях отобразить еще один график, то это можно сделать так:
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() несколько раз подряд, например:
Получим аналогичный эффект – два графика в одних координатах. Такая реализация возможна благодаря объектно-ориентированной архитектуре пакета matplotlib. Здесь координатные оси – это объект Axes. Соответственно, вызывая функцию plot() снова и снова, в этот объект помещают новые и новые данные для каждого отдельного графика:
- Figure – объект для отображения всех данных, связанных с графиком;
- Axes – двумерная координатная ось декартовой системы.
Изменение стилей линий у графиков
то график будет изображен не сплошной линией, а штрихами. Какие еще варианты типа линий возможны? Они приведены в следующей таблице:
Обозначение типа линии | Описание |
‘-‘ | Непрерывная линия (используется по умолчанию) |
‘—‘ | Штриховая линия |
‘-.’ | Штрихпунктирная линия |
‘:’ | Пунктирная линия |
‘None’ или ‘ ‘ | Без рисования линии |
Например, для второго графика мы можем указать пунктирную линию:
lines = plt.plot(x, y, '--') print(lines)
то в консоли увидим список из одного объекта, так как функция отображает один график. Через этот объект можно непосредственно управлять графиком, например, поменять тип линии:
Здесь используется еще одна функция setp() для настройки свойств объектов, в данном случае линейного графика. Если же мы отобразим два графика одной функцией plot():
Изменение цвета линий графиков
Помимо типа линий у графиков, конечно же, можно менять и их цвет. В самом простом варианте достаточно после стиля указать один из символов предопределенных цветов:
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')
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. Так что эта информация в дальнейшем нам еще пригодится.
Изменение маркеров точек у графиков
Наконец, можно поменять тип маркеров у точек. Для этого в форматную строку достаточно прописать один из предопределенных символов. Например, вот такая запись:
отображает график с круглыми точками: Какие типы маркеров еще могут быть? Они перечислены в таблице ниже:
Обозначение | Описание маркера |
‘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.
Заливка областей графика
- 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:
то получим следующий эффект: А если дополнительно еще сделать ограничение на выбор заливаемого региона, когда 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() отображать графики в координатных осях и делать их простое оформление.
Linestyles#
Simple linestyles can be defined using the strings «solid», «dotted», «dashed» or «dashdot». More refined control can be achieved by providing a dash tuple (offset, (on_off_seq)) . For example, (0, (3, 10, 1, 15)) means (3pt line, 10pt space, 1pt line, 15pt space) with no offset, while (5, (10, 3)) , means (10pt line, 3pt space), but skip the first 5pt line. See also Line2D.set_linestyle .
Note: The dash style can also be configured via Line2D.set_dashes as shown in Customizing dashed line styles and passing a list of dash sequences using the keyword dashes to the cycler in property_cycle .
import numpy as np import matplotlib.pyplot as plt linestyle_str = [ ('solid', 'solid'), # Same as (0, ()) or '-' ('dotted', 'dotted'), # Same as (0, (1, 1)) or ':' ('dashed', 'dashed'), # Same as '--' ('dashdot', 'dashdot')] # Same as '-.' linestyle_tuple = [ ('loosely dotted', (0, (1, 10))), ('dotted', (0, (1, 1))), ('densely dotted', (0, (1, 1))), ('long dash with offset', (5, (10, 3))), ('loosely dashed', (0, (5, 10))), ('dashed', (0, (5, 5))), ('densely dashed', (0, (5, 1))), ('loosely dashdotted', (0, (3, 10, 1, 10))), ('dashdotted', (0, (3, 5, 1, 5))), ('densely dashdotted', (0, (3, 1, 1, 1))), ('dashdotdotted', (0, (3, 5, 1, 5, 1, 5))), ('loosely dashdotdotted', (0, (3, 10, 1, 10, 1, 10))), ('densely dashdotdotted', (0, (3, 1, 1, 1, 1, 1)))] def plot_linestyles(ax, linestyles, title): X, Y = np.linspace(0, 100, 10), np.zeros(10) yticklabels = [] for i, (name, linestyle) in enumerate(linestyles): ax.plot(X, Y+i, linestyle=linestyle, linewidth=1.5, color='black') yticklabels.append(name) ax.set_title(title) ax.set(ylim=(-0.5, len(linestyles)-0.5), yticks=np.arange(len(linestyles)), yticklabels=yticklabels) ax.tick_params(left=False, bottom=False, labelbottom=False) ax.spines[:].set_visible(False) # For each line style, add a text annotation with a small offset from # the reference point (0 in Axes coords, y tick value in Data coords). for i, (name, linestyle) in enumerate(linestyles): ax.annotate(repr(linestyle), xy=(0.0, i), xycoords=ax.get_yaxis_transform(), xytext=(-6, -12), textcoords='offset points', color="blue", fontsize=8, ha="right", family="monospace") fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(10, 8), height_ratios=[1, 3]) plot_linestyles(ax0, linestyle_str[::-1], title='Named linestyles') plot_linestyles(ax1, linestyle_tuple[::-1], title='Parametrized linestyles') plt.tight_layout() plt.show()