当前位置: 首页 > news >正文

【使用PyQt6与Matplotlib编写交互式生成一元二次函数图形程序】

目录

一、程序交互界面实现效果

二、如何在PyQt6中集成Matplotlib

三、程序具体代码实现

1. 引入库

2. 创建matplotlib画布类

3. 创建主窗口类

4. 主程序代码

四、总结


一、程序交互界面实现效果

在使用百度搜索引擎查询“一元二次函数”时,发现百度给出的关于一元二次函数的介绍内容中,有一个一元二次函数图形生成的交互式的工具不错。对该图形生成工具,百度网页上的原文如是说:想直观看看抛物线怎么变?试试这个工具。


图1 百度搜索引擎使用的抛物线生成工具

图1所示抛物线生成工具的交互性非常好,不仅可以通过a、b、c来改变抛物线的形状,还可以通过上下平移抛物线来改变常数项c的值。

于是想着自己来尝试实现这个工具。最省事的语言自然是Python语言了。至于使用Python语言的哪些库来绘制界面和图形,这里选择的是使用PyQt6来制作窗体界面,使用Matplotlib来绘制抛物线图形。

几番鼓捣,大部分功能终于实现,即可以通过调整过a、b、c来控制抛物线的形状,但通过上下平移抛物线来改变常数项c的值这项功能没有实现,有兴趣的读者可以自己去尝试实现之。因为本程序重在界面交互,所以下面截取了3个程序界面,见图2、图3、图4所示。

图2

图3

图4

二、如何在PyQt6中集成Matplotlib

在 PyQt6中集成 Matplotlib 的核心在于使用FigureCanvasQTAgg将 Matplotlib的图形对象转换为 Qt 的 Widget对象。以下是核心实现步骤。

核心步骤

  1. 安装依赖:确保安装了PyQt6和matplotlib。

  2. 导入后端:从matplotlib.backends.backend_qtagg导入FigureCanvasQTAgg。

  3. 创建画布类:创建一个继承自FigureCanvasQTAgg的类,在其中初始化Figure和Axes。

  4. 嵌入界面:将该画布实例作为普通 Widget 添加到 PyQt6 的布局中。

  5. 动态更新:通过修改数据并调用draw()或draw_idle()来刷新图表。

三、程序具体代码实现

1. 引入库

代码如下:

import sys from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QSlider, QVBoxLayout, QHBoxLayout) from PyQt6.QtCore import Qt from PyQt6.QtGui import QFont from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib as mpl import numpy as np

2. 创建matplotlib画布类

实现代码如下:

# 创建matplotlib画布类 class MplCanvas(FigureCanvas): def __init__(self, parent=None, width=6.4, height=4.5, dpi=100): # figsize以英寸为单位,实际像素 = figsize×dpi‌(默认 dpi=100,则 8×6 英寸 → 800×600 像素) self.figure = Figure(figsize=(width,height), dpi=dpi) self.ax = self.figure.add_subplot(111) # self.add_line() super().__init__(self.figure) def add_line(self, a=1, b=0, c=0): # 初始曲线 mpl.rc('mathtext', fontset = "cm") # global fontset cm: Computer Modern(TeX) if a != 0: symmetry_x = -b/(2*a) # axis of symmetry vertex_y = (4*a*c - b*b)/(4*a) # 顶点的纵坐标 x = np.linspace(symmetry_x-10, symmetry_x+10, 100) y = a*x**2 + b*x + c self.ax.cla() self.ax.plot(x, y, color="blue", label=f"$f(x)={a}x^2+{b}x+{c}$") if a>0: # 抛物线开口向上 self.ax.set_ylim(bottom = vertex_y-10) # (bottom, top) else: self.ax.set_ylim(top = vertex_y+10) else: x = np.linspace(-10, 10, 100) y = b*x + c self.ax.cla() self.ax.plot(x, y, color="blue", label=f"$f(x)={b}x+{c}$") self.ax.grid(ls="--", alpha=0.4) self.ax.legend(framealpha=0) self.figure.tight_layout() # 解决子图重叠问题 # self.figure.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1) # 控制图形与画布边框之间的距离

3. 创建主窗口类

实现代码如下:

