import tkinter as tk from tkinter import messagebox from collections import OrderedDict from mpl_toolkits import axisartist from sympy import sympify, SympifyError from scipy.optimize import curve_fit from tkinter import filedialog import numpy as np import matplotlib.pyplot as plt from formula import expression_output index = 1 def check_formula_syntax(formula): try: sympify(formula) return True except SympifyError: return False # 创建弹出窗口 def creat_window(title): top = tk.Toplevel(Root) top.geometry("300x350") top.title(title) return top # 输入框 def create_input_box(top, text, value): box_label = tk.Label(top, text=text) box_label.pack(padx=10, pady=10) box_size = tk.IntVar(top, value=value) # 创建一个IntVar对象,并设置默认值为3 box_size_entry = tk.Entry(top, textvariable=box_size) # 关联IntVar对象 box_size_entry.pack(padx=20, pady=20) return box_size_entry def askfile():# 从本地选择一个文件,并返回文件的路径 global sampleData # 弹出文件选择对话框,选择要打开的文本文件 file_path = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')]) # 如果没有选择文件,直接返回 if not file_path: return x, y = [], []#初始化x,y with open(file_path, 'r') as file: for line in file:#逐行读文件 line = line.strip('\n')#移除换行符 sx, sy = line.split(' ')#以空格分割x,y x.append(float(sx))#将sx转换为浮点数并加入数组 y.append(float(sy))#将sy转换为浮点数并加入数组 X, Y = np.array(x), np.array(y)#x,y数组转为array并赋值给全局变量 sampleData.append(X) sampleData.append(Y) print(sampleData) def create_func(code_str): # 创建一个空的命名空间 namespace = {} # 使用exec函数执行字符串代码,并指定命名空间为locals exec(code_str, globals(), namespace) # 返回命名空间中的函数对象 return namespace['func'] def draw_axis(low, high, step=250): fig = plt.figure(figsize=(4.4, 3.2)) ax = axisartist.Subplot(fig, 111)# 使用axisartist.Subplot方法创建一个绘图区对象ax fig.add_axes(ax)# 将绘图区对象添加到画布中 ax.axis[:].set_visible(False)# 通过set_visible方法设置绘图区所有坐标轴隐藏 ax.axis["x"] = ax.new_floating_axis(0, 0)# 添加新的x坐标轴 ax.axis["x"].set_axisline_style("-|>", size=1.0)# 给x坐标轴加上箭头 ax.axis["y"] = ax.new_floating_axis(1, 0)# 添加新的y坐标轴 ax.axis["y"].set_axisline_style("-|>", size=1.0)# y坐标轴加上箭头 ax.axis["x"].set_axis_direction("bottom")# 设置x、y轴上刻度显示方向 ax.axis["y"].set_axis_direction("left")# 设置x、y轴上刻度显示方向 plt.xlim(low, high) # 把x轴的刻度范围设置 plt.ylim(low, high) # 把y轴的刻度范围设置 ax.set_xticks(np.arange(low, high + 5, step))# 把x轴的刻度间隔设置 ax.set_yticks(np.arange(low, high + 5, step))# 把y轴的刻度间隔设置 def fitting(): global letters askfile() letters, result=expression_output(result2) # print(letters,result) # 定义要转换的字符串 code_str = ''' def func({}): return {} '''.format(letters,result) # print(code_str) my_func = create_func(code_str) popt, pcov = curve_fit(my_func, sampleData[0], sampleData[1])# 用curve_fit来对点进行拟合 draw_axis(-1000, 1000) # 绘制坐标轴 positive_mask = sampleData[0] >= 0.0#给样本点分类 negative_mask = sampleData[1] < 0.0#给样本点分类 positive_colors = ['red' if x >= 0.0 else 'blue' for x in sampleData[0]]#给样本点分类 negative_colors = ['green' if x >= 0.0 else 'purple' for x in sampleData[0]]#给样本点分类 #根据样本点类型决定样本点颜色 plt.scatter(sampleData[0][positive_mask], sampleData[1][positive_mask], color=np.array(positive_colors)[positive_mask], lw=1) plt.scatter(sampleData[0][negative_mask], sampleData[1][negative_mask], color=np.array(negative_colors)[negative_mask], lw=1) curve_x = np.arange(-1000, 1000)#按照步长生成的一串数字 curve_y = [my_func(i, * popt) for i in curve_x]# 根据x来计算y1值 plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve')#绘制拟合曲线 plt.savefig(r"dot5.png", facecolor='w') # 保存到本地 plt.legend() plt.show() def add(): top = creat_window('新增拟合函数') # 创建弹出窗口 function_entry = create_input_box(top, "拟合函数名称:", '') # 创建一个输入框,获取拟合函数名称 math_entry = create_input_box(top, "数学式:", '') # 创建一个输入框,获取数学式 def get_input(): # 创建 # 获取输入框的内容 global result1, result2 result1 = function_entry.get() result2 = math_entry.get() if result1 and result2: if check_formula_syntax(result2): top.destroy() # 关闭窗口 # fitting() letters, result = expression_output(result2) print(letters) print(result) else: messagebox.showinfo('提示', '你输入的数学公式错误!') else: messagebox.showinfo('提示','你未输入的完成!') button = tk.Button(top, text="确定", command=get_input) button.pack() if __name__ == '__main__': # 创建一个二维数组sampleData,用于存储样本数据 sampleData = [] Root = tk.Tk() window_width = 400 # 窗口的宽度 window_height = 350 # 窗口的高度 Root.title("函数拟合") Root.geometry("400x350") # 设置窗口的大小和位置 button = tk.Button(Root,text='新增拟合函数',bg='blue',command=add) button.place(x=250,y=10) Root.mainloop()