Public
Edited
Sep 3, 2024
Importers
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
params = new URLSearchParams(location.search)
Insert cell
Insert cell
Insert cell
Insert cell
scales = Object.keys(d3Scale)
.filter((x) => x.startsWith("interpolate"))
.map((x) => x.replace("interpolate", ""))
Insert cell
function drawQuilt(
quiltData,
{
palette = "Spectral",
scheme = "Sequence",
center = false,
highlightIndex = -1,
size = 600
} = {}
) {
const maxSize = size;
const n = quiltData.n;
const cellSize = n > maxSize ? 1 : Math.floor(maxSize / n);
const quilt = quiltData.sequences;
const canvas = html`<canvas id="quilt" width="${n * cellSize}" height="${
n * cellSize
}" style="width: 100%; height: 100%"></canvas>`;
const ctx = canvas.getContext("2d", { alpha: false });
ctx.imageSmoothingEnabled = false;
const numSequences = quilt.length;
const offset = Math.floor(n / 2);
const grayscale = culori.filterSaturate(0);
const colors = quilt.map((sequence, index) => {
const [i, j] = sequence;
const scale = d3Scale["interpolate" + palette];
let color;
switch (scheme) {
case "Columns": {
const hue = scale(j / n);
const desaturate = culori.filterSaturate((n - i) / n);
color = scale(index / (numSequences + 1));
// color = chroma(hue).desaturate((n - i) / n - 1);
break;
}
case "Period": {
color = scale(
quiltData.periods().indexOf(sequence.length) /
(quiltData.periods.length - 1)
);
break;
}
case "Unique Nums": {
color = scale(new Set(sequence).size / n);
break;
}
default:
color = scale(index / (numSequences + 1));
}
if (+highlightIndex >= 0 && +highlightIndex !== i) {
let hsl = d3.hsl(color);
hsl.s = 0;
color = d3.color(hsl);
}
return d3.color(color).rgb();
});
const pixels = new Uint8ClampedArray(
4 * quiltData.table.length * cellSize * cellSize
);
for (let k = 0; k < quiltData.table.length; k++) {
let color = colors[quiltData.table[k]];
let i = Math.floor(k / n);
let j = k % n;
for (let ipix = i * cellSize; ipix < (i + 1) * cellSize; ipix++) {
for (let jpix = j * cellSize; jpix < (j + 1) * cellSize; jpix++) {
let kpix = ipix * n * cellSize + jpix;
pixels[4 * kpix] = Math.floor(color.r);
pixels[4 * kpix + 1] = Math.floor(color.g);
pixels[4 * kpix + 2] = Math.floor(color.b);
pixels[4 * kpix + 3] = 255;
}
}
}
const imageData = new ImageData(pixels, n * cellSize, n * cellSize);
ctx.putImageData(imageData, 0, 0);
return html`<div style="width: ${maxSize}px; height: ${maxSize}px;">${canvas}</div>`;
}
Insert cell
{
const canvases = [].map((n) => {
const quilt = pisanoQuilt(n);
return html`<div><p>${n}</p>${drawQuilt(n, quilt)}</div>`;
});
return html`<div style="display: flex; flex-direction: column; gap: 16px; width: 300px;">${canvases}</div>`;
}
Insert cell
pisanoQuilt = _.memoize(function pisanoQuilt(n) {
const table = new Uint32Array(n ** 2);
const sequences = [[0, 0]];
let sequenceIndex = 1;
let next = [0, 1];
while (next) {
let [i, j] = next;
const sequence = [i];
while (table[i * n + j] === 0) {
sequence.push(j);
table[i * n + j] = sequenceIndex;
let k = (i + j) % n;
i = j;
j = k;
}
sequences.push(sequence);
sequenceIndex++;
next = findNext(n, table, next);
}
let periods = _.memoize(() => {
return _.sortBy([...new Set(sequences.map(seq => seq.length))])
})
return { n, sequences, table, periods };
})
Insert cell
function findNext(n, table, prev) {
const [istart, jstart] = prev;
for (let j = jstart + 1; j < n; j++) {
if (table[istart * n + j] === 0) {
return [istart, j];
}
}
for (let i = istart + 1; i < n / 2; i++) {
for (let j = i + 1; j < n; j++) {
if (table[i * n + j] === 0) {
return [i, j];
}
}
}
return null;
}
Insert cell
Insert cell
d3Scale = require("d3-scale-chromatic")
Insert cell
_ = require("lodash")
Insert cell
fib4 = [1, 4, 5, 9, 14, 23, 37, 60, 97, 157, 254, 411, 665, 1076]
Insert cell
fib5 = [1, 5, 6, 11, 17, 28, 45, 73, 118, 191, 309, 500, 809, 1309]
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
d3Color = require("d3-color")
Insert cell
culori = require("culori")
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