Public
Edited
Sep 25, 2024
Importers
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof tennisBallDiameter = dist`${normalInterval(6.54, 6.86, {
p: 0.95
})} / 100`
Insert cell
Insert cell
Insert cell
tennisBallDiameter
Insert cell
Insert cell
[d3.mean(tennisBallDiameter), d3.variance(tennisBallDiameter)]
Insert cell
Insert cell
Plot.tickX(tennisBallDiameter, { strokeOpacity: 0.3 }).plot()
Insert cell
Insert cell
viewof tennisBallVolume = dist`4/3 * ${Math.PI} * (${tennisBallDiameter}^2)`
Insert cell
Insert cell
busLength = to(10, 15)
Insert cell
Insert cell
busWidth = to(2, 2.5, { p: 0.95, n: 10000 })
Insert cell
Insert cell
Insert cell
viewof isDoubleDeckerBus = Inputs.toggle({ label: "Is double decker bus?" })
Insert cell
Insert cell
viewof busHeight = dist`(3 to 4) * ${isDoubleDeckerBus ? 2 : 1}`
Insert cell
viewof busVolume = dist`${busLength} * ${busWidth} * ${busHeight}`
Insert cell
Insert cell
availableSpace = to(0.6, 0.85)
Insert cell
Insert cell
viewof worstPackingEfficiency = Inputs.range([0, 73.99], {
label: "Worst-case % of space filled with tennis balls",
value: 63.5
})
Insert cell
Insert cell
viewof numberOfBalls = dist`
(${busVolume} * ${availableSpace} * ((${worstPackingEfficiency} / 100) to 0.74)) / ${tennisBallVolume}
`
Insert cell
The number of tennis balls that can fit into a ${isDoubleDeckerBus ? "double" : "single"}-decker bus is ~${Math.round(d3.mean(numberOfBalls))}.
Insert cell
Insert cell
Insert cell
function randomSample(random, n, ...args) {
const S = Array.from({ length: n });
for (let i = 0; i < n; i++) {
S[i] = random(...args);
}
return S;
}
Insert cell
DEFAULT_P = 0.9
Insert cell
DEFAULT_N = 1000
Insert cell
Insert cell
randomLognormal = (
await import("https://esm.sh/@stdlib/random@0.3.0/base/lognormal")
).default
Insert cell
function lognormal(μ, σ, { n = DEFAULT_N } = {}) {
return randomSample(randomLognormal, n, μ, σ);
}
Insert cell
Insert cell
erfinv = (await import("https://esm.sh/@stdlib/math@0.3.0/base/special/erfinv"))
.default
Insert cell
function lognormalInterval(u, v, { p = DEFAULT_P, n = DEFAULT_N } = {}) {
const logU = Math.log(u);
const logV = Math.log(v);

const Z = Math.sqrt(2) * erfinv(p);
const μ = (logU + logV) / 2;
const σ = (logV - logU) / (2 * Z);

return lognormal(μ, σ, { n });
}
Insert cell
Insert cell
to = lognormalInterval
Insert cell
Insert cell
lognormalInterval(5, 10)
Insert cell
Insert cell
Insert cell
randomNormal = (await import("https://esm.sh/@stdlib/random@0.3.0/base/normal"))
.default
Insert cell
function normal(μ, σ, { n = DEFAULT_N } = {}) {
return randomSample(randomNormal, n, μ, σ);
}
Insert cell
function normalInterval(u, v, { p = DEFAULT_P, n = DEFAULT_N } = {}) {
const Z = Math.sqrt(2) * erfinv(p);
const μ = (u + v) / 2;
const σ = (v - u) / (2 * Z);
return normal(μ, σ, { n });
}
Insert cell
Insert cell
randomUniform = (
await import("https://esm.sh/@stdlib/random@0.3.0/base/uniform")
).default
Insert cell
function uniform(a, b, { n = DEFAULT_N } = {}) {
return randomSample(randomUniform, n, a, b);
}
Insert cell
Insert cell
randomBeta = (await import("https://esm.sh/@stdlib/random@0.3.0/base/beta"))
.default
Insert cell
function beta(α, β, { n = DEFAULT_N } = {}) {
return randomSample(randomBeta, n, α, β);
}
Insert cell
Insert cell
Insert cell
function betaMeanSampleSize(μ, ν, { n = DEFAULT_N } = {}) {
const α = μ * ν;
const β = (1 - μ) * ν;
return beta(α, β, { n });
}
Insert cell
Insert cell
Insert cell
function betaMeanStdev(μ, σ, { n = DEFAULT_N } = {}) {
const ν = (μ * (1 - μ)) / σ ** 2 - 1;
return betaMeanSampleSize(μ, ν, { n });
}
Insert cell
Insert cell
randomGamma = (await import("https://esm.sh/@stdlib/random@0.3.0/base/gamma"))
.default
Insert cell
function gamma(α, β, { n = DEFAULT_N } = {}) {
return randomSample(randomGamma, n, α, β, );
}
Insert cell
Insert cell
function exponential(λ, { n = DEFAULT_N } = {}) {
return gamma(1, λ, { n });
}
Insert cell
Insert cell
sample = (await import("https://esm.sh/@stdlib/random@0.3.0/sample")).default
Insert cell
function extractViewof(view) {
if (typeof view === "object" && "value" in view) {
return view.value;
}
return view;
}
Insert cell
function operate(operation, a, b) {
a = extractViewof(a);
b = extractViewof(b);

if (typeof a === "number" && typeof b === "number") {
return operation(a, b);
}

if (typeof a === "number" && Array.isArray(b)) {
const S = b.slice();
for (let i = 0; i < S.length; i++) {
S[i] = operation(a, S[i]);
}
return S;
}

if (Array.isArray(a) && typeof b === "number") {
const S = a.slice();
for (let i = 0; i < S.length; i++) {
S[i] = operation(S[i], b);
}
return S;
}

if (Array.isArray(a) && Array.isArray(b)) {
const n = Math.min(a.length, b.length);
const S = Array.from({ length: n });

const aBar = sample(a, { size: n });
const bBar = sample(b, { size: n });

for (let i = 0; i < S.length; i++) {
S[i] = operation(aBar[i], bBar[i]);
}

return S;
}
}
Insert cell
Insert cell
{
const x = to(10, 20);
const y = to(2, 3);
const z = to(1, 100);

const add = (a, b) => operate((a, b) => a + b, a, b);
const multiply = (a, b) => operate((a, b) => a * b, a, b);

return add(multiply(x, y), z);
}
Insert cell
Insert cell
parse = import("https://esm.sh/subscript@7.4.0/parse.js")
Insert cell
compile = import("https://esm.sh/subscript@7.4.0/compile.js")
Insert cell
Insert cell
Insert cell
Insert cell
NUMERIC_CHARACTERS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."]
Insert cell
function number() {
const parsed = parse.skip((character) =>
NUMERIC_CHARACTERS.includes(String.fromCharCode(character)) ? 1 : 0
);
const number = Number(parsed);
return ["", Number.isFinite(number) ? number : parse.err()];
}
Insert cell
Insert cell
numericLiterals = {
for (const character of NUMERIC_CHARACTERS) {
parse.lookup[character.charCodeAt()] = number;
}
}
Insert cell
Insert cell
literals = {
compile.operator("", (value) => () => value);
}
Insert cell
Insert cell
function defineOperator(operator, precedence, operation) {
parse.binary(operator, precedence);
compile.operator(operator, (expressionLeft, expressionRight) => {
if (!expressionRight) {
return;
}

const executeLeft = compile.default(expressionLeft);
const executeRight = compile.default(expressionRight);

return (bindings) => {
const a = executeLeft(bindings);
const b = executeRight(bindings);
return operate(operation, a, b);
};
});
}
Insert cell
Insert cell
PRECEDENCE = ({
ADD: 1,
MULTIPLY: 2,
EXPONENTIATE: 3,
NEGATIVE: 4,
BRACKETS: 5,
TO: 6
})
Insert cell
operators = {
defineOperator("+", PRECEDENCE.ADD, (a, b) => a + b);
defineOperator("-", PRECEDENCE.ADD, (a, b) => a - b);
defineOperator("*", PRECEDENCE.MULTIPLY, (a, b) => a * b);
defineOperator("/", PRECEDENCE.MULTIPLY, (a, b) => a / b);
defineOperator("^", PRECEDENCE.EXPONENTIATE, Math.pow);
defineOperator("to", PRECEDENCE.TO, to);
}
Insert cell
Insert cell
negative = {
parse.unary("-", PRECEDENCE.NEGATIVE);
compile.operator("-", (expression, expressionRight) => {
if (expressionRight) {
return;
}
const execute = compile.default(expression);
return (bindings) => {
const a = execute(bindings);
return -a;
};
});
}
Insert cell
Insert cell
brackets = {
parse.token("(", PRECEDENCE.BRACKETS, () => [
"(",
parse.expr(0, ")".charCodeAt())
]);
compile.operator("(", compile.default);
}
Insert cell
Insert cell
function distValue(strings, ...substitutions) {
numericLiterals;
literals;
operators;
negative;
brackets;

const bindings = Object.fromEntries(
substitutions.map((value, index) => [`v${index}`, value])
);
const code = String.raw(strings, ...Object.keys(bindings));
const expression = parse.default(code);
const execute = compile.default(expression);
return execute(bindings);
}
Insert cell
Insert cell
Insert cell
kde = await import("https://esm.sh/fast-kde@0.2.2")
Insert cell
function plot(sample) {
const density = [...kde.density1d(sample)];

const nearestQuantilesInDensity = [0.05, 0.5, 0.95]
.map((p) => d3.quantile(sample, p))
.map((q) => ({
i: d3.bisectCenter(
density.map((d) => d.x),
q
),
q
}))
.map(({ q, i }) => ({ x: q, y: density[i].y }));

const plot = Plot.plot({
y: { ticks: 0, label: "Density Estimate" },
x: { label: "Value" },
height: 196,
width,
marks: [
Plot.areaY(density, { x: "x", y: "y", fillOpacity: 0.1 }),
Plot.lineY(density, { x: "x", y: "y" }),
Plot.ruleY([0]),
Plot.ruleX(nearestQuantilesInDensity, {
x: "x",
y2: "y",
strokeDasharray: "5, 3"
}),
Plot.axisX(),
Plot.axisX(
nearestQuantilesInDensity.map(({ x }) => x),
{ textStroke: "#fff", textStrokeWidth: 5 }
),
Plot.crosshairX(density, { x: "x", y: "y" })
]
});

plot.addEventListener("input", (e) => e.stopImmediatePropagation());

return Object.assign(htl.html`<div>${plot}</div>`, { value: sample });
}
Insert cell
Insert cell
function dist(strings, ...substitutions) {
return plot(distValue(strings, ...substitutions));
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more