Skip to content

Commit

Permalink
DOCS: Add docs and example for custom_bc
Browse files Browse the repository at this point in the history
Also updated the logo_plot helper script to use the Baseline class.
  • Loading branch information
derb12 committed Feb 12, 2024
1 parent 2978e0f commit d677d71
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 6 deletions.
12 changes: 12 additions & 0 deletions docs/algorithms/optimizers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,15 @@ the name).
poly_order = 1
baseline, params = baseline_fitter.adaptive_minmax(y, poly_order=poly_order, method='imodpoly')
ax.plot(baseline, 'g--')


custom_bc (Customized Baseline Correction)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:meth:`~.Baseline.custom_bc` allows fine tuning the stiffness of the
baseline within different regions of the fit data, which is helpful when
experimental data has drastically different baselines within it. This is done by
reducing the number of data points in regions where higher stiffness
is required. There is no figure showing the fits for various baseline types for
this method since it is more suited for hard-to-fit data; however, :ref:`an
example <sphx_glr_examples_optimizers_plot_custom_bc_1_whittaker.py>` showcases its use.
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@
'../examples/morphological',
'../examples/spline',
'../examples/classification',
'../examples/misc'
'../examples/misc',
'../examples/optimizers',
]

sphinx_gallery_conf = {
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pybaselines is a library of algorithms for the baseline correction of experiment
introduction
installation
quickstart
parameter_selection
algorithms/index
examples/index
api/index
Expand Down
1 change: 1 addition & 0 deletions docs/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ names of the algorithms were used. The algorithms are grouped accordingly:
* collab_pls (Collaborative Penalized Least Squares)
* optimize_extended_range
* adaptive_minmax (Adaptive MinMax)
* custom_bc (Customized Baseline Correction)

* Miscellaneous methods (:mod:`pybaselines.misc`)

Expand Down
53 changes: 53 additions & 0 deletions docs/parameter_selection.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
===================
Parameter Selection
===================

Most baseline algorithms in pybaselines have several parameters that can be adjusted.
While this allows for fine-tuning each algorithm to work in a wide array of cases,
it can also present a difficulty for new users. It is suggested to start by adjusting only
one or two main parameters, and then change other parameters as needed. **Due to the
variable nature of baselines, it is highly recommended to not assume the default
parameters will work for your data!** Below are the suggested parameters to begin
adjusting for each family of algorithms within pybaselines:

* Polynomial methods

* ``poly_order`` controls the curvature of the baseline.

* Whittaker-smoothing-based methods

* ``lam`` controls the curvature of the baseline. See
:ref:`this example <sphx_glr_examples_whittaker_plot_lam_effects.py>`
to get an idea of how ``lam`` effects the baseline. The optimal ``lam``
value for each algorithm is not typically the same.

* Morphological methods

* ``half_window`` controls the general fit of the baseline. See
:ref:`this example <sphx_glr_examples_morphological_plot_half_window_effects.py>`
to get an idea of how ``half_window`` effects the baseline. The optimal
``half_window`` value for each algorithm is not typically the same.

* Spline methods

* ``lam`` controls the curvature of the baseline. The
:ref:`Whittaker example <sphx_glr_examples_whittaker_plot_lam_effects.py>`
also generally applies to spline methods.

* Smoothing-based methods

* ``half_window`` controls the general fit of the baseline. The
:ref:`Morphological example <sphx_glr_examples_morphological_plot_half_window_effects.py>`
also generally applies to smoothing methods.

* Baseline/Peak Classification methods

* Algorithm dependent

* Optimizers

* Algorithm dependent

* Miscellaneous methods

* Algorithm dependent
2 changes: 2 additions & 0 deletions examples/optimizers/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Optimizer Baseline Examples
---------------------------
104 changes: 104 additions & 0 deletions examples/optimizers/plot_custom_bc_1_whittaker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
"""
Customized Baseline Correction
------------------------------
This example looks at the ingenious basline correction method created
by Liland et al., :meth:`~.Baseline.custom_bc`.
The :meth:`.custom_bc` method works exceedingly well for morphological
and smoothing baselines, since those methods typically depend directly
on the number of data points, and for Whittaker-smoothing-based methods,
since the `lam` value is :ref:`heavily dependant on the number of data
points <sphx_glr_examples_whittaker_plot_lam_vs_data_size.py>`.
This example will examine the use of the optimizer method
:meth:`~.Baseline.custom_bc` paired with the Whittaker-smoothing-based
method :meth:`~.Baseline.arpls`
"""
# sphinx_gallery_thumbnail_number = 1

import matplotlib.pyplot as plt
import numpy as np

from pybaselines import Baseline
from pybaselines.utils import gaussian


x = np.linspace(20, 1000, 1000)
signal = (
+ gaussian(x, 6, 240, 5)
+ gaussian(x, 8, 350, 11)
+ gaussian(x, 15, 400, 18)
+ gaussian(x, 6, 550, 6)
+ gaussian(x, 13, 700, 8)
+ gaussian(x, 9, 800, 9)
+ gaussian(x, 9, 880, 7)
)
baseline = 5 + 6 * np.exp(-(x - 40) / 30) + gaussian(x, 5, 1000, 300)
noise = np.random.default_rng(0).normal(0, 0.1, len(x))
y = signal + baseline + noise

baseline_fitter = Baseline(x_data=x)
# %%
# For certain types of data, there can often be a sharp change in the
# baseline withinin a small region, such as in Raman spectroscopy
# near a wavenumber of 0 or in XRD at low two-theta. This presents a
# significant challenge to baseline algorithms that fit a single "global"
# baseline such as Whittaker-smoothing-based methods. The majority of
# the data can be fit using a "stiff" baseline, but the anomolous region
# requires a more flexible baseline.
#
# Plotting each of these two cases separately, it is apparent each fits
# its target region well, but combining the two into a single baseline
# is difficult.
lam_flexible = 1e2
lam_stiff = 5e5

flexible_baseline = baseline_fitter.arpls(y, lam=lam_flexible)[0]
stiff_baseline = baseline_fitter.arpls(y, lam=lam_stiff)[0]

plt.figure()
plt.plot(x, y)
plt.plot(x, flexible_baseline, label='Flexible baseline')
plt.plot(x, stiff_baseline, label='Stiff baseline')
plt.legend()

# %%
# The beauty of Liland's customized baseline correction method is that
# it allows fitting baselines that are stiff in some regions and flexible
# in others by simply truncating the data to increase the stiffness. The input
# ``lam`` value within `method_kwargs` should correspond to the most flexible region, and the
# truncation should begin close to where the stiff and flexible baselines
# overlap, which is at approximately x=160 from the above figure. A small `lam` value
# of 1e1 is used to then smooth the calculated baseline using Whittaker
# smoothing so that the two regions connect without any significant discontinuity.

crossover_index = np.argmin(abs(x - 160))
fit_baseline, params = baseline_fitter.custom_bc(
y, 'arpls',
regions=([crossover_index, None],),
sampling=15,
method_kwargs={'lam': lam_flexible},
lam=1e1
)

plt.figure()
plt.plot(x, y)
plt.plot(x, fit_baseline, label='Fit baseline')
plt.plot(x, baseline, '--', label='True baseline')
plt.legend()

# %%
# Looking at the results, this method is able to accurately recreate the
# true data even though the two baselines have significantly different
# requirements for stiffness.

plt.figure()
plt.plot(x, y - baseline, label='True data')
plt.plot(x, y - fit_baseline, label='Baseline corrected')
plt.legend()


plt.show()
1 change: 1 addition & 0 deletions pybaselines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
* collab_pls (Collaborative Penalized Least Squares)
* optimize_extended_range
* adaptive_minmax (Adaptive MinMax)
* custom_bc (Customized Baseline Correction)
* Miscellaneous methods (:mod:`pybaselines.misc`)
Expand Down
12 changes: 7 additions & 5 deletions tools/logo_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
raise
import numpy as np

import pybaselines
from pybaselines import utils
from pybaselines import Baseline, utils

# assumes file is in pybaselines/tools
image_directory = Path(__file__).parent
Expand All @@ -46,17 +45,20 @@
noise = np.random.default_rng(1).normal(0, 0.05, x.size)

y = signal + true_baseline + noise
baseline = pybaselines.whittaker.arpls(y, lam=1e7)[0]
baseline = Baseline().arpls(y, lam=1e7)[0]

ax.plot(x, y, lw=1.5)
ax.plot(x, baseline)
blue = '#0952ff'
pink = '#ff5255'
ax.plot(x, y, lw=1.5, color=blue)
ax.plot(x, baseline, lw=4, color=pink)

ax.set_yticks([])
ax.set_xticks([])
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)

# save as an svg so that it can be edited/scaled in inkskape without
# losing image quality
fig.savefig(image_directory.joinpath('logo_new.svg'), transparent=True)
Expand Down

0 comments on commit d677d71

Please sign in to comment.