问题描述:
做一个项目的小软件的时候需要利用计算出来的数值绘制图像,搜索之后发现可以利用matplotlib.backends.backend_qt5agg中的FigureCanvasQTAgg类实现pyqt5与matplotlib的结合,并成功的绘制的图像,但是当我重新输入一组数据后,发现图像不能够更新,即不能利用新的数据重新绘制图像。
pyqt5+matplotlib:
项目不便展示,因此在这里举一个小例子
1.首先用qtdesigner创建一个界面,注意红箭头指的是一个GroupBox,用来给图像提供画板。
2.然后使用Eric6编译窗体,Eric6+pyqt5结合非常好用,当然不用这个IDE也可以将ui文件转化为python代码,具体操作自行百度。
3.生成代码如下图,运行之后就是一个界面,没有功能。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'C:\Users\jxq\Desktop\boke\window_UI.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(584, 496)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralWidget)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.groupBox = QtWidgets.QGroupBox(self.centralWidget)
self.groupBox.setMinimumSize(QtCore.QSize(0, 400))
self.groupBox.setObjectName("groupBox")
self.gridLayout.addWidget(self.groupBox, 1, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.horizontalLayout.setContentsMargins(0, -1, -1, -1)
self.horizontalLayout.setSpacing(6)
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton = QtWidgets.QPushButton(self.centralWidget)
self.pushButton.setMaximumSize(QtCore.QSize(150, 40))
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(self.centralWidget)
self.pushButton_2.setMaximumSize(QtCore.QSize(150, 40))
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout.addWidget(self.pushButton_2)
self.pushButton_3 = QtWidgets.QPushButton(self.centralWidget)
self.pushButton_3.setMaximumSize(QtCore.QSize(150, 40))
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout.addWidget(self.pushButton_3)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.horizontalLayout_2.addLayout(self.gridLayout)
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.groupBox.setTitle(_translate("MainWindow", "GroupBox"))
self.pushButton.setText(_translate("MainWindow", "绘制正弦函数"))
self.pushButton_2.setText(_translate("MainWindow", "绘制余弦函数"))
self.pushButton_3.setText(_translate("MainWindow", "清空图形"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
4.具体实现功能需要新建一个Main.py文件,使用Eric6可以快速生成对话框代码,手写也可,文件代码如下,此时点击“绘制正弦图像”按键即可绘制图像,代码讲解写在注释上。
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import QMainWindow, QGridLayout, QApplication
from Ui_window_UI import Ui_MainWindow
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
from matplotlib.figure import Figure
import sys
#这个类用来画图
class Figure_Canvas(FigureCanvas):
def __init__(self,width=4,height=3,dpi=100):
self.fig=Figure(figsize=(width,height),dpi=100)#设置长宽以及分辨率
super(Figure_Canvas,self).__init__(self.fig)
self.ax=self.fig.add_subplot(111)#创建axes对象实例,这个也可以在具体函数中添加
#这是主界面
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.Plot_Sin)#按键连接Plot_Sin函数
def Plot(self):#这里是绘图的关键
self.plot_Figure = Figure_Canvas()#创建实例
self.plot_FigureLayout = QGridLayout(self.groupBox)#利用栅格布局将图像与画板连接
self.plot_FigureLayout.addWidget(self.plot_Figure)
def Plot_Sin(self):
self.Plot()
self.x = np.linspace(0,2*np.pi,240,endpoint=True)
self.y = np.sin(self.x)
self.plot_Figure.ax.plot(self.x, self.y)#绘图
if __name__ == "__main__":
app = QApplication(sys.argv)
ui = MainWindow()
ui.show()
sys.exit(app.exec_())
5.至此已经完成 pyqt5与matplotlib的结合
图像更新问题:
与上文类似,接着写了cos函数的代码,把这行代码写在MainWindow类的初始化函数中,再添加一个Plot_Cos函数,此时按道理点击余弦按钮应该显示显示余弦图像,但是实际测试并未更新。
self.pushButton_2.clicked.connect(self.Plot_Cos)
def Plot_Cos(self):
self.Plot()
self.x = np.linspace(0,2*np.pi,240,endpoint=True)
self.y = np.cos(self.x)
self.plot_Figure.ax.plot(self.x, self.y)
解决方案:
为了解决这个问题设置了清空图像按键,函数如下,删除布局代码不可省,不然还是无法更新。
self.pushButton_3.clicked.connect(self.ReSet)
def ReSet(self):
self.plot_Figure.deleteLater()#删除图像对象
self.plot_FigureLayout.deleteLater()#删除布局
解决后效果如下
1.单击“绘制正弦函数”,出先正弦函数图像
2.单击“清空图形”,图像被清空
3.再点绘制“余弦函数”,图像成功刷新
ps:“清空图像”无法连续点击两次,因为已经删除了画图对象和布局了,再删会报错,实际应用可以嵌入在绘图函数中而不用单独设置清除键,也可设置一个flag来检测是否存在画图对象以及布局,防止重复删除报错。
pss:import sip ,使用sip.delete(),删除那两个对象也可以实现更新