Public
Edited
Oct 29, 2023
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
canvasElement = html`<canvas id="scatterplot" width="600" height="300" style="background-color: #002036;"></canvas>`
Insert cell
Insert cell
Insert cell
THREE = import("three@0.158.0")
Insert cell
Insert cell
canvas = canvasElement
Insert cell
renderer = {
const renderer = new THREE.WebGLRenderer({ canvas: canvas })
renderer.setClearColor(0x002036, 1) // set background color
return renderer
}
Insert cell
Insert cell
scene = new THREE.Scene()
Insert cell
camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 1, 10) // left, right, top, bottom, near, far
Insert cell
camera.position.z = 1
Insert cell
Insert cell
numberOfPoints = 100
Insert cell
// // optional: make dynamic attributes
// viewof numberOfPoints = Inputs.range([100, 10000], {label: "number of points", step: 10, value: 100})
Insert cell
sizeOfPoints = 10
Insert cell
pointColor = 0xffffff
Insert cell
Insert cell
material = new THREE.PointsMaterial({ size: sizeOfPoints, color: pointColor })
Insert cell
// // OPTIONAL: custom shader to clip square points into circle points
// material = new THREE.ShaderMaterial({
// uniforms: {
// pointSize: { value: sizeOfPoints },
// color: { value: new THREE.Color(pointColor) },
// },
// vertexShader: `
// uniform float pointSize;
// void main() {
// gl_PointSize = pointSize;
// gl_Position = vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform vec3 color;
// void main() {
// vec2 coord = gl_PointCoord - vec2(0.5);
// if (length(coord) > 0.5) {
// discard;
// }
// gl_FragColor = vec4(color, 1.0);
// }
// `
// })
Insert cell
points = {
// clear any existing points before drawing new ones
if (scene.children.length > 0) {
scene.remove(scene.children[0])
}

// create array of point coordinates
const numPoints = numberOfPoints
const vertices = []
for (let i = 0; i < numPoints; i++) {
vertices.push(Math.random() * 2 - 1) // x
vertices.push(Math.random() * 2 - 1) // y
vertices.push(0) // z (not used for 2D)
}

// prepare the geometry
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))

// set geometry and material of the points
const points = new THREE.Points(geometry, material)
return points
}
Insert cell
Insert cell
scene.add(points)
Insert cell
Insert cell
renderer.render(scene, camera)
Insert cell
// starts animation loop
renderLoop = {
function update() {
renderer.render(scene, camera)

requestAnimationFrame(update)
}

update()

// doesn't return anything, just starts the loop
return
}
Insert cell
// If you want to run from a .html file

// <!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8">
// <meta name="viewport" content="width=device-width, initial-scale=1.0">

// <title>WebGL (+ Threejs) Scatterplot</title>

// <script src="https://threejs.org/build/three.js"></script>
// </head>
// <body>
// <!-- Create the HTML canvas element -->
// <canvas id="scatterplot" width="600" height="300"></canvas>

// <script>
// // Grab the canvas
// const canvas = document.getElementById('scatterplot')

// // Apply the 'webgl' context via Threejs (as opposed to '2d')
// const renderer = new THREE.WebGLRenderer({ canvas: canvas })
// renderer.setClearColor(0x002036, 1) // set background color

// const scene = new THREE.Scene();
// const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 1, 10) // left, right, top, bottom, near, far
// camera.position.z = 1

// // Define the visualization's attributes
// const numberOfPoints = 100
// const sizeOfPoints = 10
// const pointColor = 0xffffff

// // Use a for loop to draw all the points
// const vertices = []
// for (let i = 0; i < numberOfPoints; i++) {
// vertices.push(Math.random() * 2 - 1) // x
// vertices.push(Math.random() * 2 - 1) // y
// vertices.push(0) // z (not used for 2D)
// }

// // Prepare the geometry and material
// const geometry = new THREE.BufferGeometry()
// geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))

// const material = new THREE.PointsMaterial({ size: sizeOfPoints, color: pointColor })
// // Optional custom shader to clip square into circle
// // const material = new THREE.ShaderMaterial({
// // uniforms: {
// // pointSize: { value: sizeOfPoints },
// // color: { value: new THREE.Color(pointColor) },
// // },
// // vertexShader: `
// // uniform float pointSize;
// // void main() {
// // gl_PointSize = pointSize;
// // gl_Position = vec4(position, 1.0);
// // }
// // `,
// // fragmentShader: `
// // uniform vec3 color;
// // void main() {
// // vec2 coord = gl_PointCoord - vec2(0.5);
// // if (length(coord) > 0.5) {
// // discard;
// // }
// // gl_FragColor = vec4(color, 1.0);
// // }
// // `
// // })

// const points = new THREE.Points(geometry, material)
// scene.add(points)

// renderer.render(scene, camera)
// </script>
// </body>
// </html>

// <!--
// Notes:
// - Coordinates are (0, 0) at the center of the canvas and are normalized between -1 and 1 top and bottom, left to right
// -->
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