# ml-peak-shape-generator

[![NPM version][npm-image]][npm-url]
[![build status][ci-image]][ci-url]
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

Generate various peak shapes.

The current supported kinds of shapes:

| Name                        | `kind`                  |                                                                                                                           Equation                                                                                                                            |
| --------------------------- | ----------------------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Gaussian                    | `gaussian`              |                                                          <img src="https://tex.cheminfo.org/?tex=y%5Ccdot%20exp%5Cleft%5B-%5Cfrac%7B1%7D%7B2%7D%5Cfrac%7B%5Cdelta%7D%7B%5Csigma%5E2%7D%5Cright%5D"/>                                                          |
| Lorentzian                  | `lorentzian`            |                                                                       <img src="https://tex.cheminfo.org/?tex=y%5Ccdot%5Cfrac%7B%5Comega%5E2%7D%7B4%5Cdelta%20%2B%20%5Comega%5E2%7D"/>                                                                        |
| Lorentzian Dispersive       | `lorentzianDispersive`  |                                                                       <img src="https://tex.cheminfo.org/?tex=y%5Ccdot%5Cfrac%7B2%5Comega%5Cdelta%7D%7B4%5Cdelta%5E2%20%2B%20%5Comega%5E2%7D"/>                                                                        |
| Generalized Lorentzian      | `generalizedLorentzian` | <img src="https://tex.cheminfo.org/?tex=y%5Ccdot%5Cleft%5B%281-%5Cgamma%29%5Ccdot%5Cfrac%7B1%7D%7B1%2Bu%7D%20%2B%20%5Cgamma%5Ccdot%5Cfrac%7B1%2B%5Cfrac%7Bu%7D%7B2%7D%7D%7B1%2Bu%2Bu%5E2%7D%5Cright%5D"/> |
| Pseudo Voigt                | `pseudoVoigt`           | <img src="https://tex.cheminfo.org/v1/?tex=y%20%5Ccdot%5Cleft%5Bmu%5Ccdot%20exp%5Cleft%5B-%5Cfrac%7B1%7D%7B2%7D%5Cfrac%7B%5Cdelta%7D%7B%5Csigma%5E2%7D%5Cright%5D%20%2B%20%5Cleft(1%20-%20mu%5Cright)%5Ccdot%5Cfrac%7B%5Comega%5E2%7D%7B4%5Cdelta%20%2B%20%5Comega%5E2%7D%5Cright%5D"/> |
| Pseudo Voigt (TCH)          | `pseudoVoigtTCH`        | The pseudo Voigt above, with independent gaussian and lorentzian widths `fwhmG` and `fwhmL`. The effective `fwhm` and `mu` are derived from them through the Thompson–Cox–Hastings approximation. |
| Split Gaussian (asymmetric) | `splitGaussian`         | Two gaussian halves sharing the apex: the lower-x half (`t ≤ x`) uses `fwhmLow`, the higher-x half (`t > x`) uses `fwhmHigh`. |

The only 2D shape is `gaussian`, whose widths are set per axis.

where

| <img src="https://tex.cheminfo.org/?tex=%5Cdelta%20%3D%20%5Cleft(t%20-%20x%5Cright)%5E2%0A"/> | <img src="https://tex.cheminfo.org/?tex=%5Csigma%20%3D%20%5Cfrac%7BFWHM%7D%7B2%5Csqrt%7B2%20%5Ccdot%20ln(2)%7D%7D"/> | <img src="https://tex.cheminfo.org/?tex=%5Comega%20%3D%20FWHM"/> |<img src="https://tex.cheminfo.org/v1/?tex=u%20%3D%20%5Cleft(%5Cfrac%7B2%5Cdelta%7D%7B%5Comega%7D%5Cright)%5E2"/> |
|---------------------: | :---------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------- |

## Installation

`$ npm i ml-peak-shape-generator`

This package allows to calculate various shapes. By default they will have a height of 1.

![demo.png](demo.png)

