Public
Edited
Nov 13, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
<div id='statsMonitorDiv'>${statsMonitor.dom}</div>
<div id='canvasDiv'>
${canvasStuff.canvas}
</div>
Insert cell
canvasStuff = {
refreshBtn;

const canvas = DOM.canvas(width, height),
ctx = canvas.getContext("2d"),
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

return { canvas, ctx, imageData };
}
Insert cell
gradientSteps = (initX = 0.6, initY = 0.4, t = 0.5) => {
const { ctx } = canvasStuff,
trace = [],
traceNewton = [],
scaleX = d3.scaleLinear().domain([0, 1]).range([0, width]),
scaleY = d3.scaleLinear().domain([0, 1]).range([0, height]);

{
var x = initX, //d3.randomUniform()(),
y = initY, //d3.randomUniform()();
dx,
dy,
n = 100;

trace.push(Object.assign({}, { r: 0, i: 0, x, y }));

for (let i = 1; i < n + 1; ++i) {
dx = dfdx(x, y, t) * unitX;
dy = dfdy(x, y, t) * unitX;
x -= dx;
y -= dy;
trace.push(Object.assign({}, { r: i / n, i, x, y }));
}
}

{
var x = initX, //d3.randomUniform()(),
y = initY, //d3.randomUniform()();
dx,
dy,
d2xx,
d2xy,
d2yx,
d2yy,
grad,
hessian,
svd,
hessianInv,
dxdy,
n = 20;

traceNewton.push(Object.assign({}, { r: 0, i: 0, x, y }));

for (let i = 1; i < n; ++i) {
d2xx = d2fdxdx(x, y, t);
d2xy = d2fdxdy(x, y, t);
d2yx = d2fdydx(x, y, t);
d2yy = d2fdydy(x, y, t);
dx = dfdx(x, y, t);
dy = dfdy(x, y, t);

grad = new ML.Matrix([[dx], [dy]]);
hessian = new ML.Matrix([
[d2xx, d2xy],
[d2yx, d2yy]
]);
svd = new ML.SVD(hessian);
if (svd.s[0] > 0 && svd.s[1] > 0) {
hessianInv = ML.inverse(hessian);
dxdy = hessianInv.mmul(grad).data.map((d) => d[0]);
x -= dxdy[0];
y -= dxdy[1];
}
traceNewton.push(Object.assign({}, { r: i / n, i, x, y }));
}
}

// const drawPnt = ({ r, i, x, y }) => {
// ctx.beginPath();
// ctx.rect(scaleX(x), scaleY(y), 3, 3);
// ctx.fillStyle = d3.interpolateWarm(r); //"white";
// ctx.fill();
// };
// trace.map((d) => drawPnt(d));

if (checkboxes.includes("Grad")) {
for (let i = 1; i < trace.length; ++i) {
const { x: x1, y: y1, r } = trace[i - 1],
{ x: x2, y: y2 } = trace[i];

ctx.beginPath();
ctx.moveTo(scaleX(x1), scaleY(y1));
ctx.lineTo(scaleX(x2), scaleY(y2));
ctx.strokeStyle = d3.interpolateWarm(r);
ctx.lineWidth = 2;
ctx.stroke();

if (i === 1 || i === trace.length - 1) {
ctx.beginPath();
ctx.rect(scaleX(x1) - 10, scaleY(y1) - 10, 20, 20);
ctx.strokeStyle = "gray";
ctx.lineWidth = 1;
ctx.stroke();
}
}
}

if (checkboxes.includes("Hessian")) {
for (let i = 1; i < traceNewton.length; ++i) {
const { x: x1, y: y1, r } = traceNewton[i - 1],
{ x: x2, y: y2 } = traceNewton[i];

ctx.beginPath();
ctx.moveTo(scaleX(x1), scaleY(y1));
ctx.lineTo(scaleX(x2), scaleY(y2));
ctx.strokeStyle = d3.interpolateGreys(r);
ctx.lineWidth = 2;
ctx.stroke();

if (i === 1 || i === traceNewton.length - 1) {
ctx.beginPath();

if (i === 1) ctx.rect(scaleX(x1) - 5, scaleY(y1) - 5, 10, 10);
else ctx.rect(scaleX(x2) - 5, scaleY(y2) - 5, 10, 10);

ctx.strokeStyle = "white";
ctx.lineWidth = 2;
ctx.stroke();
}
}
}
}
Insert cell
d3.interpolateWarm(0)
Insert cell
{
refreshBtn;

const { canvas, ctx, imageData, tStep } = canvasStuff,
{ width, height } = canvas,
{ data } = imageData;

var x,
y,
v,
r,
g = 10,
b;

function drawPlasma(secs = 0.5) {
const t = (secs / 5) * timeScaler;

for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
x = i / width;
y = j / height;

v = getPixel(x, y, t); // * 0.5 + 0.5;

if (v > 0) {
r = v * 200;
b = 0;
} else {
r = 0;
b = -v * 200;
}

data[(i + j * width) * 4 + 0] = r;
data[(i + j * width) * 4 + 1] = g;
data[(i + j * width) * 4 + 2] = b;
data[(i + j * width) * 4 + 3] = 255;
}
}

