Использование библиотеки Matplotlib. Как менять положение легенды

Введение

В статье Как отобразить легенду было перечислено несколько способов создания легенды для графиков (под легендой понимается прямоугольная область на графике, в которой показывается, какая линия чему соответствует). Напомню, что для создания описания линий, мы можем использовать параметр label функции plot() из модуля matplotlib.pyplot, добавляя таким образом описание для каждой линии, а можем передать список строк с описаниями в функцию legend() из того же модуля. В выше упоминаемой статье были перечислены и другие способы создания легенды. На мой взгляд предпочтительней использовать первый вариант, чтобы оформление линий и их названия устанавливались в одном месте, ведь вызов legend() может быть далеко в коде от вызова plot().

В этой статье мы рассмотрим способы изменения положения легенды в окне.

Сначала приведем пример отображения легенды, который будем в дальнейшем модифицировать.

  1. # coding: utf-8
  2.  
  3. # Импортируем один из пакетов Matplotlib
  4. import matplotlib.pyplot as plt
  5.  
  6. import numpy as np
  7.  
  8.  
  9. if __name__ == '__main__':
  10.     # Интервал изменения переменной по оси X
  11.     xmin = -30.0
  12.     xmax = 10.0
  13.  
  14.     # Шаг между точками
  15.     dx = 0.1
  16.  
  17.     # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
  18.     x = np.arange(xmin, xmax + dx, dx)
  19.  
  20.     # Вычислим значение функции в заданных точках
  21.     y1 = np.sinc(x)
  22.     y2 = np.sinc(x * 0.2)
  23.  
  24.     # Нарисуем два одномерных графика
  25.     # !!! Метки сразу привязываем к соответствующей кривой графика
  26.     plt.plot(x, y1, 'b-', label='f(x)')
  27.     plt.plot(x, y2, 'g--', label='f(x * 0.2)')
  28.  
  29.     # !!! Добавим легенду
  30.     plt.legend(title='f(x) = sinc(x)')
  31.  
  32.     # Покажем окно с нарисованным графиком
  33.     plt.show()

В результате будет показано следующее окно:

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

Положение легенды

Хотя по умолчанию Matplotlib перемещает легенду таким образом, чтобы она не закрывала собой кривые на графике, для наших задач может понадобиться принудительно поместить легенду в какое-нибудь другое место. Для того, чтобы поменять положение легенды, в функцию legend() нужно передать именованный параметр loc, который может быть разных типов:

  1. Строкой.
  2. Целочисленным значением.
  3. Кортежем из двух значений, задающих координаты легенды.

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

'best'0
'upper right'1
'upper left'2
'lower left'3
'lower right'4
'right'5
'center left'6
'center right'7
'lower center'8
'upper center'9
'center'10

Думаю, что значения строковых констант говорят сами за себя относительно того, где будет располагаться легенда. По умолчанию значение параметра loc равно 'best', хотя значение по умолчанию можно менять через rcParams. Изменим предыдущий код таким образом, чтобы легенда оказалась сверху по центру:

  1. # coding: utf-8
  2.  
  3. # Импортируем один из пакетов Matplotlib
  4. import matplotlib.pyplot as plt
  5.  
  6. import numpy as np
  7.  
  8.  
  9. if __name__ == '__main__':
  10.     # Интервал изменения переменной по оси X
  11.     xmin = -30.0
  12.     xmax = 10.0
  13.  
  14.     # Шаг между точками
  15.     dx = 0.1
  16.  
  17.     # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
  18.     x = np.arange(xmin, xmax + dx, dx)
  19.  
  20.     # Вычислим значение функции в заданных точках
  21.     y1 = np.sinc(x)
  22.     y2 = np.sinc(x * 0.2)
  23.  
  24.     # Нарисуем два одномерных графика
  25.     # !!! Метки сразу привязываем к соответствующей кривой графика
  26.     plt.plot(x, y1, 'b-', label='f(x)')
  27.     plt.plot(x, y2, 'g--', label='f(x * 0.2)')
  28.  
  29.     # !!! Добавим легенду
  30.     plt.legend(title='f(x) = sinc(x)', loc='upper center')
  31.  
  32.     # Покажем окно с нарисованным графиком
  33.     plt.show()

