Использование библиотеки Matplotlib. Как рисовать стрелки на графиках и добавлять аннотации
Иногда на графиках нужно нарисовать указатель на какую-то особую точку, на которую стоит обратить внимание, или указательные линии с номерами кривых могут служить заменой легенды. Для того, чтобы рисовать такие стрелки и линии, предназначена функция annotate(). Кроме того, эту функцию можно использовать для отображения векторов на плоскости.
Функция annotate() может принимать большое количество параметров, отвечающих за внешний вид стрелок и отображаемого текста. Строго говоря, обязательными являются только два параметра:
- s - строка, содержащая выводимый текст;
- xy - кортеж из двух элементов, задающие координаты точки, на которую нужно указать. По умолчанию координаты точек задаются в системе координат графика, но это поведение можно менять с помощью параметра xycoords, который в данной статье не рассматривается.
Однако, если мы ограничимся только этими параметрами, то функция annotate() выведет только текст около указанной точки:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
# Интервал изменения и шаг переменной по оси X
xmin = -10.0
xmax = 10.0
count = 300
# Создадим список координат по осям X и Y на отрезке [xmin; xmax], включая концы
x = np.linspace(xmin, xmax, count)
y = np.sinc(x)
# Координаты точки, куда будет указывать стрелка
selected_x = 2.5
selected_y = np.sinc(selected_x)
# Нарисуем график
plt.plot(x, y)
# !!! Добавление аннотации
plt.annotate('Очень важная точка', xy=(selected_x, selected_y))
# Покажем окно с нарисованным графиком
plt.show()
Результат будет напоминать работу функции text:
Чтобы аннотация выглядела более интересно, добавим два именованных параметра:
- xytext - кортеж из двух элементов, который задает координаты текста; из этой же точки будет начинаться стрелка указателя;
- arrowprops - словарь, который содержит элементы, задающие внешний вид стрелки.
Чуть позже мы подробнее рассмотрим возможные значения в словаре arrowprops, а пока сделаем так, чтобы у нас отображалась обычная стрелка:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
# Интервал изменения и шаг переменной по оси X
xmin = -10.0
xmax = 10.0
count = 300
# Создадим список координат по осям X и Y на отрезке [xmin; xmax], включая концы
x = np.linspace(xmin, xmax, count)
y = np.sinc(x)
# Координаты точки, куда будет указывать стрелка
selected_x = 2.5
selected_y = np.sinc(selected_x)
# Нарисуем график
plt.plot(x, y)
# !!! Добавление аннотации
# !!! Словарь задает внешний вид стрелки
arrowprops = {
'arrowstyle': '->',
}
# !!! Добавление аннотации
plt.annotate('Очень важная точка',
xy=(selected_x, selected_y),
xytext=(selected_x + 1.5, selected_y + 0.2),
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.show()
Теперь окно с графиком будет выглядеть следующим образом:
С помощью элементов словаря arrowprops мы можем передавать множество настроек в класс FancyArrowPatch, который используется для отображения стрелок. Коротко рассмотрим только некоторые из них:
- arrowstyle - задает стиль стрелок (список возможных значений будет приведен ниже).
- connectionstyle - задает способ проведения линии указателя, будет она соединять две точки по прямой, по дуге или нужно, чтобы стрелки состояли из ломанных отрезков, расположенных параллельно координатным осям. С помощью этого параметра можно задавать и другие настройки линии.
- linewidth - задает толщину линии.
- linestyle - задает стиль линии. Возможные значения - 'solid', 'dashed', 'dashdot', '‘dotted'.
- mutation_scale - задает размер "головы" стрелки на конце.
- color - задает цвет указателя.
- alpha - задает степень прозрачности. 0 - полностью прозрачный, 1 - полностью непрозрачный.
Если словарь arrowprops не содержит ключ "arrowstyle", то для отображения стрелки будут использоваться следующие ключи в словаре arrowprops:
- width - задает ширину линии указателя.
- shrink - коэффициент, показывающий, какую часть длины указателя будет занимать "голова" стрелки. Например, если shrink = 0.5, то стрелка будет занимать половину длины указателя.
- headwidth - задает ширину "головы" стрелки.
- headlength - задает длину "головы" стрелки.
Если используется параметр arrowstyle, то он может быть также экземпляром класса ArrowStyle, который позволяет очень гибко настраивать внешний вид стрелок, а может быть строкой, описывающей уже предустановленные стили стрелок. В качестве строки arrowstyle может принимать следующие значения:
'-' |
'->' |
'-[' |
'-|>' |
'<-' |
'<->' |
'<|-' |
'-' |
']-' |
']-[' |
'fancy' |
'simple' |
'wedge' |
'|-|' |
Чтобы продемонстрировать, как выглядят эти стили, был написан следующий скрипт:
import matplotlib.pyplot as plt
if __name__ == '__main__':
plt.xlim([-10, 50])
plt.ylim([-180, 20])
arrowstyles = ['-', '->', '-[', '-|>',
'<-', '<->', '<|-', '<|-|>',
']-', ']-[', 'fancy', 'simple',
'wedge', '|-|']
shift_x = 2
shift_y = -12
dx = 10
dy = 10
for n, arrowstyle in enumerate(arrowstyles):
# !!! Словарь задает внешний вид стрелки
arrowprops = {
'arrowstyle': arrowstyle,
}
x = n * shift_x
y = n * shift_y
# !!! Добавление аннотации
plt.annotate('arrowstyle: ' + arrowstyle,
xy=(x, y),
xytext=(x + dx, y + dy),
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.show()
С помощью него была получена следующая картинка:
Кроме того, мы можем влиять на то, каким образом будет проводиться линия от начальной точки до конечной: будет это прямая линия, ломаная или закругленная. На это влияет параметр connectionstyle, который может быть экземпляром класса ConnectionStyle для очень точной настройки внешнего вида, а может быть одной из строк (пример в документации), с помощью которых можно задать один из предустановленных внешних видов указателей. Вот эти возможные строки:
'angle' |
'angle3' |
'arc' |
'arc3' |
'bar' |
Цифра "3" в конце некоторых стилей обозначают, что для проведения линии используется квадратичный сплайн, то есть линия проводится через три точки. Чтобы продемонстрировать эти стили, был написан следующий скрипт:
import matplotlib.pyplot as plt
if __name__ == '__main__':
plt.xlim([-10, 50])
plt.ylim([-190, 40])
connectionstyle = ['angle', 'angle3', 'arc', 'arc3', 'bar']
shift_x = 2
shift_y = -45
dx = 10
dy = 20
for n, style in enumerate(connectionstyle):
# !!! Словарь задает внешний вид стрелки
arrowprops = {
'arrowstyle': '->',
'connectionstyle': style,
}
x = n * shift_x
y = n * shift_y
# !!! Добавление аннотации
plt.annotate('connectionstyle: ' + style,
xy=(x, y),
xytext=(x + dx, y + dy),
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.show()
Результат его работы выглядит следующим образом:
В этом примере стили arc и arc3 не отличаются, потому что мы не воспользовались дополнительными параметрами для каждого стиля. Дополнительные параметры задаются через запятую после имени стиля, причем у каждого стиля свой набор параметров. Ниже приведена таблица с параметрами по умолчанию, взятая из документации]. Там же видно, какие параметры существуют для каждого стиля.
'angle' | angleA=90,angleB=0,rad=0.0 |
'angle3' | angleA=90,angleB=0 |
'arc' | angleA=0,angleB=0,armA=None,armB=None,rad=0.0 |
'arc3' | rad=0.0 |
'bar' | armA=0.0,armB=0.0,fraction=0.3,angle=None |
Для демонстрации того, как задаются параметры стилей, изменим предыдущий пример:
import matplotlib.pyplot as plt
if __name__ == '__main__':
plt.figure(figsize=(8, 6))
plt.xlim([-10, 50])
plt.ylim([-190, 40])
connectionstyle = ['angle,angleA=0,angleB=45',
'angle3,angleA=45,angleB=0',
'arc,angleA=-90,armA=30,armB=80',
'arc3,rad=0.5',
'bar,armA=15,fraction=0.1']
shift_x = 2
shift_y = -45
dx = 10
dy = 20
for n, style in enumerate(connectionstyle):
# !!! Словарь задает внешний вид стрелки
arrowprops = {
'arrowstyle': '->',
'connectionstyle': style,
}
x = n * shift_x
y = n * shift_y
# !!! Добавление аннотации
plt.annotate('connectionstyle: ' + style,
xy=(x, y),
xytext=(x + dx, y + dy),
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.show()
Не будем приводить здесь описание каждого параметра, потому что проще всего их "пощупать" самим, чтобы понять, что они делают. Результат данного скрипта выглядит следующим образом:
Функцию annotate можно использовать для отображения векторов на плоскости, для этого достаточно в качестве первого параметра передать пустую строку.
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
plt.xlim([-1, 10])
plt.ylim([-1, 10])
a = np.array([1, 3])
b = np.array([5, 2])
c = a + b
arrowprops = {
'arrowstyle': '<|-',
}
# !!! Добавление аннотации
plt.annotate('',
xy=(0, 0),
xytext=a,
arrowprops=arrowprops)
plt.annotate('',
xy=(0, 0),
xytext=b,
arrowprops=arrowprops)
plt.annotate('',
xy=(0, 0),
xytext=c,
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.grid()
plt.show()
С другой стороны, можно воспользоваться тем фактом, что в строке (в первом параметре) может использоваться нотация LaTeX, и мы можем отображать названия векторов.
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
plt.xlim([-1, 10])
plt.ylim([-1, 10])
a = np.array([1, 3])
b = np.array([5, 2])
c = a + b
arrowprops = {
'arrowstyle': '<|-',
}
# !!! Добавление аннотации
plt.annotate(r'$\vec a$',
xy=(0, 0),
xytext=a,
arrowprops=arrowprops)
plt.annotate(r'$\vec b$',
xy=(0, 0),
xytext=b,
arrowprops=arrowprops)
plt.annotate(r'$\vec c = \vec a + \vec b$',
xy=(0, 0),
xytext=c,
arrowprops=arrowprops)
# Покажем окно с нарисованным графиком
plt.grid()
plt.show()
В этой статье были рассмотрены основные параметры, влияющие на внешний вид указателей, отображаемых с помощью функции annotate(). Какие-то параметры не попали в статью, но они все описаны в документации, хоть и разбросаны по разным разделам.
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.