Использование библиотеки 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:
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, нужно проделать следующие операции:
- Создать экземпляр класса matplotlib.figure.Figure.
- Из созданной фигуры получить экземпляр класса matplotlib.axes.Axes.
- Создать панель (канву) для рисования с помощью Matplotlib. Для работы из wxPython это будет экземпляр класса matplotlib.backends.backend_wxagg.FigureCanvasWxAgg. Этот класс в качестве одного из параметров конструктора принимает экземпляр класса matplotlib.figure.Figure, созданный на первом шаге.
- Нарисовать график, используя методы экземпляр класса matplotlib.axes.Axes, который был создан на втором шаге.
Все это продемонстрировано в файле mainwindow.py. Строки, относящиеся к работе с Matplotlib отмечены комментарием !!!, чтобы их можно было проще найти. Для сокращения места будем приводить полностью текст этого файла, который вы можете скачать, разберем только отдельные его части.
Класс главного окна приложения MainWindow является производным от класса wx.Frame, его конструктор выглядит следующим образом:
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 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. Конструктор этого класса принимает три параметра:
- Родитель создаваемой панели.
- Идентификатор.
- Экземпляр класса matplotlib.figure.Figure.
В качестве первого параметра используется само главное окно. Т.к. мы не будем обращаться к панели по идентификатору, то в качестве второго параметра передается константа wx.ID_ANY. В качестве третьего параметра передается фигура, созданная ранее, для которой были созданы оси.
Надо отметить, что созданная таким образом канва для рисования является производной от класса wx.Panel, поэтому ее можно использовать как обычный элемент управления wxPython, в том числе и добавлять в сайзеры, что и делается дальше в скрипте.
Если запустить программу в таком виде (без реализации метода _drawGraph()), то будет создано окно:
То есть Matplotlib уже работает, библиотека нарисовала оси, осталось только наполнить их содержимым. Это делает метод _drawGraph().
...
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()
В начале функции считываются введенные пользователем значения параметров, затем создаются массивы для рисования функции Гаусса:
...
@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 классах.
Похожие статьи
- Другие статьи про Matplotlib
- Применение объектно-ориентированного стиля
- Сайзеры в wxWidgets / wxPython
- Как рисовать графики вида y = f(x)
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.