Create a Normal Distribution Curve
Let’s write a function to create the data for our visualisation. I would like to chart a normal distribution curve with a mean m
and a standard deviation of sd
Create the data
<script lang="ts">const n = 500;
const xRange = 40;
const xDomain = [0, 35];
const dist = { m: 8, sd: 2.5, color: "red" };
const normPDF = (m, sd, x) => {
const numerator = Math.exp(-Math.pow(x - m, 2) / (2 * Math.pow(sd, 2)));
const denominator = sd * Math.sqrt(2 * Math.PI);
return numerator / denominator;
};
const createDatum = (i, dist2) => {
const x = xDomain[0] + xRange * i / n;
const y = normPDF(dist2.m, dist2.sd, x);
return {
dist: dist2,
index: i,
x,
y
};
};
const data = new Array(n + 1).fill(0);
$: data.forEach((datum, i) => {
data[i] = createDatum(i, dist);
});
</script>
<!-- Show a sample of data we just created -->
{#each data.slice(50, 60) as d}
<div class="pb-1">{JSON.stringify(d, null, 2)}</div>
{/each}
</script>
Let’s print a piece of the data we just created:
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 50,
"x": 4,
"y": 0.04436833387178223
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 51,
"x": 4.08,
"y": 0.04667524852055666
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 52,
"x": 4.16,
"y": 0.049051855493194
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 53,
"x": 4.24,
"y": 0.05149671472582249
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 54,
"x": 4.32,
"y": 0.054008098843573736
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 55,
"x": 4.4,
"y": 0.05658398608993554
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 56,
"x": 4.48,
"y": 0.05922205445026807
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 57,
"x": 4.56,
"y": 0.0619196770646263
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 58,
"x": 4.64,
"y": 0.06467391902016778
}
{
"dist": {
"m": 8,
"sd": 2.5,
"color": "red"
},
"index": 59,
"x": 4.72,
"y": 0.06748153560757181
}
Plot the chart
Now it’s time to plot that data:
<script lang="ts">import { scaleLinear } from "d3-scale";
let width = 1e3;
let height = 250;
const margin = { top: 40, right: 0, bottom: 0, left: 0 };
export let n = 500;
const xRange = 40;
const xDomain = [0, 35];
$: x = scaleLinear().domain(xDomain).range([margin.left, width - margin.right]);
$: y = scaleLinear().domain([0, 0.15]).range([height - margin.bottom, margin.top]);
const dist = { m: 8, sd: 2.5, color: "red" };
const normPDF = (m, sd, x2) => {
const numerator = Math.exp(-Math.pow(x2 - m, 2) / (2 * Math.pow(sd, 2)));
const denominator = sd * Math.sqrt(2 * Math.PI);
return numerator / denominator;
};
const createDatum = (i, dist2) => {
const x2 = xDomain[0] + xRange * i / n;
const y2 = normPDF(dist2.m, dist2.sd, x2);
return {
dist: dist2,
index: i,
x: x2,
y: y2
};
};
let data;
$: data = new Array(n + 1).fill(0);
$: data.forEach((datum, i) => {
data[i] = createDatum(i, dist);
});
</script>
<svg viewBox="0 0 896 300" width="896px" height="300px">
{#if data}
{#each data as d}
<circle cx={x(d.x)} cy={y(d.y)} r="1" fill="red" />
{/each}
{/if}
</svg>
Here is how our data points look like:
In the next step we will use these kind of data to create a normal distribution curve and animating between distributions.