Public
Edited
Sep 11, 2023
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function drawLayers(data, { width = 400, strokeWidth = 0.75 } = {}) {
return Plot.plot({
width,
y: { domain: [-1, 1] },
x: {
axis: false,
grid: true
},
facet: {
// marginRight: 0
},
fy: {
padding: 0.125,
label: "Layer",
reverse: true
},
marks: [
Plot.frame({ stroke: "lightgray" }),
Plot.line(data, {
x: "x",
y: "value",
fy: "layer",
strokeWidth
})
]
});
}
Insert cell
function drawMergedLayer(data, { width = 400, strokeWidth = 0.75 } = {}) {
return Plot.plot({
width,
height: width / 2,
y: { domain: [-1, 1] },
x: {
axis: false,
grid: true
},
marks: [
Plot.frame({ stroke: "lightgray" }),
Plot.line(data, {
x: "x",
y: "value",
strokeWidth
})
]
});
}
Insert cell
function isNoisePreview() {
return previewWave === "Noise";
}
Insert cell
layers = {
const scale = 2 ** noiseScale1;
const fn = isNoisePreview() ? noise2DA : Math.sin;
return Array.from({ length: width }).flatMap((_, i) => {
const x = i * scale;

let totalAmplitude = 0;
let frequency = 1;
let amplitude = 1;
const layers = Array.from({ length: octaves1 + 1 }).map((_, l) => {
const value = fn(x * frequency, 0) * amplitude;

totalAmplitude += amplitude;
amplitude *= 0.5; // Halves amplitude in each layers
frequency *= 2; // Doubles the amplitude in each layers
return {
layer: l,
x: i,
value
};
});

return layers.map((obj) => ({ ...obj, totalAmplitude }));
});
}
Insert cell
layersMerged = d3
.groups(layers, (d) => d.x)
.map(([_, layers]) => {
const { totalAmplitude } = layers[0];
const value = sumBy(layers, (d) => d.value) / totalAmplitude;
return {
...layers[0],
value
};
})
Insert cell
noise2DA = {
const prng = alea(randomize1);
return simplex.createNoise2D(prng);
}
Insert cell
Insert cell
scale = 2 ** noiseScale
Insert cell
function drawNoise(
context,
{ octaves = 1, width, height, scale = 2 ** -5 } = {}
) {
const aspectRatio = height / width;

const image = context.createImageData(width * dpr, height * dpr);

const imageDataWidth = width * dpr * 4;
for (let i = 0; i < image.data.length; i += 4) {
const x = (i % imageDataWidth) / 4;
const y = Math.floor(i / imageDataWidth / 2);

const xScale = scale;
const yScale = scale / aspectRatio;
const noiseFn = octave(noise2DB, octaves + 1);
const noise = noiseFn(x * xScale, y * yScale);
const u = 0.5 + noise * 0.5;
const v = Math.trunc(math.lerp(0, 255, u));

image.data[i + 0] = v; // R
image.data[i + 1] = v; // G
image.data[i + 2] = v; // B
image.data[i + 3] = 255; // Alpha
}

context.putImageData(image, 0, 0);
}
Insert cell
// Based on Mike Bostock's https://observablehq.com/@mbostock/perlin-noise#octave
function octave(noiseFn, octaves) {
return function (x, y) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let value = 0;

for (let i = 0; i < octaves; ++i) {
value += noiseFn(x * frequency, y * frequency) * amplitude;

total += amplitude;
amplitude *= 0.5;
frequency *= 2;
}

return value / total;
};
}
Insert cell
dpr = window.devicePixelRatio
Insert cell
aspectRatio = 9 / 16
Insert cell
height = Math.floor(width * aspectRatio)
Insert cell
noise2DB = {
const prng = alea(randomize);
return simplex.createNoise2D(prng);
}
Insert cell
Insert cell
// Source: https://youmightnotneed.com/lodash/#sumBy
sumBy = (arr, func) => arr.reduce((acc, item) => acc + func(item), 0)
Insert cell
Insert cell
<style>
.grid {
display: grid;
grid-template-columns: 8fr 1fr 8fr;
align-items: center;
}
.symbol {
font-size: 4rem;
font-weight: bold;
color: var(--lt-color-gray-500, #999);
}
</style>
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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