英文:
Showing the error of lmfit-model center in plot
问题
我帮您翻译代码中的相关部分,只返回翻译好的内容,不包含其他内容。
# 创建一个包含伪Voigt模型的函数
def Voigt_app(x, y, a, b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y, x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c=(y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
# 获取拟合结果的详细信息
details = out.fit_report(min_correl=0.25)
return out, details
# 创建一个包含正弦模型的函数
def Sin_app(x, y):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y, x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c=np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x)
# 获取拟合结果的详细信息
details = out.fit_report(min_correl=0.25)
return out, details
# 数据
data = np.asarray(
[[14407.0 , 26989.0 , 31026.0 , 31194.0 , 31302.0 , 91996.0 , 112250.0 , 112204.0 , 113431.0 , 75097.0 , 55942.0 , 55826.0 , 56181.0 , 28266.0 , 14687.0],
[12842.0 , 13275.0 , 13581.0 , 13943.0 , 14914.0 , 20463.0 , 21132.0 , 21457.0 , 23308.0 , 32017.0 , 30808.0 , 30927.0 , 30337.0 , 21025.0 , 15216.0],
[15770.0 , 17677.0 , 19008.0 , 20911.0 , 25958.0 , 27984.0 , 28164.0 , 31161.0 , 33517.0 , 29430.0 , 28673.0 , 32725.0 , 28495.0 , 24527.0 , 25173.0],
[16299.0 , 20067.0 , 25102.0 , 34968.0 , 37757.0 , 44871.0 , 51347.0 , 60154.0 , 54985.0 , 53383.0 , 45776.0 , 40836.0 , 30816.0 , 27922.0 , 26066.0]])
a, b = 1932, 1947
centers = []
colors = ['red', 'black', 'green', 'blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15), data[i, :], label=f'data {i}', color=colors[i])
out, details = Voigt_app(x, data[i, :], a, b)
ax.plot(out.best_fit, label=f'fit {i}', color=colors[i])
centers.append(out.values['psvo_center'])
ax.set_title('数据点和伪Voigt拟合')
ax.legend()
# 创建误差棒图
fig, ax = plt.subplots()
ax.errorbar(np.arange(4), centers, yerr=np.sqrt(out.covar[2, 2]), color='red', fmt='o', label='data')
out, details = Sin_app(np.arange(4), np.asarray(centers))
ax.plot(np.arange(4), out.best_fit, color='black', label='fit')
ax.set_title('峰值位置和正弦拟合')
ax.legend()
以上是将第二张图的散点图替换为带有伪Voigt峰位置置信区间的误差棒图的代码部分。
英文:
I'm working with fitting of data with the python lmfit package. I am looking at several peaks and fitting them with a pseudo-Voigt + constant model. I then extract the center position of the fitted peak and compile about a hundred of these peak positions. The hundred positions are then plotted and fitted with a sine-wave model, also with lmfit.
My issue, is that I am not able to find the information I need to show the uncertainty of the peak positions extracted from the pseudo-Voigt fitting. In many similar questions, I encounter the eval_uncertainty function also included in the lmfit package, but I am not able to use this to extract the confidence intervals of the center position, only uncertainties in the amplitude and sigma value of the peak.
The ideal result would look like the following image:
The ideal case I'm trying to achieve
And my current graph looks like this:
Current graph
Obviously I need to switch from a scatter plot to an errorbar plot, but I do not have any error-intervals to work with at the moment.
The following is the most simple workable "mini"-case I could construct, while still including my original fit-models. My original data is around 100 datapoints instead of four, and the sine-wave in this smaller case is therefore not "smooth", but this should not affect the method of introduction of errorbars.
import numpy as np
import matplotlib.pyplot as plt
from lmfit.models import PseudoVoigtModel, ConstantModel, SineModel
def Voigt_app(x,y,a,b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = (y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
details = out.fit_report(min_correl=0.25)
return out, details
def Sin_app(x,y):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y,pars,x=x)
details = out.fit_report(min_correl=0.25)
return out, details
data = np.asarray(
[[14407.0 , 26989.0 , 31026.0 , 31194.0 , 31302.0 , 91996.0 , 112250.0 , 112204.0 , 113431.0 , 75097.0 , 55942.0 , 55826.0 , 56181.0 , 28266.0 , 14687.0],
[12842.0 , 13275.0 , 13581.0 , 13943.0 , 14914.0 , 20463.0 , 21132.0 , 21457.0 , 23308.0 , 32017.0 , 30808.0 , 30927.0 , 30337.0 , 21025.0 , 15216.0],
[15770.0 , 17677.0 , 19008.0 , 20911.0 , 25958.0 , 27984.0 , 28164.0 , 31161.0 , 33517.0 , 29430.0 , 28673.0 , 32725.0 , 28495.0 , 24527.0 , 25173.0],
[16299.0 , 20067.0 , 25102.0 , 34968.0 , 37757.0 , 44871.0 , 51347.0 , 60154.0 , 54985.0 , 53383.0 , 45776.0 , 40836.0 , 30816.0 , 27922.0 , 26066.0]])
a,b = 1932, 1947
centers = []
colors = ['red','black','green','blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15),data[i,:],label=f'data {i}',color=colors[i])
out, details = Voigt_app(x,data[i,:],a,b)
ax.plot(out.best_fit,label=f'fit {i}',color=colors[i])
centers.append(out.values['psvo_center'])
ax.set_title('Data points and pseudo-Voigt fits')
ax.legend()
fig, ax = plt.subplots()
ax.scatter(np.arange(4),centers,color='red',label='data')
out, details = Sin_app(np.arange(4),np.asarray(centers))
ax.plot(np.arange(4),out.best_fit,color='black',label='fit')
ax.set_title('Peak positions and sine-wave fit')
ax.legend()
From this I would like to switch out the scatter plot in the second graph with an errorbar plot with the confidence intervals of the pseudo-Voigt peak positions ("out.values['psvo_center']").
答案1
得分: 0
这是如何修改您的Voigt_app函数以实现此目标的示例:
def Voigt_app(x, y, a, b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y, x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c=(y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
# 计算拟合参数的置信区间
ci = lmfit.conf_interval(out, out)
print(lmfit.printfuncs.report_ci(ci))
# 提取'psvo_center'的不确定性
center_err = (ci['psvo_center'][2][1] - ci['psvo_center'][1][1]) / 2
details = out.fit_report(min_correl=0.25)
return out, details, center_err
然后,您可以在绘制误差条时使用这些不确定性:
center_errs = []
for i in range(4):
out, details, center_err = Voigt_app(x, data[i, :], a, b)
# ...
center_errs.append(center_err)
# ...
ax.errorbar(np.arange(4), centers, yerr=center_errs, fmt='o', color='red', label='data')
请注意,这只是提供了如何修改您的代码以包括不确定性和绘制误差条的示例。具体的应用取决于您的数据和需求。
英文:
Here's how you could modify your Voigt_app function to do that:
def Voigt_app(x,y,a,b):
psvo_mod = PseudoVoigtModel(prefix='psvo_')
pars = psvo_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = (y[0]+y[1])/2))
mod = psvo_mod + con_mod
out = mod.fit(y, pars, x=x)
# Calculate the confidence interval for the fitted parameters
ci = lmfit.conf_interval(out, out)
print(lmfit.printfuncs.report_ci(ci))
# Extract the uncertainty for 'psvo_center'
center_err = (ci['psvo_center'][2][1] - ci['psvo_center'][1][1])/2
details = out.fit_report(min_correl=0.25)
return out, details, center_err
You can then use these uncertainties when plotting the error bars:
center_errs = []
for i in range(4):
out, details, center_err = Voigt_app(x, data[i,:], a, b)
# ...
center_errs.append(center_err)
# ...
ax.errorbar(np.arange(4), centers, yerr=center_errs, fmt='o', color='red', label='data')
答案2
得分: 0
如果我理解您的问题正确,您想要提取每个拟合的“psvo_center”参数的最佳拟合值,以及“psvo_center”的标准误差,然后将它们用作拟合正弦振荡的数据。
如果我理解正确的话,我认为您想要保存stderr
属性,通过修改您的代码如下:
centers = []
stderrs = [] # < new
colors = ['red','black','green','blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15),data[i,:],label=f'data {i}',color=colors[i])
out, details = Voigt_app(np.arange(15), data[i,:], a, b)
ax.plot(out.best_fit,label=f'fit {i}',color=colors[i])
centers.append(out.params['psvo_center'].value) # < new
stderrs.append(out.params['psvo_center'].stderr) # < new
然后,您可以使用它们创建一个误差棒图:
ax.errorbar(np.arange(4), centers, stderrs, color='red',label='data')
您可能还想使用这些stderrs
来加权拟合正弦函数,可以修改您的Sin_App
如下:
def Sin_app(x, y, dely): # < new
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely) # < new
details = out.fit_report(min_correl=0.25)
return out, details
然后调用:
out, details = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
对于您提供的4个示例数据集,标准误差的变化并不是很大,所以对拟合结果的影响不大。但是随着您添加更多数据集,这可能会变得更重要。在“生产环境”中使用之前,您可能想添加一个检查以确保stderr
有效(例如,不是None
且不是0
)。
最后,您可能还想计算正弦函数的预测不确定性并绘制该范围。您的示例对于正弦拟合有4个变量和只有4个值,这在这种情况下会导致拟合非常完美,拟合的正弦函数具有非常小的不确定性。因此,为了说明这种方法,我在下面的拟合中固定了con_c
参数。如果拟合超过4个峰值剖面的结果,这可能就不是必要的。但是,作为说明:
将您的Sin_app
修改如下:
def Sin_app(x, y, dely):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
pars['con_c'].vary = False # 只有4个(x,y)值时需要
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely)
details = out.fit_report(min_correl=0.25)
delta_fit = out.eval_uncertainty(sigma=1) # < new
return out, details, delta_fit
然后使用以下代码绘制结果:
out, details, delta_fit = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
ax.plot(np.arange(4),out.best_fit, 'o', color='black',label='fit')
ax.fill_between(np.arange(4),
out.best_fit-delta_fit, out.best_fit+delta_fit,
color="#D7D7D7")
ax.set_title('Peak positions and sine-wave fit')
ax.legend()
这将导致最终绘图如下:
显示了峰值中心的“数据”带有误差棒,拟合值以及拟合的1σ范围。
英文:
If I understand your question correctly, you want to extract not only the best-fit value for the 'psvo_center' parameter for each of your fits, but also the standard error for 'psvo_center', and then use those as the data for fitting to a sinusoidal oscillation.
If that is correct, I think that what you want to do is to save the stderr
attribute, by changing you code to
centers = []
stderrs = [] # < new
colors = ['red','black','green','blue']
fig, ax = plt.subplots()
for i in range(4):
ax.scatter(np.arange(15),data[i,:],label=f'data {i}',color=colors[i])
out, details = Voigt_app(np.arange(15), data[i,:], a, b)
ax.plot(out.best_fit,label=f'fit {i}',color=colors[i])
centers.append(out.params['psvo_center'].value) # < new
stderrs.append(out.params['psvo_center'].stderr) # < new
You can then use that to make and error-bar plot with
ax.errorbar(np.arange(4), centers, stderrs, color='red',label='data')
You might also want to use those stderrs
to weight the fit to the sinusoidal function, perhaps modifying your Sin_App
to be
def Sin_app(x, y, dely): # < new
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely) # < new
details = out.fit_report(min_correl=0.25)
return out, details
and calling that with
out, details = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
for the 4 example datasets you give, the variation in the standard-error isn't very big, so it does not make a big difference. But as you add more datasets, it might become more important. You might want to add a check that stderr
is valid (like, not None
and not 0
) before using this "in production".
For "one more thing", you might also want to calculate the predicted uncertainty in the sinusoidal function and plot that range too. Your example has 4 variables for the sinusoidal fit and only 4 values, which results for this case in a near-perfect fit with absurdly small uncertainties on the fitted sine function. So to illustrate the approach, I fix the con_c
parameter in the fit below. If fitting the results of more than 4 peak profiles, that should not be necessary. But, for illustration,
changing your Sin_app
to be
def Sin_app(x, y, dely):
sin_mod = SineModel(prefix='sin_')
pars = sin_mod.guess(y,x=x)
con_mod = ConstantModel(prefix='con_')
pars = pars.update(con_mod.make_params(c = np.mean(y)))
pars['con_c'].vary = False # needed with only 4 (x,y) values
mod = sin_mod + con_mod
out = mod.fit(y, pars, x=x, weights=1./dely)
details = out.fit_report(min_correl=0.25)
delta_fit = out.eval_uncertainty(sigma=1) # < new
return out, details, delta_fit
and then plotting the results of using that with
out, details, delta_fit = Sin_app(np.arange(4), np.asarray(centers), np.asarray(stderrs))
ax.plot(np.arange(4),out.best_fit, 'o', color='black',label='fit')
ax.fill_between(np.arange(4),
out.best_fit-delta_fit, out.best_fit+delta_fit,
color="#D7D7D7")
ax.set_title('Peak positions and sine-wave fit')
ax.legend()
This leads to the final plot of:
showing the "data" for the peak centers with error bars, the fitted values, and the 1-sigma range of the fit.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论