Skip to content
Matplotlib与PySide6兼容性问题及解决方案

Matplotlib与PySide6兼容性问题及解决方案

August 4, 2025·chase
本文目录 展开章节导航

Matplotlib 与 PySide6 集成时,先区分“生成静态图片”和“把可交互画布嵌入 Qt 窗口”。当前 Qt 后端支持 PySide6;发生异常时应核对实际版本、导入顺序和 Qt 绑定,不能直接假定必须降级到旧版 PySide6。

1. 记录当前环境

python -m pip show matplotlib PySide6 PyQt5 PyQt6 toppra
python -m pip check
python -c "import sys, matplotlib; print(sys.executable); print(matplotlib.__version__)"

不要仅根据某篇旧教程推断第三方库要求 matplotlib<3.0。应查看正在使用的包版本与安装元数据。Matplotlib 2.2.3 与 PySide6 6.2 也不是本文建议的组合。

2. 仅保存图片:Agg

必须在导入 pyplot 之前选择后端:

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set(xlabel="x", ylabel="y", title="Headless rendering")
fig.savefig("output.png", dpi=150, bbox_inches="tight")
plt.close(fig)

Agg 不创建交互窗口,适合服务器批量出图;它不负责消除其他依赖问题。

3. 嵌入 Qt:使用 backend_qtagg

先导入所需的 Qt 绑定,再创建画布,避免环境中其他绑定先被选中:

import sys
import math
from PySide6.QtCore import QTimer
from PySide6.QtWidgets import QApplication, QMainWindow
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure


class PlotWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Matplotlib + PySide6")
        self.canvas = FigureCanvasQTAgg(Figure(figsize=(6, 4)))
        self.setCentralWidget(self.canvas)
        self.axes = self.canvas.figure.subplots()
        self.line, = self.axes.plot([], [])
        self.axes.set(xlabel="x", ylabel="sin(x + phase)")
        self.phase = 0.0
        self.update_plot()
        self.timer = QTimer(self)  # 随窗口销毁,不使用无父对象的临时定时器。
        self.timer.setInterval(100)
        self.timer.timeout.connect(self.update_plot)
        self.timer.start()

    def update_plot(self):
        xs = [i * 0.05 for i in range(126)]
        ys = [math.sin(x + self.phase) for x in xs]
        self.line.set_data(xs, ys)  # 复用同一条曲线,不在每次刷新时继续 plot。
        self.axes.relim()
        self.axes.autoscale_view()
        self.canvas.draw_idle()
        self.phase += 0.1

    def closeEvent(self, event):
        self.timer.stop()
        super().closeEvent(event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = PlotWindow()
    window.show()
    sys.exit(app.exec())

保存为 plot_window.py,在具有桌面显示权限的环境执行 python plot_window.py。需要缩放和平移工具栏时,可添加同一后端中的 NavigationToolbar2QTMatplotlib Qt 后端文档

曲线每 100 ms 请求一次重绘;draw_idle() 会等待 GUI 事件循环,必要时合并重绘,并不保证精确 10 FPS。关闭窗口会停止定时器;本示例不复用已经关闭的实例,需要再次打开时创建新窗口。持续自动缩放会影响手动缩放体验;实现交互浏览时应允许暂停刷新或固定坐标范围。

验收时连续更新几十次,检查 len(window.axes.lines) 仍为 1,关闭后 window.timer.isActive()False。无桌面环境可用 offscreen 平台做生命周期测试,但仍需在目标桌面验证实际显示。

4. 按症状排查

症状优先检查
导入时出现 Qt 枚举或符号错误实际导入的 Qt 绑定、版本及包来源
找不到 xcb 或无法连接 display显示会话与平台插件依赖
能保存图片但没有窗口是否选择了 Agg、是否进入 Qt 事件循环
更新曲线时卡顿或崩溃是否在主线程操作 GUI、是否重复创建 QApplication

数据计算可以放在工作线程,界面和画布更新通过 Qt 信号交给主线程。修改依赖后重启 Python 进程,以免旧 Qt 动态库仍留在进程中。

阅读自测与验收

  • 重复打开、更新和关闭绘图窗口,确认 QApplication、Canvas、定时器与窗口生命周期一致。
  • 从工作线程获取数据时通过信号回到 GUI 线程更新界面;刷新频率应与数据速率和绘制成本匹配。
Last updated on