function binomial_pmf(k, n, p) {
if (k > n || k < 0) return 0;
const logBinom = d3.sum(d3.range(1, k + 1), i => Math.log(n - i + 1) - Math.log(i));
return Math.exp(logBinom + k * Math.log(p) + (n - k) * Math.log(1 - p));
}
// Poisson probability function
function poisson_pmf(k, lambda) {
if (lambda <= 0) return 0;
return Math.exp(-lambda + k * Math.log(lambda) - d3.sum(d3.range(1, k + 1), i => Math.log(i)));
}
// Generate data
max_y = Math.min(n, Math.ceil(lambda + 4 * Math.sqrt(lambda)))
data = d3.range(0, max_y + 1).map(y => ({
y: y,
binomial: binomial_pmf(y, n, p),
poisson: poisson_pmf(y, lambda)
}))
Plot.plot({
width: 800,
height: 450,
marginLeft: 50,
marginBottom: 40,
x: {
label: "Number of Events (y) โ",
labelOffset: 35,
grid: true
},
y: {
label: "โ Probability",
labelOffset: 40,
domain: [0, Math.max(...data.map(d => Math.max(d.binomial, d.poisson))) * 1.1]
},
marks: [
Plot.line(data, {
x: "y",
y: "binomial",
stroke: "#2563eb",
strokeWidth: 3,
tip: true
}),
Plot.dot(data, {
x: "y",
y: "binomial",
fill: "#2563eb",
r: 4,
tip: {format: {y: ".4f"}}
}),
Plot.line(data, {
x: "y",
y: "poisson",
stroke: "#dc2626",
strokeWidth: 2,
strokeDasharray: "5,5",
tip: true
}),
Plot.dot(data, {
x: "y",
y: "poisson",
fill: "#dc2626",
r: 3,
tip: {format: {y: ".4f"}}
}),
Plot.ruleY([0])
],
caption: html`<span style="color: #2563eb;">โโโโ</span> Binomial(n, p) <span style="color: #dc2626;">โโโโ</span> Poisson(ฮป=np)`
})