Использование библиотеки Matplotlib. Как рисовать графики с помощью Matplotlib при использовании wxPython

Немного рекламы

Matplotlib - очень удобная библиотека для рисования графиков. Особенно приятно, что графики, отображаемые с помощью этой библиотеки можно легко встраивать в приложения, написанные с использованием различных библиотек для построения интерфейса. На момент написания этой статьи Matplotlib может встраиваться в приложения, написанные с использованием библиотек wxPython, pyQT и pyGTK. Далее будет показано, как можно рисовать графики внутри окон wxPython.

Для интеграции Matplotlib с другими библиотеками используется пакет matplotlib.backends, в который входят в частности модули matplotlib.backends.backend_wxagg для интеграции с приложениями wxPython, matplotlib.backends.backend_qt4agg для интеграции с pyQT и matplotlib.backends.backend_gtkagg для интеграции с pyGTK. В этот же пакет входит модуль matplotlib.backends.backend_pdf для рисования графиков в файл PDF.

Часто библиотека Matplotlib не используется в объектно-ориентированном стиле, когда просто вызываются функции из модуля pylab: pylab.plot(...), pylab.show(...) и т.д. Однако Matplotlib - это полностью объектно-ориентированная библиотека, где разные части графика представлены своим классом, и при интеграции Matplotlib в ваше приложение нужно будет использовать непосредственно эти классы.

Для примера мы будем делать программу, рисующую функцию Гаусса . При этом интервал по оси X, а также параметры sigma и mu будут задаваться пользователем в окне. Вот как будет выглядеть конечный результат:

Для начала создадим два файла. Первый файл - plotgauss.py содержит класс приложения wxPython, и именно этот файл нужно будет запускать с помощью команды python plotgauss.py. Не будем вдаваться в подробности частей программы, которые не относятся непосредственно к Matplotlib, будем считать, что вы представляете, как работать с библиотекой wxPython.

Итак, файл plotgauss.py:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import wx
import pylab
import numpy

from mainwindow import MainWindow


class PlotGauss(wx.App):
    def __init__(self, *args, **kwds):
        wx.App.__init__ (self, *args, **kwds)


    def OnInit(self):
        wx.InitAllImageHandlers()

        mainWnd = MainWindow(None, -1, "")
        mainWnd.Show()

        self.SetTopWindow (mainWnd)

        return True


if __name__ == "__main__":
    application = PlotGauss(False)
    application.MainLoop()

Здесь нет никаких особенностей - создается экземпляр класса приложения PlotGauss и запускается цикл обработки сообщений с помощью метода MainLoop().

В качестве главного окна используется экземпляр класса MainWindow из файла mainwindow.py. Именно в нем и содержится все самое интересное.

Чтобы встроить график Matplotlib в приложение wxPython, нужно проделать следующие операции:

  1. Создать экземпляр класса matplotlib.figure.Figure.
  2. Из созданной фигуры получить экземпляр класса matplotlib.axes.Axes.
  3. Создать панель (канву) для рисования с помощью Matplotlib. Для работы из wxPython это будет экземпляр класса matplotlib.backends.backend_wxagg.FigureCanvasWxAgg.
  4. Нарисовать график, используя методы экземпляр класса matplotlib.axes.Axes, который был создан на втором шаге.

Все это продемонстрировано в файле mainwindow.py. Строки, относящиеся к работе с Matplotlib отмечены комменатрием !!!, чтобы их можно было проще найти. Чтобы не раздувать статью, я не буду приводить полностью текст этого файла, который вы можете и так скачать, разберем только отдельные его части.

Класс главного окна приложения MainWindow является производным от класса wx.Frame, его конструктор выглядит следующим образом:

import numpy
import wx
import matplotlib.figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg

