30.09.2009

Пакет matplotlib. Наводим красивости

Продолжаем разговор о пакете matplotlib. Сегодня обсудим способы изменения внешнего вида элементов диаграмм - другими словами способы наведения красивостей.

Изменение свойств графических элементов пакета matplotlib

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

>>> import matplotlib.pyplot as plt
>>> line, = plt.plot([1, 2, 3])
>>> line
<matplotlib.lines.Line2D object at 0x030509D0>
>>> type(line)
<class 'matplotlib.lines.Line2D'>
>>> caption = plt.title(u'Заголовок диаграммы')
>>> caption
<matplotlib.text.Text object at 0x0308FC90>
>>> type(caption)
<class 'matplotlib.text.Text'>

Авторы пакета matplotlib предусмотрели три способа изменения свойств графических объектов.

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

>>> plt.plot([1, 2, 3], color = 'red', marker = '^', linestyle = '--', linewidth = 2, markersize = 5, label = u'Прямая линия')
[<matplotlib.lines.Line2D object at 0x02E3E150>]
>>> plt.title(u'Заголовок диаграммы', color = 'black', family = 'fantasy', fontsize = 'x-large')
<matplotlib.text.Text object at 0x02E66E10>

Второй способ. Как и подобает в соответствии с догмами объектно-ориентированного программирования, для каждого поля объекта существуют методы, предоставляющие возможность читать/писать значение поля. Уже существующий объект можно настроить посредством указанных методов:

>>> line, = plt.plot([1, 2, 3])
>>> line.set_color('red')
>>> line.set_marker('^')
>>> line.set_linestyle('--')
>>> line.set_linewidth(2)

В matplotlib принято следующее соглашение по именованию методов - метод возвращающий значение свойства property именуется get_property(), метод изменяющий значение свойства set_property()

Третий способ. Часто возникает необходимость для группы объектов (не обязательно экземпляров одного и того же класса) установить одинаковые значения для одного (нескольких) общих свойств. На этот случай авторы matplotlib предусмотрели специальную функцию matplotlib.pyplot.setp(*args, **kwargs) - "setup property" - установить свойство. Функция принимает ссылку или список ссылок на объекты и произвольный набор именованных переменных соответствующих изменяемым свойствам:

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> X = np.linspace(0.0, 5.0, 10)
>>> Y1 = X
>>> Y2 = 3 * X
>>> Y3 = 7 * X
>>> lines = plt.plot(X, Y1, X, Y2, X, Y3)
>>> plt.setp(lines, color = 'red', marker = '^', linestyle = '--', linewidth = 2)
[None, None, None, None, None, None, None, None, None, None, None, None]
>>> plt.show()

В результате выполнения кода примера появиться вот такое окно:

Пакет matplotlib. Пример использования функции setp()

Все три линии на диаграмме оформлены одинаково.

А какой глубокий смысл кроется в структуре возвращаемой функцией setp() я, честно говоря, не знаю.

Возможен и альтернативный синтаксис вызова функции. Вместо набора именованных переменных функция принимает набор пар: строка - имя свойства, произвольный тип - значение свойства (так принято работать с объектами в Matlab):

>>> plt.setp(lines, 'color', 'red', 'marker', '^', 'linestyle', '--', 'linewidth', 2)

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

>>> plt.setp(line, 'linestyle')
 linestyle: [ '-' | '--' | '-.' | ':' | 'None' | ' ' | '' ] and any drawstyle in combination with a linestyle, e.g. 'steps--'.
>>> plt.setp(line, 'color')
 color: any matplotlib color

Если вызвать функцию setp(), передав только ссылку на объект, будет выведен список всех свойств объекта и список возможных значений для каждого из свойств:

>>> plt.setp(line)
  alpha: float (0.0 transparent through 1.0 opaque)
  animated: [True | False]
  antialiased or aa: [True | False]
  axes: an :class:`~matplotlib.axes.Axes` instance
  ...

Ну и если первый аргумент функции - список ссылок на объекты, описанные выше действия производятся для объекта, ссылка на который стоит в переданном списке первой.

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

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

# -*- coding: UTF-8 -*-

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

# Значения по оси X
X = np.linspace(0.0, 2.0, 15)
# Значения по оси Y
Y_01 = X
Y_02 = X * 3
Y_03 = X * 7

# Задаем размер диаграммы
mpl.rcParams['figure.figsize'] = (8.0, 6.0)

# Строим диаграмму
# Линии
line_01 = plt.plot(X, Y_01)
line_02 = plt.plot(X, Y_02)
line_03 = plt.plot(X, Y_03)

# Сохраняем диаграмму в файл
plt.savefig('set_exmp_01.png', format = 'png')

В результате получим вот такое изображение:

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

# -*- coding: UTF-8 -*-

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

