PyQT脚本中如何实现在单个窗口显示绘图而非每次弹出新窗口
我来帮你搞定这个问题!核心思路是只创建一次绘图窗口和轴对象,之后每次更新变量时,只清除旧的绘图内容并重新绘制,而不是新建figure并调用plt.show()弹出新窗口。下面分两种常见场景给你具体实现方案:
解决方法:复用同一个绘图窗口
场景1:在PyQt窗口中嵌入Matplotlib绘图(推荐)
这种方式能完美整合到你的PyQt界面里,所有绘图都在同一个窗口的指定区域更新,完全符合PyQt项目的开发逻辑:
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.patches as patches class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("复用绘图窗口") # 只初始化一次Matplotlib的figure和轴对象! self.figure = Figure() self.ax = self.figure.add_subplot(111, aspect='equal') self.canvas = FigureCanvas(self.figure) # 加个按钮用来触发绘图更新(你可以换成自己的变量修改触发逻辑) self.update_btn = QPushButton("更新绘图") self.update_btn.clicked.connect(self.update_plot) # 界面布局 central_widget = QWidget() layout = QVBoxLayout(central_widget) layout.addWidget(self.canvas) layout.addWidget(self.update_btn) self.setCentralWidget(central_widget) # 初始变量和绘图 self.x1, self.y1, self.r1 = 1, 1, 0.5 self.x2, self.y2, self.r2 = 2, 2, 0.5 self.x3, self.y3, self.r3 = 3, 1, 0.5 self.x_centroid, self.y_centroid = 2, 1.33 self.update_plot() def update_plot(self): # 每次更新前先清除轴上的旧内容 self.ax.clear() # 重新绘制所有图形 self.ax.add_patch(patches.Circle((self.x1, self.y1), self.r1, fill=False)) self.ax.add_patch(patches.Circle((self.x2, self.y2), self.r2, fill=False)) self.ax.add_patch(patches.Circle((self.x3, self.y3), self.r3, fill=False)) self.ax.plot([self.x_centroid], [self.y_centroid], 'ro') # 可选:固定轴范围,防止图形显示偏移 self.ax.set_xlim(0, 4) self.ax.set_ylim(0, 3) # 刷新画布显示新内容 self.canvas.draw() if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())
场景2:不嵌入PyQt界面,仅复用Matplotlib独立窗口
如果你的脚本不需要复杂的PyQt界面,只是希望Matplotlib绘图窗口不重复弹出,可以用这种轻量方式:
import matplotlib.pyplot as plt import matplotlib.patches as patches # 只初始化一次figure和ax,放在全局位置 fig2 = plt.figure() ax2 = fig2.add_subplot(111, aspect='equal') plt.ion() # 开启Matplotlib交互模式 plt.show(block=False) # 非阻塞显示窗口,不卡住脚本执行 def update_plot(x1, y1, r1, x2, y2, r2, x3, y3, r3, x_centroid, y_centroid): # 清除轴上的旧图形 ax2.clear() # 重新绘制内容 ax2.add_patch(patches.Circle((x1, y1), r1, fill=False)) ax2.add_patch(patches.Circle((x2, y2), r2, fill=False)) ax2.add_patch(patches.Circle((x3, y3), r3, fill=False)) ax2.plot([x_centroid], [y_centroid], 'ro') # 自动调整轴范围适配图形 ax2.set_xlim(min(x1-r1, x2-r2, x3-r3)-0.5, max(x1+r1, x2+r2, x3+r3)+0.5) ax2.set_ylim(min(y1-r1, y2-r2, y3-r3)-0.5, max(y1+r1, y2+r2, y3+r3)+0.5) # 刷新窗口显示 fig2.canvas.draw() fig2.canvas.flush_events() # 示例:模拟修改变量后更新绘图 if __name__ == "__main__": # 初始绘图 update_plot(1,1,0.5, 2,2,0.5, 3,1,0.5, 2,1.33) # 2秒后修改变量并更新 import time time.sleep(2) update_plot(1.5,1.5,0.6, 2.5,2,0.4, 3,1.5,0.5, 2.33,1.66)
核心注意点:
- 不要重复创建
plt.figure():把figure和轴对象的初始化放在外部,只执行一次。 - 用
clear()清除旧内容:每次更新前清除轴上的旧图形,而不是新建窗口。 - 刷新画布而非重新调用
plt.show():用canvas.draw()(PyQt嵌入场景)或者canvas.draw()+flush_events()(独立窗口场景)来更新显示,避免弹出新窗口。
这样无论你怎么修改变量,绘图都会在同一个窗口里更新啦!
内容的提问来源于stack exchange,提问作者Shubham Kuse
相关产品推荐
相关产品推荐