class MainWindow(QMainWindow): def __init__(self, parent = None): super().__init__(parent) #调用父类构造函数,创建窗体 self.initUI() def initUI(self): self.setWindowTitle("QSlider Demo") self.resize(640, 800) # slider1 self.labelSlider1Value = QLabel("1") self.labelSlider1Value.setAlignment(Qt.AlignmentFlag.AlignRight) # 设置QLabel内文本右对齐 self.horizontalSlider1 = QSlider() self.horizontalSlider1.setOrientation(Qt.Orientation.Horizontal) self.horizontalSlider1.setObjectName("horizontalSlider1") self.horizontalSlider1.setMinimum(-5) # 设置最小值 self.horizontalSlider1.setMaximum(5) # 设置最大值 self.horizontalSlider1.setSingleStep(1) # 步长 self.horizontalSlider1.setValue(1) # 设置当前值 self.horizontalSlider1.setTickPosition(QSlider.TickPosition.TicksBelow) self.horizontalSlider1.setTickInterval(1) # 设置刻度间距 self.horizontalSlider1.valueChanged.connect(self.valueChanged) # 使用valueChanged信号 hbox_layout1 = QHBoxLayout() # 创建水平排列布局 hbox_layout1.addWidget( QLabel("a (二次项系数)")) # 在布局中插入组件 hbox_layout1.addWidget(self.labelSlider1Value) # slider2 self.labelSlider2Value = QLabel("0") self.labelSlider2Value.setAlignment(Qt.AlignmentFlag.AlignRight) # 设置QLabel内文本右对齐 self.horizontalSlider2 = QSlider() self.horizontalSlider2.setOrientation(Qt.Orientation.Horizontal) self.horizontalSlider2.setObjectName("horizontalSlider2") self.horizontalSlider2.setMinimum(-10) # 设置最小值 self.horizontalSlider2.setMaximum(10) # 设置最大值 self.horizontalSlider2.setSingleStep(1) # 步长 self.horizontalSlider2.setValue(0) # 设置当前值 self.horizontalSlider2.setTickPosition(QSlider.TickPosition.TicksBelow) self.horizontalSlider2.setTickInterval(1) # 设置刻度间距 self.horizontalSlider2.valueChanged.connect(self.valueChanged) hbox_layout2 = QHBoxLayout() # 创建水平排列布局 hbox_layout2.addWidget(QLabel("b (一次项系数)")) # 在布局中插入组件 hbox_layout2.addWidget(self.labelSlider2Value) # slider3 self.labelSlider3Value = QLabel("0") self.labelSlider3Value.setAlignment(Qt.AlignmentFlag.AlignRight) # 设置QLabel内文本右对齐 self.horizontalSlider3 = QSlider() self.horizontalSlider3.setOrientation(Qt.Orientation.Horizontal) self.horizontalSlider3.setObjectName("horizontalSlider3") self.horizontalSlider3.setMinimum(-100) # 设置最小值 self.horizontalSlider3.setMaximum(100) # 设置最大值 self.horizontalSlider3.setSingleStep(5) # 步长 self.horizontalSlider3.setValue(0) # 设置当前值 self.horizontalSlider3.setTickPosition(QSlider.TickPosition.TicksBelow) self.horizontalSlider3.setTickInterval(5) # 设置刻度间距 self.horizontalSlider3.valueChanged.connect(self.valueChanged) hbox_layout3 = QHBoxLayout() # 创建水平排列布局 hbox_layout3.addWidget(QLabel("c (常数项)")) # 在布局中插入组件 hbox_layout3.addWidget(self.labelSlider3Value) hbox_layout4 = QHBoxLayout() hbox_layout4.addWidget(QLabel("提示:拖动滑块进行参数调整")) hbox_layout4.setAlignment(Qt.AlignmentFlag.AlignHCenter) self.canvas = MplCanvas(self, width=6.4, height=4.5, dpi=100) self.canvas.add_line(1, 0, 0) vbox_layout = QVBoxLayout() vbox_layout.addWidget(self.canvas) self.labelPrompt = QLabel("参数控制") self.labelPrompt.setFont(QFont('黑体', 16)) vbox_layout.addWidget(self.labelPrompt) vbox_layout.addWidget(self.horizontalSlider1) vbox_layout.addLayout(hbox_layout1) vbox_layout.addWidget(self.horizontalSlider2) vbox_layout.addLayout(hbox_layout2) vbox_layout.addWidget(self.horizontalSlider3) vbox_layout.addLayout(hbox_layout3) vbox_layout.addLayout(hbox_layout4) # vbox_layout.addStretch(1) # self.setLayout(vbox_layout) # 加入子布局 container = QWidget() container.setLayout(vbox_layout) # 加入子布局 self.setCentralWidget(container) # 设置主窗口的中心部件 def valueChanged(self): current_a = self.horizontalSlider1.value() # print('当前刻度值=%s' % currentValue) self.labelSlider1Value.setText(str(current_a)) current_b = self.horizontalSlider2.value() self.labelSlider2Value.setText(str(current_b)) current_c = self.horizontalSlider3.value() self.labelSlider3Value.setText(str(current_c)) self.canvas.add_line(current_a, current_b, current_c) # self.canvas.ax.relim() # 重置视图界限以适应新数据点 # self.canvas.ax.autoscale_view() # 自动缩放视图以适应新数据点 self.canvas.draw()

