{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Fitting `lmfit.Model`s to `xarray` objects\n", "\n", "`xarray-lmfit` adds some methods to xarray objects that allows you to fit data with lmfit models: {meth}`xarray.DataArray.xlm.modelfit` and {meth}`xarray.Dataset.xlm.modelfit`, depending on whether you want to fit a single DataArray or multiple DataArrays in a Dataset.\n", "\n", ":::{hint}\n", "\n", "The syntax of the accessors are similar to the xarray native methods {meth}`xarray.DataArray.curvefit` and {meth}`xarray.Dataset.curvefit`.\n", "\n", ":::\n", "\n", "First, let us generate a Gaussian peak on a linear background." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import xarray as xr\n", "import matplotlib.pyplot as plt\n", "import lmfit\n", "\n", "# Generate Gaussian peak on linear background\n", "x = np.linspace(0, 10, 50)\n", "y = -0.1 * x + 2 + 3 * np.exp(-((x - 5) ** 2) / (2 * 1**2))\n", "\n", "# Add some noise with fixed seed for reproducibility\n", "rng = np.random.default_rng(5)\n", "yerr = np.full_like(x, 0.3)\n", "y = rng.normal(y, yerr)\n", "\n", "y_arr = xr.DataArray(y, dims=(\"x\",), coords={\"x\": x})\n", "\n", "y_arr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, `y_arr` is the DataArray that contains both the values we want to fit, along with the independent variable `x` as a coordinate.\n", "\n", "After importing `xarray_lmfit`, we can use {meth}`xarray.DataArray.xlm.modelfit` to fit the data to a model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import xarray_lmfit\n", "\n", "model = lmfit.models.GaussianModel() + lmfit.models.LinearModel()\n", "\n", "params = model.make_params(slope=-0.1, center=5.0, sigma={\"value\": 0.1, \"min\": 0})\n", "\n", "result = y_arr.xlm.modelfit(\"x\", model=model, params=params)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The fit result Dataset\n", "\n", "{meth}`xarray.DataArray.xlm.modelfit` returns a {class}`xarray.Dataset` including the best-fit parameters and the fit statistics:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's take a closer look at the data variables in the resulting Dataset.\n", "\n", "- `modelfit_results` contains the underlying {class}`lmfit.model.ModelResult` object from the fit.\n", "- `modelfit_coefficients` and `modelfit_stderr` contain the best-fit coefficients and their errors, respectively.\n", "- `modelfit_stats` contains the [goodness-of-fit statistics](https://lmfit.github.io/lmfit-py/fitting.html#goodness-of-fit-statistics).\n", "\n", "When called on a Dataset instead of a DataArray, these variables will be prefixed with the name of the data variable they correspond to.\n", "\n", "It may not be immediately obvious how this is useful, but the true power of the accessor comes from its ability to utilize xarray's powerful broadcasting capabilities, as described in the next section." ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.1" } }, "nbformat": 4, "nbformat_minor": 4 }