用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)
大体框架如下