用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()
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 = 0
self.master.title('插值法及函数图像简单拟合函数')
canvas = Canvas(self.master, confine=True, width=660, height=800, scrollregion=(-1, -1, 660, 1100))
scrollbar = Scrollbar(self.master, command=canvas.yview, bd=2)
scrollbar.pack(side=RIGHT, fill=Y)
canvas.pack(fill=Y)
canvas.config(yscrollcommand=scrollbar.set)
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)
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 = 2
for 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 += 1
fx = 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()
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)
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 = 1
self.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 += 1
canvas.create_window(15, 410, window=frm, anchor=W)
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()
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)
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 += 5
lb = 5
self.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 -= 5
if self.ep > 5:
lb = 5
else:
lb = 1
self.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:
pass
self.f_ = 0
self.fff = 1
self.ifpoint = 0
self._fx = self.fdict[self.fx.get()]
def if_5(self):
self.f_ = 1
if self.ifpoint:
try:
self.pt.destroy()
except:
pass
self.ifpoint = 0
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 = 0
self._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._lx
if 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 = 1
lt = 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)
def get_point(self):
if self.ifpoint == 1:
try:
self.pt.destroy()
except:
pass
self.ifpoint = 1
self.noinfo_window = 1
self.entryfx.destroy()
self.point_ct = 0
self.ex = []
self.ey = []
self.m = 1
global pd
pd = 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))
scrollbar = Scrollbar(self.pt, command=canvas1.yview, bd=2)
scrollbar.pack(side=RIGHT, fill=Y)
canvas1.pack(fill=Y)
canvas1.config(yscrollcommand=scrollbar.set)
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()
def newp(self):
if self.point_ct == 0 and self.noinfo_window:
self.noinfo_window = 0
messagebox.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
def del_last(self):
if self.point_ct > 1:
self.point_ct -= 1
self.etx[self.point_ct].destroy()
self.ety[self.point_ct].destroy()
self.xlst[self.point_ct] = None
self.ylst[self.point_ct] = None
def f_end(self):
self.ifpoint = 1
self.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:
continue
else:
if not isinstance(type(eval(et_x)), (int, float)) and isinstance(type(eval(et_y)),
(int, float)):
messagebox.showwarning('Warining', '请检查输入是否合法(只能输入数字)\n[字母,符号,不输入都将报错]!')
self.pointdic.clear()
break
else:
et_x, et_y = eval(et_x), eval(et_y)
if et_x in self.pointdic.keys():
messagebox.showwarning('Warining', 'X重复,请检查!')
self.pointdic.clear()
break
else:
self.pointdic[et_x] = et_y
else:
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 = 1
self.m = m
lt = 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
except Exception as t:
print(t)
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 = None
self.ojbk = None
self.ifpoint = None
self._lx = None
self.lx_ = None
self._fx = None
self.dw_ = 1
self.ex = None
self.ey = None
self.nh_fx = None
self.m = 1
self.fx_lst = []
def s_set(self, *, _lx=None, lx_=None, _fx=None, nm=None):
self.ojbk = 1
self.ifpoint = 0
self._lx = _lx
self.lx_ = lx_
self._fx = _fx
self.nm = nm
def p_set(self, *, ex=None, ey=None):
self.ex = ex
self.ey = ey
def get_flist(self):
if not self.ojbk:
quit(self.get_flist)
if self.ifpoint == 0:
n = self.nm
m = 3
limits = [self._lx, self.lx_]
_x, x_, x_l = limits[0], limits[1], abs(limits[1] - limits[0])
x1, y1 = [], []
fx = self._fx
if self.dw_ > 0.01:
cont = 0.0001
else:
cont = 0.00001
dex = x_l * 0.25
x = np.arange(_x - dex, x_ + dex, cont)
eval(fx)
try:
y0 = eval(fx)
if len(y0) == 1:
messagebox.showwarning('Warining', '函数解析错误,函数不能为纯数字,或者包含其它非法字符')
return None
except Exception as t:
print(t)
messagebox.showwarning('Warining', '函数解析错误,函数不能为纯数字,或者包含其它非法字符')
return None
x0 = x
for xo in np.linspace(_x, x_, n):
x = xo + np.random.rand() * (x_l / n)
x1.append(x)
y1.append(eval(fx))
else:
x1, y1 = self.ex, self.ey
dex = (self.ex[-1] - self.ex[0]) * 0.2
n = len(x1)
m = 2
cont = 0.0001
x0 = np.arange(x1[0] - dex, x1[-1] + dex, cont)
'''
# 拉格朗日插值法 获得 y2
y2 = x0 * 0
for i in range(n):
fz, fm = x0* 0 + 1, 1
for j in range(n):
if not j==i:
fz *= (x0 - x1[j])
fm *= (x1[i] - x1[j])
y2 += y1[i] * (fz / fm)
'''
y3 = x0 * 0 + y1[0]
x3 = x0 * 0 + 1
y4 = [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] * x3
y4 = [y4[1], []]
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 * dex
else:
dx1_ = 0
dx1 = dex
elif i == sq[-1]:
dx1 = 0
dx1_ = 3*dex
else:
dx1 = 0
dx1_ = 0
fz5, fm5 = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont) * 0 + 1, 1
y_y = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont) * 0
x_x = np.arange(x1[i] - dx1, x1[i + 2] + dx1_, cont)
for k in range(i, i + 3):
fz5, fm5 = fz5 * 0 + 1, 1
for 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 = dex
else:
dx0 = 0
fz, fm = np.arange(x1[i] - dx0, x1[i + 2], cont) * 0 + 1, 1
yy = np.arange(x1[i] - dx0, x1[i + 2], cont) * 0
l_x = np.arange(x1[i] - dx0, x1[i + 2], cont)
for k in range(i, i + 3):
fz, fm = fz * 0 + 1, 1
for 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 = dex
else:
dx0 = 0
fz_, fm_ = np.arange(x1[i_], x1[i_ + 2] + dx0, cont) * 0 + 1, 1
yy_ = np.arange(x1[i_], x1[i_ + 2] + dx0, cont) * 0
x_r = np.arange(x1[i_], x1[i_ + 2] + dx0, cont)
for k_ in range(i_, i_ + 3):
fz_, fm_ = fz_ * 0 + 1, 1
for 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 = 0
else:
start1 = start = len(x0) // 2
while 1:
if n < 7:
left = right = 0
break
if x0[start] < x4[-1] and start:
left = start + 1
start = 0
if x0[start1] > x4_[0] and start1:
right = start1 - 1
start1 = 0
if start:
start -= 1
if start1:
start1 += 1
if not (start + start1):
break
y4 = 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]
def get_plist(self):
self.nh_fx = ''
ex = self.ex
ey = self.ey
x_or_cplx = 1
if x_or_cplx == 1:
m = self.m
b = [0 for i in range(m + 1)]
fai = [0 for i in range(2 * m + 1)]
A = [[0 for i in range(m + 1)] for i in range(m + 1)]
for i in range(2 * m + 1):
for j in range(len(ex)):
fai[i] += ex[j] ** i
if 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)
except Exception as t:
print(t)
a = [1,]
pass
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.1
x = np.arange(ex[0] - dex, ex[-1] + dex, 0.001)
y = x * 0
for i in range(m + 1):
y += a[i] * (x ** i)
else:
m = 3
b = [0 for i in range(m + 1)]
A = [[0 for i in range(m + 1)] for i in range(m + 1)]
ff = ['self.f0(xm)', 'self.f1(xm)', 'self.f2(xm)', 'self.f3(xm)',]
for i in range(m + 1):
for j in range(i, m + 1):
n = 0
for xm in ex:
A[i][j] += eval(ff[j]) * eval(ff[i])
if i == 0:
b[j] += ey[n] * eval(ff[j])
n += 1
for i in range(m + 1):
for j in range(0, i):
A[i][j] = A[j][i]
try:
a = np.linalg.solve(A, b)
except:
pass
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({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.11
x = np.arange(ex[0] - dex, ex[-1] + dex, 0.001)
y = x * 0
xm = x
for i in range(m + 1):
y += a[i] * eval(ff[i])
return [x, y]
def f0(self, xn):
return 1
def 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 = None
self.ifpoint = None
self._lx = None
self.lx_ = None
self.paint = None
self.nh_fx = None
def s_plot(self, lst):
if not self.ojbk or not lst:
return None
matplotlib.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])
ax2 = plt.subplot(gs[0, 2:])
ax3 = plt.subplot(gs[1, 2])
ax4 = plt.subplot(gs[1, 3])
x0, y0 = lst[0], lst[1]
x1, y1 = lst[2], lst[3]
x4, y4 = lst[4], lst[5]
x5, y5 = lst[6], lst[7]
y2 = lst[8]
if self.ifpoint == 0:
x0_ = x0
mn, mx = min(y0), max(y0)
if math.isnan(mn):
mn = -20
if math.isnan(mx):
mx = 20
dy = abs(mx - mn) / 8
foc_y = mn + (mx - mn) * 0.35
mn, mx = mn - dy, mx + dy
foc = (self._lx + self.lx_) / 2
else:
x0_ = []
mn, mx = min(y1), max(y1)
dy = abs(mx - mn) / 8
foc_y = mn + (mx - mn) * 0.35
mn, mx = mn - dy, mx + dy
foc = (x1[0] + x1[-1]) / 2
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'原函数')
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'原函数')
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 = 1
plt.show()
plt.close()
def 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 = -20
if math.isnan(low):
low = 20
ddy = (up - low) * 0.2
xup, xlow = max(x1), min(x1)
ddx = (xup - xlow) * 0.23
plt.figure(num='最小二乘法、拉格朗日插值法、分段二次插值法拟合曲线比较', figsize=(10, 10))
plt.clf()
plt.plot(x0, y0, color='red', label=self.nh_fx, linewidth=2, alpha=.98)
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)
大体框架如下


