Использование библиотеки Matplotlib. Применение объектно-ориентированного стиля
В большинстве примеров данного цикла статей используется процедурный подход к созданию графиков, когда для выполнения той или иной операции вызываются функции модуля pylab, т.е. типичный пример создания графика выглядит следующим образом (здесь для вычислений значений функции используется библиотека numpy, чтобы пример был более компактным):
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- import numpy
- # Импортируем один из пакетов Matplotlib
- import pylab
- if __name__ == '__main__':
- x = numpy.arange (0.0, 4 * numpy.pi, 0.01)
- y = numpy.sin (x) * numpy.cos (3 * x)
- pylab.plot (x, y, '-k', label=u'y = f(x)')
- pylab.grid()
- pylab.ylim ([-2, 2])
- pylab.legend()
- pylab.show()
В результате с помощью этого кода мы рисуем одну кривую, включаем сетку, меняем пределы по оси Y, отображаем легенду и показываем окно. Результат выглядит следующим образом:

Здесь все хорошо и удобно, и в большинстве случаев этого достаточно, но для некоторых задач (например, для рисования трехмерных графиков или для того, чтобы сделать легенду перемещаемой с помощью мышки) нужно понимать, что Matplotlib - это объектно-ориентированная библиотека, и мы можем получить доступ к ее внутренним объектам.
Проще всего (и желательно так делать) для этого воспользоваться все теми же функциями из модуля pylab, используя тот факт, что многие функции модуля возвращают какие-то объекты. Изменим предыдущий пример таким образом, чтобы получить некоторые такие объекты, после чего настройки графика изменим, используя полученные экземпляры классов.
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- import numpy
- # Импортируем один из пакетов Matplotlib
- import pylab
- if __name__ == '__main__':
- x = numpy.arange (0.0, 4 * numpy.pi, 0.01)
- y = numpy.sin (x) * numpy.cos (3 * x)
- # Получим экземпляр класса Figure
- figure = pylab.figure()
- print type (figure)
- # Получим экземпляр класса осей
- axes = figure.add_subplot (1, 1, 1)
- print type (axes)
- # Получим список новых кривых
- curves = axes.plot (x, y, '--k', label=u'y = f(x)')
- print curves
- # Изменим настройки осей
- axes.grid()
- axes.set_ylim ([-2, 2])
- axes.set_xlabel (u'angle, radians')
- axes.set_ylabel (u'U, mV')
- # Создадим легенду и получим экземпляр класса Legend
- legend = pylab.legend()
- print type (legend)
- # Изменим заголовок легенды
- legend.set_title (u'Title')
- pylab.show()
Теперь наше окно выглядит следующим образом:

Кроме того, этот пример последовательно выводит названия типов классов. Так, после создания окна с будущим графиком с помощью функции pylab.figure, мы получили экземпляр класса matplotlib.figure.Figure, затем мы создали оси с помощью метода add_subplot и получили экземпляр класса matplotlib.axes.AxesSubplot - класс, производный от matplotlib.axes.Axes, который хорошо документирован, в отличие от matplotlib.axes.AxesSubplot.
Затем, уже используя класс осей, мы нарисовали кривую, используя хорошо известный нам метод plot, но уже вызываемый непосредственно для класса matplotlib.axes.Axes или его производных. Этот метод возвращает список объектов, описываеющих содержимое графика. Метод plot возвращает список классов matplotlib.lines.Line2D, другие методы рисования возвращают другие объекты.
После этого мы возвращаемся к экземпляру класса осей axes и меняем их настройки.
Затем мы создаем легенду с помощью знакомой функции pylab.legend, которая возвращает экземпляр класса matplotlib.legend.Legend, и, используя экземпляр этого класса, меняем заголовок легенды с помощью метода set_title.
Обратите внимание, что методы классов очень напоминают функции модуля pylab, возможно с приставками set_ или get_. Например, pylab.xlim <--> Axes.set_ylim, pylab.xlabel <--> Axes.set_xlabel и т.п.
В предыдущем примере мы могли бы расписать 23-ю строку (curves = axes.plot (x, y, '-k', label=u'y = f(x)')) по-другому, устанавливая параметры кривой в несколько этапов, как показано в следующем примере:
- #!/usr/bin/env python
- # -*- coding: UTF-8 -*-
- import numpy
- # Импортируем один из пакетов Matplotlib
- import pylab
- if __name__ == '__main__':
- x = numpy.arange (0.0, 4 * numpy.pi, 0.01)
- y = numpy.sin (x) * numpy.cos (3 * x)
- # Получим экземпляр класса Figure
- figure = pylab.figure()
- print type (figure)
- # Получим экземпляр класса осей
- axes = figure.add_subplot (1, 1, 1)
- print type (axes)
- # Получим список новых кривых
- curves = axes.plot (x, y)
- print curves
- curves[0].set_linestyle ('--')
- curves[0].set_color ('k')
- curves[0].set_label (u'y = f(x)')
- # Изменим настройки осей
- axes.grid()
- axes.set_ylim ([-2, 2])
- axes.set_xlabel (u'angle, radians')
- axes.set_ylabel (u'U, mV')
- # Создадим легенду и получим экземпляр класса Legend
- legend = pylab.legend()
- print type (legend)
- # Изменим заголовок легенды
- legend.set_title (u'Title')
- pylab.show()
Результат будет выглядеть точно также.
Оси мы могли бы создать с помощью функции pylab.axes, заменив в предыдущем примере 19-ю строку (axes = figure.add_subplot (1, 1, 1)) на
В этом случае переменная axes будет хранить экземпляр класса matplotlib.axes.Axes, что не скажется на остальной код. Переданный в функцию axes кортеж задает координаты левого нижнего угла будущего графика, а также его ширину и высоту. Координаты угла и размеры задаются в нормированных координатах, где (0.0; 0.0) - координаты левого нижнего угла окна, а (1.0; 1.0) - координаты правого верхнего угла окна.
После всего написанного выше может возникнуть желание пойти дальше и вообще отказаться от использования модуля pylab, а вызывать конструкторы Figure, Axes и Legend вручную. Теоретически это можно попробовать сделать, но это не просто, поскольку "под капотом" модуля pylab происходит некая магия, связанная с так называемыми менеджерами фигур.
Если вам интересно покопаться в исходниках matplotlib (а там код сравнительно понятный), то можете начинать свое изучение с файла lib/matplotlib/pyplot.py - там описаны все функции модуля pylab, затем вам понадобится синглтон Gcf из файла lib/matplotlib/_pylab_helpers.py, и вообще придется задействовать функции, не предназначенные для вызова пользователями. Но это все уже другая, хотя и достаточно интересная, тема.
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.