Interactive Curve-Fitting in the IPython Notebook

Important: Widgets will not display in "static" notebooks until IPython 3.0. They must be backed by a live IPython kernel. Therefore, to view the full widget display, you must download this notebook and run it locally using IPython 2.x or greater.

In [1]:
%matplotlib inline
from lmfit import Model, Fitter
import numpy as np

lmfit

The lmfit package provides layers of high-level interfaces to the nonlinear optimization and curve fitting algorithms in scipy.

  • Parameter objects allow fit parameters to be bounded (min, max) or held fixed (vary=False).
  • The Model class provides a general way to wrap a user-defined function as a fitting model.
  • Fitter provides a curve-fitting workflow akin to popular GUI-based tools while retaining programmatic access to the underlying objects.

BaseFitter introduces no new dependencies; MPLFitter requires matplotlib; NotebookFitter uses IPython's rich display to represent each Parameter as a group of IPython widgets. Fitter will point to the richest implementation available.

Interactive Fitting Widget

Select any model from the drop-down menu.

Text input widgets will appear corresponding to the parameters for that model. If the model supports automatic guessing, the values will be initialized according to model.guess(data, ...), and an auto-guess button will be available to re-generate these values at any time.

The values in the text input widgets will serve as an initial guess, and they can be edited by the user. Text inputs for min and max appear when the associated checkboxes are checked. At all times, fitter.current_params is maintained in sync with the values shown in the widget.

When satisfied with the initial guess, click "Fit". The plot will update to show the data, the initial guess fit (gray), and the best fit (red). The attribute fitter.current_result will contain the result object created by the latest execution of fit. The text widgets and the property fitter.current_params will be updated from the initial fit to the latest best fit.

In [2]:
data = np.array([1,2,3,4,5,4,3,2])
x = np.arange(len(data))

fitter = Fitter(data, x=x)

fitter
In [3]:
fitter.current_result.values
Out[3]:
{'amplitude': 26.028242079115383,
 'center': 3.9949292338671754,
 'fwhm': 5.2960363977622071,
 'sigma': 2.2490196268768767}

Reuse the Fitter on Different Data

Unlike Model, Fitter is "stateful;" it remembers that it has been called, and it uses each best fit as the initial guess for the next fit (unless a new guess is provided).

Execute the cell below and revisit to the fitter above. (Or create a new view below; multiple views of the same instance of fitter all stay in sync.) Clicking "Fit" will use the most recent best fit to data as the initial guesss for fitting other_data.

In [4]:
other_data = np.array([10, 11, 12, 11, 10, 8, 7, 6])
fitter.data = other_data

Select a User-Defined Model

Any subclass of Model will be included in the drop-down menu. Look for 'UserDefinedModel' in the menu below.

In [5]:
def func(x, a=1):
    "a very simple model indeed"
    return x + a

class UserDefinedModel(Model):
    def __init__(self, *args, **kwargs):
        super(UserDefinedModel, self).__init__(func, *args, **kwargs)
In [6]:
data = np.array([1,2,3,4,5,4,3,2])
x = np.arange(len(data))

fitter = Fitter(data, x=x)

fitter

See the docstring for more, including complete access to the plot elements.