import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit as cf

#Define our function in order to curve fit
def NormalFunc(x, mu, sigma, amp):
    return amp*(1/np.sqrt(2*np.pi*sigma**2))*np.exp(-((x-mu)**2)/(2*sigma**2))

#Create a data set of random numbers in a normal distribution
data = np.random.standard_normal(8000)

###############################################################################

#Graph the data with the matplotlib histogram function using auto numbered bins
n1, bins1, patches1 = plt.hist(data, bins='auto')
plt.title('Random Numbers Generated by Numpy Normal Distribution')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()

#Create an array of the center of each bin and curvefit the histogram
centers1 = bins1[:-1]+np.diff(bins1)/2
popt1, pcov1 = cf(NormalFunc, centers1, n1, p0=[0.1, 1, 500], maxfev=5000)

#Plot the histogram along with the fitted normal distribution function
fitx = np.linspace(bins1[0], bins1[-1], 10000)
plt.hist(data, bins='auto')
plt.plot(fitx, NormalFunc(fitx, *popt1))
plt.title('Random Numbers Generated by Numpy Normal Distribution Fitted to Curve')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()

###############################################################################

#Graph the data with the matplotlib histogram function using 25 bins
n2, bins2, patches2 = plt.hist(data, bins=25)
plt.title('Random Numbers Generated by Numpy Normal Distribution')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()

#Create an array of the center of each bin and curvefit the histogram
centers2 = bins2[:-1]+np.diff(bins2)/2
popt2, pcov2 = cf(NormalFunc, centers2, n2, p0=[0.1, 1, 1000], maxfev=5000)

#Plot the histogram along with the fitted normal distribution function
fitx = np.linspace(bins2[0], bins2[-1], 10000)
plt.hist(data, bins=25)
plt.plot(fitx, NormalFunc(fitx, *popt2))
plt.title('Random Numbers Generated by Numpy Normal Distribution Fitted to Curve')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()

###############################################################################

#Graph the data with the matplotlib histogram function using 10 bins
n3, bins3, patches3 = plt.hist(data, bins=10)
plt.title('Random Numbers Generated by Numpy Normal Distribution')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()

#Create an array of the center of each bin and curvefit the histogram
centers3 = bins3[:-1]+np.diff(bins3)/2
popt3, pcov3 = cf(NormalFunc, centers3, n3, p0=[0.1, 1, 2000], maxfev=5000)

#Plot the histogram along with the fitted normal distribution function
fitx = np.linspace(bins3[0], bins3[-1], 10000)
plt.hist(data, bins=10)
plt.plot(fitx, NormalFunc(fitx, *popt3))
plt.title('Random Numbers Generated by Numpy Normal Distribution Fitted to Curve')
plt.xlabel('Number')
plt.ylabel('Frequency')
plt.show()