用Python的Tkinter、Numpy、Matplotlib库对曲线拟合的一点探索【已改进】

需要用到的库:如标题
三大方面 功能 需要的库
一、 简单交互,获取函数或者样本点 tkinter[python自带]
二、 处理所获得的信息,并得到绘图所需数据 numpy,math
三、 根据所得到的数据进行绘图 matplotlib

首先得把需要的库给 import 喽,没有安装的库 pip install 一下也就OK啦

上码

from tkinter import *
import tkinter.messagebox as messagebox
from numpy import *
import numpy as np
import sys
import math
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.gridspec as gridspec

一、 交互界面的设计[tkinter]

函数字符串为数据源部分 功能 tkinter相应实现模块
1 函数字符串获取 单选按钮
2 插值区间选择 滑动条
3 随机获取样本点的数量 微调框
4 文字部分 标签
5 按钮部分 按钮

样本点为数据源部分 功能 tkinter相应实现模块
1 样本点获取 文本框
2 拟合阶数选取 滑动条
3 删除,添加,确认按键 按钮
代码来了
class Miao(get_list, plot):def __init__(self):get_list.__init__(self)plot.__init__(self)self.master = Tk()self.xlst = [StringVar() for i in range(400)]self.ylst = [StringVar() for i in range(400)]self.etx = [Entry() for i in range(400)]self.ety = [Entry() for i in range(400)]self.entryfx = Entry()self.f_ = IntVar()  # 判断函数字符串是选择还是写入的标志self._fx = StringVar()  # 存储用户所选函数串self.fff = 0  # 判断是否进行函数选择, 否则self.num = StringVar()  # 判断数字框输入是否非法的字符串变量self.nm = IntVar()  # 存储样本点数量的整数型self._lx, self.lx_ = IntVar(), IntVar()  # 存储 x左右 范围(取点、插值、画图self.fx = IntVar()  # 选择项值获取self.paint = 0  # 判断,如果不是第一次绘图,就先清空画板self.ifpoint = 0  # 判断是样点作图还是函数作图self.point_ct = 0  # 统计样本点个数self.fdict = {0: 'cos(2*pi*x)*(e**(-x)) + 0.8',1: '1/(1+25*x**2)',2: '(e**(-x**2/2))/(2*pi)**0.5',}self.f_x = StringVar()  # 文本框获取值self.lst = []  # 存储 画图数据的列表self.ep = 10  # 插值区间长度初始值self.ojbk = 0self.master.title('插值法及函数图像简单拟合函数')# self.master.geometry('630x700+100+30')# 滚动条设定canvas = Canvas(self.master, confine=True, width=660, height=800, scrollregion=(-1, -1, 660, 1100))  # , bg='snow')scrollbar = Scrollbar(self.master, command=canvas.yview, bd=2)scrollbar.pack(side=RIGHT, fill=Y)canvas.pack(fill=Y)canvas.config(yscrollcommand=scrollbar.set)# 文字 (Label)title = Label(self.master, text='简单插值法以及曲线拟合', font=('黑体', 18), bg='turquoise', fg='black')title.pack(fill=X)canvas.create_window(280, 15, height=24, window=title, anchor=CENTER)# frame1 请您输入self.frame1 = Frame(canvas)self.frame1.pack(fill=X)label1 = Label(self.frame1, text='【1】请选择/输入一个函数:', font=('楷体', 14), fg='darkblue', bg='seashell')label1.grid(row=1, column=0, sticky=W)# 单选按钮fxx = [(0, "cos(2*pi*x)*(e**(-x)) + 0.8"),(1, "1/(1+25*x**2)"),(2, "(e**(-x**2/2))/(2*pi)**0.5"),]j = 2for fid, fx in fxx:fx = Radiobutton(self.frame1, text=fx, fg='cornflowerblue', variable=self.fx, font=('楷体', 13), value=fid,command=self.getfx)fx.grid(row=j, column=0, stick=W)j += 1fx = Radiobutton(self.frame1, text='手动输入函数', fg='cornflowerblue', variable=self.fx, font=('楷体', 13), value=3,command=self.if_5)fx.grid(row=6, column=0, stick=W)fx = Radiobutton(self.frame1, text='输入样点数据', fg='cornflowerblue', variable=self.fx, font=('楷体', 13), value=4,command=self.get_point)fx.grid(row=5, column=0, stick=W)canvas.create_window(20, 120, window=self.frame1, anchor=W)# 输入说明frame2 = Frame(canvas)frame2.pack()# 容器框 (LabelFrame)self.group = LabelFrame(frame2, text="函数输入说明", font='5', padx=5, pady=5, fg='red')self.group.grid()labels = ["1.平方‘**’来表示,绝对值:abs(x),乘号‘*’,除号‘/’,加减号‘+’ ‘-’","2.支持无理数e的输入,圆周率用pi表示","3.未知变量统一用x表示(只限用x表示),不支持中文符号输入(如中文输入法的括号。","4.一些简单示例: sin(x), cos(x), cos(pi*x), e**x, (10-abs(x))**0.5,log(x)","5.函数解析基于Python Numpy,有兴趣可以多尝试一些函数表达(4. 没列出的","6.注意暂不支持纯数字输入! 若是输入log(x),请勿选择负区间,否则函数失效(开根号也如此)"]for lb in labels:w = Label(self.group, text=lb, fg='darkcyan', font=('宋体', 10))w.grid(sticky=W)canvas.create_window(11, 290, window=frame2, anchor=W)# 区间选择  注意判断大小# frame4 请您输入self.frame4 = Frame(canvas)self.frame4.pack(fill=X)label4 = Label(self.frame4, text='【2】请选择一个取样区间:', font=('黑体', 14), fg='darkblue', bg='seashell')label4.grid(row=0, column=0, sticky=W)label4 = Label(self.frame4, text='  \n ')label4.grid(row=1, column=0, sticky=W)# 单选按钮  挡位frm = Frame(canvas)frm.pack()lab = Button(frm, relief='sunken', borderwidth=3, text='请选择档位:', font='12', fg='tomato')lab.grid(row=1, column=0, sticky=W)self.dwdict = {0: 'x1',1: 'x5',2: 'x10',3: 'x20',4: 'x0.1',5: 'x0.01',6: 'x0.001'}cl = 1self.dw = IntVar()for d in self.dwdict:dx = Radiobutton(frm, text=self.dwdict[d], fg='blue', variable=self.dw, font=('楷体', 14), value=d,command=self.getdw)dx.grid(row=1, column=cl, stick=W)cl += 1canvas.create_window(15, 410, window=frm, anchor=W)# 滑动条 (Scale)self.lx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280, label="从",tickinterval=5, relief=GROOVE)  # 默认垂直self.lx.grid(row=2, column=0, sticky=W)self.rx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280, label="到",tickinterval=5, relief=RIDGE)  # 默认垂直self.rx.grid(row=2, column=1, sticky=W)canvas.create_window(10, 440, window=self.frame4, anchor=W)# 改变选区frameb = Frame(canvas)frameb.pack()low = Button(frameb, text='减小选择区间', borderwidth=4, font=('隶书', 11), command=self.lower, )low.grid(row=1, column=0, sticky=W)up = Button(frameb, text='扩大选择区间', borderwidth=4, font=('隶书', 11), command=self.upper, )up.grid(row=1, column=1, sticky=W)canvas.create_window(185, 530, window=frameb, anchor=W)#  插值点个数frame5 = Frame(canvas)frame5.pack(fill=X)label5 = Label(frame5, text='【3】请选择取样点个数', font=('黑体', 14), fg='darkblue', bg='seashell')label5.grid(row=2, column=0, sticky=W)self.number = Spinbox(frame5, borderwidth=2, relief='raised', font=10, textvariable=self.num, from_=3, to=500)self.number.grid(row=2, column=1, sticky=W)label51 = Label(frame5, text='[请选择或输入 3~500 间的整数]', fg='red')label51.grid(row=2, column=2)canvas.create_window(12, 565, window=frame5, anchor=W)# 输入说明framep = Frame(canvas)framep.pack()# 容器框 (LabelFrame)self.group = LabelFrame(framep, text="整体框架说明", font='4', padx=5, pady=5, fg='steelblue')self.group.grid()labels = ["一、插值法部分"," 1.由用户输入合法的函数字符串,选择取样区间及样本点个数;"," 2.确认输入无误后开始执行,相对随机进行样本点的获取;"," 3.由所得样本点经过拉格朗日/牛顿插值法、分段二次插值法、\n分段法再拟合出函数图;"," 4.最后展示拟合图像以及原图像\n"," 标注:分段二次插值法是照搬书上套路,分段法是将函数为三段:\n\r中间一段用拉格朗日/牛顿插值法得到\n\r两边两段用二次插值法得到","\n二、最小二乘法部分"," 1.用户输入一系列样本点,并选择拟合函数的阶数进行拟合"," 2.由于一些原因,可能出现无法拟合,这时可以调整一下你和阶数"," 3.阶数说明:由于这里拟合默认拟合曲线方程为x的幂次多项式,阶数即是\nx的最高幂次","",]for lb in labels:w = Label(self.group, text=lb, fg='seagreen', font=('楷书', 11))w.grid(sticky=W)canvas.create_window(20, 840, window=framep, anchor=W)# ok按钮  (Button)framed = Frame(canvas)framed.pack()okk = Button(framed, relief='raised', borderwidth=5, text='确认输入', font=('楷书', 14), width=55, command=self.ok)okk.grid(row=1, column=0)canvas.create_window(10, 620, window=framed, anchor=W)framed1 = Frame(canvas)framed1.pack()okk = Button(framed1, relief='raised', borderwidth=4, text='点\n击\n退\n出', font=('楷书', 14), bg='red',command=self.for_end)okk.grid(row=1, column=0)canvas.create_window(500, 100, window=framed1, anchor=W)framed2 = Frame(canvas)framed2.pack()end = Button(framed2, relief='raised', borderwidth=4, text='   确认输入   ', bg='aqua', font=('楷书', 14),command=self.ok)end.grid(row=1, column=0)canvas.create_window(440, 170, window=framed2, anchor=W)self.master.mainloop()# 区间上升(主框架def upper(self):if self.ep < 20:self.ep += 5lb = 5self.lx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280,label="从", tickinterval=lb, relief=GROOVE)  # 默认垂直self.lx.grid(row=2, column=0, sticky=W)self.rx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280,label="到", tickinterval=lb, relief=RIDGE)  # 默认垂直self.rx.grid(row=2, column=1, sticky=W)# 区间下降(主框架def lower(self):if self.ep > 5:self.ep -= 5if self.ep > 5:lb = 5else:lb = 1self.lx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280,label="从", tickinterval=lb, relief=GROOVE)  # 默认垂直self.lx.grid(row=2, column=0, sticky=W)self.rx = Scale(self.frame4, from_=-self.ep, to=self.ep, orient=HORIZONTAL, resolution=1, length=280,label="到", tickinterval=lb, relief=RIDGE)  # 默认垂直self.rx.grid(row=2, column=1, sticky=W)# 按钮获取函数(主框架def getfx(self):self.entryfx.destroy()if self.ifpoint:try:self.pt.destroy()except:passself.f_ = 0self.fff = 1self.ifpoint = 0self._fx = self.fdict[self.fx.get()]# 文本框中函数获取(主框架def if_5(self):self.f_ = 1  # 如果点击了 自己输入  标记self.f_ 为 1 否则为 0if self.ifpoint:try:self.pt.destroy()except:passself.ifpoint = 0  # 判断是输入样本点还是函数字符串  字符 0  样本点 1# 输入框 (Entry)  #自我输入函数框图self.entryfx = Entry(self.frame1, textvariable=self.f_x, width=30)self.entryfx.grid(row=7, column=0, columnspan=4, sticky=W)# 获取插值点个数档位函数(主框架def getdw(self):self.dw_ = float(self.dwdict[self.dw.get()].strip('x'))# 判断 函数字符串输入结束, 开始画图(主框架# 改+++++def ok(self):self.ifpoint = 0self._lx, self.lx_ = self.lx.get() * self.dw_, self.rx.get() * self.dw_if self.f_ == 1:  # 捕捉获取的字符串self._fx = self.f_x.get()if self.fff == 0 and self.f_ != 1:self._fx = "cos(2*np.pi*x)*np.exp(-x) + 0.8"if self._lx > self.lx_:self._lx, self.lx_ = self.lx_, self._lxif not self.num.get().isdigit():messagebox.showwarning('Warining', '条目[3]非法输入')else:if not isinstance(type(eval(self.num.get())), int) and not 2 < eval(self.num.get()) < 501:messagebox.showwarning('Warining', '条目[3]非法输入')elif not self._fx:messagebox.showwarning('Warining', '函数输入为空')elif self._lx == self.lx_:self.warn1()else:self.nm = int(self.num.get())if messagebox.askokcancel('这是一个弹窗', '输入完成,是否开始下一步'):self.ojbk = 1lt = self.get_flist()try:self.s_plot(lt)except Exception as t:print(t)messagebox.showerror('(*_*)', '运行失败了T_T')# 结束运行 关闭窗口(主框架def for_end(self):if messagebox.askokcancel('这是一个弹窗', '是否确认退出?'):sys.exit(0)#\ 获取样本点(开小框架获取样本店 框架0.1def get_point(self):if self.ifpoint == 1:try:self.pt.destroy()except:passself.ifpoint = 1self.noinfo_window = 1  # 判断提示弹窗是否出现self.entryfx.destroy()self.point_ct = 0  # 统计样本点个数self.ex = []  # 置空刷新self.ey = []  # 置空刷新self.m = 1  # 阶数 默认为1global pdpd = Spinbox()self.pointdic = {}self.pt = Tk()self.pt.title('样本点获取')self.pt.geometry('350x500+800+30')# 滚动条设定canvas1 = Canvas(self.pt, confine=True, width=500, height=3000,scrollregion=(0, 0, 500, 3000))  # , bg='snow')scrollbar = Scrollbar(self.pt, command=canvas1.yview, bd=2)scrollbar.pack(side=RIGHT, fill=Y)canvas1.pack(fill=Y)canvas1.config(yscrollcommand=scrollbar.set)# 文字 (Label)title = Label(self.pt, text='样本点获取', font=('黑体', 18), bg='lightblue', fg='black')title.pack(fill=X)canvas1.create_window(150, 15, height=24, window=title, anchor=CENTER)lbxy = Label(self.pt, text='X       \t   Y', font='10', )lbxy.pack(fill=X)canvas1.create_window(150, 140, height=24, window=lbxy, anchor=CENTER)# 拟合函数阶数frm1 = Frame(canvas1)frm1.pack(fill=X)lbl1 = Label(frm1, text='*请选择一个拟合函数阶数:', font=('黑体', 11), fg='darkblue')lbl1.grid(row=0, column=0, sticky=W)self.pdw = IntVar()pd = Spinbox(frm1, borderwidth=2, width=15, relief='raised', font=10, textvariable=self.pdw, from_=1, to=150)pd.grid(row=1, column=0, sticky=W)label51 = Label(frm1, text='[1~150 间的整数]', fg='red')label51.grid(row=1, column=1, sticky=W)canvas1.create_window(15, 100, window=frm1, anchor=W)# 数据文本框 系列self.frm2 = Frame(canvas1)self.frm2.pack()canvas1.create_window(150, 160, window=self.frm2, anchor=N)# 添加数据按钮button1 = Button(canvas1, text='添加数据', borderwidth=5, command=self.newp)canvas1.create_window(20, 50, window=button1, anchor=W)# 删除数据按钮button1 = Button(canvas1, text='删除上一数据', borderwidth=5, fg='red', command=self.del_last)canvas1.create_window(90, 50, window=button1, anchor=W)# 完成按钮button1 = Button(canvas1, text='输入完成', borderwidth=5, fg='blue', bg='snow', command=self.f_end)canvas1.create_window(250, 50, window=button1, anchor=W)self.pt.mainloop()#\ 创建新数据表  样本点(框架0.1def newp(self):if self.point_ct == 0 and self.noinfo_window:self.noinfo_window = 0messagebox.showinfo('输入小提示', "1.不支持数字外其他输入,比如符号,字母;\n2.可以x,y都为空,但不能只有一个值;\n3.x值可以不按照数轴顺序输入", )if self.point_ct < 400:self.etx[self.point_ct] = Entry(self.frm2, textvariable=self.xlst[self.point_ct])self.etx[self.point_ct].grid(row=self.point_ct, column=0, columnspan=1, )self.ety[self.point_ct] = Entry(self.frm2, textvariable=self.ylst[self.point_ct])self.ety[self.point_ct].grid(row=self.point_ct, column=2, columnspan=1, )self.point_ct += 1#\ 删除 最后输入样本点(框架0.1def del_last(self):if self.point_ct > 1:self.point_ct -= 1self.etx[self.point_ct].destroy()self.ety[self.point_ct].destroy()self.xlst[self.point_ct] = Noneself.ylst[self.point_ct] = None#\ 样本点输入结束(框架0.1def f_end(self):self.ifpoint = 1self.ex = []  # 置空刷新self.ey = []  # 置空刷新self.pointdic = {}if self.point_ct < 3:messagebox.showwarning('Warining', '样本点个数过少')elif not isinstance(type(eval(pd.get())), int) and not 0 < eval(pd.get()) < 151:messagebox.showwarning('Warining', '阶数非法输入')else:m = eval(pd.get())try:for i in range(self.point_ct):et_x, et_y = self.etx[i].get(), self.ety[i].get()if len(et_x) == len(et_y) == 0:continueelse:if not isinstance(type(eval(et_x)), (int, float)) and isinstance(type(eval(et_y)),(int, float)):messagebox.showwarning('Warining', '请检查输入是否合法(只能输入数字)\n[字母,符号,不输入都将报错]!')self.pointdic.clear()breakelse:  # 已经确定两个数类型可靠et_x, et_y = eval(et_x), eval(et_y)if et_x in self.pointdic.keys():messagebox.showwarning('Warining', 'X重复,请检查!')self.pointdic.clear()breakelse:self.pointdic[et_x] = et_yelse:keylst = list(self.pointdic.keys())keylst = sorted(keylst)for key in keylst:self.ex.append(key)self.ey.append(self.pointdic[key])else:if messagebox.askokcancel('这是一个弹窗', '输入完成,是否开始拟合'):self.ojbk = 1self.m = mlt = self.get_flist()lt1 = self.get_plist()lt.append(lt[0])lt[0], lt[1] = lt1[0], lt1[1]self.p_plot(lt)  # 开始绘图self.point_ct = 0  # 保证再一次进入到结束判断时字典、列表的存储位置从0开始except Exception as t:print(t)messagebox.showwarning('Warining', '错误!')# 警告 (主框架#def warn0(self):#messagebox.showwarning('Warining', '函数解析错误,函数不能为纯数字,或者包含其它非法字符')# 警告(主框架def warn1(self):messagebox.showwarning('Warining', '所选区间长度为空')# 错误(主框架def fail(self):messagebox.showerror('喵喵喵', '执行失败')

