I am trying to fit a gaussian to a set of data points that seem to follow a gaussian distribution. I have already checked a lot of possible ways to do that, but I don\'t really
I think there are two different things here:
seem to follow a gaussian distribution
→ If you think that the data are normally distributed, you are in the realms of statistics and probability distributions, and may want to make a test to see if they agree with a particular distribution (normal or other).
And work with your plot:
get a "better" gaussian plot
In your code, you can leave out the first estimation in curve_fit
and plot the fitted curve against a continuous independent variable:
import numpy as np
import matplotlib.pyplot as plt
from scipy import asarray as ar, exp, sqrt
from scipy.optimize import curve_fit
angles = [-8, -6, -4, -2, 0, 2, 4, 6, 8]
data = [99, 610, 1271, 1804, 1823, 1346, 635, 125, 24]
angles = ar(angles)
data = ar(data)
n = len(data) ## <---
mean = sum(data*angles)/n
sigma = sqrt(sum(data*(angles-mean)**2)/n)
def gaus(x,a,mu,sigma):
return a*exp(-(x-mu)**2/(2*sigma**2))
popt,pcov = curve_fit(gaus,angles,data)#,p0=[0.18,mean,sigma]) ## <--- leave out the first estimation of the parameters
xx = np.linspace( -10, 10, 100 ) ## <--- calculate against a continuous variable
fig = plt.figure()
plt.plot(angles, data, "ob", label = "Measured")
plt.plot(xx,gaus(xx,*popt),'r',label='Fit') ## <--- plot against the contious variable
plt.xlim(-10, 10)
plt.ylim(0, 2000)
plt.xticks(angles)
plt.title("$^{137}$Cs Zero Point")
plt.xlabel("Angle [$^\circ$]")
plt.ylabel("662 keV-Photon Count")
plt.grid()
plt.legend()
plt.savefig('normal.png')
plt.show()
In this example:
print( popt )
[ 1.93154077e+03 -9.21486804e-01 3.26251063e+00]
Note that the first estimation of the parameter is orders of magnitude away from the result: 0.18 vs. 1931.15.
The best way is to simply use the mean and variance of the points. I mean if you have access to the underlying data that generated this histogram, then you should calculate its mean and variance using the mean
and var
functions.
The histogram is just a visual approximation to the underlying data, and essentially you are estimating the mean and variance in a roundabout way by fitting the histogram instead of the data.
In any event, if you want to continue with your train of thought above, you need to add more points to angles. The best way to do this would be to do something like
angles2 = np.arange(-8,8,.1);
plt.plot(angles2,gaus(angles2,*popt),'r',label='Fit')
It could be that your fit just looks bad because you have very few data points. Using this approach, you would see what the continuous dictribution should look like.