4. 主程序代码

主程序实现代码如下:

if __name__ == "__main__": # 用于当前窗体测试 app = QApplication(sys.argv) # 建立application对象 main_form = MainWindow() # 创建窗体 main_form.show() # 显示窗体 sys.exit(app.exec()) # 运行程序

四、总结

以上代码实现了一个包含抛物线绘制和动态更新功能的相对完整 PyQt6 应用程序。

其中自定义的MplCanvas继承自FigureCanvasQTAgg,封装了Matplotlib的Figure和Axes对象,使其能够像普通Qt控件一样被添加到布局中。

http://www.jsqmd.com/news/952851/

相关文章:

  • ZYNQ7000 PS端IO不够用?试试用AXI GPIO在Vivado里扩展32个引脚(附完整SDK代码)
  • 【从0到1实战FastAPI+AI开发学生信息管理系统(FastAPI+MySQL+Vue3)】
  • 告别Keil MDK:在Win10上用VSCode + CMake + GCC编译STM32G0项目(附完整CMakeLists.txt)
  • 从零搭建Python数据分析环境:手把手教你用Jupyter Notebook仪表盘管理你的第一个项目
  • 2026年5月口才学习品牌推荐,成人口才培训/当众讲话培训/口才学习/演讲培训/成人口才学习,口才学习品牌推荐分析 - 品牌推荐师
  • 计算机毕业设计之基于Hive的电影推荐系统的设计与实现
  • 别再只会调电阻了!深入555多谐振荡器公式,精准控制你的流水灯闪烁频率
  • 从信息论到特征工程:如何用k-近邻互信息为你的模型挑选‘黄金搭档’特征?
  • 数据侦查思维:用福尔摩斯方法论做现场勘查式分析
  • 2026年推荐几家面条机/玉米面条机用户口碑推荐厂家 - 行业平台推荐
  • 出口孟加拉务必留意信用证隐患,7万美金订单险些遭遇资金损失
  • ZYNQ7000项目实战:用AXI GPIO扩展PS端IO,告别EMIO的繁琐配置
  • 企业AI开发工具身份集成实践与安全架构设计
  • 告别CAN总线!手把手教你用Wireshark抓包分析DoIP诊断协议(ISO 13400实战)
  • ORBSLAM3 VIO精度评估实战:用KITTI数据集和evo工具完整走一遍
  • 2026年靠谱的九江工厂短视频拍摄/九江短视频/九江本地短视频线索投放热门公司推荐 - 行业平台推荐
  • 3步掌握LaTeX2Word-Equation:学术写作效率提升50%
  • 别再被CUDNN_STATUS_NOT_INITIALIZED搞懵了!手把手教你排查PyTorch+CUDA环境(附版本对照表)
  • STM32F401CC与CEU6傻傻分不清?一次搞懂MicroPython固件兼容性与硬件选型要点
  • 别再死记硬背了!用一张时序图彻底搞懂Setup和Hold的检查逻辑
  • WRF模式新手必看:从namelist.wps参数详解到网格嵌套设计实战(以一次模拟为例)
  • 保姆级教程:手把手教你用ORBSLAM3-VIO跑通KITTI数据集(含IMU参数配置与数据对齐)
  • 2026年推荐几家冷面机/面条切割机生产厂家推荐 - 品牌宣传支持者
  • web应用技术03-JDBC数据库操作
  • 2026年评价高的内蒙古残疾人劳务派遣/内蒙古劳务派遣哪家值得选 - 品牌宣传支持者
  • Redis 分布式锁进阶第七十1篇
  • 别再Ctrl+F了!用VLookup函数5分钟搞定Excel跨表数据匹配(附常见错误排查)
  • 如何快速提取Wallpaper Engine资源:RePKG完整工具使用指南
  • 入驻孟加拉难点梳理,详解各类市场准入限制条件
  • 从玩具四轴到工业电调:手把手拆解无刷电机六步换向,搞懂两两与三三导通对性能的实际影响