# Normal distributions and MCMC

> Gaussian2D { mean, covariance } is a 2D normal distribution. density(p) is its probability density, principal_axes() the standard deviation along each…

Page: https://fframes-kit.pages.dev/docs/machine-learning/normal-distributions-and-mcmc/
Cargo feature: `ml` (`fframes-kit = { version = "..", features = ["ml"] }`)

`Gaussian2D { mean, covariance }` is a 2D normal distribution. `density(p)` is its
probability density, `principal_axes()` the standard deviation along each eigenvector of the
covariance (the longer axis first), `ring(k)` the ellipse `k` standard deviations from the
mean, and `samples(seed, n)` seeded samples. All of these are empty or `None` when the
covariance is not positive definite.

- **`GaussianEllipse`.** The ellipses of equal density `sigmas` standard deviations from the
  mean (1, 2 and 3 by default) on `axes`, each filled at `fill_opacity` so the middle is
  darkest, the mean as a dot and, with `show_axes`, the principal axes. With `stagger` the
  rings appear one after the other from `start`, the innermost first.
- **`McmcChain`.** A random-walk Metropolis-Hastings chain sampling the equal mixture of the
  distributions in `target`. It starts at `origin`, proposes steps from a normal distribution
  `proposal` wide, and takes a step with the probability `min(1, p(to) / p(from))`, so a step
  uphill is always taken. `chain()` gives its `steps` (`McmcStep { from, to, accepted }`), the
  same for the same `seed`. With `run: Some(ChainRun { start, duration })` a dot walks the
  accepted moves at an even speed over `duration`, drawing the path in `accepted_color`.
  Every proposal it rejects appears as a ring in `rejected_color` when the dot is where it was
  proposed. Rejected proposals outside the axes are not drawn.

Draw both before the `Axes` so the axis lines stay on top. Gallery scenes: `GaussianEllipse`,
`McmcChain` (a chain finding both modes of a mixture), `McmcSwarm` (ten chains from the edge
finding three modes together).

Gallery clip of `GaussianEllipse`: https://fframes-kit.pages.dev/media/scenes/GaussianEllipse-4633b057.mp4

Gallery clip of `McmcChain`: https://fframes-kit.pages.dev/media/scenes/McmcChain-122955ac.mp4

Gallery clip of `McmcSwarm`: https://fframes-kit.pages.dev/media/scenes/McmcSwarm-ce159bfa.mp4

```rust
use fframes_kit::prelude::*;

fn distribution<'a>(ui: &mut Ui<'a, '_, '_>) -> Svgr<'a> {
    let axes = Axes::default();
    let gaussian = Gaussian2D { mean: (0.4, -0.2), covariance: [[1.2, 0.5], [0.5, 0.45]] };
    let ellipse = ui.show(GaussianEllipse { gaussian, axes: axes.map(ui), ..ui.defaults() });
    let chain = ui.show(McmcChain {
        target: vec![gaussian], axes: axes.map(ui), steps: 70, seed: 5,
        run: Some(ChainRun { start: 0.9, duration: 3.6 }), ..ui.defaults()
    });
    let axes = ui.show(axes);
    svgr!(<g>{ellipse}{chain}{axes}</g>)
}
```

## API

Components are plain structs. Set the fields you need and fill the rest with `..ui.defaults()`: the defaults below come from the current theme (`theme.` values are fields of `Theme`).

### GaussianEllipse

A 2D normal distribution drawn as its ellipses of equal density (`ManimML`'s `GaussianDistribution`): a ring `sigmas` standard deviations from the mean for each entry, in `color`, each filled at `fill_opacity` (the inner rings stack up darker), the mean as a dot and, with `show_axes`, the principal axes out to the outer ring. On `axes`; draw the [`Axes`](https://fframes-kit.pages.dev/docs/layout-and-shapes/coordinate-systems.md) after it. With `stagger` the rings appear one after the other from `start`, the innermost first.

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `gaussian` | `Gaussian2D` | `Gaussian2D::default()` | The 2D normal distribution (mean and covariance) whose ellipses are drawn. |
| `axes` | `AxesMap` | `AxesMap::default()` | The axes to draw on, mapping data values to the canvas. |
| `sigmas` | `Vec<f64>` | `vec![1.0, 2.0, 3.0]` | Standard deviations from the mean at which a ring is drawn, one ring per entry. |
| `color` | `Color` | `theme.colors.accent` | Colour of the rings, their fill, the mean dot and the principal axes. |
| `fill_opacity` | `f32` | `0.12` | 0 transparent to 1 opaque, of each ring's fill; inner rings stack up darker. |
| `stroke_width` | `f32` | `2.5` | Width in pixels of the ring outlines; the mean dot scales with it. |
| `show_axes` | `bool` | `false` | Draws the principal axes of the distribution out to the outer ring. |
| `start` | `f32` | `0.0` | Seconds after the container's start when the first ring begins to appear. |
| `stagger` | `f32` | `0.0` | Seconds between one ring appearing and the next, innermost first; 0 shows all rings from the start. |
| `enter` | `Option<FadeIn>` | `None` | Fade in at the start; `None` for none. |
| `exit` | `Option<FadeOut>` | `None` | Fade out before the end; `None` for none. |

Feature `ml` · [Source](https://github.com/khanhthanhdev/fframes-kit/blob/main/fframes-kit/src/kits/ml/probability.rs#L176)

### McmcChain

A random-walk Metropolis-Hastings chain sampling the equal mixture of the normal distributions in `target` (`ManimML`'s MCMC scenes). It starts at `origin` and proposes steps drawn from a normal distribution `proposal` wide; a step is accepted with the probability `min(1, p(to) / p(from))`. The chain is the same for the same `seed`. With `run` it plays one step after another over the run's duration from its start: accepted moves extend the path in `accepted_color`, rejected proposals inside the axes stay as hollow marks in `rejected_color`, and the current state is a dot. On `axes`.

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `target` | `Vec<Gaussian2D>` | `vec![Gaussian2D::default()]` | The normal distributions whose equal mixture the chain samples. |
| `origin` | `(f64, f64)` | `(0.0, 0.0)` | The state the chain starts at, in data units of `axes`. |
| `proposal` | `f64` | `0.6` | Standard deviation of the random step proposed each time, in data units. |
| `steps` | `usize` | `60` | Number of steps (proposals) in the whole chain. |
| `seed` | `u64` | `1` | Seed of the chain; the same seed gives the same chain on every frame and machine. |
| `axes` | `AxesMap` | `AxesMap::default()` | The axes to draw on, mapping data values to the canvas. |
| `run` | `Option<ChainRun>` | `None` | When the steps play, and over how long; `None` shows the whole chain at once. |
| `accepted_color` | `Color` | `theme.colors.highlight` | Colour of the path of accepted moves and of the current state dot. |
| `rejected_color` | `Color` | `Color::hex("#ff6b6b")` | Colour of the hollow marks for rejected proposals. |
| `stroke_width` | `f32` | `2.5` | Width in pixels of the path and the rejected marks. |
| `point_radius` | `f32` | `6.0` | Radius in pixels of the current state dot. |
| `enter` | `Option<FadeIn>` | `None` | Fade in at the start; `None` for none. |
| `exit` | `Option<FadeOut>` | `None` | Fade out before the end; `None` for none. |

Methods:

- `fn chain(&self) -> Vec<McmcStep>`: The steps of the chain.

Feature `ml` · [Source](https://github.com/khanhthanhdev/fframes-kit/blob/main/fframes-kit/src/kits/ml/probability.rs#L298)