Легенда переместилась:

Аналогичного результата мы достигнем, если заменим строку plt.legend(title='f(x) = sinc(x)', loc='upper center') на plt.legend(title='f(x) = sinc(x)', loc=9)

Точное указание координат легенды

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

Координаты мы тоже можем указать, если передадим их в виде кортежа двух чисел в качестве значения того же параметра loc. Координаты являются нормированными, т.е. точка (0.0, 0.0) соответствует левому нижнему углу графика (не окна, а той области, где отображается сам график), а точка (1.0, 1.0) - правому верхнему углу. Если в качестве значения параметра loc передается кортеж, то это означает, что в указанные нормированные координаты будет помещен левый нижний угол легенды. В принципе, легенда может вылезать за пределы графика.

Исправим 33-ю строку предыдущего исходника на следующую (остальной код остается без изменений):

        plt.legend(title='f(x) = sinc(x)', loc=(0.0, 0.0))

Легенда переместилась в соответствующее положение:

Или переместим легенду в правый верхний угол (я долго "прицеливался", чтобы попасть в нужные координаты):

        plt.legend(title='f(x) = sinc(x)', loc=(0.772, 0.815))

Зазор между осями и легендой

Вы, наверное, обратили внимание, что когда мы устанавливаем положение легенды с помощью параметра loc, в случае, когда он принимает строковые или целочисленные значения, между легендой и осями графика остается зазор. Его величина настраивается с помощью параметра borderaxespad. Например, следующий код не только устанавливает легенду в правый верхний угол, но и совмещает границы легенды с границами графика, передавая в качестве значения borderaxespad значение 0. Эта величина задается в неких условных единицах, а точнее в единицах, в которых задаются размеры шрифтов. Таким образом, предыдущий пример с совмещением легенды и угла графика можно сделать более простым и надежным способом:

  1. # coding: utf-8
  2.  
  3. # Импортируем один из пакетов Matplotlib
  4. import matplotlib.pyplot as plt
  5.  
  6. import numpy as np
  7.  
  8.  
  9. if __name__ == '__main__':
  10.     # Интервал изменения переменной по оси X
  11.     xmin = -30.0
  12.     xmax = 10.0
  13.  
  14.     # Шаг между точками
  15.     dx = 0.1
  16.  
  17.     # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
  18.     x = np.arange(xmin, xmax + dx, dx)
  19.  
  20.     # Вычислим значение функции в заданных точках
  21.     y1 = np.sinc(x)
  22.     y2 = np.sinc(x * 0.2)
  23.  
  24.     # Нарисуем два одномерных графика
  25.     # !!! Метки сразу привязываем к соответствующей кривой графика
  26.     plt.plot(x, y1, 'b-', label='f(x)')
  27.     plt.plot(x, y2, 'g--', label='f(x * 0.2)')
  28.  
  29.     # !!! Добавим легенду
  30.     plt.legend(title='f(x) = sinc(x)', loc='upper right', borderaxespad=0)
  31.  
  32.     # Покажем окно с нарисованным графиком
  33.     plt.show()

Результат выглядит следующим образом:

Функция legend() может принимать несколько похожих параметров, которые регулируют различные отступы. В частности:

  • borderpad - внутренний зазор между рамкой и строками легенды.
  • labelspacing - вертикальный зазор между строками легенды.
  • handletextpad - горизонтальное расстояние между линией и текстом в легенде.
  • columnspacing - расстояние между столбцами, если элементы легенды размещаются в несколько столбцов. Об этом см. далее.

"Широкая" легенда

