Published
Edited
Apr 14, 2022
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function unitball3d_m1(p) {

// Generate a set of equispaced values from -1 to 1
let range = [...Array(num_steps).keys()].map( i => (i * 2) / (num_steps - 1) - 1 );

// Initialize z with NaNs
let z = [...Array(num_steps * 2)].map( () => Array(num_steps));

// Precompute as much as possible outside of the loop
let abs_pow = range.map(val => Math.abs(val)**p);

// Compute z based on x and y
for (let i = 0; i < num_steps; i++) {
let x_val = abs_pow[i];
for (let j = 0; j < num_steps; j++) {
let y_val = abs_pow[j];
let z_val = 1 - x_val - y_val;
if (z_val >= 0) {
z[i][j] = z_val**(1/p);
z[num_steps * 2 - 1 - i][j] = -z[i][j];
}
}
}

// Generate the (x, y) mesh grid
let x = [...Array(num_steps)].map( () => range );
let y = [...Array(num_steps)].map( () => Array(num_steps) );
range.forEach( (val, i) => y[i].fill(val) );
x = x.concat(Array.from(x).reverse());
y = y.concat(Array.from(y).reverse());

return {x, y, z}
}

Insert cell
Insert cell
Insert cell
Insert cell
function coords_patchwork(p) {

let {x, y, z} = unitball3d_m1(p);

let X = [];
let Y = [];
let Z = [];
// Patch together our X, Y, Z symmetrically to cover the gaps
x.forEach(function(val, i) {
X.push([].concat(x[i], z[i], y[i]));
Y.push([].concat(y[i], x[i], z[i]));
Z.push([].concat(z[i], y[i], x[i]));
});

return {x: X, y: Y, z: Z}
}
Insert cell
Insert cell
Insert cell
Insert cell
theta = [...Array(num_steps).keys()].map(x => (x * Math.PI * 2) / (num_steps - 1) )
Insert cell
phi = [...Array(num_steps).keys()].map(x => (x * Math.PI) / (num_steps - 1) )
Insert cell
sin = ({theta: theta.map(x => Math.sin(x)), phi: phi.map(x => Math.sin(x))});
Insert cell
cos = ({theta: theta.map(x => Math.cos(x)), phi: phi.map(x => Math.cos(x))});
Insert cell
function unitball3d_m2(p) {

let x = [...Array(num_steps)].map( () => Array(num_steps));
let y = [...Array(num_steps)].map( () => Array(num_steps));
let z = [...Array(num_steps)].map( () => Array(num_steps));
// Pull as much math outside of the inner loops as possible
let r3 = cos.theta.map( (val, i) => Math.abs(val)**p + Math.abs(sin.theta[i])**p );

// Create a mesh grid of Cartesian points
for (let i = 0; i < num_steps; i++) {
let r1 = Math.abs(cos.phi[i])**p;
let r2 = sin.phi[i]**p;
for (let j = 0; j < num_steps; j++) {
let r = (r1 + r2 * r3[j])**(-1/p);
x[i][j] = sin.phi[i] * r * cos.theta[j];
y[i][j] = sin.phi[i] * r * sin.theta[j];
z[i][j] = cos.phi[i] * r;
}
}

return {x, y, z};
}
Insert cell
Insert cell
Insert cell
Insert cell
function unitball3d_m3(p) {

// Generate equispaced values from -1 to 1
let range = [...Array(num_steps).keys()].map( i => (i * 2) / (num_steps - 1) - 1 );

let x = [...Array(num_steps)].map( () => Array(num_steps));
let y = [...Array(num_steps)].map( () => Array(num_steps));
let z = [...Array(num_steps)].map( () => Array(num_steps));

// Fill in z-values in a mesh grid pattern
range.forEach( (val, i) => z[i].fill(val) );
// Pull as much math outside of the loop as possible
let r2 = cos.theta.map( (val, i) => Math.abs(val)**p + Math.abs(sin.theta[i])**p );

// Create a mesh grid of Cartesian points
for (let i = 0; i < num_steps; i++) {
let r1 = (1 - Math.abs(range[i])**p);
for (let j = 0; j < num_steps; j++) {

let r = (r1 / r2[j])**(1/p)
x[i][j] = r * cos.theta[j];
y[i][j] = r * sin.theta[j];
}
}

return {x, y, z};
}
Insert cell
Insert cell
Insert cell
Insert cell
function unitball3d(p) {

let x = [...Array(num_steps)].map( () => Array(num_steps));
let y = [...Array(num_steps)].map( () => Array(num_steps));
let z = [...Array(num_steps)].map( () => Array(num_steps));
let r = {phi: Array(num_steps), theta: Array(num_steps)};

// Calculate our rho values
for (let i = 0; i < num_steps; i++) {
r.phi[i] = (Math.abs(sin.phi[i])**p + Math.abs(cos.phi[i])**p)**(-1/p);
r.theta[i] = (Math.abs(sin.theta[i])**p + Math.abs(cos.theta[i])**p)**(-1/p);
}

// Create a mesh grid of Cartesian points
for (let i = 0; i < num_steps; i++) {
for (let j = 0; j < num_steps; j++) {
x[i][j] = sin.phi[i] * r.phi[i] * cos.theta[j] * r.theta[j];
y[i][j] = sin.phi[i] * r.phi[i] * sin.theta[j] * r.theta[j];
z[i][j] = cos.phi[i] * r.phi[i];
}
}

return {x, y, z};
}
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
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