二、 数据处理部分[math,numpy]

函数数据处理
1 获取原函数横纵坐标x,y x=numpy.arange(x0,xn, 0.001) +eval(fx)
2 拉格朗日插值法数据获取 ------
3 分段二次插值法 ------
4 分段法 (简单结合拉格朗日插值法与分段二次插值法)
样本点数据处理 最小二乘法
代码来了
class get_list():def __init__(self):self.nm = Noneself.ojbk = Noneself.ifpoint = Noneself._lx = Noneself.lx_ = Noneself._fx = Noneself.dw_ = 1self.ex = Noneself.ey = Noneself.nh_fx = Noneself.m = 1self.fx_lst = []def s_set(self, *, _lx=None, lx_=None, _fx=None, nm=None):self.ojbk = 1self.ifpoint = 0self._lx = _lxself.lx_ = lx_self._fx = _fxself.nm = nmdef p_set(self, *, ex=None, ey=None):self.ex = exself.ey = ey# 处理字符串/样本点,返回一系列数据的列表【绘图数据获取】# 参数 self.nm(point_count), self.ojbk, self.ifpoint, self._lx,self.lx_, self._fx,# self.dw_, self.ex, self.ey,# return [x0, y0, x1, y1, x4, y4, x5, y5, y3]def get_flist(self):if not self.ojbk:quit(self.get_flist)if self.ifpoint == 0:  # 获取函数字符串数据n = self.nm  # 30  # 取样点个数( 相对随机 xk = xk + rand(0~1)*[(xn-x0)/n]m = 3  # 分段时左右两段取样点所占比重  sum(x1)/mlimits = [self._lx, self.lx_]_x, x_, x_l = limits[0], limits[1], abs(limits[1] - limits[0])x1, y1 = [], []  # 存储样本点# 函数fx = self._fxif self.dw_ > 0.01:cont = 0.0001else:cont = 0.00001dex = x_l * 0.25# 获取原函数画图所需点列表 x0, y0  (插值拟合数据源x = np.arange(_x - dex, x_ + dex, cont)eval(fx)try:y0 = eval(fx)if len(y0) == 1:messagebox.showwarning('Warining', '函数解析错误,函数不能为纯数字,或者包含其它非法字符')return Noneexcept Exception as t:print(t)messagebox.showwarning('Warining', '函数解析错误,函数不能为纯数字,或者包含其它非法字符')return Nonex0 = x# 获取样本点并存入列表 x1, y1  (折线图数据源for xo in np.linspace(_x, x_, n):x = xo + np.random.rand() * (x_l / n)x1.append(x)y1.append(eval(fx))else:  # 样本点  初始化 参数:self.ex; self.ey; self.m; self.ifpoint; self.nh_fxx1, y1 = self.ex, self.eydex = (self.ex[-1] - self.ex[0]) * 0.2n = len(x1)m = 2  # 不需要cont = 0.0001x0 = np.arange(x1[0] - dex, x1[-1] + dex, cont)# 拟合所需 1_原函数 x0, y0; 2_取样点 x1, y1; 3_取样点个数 n, 取样精度 cnt'''# 拉格朗日插值法 获得 y2y2 = x0 * 0for i in range(n):fz, fm = x0* 0 + 1, 1for j in range(n):if not j==i:fz *= (x0 - x1[j])fm *= (x1[i] - x1[j])y2 += y1[i] * (fz / fm)'''# 牛顿插值法 获得 y3y3 = x0 * 0 + y1[0]x3 = x0 * 0 + 1y4 = [y1, []]#   获得差商标for i in np.arange(1, n)[::-1]:x3 *= (x0 - x1[n - 1 - i])for j in range(i):ff = (y4[0][j + 1] - y4[0][j]) / (x1[n - i + j] - x1[j])y4[1].append(ff)y3 += y4[1][0] * x3y4 = [y4[1], []]# 分段二次数插值法  ----1段式  (相当于 m==2)x5, y5 = [], []  # 存取插值函数数据# 左右两部分取样点下标列表lln = len(x1)sq = list(range(0, lln - 2, 2))for i in range(0, lln - 2, 2):  #if i == 0:if i == sq[-1]:dx1_ = 3 * dexelse:dx1_ = 0dx1 = dexelif i == sq[-1]:dx1 = 0dx1_ = 3*dexelse:dx1 = 0dx1_ = 0fz5, fm5 = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont) * 0 + 1, 1y_y = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont) * 0  # 累加获得小段函数值数据源x_x = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont)  # 获取当前区间 x 的列表 xfor k in range(i, i + 3):fz5, fm5 = fz5 * 0 + 1, 1for j in range(i, i + 3):if not j == k:fz5 *= (x_x - x1[j])fm5 *= (x1[k] - x1[j])y_y += y1[k] * (fz5 / fm5)y5 += list(y_y)x5 += list(x_x)# 分段插值法  ----三段式y4, y4_ = [], []  # 存取左半边插值函数数据x4, x4_ = [], []  # 右半边数据存储# 左右两部分取样点下标列表ltx, rtx = list(range(0, int(len(x1) // m), 2)), list(range(int((1 - 1 / m) * len(x1)), len(x1), 2))rtx.pop(-1)for i in ltx:  # 左半部分if i == 0:dx0 = dexelse:dx0 = 0fz, fm = np.arange(x1[i] - dx0, x1[i + 2], cont) * 0 + 1, 1yy = np.arange(x1[i] - dx0, x1[i + 2], cont) * 0  # 累加获得小段函数值数据源l_x = np.arange(x1[i] - dx0, x1[i + 2], cont)  # 获取当前区间 x 的列表 left_xfor k in range(i, i + 3):fz, fm = fz * 0 + 1, 1for j in range(i, i + 3):if not j == k:fz *= (l_x - x1[j])fm *= (x1[k] - x1[j])yy += y1[k] * (fz / fm)y4 = y4 + list(yy)x4 += list(l_x)for i_ in rtx:  # 右半部分if i_ == rtx[-1]:dx0 = dexelse:dx0 = 0fz_, fm_ = np.arange(x1[i_], x1[i_ + 2] + dx0, cont) * 0 + 1, 1yy_ = np.arange(x1[i_], x1[i_ + 2] + dx0, cont) * 0x_r = np.arange(x1[i_], x1[i_ + 2] + dx0, cont)for k_ in range(i_, i_ + 3):fz_, fm_ = fz_ * 0 + 1, 1for j_ in range(i_, i_ + 3):if not j_ == k_ and j_ < len(x1) and k_ < len(x1):fz_ *= (x_r - x1[j_])fm_ *= (x1[k_] - x1[j_])if k_ < len(x1):yy_ += y1[k_] * (fz_ / fm_)y4_ = y4_ + list(yy_)x4_ += list(x_r)# 由中间向两边遍历循环,寻找 左 中,中 右最佳连接点if m == 2:left = right = 0else:start1 = start = len(x0) // 2while 1:if n < 7:left = right = 0breakif x0[start] < x4[-1] and start:  # 左连接点left = start + 1start = 0if x0[start1] > x4_[0] and start1:  # 右连接点right = start1 - 1start1 = 0if start:start -= 1if start1:start1 += 1if not (start + start1):breaky4 = y4 + list(y3[left:right]) + y4_  # 拼接 左中右 函数值数据源x4 = x4 + list(x0[left:right]) + x4_  # 拼接 左中右 自变量值if n < 7:x4, y4 = [], []if self.ifpoint:y0 = []return [x0, y0, x1, y1, x4, y4, x5, y5, y3]# 获取输入样本点 最小二乘法拟合曲线数据【绘图数据获取】# 参数 self.nh_fx, self.ex, self.ey, self.m,# return [x, y]def get_plist(self):self.nh_fx = ''ex = self.ex  # np.arange(-10, -4,0.1)       #[1,3,4,5,6,7,8,9,10]ey = self.ey  # eval("cos(2*np.pi*ex)*np.exp(-ex) + 0.8")#eval("sin(ex)")##[10,5,4,2,1,1,2,3,4]x_or_cplx = 1  # 判断是简单 x 线性函数拟合还是  自定义函数拟合if x_or_cplx == 1:  # x 线性拟合m = self.mb = [0 for i in range(m + 1)]  # 存储fai = [0 for i in range(2 * m + 1)]  # 存储 x 的 0~2m次方A = [[0 for i in range(m + 1)] for i in range(m + 1)]  # 存储 A 矩阵 Ax = bfor i in range(2 * m + 1):for j in range(len(ex)):fai[i] += ex[j] ** iif i < m + 1:b[i] += ey[j] * (ex[j] ** i)for i in range(m + 1):for j in range(m + 1):A[i][j] = fai[i + j]try:a = np.linalg.solve(A, b)  # .resize(1, len(b))  [32, 147, 1025, 8421, 74261]except Exception as t:print(t)a = [1,]pass#print(A, b, a, sep='\n')self.nh_fx += f"$({a[0]:.4e})"for i in range(m):if i!=0 and not i%9:self.nh_fx += '\n'self.nh_fx += f"+({a[i+1]:.4e})X^{i+1}"self.nh_fx = self.nh_fx + "$  \n[Least-Square-method]"if m>9:self.nh_fx = self.nh_fx.replace('$', '')dex = (ex[-1] - ex[0]) * 0.1x = np.arange(ex[0] - dex, ex[-1] + dex, 0.001)y = x * 0for i in range(m + 1):y += a[i] * (x ** i)else:m = 3b = [0 for i in range(m + 1)]  # 存储 fn * ynA = [[0 for i in range(m + 1)] for i in range(m + 1)]  # 存储 A 矩阵 Ax = bff = ['self.f0(xm)', 'self.f1(xm)', 'self.f2(xm)', 'self.f3(xm)',] # 'self.f4(xm)', 'self.f5(xm)', 'self.f6(xm)']for i in range(m + 1):for j in range(i, m + 1):n = 0for xm in ex:A[i][j] += eval(ff[j]) * eval(ff[i])if i == 0:b[j] += ey[n] * eval(ff[j])n += 1for i in range(m + 1):for j in range(0, i):A[i][j] = A[j][i]try:a = np.linalg.solve(A, b)  # .resize(1, len(b))except:passself.nh_fx += f"$({a[0]:.4e})"for i in range(m):if i!=0 and not i%9:self.nh_fx += '\n'self.nh_fx += f"+({a[i+1]:.4e})x({self.fx_lst[i]})"self.nh_fx = self.nh_fx + "$  \n[Least-Square-method]"if m>9:self.nh_fx = self.nh_fx.replace('$', '')dex = (ex[-1] - ex[0]) * 0.11x = np.arange(ex[0] - dex, ex[-1] + dex, 0.001)y = x * 0xm = xfor i in range(m + 1):y += a[i] * eval(ff[i])return [x, y]def f0(self, xn):return 1def f1(self, xn):if 'cos(2pi*x)(1/e^x)' not in self.fx_lst:self.fx_lst.append('cos(2pi*x)(1/e^x)')return cos(2*np.pi*xn)*np.e**(-xn)def f2(self, xn):if 'cos(2pi*x)' not in self.fx_lst:self.fx_lst.append('cos(2pi*x)')return cos(2*pi*xn)def f3(self, xn):if 'e^x' not in self.fx_lst:self.fx_lst.append('e^x')return np.e**(xn)

