Public
Edited
Dec 29, 2021
Importers
Insert cell
Insert cell
RNG = new RandomState('myseed') // uses String(seed) internally
Insert cell
x = RNG.normal(0,1)()
Insert cell
y = RNG.poisson(1.5)()
Insert cell
RNG.uniform().array(3, {dtype:Float32Array})
Insert cell
RNG.sample(x => x ** 2, 0, 1)()
Insert cell
RNG.onsphere(2)()
Insert cell
{
const radius = 2, n = 5;
const [vx,vy,vz] = RNG.onsphere(radius).array(n);
return Float64Array.from({length:n}, (_,i) => Math.sqrt(vx[i]**2 + vy[i]**2 + vz[i]**2));
}
Insert cell
RNG.shuffle([0,1,2,3,4,5,6,7,8,9])
Insert cell
Insert cell
class RandomState {
constructor(seed) {
this.source = new alea(seed);
for(const name in d3random) {
if(!name.startsWith('random')) continue;
// randomXyz => xyz
const distribution = name[6].toLowerCase() + name.slice(7);
this[distribution] = (...args) => {
const generator = d3random[name].source(this.source)(...args);
generator.array = (size, {dtype=Float64Array}={}) => dtype.from({length:size}, () => generator());
return generator;
}
}
}
// Generate random samples drawn from func(x) normalized on [lo,hi].
// Uses ngrid equally spaced points on [lo,hi] to interpolate the inverse CDF.
sample(func, lo, hi, {ngrid=128}={}) {
// Tabulate the function on a grid of x values.
const dx = (hi - lo) / ngrid;
const x = Float64Array.from({length: ngrid+1}, (_,i) => lo + dx * i);
const fx = x.map(x => func(x));
// Calculate the cummulative distribution function for func(x) normalized over [xlo,xhi]
let cdf = fx.reduce(
(out, _, i, fx) => {
out.push((i==0? 0: out[i-1] + 0.5 * (fx[i-1] + fx[i])));
return out
}, []);
cdf = cdf.map(x => x / cdf[ngrid]);
const generator = () => interp(this.uniform(0,1)(), cdf, x);
// Implement a more efficient custom array generator.
generator.array = (size, {dtype=Float64Array}={}) => interp(
this.uniform(0,1).array(size, {dtype:dtype}), cdf, x);
return generator;
}
// Generate random points uniformly distributed on the surface of a sphere.
onsphere(radius=1) {
const twopi = 2 * Math.PI;
const generator = () => {
const phi = this.uniform(0, twopi)();
const vz = this.uniform(-radius, radius)();
const vr = Math.sqrt(radius * radius - vz * vz);
const vx = vr * Math.cos(phi);
const vy = vr * Math.sin(phi);
return [vx, vy, vz];
}
// Implement array generator that returns [vx0,vy0,vz0,vx1,vy1,vz1,...]
generator.array = (size, {dtype=Float64Array}={}) => {
const phi = this.uniform(0, twopi).array(size, {dtype:dtype});
const vz = this.uniform(-radius, radius).array(size, {dtype:dtype});
const rsq = radius * radius;
const vr = vz.map(vz => Math.sqrt(rsq - vz * vz));
const vx = vr.map((vr,i) => vr * Math.cos(phi[i]));
const vy = vr.map((vr,i) => vr * Math.sin(phi[i]));
return [vx, vy, vz];
};
return generator;
}
// Shuffle an array in place.
shuffle(array) {
const u = this.uniform(0,1).array(array.length, {dtype:Float64Array});
const swap = Int32Array.from({length:u.length}, (_,i)=>Math.floor(u[i]*i));
for(let i=array.length-1; i>0; i--) {
const j = swap[i];
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
}
Insert cell
Insert cell
Insert cell
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