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

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