Использование библиотеки Matplotlib. Как рисовать стрелки на графиках и добавлять аннотации | jenyay.net

Использование библиотеки Matplotlib. Как рисовать стрелки на графиках и добавлять аннотации

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

Функция annotate() может принимать большое количество параметров, отвечающих за внешний вид стрелок и отображаемого текста. Строго говоря, обязательными являются только два параметра:

  • s - строка, содержащая выводимый текст;
  • xy - кортеж из двух элементов, задающие координаты точки, на которую нужно указать. По умолчанию координаты точек задаются в системе координат графика, но это поведение можно менять с помощью параметра xycoords, который в данной статье не рассматривается.

Однако, если мы ограничимся только этими параметрами, то функция annotate() выведет только текст около указанной точки:

# -*- coding: utf-8 -*-

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, а пока сделаем так, чтобы у нас отображалась обычная стрелка:

# -*- coding: utf-8 -*-

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'
'|-|'

Чтобы продемонстрировать, как выглядят эти стили, был написан следующий скрипт:

# -*- coding: utf-8 -*-

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" в конце некоторых стилей обозначают, что для проведения линии используется квадратичный сплайн, то есть линия проводится через три точки. Чтобы продемонстрировать эти стили, был написан следующий скрипт:

# -*- coding: utf-8 -*-

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

Для демонстрации того, как задаются параметры стилей, изменим предыдущий пример:

# -*- coding: utf-8 -*-

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 можно использовать для отображения векторов на плоскости, для этого достаточно в качестве первого параметра передать пустую строку.

# -*- coding: utf-8 -*-

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, и мы можем отображать названия векторов.

# -*- coding: utf-8 -*-

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(). Какие-то параметры не попали в статью, но они все описаны в документации, хоть и разбросаны по разным разделам.

Другие статьи про Matplotlib

Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.
5 stars

Рейтинг 4.8/5. Всего 12 голос(а, ов)




Подписаться на комментарии
Автор:
Тема:
 Ваш комментарий
 
 
Введите код 241