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

Python使用Tkinter+Matplotlib实现用户自定义函数绘图的问题咨询

实现方案

核心是通过eval()函数将函数字符串解析为可执行的表达式,同时做输入预处理和异常处理保证程序稳定性,具体修改如下:

核心修改逻辑

  1. 预处理用户输入:去除y = 这类前缀,仅保留关于x的表达式部分
  2. 执行表达式时限定命名空间,仅允许调用numpy库和预设的x变量,降低eval()的安全风险
  3. 异常捕获:处理用户输入非法表达式的场景,避免程序直接崩溃
  4. 优化绘图逻辑:把画布和工具栏初始化放到点击事件外,避免重复生成组件

修改后完整代码

import matplotlib
matplotlib.use("TkAgg")
import numpy as np
from tkinter import messagebox

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure

import tkinter as tk
from tkinter import ttk

LARGE_FONT=("Times New Roman",12)
x=np.linspace(-5,5,100)


class MyApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self,*args,**kwargs)
        tk.Tk.wm_title(self, "My app")
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}
        for F in (StartPage, GraphPage):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column = 0, sticky="nsew")
        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class StartPage(tk.Frame):
    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self,text="Ed. App - Start Page",font = LARGE_FONT)
        label.pack(pady=10,padx=10)
        button3 = ttk.Button(self, text="Go to graph page ->", command = lambda:controller.show_frame(GraphPage))
        button3.pack()

class GraphPage(tk.Frame):
    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        # 输入框
        self.e = tk.Entry(self, width =50)
        self.e.pack()
        label = tk.Label(self,text="Graph your function! 输入示例:np.sin(x)、x**2+2*x",font = LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back to Home", command = lambda:controller.show_frame(StartPage))
        button1.pack()

        # 绘图相关初始化放到点击事件外,避免重复生成
        self.f = Figure(figsize=(5,5), dpi=100)
        self.a = self.f.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.f, self)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.toolbar = NavigationToolbar2Tk(self.canvas, self)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

        def myClick():
            func_str = self.e.get().strip()
            # 处理y=开头的输入
            if func_str.lower().startswith('y='):
                func_str = func_str[2:].strip()
            try:
                # 限定命名空间,仅允许使用np和x,屏蔽内置危险函数
                y = eval(func_str, {"np": np, "x": x, "__builtins__": {}})
                # 每次绘图前清空旧图像
                self.a.clear()
                self.a.plot(x,y,'r')
                # 刷新画布
                self.canvas.draw()
            except Exception as e:
                messagebox.showerror("输入错误", f"函数表达式不合法:{str(e)}")

        button4 = ttk.Button(self, text="plot", command = myClick)
        button4.pack()

app = MyApp()
app.mainloop()

注意事项

  • 个人使用场景下eval()完全够用,若要面向公开用户部署,可改用numexpr库或者自定义语法解析器进一步提升安全性
  • 输入时直接写x**2、np.cos(x)、np.log(x)这类表达式即可,也支持带y=前缀的输入格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 11:36:08