Public
Edited
Sep 25
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more