ctx.putImageData(imageData, 0, 0);

gradientSteps(0.4, 0.6, t);
gradientSteps(0.5, 0.6, t);
gradientSteps(0.4, 0.5, t);
gradientSteps(0.5, 0.5, t);

statsMonitor.update();

return t;
}

var secs = performance.now() / 1000;

drawPlasma(secs);

while (toggle) {
secs = performance.now() / 1000;
yield drawPlasma(secs);
// yield secs;
}
}
Insert cell
dif = 1/10000
Insert cell
dfdx = (x, y, t) => {
const dx = dif,
df = getPixel(x + dx, y, t) - getPixel(x, y, t);

return df / dx;
}
Insert cell
dfdy = (x, y, t) => {
const dy = dif,
df = getPixel(x, y + dy, t) - getPixel(x, y, t);

return df / dy;
}
Insert cell
d2fdxdx = (x, y, t) => {
const dx =dif,
d = dfdx(x + dx, y, t) - dfdx(x, y, t);

return d / dx;
}
Insert cell
d2fdydx = (x, y, t) => {
const dx = dif,
d = dfdy(x + dx, y, t) - dfdy(x, y, t);

return d / dx;
}
Insert cell
d2fdxdy = (x, y, t) => {
const dy = dif,
d = dfdx(x, y + dy, t) - dfdx(x, y, t);

return d / dy;
}
Insert cell
d2fdydy = (x, y, t) => {
const dy = dif,
d = dfdy(x, y + dy, t) - dfdy(x, y, t);

return d / dy;
}
Insert cell
unitX = 1 / width
Insert cell
unitY = 1 / height
Insert cell
getPixel = (x, y, t) => {
return noiseGen.noise3D(x * spatialZoom, y * spatialZoom, t);
}
Insert cell
noiseGen = {
const noiseGen = new simplexNoise(d3.randomUniform()());
return noiseGen;
}
Insert cell
width = 600
Insert cell
height = 400
Insert cell
statsMonitor = {
const stats = new Stats(),
{ dom } = stats;
dom.style.position = "relative";

return stats;
}
Insert cell
Stats = await require("https://cdn.jsdelivr.net/npm/stats-js@1.0.1/build/stats.min.js")
Insert cell
simplexNoise = require("simplex-noise@2.4.0")
Insert cell
ML = require("https://cdn.jsdelivr.net/npm/ml-matrix@6.10.5/matrix.umd.min.js")
Insert cell
new ML.SVD(mat)
Insert cell
mat = new ML.Matrix([
[1, 0],
[0, 2]
])
Insert cell
grad = new ML.Matrix([[1], [2]])
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