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

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

Дата публикации: 13.12.2012
Дата последней правки: 25.02.2023

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

Для интеграции Matplotlib с другими библиотеками используется пакет matplotlib.backends, в который входят в частности модули matplotlib.backends.backend_wxagg для интеграции с приложениями wxPython, matplotlib.backends.backend_tkagg для интеграции с Tkinter, 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:

import wx

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. Этот класс в качестве одного из параметров конструктора принимает экземпляр класса matplotlib.figure.Figure, созданный на первом шаге.
  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('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, wx.ID_ANY, self.figure)
        self.canvas.SetMinSize((100, 100))

        # Размещение элементов управления в окне
        mainSizer = wx.FlexGridSizer(cols=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.

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

Надо отметить, что созданная таким образом канва для рисования является производной от класса 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 as 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(['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. В завершении рисования надо не забыть обновить канву (панель), вызвав метод draw() для экземпляра класса FigureCanvasWxAgg.

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

Похожие статьи

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

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




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