Public
Edited
May 3
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 - 1))])
})
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
d3Color = require("d3-color")
Insert cell
culori = require("culori")
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