如何在PyQt6的Matplotlib画布中添加新Figure对象而不清除原有绘图
问题:在PyQt6的Matplotlib画布中叠加绘制独立Figure对象
我正在用PyQt6构建带Matplotlib图形可视化的GUI,待展示的图形由函数生成并返回独立的matplotlib.figure.Figure对象(该对象不由pyplot管理,且不愿修改此生成方式)。现在需要实现:在已绘制过图形的同一个Matplotlib画布中,叠加绘制新的Figure对象,且不清除原有绘图。
现有MplWidget的最小可运行示例中,update_figure方法已实现替换画布内容(绘制首个Figure),但add_figure方法尚未实现叠加功能:
# ------------------------------------------------------ # -------------------- mplwidget.py -------------------- # ------------------------------------------------------ from PyQt6.QtWidgets import* from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg from matplotlib.figure import Figure from PyQt6.QtGui import QFont, QFontInfo import matplotlib.pyplot as plt import matplotlib matplotlib.use('Qt5Agg') class MplWidget(QWidget): def __init__(self, parent = None): super(QWidget, self).__init__() self.canvas = FigureCanvasQTAgg(Figure()) vertical_layout = QVBoxLayout() vertical_layout.addWidget(self.canvas) self.canvas.axes = self.canvas.figure.add_subplot(111) self.canvas.draw() # 获取系统默认字体并应用到画布 self.resetFontStyle() self.setLayout(vertical_layout) def update_figure(self, new_figure): # new_figure 是 matplotlib Figure 对象 # 清除现有内容 self.canvas.figure.clf() self.canvas.axes = self.canvas.figure.add_subplot(111) # 复制新Figure的内容到当前画布 # 修正原逻辑:避免直接替换figure对象导致绑定异常 for ax in new_figure.get_axes(): for line in ax.get_lines(): self.canvas.axes.plot(line.get_xdata(), line.get_ydata(), label=line.get_label(), **line.get_properties()) # 同步轴标签、标题 self.canvas.axes.set_xlabel(ax.get_xlabel()) self.canvas.axes.set_ylabel(ax.get_ylabel()) self.canvas.axes.set_title(ax.get_title()) self.canvas.draw() def add_figure(self, new_figure): # new_figure 是 matplotlib Figure 对象 # 遍历新Figure的所有子图 for new_ax in new_figure.get_axes(): # 复制子图中的线条类元素(plot曲线等) for line in new_ax.get_lines(): self.canvas.axes.plot(line.get_xdata(), line.get_ydata(), label=line.get_label(), **line.get_properties()) # 复制散点图元素 for collection in new_ax.collections: if isinstance(collection, matplotlib.collections.PathCollection): self.canvas.axes.scatter(collection.get_offsets()[:,0], collection.get_offsets()[:,1], s=collection.get_sizes(), c=collection.get_facecolors(), label=collection.get_label()) # 可选:同步轴标签(按需开启) # self.canvas.axes.set_xlabel(new_ax.get_xlabel()) # self.canvas.axes.set_ylabel(new_ax.get_ylabel()) # 添加图例(如果元素带标签) self.canvas.axes.legend() # 重绘画布 self.canvas.draw() def resetFontStyle(self): font = QFont() font_info = QFontInfo(font) matplotlib.rcParams['font.family'] = font_info.family() matplotlib.rcParams['font.size'] = font.pointSize()
关键实现说明
- 避免直接替换Figure对象:原
update_figure中直接替换self.canvas.figure = new_figure会导致画布与原Figure的绑定关系失效,改为复制子图元素到当前画布的轴中。 - 叠加绘制核心逻辑:
- 遍历新Figure的所有子图(
new_figure.get_axes()) - 提取子图中的线条(
get_lines())、散点(collections)等可视化元素,完整复制样式(颜色、标签、大小等)到当前画布的轴上
- 遍历新Figure的所有子图(
- 可选扩展:如果需要支持直方图、柱状图等其他类型的绘图,需对应提取
patches等元素并复制。
内容的提问来源于stack exchange,提问作者ren1
相关产品推荐
相关产品推荐

