Matplotlib工具栏在PySimpleGUI或Tkinter中不显示图标,仅显示重叠文字按钮
看起来你在Mac环境下遇到了Matplotlib工具栏嵌入PySimpleGUI后,图标不显示、按钮文字重叠的问题,我之前在Mac上开发时也碰到过类似情况,结合你的版本信息(Python3.9.12、Matplotlib3.7.1、PySimpleGUI4.60.4),给你几个针对性的解决方案:
问题根源分析
Mac系统下的Tkinter对Matplotlib的图标渲染有特殊兼容情况,再加上你布局里的控制栏Canvas没有设置足够尺寸,导致按钮挤在一起文字重叠;另外你自定义的Toolbar类没有额外功能,反而可能干扰了原生工具栏的图标加载逻辑。
具体解决方案
1. 显式指定Matplotlib后端
在导入Matplotlib相关模块后,强制指定使用TkAgg后端,避免Mac默认后端导致图标加载失败:
import matplotlib.pyplot as plt plt.switch_backend('TkAgg') # 新增这一行 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
2. 移除自定义Toolbar类,使用原生组件
你自定义的Toolbar类没有添加任何额外功能,反而可能破坏了原生工具栏的图标加载流程。直接删掉这个类,在draw_figure_w_toolbar函数中使用原生的NavigationToolbar2Tk:
def draw_figure_w_toolbar(canvas, fig, canvas_toolbar): if canvas.children: for child in canvas.winfo_children(): child.destroy() if canvas_toolbar.children: for child in canvas_toolbar.winfo_children(): child.destroy() figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas) figure_canvas_agg.draw() # 使用原生工具栏,替换自定义的Toolbar类 toolbar = NavigationToolbar2Tk(figure_canvas_agg, canvas_toolbar) toolbar.update() figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1)
3. 调整控制栏Canvas的尺寸
你的布局中controls_cv这个Canvas没有设置尺寸,导致工具栏按钮挤在一起重叠。修改布局里的Canvas定义,给它一个合适的宽度和高度:
[sg.T('Controls:')], [sg.Canvas(key='controls_cv', size=(800, 40))], # 新增size参数
4. 升级PySimpleGUI到最新版本
你使用的4.60.4版本相对较旧,新版本修复了很多Mac平台的兼容问题。执行以下命令升级:
pip install --upgrade PySimpleGUI
修改后的完整代码示例
import PySimpleGUI as sg import numpy as np """ Embedding the Matplotlib toolbar into your application """ # ------------------------------- This is to include a matplotlib figure in a Tkinter canvas import matplotlib.pyplot as plt plt.switch_backend('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk def draw_figure_w_toolbar(canvas, fig, canvas_toolbar): if canvas.children: for child in canvas.winfo_children(): child.destroy() if canvas_toolbar.children: for child in canvas_toolbar.winfo_children(): child.destroy() figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas) figure_canvas_agg.draw() toolbar = NavigationToolbar2Tk(figure_canvas_agg, canvas_toolbar) toolbar.update() figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1) # ------------------------------- PySimpleGUI CODE layout = [ [sg.T('Graph: y=sin(x)')], [sg.B('Plot'), sg.B('Exit')], [sg.T('Controls:')], [sg.Canvas(key='controls_cv', size=(800, 40))], [sg.T('Figure:')], [sg.Column( layout=[ [sg.Canvas(key='fig_cv', # it's important that you set this size size=(400 * 2, 400) )] ], background_color='#DAE0E6', pad=(0, 0) )], [sg.B('Alive?')] ] window = sg.Window('Graph with controls', layout) if __name__ == "__main__": while True: event, values = window.read() print(event, values) if event in (sg.WIN_CLOSED, 'Exit'): # always, always give a way out! break elif event == 'Plot': # ------------------------------- PASTE YOUR MATPLOTLIB CODE HERE plt.figure(1) fig = plt.gcf() DPI = fig.get_dpi() # ------------------------------- you have to play with this size to reduce the movement error when the mouse hovers over the figure, it's close to canvas size fig.set_size_inches(404 * 2 / float(DPI), 404 / float(DPI)) # ------------------------------- x = np.linspace(0, 2 * np.pi) y = np.sin(x) plt.plot(x, y) plt.title('y=sin(x)') plt.xlabel('X') plt.ylabel('Y') plt.grid() # ------------------------------- Instead of plt.show() draw_figure_w_toolbar(window['fig_cv'].TKCanvas, fig, window['controls_cv'].TKCanvas) window.close()
如果以上方案还是无法解决问题,可以尝试重置Matplotlib的配置文件(删除~/.matplotlib目录下的缓存文件),或者检查Mac上的Tkinter是否为完整版本(Python3.9自带的Tkinter一般没问题,若缺失可以通过Homebrew安装tcl-tk)。
备注:内容来源于stack exchange,提问作者WBT

