Gaussian fits using fit_pandas_GUI()
¶
You can try this notebook live by lauching it in Binder.This can take a while to launch, be patient. .
First we import pandas
and pandas_GUI
and then load some data to fit.
import pandas as pd
from pandas_GUI import *
df = pd.read_csv('DataSets/ethaneIRabs.csv.gz')
Then make a quick plot using plot_pandas_GUI()
to see what the data looks like. See the Pandas GUI Website for examples and documentation on using the plotting GUI.
# CODE BLOCK generated using plot_pandas_GUI().
# See https://jupyterphysscilab.github.io/jupyter_Pandas_GUI.
from plotly import graph_objects as go
Figure_1 = go.FigureWidget(layout_template="simple_white")
# Trace declaration(s) and trace formatting
scat = go.Scatter(x = df['1/CM'], y = df['Absorbance'],
mode = 'lines', name = 'Absorbance',)
Figure_1.add_trace(scat)
# Axes labels
Figure_1.update_xaxes(title= '1/cm', mirror = True)
Figure_1.update_yaxes(title= 'absorbance', mirror = True)
# Plot formatting
Figure_1.update_layout(title = 'Figure_1', template = 'simple_white', autosize=True)
Figure_1.show(config = {'toImageButtonOptions': {'format': 'svg'}})
Figure 1: IR absorbance spectrum of ethane.
Fitting a Gaussian to one of the bands (peaks)¶
All three of the bands have multiple overlapping peaks in them, so will only be fit poorly. However, they are adequate to illustrate the procedure.
Start by launching the fitting GUI by putting the command fit_pandas_GUI()
in an empty cell and running the cell.
1. On the first tab¶
the data set and a name for the trace is set. See the screenshot below.
2. On the second tab¶
the default "none" was kept for the Error Type
. See the screen shot below.
3. On the third tab¶
"GaussianModel" was chosen from the popup menu. Gaussian fits work poorly if they do not start with a good guess for the peak center. In this case we will fit to the middle peak. Thus, 1500 was entered for the center location. *Note: that it is necessary to click outside the box the number was entered in to set the value.
4. On tab 4¶
the range of the data to fit to was chosen to ignore the other two peaks. Consecutive pairs of selected points starting with the lowest data index number define each range. Points can be deselected by holding down the ctrl
key while clicking on a point.
The Extend fitted function plot
box was also checked so that the fit is shown in the ignored regions.
See the screenshot below.
5. On the fifth tab¶
labels for the X and Y axis were input and the Display Mirror Axes
box was checked.
6. On the last (sixth) tab¶
the final checks were done and then the 'Do Fit' button was clicked, closing the GUI and running the code in the cell below to perform the fit and display the results.
# CODE BLOCK generated using fit_pandas_GUI().
# See https://jupyterphysscilab.github.io/jupyter_Pandas_GUI.
# Integers wrapped in `int()` to avoid having them cast
# as other types by interactive preparsers.
# Imports (no effect if already imported)
import numpy as np
import lmfit as lmfit
import round_using_error as rue
import copy as copy
from plotly import graph_objects as go
from IPython.display import HTML, Math
# Define data and trace name
Xvals = df["1/CM"]
Yvals = df["Absorbance"]
tracename = "Absorbance"
# Define error (uncertainty)
Yerr = df["Absorbance"]*0.0 + 1.0
# Define the fit model, initial guesses, and constraints
fitmod = lmfit.models.GaussianModel()
fitmod.set_param_hint("amplitude", vary = True, value = 1.769551078621726)
fitmod.set_param_hint("center", vary = True, value = 1493.0)
fitmod.set_param_hint("sigma", vary = True, value = 1.0, min = 0.0)
# Define fit ranges
Yfiterr = copy.deepcopy(Yerr) # ranges not to fit = np.inf
Xfitdata = copy.deepcopy(Xvals) # ranges where fit not displayed = np.nan
Yfiterr[int(0):int(706)] = np.inf
Xfitdata[int(0):int(706)] = np.nan
Yfiterr[int(1635):int(3571)] = np.inf
Xfitdata[int(1635):int(3571)] = np.nan
# Do fit
Fit_1 = fitmod.fit(Yvals, x=Xvals, weights = 1/Yfiterr, scale_covar = True, nan_policy = "omit")
# Calculate residuals (data - fit) because lmfit
# does not calculate for all points under all conditions
resid = []
# explicit int(0) below avoids collisions with some preparsers.
for i in range(int(0),len(Fit_1.data)):
resid.append(Fit_1.data[i]-Fit_1.best_fit[i])
# Plot Results
# explicit int(..) below avoids collisions with some preparsers.
Fit_1_Figure = go.FigureWidget(layout_template="simple_white")
Fit_1_Figure.update_layout(title = "Fit_1_Figure",autosize=True)
Fit_1_Figure.set_subplots(rows=int(2), cols=int(1), row_heights=[0.2,0.8], shared_xaxes=True)
scat = go.Scatter(y=resid,x=Xvals, mode="markers",name = "residuals")
Fit_1_Figure.update_yaxes(title = "Residuals", row=int(1), col=int(1), zeroline=True, zerolinecolor = "lightgrey", mirror = True)
Fit_1_Figure.update_xaxes(row=int(1), col=int(1), mirror = True)
Fit_1_Figure.add_trace(scat,col=int(1),row=int(1))
scat = go.Scatter(x=Xvals, y=Yvals, mode="markers", name=tracename)
Fit_1_Figure.add_trace(scat, col=int(1), row=int(2))
Fit_1_Figure.update_yaxes(title = "absorbance", row=int(2), col=int(1), mirror = True)
Fit_1_Figure.update_xaxes(title = "1/cm", row=int(2), col=int(1), mirror = True)
scat = go.Scatter(y=Fit_1.best_fit, x=Xvals, mode="lines", line_color = "black", name="extrapolated",line_dash="dash")
Fit_1_Figure.add_trace(scat, col=int(1), row=int(2))
scat = go.Scatter(y=Fit_1.best_fit,x=Xfitdata, mode="lines", name="fit", line_color = "black", line_dash="solid")
Fit_1_Figure.add_trace(scat,col=int(1),row=int(2))
Fit_1_Figure.show(config = {'toImageButtonOptions': {'format': 'svg'}})
# Display best fit equation
ampstr = ''
centstr = ''
sigmastr = ''
for k in Fit_1.params.keys():
if Fit_1.params[k].vary:
paramstr = r'({\color{red}{'+rue.latex_rndwitherr(Fit_1.params[k].value,
Fit_1.params[k].stderr,
errdig=int(1),
lowmag=-int(3))+'}})'
else:
paramstr = r'{\color{blue}{'+str(Fit_1.params[k].value,
)+'}}'
if k == 'amplitude':
ampstr = paramstr
if k == 'center':
centstr = paramstr
if k == 'sigma':
sigmastr = paramstr
fitstr = r'$$fit = \frac{'+ampstr+'}{'+sigmastr+r'\sqrt{2\pi}}\exp \left( \frac{-\left[x-'+centstr+r'\right]^2}{2'+sigmastr+r'^2}\right)$$'
captionstr = r'<p>Use the command <code>Fit_1</code> as the last line of a code cell for more details.</p>'
display(Math(fitstr))
display(HTML(captionstr))
Use the command Fit_1
as the last line of a code cell for more details.
Figure 2: The results of the fit. Notice that the Gaussian is not a good fit to the details of the band (zoom in). However, it does fit the overall shape reasonably well.
Learn More¶
In addition to trying it below if this is a live notebook, you can look at the other examples listed in the Pandas GUI website.
Try It¶
If you are running this notebook live in binder you can try it here by running the first cell to import the tools and load the data. Then run the cell below to create the fit GUI. Note: You may want to expand the collapsed instructions to learn more about each tab.
fit_pandas_GUI()