如何基于复杂Matplotlib代码构建Tkinter页面以显示绘图
Tkinter集成Matplotlib复杂绘图实现
要实现点击按钮显示复杂Matplotlib绘图的Tkinter界面,核心是将Matplotlib的绘图逻辑嵌入Tkinter窗口,以下是完整实现方案:
实现步骤
- 导入Tkinter及Matplotlib的Tk后端模块,替代直接使用pyplot的全局绘图方式
- 将原有Matplotlib绘图逻辑封装为函数,使用
matplotlib.figure.Figure创建绘图对象 - 创建Tkinter主窗口,添加触发按钮,点击按钮时调用绘图函数并将画布嵌入窗口
完整代码
import math import numpy import tkinter as tk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk # 原有的Panel类保持不变 class Panel: def __init__(self, xa, ya, xb, yb): self.xa, self.ya = xa, ya self.xb, self.yb = xb, yb self.xc, self.yc = (xa + xb) / 2, (ya + yb) / 2 self.length = math.sqrt((xb - xa)**2 + (yb - ya)**2) if xb - xa <= 0.: self.beta = math.acos((yb - ya) / self.length) elif xb - xa > 0.: self.beta = math.pi + math.acos(-(yb - ya) / self.length) self.sigma = 1000.0 # source strength self.vt = 1.0 # tangential velocity self.cp = 1.0 # pressure coefficient # 原有的Source类保持不变 class Source: def __init__(self, strength, x, y): self.strength = strength self.x, self.y = x, y def velocity(self, X, Y): u = (self.strength / (2 * math.pi) * (self.x - X) / (X **2 + Y **2)) v = (self.strength / (2 * math.pi) * (self.y - Y) / (X **2 + Y **2)) return u, v def stream_function(self, X, Y): psi = (self.strength / (2 * math.pi) * numpy.arctan2((Y - self.y), (X - self.x))) return psi # 封装绘图函数,用于按钮点击触发 def plot_complex_figure(frame): # 清空之前的画布,避免重复绘制 for widget in frame.winfo_children(): widget.destroy() # 原有绘图数据计算逻辑 u_inf = 5.0 N = 500 R = 5 x_center, y_center = 0.0, 0.0 theta = numpy.linspace(0.0, 2 * math.pi, 100) x_cylinder, y_cylinder = (x_center + R * numpy.cos(theta), y_center + R * numpy.sin(theta)) x_start, x_end = -10.1, 10.1 y_start, y_end = -10.1, 10.1 x = numpy.linspace(x_start, x_end, N) y = numpy.linspace(y_start, y_end, N) X, Y = numpy.meshgrid(x, y) strength_source = 5.0 x_source, y_source = 0.0, 0.0 source = Source(strength_source,x_source, y_source) u1, v1 = source.velocity(X, Y) psi1 = source.stream_function(X, Y) source_image = Source(strength_source, x_source, -y_source) u2, v2 = source_image.velocity(X, Y) psi2 = source_image.stream_function(X, Y) N_panels = 100 x_ends = R * numpy.cos(numpy.linspace(0.0, 2 * math.pi, N_panels + 1)) y_ends = R * numpy.sin(numpy.linspace(0.0, 2 * math.pi, N_panels + 1)) panels = numpy.empty(N_panels, dtype=object) for i in range(N_panels): panels[i] = Panel(x_ends[i], y_ends[i], x_ends[i + 1], y_ends[i + 1]) u = u1 + u2 v = v1 + v2 psi = psi1 + psi2 # 创建Matplotlib Figure对象,替代pyplot.figure size = 12 fig = Figure(figsize=(size, size)) ax = fig.add_subplot(111) # 在子图上绘制所有元素 ax.grid() ax.set_xlabel('x', fontsize=16) ax.set_ylabel('y', fontsize=16) ax.plot(x_cylinder, y_cylinder, color='b', linestyle='-', linewidth=1) ax.plot(x_ends, y_ends, color='#CD2305', linestyle='-', linewidth=2) ax.scatter([p.xa for p in panels], [p.ya for p in panels], color='#CD2305', s=40) ax.scatter([p.xc for p in panels], [p.yc for p in panels], color='k', s=40, zorder=3) ax.legend(loc='best', prop={'size':16}) ax.streamplot(X, Y, u, v, density=4, linewidth=0.6, arrowsize=2, arrowstyle='->') ax.set_xlim(-10.1, 10.1) ax.set_ylim(-10.1, 10.1) # 将Figure转换为Tkinter可用的画布 canvas = FigureCanvasTkAgg(fig, master=frame) canvas.draw() # 添加Matplotlib工具栏,不需要可注释 toolbar = NavigationToolbar2Tk(canvas, frame) toolbar.update() # 将画布显示在窗口中 canvas.get_tk_widget().pack(fill=tk.BOTH, expand=1) # 创建Tkinter主窗口 root = tk.Tk() root.title("Matplotlib绘图演示") # 创建按钮和绘图区域 button_frame = tk.Frame(root) button_frame.pack(pady=10) plot_btn = tk.Button(button_frame, text="显示复杂绘图", command=lambda: plot_complex_figure(plot_frame)) plot_btn.pack() plot_frame = tk.Frame(root) plot_frame.pack(fill=tk.BOTH, expand=1) # 启动Tkinter事件循环 root.mainloop()
关键说明
- 使用
matplotlib.figure.Figure创建绘图对象,避免依赖pyplot的全局状态,更适配GUI嵌入场景 FigureCanvasTkAgg负责将Matplotlib的Figure转换为Tkinter可识别的组件- 按钮点击时先清空绘图区域再重新绘制,避免重复叠加
- 可选的
NavigationToolbar2Tk提供缩放、平移等标准绘图操作工具,无需可直接注释
内容的提问来源于stack exchange,提问作者Bryant Hernandez
相关产品推荐
相关产品推荐

