Matplotlib и PyQt5
https://t.me/notes_of_young_data_scientist
Всем доброго времени суток. В построении графического интерфейса иногда очень важно визуализировать график, гистограмму и т.д. Поскольку для построения графиков мы используем matplotlib, то сегодня мы разберём связку matplotlib и PyQt5 - надстройку над библиотекой Qt, реализованная на Python.
На кого расчитана эта статья
Эта статья написана для тех людей, которые имеют минимальный опыт работы с matplotlib и PyQt. Однако если такого опыта у вас нет, внимательного чтения документации будет достаточно для того, чтобы понять, что тут происходит.
Импорт необходимых модулей
Для сегодняшнего примера нам понадобятся два пакета:
PyQt5
matplotlib
Устанавливаем их с помощью pip/pip3, и начинаем писать код. Для начала нам нужно импортировать модули стандартной библиотеки, которые нам необходимы.

Для вычислений нам необходим массив NumPy, поэтому импортируем и этот модуль.

Далее импортируем классы, необходимы для связки matplotlib и PyQt.

И для создания главного окна импортируем все классы из PyQt5.Qt:

Примечание. Согласно РЕР8, сначала мы импортируем модули стандартной библиотеки Python, затем пользовательские пакеты, а уже потом свои. Подробнее про импортирование можно почитать тут.
Создание виджета
Далее определимся с нашей задачей. В качестве примера я реализую виджет, который будет строить график рандомной тригонометрической функции на промежутке [-10, 10]. Будем использовать функции NumPy(со всем списком мат.функций можно ознакомиться здесь).
Т.к. там не реализована функция ctg и название тангенса не совсем соответствует математическим правилам, то реализуем функцию tg и ctg.

Теперь создаем виджет постройки графиков. Будем использовать ООП-парадигму, потому создадим класс, который наследует класс QWidget.

Там же создадим словарь с функциями, который будет использоваться для рандомного выбора функции. Теперь напишем инициализатор класса:

С помощью функции super вызываем метод(в данном случае инициализатор) родительского класса, а с помощью метода initUI() построим интерфейс виджета.

Создаём компоновщик, который использует в качестве родительского виджета наш виджет. Также создаём фигуру, которая будет отвечать за построения, canvas для вывода графиков на экран и панель управления canvas'ом.
Далее реализуем метод постройки графиков:

Тут много всего, поэтому давайте разбираться.
В строке 50 мы выбираем случайным образом номер функции.
В строке 52 мы выбираем саму функцию по индексу.
В строке 54 создаём данные для постройки графиков по оси Ox.
В строке 56 мы создаём данные по оси Oy путём вычисления функции(для массивов NumPy мат.функции выполняются поэлементно).
В строке 58 очищаем фигуру, чтобы убрать старый график.
В строке 59 создаем новый экземпляр Axes для построения графика.
В строке 60 устанавливаем background для поля с графиком. Используем HTML-цвета(немного цветов можно подсмотреть здесь).
В строке 62-63 мы чертим оси координат. Метод для горизонтальной линии описан тут, а метод вертикальной линии здесь.
В строке 65-66 устанавливаем ограничения графика по координатам, используя методы .set_xlim() и .set_ylim().
Для синуса и косинуса мы отдельно начертим ограничения( -1, 1) пунктиром синего цвета.
В строке 72 мы чертим сам график, устанавливаем для него цвет, стиль линии, а также надпись, используя свойством каждой функции в Python хранить своё имя в атрибуте __name__.
Далее устанавливаем легенду, помещая её в верхний правый угол.
И выводим график на экран в строке 74.
Главное окно
Отлично. Реализовав виджет для графиков, создадим главное окно программы. Дабы вас не запутать в иерархии файлов, напишем класс в том же файле.
Чтобы создать главное окно, реализуем класс, наследуемый от QMainWindow.

В инициализаторе вызываем метод построения интерфейса и связки всех сигналов с необходимыми нам методами.
Сам интерфейс реализуется так:

Как и в прошлый раз, опишем всё построчно.
В строке 85 создадим главный виджет, который будет основой нашего окна.
В строке 86-87 создаём главный компоновщик и компоновщик для кнопок.
В строке 90 создаём экземпляр класса PlotWidget.
В строке 92-93 создадим кнопки для управления программой.
В строке 95-96 установим для кнопок размер шрифта 12 и толщину шрифта 530, используя разметку CSS.
В строке 98-99 добавляем кнопки в компоновщик.
В строке 101-102 добавляем кнопки и виджет построения в главный компоновщик.
В строке 104 устанавливаем главный виджет для нашего окна.
Метод connectUi() реализован так:

Используя метод connect(), мы соединяем нажатие на кнопку с текстом 'Plot' построение графика, а нажатие на кнопку с текстом 'Clear' с методом clear(), который выглядит так:

Тут, думаю, всё понятно.
Запуск программы
Для запуска программы нам необходим следующий фрагмент кода:

Создаём экземпляр класса QApplication для запуска, создаём наше окно и вызываем метод show(). Далее устанавливаем выход из программы в момент закрытия окна.
Результат таков:

Не буду рассказывать, что делает панель управления, легче самому её опробовать :)
Внешний вид графика можно настраивать самому, суть статьи была не в этом.
Заключение
Сегодня мы разобрали, как "соединить" matplotlib и PyQt5. Особого в построении интерфейса я ничего не делал, однако пару основ таки продемонстрировал. Для того, чтобы хорошо выстраивать граф.интерфейс с помощью Qt, я бы посоветовал ознакомиться с основными виджетами и другими классами, разметкой CSS и основами дизайна приложений.
Мой телеграмм-канал: https://t.me/notes_of_young_data_scientist
Репозиторий, где можно найти пример виджета для построения графиков: https://github.com/myDiamondsDancing/ChartWidget
Весь код из статьи можно найти здесь.