В функцию legend() можно передать также параметр mode, который может принимать значение либо None - это значение по умолчанию, либо строку 'expand' - это будет означать, что легенду надо расширить на всю ширину графика. Скорее всего это будет полезно в том случае, если у вас легенда будет располагаться либо за пределами графика, либо в легенде будут описываться несколько кривых, причем они будут располагаться в строку (благодаря использованию параметра ncol). Это показано в следующем примере:

  1. # coding: utf-8
  2.  
  3. # Импортируем один из пакетов Matplotlib
  4. import matplotlib.pyplot as plt
  5.  
  6. import numpy as np
  7.  
  8.  
  9. if __name__ == '__main__':
  10.     # Интервал изменения переменной по оси X
  11.     xmin = -30.0
  12.     xmax = 10.0
  13.  
  14.     # Шаг между точками
  15.     dx = 0.1
  16.  
  17.     # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
  18.     x = np.arange(xmin, xmax + dx, dx)
  19.  
  20.     # Вычислим значение функции в заданных точках
  21.     y1 = np.sinc(x)
  22.     y2 = np.sinc(x * 0.2)
  23.     y3 = np.sinc(x * 0.1)
  24.  
  25.     # Нарисуем два одномерных графика
  26.     # !!! Метки сразу привязываем к соответствующей кривой графика
  27.     plt.plot(x, y1, 'b-', label='f(x)')
  28.     plt.plot(x, y2, 'g--', label='f(x * 0.2)')
  29.     plt.plot(x, y3, 'r-', label='f(x * 0.1)')
  30.  
  31.     # !!! Добавим легенду
  32.     plt.legend(title='f(x) = sinc(x)',
  33.                loc='upper center',
  34.                mode='expand',
  35.                borderaxespad=0,
  36.                ncol=3)
  37.  
  38.     # Покажем окно с нарисованным графиком
  39.     plt.show()

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

Разрешение перемещения легенды с помощью мышки

Если мы заранее не можем предсказать, где легенда будет смотреться лучше, мы можем разрешить пользователю ее перемещать самостоятельно. Для этого нужно сначала получить экземпляр класса matplotlib.legend.Legend (см. статью Применение объектно-ориентированного стиля), который возвращается функцией legend(), а затем для полученного экземпляра класса вызвать метод set_draggable(), передав ему в качестве параметра True:

  1. #!/usr/bin/env python
  2. # coding: utf-8
  3.  
  4. # Импортируем один из пакетов Matplotlib
  5. import matplotlib.pyplot as plt
  6.  
  7. import numpy as np
  8.  
  9.  
  10. if __name__ == '__main__':
  11.     # Интервал изменения переменной по оси X
  12.     xmin = -30.0
  13.     xmax = 10.0
  14.  
  15.     # Шаг между точками
  16.     dx = 0.1
  17.  
  18.     # Создадим список координат по оси X на отрезке [xmin; xmax], включая концы
  19.     x = np.arange(xmin, xmax + dx, dx)
  20.  
  21.     # Вычислим значение функции в заданных точках
  22.     y1 = np.sinc(x)
  23.     y2 = np.sinc(x * 0.2)
  24.  
  25.     # Нарисуем два одномерных графика
  26.     # !!! Метки сразу привязываем к соответствующей кривой графика
  27.     plt.plot(x, y1, 'b-', label='f(x)')
  28.     plt.plot(x, y2, 'g--', label='f(x * 0.2)')
  29.  
  30.     # !!! Добавим легенду
  31.     legend_obj = plt.legend()
  32.     legend_obj.set_draggable(True)
  33.  
  34.     # Покажем окно с нарисованным графиком
  35.     plt.show()

Теперь пользователь сможет перемещать легенду, захватывая ее мышкой:

Заключение

Мы рассмотрели почти все способы расположение легенды на графике. "Почти", потому что остался не рассмотренным еще один параметр bbox_to_anchor, задающий прямоугольную область, относительно которой будет выравниваться легенда с помощью параметра loc. На мой взгляд этим параметром пользоваться менее удобно по сравнению с явным заданием координат с помощью того же параметра loc.

Надеюсь, что эта статья будет вам полезна. Жду ваших оценок, дополнений и комментариев. :)

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

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

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




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