# Значения по оси X
X = np.linspace(0.0, 2.0, 15)
# Значения по оси Y
Y_01 = X 
Y_02 = X * 3
Y_03 = X * 7

# Задаем размер диаграммы
mpl.rcParams['figure.figsize'] = (8.0, 6.0)

# Строим диаграмму

# Линии

# Первый способ настройки объектов
line_01, = plt.plot(X, Y_01, color = 'blue', linestyle = ':', linewidth = 1, marker = 's',  markersize = 6, markeredgecolor = 'black', markerfacecolor = 'blue', markeredgewidth = 1, label = u'y = x' )

line_02,  = plt.plot(X, Y_02)
line_03,  = plt.plot(X, Y_03)

# Второй способ настройки объектов
line_02.set_color('red')
line_02.set_linestyle(':')
line_02.set_linewidth(1)
line_02.set_marker('D')
line_02.set_markersize(5)
line_02.set_markeredgecolor('black')
line_02.set_markerfacecolor('red')
line_02.set_markeredgewidth(1)
line_02.set_label(u'y = 3 * x')

# Третьий способ настройки объектов
plt.setp(line_03, color = 'magenta', linestyle = ':', linewidth = 1, marker = 'o', markersize = 6, markeredgecolor = 'black', markerfacecolor = 'magenta', markeredgewidth = 1, label = u'y = 7 * x')

# Задаем интервалы значений по осям X, Y
plt.axis((-0.03, 2.03, -0.2, 14.2))

# Добавим легенду
plt.legend(loc = 'best')

# Сохраняем диаграмму в файл
plt.savefig('set_exmp_02.png', format = 'png')

Теперь изображение будет выглядеть вот так:

Пакет matplotlib. Пример диаграммы при измененных значениях свойств объектов

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

Остановимся подробнее на свойствах объектов класса matplotlib.lines.Line2D - линии, которая неизбежно присутствует практически на каждой диаграмме.

О свойствах объектов класса matplotlib.lines.Line2D

Ниже в таблице приведены основные свойства объекта класса matplotlib.lines.Line2D.

Свойство Значение Описание
alpha Вещественное число в интервале [0.0, 1.0] Степень прозрачность элементов линии (собственно линии и маркеров) - от полностью прозрачного 0.0, до полностью непрозрачного 1.0. Пример использования смотри ниже
antialiased или aa True, False Включить (True), выключить (False) режим антиалиазинга элементов линии
color или c Один из возможных способов представления цвета в matplotlib, подробности смотри ниже Цвет линии
dash_capstyle Строки: 'butt', 'round', 'projecting' Стиль оконечностей пунктирной линии. Пример использования смотри ниже
dash_joinstyle Строки: 'miter', 'round', 'bevel' Стиль соединения пунктирных линий
dashes Список (кортеж) целых чисел, количество элементов списка должно быть четным Каждая пара чисел в списке рассматривается как количество индуцируемых точек, количество погашенных точек. С помощью свойства dashes можно рисовать линии состоящие из произвольного повторяющегося набора штрихов и пунктиров. Пример использования смотри ниже
drawstyle Строки: 'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post' Стиль отображения линии: 'default' - соседние точки соединены прямой, остальные значения - соседние точки соединены пересекающимися под прямым углом отрезками ("ступенькой") с различными вариациями пересечения отрезков. Пример использования смотри ниже
label Произвольная строка Подпись к линии, используется при создании легенды диаграммы
linestyle или ls Строки: '-', '--', '-.', ':', 'steps', 'steps-pre', 'steps-mid', 'steps-post', 'None', ' ', '' Стиль линии. Пример использования первых четырех стилей был приведен ранее, пример использования следующих четырех (можно задавать и через свойство drawstyle) смотри ниже, 'None', пробел и пустая строка выключают отображение линии, (собственно линии, маркеры, при этом, будут отображаться)
linewidth или lw float Толщина линии в точках
marker Строки: '.', ',', 'o', 'v', '^', '<', '>', '1', '2', '3', '4', 's', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd', '|', '_' Стиль маркера. Пример использования был приведен ранее
markeredgecolor или mec Один из возможных способов представления цвета в matplotlib, подробности смотри ниже Цвет границы маркера
markeredgewidth или mew float Толщина границы маркера в точках
markerfacecolor или mfc Один из возможных способов представления цвета в matplotlib, подробности смотри ниже Цвет маркера
markersize или ms float Размер маркера в точках
markevery None, integer N, список/кортеж (integer start, integer N) Свойство определяет, как будут использоваться маркеры при построении данной линии. Если None будут отображены все маркеры. Если целое число N, будет отображен каждый N-ый маркер. Если кортеж целых чисел (start, N) будет отображен каждый N-ый маркер начиная с start. Пример использования смотри ниже
solid_capstyle Строки: 'butt', 'round', 'projecting' Стиль оконечностей непрерывной линии
solid_joinstyle Строки: 'miter', 'round', 'bevel' Стиль соединения непрерывных линий
visible True, False В случае False линия и маркеры становятся невидимыми. True включает отображение элементов линии
zorder integer Порядок наложения элементов диаграммы (Z-order). Элемент с наибольшим значением zorder будет отображен на переднем плане (по отношению к наблюдателю) или, другими словами, элемент с наибольшим zorder будет отображен последним (самым верхним). Пример использования смотри ниже

