Public
Edited
May 9, 2023
1 fork
13 stars
A Julia set on the Riemann sphereThe Z-CurveBarnsley's fernA stochastic digraph IFS algorithmSelf-affine tilesThe TwindragonThe Eisenstein fractionsA self-affine tile with holesSelf-affine tiles via polygon mergeGolden rectangle fractalsBifurcation diagram with critical curvesThe tame twindragonIllustrations for the proof of Green's theoremNon-orientability of a Mobius stripExamples of parametric surfacesPenrose tilingThe extended unit circlePenrose three coloringNewtons's method on the Riemann sphere
Conic sections
Divisor graphsThe dance of Earth and VenusIterating multiples of the sine functionBorderline fractalsSelf-similar intersectionsBox-counting dimension examplesMandelbrot by dimensionInverse iteration for quadratic Julia setsInteger Apollonian PackingsIllustrations of two-dimensonal heat flowThe logistic bifurcation locusThe eleven unfoldings of the cubeA unimodal function with fractal level curvesGreen's theorem and polygonal areaThe geometry and numerics of first order ODEsThe xxx^xxx-spindleAnimated beatsRauzy FractalsHilbert's coordinate functionsPluckNot PiDrum strikeThe Koch snowflakeFractalized squareA Taylor series about π/4\pi/4π/4PlotX3D HyperboloidA PlotX3D animationModular arithmetic in 5th grade artSimple S-I-R ModelThe Poisson KernelPoly-gasketsClassification of 2D linear systems via trace and determinantJulia sets and the Mandelbrot setWater wavesFourier SeriesDisks for a solid of revolutionOrbit detection for the Mandelbrot setTracing a path on a spherePlot for mathematiciansFunctions of two variablesPartial derivativesDijkstra's algorithm on an RGGGradient ascentUnfolding polyhedraTangent plane to a level surfaceA strange discontinuityExamples of level surfacesMcMullen carpetsHills and valleysThe definition of ⇒Double and iterated integralsMST in an RGGTrees are bipartiteFractal typesettingd3.hierarchy and d3.treeK23 is PlanarPolar CoordinatesParametric region generatorParametric Plot 2DContour plotsGreedy graph coloringGraph6A few hundred interesting graphsThe Kings ProblemFirst order, autonomous systems of ODEsRunge-Kutta for systems of ODEs
Also listed in…
X3Dom
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function* setup() {
// Basic setup
let this_width = 0.8 * width;
let height = 0.7 * d3.min([this_width, window.screen.height]);
let container = d3
.create('div')
.style('width', this_width.toString() + 'px')
.style('height', height.toString() + 'px');

let scene = container
.append('x3d')
.attr('width', this_width.toString() + 'px')
.attr('height', height.toString() + 'px')
.append('scene');
scene
.append('viewpoint')
.attr('position', '11.08014 -3.40616 4.08709')
.attr('orientation', '0.61973 0.43866 0.65078 1.70872');

// Add the cone
let coneTransform = scene
.append('transform')
.attr('rotation', `1 0 0 ${Math.PI / 2}`);
let transform1 = coneTransform
.append('transform')
.attr('translation', '0 -1.5 0');
let shape = transform1.append('shape');
shape
.append('appearance')
.append('material')
.attr('diffuseColor', `0.2 0.2 0.8`)
.attr('specularColor', '0.2 0.2 0.2');
shape
.append('cone')
.attr('subdivision', '128')
.attr('height', 3)
.attr('bottomRadius', 3)
.attr('bottom', 'false')
.attr('solid', 'false');
let transform2 = coneTransform
.append('transform')
.attr('translation', '0 1.5 0')
.attr('rotation', `0 0 1 ${Math.PI}`);
shape = transform2.append('shape');
shape
.append('appearance')
.append('material')
.attr('diffuseColor', `0.2 0.2 0.8`)
.attr('specularColor', '0.2 0.2 0.2');
shape
.append('cone')
.attr('subdivision', '128')
.attr('height', 3)
.attr('bottomRadius', 3)
.attr('bottom', 'false')
.attr('solid', 'false');

// Add the plane
let translation = scene
.append('transform')
.attr('id', 'plane_translation')
.attr('translation', '0 0 -1');
let plane_rotation = translation
.append('transform')
.attr('id', 'plane_rotation')
.attr('rotation', `1 0 0 ${Math.PI / 6}`);
let planeShape = plane_rotation.append('shape').attr('id', 'plane');
planeShape
.append('appearance')
.append('material')
.attr('transparency', '0.25')
.attr('diffuseColor', `0.8 0.8 0.2`)
.attr('specularColor', '0.2 0.2 0.2');
planeShape
.append('plane')
.attr('solid', 'false')
.attr('size', '8 8');

// Add all the sections as curves on the cone.
// Initial transparency will be set to 1; curve
// will only be shown once selected.
let sections = scene.append('group').attr('id', 'sections');

// Add the point
let point = sections.append('group').attr('id', 'point');
shape = point.append('shape');
shape
.append('appearance')
.append('material')
.attr('transparency', 1)
.attr('diffuseColor', '0 0 0');
shape.append('sphere').attr('radius', '0.05');

// Add the circle
let circle_points = d3.range(-1, 102).map(function(t) {
return [
2 * Math.cos((2 * Math.PI * t) / 100),
2 * Math.sin((2 * Math.PI * t) / 100),
-2
];
});
sections.append(() =>
create_tube(circle_points, 0.02, {
cross_vector: [0, 0, 1],
m: 6,
diffuseColor: '0 0 0',
transparency: '1',
id: 'circle'
})
);

// Add the ellipse
let ellipse_points = d3.range(-1, 102).map(function(t) {
let tt = (2 * Math.PI * t) / 100;
let sqrt3 = Math.sqrt(3);
let cost = Math.cos(tt);
return [
Math.sqrt(1.5) * Math.sin(tt),
-(sqrt3 + 3 * cost) / 2,
-(3 + sqrt3 * cost) / 2
];
});
sections.append(() =>
create_tube(ellipse_points, 0.02, {
cross_vector: [0, -Math.sqrt(3) / 2, 1 / 2],
m: 12,
diffuseColor: '0 0 0',
transparency: '1',
id: 'ellipse'
})
);

// Add the parabola
let parabola_points = d3.range(-21, 22).map(function(x) {
let xx = (Math.sqrt(5) * x) / 20;
return [xx, (1 - xx ** 2) / 2, (-1 - xx ** 2) / 2];
});
sections.append(() =>
create_tube(parabola_points, 0.02, {
cross_vector: [0, -1, 1],
m: 12,
diffuseColor: '0 0 0',
transparency: '1',
id: 'parabola'
})
);

// Add the hyperbola in two parts
let hyperbola = sections.append('group').attr('id', 'hyperbola');

let xwidth = 20 * Math.acosh(3);
let dx = xwidth / 40;

let hyperbola_points1 = d3
.range(-xwidth - dx, xwidth + 2 * dx, dx)
.map(function(t) {
let tt = t / 20;
return [-Math.sinh(tt), 1, Math.cosh(tt)];
});
hyperbola.append(() =>
create_tube(hyperbola_points1, 0.02, {
cross_vector: [0, 1, 0],
m: 12,
diffuseColor: '0 0 0',
transparency: '1',
id: 'hyperbola_points1'
})
);
let hyperbola_points2 = hyperbola_points1.map(([x, y, z]) => [x, y, -z]);
hyperbola.append(() =>
create_tube(hyperbola_points2, 0.02, {
cross_vector: [0, 1, 0],
m: 12,
diffuseColor: '0 0 0',
transparency: '1',
id: 'hyperbola_points2'
})
);

// Add the single line
let single_line_transform = sections
.append('transform')
.attr('id', 'line')
.attr('rotation', `1 0 0 ${Math.PI / 4}`);
shape = single_line_transform.append('shape');
shape
.append('appearance')
.append('material')
.attr('transparency', 1)
.attr('diffuseColor', '0 0 0');
shape
.append('cylinder')
.attr('height', `${Math.sqrt(2) * 6}`)
.attr('radius', '0.02');

// Add the intersecting lines in two parts
let lines = sections.append('group').attr('id', 'lines');
let line1_transform = lines
.append('transform')
.attr(
'rotation',
`0 ${-Math.sqrt(3) / 2} 0.5 ${Math.acos(Math.sqrt(2 / 3))}`
)
.append('transform')
.attr('rotation', `1 0 0 ${Math.PI / 3}`);
shape = line1_transform.append('shape');
shape
.append('appearance')
.append('material')
.attr('transparency', 1)
.attr('diffuseColor', '0 0 0');
shape
.append('cylinder')
.attr('height', `${Math.sqrt(2) * 6}`)
.attr('radius', '0.02');
let line2_transform = lines
.append('transform')
.attr(
'rotation',
`0 ${-Math.sqrt(3) / 2} 0.5 ${-Math.acos(Math.sqrt(2 / 3))}`
)
.append('transform')
.attr('rotation', `1 0 0 ${Math.PI / 3}`);
shape = line2_transform.append('shape');
shape
.append('appearance')
.append('material')
.attr('transparency', 1)
.attr('diffuseColor', '0 0 0');
shape
.append('cylinder')
.attr('height', `${Math.sqrt(2) * 6}`)
.attr('radius', '0.02');

// Yield and reload
yield container.node();
x3dom.reload();
}
Insert cell
Insert cell
// Use the slider value to set the plane transparency
transparency = {
d3.select(x3d)
.select('#plane')
.select('material')
.attr('transparency', `${plane_transparency}`);
}
Insert cell
// Use the radio button to set the section
select = {
// Dim whatever section is currently shown
d3.select(x3d)
.select("#sections")
.selectAll("material")
.transition()
.duration("150")
.attr("transparency", 1);

// Get the transforms of the plane with their current values
let translation_node = d3.select(x3d).select("#plane_translation");
let rotation_node = d3.select(x3d).select("#plane_rotation");
let current_translation = translation_node.attr("translation");
let current_rotation = rotation_node.attr("rotation");

// Set up the values for the new transform base on which
// radio button is pushed.
let new_translation, new_rotation;
if (section == "point") {
new_translation = "0 0 0";
new_rotation = "1 0 0 0";
} else if (section == "circle") {
new_translation = "0 0 -2";
new_rotation = "1 0 0 0";
} else if (section == "ellipse") {
new_translation = "0 0 -1";
new_rotation = `1 0 0 ${Math.PI / 6}`;
} else if (section == "hyperbola") {
new_translation = "0 1 0";
new_rotation = `1 0 0 ${Math.PI / 2}`;
} else if (section == "parabola") {
new_translation = "0 0 -1";
new_rotation = `1 0 0 ${Math.PI / 4}`;
} else if (section == "lines") {
new_translation = "0 0 0";
new_rotation = `1 0 0 ${Math.PI / 3}`;
} else if (section == "line") {
new_translation = "0 0 0";
new_rotation = `1 0 0 ${Math.PI / 4}`;
}

// Interpolate from the current transform to the new
let i = 0;
let translation_interpolator = d3.interpolate(
current_translation,
new_translation
);
let rotation_interpolator = d3.interpolate(current_rotation, new_rotation);
while (i < 20) {
yield Promises.delay(5).then(function () {
i++;
translation_node.attr("translation", translation_interpolator(i / 20));
rotation_node.attr("rotation", rotation_interpolator(i / 20));
});
}

// Reveal the new intersection
d3.select(x3d)
.select("#" + section)
.selectAll("material")
.attr("transparency", "1")
.transition()
.duration(150)
.attr("transparency", "0");
}
Insert cell
Insert cell
function make_axes() {
let axis_group = d3.create('group');
let yaxis_transform = axis_group
.append('transform')
.attr('translation', '0 0 0')
.attr('DEF', 'axis');
let yaxis_shape = yaxis_transform.append('shape');
yaxis_shape
.append('appearance')
.append('material')
.attr('diffuseColor', '0 0 0 0.5')
.attr('transparency', 0.2);
yaxis_shape
.append('cylinder')
.attr('radius', 0.01)
.attr('subdivision', '32')
.attr('height', '8');

let xaxis_transform = axis_group
.append('transform')
.attr('rotation', '0,0,1,1.570796')
.attr('translation', '-2,0,0')
.attr('scale', '1 1.8 1')
.append('transform')
.attr('USE', 'axis');

let zaxis_transform = axis_group
.append('transform')
.attr('rotation', '1,0,0,1.570796')
.attr('scale', '1 1.3 1')
.append('transform')
.attr('USE', 'axis');

return axis_group;
}
Insert cell
function create_indexedLineSet(pts) {
let shape = d3.create('shape');
let appearance = shape.append('appearance');
let material = appearance.append('material');
let indexedLineSet = shape
.append('IndexedLineSet')
.attr('coordIndex', d3.range(pts.length).toString());
indexedLineSet
.append('coordinate')
.attr('point', String.concat(pts).replace(/,/g, ' '));
return shape;
}
Insert cell
Insert cell
d3 = require("d3")
Insert cell
x3dom = require('x3dom').catch(() => window['x3dom'])
Insert cell
import { radio, slider } from "@jashkenas/inputs"
Insert cell
import { create_tube } from "@mcmcclur/space-curves-and-tubes"
Insert cell
// Supress the annoying dashed box that appears around X3Dom display.
html`<style>
canvas {
outline: none;
}
</style>`
Insert cell
d3.select(x3d).select("X3D").node().outerHTML
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