PyQt+Matplotlib绘图在不同显示器上出现异常行为
问题分析与解决方案
你的代码实现存在错误,并非Matplotlib与PyQt的Bug,问题出在重复创建画布+混用全局pyplot接口的逻辑上,不同显示器的表现差异是因为DPI缩放设置不同,错误在高DPI环境(通常笔记本屏幕)下暴露更明显。
核心错误点
- 每次点击按钮都创建新的
FigureCanvasQTAgg实例,并用replaceWidget替换旧画布,但旧画布未被正确销毁,导致资源泄漏和渲染冲突 - 使用全局的
plt.plot()绘图,而非绑定到当前轴对象self.ax,会干扰Matplotlib的内部状态,重复绘制时出现线条叠加/变粗的问题 - 替换画布的操作会打乱Qt的布局管理,在窗口resize时触发布局错乱
修正后的代码
import matplotlib.pyplot as plt from random import random from PyQt6 import QtWidgets from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg class Window(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.resize(1126, 568) self.centralwidget = QtWidgets.QWidget() self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.pushButtonConnect = QtWidgets.QPushButton("Connect") self.gridLayout.addWidget(self.pushButtonConnect, 0, 0, 1, 1) self.setCentralWidget(self.centralwidget) # 初始化画布和轴,复用同一实例 self.fig, self.ax = plt.subplots() self.canvas = FigureCanvasQTAgg(self.fig) self.gridLayout.addWidget(self.canvas, 0, 1, 1, 1) self.pushButtonConnect.clicked.connect(self.runGraph) self.ax.set_xlim([0, 1]) self.ax.set_ylim([0, 1]) # 初始绘制空白画布 self.canvas.draw() def runGraph(self): # 可选:如果需要每次点击清空旧数据,取消下面注释 # self.ax.clear() # self.ax.set_xlim([0, 1]) # self.ax.set_ylim([0, 1]) # 使用当前轴对象绘图,而非全局plt self.ax.plot([random(), random()], [random(), random()]) # 刷新画布即可,无需替换 self.canvas.draw_idle() if __name__ == "__main__": app = QtWidgets.QApplication([]) win = Window() win.show() app.exec()
关键修改说明
- 复用画布实例:全程使用同一个
self.canvas,不再创建新实例替换,避免布局和资源问题 - 绑定轴对象绘图:用
self.ax.plot()替代plt.plot(),确保绘图操作仅作用于当前窗口的图表,不干扰全局状态 - 刷新画布而非替换:调用
self.canvas.draw_idle()高效刷新图表显示,这是Matplotlib在Qt中更新绘图的标准方式 - 可选清空旧数据:如果需要每次点击显示全新数据而非叠加,取消
self.ax.clear()及重置坐标轴范围的注释即可
内容的提问来源于stack exchange,提问作者cozimus77
相关产品推荐
相关产品推荐

