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

PySimpleGUI更新Matplotlib图表时画布逐次变大问题求解

问题根因

窗口逐次变大的核心诱因有三点:

  1. 每次更新绘图时都通过plt.gcf()获取全局画布,matplotlib在无活跃画布时会自动创建新的默认尺寸画布,反复往Tk容器中嵌入新画布控件时,控件会自动计算可用空间,导致尺寸逐次累加变大。
  2. 旧画布清理逻辑不完整,仅用forget()把控件从布局中隐藏,没有彻底销毁控件实例,残留的尺寸属性会干扰新画布的渲染计算。
  3. 事件循环未做拦截,窗口初始化、关闭等非更新事件也会触发绘图逻辑,进一步放大尺寸异常。
修复方案
  • 初始化阶段就创建固定尺寸的matplotlib画布和绘图轴,后续更新仅清空轴内曲线重绘,全程不新建画布实例。
  • 补全旧控件销毁逻辑,清理画布时直接调用destroy()彻底释放控件实例,不要仅用forget()隐藏。
  • 给事件循环加判断逻辑,仅滑块拖动、Plot按钮点击时触发重绘,窗口关闭事件直接退出循环。
  • 可手动固定绘图轴的坐标范围,避免重绘时视图自动缩放导致的显示跳动。
修复后完整代码
import numpy as np
import PySimpleGUI as sg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

# 初始化固定尺寸的画布,全程复用不新建
fig = Figure(figsize=(4, 4), dpi=100)
ax = fig.add_subplot(111)

def fun(ax, nu):
    ax.clear()  # 每次重绘前清空旧曲线
    x = np.arange(1, 10, 0.1)
    ax.plot(x, nu * x)
    ax.set_ylim(0, 10)  # 固定Y轴范围,避免视图跳动

sg.theme('SandyBeach')  

# 参数输入窗口
param_layout = [
    [sg.Text('nu_min', size=(15, 1)), sg.InputText(0.2, key='-nu_min-')],
    [sg.Text('nu_max', size=(15, 1)), sg.InputText(1, key='-nu_max-')],
    [sg.Text('nu_step', size=(15, 1)), sg.InputText(0.1, key='-nu_step-')],
    [sg.Submit('Run'), sg.Cancel()]
]
param_window = sg.Window('参数设置', param_layout)
event, values = param_window.read()
param_window.close()
if event in (sg.WIN_CLOSED, 'Cancel'):
    exit()

nu_min = float(values['-nu_min-'])
nu_max = float(values['-nu_max-'])
nu_step = float(values['-nu_step-'])

def draw_figure(canvas, figure):
    figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
    figure_canvas_agg.draw()
    figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
    return figure_canvas_agg

# 绘图窗口布局
figure_w, figure_h = 400, 400
main_layout = [
    [sg.Text('滑块控制函数绘图', justification='center', relief=sg.RELIEF_SUNKEN, expand_x=True, font='Courier 18')],
    [sg.Button('Plot'), sg.Cancel(), sg.Button('Popup')],
    [sg.Canvas(size=(figure_w, figure_h), key='-CANVAS-')],
    [sg.Text('nu', font='Courier 14'), sg.Slider((nu_min, nu_max), default_value=nu_min, resolution=nu_step, orientation='h', enable_events=True, key='-slider_nu-', expand_x=True)]
]

main_window = sg.Window('绘图界面', main_layout, finalize=True)
# 首次渲染画布
figure_agg = draw_figure(main_window['-CANVAS-'].TKCanvas, fig)
fun(ax, nu_min)
figure_agg.draw()

# 事件循环
while True:
    event, values = main_window.read()
    if event in (sg.WIN_CLOSED, 'Cancel'):
        break
    # 仅滑块拖动/Plot按钮触发重绘
    if event in ('-slider_nu-', 'Plot'):
        fun(ax, values['-slider_nu-'])
        figure_agg.draw()

main_window.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:27:26