如何在Tkinter中显示Matplotlib 3D绘图并保留Canvas背景色
问题描述
我有一段生成3D曲面图的Matplotlib代码:
import numpy as np import matplotlib.pyplot as plt # 创建figure对象 surf_3D = plt.figure() # 创建3D坐标轴对象 axes_3d = plt.axes(projection = "3d") # 生成X和Y数据 x_demo3d = np.arange(-5,5,0.1) y_demo3d = np.arange(-5,5,0.1) # 创建网格数据 X3,Y3 = np.meshgrid(x_demo3d, y_demo3d) # 生成Z数据(正弦余弦组合) Z3 = np.sin(X3) * np.cos(Y3) # 绘制3D曲面 axes_3d.plot_surface(X3, Y3, Z3, cmap = "plasma") # 设置坐标轴面板透明 axes_3d.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) # 隐藏坐标轴刻度 axes_3d.set_xticks([]) axes_3d.set_yticks([]) axes_3d.set_zticks([]) # 显示图形 surf_3D.show()
这段代码能生成正常的3D曲面图。
之后我尝试把这个3D绘图嵌入到Tkinter窗口的深红色背景Canvas中,代码如下:
import numpy as np import matplotlib.pyplot as plt from tkinter import * from matplotlib.backends.backend_tkagg import ( FigureCanvasTkAgg, NavigationToolbar2Tk) class Program_Class: def __init__(self, master): # 主窗口参数设置 Main.resizable(0,0) Main.geometry("900x550") Main.title("Main") # 创建figure对象 surf_3D = plt.figure(figsize=(2,2)) # 创建3D坐标轴对象 axes_3d = plt.axes(projection = "3d") # 生成X和Y数据 x = np.arange(-5,5,0.1) y = np.arange(-5,5,0.1) # 创建网格数据 x, y = np.meshgrid(x, y) # 生成Z数据(正弦余弦组合) z = np.sin(x) * np.cos(y) # 绘制3D曲面 axes_3d.plot_surface(x, y, z, cmap = "plasma") # 设置坐标轴面板透明 axes_3d.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) # 隐藏坐标轴刻度 axes_3d.set_xticks([]) axes_3d.set_yticks([]) axes_3d.set_zticks([]) # 尝试将绘图嵌入Canvas(背景色设为深红色#8B0000) Canvas_demo3d = Canvas(Main, width=300, height =200, borderwidth=0, highlightthickness=0, bg='#8B0000') Canvas_demo3d = FigureCanvasTkAgg(surf_3D, master=Main) Canvas_demo3d.get_tk_widget().place(x=300,y=71) Canvas_demo3d.draw() Main = Tk() Program_Class(Main) Main.mainloop()
实际运行后发现,绘图占据了Canvas的全部空间,看不到设置的深红色背景。请问如何修改代码,让未被绘图覆盖的Canvas区域显示自定义背景色,同时正常展示3D曲面图?
解决方案
问题根源是你创建Tkinter Canvas后,用FigureCanvasTkAgg对象覆盖了它的变量引用,且Matplotlib的figure默认白色背景会挡住下方Canvas。修改步骤如下:
- 保留Tkinter Canvas作为底层背景,不覆盖变量
- 设置Matplotlib的figure和坐标轴背景为透明,让底层Canvas颜色透出
- 将Matplotlib绘图控件放置在背景Canvas上方
修改后的完整代码:
import numpy as np import matplotlib.pyplot as plt from tkinter import * from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg class Program_Class: def __init__(self, master): # 主窗口参数设置 master.resizable(0,0) master.geometry("900x550") master.title("Main") # 1. 创建深红色背景的Canvas作为底层 canvas_bg = Canvas(master, width=300, height=200, borderwidth=0, highlightthickness=0, bg='#8B0000') canvas_bg.place(x=300, y=71) # 2. 创建Matplotlib figure并设置背景透明 surf_3D = plt.figure(figsize=(2,2), facecolor='none') # 创建3D坐标轴并设置背景透明 axes_3d = plt.axes(projection="3d", facecolor='none') # 生成数据和绘制曲面 x = np.arange(-5,5,0.1) y = np.arange(-5,5,0.1) x, y = np.meshgrid(x, y) z = np.sin(x) * np.cos(y) axes_3d.plot_surface(x, y, z, cmap="plasma") # 设置坐标轴面板透明 axes_3d.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) axes_3d.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) # 隐藏坐标轴刻度 axes_3d.set_xticks([]) axes_3d.set_yticks([]) axes_3d.set_zticks([]) # 3. 创建Matplotlib画布并绑定到背景Canvas,放置在上方 canvas_plot = FigureCanvasTkAgg(surf_3D, master=canvas_bg) canvas_plot.get_tk_widget().pack(fill=BOTH, expand=True) canvas_plot.draw() Main = Tk() Program_Class(Main) Main.mainloop()
关键修改说明:
- 拆分变量:将原
Canvas_demo3d拆分为canvas_bg(底层背景)和canvas_plot(Matplotlib绘图控件),避免变量覆盖 - 透明设置:创建
plt.figure时添加facecolor='none',创建3D坐标轴时添加facecolor='none',让底层背景透出 - 层级绑定:把Matplotlib绘图控件绑定到背景Canvas上,通过
pack适配Canvas大小,确保绘图区域外显示深红色背景
内容的提问来源于stack exchange,提问作者i33SoDA
相关产品推荐
相关产品推荐

