2024/06/07

学习时长:4小时

代码行数:166行

博客数量:1篇

今天主要完成了python大作业的有关内容

散点图的曲线拟合:可视化界面实现

import tkinter as tk
import numpy as np
import re
import os
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from tkinter import messagebox

# 存储输入框的结果
entry_results_x = []
entry_results_y = []

def save_fit_results(x_data, y_data, params):
    
    # 将拟合的参数转换成函数表达式的形式
    function_expression = 'y = {:.2f}x^4 + {:.2f}x^3 + {:.2f}x^2 + {:.2f}x + {:.2f}'.format(*params)

    with open("big_work/拟合记录.txt", "a",encoding="utf-8") as file:
        file.write("参数坐标 (x, y):\n")
        for x, y in zip(x_data, y_data):
            file.write("({:.2f}, {:.2f})\n".format(x, y))
        
        file.write("\n拟合结果表达式:\n")
        file.write(function_expression + "\n\n")
    extremum_points = calculate_extremum_points(params)
    messagebox.showinfo("极值点", "拟合曲线的极值点为: " + str(extremum_points))
    

def save_function_results(function_expression, x, y):
    folder_name = "big_work/表达式生成记录"
    os.makedirs(folder_name, exist_ok=True)
    file_name = re.sub('[^A-Za-z0-9]+', '_', function_expression)
    # 保存函数表达式数据到文件
    data_file_path = os.path.join(folder_name, "表达式.txt")
    with open(data_file_path, 'a',encoding="utf-8") as file:
        file.write("函数表达式: {}\n".format(function_expression))
    
    # 保存函数图像到文件
    image_file_path = os.path.join(folder_name, file_name+"_plot.png")
    plt.savefig(image_file_path)
    

def add_entry():
    height = 0
    row = len(entry_results_x) // 21
    entry_x = tk.Entry(canvas, font=('Arial', 10), width=5)
    entry_results_x.append(entry_x)
    entry_y = tk.Entry(canvas, font=('Arial', 10), width=5)
    entry_results_y.append(entry_y)
    entry_window_x = canvas.create_window((len(entry_results_x) - row * 21) * 50 + 100, 570 + row * 60, window=entry_x, anchor='center')
    entry_window_y = canvas.create_window((len(entry_results_y) - row * 21) * 50 + 100, 600 + row * 60, window=entry_y, anchor='center')

def complex_func(x, a, b, c, d, e):#拟合曲线
    return a*x**4 + b*x**3 + c*x**2 + d*x + e

def calculate_extremum_points(params):#求极值
    a, b, c, d, e = params
    extremum_x = -b / (4 * a)
    extremum_y = complex_func(extremum_x, a, b, c, d, e)
    extremum_type = "极小值" if a < 0 else "极大值"  # 判断极值点类型
    return extremum_x, extremum_y, extremum_type

def plot_extremum_points(params):
    extremum_x, extremum_y,extremum_type = calculate_extremum_points(params)
    extremum_text = "极值点: {}:({:.2f}, {:.2f})".format(extremum_type,extremum_x, extremum_y)
    extremum_point_label = tk.Label(canvas, text=extremum_text, font=('Arial', 12), bg='ivory')
    extremum_point_window = canvas.create_window(50, 50, window=extremum_point_label, anchor='nw')
 
    extremum_point_label.update_idletasks()

    root.update()