三、 绘图[matplotlib]

函数字符串部分
  • 拉格朗日、分段二次、分段法与原函数同坐标系绘图比较+所选样本点散点图
  • 不同方法函数 单独图像
  • 原函数小图
  • 图标
样本点处理后绘图部分
  • 最小二乘法、拉格朗日、分段二次法函数图同坐标系绘图比较
  • 样本点散点图
  • 图标
代码来了
class plot():def __init__(self):self.ojbk = Noneself.ifpoint = Noneself._lx = Noneself.lx_ = Noneself.paint = Noneself.nh_fx = None# 画图【绘图】# 参数 lst, self.ojbk, self.ifpoint, self._lx, self.lx_, self.paintdef s_plot(self, lst):  # 画图if not self.ojbk or not lst:return Nonematplotlib.rcParams['font.family'] = 'SimHei'matplotlib.rcParams['font.sans-serif'] = ['SimHei']matplotlib.rcParams['axes.unicode_minus'] = False  # 中文负号问题plt.figure(num='插值法以及曲线拟合的一点探索', figsize=(15, 15), dpi=110, facecolor='w', edgecolor='cyan')gs = gridspec.GridSpec(2, 4)ax1 = plt.subplot(gs[0:, :2])  # mix  原图 x0, y0ax2 = plt.subplot(gs[0, 2:])  # 牛顿/拉格朗日插值 x0, y2ax3 = plt.subplot(gs[1, 2])  # 分段二次插值    x4, y4ax4 = plt.subplot(gs[1, 3])  #    x1, y1x0, y0 = lst[0], lst[1]  # mix  原图 x0, y0x1, y1 = lst[2], lst[3]  #  x1, y1  散点图x4, y4 = lst[4], lst[5]  # 分段插值    x4, y4x5, y5 = lst[6], lst[7]  #y2 = lst[8]  # 牛顿/拉格朗日插值 x0, y2if self.ifpoint == 0:x0_ = x0mn, mx = min(y0), max(y0)if math.isnan(mn):mn = -20if math.isnan(mx):mx = 20dy = abs(mx - mn) / 8foc_y = mn + (mx - mn) * 0.35mn, mx = mn - dy, mx + dyfoc = (self._lx + self.lx_) / 2  # 横坐标与纵坐标交点else:x0_ = []mn, mx = min(y1), max(y1)dy = abs(mx - mn) / 8foc_y = mn + (mx - mn) * 0.35mn, mx = mn - dy, mx + dyfoc = (x1[0] + x1[-1]) / 2  # 横坐标 与纵坐标交点处x 的值if self.paint != 0:for ax in [ax1, ax2, ax3, ax4]:ax.cla()ax1.plot(x0_, y0, color='r', label=r'$Original-function$', linewidth=1.5, alpha=.98)ax1.scatter(x1, y1, s=50, marker="o", label=r'Sample-point', color='lime', alpha=.79)ax1.plot(x0, y2, color='darkviolet', label=r"$Lagrange's/Newton-interpolation$", linewidth=.8)ax1.plot(x5, y5, color='blue', label=r'$Piecewise-interpolation$', linewidth=.7)ax1.plot(x4, y4, color='peru', label=r'$Simple-Piecewise-interpolation$', linewidth=.7, alpha=0.95)# 小图mini = plt.figure(num='插值法以及曲线拟合的一点探索').add_axes([.02, .8, .15, .15])if self.paint != 0:mini.cla()mini.plot(x0_, y0, color='r', linewidth=1)mini.spines['top'].set_color('none')mini.spines['right'].set_color('none')mini.xaxis.set_ticks_position('bottom')mini.yaxis.set_ticks_position('left')mini.spines['bottom'].set_position(('data', foc_y))mini.spines['left'].set_position(('data', foc))mini.set_title(r'原函数')ax1.set_title('函数图比较')ax2.plot(x0, y2, color='darkviolet', linewidth=1, alpha=.9)ax2.scatter(x1, y1, s=50, marker="o", color='lime', alpha=.8)ax2.set_title('拉格朗日/牛顿插值法')ax3.plot(x5, y5, color='blue', linewidth=1)ax3.scatter(x1, y1, s=50, marker="o", color='lime', alpha=.8)ax3.set_title('分段二次插值法')ax4.plot(x4, y4, color='peru', linewidth=1)ax4.scatter(x1, y1, s=50, marker="o", color='lime', alpha=.8)ax4.set_title('简单分段插值法')plt.figlegend(loc='upper center')for ax in [ax1, ax2, ax3, ax4]:ax.spines['top'].set_color('none')ax.spines['right'].set_color('none')ax.xaxis.set_ticks_position('bottom')ax.yaxis.set_ticks_position('left')ax.spines['bottom'].set_position(('data', foc_y))ax.spines['left'].set_position(('data', foc))ax.axis([x0[0], x0[-1], mn, mx])# 拉格朗日 插值 大图plt.figure(num='拉格朗日/牛顿插值法', figsize=(10, 10))if self.paint != 0:plt.clf()plt.plot(x0, y2, color='blueviolet', label=r"$Lagrange's/Newton-interpolation$", linewidth=.8)plt.title('拉格朗日/牛顿插值法')plt.plot(x0_, y0, color='red', label=r'$Original-function$', linewidth=.8)plt.scatter(x1, y1, s=50, marker="o", label=r'Sample-point', color='lime', alpha=.8)plt.legend(loc='best')plt1 = plt.gca()plt1.spines['top'].set_color('none')plt1.spines['right'].set_color('none')plt1.xaxis.set_ticks_position('bottom')plt1.yaxis.set_ticks_position('left')plt1.spines['bottom'].set_position(('data', foc_y))plt1.spines['left'].set_position(('data', foc))plt.axis([x0[0], x0[-1], mn - 2 * dy, mx])# 小图mini = plt.figure(num='拉格朗日/牛顿插值法').add_axes([.02, .75, .22, .22])if self.paint != 0:mini.cla()mini.plot(x0_, y0, color='r', linewidth=1)mini.spines['top'].set_color('none')mini.spines['right'].set_color('none')mini.xaxis.set_ticks_position('bottom')mini.yaxis.set_ticks_position('left')mini.spines['bottom'].set_position(('data', foc_y))mini.spines['left'].set_position(('data', foc))mini.set_title(r'原函数')# 分段法2 大图plt.figure(num='简单分段插值法', figsize=(10, 10))if self.paint != 0:plt.clf()plt.plot(x4, y4, color='teal', label=r'$Simple-Piecewise-interpolation$', linewidth=1)plt.title('简单分段插值法')plt.plot(x0_, y0, color='red', label=r'$Original-function$', linewidth=1)plt.scatter(x1, y1, s=50, marker="o", label=r'Sample-point', color='lime', alpha=.8)plt.legend(loc='best')plt1 = plt.gca()plt1.spines['top'].set_color('none')plt1.spines['right'].set_color('none')plt1.xaxis.set_ticks_position('bottom')plt1.yaxis.set_ticks_position('left')plt1.spines['bottom'].set_position(('data', foc_y))plt1.spines['left'].set_position(('data', foc))plt.axis([x0[0], x0[-1], mn - 2 * dy, mx])# 小图mini = plt.figure(num='简单分段插值法').add_axes([.02, .75, .22, .22])if self.paint != 0:mini.cla()mini.plot(x0_, y0, color='r', linewidth=1)mini.spines['top'].set_color('none')mini.spines['right'].set_color('none')mini.xaxis.set_ticks_position('bottom')mini.yaxis.set_ticks_position('left')mini.spines['bottom'].set_position(('data', foc_y))mini.spines['left'].set_position(('data', foc))mini.set_title(r'原函数')# 分段法1 大图plt.figure(num='分段二次插值法', figsize=(10, 10))if self.paint != 0:plt.clf()plt.plot(x5, y5, color='teal', label=r'$Piecewise-interpolation$', linewidth=1)plt.title('分段二次插值法')plt.plot(x0_, y0, color='red', label=r'$Original-function$', linewidth=1)plt.scatter(x1, y1, s=50, marker="o", label=r'Sample-point', color='lime', alpha=.8)plt.legend(loc='best')plt1 = plt.gca()plt1.spines['top'].set_color('none')plt1.spines['right'].set_color('none')plt1.xaxis.set_ticks_position('bottom')plt1.yaxis.set_ticks_position('left')plt1.spines['bottom'].set_position(('data', foc_y))plt1.spines['left'].set_position(('data', foc))plt.axis([x0[0], x0[-1], mn - 2 * dy, mx])# 小图mini = plt.figure(num='分段二次插值法').add_axes([.02, .75, .22, .22])if self.paint != 0:mini.cla()mini.plot(x0_, y0, color='r', linewidth=1)mini.spines['top'].set_color('none')mini.spines['right'].set_color('none')mini.xaxis.set_ticks_position('bottom')mini.yaxis.set_ticks_position('left')mini.spines['bottom'].set_position(('data', foc_y))mini.spines['left'].set_position(('data', foc))mini.set_title(r'原函数')self.paint = 1plt.show()plt.close()# 最小二乘法绘图【绘图】# 参数 lst, self.nh_fxdef p_plot(self, lst):matplotlib.rcParams['font.family'] = 'SimHei'matplotlib.rcParams['font.sans-serif'] = ['SimHei']matplotlib.rcParams['axes.unicode_minus'] = False  # 中文负号问题x0, y0 = lst[0], lst[1]  # 二乘法x1, y1 = lst[2], lst[3]  # 散点图x5, y5 = lst[6], lst[7]  # 分段二次插值x2, y2 = lst[9], lst[8]  # 拉格朗日up, low = max(y0), min(y0)if math.isnan(up):up = -20if math.isnan(low):low = 20ddy = (up - low) * 0.2xup, xlow = max(x1), min(x1)ddx = (xup - xlow) * 0.23plt.figure(num='最小二乘法、拉格朗日插值法、分段二次插值法拟合曲线比较', figsize=(10, 10))# plt.title('')plt.clf()plt.plot(x0, y0, color='red', label=self.nh_fx, linewidth=2, alpha=.98)  # r'$Least-Square-method$' 最小二乘plt.scatter(x1, y1, s=50, marker="x", label=r'Sample-point', color='black', alpha=1)  # 散点plt.plot(x2, y2, color='darkviolet', label=r"$Lagrange's/Newton-interpolation$", linewidth=0.7)   # 拉格朗日plt.plot(x5, y5, color='blue', label=r'$Piecewise-interpolation$', linewidth=.7)   #分段二次plt.figlegend(loc='upper left')plt1 = plt.gca()plt1.spines['top'].set_color('none')plt1.spines['right'].set_color('none')plt1.xaxis.set_ticks_position('bottom')plt1.yaxis.set_ticks_position('left')plt1.spines['bottom'].set_position(('data', low-ddy))plt1.spines['left'].set_position(('data', xlow-ddx))plt.axis([x1[0] - ddx, x1[-1] + ddx, low - ddy, up + ddy])plt.show()plt.close()

