You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将matplotlib FuncAnimation嵌入tkinter时出现双绘图问题

解决方案

问题出在plt.show()调用——当你把matplotlib绘图嵌入tkinter窗口时,这个函数会触发matplotlib默认后端创建独立的绘图窗口,而我们已经通过FigureCanvasTkAgg将画布绑定到tkinter组件上,完全不需要这个调用。

按以下步骤修改代码即可解决:

  1. 删除plt.show():这是产生额外窗口的直接原因,移除后不会再弹出独立的matplotlib窗口。
  2. 保留动画对象引用:将ani1设为实例属性(self.ani1),避免Python垃圾回收机制回收动画对象导致更新停止。
  3. 修正方法调用:原代码中plotting_function()应该改为self.plotting_function(),否则无法调用实例方法。
  4. (可选)指定tkinter后端:在文件开头添加plt.switch_backend('TkAgg'),确保matplotlib使用tkinter作为绘图后端,避免潜在的后端冲突。

修改后的VisualizationPage1类代码:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.animation import FuncAnimation

plt.switch_backend('TkAgg')  # 可选但推荐

class VisualizationPage1():
    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        # Define self.body_sublabelframe2 and other frames

        self.plotting_function()  # 修正为实例方法调用

    def plotting_function(self):
        x_val = []
        y_val = []

        figure1 = plt.figure(figsize=(8, 8), linewidth=5, edgecolor="#04253a", dpi=35)
        ax1 = figure1.add_subplot(111)
        canvas_1 = FigureCanvasTkAgg(figure1, self.body_sublabelframe2)
        canvas_1.get_tk_widget().grid(row=0, column=0)

        ax1.legend(["Some Legend"])
        ax1.set_xlabel("X Label")
        ax1.set_ylabel("Y Label")
        ax1.set_title("Plot Title")

        def animate(i):
            x_val.append(len(x_val))
            y_val.append(2 ** len(y_val))

            ax1.cla()
            ax1.plot(x_val, y_val)
            ax1.legend(["Some Legend"])  # 每次cla后需要重新添加图例,否则会消失
            ax1.set_xlabel("X Label")
            ax1.set_ylabel("Y Label")
            ax1.set_title("Plot Title")

        self.ani1 = FuncAnimation(figure1, animate, interval=100)  # 设为实例属性
        # 移除plt.show()

优化补充

因为每次animate函数里调用ax1.cla()会清除坐标轴的所有设置(包括图例、标签、标题),所以需要在animate里重新添加这些元素。如果想提升动画性能并避免重复设置样式,可以改用更新线条数据的方式,示例如下:

def plotting_function(self):
    x_val = []
    y_val = []

    figure1 = plt.figure(figsize=(8, 8), linewidth=5, edgecolor="#04253a", dpi=35)
    ax1 = figure1.add_subplot(111)
    line, = ax1.plot(x_val, y_val)  # 保存线条对象

    ax1.legend(["Some Legend"])
    ax1.set_xlabel("X Label")
    ax1.set_ylabel("Y Label")
    ax1.set_title("Plot Title")

    def animate(i):
        x_val.append(len(x_val))
        y_val.append(2 ** len(y_val))
        line.set_data(x_val, y_val)  # 直接更新线条数据
        ax1.relim()  # 更新坐标轴范围
        ax1.autoscale_view()  # 自动调整视图

    self.ani1 = FuncAnimation(figure1, animate, interval=100)

这种方式避免了每次清除和重绘坐标轴,动画性能更好,样式也能保持一致。

内容的提问来源于stack exchange,提问作者Amazonian_panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:16:12