Продолжаем разговор о пакете 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()
В результате выполнения кода примера появиться вот такое окно:
Все три линии на диаграмме оформлены одинаково.
А какой глубокий смысл кроется в структуре возвращаемой функцией 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')
Теперь изображение будет выглядеть вот так:
В примерах, для формирования массивов значений был использован модуль 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. Пример использования на рисунке ниже:
Значения свойства drawstyle и остальные значения свойства linestyle можно комбинировать. Пример на рисунке ниже:
Свойство dash_capstyle
Для того, чтобы ясно углядеть различия в начертаниях "кончика штриха" необходимо установить толщину линии как минимум в четыре точки. Пример использования на рисунке:
Свойство dashes
Когда существующие стили пунктирных линий не устраивают, можно поиграться с значениями свойства 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')
А вот результат прогона кода:
Свойство zorder
Чем больше значение свойства zorder тем ближе к наблюдателю объект:
Свойство alpha
Для иллюстрации "прозрачности" воспользуемся предыдущим рисунком. Получилось коряво, но смысл свойства alpha понять можно (в matplotlib атрибут прозрачности жутко портит некоторые цвета)
Ну вот пожалуй на сегодня и все...
Предыдущий пост по теме: Пакет matplotlib. График с дополнительной осью ординат.
Читать далее...