From 61e620d19d8af41481c6be90ab17486f7d014c8a Mon Sep 17 00:00:00 2001 From: bettleChen <2207153529@qq.com> Date: Thu, 31 Aug 2023 15:27:41 +0800 Subject: [PATCH] upload fitt project --- X1.py | 29 ++++ X2.py | 113 ++++++++++++++ X3.py | 343 ++++++++++++++++++++++++++++++++++++++++++ X4.py | 225 +++++++++++++++++++++++++++ X5.py | 265 ++++++++++++++++++++++++++++++++ data.py | 129 ++++++++++++++++ dot.png | Bin 0 -> 17287 bytes fitting.py | 117 ++++++++++++++ function.py | 137 +++++++++++++++++ functions.xlsx | Bin 0 -> 5387 bytes input.py | 83 ++++++++++ line.png | Bin 0 -> 21337 bytes requirements.txt | Bin 0 -> 666 bytes test/一次函数.txt | 30 ++++ test/三次函数.txt | 30 ++++ test/二次函数.txt | 30 ++++ test/四次函数.txt | 30 ++++ test/对数.txt | 16 ++ test/指数函数.txt | 30 ++++ 19 files changed, 1607 insertions(+) create mode 100644 X1.py create mode 100644 X2.py create mode 100644 X3.py create mode 100644 X4.py create mode 100644 X5.py create mode 100644 data.py create mode 100644 dot.png create mode 100644 fitting.py create mode 100644 function.py create mode 100644 functions.xlsx create mode 100644 input.py create mode 100644 line.png create mode 100644 requirements.txt create mode 100644 test/一次函数.txt create mode 100644 test/三次函数.txt create mode 100644 test/二次函数.txt create mode 100644 test/四次函数.txt create mode 100644 test/对数.txt create mode 100644 test/指数函数.txt 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 0000000000000000000000000000000000000000..9855778b32ad9db909d789cad42b8422c38fe4f6 GIT binary patch literal 17287 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", 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 0000000000000000000000000000000000000000..7c656f373716df58498925353d81a5790ec87669 GIT binary patch literal 5387 zcmZ`-1yoe)_Z><}krD(6r5gqilm_XR4r!!2q$P$>YK9huPN|{08;PN$OF~4tMpFLc zbG`MR{NHb8-8<{9HT&H2?X~y$&UaK5(9nqi001VyTEAaQTCW2)2>DcjyzV0}b4N2( z7e^;oP7^054o`bKrD!FbPOkeeZsfNX9W)PUxM?PHRt9`z`JaN#B|So}eAPQ*=7pBH zA{$9Q>2%Y+;S239@Fy6M0o3A1cS%lsd?-UtZmmNlHsTdQG;7&SS5DD~W=x{UGm?5m zxl{9e^HDS3D)UxxT}U$2Ey;$P=`6|iI67pynYz~T+ytX7?gB&gk9@!L4RL=*<~fK0 z01*5;Uo%G+i(d)nK{}MXxNt*_EWWq6&&i`@vyt9s1cQ^&S0B(XJs9IvGo9Sql^dK2 zTAZvP%ldv|2ZoxWnclud=A;gdOF|$V ze2n@-`RoU#=$n=*6Zy59TfI^ZL@zicHlr42-;%*mnOCOU22}ne=7Ry0_Wm6J0Llme z5Fv^2wBvNMvaq-Kedqo~&90ul>zn|w|2}Ng(-L8i)B7~AwwlP*+GD=@187&7I)p$c z%FfFi0(#pf^Ys2;BHnJSQe&zRI@{Leh?LCcHvzBXJr2`vq2cjIp2oAB^HWWAoJ%X( zKso|(u7?G%gLdpZMZ+3BYe1KP-vAL|*FsPPrh+H&;FQ6NJ~=1t)c5N7MJIVCXAfr~KyA)^BKfk86>|bN?m2*hu`vcsudJF zN?&Ed_RZo%^t;~DQBSQ&jbZiPyeg z>5LsW08hc0YgEZGQ~Co>Wr7~}EWoZ$lbQx{dA!s7o{!kZzqKw#DcEgFg~wgFep}Bd zh?`cD7;$Q5!#cdA)i()abPyzRdH%>!!WWJ}K=SB;@cnb_ZDk=#YOTcbS8(`xdZY_& z(;`C051}ICKs)`hz3RzyyfmFuMn8MwI)Olq93GHJ6f-R}*+%sdYAzOcVpix`b#Dp5 z3Xxx3D`x+4RQQi##}r}hEFHNy(Aj-y@>QtoSJyGS%e#5fV+hUWg`6ZE5|kveW!@q_ zww@`^g!aQys1PL);cz_89r4g4ItIdz&-|5SiGH%?&HaQq=IynkYxL;0{DK`1CuEh(y`AA_u$4ya&s(J7^!1gsJwrVpQzyVN`g ztabhfGS(yP9rIKkuO_(CE#Zq3G49_PhPaPRLGBU68uBCmI}!mVXrl@hkWbmocGf|^ zPB-k5>-ZKl`1-ouKlC$?9b5DdnMqRlb$o^b(JdhF-JBF%tQL@#O-4}|uSg*k5F6vL zfl6e<+Y_5VvA0>ZEXW7tW^9hXv-m8i{n=X%KX~4L!-;U#cpX2jpJm5Hg#MDWgMRmA z8TZ^YF9(yEw##sTp9U?_{`wXy%T0t0elBFRSv`!yBU$I7@Vz#^ zwT3}J{-k2aNttR8SI|-@ma_IuCMDk`;+4lbZ623;l4L!(L@SzoW7@)Vf%IfZ1NOvA zuw&QxR*xt7>a$t&2ESx&`^}lLvCGX4wep;Op+w5Q@T2U- zF&>k;tnKf|*}RFIzF-Tq2WbG!Ka+lveAgk&<03huL4RB}$AA+uzp63ZMBd6^tkC7{ zkjBnx@fXNu|^xctm%{`nG`;a4Iy$z1;qzxVG0 z2#QTx8(}Kv^iaWSpTj_!)T^oaT*TrEuJ2^AUYzsX zO?SJ#WyorSftg|gi&CXaei`#Hr+W+Tw1Ct`^16VTV`8o>fyJs#;Gpi3An_5wUB|vZ70?}X8gbz`v{m* z?15}a?6Q)odqzC#CEWgug49Axbv0FWj~P? zf1+-P&zh8~sG7heiq9$;`xPs{63XB839|qQtm`UrQSu05Njo3=VCtT)^8}F5H{bAO zdtSsB2h;y(1ggwPO0BY_n{L){<)Fx!f3#CEe`i3sXuh$GRngMPF~Lqmm$zHJ?>5>`Wv9th-W66koTeNZdMqfgd90#qB6JX z0L#FYYZvBx<`^b8G`J7iPsQ^>fI}`WcaziZRiVKPLU?!`h4-0;u7yTehg8$aUD5P1 zzmn?rQeanX+SfJP9%)G~-RTeJJCsGiC)CoT>)Myq4nn(f2wM)ZT<#39Y_OQ!Q#-r# zTF^er5@P>363~lkg4!kkWX!bkVT6ugHMwUax*dd^0V?ehUPA$4I9|DhP<>5^W_+`1yYn*OgN@xBgW>MT6=v&HZyL`n8HhTM%1 zSRTwPzFxOqFbtay-rVdAcAhU=qY9a)(Amur!u|1ZEe-rxm+vKSPdD`fB%9Tq5%{Ae z<;gOB=1eKcle5dY(6P~Izyn5@@unL#1!=26Qg^r^kLEVz3HO0RVd(008f|$6VdK z>?~Y=wP%Z3^UssufD)J{^}&n6t@S3~Nm>4x%?ID^f$KoAr^eHdt3wfDhw z;k%CxdhB#-Z}yej&g0e=i@u&CGw+TAd?$5^c_*I@royMT1NvdOtcWyH=+>bc#b%_$ zM*=%XUK|M2O51I@pT(V$*R;~TSgNb8@!N)$p9c|!tVv&|Jo=+*0B-A zvK!lu9B4gI(Ty)N_|tpMRDp z9f)ae;R_WWJsI;R9>=28PO~B}GpYmZ2x@hybR?k7d_G8w8W&FMU`bowZzjlLfj3c= zKX9I=d)uXEKs;f6$5Mj-sy)@-V9sy12OZss0>;(PKiblU8E%dN4!BR}2QdMcwA1=s z$9R=~YetoouJ@+U8!I6h#%|`%Ds7W9LN5kI$TqMYH#7AgIn+6ZRnXh&5T8B9jU{*z zb`rAmv-XGwjf>~$+hn}T!74M!d?B7}^G`epGU0`fT|UK<0meyP`t!j=A>#L2ohC80 z(#@I>^&hh?Kbe+uh`*x&~A0SnY6g9xe#lp^&ljGMtEmpw+l^a(KMrdKA_^}(6 zyJV(ZG90J=-Db{*Zird;2_kByoyLkl;U+zu9fr@F>G8;QKF_X~tJ`2!i?0+=Y0GS! z?wqZ|!lxj{p2Z6uJ)ODF_Vt*)pS{ars!q}MO6~+3vfb!fZSe-1_!Q-=tSg09UQ%z? zIeU&l_V zw|SrLjyeR%DQ+7k2gqUGm-K<_y{Sp;PFQm&hcU`AE3Sqx_DxR>v=~Ce@ddLb5hhW` zt{j@IJutGG_*LW453H6pXCwX-`-WM$e#rf(HS3x_h#9dl@Mv4Ow)QS6K zZoB$`iq~SgQOfM3IaS&tM}yJmMQ7?7Ih9fZ=gT28uVqf^C4-N2i%y2WUYX zS=%9dW0(i>I6_>fl#PC!AhL6*Xt(zjua)(gG_x7-v&yzRV$esWo~N6U9W?%wj)szx zyQzxa1;+$~i?A7^=pp&j{BiRut^8j(tT^}Hxm}ytHGe}ogg!DZ@8AFrHjuijc@YN!N=0=d9xWRvylgsv~?=-_7I;AW)Z zX(X2JYKd0dYE^nCZ0cvdV-v`Dx)VYh3QG`ZxIAXYoW;!8j#9 z_pS-l+hezYQ#$5gwSFSf8LBGauCUZ>h#VuQf48=}a*8j1D8A-0-)?NV?89i zhhUSdrC|qSaD(jnq&+slYz_L`%{05M;)s3;aKFK`b&&b)EF);i8Sg?%K;?`!*W&=a zr+kR|_)P}mwLZBQe%AHA&lD^#u2%&w{EIM56xpnzpb`WA_uvXi=wF`zB*XuIjCC7* zdyMoO3jhS5l>Zz3_fY9J{PwWrANTwP=Q?RMht zC;=!A$Xbj{*@ahh<9^H literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bd6ae22eaeb2f8dc916858d739d6b4003a07cb90 GIT binary patch literal 21337 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 xtuPsRWCyHqh;?vT1I|{sRJIElvOc literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a10b600ecb69c30796b4f1006b96b79f20e21c0 GIT binary patch literal 666 zcmZva-A=+l6olv6#7B{|1^+I12VVi#q77xcX^T`IUY$8-3mOgShIHn9Gkf6cGoVAn z$n$_62_IPVQ(|FHfoohL@NGbgnhvRjsq(m9bN&Vs_VjGgnDZ}Xo0F8)(K8rpMat?& zRzpgn-jmsq^-OZleoD8%3V-RF>ilIU-(o`W7nAYO702 zc;ZxR9gj9ynkL=%tz;2;PG9)CgFKJMkY~gj?-{v4C5>!-;3>BES>S>GxwHJItQ5Je o_ZfJb=GQ*T{14Gi)nUp#wIlysq=@Iqn}4|{qbAeT-e