简体   繁体   English

拟合函数时如何更新matplotlib图形?

[英]How do I update a matplotlib figure while fitting a function?

I have written a python script which opens UV-Vis spectra and attempts to fit them with a large sum of functions. 我编写了一个python脚本,该脚本可打开UV-Vis光谱,并尝试使用大量功能将它们拟合。 However, I would like the fitting steps to be shown in a plot as the minimum residual is being found. 但是,我希望在图中找到拟合步骤,因为找到了最小残差。 Stackoverflow actually has some examples that touch on this idea (http://stackoverflow.com/questions/4098131/matplotlib-update-a-plot), but for some reason this approach isn't working for me very well. 实际上,Stackoverflow上有一些实例可以解决这个问题(http://stackoverflow.com/questions/4098131/matplotlib-update-a-plot),但是由于某种原因,这种方法对我来说效果不佳。 What I mean by "isn't working very well" is that the plot window does not respond to the updates that are occurring in the script. 我的意思是“效果不佳”是绘图窗口无法响应脚本中发生的更新。 I have attempted to cut down my code to something that is more understandable, still compiles, but is also closer to the code I have than the example and it is shown below. 我试图将代码缩减为更易于理解的代码,仍然可以编译,但比示例更接近于我拥有的代码,如下所示。

To re-phrase my question: Is there a better way of doing this type of screen refreshing through a fitting process so that the window does not become "(Not Responding)"? 重述我的问题:是否有更好的方法通过拟合过程来刷新这种类型的屏幕,以使窗口不会变为“(无响应)”?

Here is my simplified code: 这是我的简化代码:

# 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()

interesting, I tried running a simple test. 有趣的是,我尝试运行一个简单的测试。

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'

and well it worked as expected. 并按预期工作。
maybe because your generating a second figure. 也许是因为您生成了第二个数字。

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)

nope still worked fine. 仍然没有问题。
It could be my setup. 这可能是我的设置。

Though its also possible that its minimizing at very slow rate, so when you plot the update you can't tell the difference, you can calculate the RMSE to see how big the difference is 尽管也有可能以非常慢的速度将其最小化,所以当您绘制更新时您无法分辨出差异,您可以计算出RMSE来查看差异有多大

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

Also I usually use scipy's minimization function http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html being that it can minimize most functions, though it works by randomly mutating the input so I don't know how fast it can be, but it can be applied in many many situations. 另外,我通常使用scipy的最小化函数http://docs.scipy.org/doc/scipy/reference/produced/scipy.optimize.minimize.html ,因为它可以最小化大多数功能,尽管它可以通过随机改变输入来工作,所以我不知道它有多快,但是它可以在许多情况下应用。

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM