PyQt,PySide2中嵌入Matplotlib图像
PyQt,PySide2中嵌入Matplotlib图像
方式1
使用Qt Designer新建一个Main Window,在此之上创建一个Vertical Layout。
import sys import numpy as np from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication import matplotlib matplotlib.use("Qt5Agg") from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 class FigureCanvasDemo1(FigureCanvas): def __init__(self): fig = Figure() FigureCanvas.__init__(self, fig) self.axes = fig.add_subplot() # 开始作图 x = np.linspace(0, 10, 100) y = 2 * np.sin(2 * x) self.axes.plot(x, y) self.axes.set_title('样例-sin图像') self.axes.grid() self.draw() class MainWindow(): def __init__(self): super().__init__() loader = QUiLoader() # 加载之前新建的ui文件 self.ui = loader.load("./ui/PicDemo1.ui") self.plot = FigureCanvasDemo1() layout = self.ui.verticalLayout layout.addWidget(self.plot) self.ui.setLayout(layout) if __name__ == '__main__': app = QApplication(sys.argv) mainwindow = MainWindow() mainwindow.ui.show() sys.exit(app.exec_())
显示效果
方式2
使用Qt Designer新建一个Main Window,在此之上创建一个Graphics View。
import sys import numpy as np from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication, QGraphicsScene import matplotlib matplotlib.use("Qt5Agg") from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 class FigureCanvasDemo2(FigureCanvas): def __init__(self, parent=None, width=10, height=5): # 创建一个Figure 如果不加figsize 显示图像过大 需要缩小 fig = plt.Figure(figsize=(width, height), tight_layout=True) # tight_layout: 用于去除画图时两边的空白 FigureCanvas.__init__(self, fig) # 初始化父类 self.setParent(parent) self.axes = fig.add_subplot(111) # 添加子图 self.axes.spines['top'].set_visible(False) # 去掉绘图时上面的横线 self.axes.spines['right'].set_visible(False) # 去掉绘图时右面的横线 class MainWindow(): def __init__(self): super().__init__() loader = QUiLoader().load("./ui/PicDemo2.ui") # 加载之前新建的ui文件 # 缩小图像尺寸 self.visual_data = FigureCanvasDemo2(width=self.ui.graphicsView.width() / 101, height=self.ui.graphicsView.height() / 101) x = np.linspace(0, 10, 100) y = 2 * np.sin(2 * x) self.visual_data.axes.plot(x, y) self.visual_data.axes.grid() # 加载的图形(FigureCanvas)不能直接放到graphicview控件中,必须先放到graphicScene,然后再把graphicscene放到graphicview中 self.graphicsScene = QGraphicsScene() # 创建一个QGraphicsScene # 把图形放到QGraphicsScene中,注意:图形是作为一个QWidget放到放到QGraphicsScene中的 self.graphicsScene.addWidget(self.visual_data) # 把QGraphicsScene放入QGraphicsView中 # self.ui 后跟的是对象的名字 这里QGraphicsView对象的名字是graphicsView self.ui.graphicsView.setScene(self.graphicsScene) self.ui.graphicsView.show() # 调用show方法呈现图形 if __name__ == '__main__': app = QApplication(sys.argv) mainwindow = MainWindow() mainwindow.ui.show() sys.exit(app.exec_())
显示效果
方式3
ui文件同方式2,还是GraphicsView
import sys import numpy as np from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication, QGraphicsScene import matplotlib matplotlib.use("Qt5Agg") from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 class FigureCanvasDemo3(FigureCanvas): def __init__(self, parent=None, width=10, height=5): fig = Figure(figsize=(width, height), tight_layout=True) FigureCanvas.__init__(self, fig) self.axes = fig.add_subplot() # 开始作图 x = np.linspace(0, 10, 100) y = 2 * np.sin(2 * x) self.axes.plot(x, y) self.axes.set_title('样例-sin图像') self.axes.grid() self.draw() class MainWindow(): def __init__(self): super().__init__() loader = QUiLoader() # 加载之前新建的ui文件 self.ui = loader.load("./ui/PicDemo2.ui") self.plot = FigureCanvasDemo3( width=self.ui.graphicsView.width() / 101, height=self.ui.graphicsView.height() / 101 ) self.graphicsScene = QGraphicsScene() # 创建一个QGraphicsScene self.graphicsScene.addWidget(self.plot) self.ui.graphicsView.setScene(self.graphicsScene) self.ui.graphicsView.show() # 调用show方法呈现图形 if __name__ == '__main__': app = QApplication(sys.argv) mainwindow = MainWindow() mainwindow.ui.show() sys.exit(app.exec_())
显示效果
在PyQt5设计的GUI界面中显示matplotlib绘制的图形
一、matplotlib如何嵌入PyQt5中?
通过matplotlib.backends.backend_qt5agg类连接PyQt5。在实际代码中,我们需要在引用部分加入内容:
import matplotlib matplotlib.use("Qt5Agg") # 声明使用QT5 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.pyplot as plt
二、如何使用FigureCanvas和Figure类
在使用FigureCanvas和Figure类创建plot绘制窗口时设计的相关内容可参考:
【matplotlib.figure类】https://matplotlib.org/api/figure_api.html
【backend类】https://matplotlib.org/api/index_backend_api.html
其中构造函数Figure()用来创建一个类似Matlab的figure()或matplotlib.pyplot的figure()。
class matplotlib.figure.Figure(figsize=None, dpi=None,
facecolor=None, edgecolor=None, linewidth=0.0,
tight_layout=None, constrained_layout=None)
例如:
width=5, height=4, dpi=100
self.fig = Figure(figsize=(width, height), dpi=dpi)
其中:width,height,为窗口尺寸,5英寸*4英寸,分辨率为dpi=100
另外一个函数是:add_subplot(221)
它是用来创建子图,如图matlab的subplot(2,2,1),表示共有4个子图,当前为第一个子图。具体应用如下:
sefl.axes = self.fig.add_subplot(221)
1
然后在self.axes中绘制图形如下:
t = np.arange(0.0, 3.0, 0.01)
s = np.sin(2 * np.pi * t)
self.axes.plot(t, s)
上述介绍的是使用Figure和subplot如何绘制图形,图形是可以绘制了,但是怎么将其在Gui界面控件中显示呢?
三、如何将图形显示在Gui控件上?
图形:正弦曲线,使用Figure实现的self.axes.plot(t, s)
GUi:Widget、Dialog和MainWindow三种窗口类型
控件(部件):
1)QTabWidget()部件的页面上
2)QGraphicsView图形视图
3)QgroupBox组框控件
4)还有其他可以作为Ui容器的控件都可以
【因为创建的Figure本身是一个部件,它也是PyQt中的Widget,所以我们只需要将创建的图形添加到GUI界面中的容器控件中即可显示图形。】
例1 在对话框中添加一个Widget中心部件,然后再在中心部件中添加一个GroupBox部件,保存ui文件(使用Qt designer)。并将其转为.py文件,代码如下:
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'testplot2pyqt5.ui' # Created by: PyQt5 UI code generator 5.10 # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(718, 515) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setGeometry(QtCore.QRect(370, 470, 341, 32)) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.widget = QtWidgets.QWidget(Dialog) self.widget.setGeometry(QtCore.QRect(10, 10, 691, 451)) self.widget.setObjectName("widget") self.groupBox = QtWidgets.QGroupBox(self.widget) self.groupBox.setGeometry(QtCore.QRect(0, 0, 691, 451)) self.groupBox.setObjectName("groupBox") self.retranslateUi(Dialog) self.buttonBox.accepted.connect(Dialog.accept) self.buttonBox.rejected.connect(Dialog.reject) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.groupBox.setTitle(_translate("Dialog", "GroupBox_Matplotlib的图形显示:"))
下面另新建一个python文件用于写主函数部分,具体代码如下:
#-*-coding:utf-8-*- from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * import sys import numpy as np from testplot2pyqt5 import Ui_Dialog import matplotlib matplotlib.use("Qt5Agg") # 声明使用QT5 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.pyplot as plt #创建一个matplotlib图形绘制类 class MyFigure(FigureCanvas): def __init__(self,width=5, height=4, dpi=100): #第一步:创建一个创建Figure self.fig = Figure(figsize=(width, height), dpi=dpi) #第二步:在父类中激活Figure窗口 super(MyFigure,self).__init__(self.fig) #此句必不可少,否则不能显示图形 #第三步:创建一个子图,用于绘制图形用,111表示子图编号,如matlab的subplot(1,1,1) self.axes = self.fig.add_subplot(111) #第四步:就是画图,【可以在此类中画,也可以在其它类中画】 def plotsin(self): self.axes0 = self.fig.add_subplot(111) t = np.arange(0.0, 3.0, 0.01) s = np.sin(2 * np.pi * t) self.axes0.plot(t, s) def plotcos(self): t = np.arange(0.0, 3.0, 0.01) s = np.sin(2 * np.pi * t) self.axes.plot(t, s) class MainDialogImgBW(QDialog,Ui_Dialog): def __init__(self): super(MainDialogImgBW,self).__init__() self.setupUi(self) self.setWindowTitle("显示matplotlib绘制图形") self.setMinimumSize(0,0) #第五步:定义MyFigure类的一个实例 self.F = MyFigure(width=3, height=2, dpi=100) #self.F.plotsin() self.plotcos() #第六步:在GUI的groupBox中创建一个布局,用于添加MyFigure类的实例(即图形)后其他部件。 self.gridlayout = QGridLayout(self.groupBox) # 继承容器groupBox self.gridlayout.addWidget(self.F,0,1) #补充:另创建一个实例绘图并显示 self.plotother() def plotcos(self): t = np.arange(0.0, 5.0, 0.01) s = np.cos(2 * np.pi * t) self.F.axes.plot(t, s) self.F.fig.suptitle("cos") def plotother(self): F1 = MyFigure(width=5, height=4, dpi=100) F1.fig.suptitle("Figuer_4") F1.axes1 = F1.fig.add_subplot(221) x = np.arange(0, 50) y = np.random.rand(50) F1.axes1.hist(y, bins=50) F1.axes1.plot(x, y) F1.axes1.bar(x, y) F1.axes1.set_title("hist") F1.axes2 = F1.fig.add_subplot(222) ## 调用figure下面的add_subplot方法,类似于matplotlib.pyplot下面的subplot方法 x = [1, 2, 3, 4, 5, 6, 7, 8, 9] y = [23, 21, 32, 13, 3, 132, 13, 3, 1] F1.axes2.plot(x, y) F1.axes2.set_title("line") # 散点图 F1.axes3 = F1.fig.add_subplot(223) F1.axes3.scatter(np.random.rand(20), np.random.rand(20)) F1.axes3.set_title("scatter") # 折线图 F1.axes4 = F1.fig.add_subplot(224) x = np.arange(0, 5, 0.1) F1.axes4.plot(x, np.sin(x), x, np.cos(x)) F1.axes4.set_title("sincos") self.gridlayout.addWidget(F1, 0, 2) if __name__ == "__main__": app = QApplication(sys.argv) main = MainDialogImgBW() main.show() #app.installEventFilter(main) sys.exit(app.exec_())
结果如下图:
例2,在上例基础上,添加一个TabWidget控件,将绘制的图形显示在Tabwidget控件中。【主要修改第六步即可】
第五步:定义MyFigure类的一个实例
self.F = MyFigure(width=3, height=2, dpi=100) #self.F.plotsin() self.plotcos() #**修改第六步**:在GUI的groupBox中创建一个布局,用于添加MyFigure类的实例(即图形)后其他部件。 # self.gridlayout = QGridLayout(self.groupBox) # 继承容器groupBox # self.gridlayout.addWidget(self.F,0,1) vlayout = QVBoxLayout(self.widget) #在中心部件上创建一个布局添加TabWidget控件 self.tabwidget = QTabWidget() # 添加一个Tab控件用于存放显示图像的部件 #下面这些属性设置可不要 self.tabwidget.setTabsClosable(True) self.tabwidget.setUsesScrollButtons(True) self.tabwidget.setTabPosition(0) self.tabwidget.setElideMode(2) self.tabwidget.setMovable(True) self.tabwidget.resize(300, 500) vlayout.addWidget(self.tabwidget) self.gridlayout1 = QGridLayout(self.tabwidget) self.gridlayout1.addWidget(self.F,0,0)
结果:
例3 同样在例1基础上修改第六步,在GroupBox框中添加QGraphicsView视图窗口显示图形,具体修改如下:
修改第六步:在groupBox框中使用QGraphicsView控件来显示
self.gridlayout = QGridLayout(self.groupBox) # 继承容器groupBox self.graphicsview = QGraphicsView(self.groupBox) self.gridlayout.addWidget(self.graphicsview, 1, 0) self.scene = QGraphicsScene() #创建一个场景 self.scene.addWidget(self.F) #将图形元素添加到场景中 self.graphicsview.setScene(self.scene) #将创建添加到图形视图显示窗口 self.graphicsview.show() #显示
结果:
从3个结果图我们可以看出,例3使用GraphicsView显示比较浪费空间,显示不够饱满,例1和例2显示效果较好些。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了