You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fitt/X5.py

266 lines
12 KiB

# -*- 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(' ')#以空格分割xy
print(f'sx: {float(sx)}, sy: {float(sy)}')#将sx、sy转换为浮点数并打印
def read_sample_data(file_path):
x, y = [], []#初始化xy
with open(file_path, 'r') as file:
for line in file:#逐行读文件
line = line.strip('\n')#移除换行符
sx, sy = line.split(' ')#以空格分割xy
x.append(float(sx))#将sx转换为浮点数并加入数组
y.append(float(sy))#将sy转换为浮点数并加入数组
gl_data.X, gl_data.Y = np.array(x), np.array(y)#xy数组转为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