// Convert x into its expansion in base b, as an array of integers (ascending powers of b) toBase = (b, x) => { if (x == 0) { return [0] } let ret = []; while (x > 0) { ret.push(x % b); x = Math.floor(x / b); } return ret; }; // Interpret xs as an expansion in base b (ascending powers of b) fromBase = (b, xs) => { let plval = 1 return xs.reduce((a, x) => { let new_a = x * plval; plval *= b; return a + new_a; }, 0) } // Map an expansion to a complex number (as a 2-array). // The expansion is interpreted in base `b`. // `n` terms of the series are used, with geometric ratio `c` adicAngles = (expansion, b, n, c) => { return d3.range(n).reduce((a, i) => { let angle = fromBase(b, expansion.slice(null, i + 1)) / (b ** (i + 1)); let x = c**i * Math.cos(2 * Math.PI * angle); let y = c**i * Math.sin(2 * Math.PI * angle); return [a[0] + x, a[1] + y]; }, [0, 0]); } pointCount = 1024; expansions = d3.range(pointCount).map((x) => toBase(base, x)); embedding = expansions.map( (x) => adicAngles(x, embedBase, 15, geometric) ); viewof base = Inputs.range([2, 10], { value: 2, step: 1, label: "Base of expansions (b)", }); viewof embedBase = Inputs.range([1.1, 10], { value: 2, step: 0.1, label: "Embedding base (p)", }); viewof geometric = Inputs.range([0.005, 0.995], { value: 0.9, step: 0.005, label: "Geometric ratio (c)", }); plot = Plot.plot({ grid: true, inset: 10, // aspectRatio: 1, width: 640, height: 480, marks: [ Plot.dot(embedding, { r: 1 }) ] });