class MainWindow (wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        super (MainWindow, self).__init__ (*args, **kwds)
        self.SetTitle (u"Matplotlib + wxPython")

        # Дискрет, с которым будет строиться график
        self._graphStep = 0.01

        # Установим размер главного окна
        self.SetSize ((600, 500))

        # Заполнить главное окно элементами управления
        self._createGui ()
        self.updateBtn.Bind (wx.EVT_BUTTON, handler=self._onUpdateClick)

        # Нарисовать график
        self._drawGraph ()

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

Сначала рассмотрим метод _createGui(). В приведенном ниже исходном тексте пропущены строки, не относящиеся к Matplotlib, такие как созданеи кнопки, полей ввода и надписей.

import numpy
import wx
import matplotlib.figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg

class MainWindow (wx.Frame):
    ...
    def _createGui (self):
        """
        Заполнить главное окно элементами управления
        """

        # Элементы управления для ввода минимального значения по оси X
        ...
        # Элементы управления для ввода максимального значения по оси X
        ...
        # Элементы управления для ввода sigma
        ...
        # Элементы управления для ввода mu
        ...
        # Создание кнопки
        ...

        # !!!
        # 1. Создание фигуры
        self.figure = matplotlib.figure.Figure ()

        # 2. Создание осей
        self.axes = self.figure.add_subplot (1, 1, 1)

        # 3. Создание панели для рисования с помощью Matplotlib
        self.canvas = FigureCanvasWxAgg (self, -1, self.figure)
        self.canvas.SetMinSize ((100, 100))

        # Размещение элементов управления в окне
        mainSizer = wx.FlexGridSizer (0, 1)
        mainSizer.AddGrowableCol (0)
        mainSizer.AddGrowableRow (5)

        # Размещение элементов интерфейса
        ...
        mainSizer.Add (self.canvas, flag=wx.ALL | wx.EXPAND, border=2)

        self.SetSizer (mainSizer)
        self.Layout()

Сначала создается экземпляр класса matplotlib.figure.Figure, конструктор которого в простейшем случае может не принимать никаких параметров, но при желании можно задавать некоторые параметры, такие как разрешение (актуально для рисования не на экране), цвет фона и некоторые другие, которые вы можете посмотреть в документации.

Чтобы создать оси, в которых будет происходить рисование, используется метод add_subplot() экземпляра класса Figure. Этот метод аналогичен функции subplot(), которая рассматривалась в статье Как нарисовать несколько графиков в одном окне. Этот метод возвращает экземпляр класса matplotlib.axes.Axes. Позже этот экземпляр будет использоваться непосредственно для рисования графика.

После этого создается панель, на которой можно будет рисовать с помощью библиотеки Matplotlib. При использовании wxPython, нужно создать экземпляр класса matplotlib.backends.backend_wxagg.FigureCanvasWxAgg. Конструктор этого класса принимает три параметра:

  1. Родитель создаваемой панели.
  2. Идентификатор.
  3. Экземпляр класса matplotlib.figure.Figure.

В качестве первого параметра используется само главное окно. Т.к. мы не будем обращаться к панели по идентификатору, то в качестве второго параметра передается -1. В качестве третьего параметра передается фигура, созданная ранее, в которой мы создали оси.

Надо отметить, что созданная таким образом канва для рисования является производной от класса wx.Panel, поэтому ее можно использовать как обычный элемент управления wxPython, в том числе и добавлять в сайзеры, что и делается дальше в скрипте.

Если бы мы попытались запустить программу в таком виде (без реализации метода _drawGraph()), то увидели бы следующее окно:

То есть Matplotlib уже работает, библиотека нарисовала оси, осталось только наполнить их содержимым. Это делает метод _drawGraph().

class MainWindow (wx.Frame):
    ...
    def _drawGraph (self):
        """
        Нарисовать график согласно введенным настройкам
        """

        # Получим введенные значения.
        # Т.к. это всего лишь демонстрационный пример, проверка правильности ввода простейшая
        try:
            xmin = float (self.xminText.Value)
            xmax = float (self.xmaxText.Value)
            sigma = float (self.sigmaText.Value)
            mu = float (self.muText.Value)
        except ValueError, e:
            print e
            return

        # Координаты точек по осям X и Y
        xvals = numpy.arange (xmin, xmax + self._graphStep, self._graphStep)
        yvals = self.gauss (sigma, mu, xvals)

        # !!!
        # Удалим предыдущий график, если он есть
        self.axes.clear()

        # Нарисуем новый график
        self.axes.plot (xvals, yvals)

        # Включим сетку
        self.axes.grid ()

        # self.axes.legend ([u"Функция Гаусса"], prop={"family": "verdana"})
        self.axes.legend ([u"Gaussian"])

        # Установим пределы по осям
        self.axes.set_xlim ([xmin, xmax])

        # Обновим окно
        self.canvas.draw()

В начале функции считываются введенные пользователем значения параметров, затем создаются массивы для рисования функции Гаусса:

class MainWindow (wx.Frame):
    ...
    @staticmethod
    def gauss (sigma, mu, x):
        """
        Функция Гаусса, которую отображаем
        """

        return 1.0 / (sigma * numpy.sqrt (2.0 * numpy.pi)) * numpy.exp (-((x - mu) ** 2) / (2 * sigma * sigma))

После этого происходит само рисование с использованием экземпляра класса Axes. Этот класс содержит методы, очень напоминающие функции из модуля pylab. Из используемых в данном примере методов по названию отличается только метод set_xlim(), аналог которого в pylab называется просто xlim().

В завершении рисования надо не забыть обновить канву (панель), вызвав метод draw() для экземпляра класса FigureCanvasWxAgg.

Подобным образом можно рисовать и другие типы графика, а также настраивать их внешний вид, нужно только найти подходящий метод в классах Axes, Figure или других используемых в Matplotlib классах.

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


Немного рекламы

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

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




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