0

UV-Visスペクトルを開き、それらを大量の関数に合わせようとするpythonスクリプトを作成しました。ただし、最小残差が見つかっているため、フィッティングステップをプロットに表示したいと思います。Stackoverflow には実際にこのアイデアに触れる例がいくつかあります (http://stackoverflow.com/questions/4098131/matplotlib-update-a-plot) が、何らかの理由でこのアプローチはうまく機能しません。「うまく動かない」というのは、プロット ウィンドウがスクリプトで発生している更新に応答しないということです。私は自分のコードをより理解しやすく、コンパイルできるものに切り詰めようとしましたが、例よりも私が持っているコードに近いものにしました。それを以下に示します。

私の質問を言い換えると、ウィンドウが「(応答なし)」にならないように、フィッティングプロセスを通じてこのタイプの画面をリフレッシュするより良い方法はありますか?

これが私の簡略化されたコードです:

# import modules that I'm using
import matplotlib
matplotlib.use('GTKAgg')
import Tkinter
from Tkinter import *
import numpy as np
import scipy as sc
import matplotlib.pyplot as pltlib
# lmfit is imported becuase parameters are allowed to depend on each other along with bounds, etc.
from lmfit import minimize, Parameters, Minimizer

#If button is pressed on the window, open a file and get the data
def open_File():
    # file is opened here and some data is taken
    # I've just set some arrays here so it will compile alone
    x=[]
    y=[]
    for num in range(0,1000):x.append(num*.001+1)
    # just some random function is given here, the real data is a UV-Vis spectrum
    for num2 in range(0,1000):y.append(sc.math.sin(num2*.06)+sc.math.e**(num2*.001))
    X = np.array(x)
    Y = np.array(y)

    # plot the initial data in one figure
    pltlib.ion()
    pltlib.interactive(True)
    pltlib.figure(1)
    pltlib.plot(X,Y, "r-")
    pltlib.show()

    #deconvolute this initial data into deveral lorentzian profiles
    deconvolute(X,Y)

#lorentz line for constructing the more complex function
def lorentz(x, amp, center, width):
    return amp*1/sc.math.pi*(width/((x-center)**2+width**2))

def deconvolute(X,Y):
    #make 2nd figure for the refreshing screen
    deconvFig = pltlib.figure(2)
    ax = deconvFig.add_subplot(111)
    line1,line2=ax.plot(X,Y,'r-',X,Y,'r-')

    # setup parameters for several (here is 30, I potentially hae many more in the real program)
    params = Parameters()
    for p in range(0,30):
        params.add('amp' + str(p), value=1)
        params.add('center' + str(p), value=1)
        params.add('width' + str(p), value=1)

    #get residual function for minimizing
    def residual(params, X, data=None):
        model = 0
        # get values for each lorentz and sum them up
        for p in range(0,30):
            amp = params['amp' + str(p)].value
            center = params['center' + str(p)].value
            width = params['width' + str(p)].value
            tmpLorentz = lorentz(X, amp, center, width)
            model = model + tmpLorentz

        # This is where the main problem is.
        # This 2nd figure stops responding after a very small (1?) number of iterations
        ########################################
        # I want redraw the figure at every step through the fitting process
        line2.set_ydata(model)
        deconvFig.canvas.draw()
        print 'screen should be refreshed'
        ########################################

        return (data - model)

    #fit the function to the data
    result = minimize(residual, params, args=(X, Y))
    print 'done fitting the program'

#create a window with a button
MainWindow = Tk()
Button(text='Open a File', command=open_File).pack(side=BOTTOM)
MainWindow.mainloop()
4

1 に答える 1

0

興味深いことに、私は簡単なテストを実行してみました。

import time
from matplotlib import pyplot as pltlib
deconvFig = pltlib.figure(2)
ax = deconvFig.add_subplot(111)
X, Y = range(10), range(10)
line1,line2 = ax.plot(X,Y,'r-',X,Y,'r-')
for x in xrange(2, 6, 1):
    line2.set_ydata(range(0, 10*x, x))
    deconvFig.canvas.draw()
    time.sleep(2)

>>> import matplotlib
>>> matplotlib.__version__
'1.1.0'

そしてそれは期待通りに機能しました。
おそらくあなたが2番目の図を生成しているからです。

import time
from matplotlib import pyplot as pltlib

pltlib.ion()
pltlib.interactive(True)
pltlib.figure(1)
pltlib.plot(range(10),range(10), "r-")
pltlib.show()

deconvFig = pltlib.figure(2)
ax = deconvFig.add_subplot(111)
X, Y = range(10), range(10)
line1,line2 = ax.plot(X,Y,'r-',X,Y,'r-')
for x in xrange(2, 6, 1):
    line2.set_ydata(range(0, 10*x, x))
    deconvFig.canvas.draw()
    time.sleep(2)

いいえ、それでも問題なく動作しました。
それは私の設定かもしれません。

非常に遅い速度で最小化する可能性もありますが、更新をプロットすると違いがわからない場合は、RMSEを計算して違いの大きさを確認できます。

print numpy.sqrt(numpy.sum((data - model)**2)/model.shape[0])/numpy.mean(data) * 100  

また、私は通常、scipyの最小化関数http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.htmlを使用します。これは、入力をランダムに変更することで機能するため、ほとんどの関数を最小化できるためです。どれだけ速くできるかはわかりませんが、多くの状況で適用できます。

これがお役に立てば幸いです。

于 2012-06-28T07:25:48.710 に答える