You see the resulting functions using this [playground](https://codesandbox.io/s/lorentzian-u1upg0?file=/Example.tsx)

## Usage

```js
import {
  getGaussianData,
  getLorentzianData,
  getPseudoVoigtData,
} from 'ml-peak-shape-generator';

// It's possible to specify the windows size with factor option
let data = getGaussianData({ sd: 500 }, { factor: 3.5 });
// or fix the number of points as Full Width at Half Maximum
let data = getGaussianData({ fwhm: 500 }, { factor: 3.5 });

// It's possible to specify the windows size with factor option
let data = getLorentzianData({ fwhm: 500 }, { factor: 5 });

// It's possible to specify the windows size with factor option
let data = getPseudoVoigtData({ fwhm: 500 }, { factor: 5 });
```

It is also possible to take an instance of each kind of shape:

```js
import { Gaussian, gaussianFct, Gaussian2D } from 'ml-peak-shape-generator';

const gaussianShape = new Gaussian({ fwhm: 500 });
// It is possible to set a new value for fwhm
gaussianShape.fwhm = 300;

// By default the height value ensure a volume equal 1.
const symmetric2DShape = new Gaussian2D({ fwhm: 500 });

// It is possible to set values for sd, fwhm and factor for each axes.
const gaussian2DShape = new Gaussian2D({ fwhm: { x: 300, y: 500 } });

// It is possible to set new value for fwhm by:
gaussian2DShape.fwhm = { x: 300, y: 500 };
// or set the same value for both axes.
gaussian2DShape.fwhm = 400;

// An instance of any shape has the same methods accessible for each
// shape e.g. fct or getData, but these use the internal parameters. e.g:

gaussianShape.fct(5);
gaussianFct(5, 500);
// getData
gaussianShape.getData({ factor: 3.5 });
```

```js
import { getShape1D, getShape2D } from 'ml-peak-shape-generator';

// If you want to dynamically select a shape you can use `getShape1D` /
// `getShape2D`. They return an instance of the required kind of shape.

const lorentzian = getShape1D({ kind: 'lorentzian', fwhm: 500 });
const gaussian2D = getShape2D({ kind: 'gaussian', sd: 500 });
```

## Descriptors, instances and serialization

A shape exists in two forms: a **descriptor** — a plain object such as
`{ kind: 'gaussian', fwhm: 500 }` — and an **instance**, the class that computes
the curve. `getShape1D` / `getShape2D` turn a descriptor into an instance.

An instance carries its own `kind` and serializes back to a descriptor, so a
shape survives a trip through JSON:

```js
import { getShape1D } from 'ml-peak-shape-generator';

const shape = getShape1D({ kind: 'pseudoVoigt', fwhm: 500, mu: 0.3 });

shape.kind; // 'pseudoVoigt'
JSON.stringify(shape); // '{"kind":"pseudoVoigt","fwhm":500,"mu":0.3}'

const restored = getShape1D(JSON.parse(JSON.stringify(shape)));
restored.fct(5) === shape.fct(5); // true
```

`toJSON` emits the parameters the shape is defined by — those `getParameters()`
reports — so a round trip preserves both the curve and its analytical
derivatives. A `splitGaussian` therefore emits `fwhmLow` and `fwhmHigh` rather
than its mean `fwhm`, and a `pseudoVoigtTCH` emits its component widths `fwhmG`
and `fwhmL`. Options that are alternative ways to express a width, such as `sd`,
are resolved first and emitted as the resulting `fwhm`.

Because an instance is itself a valid descriptor, handing one back to the
factory copies it:

```js
const copy = getShape1D(shape); // a new instance with the same parameters
```

The `kind` strings are exported as types:

```ts
import type { Shape1DKind, Shape2DKind } from 'ml-peak-shape-generator';

// Shape1DKind: 'gaussian' | 'lorentzian' | 'lorentzianDispersive' |
//              'pseudoVoigt' | 'pseudoVoigtTCH' | 'generalizedLorentzian' |
//              'splitGaussian'
// Shape2DKind: 'gaussian'
```

It is also possible to get a function that allows to calculate y for any x

```js
import { gaussianFct } from 'ml-peak-shape-generator';
const func = gaussianFct(x - mean, fwhm);
```

## [API Documentation](https://mljs.github.io/peak-shape-generator/)

## License

[MIT](./LICENSE)

[npm-image]: https://img.shields.io/npm/v/ml-peak-shape-generator.svg
[npm-url]: https://www.npmjs.com/package/ml-peak-shape-generator
[ci-image]: https://github.com/mljs/peak-shape-generator/workflows/Node.js%20CI/badge.svg?branch=main
[ci-url]: https://github.com/mljs/peak-shape-generator/actions?query=workflow%3A%22Node.js+CI%22
[codecov-image]: https://img.shields.io/codecov/c/github/mljs/peak-shape-generator.svg
[codecov-url]: https://codecov.io/gh/mljs/peak-shape-generator
[download-image]: https://img.shields.io/npm/dm/ml-peak-shape-generator.svg
[download-url]: https://www.npmjs.com/package/ml-peak-shape-generator
