Search code examples
pythonscipycurve-fittingleast-squaresdata-fitting

Data Fitting in Python for multiple peaks


import numpy as np
from sympy.physics.wigner import wigner_6j
import matplotlib.pyplot as plt
xr=np.arange(0,33)
[Jo, Ju, I, Ao, Au]=[4.5, 4.5, 2.5,674.4,929]
Ao=Ao*0.00003335640954804
Au=Au*0.00003335640954804
xr1=100000000/np.array(xr)
positions=xr1
centroid = positions.mean(axis=0)
newo=0.005+100000000/4715.2274
Fo=[]
Fu=[]
new=[]
In=[]
Fomax=Jo+I
Fomin=abs(Jo-I)
Fumax=Ju+I
Fumin=abs(Ju-I)
no=int(2*min(Jo,I)+1)
for i in range(0,no):
    Fo.append(Fomax-i)
nu=int(2*min(Ju,I)+1)
for i in range(0,nu):
    Fu.append(Fumax-i)
for i in range(0,no):
    for j in range(0,nu):
        if abs(Fo[i]-Fu[j])<2:
            new.append(newo+(Ao/2)*(Fo[i]*(Fo[i]+1)-Jo*(Jo+1)-I*(I+1))-(Au/2)*(Fu[j]*(Fu[j]+1)-Ju*(Ju+1)-I*(I+1)))
            In.append((2*Fo[i]+1)*(2*Fu[j]+1)*(wigner_6j(Jo,Fo[i],I,Fu[j],Ju,1))**2/(2*I+1))
            max1=np.max(In)
for i in range(0,len(new)):
    for j in range(0,len(new)):
        if new[i]>new[j]:
            temp=new[j]
            new[j]=new[i]
            new[i]=temp
            temp=In[j]

            In[j]=In[i]
            In[i]=temp
zr=[]
sigma=0.031
x2=[]
y2=[]
y2r=[]
for i in range(0, len(new)):
    mew=new[i]
    for j in range(-100,100):
        c=mew+j/1000
        cc=In[i]*(1/(sigma*(44/7)**0.5))*np.exp(-1*((c-mew)/sigma)**2)
        y2.append(cc)
        x2.append(c)
max2=np.max(y2)
for i in range(0,len(new)):
    In[i]=In[i]/max1
for i in range(0,len(y2)):
    y2[i]=y2[i]/max2
for i in range(0,len(y2)):
    y2r.append(y2[i])
for i   in range(0,15):
    a=5
print(centroid)
fig, ax = plt.subplots()
plt.plot(x2, y2r,label="fitted data")
plt.legend()
plt.show()

I have this code which is making multiple peaks. The image 1 shows the data with multiple peaks overlapped with each other but i m trying to achieve only one curve by using these overlapped peaks as shown in image 2 in 'red' line. This  image is formed by running the program .

But the issue is that have to fit a line as shown in the last picture Red line is drawn by hand i want it to drawn by python


Solution

  • I hope I get the question now. If I see it right the problem is basically that the x values differ. On top of it, everything is merged in a single list. To handle this I changed everything after print(centroid) to

    from scipy.interpolate import interp1d
    
    def partition( inList, n ):
        return zip( *[ iter( inList ) ] * n )
    
    xSplit = partition( x2, 200 ) ###manually set to 200 as data is created with range(-100,100)
    ySplit = partition( y2r, 200 )
    allx = sorted( x2 )
    ally = np.zeros( len( allx ), np.float )
    funcDict = dict()
    for i in range( len( xSplit ) ):
        funcDict[i] = interp1d( xSplit[i], ySplit[i], kind='linear', bounds_error=False, fill_value=0 ) 
    for i in range( len( xSplit ) ):
        ally += funcDict[i]( allx )
    
    fig, ax = plt.subplots()
    ax.plot( allx, ally, linewidth=2 )
    for col1, col2 in zip( xSplit, ySplit ):
        plt.plot( col1, col2, linestyle='--' )
    plt.legend()
    plt.show()
    

    which gives you

    sum vie interpolation

    which is the sum, but using interpolation of the data. Was that the idea?

    Edit Seems that the OP requires more an envelope rather than a sum. On solution is given by James Phillips. One can even shorten this using numpy changing

    ally += funcDict[i]( allx )
    

    to

    ally = np.maximum(ally, funcDict[i]( allx ) )
    

    which then gives

    enter image description here