def fit_data():
    x_data = []
    y_data = []

    for entry_x, entry_y in zip(entry_results_x, entry_results_y):
        x_value = entry_x.get()
        y_value = entry_y.get()
        if x_value and y_value:
            x_data.append(float(x_value))
            y_data.append(float(y_value))

    if len(x_data) < 5 or len(y_data) < 5:
        messagebox.showerror("Error", "请至少提供五个数据点用于拟合曲线!")
        return

    # 使用Scipy进行曲线拟合
    params, _ = curve_fit(complex_func, x_data, y_data, p0=[1, 1, 1, 1, 1])

    # 绘制原始数据和拟合曲线
    plt.figure()
    plt.scatter(x_data, y_data, color='blue', label='Data points')
    plt.plot(np.linspace(min(x_data), max(x_data), 100), complex_func(np.linspace(min(x_data), max(x_data), 100), *params), color='red', label='Fitted curve: y = {:.2f}x^4 + {:.2f}x^3 + {:.2f}x^2 + {:.2f}x + {:.2f}'.format(params[0], params[1], params[2], params[3], params[4]))
    plt.legend()
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.title('Fitting Result')

    # 保存图像并在画布上显示
    plt.savefig("fit_plot.png")
    fit_image = tk.PhotoImage(file="fit_plot.png")
    fit_image_label = tk.Label(canvas, image=fit_image)
    fit_image_label.image = fit_image
    fit_image_window = canvas.create_window(650, 300, window=fit_image_label, anchor='center')
    # 调用保存函数
    save_fit_results(x_data, y_data, params)
    if(var1.get()):
        messagebox.showinfo("Data Saved", "保存记录成功")
    plot_extremum_points(params)

def plot_function():
    function_expression = entry_function.get()
    x = np.linspace(-10, 10, 400)
    try:
        y = eval(function_expression)
        plt.figure()
        plt.plot(x, y, color='blue')
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.title('Function Plot: ' + function_expression)

        # 保存图像并在画布上显示
        plt.savefig("function_plot.png")
        function_image = tk.PhotoImage(file="function_plot.png")
        function_image_label = tk.Label(canvas, image=function_image)
        function_image_label.image = function_image
        function_image_window = canvas.create_window(650, 300, window=function_image_label, anchor='center')
        # 调用保存函数
        if(var1.get()):
            save_function_results(function_expression, x, y)
            messagebox.showinfo("Function Plotted", "保存文件成功")
    except Exception as e:
        messagebox.showerror("Error", "无法绘制该函数,请检查输入是否正确!")

root = tk.Tk()
root.geometry('1300x900')
root.title('散点拟合器')
canvas = tk.Canvas(root, width=1300, height=900, bg='ivory')

button_fit = tk.Button(canvas, width=20, height=4, bg='ivory', text="开始拟合", command=fit_data)
button_fit_window = canvas.create_window(400, 800, window=button_fit, anchor='s')

add_button = tk.Button(canvas, text="添加点坐标", command=add_entry)
add_button_window = canvas.create_window(400, 710, window=add_button, anchor='s')

x_text = tk.Label(canvas, text="横坐标:", width=5, height=2, font=('Arial', 12), bg='ivory')
x_text_window = canvas.create_window(80, 570, window=x_text, anchor='center')
y_text = tk.Label(canvas, text="纵坐标:", width=5, height=2, font=('Arial', 12), bg='ivory')
y_text_window = canvas.create_window(80, 600, window=y_text, anchor='center')

fun_draw=tk.Label(canvas, text="函数表达式:", width=12, height=2, font=('Arial', 12), bg='ivory')
fun_draw_s = canvas.create_window(800, 700, window=fun_draw, anchor='center')

entry_function = tk.Entry(canvas, font=('Arial', 10), width=20)
entry_function_window = canvas.create_window(920, 700, window=entry_function, anchor='center')

var1 = tk.IntVar()#勾选保存
checkbutton1 = tk.Checkbutton(canvas, text="保存记录", variable=var1,bg='ivory')
checkbutton1_window = canvas.create_window(600, 700, window=checkbutton1, anchor='nw')

plot_button = tk.Button(canvas, width=20, height=4, bg='ivory', text="绘制函数", command=plot_function)
plot_button_window = canvas.create_window(870, 800, window=plot_button, anchor='s')

canvas.pack()
root.mainloop()

 

posted @ 2024-06-07 21:14  伐木工熊大  阅读(10)  评论(0编辑  收藏  举报