Способы представления цвета в пакете matplotlib

Как следует из названия подраздела цвет в matplotlib может быть задан несколькими способами.

Способ первый. Из системы Matlab позаимствованы обозначения для восьми базовых цветов в виде отдельных символов.

Символ Цвет
'b' blue синий
'g' green зеленый
'r' red красный
'c' cyan бирюзовый
'm' magenta пурпурный
'y' yellow желтый
'k' black черный
'w' white белый
>>> plt.plot(X, Y_02, color = 'm')

Способ второй. Цвет можно задать используя стандартные обозначения цветов принятые в html, как то 'red', 'silver', 'olive' и так далее.

>>> plt.plot(X, Y_02, color = 'navy')

Способ третий. Произвольный цвет можно задать воспользовавшись HEX стилем представления цвета в html: '#cc00cc', '#9900ff', '#0099cc'.

>>> plt.plot(X, Y_02, color = '#003399')

Способ четвертый. Произвольный цвет так же можно задать передав кортеж из трех вещественных чисел, каждое из которых пренадлежит интервалу [0.0, 1.0]. Числа соответствуют представлению цвета в системе RGB: (0.75, 0.0, 1.0), (1.0, 0.33, 0.33), (0.0, 0.47, 0.21).

>>> plt.plot(X, Y_02, color = (0.0, 0.5, 0.32))

Способ пятый. Вариация на тему четвертого способа. Цвет в градации серого можно задать передав строку являющуюся представлением вещественного числа в диапазоне [0.0, 1.0], '0.0' - совсем черный, '1.0' - совсем белый.

>>> plt.plot(X, Y_02, color = '0.75')

Свойства linestyle и drawstyle

Свойство linestyle включает в себя свойство drawstyle - стили отрисовки "ступенек" можно задать как через drawstyle так и через linestyle. Пример использования на рисунке ниже:

Пакет matplotlib. Пример использования свойства drawstyle

Значения свойства drawstyle и остальные значения свойства linestyle можно комбинировать. Пример на рисунке ниже:

Пакет matplotlib. Пример использования свойства linestyle

Свойство dash_capstyle

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

Пакет matplotlib. Пример использования свойства dash_capstyle

Свойство dashes

Когда существующие стили пунктирных линий не устраивают, можно поиграться с значениями свойства dashes:

Пакет matplotlib. Пример использования свойства dashes

Свойство markevery

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

# -*- coding: UTF-8 -*-

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

# Значения по оси X
X = np.linspace(0.0, 2.0, 36)
# Значения по оси Y
Y_01 = np.exp(X)
Y_02 = np.exp(X) + 5.0

# Задаем размер диаграммы
mpl.rcParams['figure.figsize'] = (8.0, 6.0)

# Строим диаграмму

# Линии
line_01,  = plt.plot(X, Y_01, 'ro--', markevery = None, label ='markevery = None')
line_02,  = plt.plot(X, Y_02, 'bo--', markevery = (0, 5), label = 'markevery = (0, 5)')
# Подпись к диаграмме
plt.title(u'Свойство markevery')
# Добавляем легенду
plt.legend(loc = 'best')
# Задаем интервалы значений по осям X, Y
plt.axis((-0.03, 2.03, -0.03, 14.0))

# Сохраняем диаграмму в файл
plt.savefig('markevery.png', format = 'png')

А вот результат прогона кода:

Пакет matplotlib. Пример использования свойства markevery

Свойство zorder

Чем больше значение свойства zorder тем ближе к наблюдателю объект:

Пакет matplotlib. Пример использования свойства zorder

Свойство alpha

Для иллюстрации "прозрачности" воспользуемся предыдущим рисунком. Получилось коряво, но смысл свойства alpha понять можно (в matplotlib атрибут прозрачности жутко портит некоторые цвета)

Пакет matplotlib. Пример использования свойства alpha

Ну вот пожалуй на сегодня и все...

Предыдущий пост по теме: Пакет matplotlib. График с дополнительной осью ординат.

3 комментария:

  1. Спустя пять лет после написания этой статьи, просто хочется сказать спасибо. При изучении matplotlib ваши статьи мне очень помогли.

    ОтветитьУдалить
    Ответы
    1. Этот комментарий был удален автором.

      Удалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить