diff --git a/X1.py b/X1.py new file mode 100644 index 0000000..2dfd339 --- /dev/null +++ b/X1.py @@ -0,0 +1,29 @@ +import random +import numpy as np +def random_points(): + x=[] + y=[] + for i in range(20): + x_= random.uniform(0, 1000) # 生成随机浮点数 + y_= random.uniform(0, 1000) # 生成随机浮点数 + x.append(x_) # 加入列表 + y.append(y_) + x=np.array(x) # 列表转数组 + y=np.array(y) + arr = np.array(list(zip(x, y))) # 将两个一维数组拼接成二维数组 + return arr +# if __name__ == '__main__': +# arr = random_points() +# print(arr) + +def compute_curveData(num, step, coefficient): # coefficient代表二次函数系数,数组形式 + def quadratic_function(x): # 构造二次函数y = a * X^2 + b * X + C + return coefficient[0] * x ** 2 + coefficient[1] * x + coefficient[2] + x_values = np.arange(0, num, step) + y_values = quadratic_function(x_values) # 调用quadratic_function(x)函数得到y值 + curve_data = np.column_stack((x_values, y_values)) # 将两个一维数组堆叠成二维数组,形成(x,y)的形式 + return curve_data +if __name__ == '__main__': + coefficient = [1, 2, 3] + ans = compute_curveData(1000, 250, coefficient) + print(ans) \ No newline at end of file diff --git a/X2.py b/X2.py new file mode 100644 index 0000000..8b54cb5 --- /dev/null +++ b/X2.py @@ -0,0 +1,113 @@ +from tkinter import * +import tkinter as tk +import mpl_toolkits.axisartist as axisartist +import matplotlib.pyplot as plt +from scipy.optimize import curve_fit +import data as gl_data +import numpy as np +from X1 import random_points + +def window(): + root_window = Tk() + root_window.title('函数拟合') + + root_window.geometry('900x600') # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x" + # 设置主窗口的背景颜色,颜色值可以是英文单词,或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量 + root_window["background"] = "white" + root_window.resizable(0, 0) # 防止用户调整尺寸 + label1 = tk.Label(root_window, text="样本数据\n集文件", font=('Times', 8), bg="white", + width=13, height=3, # 设置标签内容区大小 + padx=0, pady=0, borderwidth=0, ) + label1.place(x=10, y=4) # 设置填充区距离、边框宽度和其样式(凹陷式) + label3 = tk.Label(root_window, text="", font=('Times', 8), bg="white", fg="black", + width=39, height=2, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue") + label3.place(x=122, y=10) + return root_window +# if __name__ == '__main__': +# root_window = window() +# root_window.mainloop() + +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轴的刻度间隔设置 + # plt.show() +# if __name__ == '__main__': +# draw_axis(-1000, 1000) + +def selfdata_show(sampleData): + num_points = len(sampleData) # 样本数据点的数量 + colors = np.random.rand(num_points, 3) # 生成随机颜色 + draw_axis(0, 1000) + plt.scatter(sampleData[:, 0], sampleData[:, 1], c=colors) # 绘制样本数据点 + plt.show() #显示图片 +# if __name__ == '__main__': +# sampleData = random_points() # 生成样本点 +# selfdata_show(sampleData) # 绘制样本数据点 + +def quadratic_function(x, a, b, c, d): #构造三次函数y = a * X^3 + b * X^2 + C * x + d + return a * x ** 3 + b * x **2 + c * x + d +def draw_line(low, high, sx, sy): + draw_axis(low, high) #绘制坐标轴 + popt = [] #初始化curve_fit + pcov = [] #初始化curve_fit + gl_data.yvals_pow = [] #初始化curve_fit + popt, pcov = curve_fit(quadratic_function, sx, sy) # 用curve_fit来对点进行拟合 + curve_x = np.arange(low, high) #按照步长生成的一串数字 + curve_y = [quadratic_function (i, *popt) for i in curve_x] # 根据x0(按照步长生成的一串数字)来计算y1值 + plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve') #绘制拟合曲线 + plt.legend() + plt.show() #显示函数图像 + +if __name__ == '__main__': + curve_data = [[-375,250],[-750,0],[-1000,-500],[0,0],[375,-250],[750,0],[1000,500]] + x = np.array([point[0] for point in curve_data]) # 为二次函数.txt + y = np.array([point[1] for point in curve_data]) + draw_line(-1000, 1000, x, y) + +# 下面是一个用于拟合曲线的最小二乘法的Python代码示例: + +# import numpy as np +# import matplotlib.pyplot as plt +# +# # 定义x和y坐标数据 +# x = np.array([1, 2, 3, 4, 5]) +# y = np.array([2, 3, 4, 5, 6]) +# +# # 定义多项式阶数m +# m = 2 +# +# # 构造A矩阵 +# A = np.vander(x, m + 1, increasing=True) +# +# # 计算拟合系数theta +# theta = np.linalg.lstsq(A, y, rcond=None)[0] +# +# # 使用theta和x的幂次计算拟合曲线 +# x_fit = np.linspace(x.min(), x.max(), 100) +# y_fit = np.polyval(theta[::-1], x_fit) +# +# # 创建图形对象并绘制拟合曲线和样本点 +# fig, ax = plt.subplots() +# ax.plot(x_fit, y_fit, label='Fitted curve') +# ax.scatter(x, y, label='Data points') +# +# # 添加标签 +# ax.set_xlabel('x') +# ax.set_ylabel('y') +# ax.set_title('Curve fitting using Least Squares') +# +# # 显示图形 +# plt.legend() +# plt.show() \ No newline at end of file diff --git a/X3.py b/X3.py new file mode 100644 index 0000000..bfd0cd3 --- /dev/null +++ b/X3.py @@ -0,0 +1,343 @@ +# -*- coding: utf-8 -*- +# Time : 2023/8/9 10:20 +# Author : lirunsheng +# User : l'r's +# Software: PyCharm +# File : X3.py + +import mpl_toolkits.axisartist as axisartist +from scipy.optimize import curve_fit +from pandas import DataFrame +import matplotlib.pyplot as plt +import numpy as np +import pylab as mpl +from tkinter import * +import data as gl_data +import pandas as pd +import tkinter +import sys +import tkinter as tk +from tkinter import filedialog + +mpl.rcParams['font.sans-serif'] = ['SimHei'] # 解决matplotlib中文不显示问题 +plt.rcParams['axes.unicode_minus'] = False # 解决matplotlib负数坐标显示问题 + +# 创建一个二维数组sampleData,用于存储样本数据 +sampleData = [] + +def askfile():# 从本地选择一个文件,并返回文件的路径 + global sampleData + # 弹出文件选择对话框,选择要打开的文本文件 + file_path = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')]) + + # 如果没有选择文件,直接返回 + if not file_path: + return + # 步骤1:打开样本数据集文件并读取每行数据 + with open(file_path, 'r') as file: + lines = file.readlines() + + # 步骤2:遍历所有行,将每行数据解析为sx和sy值,转换为浮点数并存储到sampleData中 + for line in lines: + sx, sy = line.strip().split(' ') + sx = float(sx) + sy = float(sy) + sampleData.append([sx, sy]) + + # # 步骤3:使用循环遍历样本数据并打印出来 + # for data in sampleData: + # print(data) +# if __name__ == '__main__': +# askfile() +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 generate_and_plot_sample_data(low, high): + num_samples = 25 #设置样本点数量 + gl_data.X = np.random.randint(low=low, high=high, size=num_samples)#随机生成x值 + print(gl_data.X) + gl_data.Y = np.random.randint(low=low, high=high, size=num_samples)#随机生成y值 + # 提取样本数据的x坐标和y坐标 + # x_values = [point[0] for point in sampleData] + # print(x_values) + # y_values = [point[1] for point in sampleData] + draw_axis(low, high) #绘制坐标轴 + plt.scatter(gl_data.X,gl_data.Y, color='red') # 绘制样本数据点 + plt.savefig(r"dot2.png", facecolor='w') # 保存到本地 + plt.close() # 清除内存 + # set_phtot(1) #显示到主界面 +# if __name__ == '__main__': +# askfile() +# # generate_and_plot_sample_data(gl_data.LOW, gl_data.HIGH) +def quadratic_function(x, a, b, c):#构造二次函数y = a * X^2 + b * X + C + return a * x ** 2 + b * x + c +def draw_dots_and_line(low, high, sx, sy): + draw_axis(low, high) + popt, pcov = curve_fit(quadratic_function, sx, sy)# 用curve_fit来对点进行拟合 + positive_mask = sy >= 0.0#给样本点分类 + negative_mask = sy < 0.0#给样本点分类 + positive_colors = ['red' if x >= 0.0 else 'blue' for x in sx]#给样本点分类 + negative_colors = ['green' if x >= 0.0 else 'purple' for x in sx]#给样本点分类 + #根据样本点类型决定样本点颜色 + plt.scatter(gl_data.X[positive_mask], gl_data.Y[positive_mask], color=np.array(positive_colors)[positive_mask], lw=1) + plt.scatter(gl_data.X[negative_mask], gl_data.Y[negative_mask], color=np.array(negative_colors)[negative_mask], lw=1) + curve_x = np.arange(low, high)#按照步长生成的一串数字 + curve_y = [quadratic_function (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() + return popt +# if __name__ == '__main__': +# askfile() +# gl_data.x = np.array([point[0] for point in sampleData]) # 为二次函数.txt +# gl_data.y = np.array([point[1] for point in sampleData]) +# popt = draw_dots_and_line(gl_data.low, gl_data.high, gl_data.x, gl_data.y) +# a,b,c = popt +# print(a,b,c) + +def input_num(root_tk): + global top + top = tk.Toplevel(root_tk) + top.geometry("300x50") + top.title('坐标点个数') + label1 = Label(top, text="坐标点个数") + label1.grid(row=0) # 这里的side可以赋值为LEFT RTGHT TOP BOTTOM + num1 = IntVar() + entry1 = Entry(top, textvariable=num1) + num1.set(0) + entry1.grid(row=0, column=1) + Label(top, text=" ").grid(row=0, column=3) + Button(top, text="确定", command=lambda: input_data(root_tk, int(entry1.get()))).grid(row=0, column=3) + top.mainloop() + +def add_sample_data(): + global sample_x, sample_y, sample_data + global entry_x,entry_y,label_status, numx + try: + x = float(entry_x.get()) + y = float(entry_y.get()) + except: + label_status.config(text="输入不合法") + return + entry_x.delete(0, tk.END) + entry_y.delete(0, tk.END) + if min(x, y) < gl_data.LOW or max(x, y) > gl_data.HIGH: + label_status.config(text="输入超过范围") + return + elif len(sample_data) < numx: + label_status.config(text="点对已添加") + sample_data.append((x, y)) + sample_x.append(x) + sample_y.append(y) + else: + label_status.config(text="已达到最大数量") +def check_sample_data(): + global label_status,numx,sample_x,sample_y,sample_data + if len(sample_data) == numx: + label_status.config(text="已达到最大数量") + gl_data.X = np.array(sample_x) + gl_data.Y = np.array(sample_y) + print('已添加', sample_data) + sys.exit() + else: + label_status.config(text="还需输入{}个点对".format(numx - len(sample_data))) + print(sample_data) + +def input_data(root_tk, num): + global top + global sample_x,sample_y,sample_data + global numx + numx = num + sample_x = [] + sample_y = [] + sample_data = [] + top.destroy() + top = tk.Toplevel(root_tk) + top.geometry("300x200") + top.title('坐标') + global entry_x, entry_y, label_status + label_x = tk.Label(top, text="X 值:") + label_x.pack() + entry_x = tk.Entry(top) + entry_x.pack() + label_y = tk.Label(top, text="Y 值:") + label_y.pack() + entry_y = tk.Entry(top) + entry_y.pack() + button_add = tk.Button(top, text="添加", command=add_sample_data) + button_add.pack() + button_check = tk.Button(top, text="检查", command=check_sample_data) + button_check.pack() + label_status = tk.Label(top, text="") + label_status.pack() + top.mainloop() + +# if __name__ == '__main__': +# root = tk.Tk() +# root.withdraw() +# input_num(root) + +# 定义误差函数 +def error_func(x_data, y_data, a, b, c): + y_pred = exponential_function(x_data, a, b, c) + error = np.sum((y_data - y_pred) ** 2) + residual = y_data - y_pred + ss_res = np.sum(residual ** 2) + ss_tot = np.sum((y_data - np.mean(y_data)) ** 2) + r_squared = 1 - (ss_res / ss_tot) + return error,r_squared + +# 给出一个二次函数拟合的例子,读者可自己写拟合函数 +def exponential_function(x, a, b, c): + return a * x ** 2 + b * x + c + +def fit(sample_data): # 随机生成样本数据 + x_data = np.array([data[0] for data in sample_data]) + y_data = np.array([data[1] for data in sample_data]) # 拟合样本数据 + popt, pcov = curve_fit(exponential_function, x_data, y_data) # 计算拟合结果 + # 计算拟合误差 + error,r_squared = error_func(x_data, y_data, *popt) + fit_function_name = exponential_function.__name__# 打印拟合函数的形式、系数、误差和优度 + print("拟合函数形式:{}".format(fit_function_name)) + print("拟合系数:{}".format(popt)) + print("误差:{:.4f}".format(error)) + print("拟合优度(R^2):{:.4f}".format(r_squared)) +# if __name__ == '__main__': +# askfile() +# fit(sampleData) # 对当前x、y值进行拟合 +# # 给出一个指数函数拟合的例子,读者可自己写拟合函数 +# def fit_function(x,a,b,c): +# return a * np.exp(b * x) + c +# +# def fit(sample_data): # 随机生成样本数据 +# x_data = np.array([data[0] for data in sample_data]) +# y_data = np.array([data[1] for data in sample_data]) # 拟合样本数据 +# popt, pcov = curve_fit(fit_function, x_data, y_data) # 计算拟合结果 +# y_fit = fit_function(x_data, *popt) +# residuals = y_data - y_fit +# ss_res = np.sum(residuals**2) +# ss_tot = np.sum((y_data - np.mean(y_data))**2) +# r_squared = 1 - (ss_res / ss_tot) +# fit_function_name = fit_function.__name__# 打印拟合函数的形式、系数、误差和优度 +# print("拟合函数形式:{}".format(fit_function_name)) +# print("拟合系数:{}".format(popt)) +# print("误差:{:.4f}".format(np.sqrt(np.mean(residuals**2)))) +# print("拟合优度(R^2):{:.4f}".format(r_squared)) +# if __name__ == '__main__': +# askfile() +# fit(sampleData) # 对当前x、y值进行拟合 + +def change_Q(no): + gl_data.Quadrant = no #更改全局变量的象限显示 + if no: #若为一象限,则修改显示下限为0 + gl_data.LOW = 0 + else: #若为四象限,则修改显示下限为-gl_data.MAXV + gl_data.LOW = -gl_data.MAXV + q_button() #更新象限显示面板 + +def q_button(): + r = 7.5 + rr = 2.5 + for widget in q_root.winfo_children(): + widget.destroy() + q_cv = tk.Canvas(q_root, width=450, height=500) + q_cv.place(x=0, y=0) + l = tk.Label(q_root, text='坐标轴', bd=0, font=("微软雅黑", 16) , anchor=W) + l.place(x=20, y=0, width=80, height=50,) + # 四象b限按钮 + b1 = tk.Button(q_root, text='四象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(0), anchor=W) + b1.place(x=170, y=0, width=80, height=50,) + # 一象限按钮 + b2 = tk.Button(q_root, text='一象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(1), anchor=W) + b2.place(x=320, y=0, width=80, height=50,) + # 绘制标记框 + q_cv.create_oval(140 - r, 25 - r, 140 + r, 25 + r, fill="white", width=1, outline="black") + q_cv.create_oval(290 - r, 25 - r, 290 + r, 25 + r , fill="white", width=1, outline="black") + # 根据当前的象限选择值来填充标记框 + if gl_data.Quadrant == 0: + q_cv.create_oval(140 - rr, 25 - rr, 140 + rr, 25 + rr, fill="black", width=1, outline="black")# 绘制象限 + # Q_cv.create_rectangle(80, 80, 270, 270, fill="white") # 第一象限 + # Q_cv.create_rectangle(270, 80, 500, 270, fill="red") # 第二象限 + # Q_cv.create_rectangle(80, 270, 270, 480, fill="blue") # 第三象限 + # Q_cv.create_rectangle(270, 270, 500, 480, fill="green") # 第四象限 + else: + q_cv.create_oval(290 - rr, 25 - rr, 290 + rr, 25 + rr, fill="black", width=1, outline="black") +# if __name__ == '__main__': +# # 象限选择相关界面 +# q_root = tk.Tk() +# q_root.geometry("500x550") # 设置窗口的大小和位置 +# q_button() +# q_root.mainloop() + +# 定义模型为y=ax+b +def model(x, a, b): + return a*x + b + +# 定义误差函数error_function() +def error_function(x,y,a, b): + y_pred = model(x, a, b) + error = np.mean((y - y_pred)**2) + return error + +# 定义梯度函数gradient() +def gradient(a, b,x,y): + y_pred = model(x, a, b) + gradient_a = 2*np.mean((y_pred - y)*x) + gradient_b = 2*np.mean(y_pred - y) + return gradient_a, gradient_b + +if __name__ == '__main__': + # 读取sampledata值 + sampledata = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + x = np.array(sampledata) + y = np.array([-2, 1, 0, 1, 2, 3, 4, 5, 6, 8]) + # 初始化参数 + a = 0 + b = 0 + learning_rate = 0.01 + num_iterations = 1000 + # 梯度下降算法 + for i in range(num_iterations): + grad_a, grad_b = gradient(a, b,x,y) + a -= learning_rate * grad_a + b -= learning_rate * grad_b + # 输出最终拟合结果 + final_error = error_function(x,y,a, b) + # gl_data.X = x # 为二次函数.txt + # gl_data.Y = y + # draw_axis(-100, 100) + # positive_mask = x >= 0.0 # 给样本点分类 + # negative_mask = y < 0.0 # 给样本点分类 + # positive_colors = ['red' if x >= 0.0 else 'blue' for x in x] # 给样本点分类 + # negative_colors = ['green' if x >= 0.0 else 'purple' for x in x] # 给样本点分类 + # # 根据样本点类型决定样本点颜色 + # plt.scatter(gl_data.X[positive_mask], gl_data.Y[positive_mask], color=np.array(positive_colors)[positive_mask], + # lw=1) + # plt.scatter(gl_data.X[negative_mask], gl_data.Y[negative_mask], color=np.array(negative_colors)[negative_mask], + # lw=1) + # curve_x = np.arange(-1000, 1000) # 按照步长生成的一串数字 + # curve_y = [model(i, a, b) for i in curve_x] # 根据x来计算y1值 + # plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve') # 绘制拟合曲线 + # plt.legend() + # plt.show() + print("拟合函数形式: y = ax + b") + print("系数 a:{:.2f}".format(a)) + print("系数 b:{:.2f}".format( b)) + print("误差计算方法: 均方误差") + print("最终误差:{:.2f}".format(final_error)) \ No newline at end of file diff --git a/X4.py b/X4.py new file mode 100644 index 0000000..cee551c --- /dev/null +++ b/X4.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +# Time : 2023/8/9 10:20 +# Author : lirunsheng +# User : l'r's +# Software: PyCharm +# File : X4.py + +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: main.py + @DateTime: 2023/5/30 15:29 + @SoftWare: PyCharm +""" +import sys + +from fitting import * +import numpy as np +import data as gl_data +import input +import tkinter as tk +from tkinter import * +import tkinter.filedialog # 注意次数要将文件对话框导入 + +global Q_root,F_root +global root_window +global label1,label2,label3 + +def window(): + global root_window + global label1, label2, label3 + root_window = Tk() + root_window.title('函数拟合') + root_window.geometry('900x600') # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x" + # 设置主窗口的背景颜色,颜色值可以是英文单词,或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量 + root_window["background"] = "white" + root_window.resizable(0, 0) # 防止用户调整尺寸 + label1 = tk.Label(root_window, text="样本数据\n集文件", font=('Times', 8), bg="white", + width=13, height=3, # 设置标签内容区大小 + padx=0, pady=0, borderwidth=0, ) + label1.place(x=10, y=4) # 设置填充区距离、边框宽度和其样式(凹陷式) + label3 = tk.Label(root_window, text="", font=('Times', 8), bg="white", fg="black", + width=39, height=2, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue") + label3.place(x=122, y=10) + # 使用按钮控件调用函数 + tk.Button(root_window, text="装载", relief=RAISED, command=lambda: askfile()).place(x=370, y=12) + label2 = tk.Label(root_window, text="拟合曲线类型", font=('Times', 12), bg="white", + width=20, height=3, # 设置标签内容区大小 + padx=0, pady=0, borderwidth=0, ) + # 设置填充区距离、边框宽度和其样式(凹陷式) + label2.place(x=450, y=4) + gl_data.Canvas2 = tk.Canvas(root_window, bg='white', width=450, height=330) + gl_data.Canvas2.place(x=4, y=60) +# 定义一个处理文件的相关函数 +def askfile(): + # 从本地选择一个文件,并返回文件的路径 + filename = tkinter.filedialog.askopenfilename() + if filename != '':#若选中了一个文件,则对文件进行读取 + label3.config(text=filename)#显示文件路径 + read_sample_data(filename)#将文件读取并存到sampleData中 + # print_sample_data(filename)#将文件读取并逐行输出 + selfdata_show(gl_data.X, gl_data.Y, gl_data.LOW, gl_data.HIGH) + else:#若未选择文件,则显示为空 + label3.config(text='') + +def print_sample_data(file_path):#打开对应文件 + with open(file_path, 'r') as file: + for line in file:#逐行读取文件 + line = line.strip('\n')#移除换行符 + sx, sy = line.split(' ')#以空格分割x,y + print(f'sx: {float(sx)}, sy: {float(sy)}')#将sx、sy转换为浮点数并打印 + + +def read_sample_data(file_path): + 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转换为浮点数并加入数组 + gl_data.X, gl_data.Y = np.array(x), np.array(y)#x,y数组转为array并赋值给全局变量 + +def buttons(): + # 随机生成样本点并显示 + b_dot = tk.Button(root_window, text="生成\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: generate_and_plot_sample_data(gl_data.LOW, gl_data.HIGH)) + b_dot.place(x=455, y=410) + # 显示当前样本点 + b_show = tk.Button(root_window, text="显示\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: selfdata_show(gl_data.X, gl_data.Y, gl_data.LOW, gl_data.HIGH)) + b_show.place(x=510, y=410) + # 显示数据集与曲线 + b_line = tk.Button(root_window, text="显示数据\n集与曲线", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: draw_dots_and_line(gl_data.Xian_index, gl_data.LOW, gl_data.HIGH, gl_data.X, gl_data.Y)) + b_line.place(x=565, y=410) + # 手动输入数据集 + b_input = tk.Button(root_window, text="手动输入数据集", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13), + command=lambda: input.input_num(root_window)) + b_input.place(x=633, y=410) + # 拟合并输出拟合结果 + b_fit = tk.Button(root_window, text="拟合", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13), + command=lambda: fit_data(gl_data.Xian_index, gl_data.X, gl_data.Y)) + b_fit.place(x=771, y=410) +def show_fit(): + L = tk.Label(root_window, text='结果输出:', bg='white', font=("微软雅黑", 16) + , anchor=W) + L.place(x=20, y=480, width=100, height=30) + ans = tk.Label(root_window, text=gl_data.Out, font=("微软雅黑", 14) + , anchor=W, justify='left') + ans.place(x=120, y=480, width=760, height=100) + print(gl_data.Out) + +def fit_data(xian_index, sx, sy): + # gl_data.yvals_pow = [] + cur = function.Fun[xian_index] # 装载正在选择的函数 + func = cur.get_fun()#获取当前函数func + popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合 + yvals_pow = func(gl_data.X, *popt) + rr = gl_data.goodness_of_fit(yvals_pow, gl_data.Y)# 计算本次拟合的R*R值,用于表示拟合优度 + # 输出拟合后的各个参数值 + ans = '\n函数系数:' + for i in range(cur.variable): + if i == 4: + ans += '\n' + if i != 0: + ans += ', ' + ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3)) + gl_data.Out = '函数形式:' + cur.name + ' ' + gl_data.Out += cur.demo + gl_data.Out += ans + gl_data.Out += '\n拟合优度(R\u00b2):' + str(round(rr, 5)) + show_fit()# 显示函数信息到输出框 + +def change_Q(no): + gl_data.Quadrant = no #更改全局变量的象限显示 + if no:#若为一象限,则修改显示下限为0 + gl_data.LOW = 0 + else:#若为四象限,则修改显示下限为-gl_data.maxV + gl_data.LOW = -gl_data.MAXV + q_button()#更新象限显示面板 + +def q_button(): + r = 7.5 + rr = 2.5 + for widget in Q_root.winfo_children(): + widget.destroy() + q_cv = tk.Canvas(Q_root, width=400, height=50) + q_cv.place(x=0, y=0) + l = tk.Label(Q_root, text='坐标轴', bd=0, font=("微软雅黑", 16) + , anchor=W) + l.place(x=20, y=0, width=80, height=50,) + # 四象限按钮 + b1 = tk.Button(Q_root, text='四象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(0), anchor=W) + b1.place(x=170, y=0, width=80, height=50,) + # 一象限按钮 + b2 = tk.Button(Q_root, text='一象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(1), anchor=W) + b2.place(x=320, y=0, width=80, height=50,) + # 绘制标记框 + q_cv.create_oval(140 - r, 25 - r, 140 + r, 25 + r + , fill="white", width=1, outline="black") + q_cv.create_oval(290 - r, 25 - r, 290 + r, 25 + r + , fill="white", width=1, outline="black") + # 根据当前的象限选择值来填充标记框 + if gl_data.Quadrant == 0: + q_cv.create_oval(140 - rr, 25 - rr, 140 + rr, 25 + rr + , fill="black", width=1, outline="black") + else: + q_cv.create_oval(290 - rr, 25 - rr, 290 + rr, 25 + rr + , fill="black", width=1, outline="black") + + +def change_f(no): + gl_data.Xian_index = no#设置全局函数编号为该函数 + f_button()#重新绘制函数显示界面 + +def f_button(): + r = 7.5#设置按钮大小 + rr = 2.5#设置按钮大小 + for widget in F_root.winfo_children(): + widget.destroy()#清空原有按钮 + f_cv = tk.Canvas(F_root, width=400, height=330)#新建画布 + f_cv.place(x=0, y=0)#放置画布 + f_cv.create_rectangle(2, 2, 398, 328, fill='white', outline="#0099ff")#设置画布边框及底色 + cur = 0#函数计数 + + for fun in function.Fit_type_library:#遍历函数库 + f = function.Fit_type_library.get(fun)#获取函数具体信息 + if function.Show[f[0]] == 1:# 如果show为1则显示 + f_cv.create_oval(20 - r, 20 + 15 + cur * 30 - r, 20 + r, 20 + 15 + cur * 30 + r + , fill="white", width=1, outline="black")# 绘制标记框 + if f[0] == gl_data.Xian_index:# 若选择为当前函数则标记 + f_cv.create_oval(20 - rr, 20 + 15 + cur * 30 - rr, 20 + rr, 20 + 15 + cur * 30 + rr + , fill="black", width=1, outline="black") + # 绘制切换按钮,单击则将当前使用函数切换为该函数 + button = tk.Button(F_root, text=f[2] + ' ' + f[1], bd=0, bg="white", font=("微软雅黑", 12) + , command=lambda x=f[0]: change_f(x), anchor=W) + button.place(x=40, y=20 + cur * 30, width=300, height=30) + cur += 1#计数加一 + +def close_window(): + sys.exit() +def main(): + global Q_root, F_root,root_window + gl_data.X = [] + gl_data.X = [] + window() + function.f_read() + # 函数选择相关界面 + F_root = tk.Frame(root_window, width=400, height=330, bg='white', ) + F_root.place(x=490, y=60) + # 象限选择相关界面 + Q_root = tk.Frame(root_window, width=400, height=50, bg='white', ) + Q_root.place(x=20, y=410) + buttons() + f_button() + q_button() + show_fit() + root_window.protocol("WM_DELETE_WINDOW", close_window) + root_window.mainloop() +if __name__ == '__main__': + main() + pass diff --git a/X5.py b/X5.py new file mode 100644 index 0000000..f9d96ae --- /dev/null +++ b/X5.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- +# Time : 2023/8/9 10:20 +# Author : lirunsheng +# User : l'r's +# Software: PyCharm +# File : X4.py + +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: main.py + @DateTime: 2023/5/30 15:29 + @SoftWare: PyCharm +""" +import sys +from fitting import * +import numpy as np +import data as gl_data +import input +import tkinter as tk +from tkinter import * +import tkinter.filedialog # 注意次数要将文件对话框导入 +# from demo1 import Addfunc + +global Q_root,F_root +global root_window +global label1,label2,label3 + +class Addfunc(): + def __init__(self): + self.r = 7.5 # 设置按钮大小 + self.rr = 2.5# 设置按钮大小 + self.window = tk.Tk() # 新建函数增加窗口 + self.window.title("新增函数曲线")#设置窗口标题 + self.window.geometry('400x300')#设置窗口大小 + self.show()#显示按钮 + self.window.mainloop()#运行UI界面 + + def show(self): + for widget in self.window.winfo_children(): + widget.destroy()#清空已有组件 + self.add_cv = tk.Canvas(self.window, width=400, height=300) # 新建画布 + self.add_cv.place(x=0, y=0) # 放置画布 + cur = 0#记录已有按钮个数 + for f in function.Fun:#遍历已有函数 + self.add_cv.create_oval(20 - self.r, 20 + 15 + cur * 30 - self.r, 20 + self.r, 20 + 15 + cur * 30 + self.r + , fill="white", width=1, outline="black")# 绘制圆圈 + if f.show == 1:#若为当前选中函数,则标记 + self.add_cv.create_oval(20 - self.rr, 20 + 15 + cur * 30 - self.rr, 20 + self.rr, 20 + 15 + cur * 30 + self.rr + , fill="black", width=1, outline="black") + button = tk.Button(self.window, text=f.name + f.demo, bd=0, font=("微软雅黑", 12) + , command=lambda x=f.no: self.change(x), anchor=W)#设置选择按钮 + button.place(x=40, y=20 + cur * 30, width=300, height=30)#放置选择按钮 + cur += 1#计数加一 + + def change(self, no):#切换函数显示情况 + function.Show[no] = not function.Show[no] + function.Fun[no].show = not function.Fun[no].show + self.show()#更新函数选择面板 + f_button()#更新函数显示界面 +# class AddFunc(Addfunc): +# def change(self, no): +# # super().change(no) +# function.Show[no] = not function.Show[no] +# function.Fun[no].show = not function.Fun[no].show +# self.show() # 更新函数选择面板 +# f_button() + +def addfunc(): + Addfunc() + # AddFunc() +def window(): + global root_window + global label1, label2, label3 + root_window = Tk() + root_window.title('函数拟合') + root_window.geometry('900x600') # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x" + # 设置主窗口的背景颜色,颜色值可以是英文单词,或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量 + root_window["background"] = "white" + root_window.resizable(0, 0) # 防止用户调整尺寸 + label1 = tk.Label(root_window, text="样本数据\n集文件", font=('Times', 8), bg="white", + width=13, height=3, # 设置标签内容区大小 + padx=0, pady=0, borderwidth=0, ) + label1.place(x=10, y=4) # 设置填充区距离、边框宽度和其样式(凹陷式) + label3 = tk.Label(root_window, text="", font=('Times', 8), bg="white", fg="black", + width=39, height=2, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue") + label3.place(x=122, y=10) + # 使用按钮控件调用函数 + tk.Button(root_window, text="装载", relief=RAISED, command=lambda: askfile()).place(x=370, y=12) + label2 = tk.Label(root_window, text="拟合曲线类型", font=('Times', 12), bg="white", + width=20, height=3, # 设置标签内容区大小 + padx=0, pady=0, borderwidth=0, ) + # 设置填充区距离、边框宽度和其样式(凹陷式) + label2.place(x=450, y=4) + gl_data.Canvas2 = tk.Canvas(root_window, bg='white', width=450, height=330) + gl_data.Canvas2.place(x=4, y=60) +# 定义一个处理文件的相关函数 +def askfile(): + # 从本地选择一个文件,并返回文件的路径 + filename = tkinter.filedialog.askopenfilename() + if filename != '':#若选中了一个文件,则对文件进行读取 + label3.config(text=filename)#显示文件路径 + read_sample_data(filename)#将文件读取并存到sampleData中 + # print_sample_data(filename)#将文件读取并逐行输出 + selfdata_show(gl_data.X, gl_data.Y, gl_data.LOW, gl_data.HIGH) + else:#若未选择文件,则显示为空 + label3.config(text='') + +def print_sample_data(file_path):#打开对应文件 + with open(file_path, 'r') as file: + for line in file:#逐行读取文件 + line = line.strip('\n')#移除换行符 + sx, sy = line.split(' ')#以空格分割x,y + print(f'sx: {float(sx)}, sy: {float(sy)}')#将sx、sy转换为浮点数并打印 + +def read_sample_data(file_path): + 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转换为浮点数并加入数组 + gl_data.X, gl_data.Y = np.array(x), np.array(y)#x,y数组转为array并赋值给全局变量 + +def buttons(): + # 随机生成样本点并显示 + b_dot = tk.Button(root_window, text="生成\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: generate_and_plot_sample_data(gl_data.LOW, gl_data.HIGH)) + b_dot.place(x=455, y=410) + # 显示当前样本点 + b_show = tk.Button(root_window, text="显示\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: selfdata_show(gl_data.X, gl_data.Y, gl_data.LOW, gl_data.HIGH)) + b_show.place(x=510, y=410) + # 显示数据集与曲线 + b_line = tk.Button(root_window, text="显示数据\n集与曲线", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10), + command=lambda: draw_dots_and_line(gl_data.Xian_index, gl_data.LOW, gl_data.HIGH, gl_data.X, gl_data.Y)) + b_line.place(x=565, y=410) + # 手动输入数据集 + b_input = tk.Button(root_window, text="手动输入数据集", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13), + command=lambda: input.input_num(root_window)) + b_input.place(x=633, y=410) + # 拟合并输出拟合结果 + b_fit = tk.Button(root_window, text="拟合", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13), + command=lambda: fit_data(gl_data.Xian_index, gl_data.X, gl_data.Y)) + b_fit.place(x=771, y=410) +def show_fit(): + L = tk.Label(root_window, text='结果输出:', bg='white', font=("微软雅黑", 16) + , anchor=W) + L.place(x=20, y=480, width=100, height=30) + sout = str(gl_data.Out) + ans = tk.Label(root_window, text=sout, font=("微软雅黑", 14) + , anchor=W, justify='left') + ans.place(x=120, y=480, width=760, height=100) + print(sout) +def fit_data(xian_index, sx, sy): + # gl_data.yvals_pow = [] + cur = function.Fun[xian_index] # 装载正在选择的函数 + func = cur.get_fun()#获取当前函数func + popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合 + yvals_pow = func(gl_data.X, *popt) + rr = gl_data.goodness_of_fit(yvals_pow, gl_data.Y)# 计算本次拟合的R*R值,用于表示拟合优度 + # 输出拟合后的各个参数值 + ans = '\n函数系数:' + for i in range(cur.variable): + if i == 4: + ans += '\n' + if i != 0: + ans += ', ' + ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3)) + gl_data.Out = '函数形式:' + cur.name + ' ' + gl_data.Out += cur.demo + gl_data.Out += ans + gl_data.Out += '\n拟合优度(R\u00b2):' + str(round(rr, 5)) + show_fit()# 显示函数信息到输出框 + +def change_Q(no): + gl_data.Quadrant = no #更改全局变量的象限显示 + if no:#若为一象限,则修改显示下限为0 + gl_data.LOW = 0 + else:#若为四象限,则修改显示下限为-gl_data.maxV + gl_data.LOW = -gl_data.MAXV + q_button()#更新象限显示面板 + +def q_button(): + r = 7.5 + rr = 2.5 + for widget in Q_root.winfo_children(): + widget.destroy() + q_cv = tk.Canvas(Q_root, width=400, height=50) + q_cv.place(x=0, y=0) + l = tk.Label(Q_root, text='坐标轴', bd=0, font=("微软雅黑", 16) + , anchor=W) + l.place(x=20, y=0, width=80, height=50,) + # 四象限按钮 + b1 = tk.Button(Q_root, text='四象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(0), anchor=W) + b1.place(x=170, y=0, width=80, height=50,) + # 一象限按钮 + b2 = tk.Button(Q_root, text='一象限', bd=0, font=("微软雅黑", 16) + , command=lambda: change_Q(1), anchor=W) + b2.place(x=320, y=0, width=80, height=50,) + # 绘制标记框 + q_cv.create_oval(140 - r, 25 - r, 140 + r, 25 + r + , fill="white", width=1, outline="black") + q_cv.create_oval(290 - r, 25 - r, 290 + r, 25 + r + , fill="white", width=1, outline="black") + # 根据当前的象限选择值来填充标记框 + if gl_data.Quadrant == 0: + q_cv.create_oval(140 - rr, 25 - rr, 140 + rr, 25 + rr + , fill="black", width=1, outline="black") + else: + q_cv.create_oval(290 - rr, 25 - rr, 290 + rr, 25 + rr + , fill="black", width=1, outline="black") +def change_f(no): + gl_data.Xian_index = no#设置全局函数编号为该函数 + f_button()#重新绘制函数显示界面 + +def f_button(): + r = 7.5#设置按钮大小 + rr = 2.5#设置按钮大小 + for widget in F_root.winfo_children(): + widget.destroy()#清空原有按钮 + f_cv = tk.Canvas(F_root, width=400, height=330)#新建画布 + f_cv.place(x=0, y=0)#放置画布 + f_cv.create_rectangle(2, 2, 398, 328, fill='white', outline="#0099ff")#设置画布边框及底色 + cur = 0#函数计数 + for fun in function.Fit_type_library:#遍历函数库 + f = function.Fit_type_library.get(fun)#获取函数具体信息 + if function.Show[f[0]] == 1:# 如果show为1则显示 + f_cv.create_oval(20 - r, 20 + 15 + cur * 30 - r, 20 + r, 20 + 15 + cur * 30 + r + , fill="white", width=1, outline="black")# 绘制标记框 + if f[0] == gl_data.Xian_index:# 若选择为当前函数则标记 + f_cv.create_oval(20 - rr, 20 + 15 + cur * 30 - rr, 20 + rr, 20 + 15 + cur * 30 + rr + , fill="black", width=1, outline="black") + # 绘制切换按钮,单击则将当前使用函数切换为该函数 + button = tk.Button(F_root, text=f[2] + ' ' + f[1], bd=0, bg="white", font=("微软雅黑", 12) + , command=lambda x=f[0]: change_f(x), anchor=W) + button.place(x=40, y=20 + cur * 30, width=300, height=30) + cur += 1#计数加一 + +def close_window(): + sys.exit() +def main(): + global Q_root, F_root,root_window + gl_data.X = [] + gl_data.X = [] + window() + # 函数选择相关界面 + F_root = tk.Frame(root_window, width=400, height=330, bg='white', ) + F_root.place(x=490, y=60) + # 象限选择相关界面 + Q_root = tk.Frame(root_window, width=400, height=50, bg='white', ) + Q_root.place(x=20, y=410) + function.f_read() + buttons() + f_button() + q_button() + show_fit() + tk.Button(root_window, text="新增拟合曲线类型", bd=4, command=addfunc).place(x=740, y=12) + root_window.protocol("WM_DELETE_WINDOW", close_window) + root_window.mainloop() +if __name__ == '__main__': + main() + pass diff --git a/data.py b/data.py new file mode 100644 index 0000000..183df80 --- /dev/null +++ b/data.py @@ -0,0 +1,129 @@ +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: data.py + @DateTime: 2023/5/31 11:42 + @SoftWare: PyCharm +""" +import tkinter as tk +from tkinter import * +import random +import numpy as np + +X = [] # 等待拟合的x值 +Y = [] # 等待拟合的y值 +global Canvas2 # 用于显示函数的画布 +Img1 = None # 绘制的dot.png图像 +Img2 = None # 绘制的line.png图像 +Xian_index = 0 # 当前选择的函数编号 +Quadrant = 0 # 当前选择的象限信息0为四象限,1为一象限 +MAXV = 1000 # 最大值 +Out = '' # 拟合输出信息 +LOW = -MAXV # 坐标轴显示上界 +HIGH = MAXV # 坐标轴显示下界 + + +def random_points(): + x=[] + y=[] + for i in range(20): + x_= random.uniform(0, 1000)#生成随机浮点数 + y_= random.uniform(0, 1000)#生成随机浮点数 + x.append(x_) #加入列表 + y.append(y_) + x=np.array(x) #列表转数组 + y=np.array(y) + arr = np.array(list(zip(x, y)))# 将两个一维数组拼接成二维数组 + return arr + +def compute_curveData(num, step, coefficient):#coefficient代表二次函数系数,数组形式 + def quadratic_function(x):#构造二次函数y = a * X^2 + b * X + C + return coefficient[0] * x ** 2 + coefficient[1] * x + coefficient[2] + x_values = np.arange(-num, num, step) + y_values = quadratic_function(x_values)#调用quadratic_function(x)函数得到y值 + curve_data = np.column_stack((x_values, y_values))#将两个一维数组堆叠成二维数组,形成(x,y)的形式 + return curve_data + + +# #################################拟合优度R^2的计算###################################### +def __sst(y_no_fitting): + """ + 计算SST(total sum of squares) 总平方和 + :param y_no_predicted: List[int] or array[int] 待拟合的y + :return: 总平方和SST + """ + y_mean = sum(y_no_fitting) / len(y_no_fitting) + s_list =[(y - y_mean)**2 for y in y_no_fitting] + sst = sum(s_list) + return sst + + +def __ssr(y_fitting, y_no_fitting): + """ + 计算SSR(regression sum of squares) 回归平方和 + :param y_fitting: List[int] or array[int] 拟合好的y值 + :param y_no_fitting: List[int] or array[int] 待拟合y值 + :return: 回归平方和SSR + """ + y_mean = sum(y_no_fitting) / len(y_no_fitting) + s_list =[(y - y_mean)**2 for y in y_fitting] + ssr = sum(s_list) + return ssr + + +def __sse(y_fitting, y_no_fitting): + """ + 计算SSE(error sum of squares) 残差平方和 + :param y_fitting: List[int] or array[int] 拟合好的y值 + :param y_no_fitting: List[int] or array[int] 待拟合y值 + :return: 残差平方和SSE + """ + s_list = [(y_fitting[i] - y_no_fitting[i])**2 for i in range(len(y_fitting))] + sse = sum(s_list) + return sse + + +def goodness_of_fit(y_fitting, y_no_fitting): + """ + 计算拟合优度R^2 + :param y_fitting: List[int] or array[int] 拟合好的y值 + :param y_no_fitting: List[int] or array[int] 待拟合y值 + :return: 拟合优度R^2 + """ + ssr = __ssr(y_fitting, y_no_fitting) + sst = __sst(y_no_fitting) + rr = ssr /sst + return rr + +def least_sqaure(x,y): + n = len(x) + sumx, sumy, sumxy, sumxx = 0, 0, 0, 0 + for i in range(0, n): + sumx += x[i] + sumy += y[i] + sumxx += x[i] * x[i] + sumxy += x[i] * y[i] + a = (n * sumxy - sumx * sumy) / (n * sumxx - sumx * sumx) + b = (sumxx * sumy - sumx * sumxy) / (n * sumxx - sumx * sumx) + return a, b +import time + +def gradient_descent(x, y): + s = time.time() + x = 10000 * np.random.randn(1) # 产生服从正太分布的一个数(均值=0,方差=1),扩大10000倍 + eta = 0.09 + i = 1 + while True: + y = x ^ 2 / 2 - 2 * x + x -= eta * 2 * x + if y <= 0.0001: + print('x is %.6f\ny is %.6f\nand steps are %d' % (x, y, i)) + break + i += 1 + e = time.time() + print('time is %.4f second' % (e - s)) + + +if __name__ == '__main__': + random_points() + pass diff --git a/dot.png b/dot.png new file mode 100644 index 0000000..9855778 Binary files /dev/null and b/dot.png differ diff --git a/fitting.py b/fitting.py new file mode 100644 index 0000000..7011ae8 --- /dev/null +++ b/fitting.py @@ -0,0 +1,117 @@ +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: fitting.py + @DateTime: 2023/5/31 14:16 + @SoftWare: PyCharm +""" + +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import curve_fit +import pylab as mpl +from tkinter import * +import mpl_toolkits.axisartist as axisartist +import data as gl_data +import function + +mpl.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文不显示问题 +plt.rcParams['axes.unicode_minus'] = False #解决负数坐标显示问题 + +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 generate_and_plot_sample_data(low, high): + num_samples = 25#设置样本点数量 + gl_data.X = np.random.randint(low=low, high=high, size=num_samples)#随机生成x值 + gl_data.Y = np.random.randint(low=low, high=high, size=num_samples)#随机生成y值 + draw_axis(low, high)#绘制坐标轴 + plt.scatter(gl_data.X, gl_data.Y, color='red') # 绘制样本数据点 + plt.savefig(r"dot.png", facecolor='w')#保存到本地 + plt.close()#清除内存 + set_phtot(1)#显示到主界面 + +# 显示数据集 +def selfdata_show(x, y, low, high):# 显示数据集 + num_points = len(x) # 样本数据点的数量 + colors = np.random.rand(num_points, 3)# 生成随机颜色 + draw_axis(low, high) + plt.scatter(x, y, c=colors)# 绘制样本数据点 + plt.savefig(r"dot.png", facecolor='w') # 保存为png文件 + plt.clf() + set_phtot(1) + +def draw_line(xian_index, low, high, sx, sy): + draw_axis(low, high)#绘制坐标轴 + popt = []#初始化curve_fit + pcov = []#初始化curve_fit + cur = function.Fun[xian_index] # 装载正在选择的函数 + func = cur.get_fun()#获取当前函数func + popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合 + curve_x = np.arange(low, high)#按照步长生成的一串数字 + curve_y = [func(i, *popt) for i in curve_x]# 根据x0(按照步长生成的一串数字)来计算y1值 + plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve')#绘制拟合曲线 + plt.legend() + # plt.show()#显示函数图像 + plt.savefig(r"line.png", facecolor='w')#将图片保存到本地 + plt.close()#清除内存 + set_phtot(2)#将图片显示到程序中 + +def draw_dots_and_line(xian_index, low, high, sx, sy): + ############## begin ##################### + draw_axis(low, high) + popt = [] + pcov = [] + cur = function.Fun[xian_index] # 装载正在选择的函数 + func = cur.get_fun()#获取当前函数func + popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合 + positive_mask = sy >= 0.0#给样本点分类 + negative_mask = sy < 0.0#给样本点分类 + positive_colors = ['red' if x >= 0.0 else 'blue' for x in sx]#给样本点分类 + negative_colors = ['green' if x >= 0.0 else 'purple' for x in sx]#给样本点分类 + #根据样本点类型决定样本点颜色 + plt.scatter(gl_data.X[positive_mask], gl_data.Y[positive_mask], color=np.array(positive_colors)[positive_mask], lw=1) + plt.scatter(gl_data.X[negative_mask], gl_data.Y[negative_mask], color=np.array(negative_colors)[negative_mask], lw=1) + curve_x = np.arange(low, high)#按照步长生成的一串数字 + curve_y = [func(i, *popt) for i in curve_x]# 根据x0(按照步长生成的一串数字)来计算y1值 + ############## end ####################### + plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve')#绘制拟合曲线 + plt.legend() + plt.savefig(r"line.png", facecolor='w')#将图片保存到本地 + plt.close()#清除内存 + set_phtot(2)#将图片显示到程序中 + + + +def set_phtot(index1): + # 显示图像 + Canvas2 = gl_data.Canvas2 + if index1 == 1: + gl_data.Img1=PhotoImage(file=r"dot.png") + # print(gl_data.Img1) + set_img1=Canvas2.create_image(2, 10, image=gl_data.Img1, anchor=NW) + Canvas2.update() + print("已输出数据点") + elif index1 == 2: + gl_data.Img2=PhotoImage(file=r"line.png") + # print(gl_data.Img2) + set_img2=Canvas2.create_image(2, 10, image=gl_data.Img2, anchor=NW) + Canvas2.update() + print("已输出数据点和曲线") +if __name__ == '__main__': + # random_points() + + pass diff --git a/function.py b/function.py new file mode 100644 index 0000000..f4e5d40 --- /dev/null +++ b/function.py @@ -0,0 +1,137 @@ +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: function.py + @DateTime: 2023/6/6 14:45 + @SoftWare: PyCharm +""" +import numpy as np +import math +import data +import pandas as pd +from pandas import DataFrame +# 函数库 +Show = [] +Fun = [] +Fit_type_library = {} +class Function: + def __init__(self, no, name, v, fun, complete='', demo=''): + # 函数名称 + self.name = name + # 变量个数 + self.variable = v + self.function = fun + # 函数编号 + self.no = no + # 是否显示 + self.show = 0 + # 完整函数 + self.complete = complete + # self.print = '' + self.demo = demo + def get_fun(self): + if self.variable == 2: + return self.fun2 + elif self.variable == 3: + return self.fun3 + elif self.variable == 4: + return self.fun4 + elif self.variable == 5: + return self.fun5 + elif self.variable == 6: + return self.fun6 + + def fun2(self, x, a0, a1): + return eval(self.function) + + def fun3(self, x, a0, a1, a2): + return eval(self.function) + + def fun4(self, x, a0, a1, a2, a3): + return eval(self.function) + + def fun5(self, x, a0, a1, a2, a3, a4): + return eval(self.function) + + def fun6(self, x, a0, a1, a2, a3, a4, a5): + return eval(self.function) + + def print_f(self, a): + # print('self.show='+self.complete) + exec('self.show='+self.complete) + # print(self.show) + return self.show +def f_init(): + cur = 0 # 函数编号 + # 一次函数 + newfun = Function(cur, '一次函数', 2, 'a0*x+a1', "f'{a[0]}x+{a[1]}'", 'ax+b') + newfun.show = 1 + Fun.append(newfun) + cur += 1 + # 二次函数 + newfun = Function(cur, '二次函数', 3, 'a0*x*x+a1*x+a2', "f'{a[0]}x^2+{a[1]}x+{a[2]}'", 'ax^2+bx+c') + newfun.show = 1 + Fun.append(newfun) + cur += 1 + # 三次函数 + newfun = Function(cur, '三次函数', 4, 'a0*x*x*x+a1*x*x+a2*x+a3', "f'{a[0]}x^3+{a[1]}x^2+{a[2]}x+{a[3]}'", 'ax^3+bx^2+cx+d') + newfun.show = 0 + Fun.append(newfun) + cur += 1 + # 四次函数 + newfun = Function(cur, '四次函数', 5, 'a0*x*x*x*x+a1*x*x*x+a2*x*x+a3*x+a4' + , "f'{a[0]}x^4+{a[1]}x^3+{a[2]}x^2+{a[3]}x+{a[4]}'", 'ax^4+bx^3+cx^2+dx+e') + newfun.show = 0 + Fun.append(newfun) + cur += 1 + # 指数函数 + newfun = Function(cur, '指数函数', 2, 'a0*np.exp(0.01*x)+a1', "f'{a[0]}e^(0.01x)+{a[1]}'", 'a*e^(0.01x)+b') + newfun.show = 0 + Fun.append(newfun) + cur += 1 + # 对数函数 + newfun = Function(cur, '对数函数', 3, 'a0*(np.log(x) + 1e-5) / (np.log(a1) + 1e-5) + a2', + "f'{a[0]}log(x,{a[1]})+{a[2]}'", 'alog(x,b)+c') + newfun.show = 0 + Fun.append(newfun) + cur += 1 + # 高斯函数 + +# F_init() +def write(): + file_path = 'functions.xlsx'#设置路径 + df = pd.read_excel(io=file_path, header=1)#设置表格 + print(df) + df.columns = ['no', 'name', 'variable', 'function', 'complete', 'demo', 'show']#设置表格标题 + cur = 0#重置计数 + for f in Fun:#遍历函数类型 + df.loc[cur] = [cur, f.name, f.variable, f.function, f.complete, f.demo, f.show]#写进表格 + cur += 1#计数加一 + DataFrame(df).to_excel(file_path, sheet_name='Sheet1', index=False, header=True)#保存xlsx + + +def f_read(): + file_path = 'functions.xlsx'#设置路径 + df = pd.read_excel(io=file_path, header=0)#设置表格 + cur = 0 + for i in range(len(df)):#逐行读取excel + newfun = Function(df.loc[i][0], df.loc[i][1], df.loc[i][2], df.loc[i][3], df.loc[i][4], df.loc[i][5]) + newfun.show = df.loc[i][6] + Show.append(df.loc[i][6])#读取函数显示信息 + Fun.append(newfun)#读取函数信息并添加 + cur += 1 + for f in Fun:#建立简表fit_type_library + Fit_type_library[f.name] = [f.no, f.demo, f.name] +if __name__ == '__main__': + f_read() + # for f in fun: + # print([f.no, f.demo, f.name]) + for f in Fun: + Fit_type_library[f.name] = [f.no, f.demo, f.name] + + print(Fit_type_library) + a = [1,2,3,4,5] + x = 2 + + + pass diff --git a/functions.xlsx b/functions.xlsx new file mode 100644 index 0000000..7c656f3 Binary files /dev/null and b/functions.xlsx differ diff --git a/input.py b/input.py new file mode 100644 index 0000000..c29a72c --- /dev/null +++ b/input.py @@ -0,0 +1,83 @@ +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: input.py + @DateTime: 2023/7/19 16:59 + @SoftWare: PyCharm +""" +import tkinter as tk + +import numpy as np + +import data as gl_data +from tkinter import * +global top +def input_num(root_tk): + global top + top = tk.Toplevel(root_tk) + label1 = Label(top, text="坐标点个数") + label1.grid(row=0) # 这里的side可以赋值为LEFT RTGHT TOP BOTTOM + num1 = IntVar() + entry1 = Entry(top, textvariable=num1) + num1.set(0) + entry1.grid(row=0, column=1) + Label(top, text=" ").grid(row=0, column=3) + Button(top, text="确定", command=lambda: input_data(root_tk, int(entry1.get()))).grid(row=0, column=3) + top.mainloop() +def input_data(root_tk, num): + global top + sample_x = [] + sample_y = [] + sample_data = [] + top.destroy() + top = tk.Toplevel(root_tk) + def add_sample_data(): + try: + x = float(entry_x.get()) + y = float(entry_y.get()) + except: + label_status.config(text="输入不合法") + return + entry_x.delete(0, tk.END) + entry_y.delete(0, tk.END) + if min(x, y) < gl_data.low or max(x, y) > gl_data.high: + label_status.config(text="输入超过范围") + return + elif len(sample_data) < num: + label_status.config(text="点对已添加") + sample_data.append((x, y)) + sample_x.append(x) + sample_y.append(y) + else: + label_status.config(text="已达到最大数量") + def check_sample_data(): + if len(sample_data) == num: + label_status.config(text="已达到最大数量") + gl_data.x = np.array(sample_x) + gl_data.y = np.array(sample_y) + print('已添加', sample_data) + top.destroy() + else: + label_status.config(text="还需输入{}个点对".format(num - len(sample_data))) + print(sample_data) + + label_x = tk.Label(top, text="X 值:") + label_x.pack() + entry_x = tk.Entry(top) + entry_x.pack() + label_y = tk.Label(top, text="Y 值:") + label_y.pack() + entry_y = tk.Entry(top) + entry_y.pack() + button_add = tk.Button(top, text="添加", command=add_sample_data) + button_add.pack() + button_check = tk.Button(top, text="检查", command=check_sample_data) + button_check.pack() + label_status = tk.Label(top, text="") + label_status.pack() + top.mainloop() + + +if __name__ == '__main__': + root = tk.Tk() + input_num(root) diff --git a/line.png b/line.png new file mode 100644 index 0000000..bd6ae22 Binary files /dev/null and b/line.png differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2a10b60 Binary files /dev/null and b/requirements.txt differ diff --git a/test/一次函数.txt b/test/一次函数.txt new file mode 100644 index 0000000..1b60975 --- /dev/null +++ b/test/一次函数.txt @@ -0,0 +1,30 @@ +-1000.000000 -303.919733 +-934.000000 -350.424580 +-868.000000 -193.369993 +-802.000000 -474.832293 +-736.000000 -101.068322 +-670.000000 -33.916365 +-604.000000 -164.504704 +-538.000000 -147.298119 +-472.000000 -124.814141 +-406.000000 -139.033018 +-340.000000 -69.265051 +-274.000000 -90.553084 +-208.000000 -114.709905 +-142.000000 -103.201058 +-76.000000 -108.245882 +-10.000000 56.710600 +56.000000 18.503031 +122.000000 185.633626 +188.000000 152.615324 +254.000000 47.216669 +320.000000 256.009421 +386.000000 270.790257 +452.000000 61.971014 +518.000000 121.635726 +584.000000 163.906089 +650.000000 166.204626 +716.000000 315.640621 +782.000000 425.649206 +848.000000 454.347899 +914.000000 289.943295 diff --git a/test/三次函数.txt b/test/三次函数.txt new file mode 100644 index 0000000..eb6c019 --- /dev/null +++ b/test/三次函数.txt @@ -0,0 +1,30 @@ +-1000.000000 -2412.037897 +-934.000000 -1906.704565 +-868.000000 -1515.407287 +-802.000000 -1286.984468 +-736.000000 -991.348043 +-670.000000 -699.579002 +-604.000000 -834.074507 +-538.000000 -694.557977 +-472.000000 -503.237387 +-406.000000 -288.033015 +-340.000000 -248.449961 +-274.000000 -317.763223 +-208.000000 -254.540871 +-142.000000 -269.952677 +-76.000000 -252.274149 +-10.000000 -373.987676 +56.000000 -129.655207 +122.000000 -325.928443 +188.000000 -98.240616 +254.000000 -325.921235 +320.000000 -161.796895 +386.000000 96.648543 +452.000000 -245.636986 +518.000000 190.848311 +584.000000 225.026237 +650.000000 317.523583 +716.000000 772.606080 +782.000000 645.906241 +848.000000 1091.495759 +914.000000 1225.588183 diff --git a/test/二次函数.txt b/test/二次函数.txt new file mode 100644 index 0000000..10614a7 --- /dev/null +++ b/test/二次函数.txt @@ -0,0 +1,30 @@ +-1000.000000 1318.415137 +-934.000000 971.366429 +-868.000000 950.320306 +-802.000000 635.325663 +-736.000000 774.823634 +-670.000000 659.035975 +-604.000000 449.284057 +-538.000000 262.096521 +-472.000000 141.521962 +-406.000000 65.441983 +-340.000000 162.273141 +-274.000000 209.914028 +-208.000000 62.504373 +-142.000000 -160.439640 +-76.000000 -201.140961 +-10.000000 -178.764894 +56.000000 -194.056288 +122.000000 -221.386689 +188.000000 -236.245098 +254.000000 -317.086262 +320.000000 -385.718988 +386.000000 -198.736083 +452.000000 -256.246461 +518.000000 -226.361577 +584.000000 -329.214396 +650.000000 98.251218 +716.000000 -132.314476 +782.000000 62.741428 +848.000000 120.654860 +914.000000 356.397702 diff --git a/test/四次函数.txt b/test/四次函数.txt new file mode 100644 index 0000000..9023afe --- /dev/null +++ b/test/四次函数.txt @@ -0,0 +1,30 @@ +-1000.000000 6580.374854 +-934.000000 5230.299130 +-868.000000 4064.603309 +-802.000000 2824.002023 +-736.000000 2151.187862 +-670.000000 1341.067791 +-604.000000 997.401541 +-538.000000 512.994167 +-472.000000 103.881466 +-406.000000 85.927912 +-340.000000 -256.482213 +-274.000000 -97.197686 +-208.000000 -264.665117 +-142.000000 -237.702195 +-76.000000 -151.105677 +-10.000000 -130.269796 +56.000000 -102.814456 +122.000000 -62.662181 +188.000000 -357.518806 +254.000000 -149.197016 +320.000000 -350.461131 +386.000000 -264.914106 +452.000000 -94.032078 +518.000000 -188.344844 +584.000000 -60.854287 +650.000000 85.277762 +716.000000 413.822510 +782.000000 695.033449 +848.000000 1169.069640 +914.000000 1762.153163 diff --git a/test/对数.txt b/test/对数.txt new file mode 100644 index 0000000..32d83cc --- /dev/null +++ b/test/对数.txt @@ -0,0 +1,16 @@ +1.000000 -14.349565 +67.000000 321.611473 +133.000000 375.298867 +199.000000 386.511032 +265.000000 408.069269 +331.000000 423.359694 +397.000000 435.982565 +463.000000 458.199244 +529.000000 451.417416 +595.000000 471.376855 +661.000000 484.015127 +727.000000 489.640132 +793.000000 500.047206 +859.000000 499.698564 +925.000000 492.870266 +991.000000 509.779156 diff --git a/test/指数函数.txt b/test/指数函数.txt new file mode 100644 index 0000000..d34b980 --- /dev/null +++ b/test/指数函数.txt @@ -0,0 +1,30 @@ +-1000.000000 282.188733 +-934.000000 -121.080276 +-868.000000 89.565718 +-802.000000 -36.875112 +-736.000000 -2.179209 +-670.000000 -33.756961 +-604.000000 -199.536348 +-538.000000 -50.378169 +-472.000000 7.288867 +-406.000000 197.918480 +-340.000000 18.543165 +-274.000000 -80.038062 +-208.000000 -0.092604 +-142.000000 24.234519 +-76.000000 112.628196 +-10.000000 57.868872 +56.000000 -75.900181 +122.000000 53.411782 +188.000000 14.463053 +254.000000 -157.854773 +320.000000 3.419914 +386.000000 -95.442953 +452.000000 -511.818439 +518.000000 -785.633833 +584.000000 -1377.367723 +650.000000 -2606.119973 +716.000000 -5115.078474 +782.000000 -9770.399635 +848.000000 -19298.079697 +914.000000 -37316.681269