最后调用一下就OK了

def main():cat = Miao()main()

框架大概就是上边这些
flag又又又来了:等有时间就把细节补上
基本能保证通过这玩意儿、可以了解到大部分常用tkinter板块、一部分matplotlib,还有一部分numpy【至少本菜鸡是这样的(T_T)】

下边就先放一点效果图,还有一部分代码图片吧

(代码要把绘图、获取列表放在前头,最后才是ui)

大体框架如下


[Python]Tkinter+Numpy+Matplotlib 进行的简单交互+曲线拟合+图像绘制【已改进】相关推荐

  1. Python|tkinter+matplotlib实现给老铁的生日礼物

    Python|tkinter+matplotlib实现给老铁的生日礼物 背景介绍 最近我的老铁生日,于是我用自己几乎所有的python知识储备给他做了一个生日祝福的小程序(虽然没有成功打包成一个exe ...

  2. 【程序员股民系列】如何用python, pandas, numpy, matplotlib绘制每日个股成交额图

    上次分享了一段代码用于绘制每日行业交易额的图: [程序员股民系列]如何用python, pandas, numpy, matplotlib绘制每日行业成交额图 分析粒度略粗,只到行业这一层,把代码稍微 ...

  3. 【程序员股民系列】如何用python, pandas, numpy, matplotlib绘制每日行业成交额图

    最近这两天股民基友们可能很多亏得底裤都没了,该说点什么呢,心态放平吧: 想长期混迹股市,还是要选基本面好的行业和个股,也要关注一些近期行业动态.当然这里面有很多维度和技巧,掌握得越多,驾驭股市的功力就 ...

  4. python实践系列之(一)安装 python/pip/numpy/matplotlib

    1.下载并安装Python3.4 在官网下载即可:Python官网 图1-1 图1-2 打开Python图形界面: 图1-3 输入 2+3+4+5,回车,出现如图,说明安装成功. 图1-4 2.安装p ...

  5. python中numpy matplotlib绘图教程_利用numpy+matplotlib绘图的基本操作教程

    简述 Matplotlib是一个基于python的2D画图库,能够用python脚本方便的画出折线图,直方图,功率谱图,散点图等常用图表,而且语法简单.具体介绍见matplot官网. Numpy(Nu ...

  6. python tkinter窗口切换_tkinter--实现简单的页面切换

    [Python] 纯文本查看 复制代码import tkinter as tk index_num = 4 def up_page(): info = frame_root.place_info() ...

  7. 【Python】Numpy中伪随机数的简单使用

    Numpy中伪随机数也很强大,很常见,简单整理一些常见的操作如下: # 加载库 import numpy as np# 设置随机数种子 np.random.seed(0)# 生成3个0.0~1.0之间 ...

  8. 【Matplotlib】在Jupyter交互页面中绘制折线图对比(自用函数)

    0x00 前言 最近数据对比的任务比较常见,比如好些模型的横向对比, 对于 Loss.PRF.Hits 之类的数据,有时需要作log,有时需要去除前面几个值, 还要考虑数据不对齐.记录文件格式不一致等 ...

  9. Python读取excel数据且横轴是日期的图像绘制

    Python的matplotlib包含很多图表函数,其中plot()函数是绘制坐标图的. 通常情况下,横轴和纵轴都是数值型数据很好画图,直接带入数据,坐标轴会自动调节大小和显示密度.但是当横轴是日期时 ...

最新文章

  1. archlinux cn源
  2. c++ stdlib中rand()函数的值范围
  3. 数据对智慧城市建设 起到极大作用
  4. ML与math:机器学习与高等数学基础概念、代码实现、案例应用之详细攻略——进阶篇
  5. wget提示失败的解决办法
  6. 腾讯JAVA岗位四面,腾讯Java社招四面面经分享(4年java经验者)
  7. Swift 性能相关
  8. Android 系统(224)---如何不显示开机SIM卡欢迎语
  9. 网络管理:超级详细Tcpdump 的用法
  10. python爬虫菜鸟教程-Python爬虫学习100练001
  11. javascript 同时下载多个文件
  12. [前端]-- jquery学习1
  13. 25个技巧和诀窍可以用来提高你的app性能
  14. 云计算基础架构 (二)redis群集
  15. ESXI6.0 windows虚拟机 硬盘扩容实例...
  16. 【SPFA + DFS/BFS】最短路的一个拓展题
  17. 搜狗大数据总监、Polarr 联合创始人关于深度学习的分享交流
  18. js实现倒计时5秒提交及redis防止多人同时提交
  19. 微信小程序的驾校预约管理系统设计与实现的源码+文档
  20. 怎么用dd命令测试U盘读写速度

热门文章

  1. 如何通过cmd查看python版本
  2. 2019上海网络赛icpc
  3. FPGA项目开发之时钟规划
  4. 《多传感器融合定位》惯性导航基础(二)
  5. 服务器系统巡检命令,服务器巡检命令
  6. python培训上岗
  7. [DB][Oracle]Oracle格式化数字的方法(指定小数点位数,每3位加逗号)
  8. java智能家居_基于JAVA的智能家居控制系统的设计(毕业设计).doc
  9. 字符串与Date类型相互转换
  10. 浅谈C++的函数重载