Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>3D Word Embeddings Visualization</title> | |
<style> | |
body { margin: 0; } | |
canvas { display: block; } | |
#info { | |
position: absolute; | |
top: 10px; | |
left: 10px; | |
background: rgba(255,255,255,0.8); | |
padding: 10px; | |
border-radius: 4px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="info">Click on a word to see details</div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> | |
<script> | |
let scene, camera, renderer, controls; | |
let raycaster = new THREE.Raycaster(); | |
let mouse = new THREE.Vector2(); | |
let spheres = []; // To keep track of word nodes | |
init(); | |
animate(); | |
function init() { | |
// Create scene and camera | |
scene = new THREE.Scene(); | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); | |
camera.position.z = 100; | |
// Renderer | |
renderer = new THREE.WebGLRenderer({antialias: true}); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
document.body.appendChild(renderer.domElement); | |
// Controls for interactive orbiting | |
controls = new THREE.OrbitControls(camera, renderer.domElement); | |
// Load JSON data with word embeddings | |
fetch('fasttext_3d.json') | |
.then(response => response.json()) | |
.then(data => { | |
// Normalize coordinates (optional, depending on your TSNE results) | |
data.forEach(item => { | |
// Create a sphere for each word | |
let geometry = new THREE.SphereGeometry(1.5, 16, 16); | |
let material = new THREE.MeshBasicMaterial({ color: 0x0077ff }); | |
let sphere = new THREE.Mesh(geometry, material); | |
sphere.position.set(item.x, item.y, item.z); | |
sphere.userData = { word: item.word }; | |
scene.add(sphere); | |
spheres.push(sphere); | |
}); | |
}) | |
.catch(err => console.error(err)); | |
// Add event listener for mouse click | |
window.addEventListener('click', onMouseClick, false); | |
} | |
function onMouseClick(event) { | |
// Calculate mouse position in normalized device coordinates (-1 to +1) | |
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; | |
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; | |
raycaster.setFromCamera(mouse, camera); | |
// Calculate objects intersecting the picking ray | |
let intersects = raycaster.intersectObjects(spheres); | |
if (intersects.length > 0) { | |
let selected = intersects[0].object; | |
let infoDiv = document.getElementById("info"); | |
infoDiv.innerHTML = "Word: " + selected.userData.word + | |
"<br>Position: (" + | |
selected.position.x.toFixed(2) + ", " + | |
selected.position.y.toFixed(2) + ", " + | |
selected.position.z.toFixed(2) + ")"; | |
} | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
controls.update(); | |
renderer.render(scene, camera); | |
} | |
</script> | |
</body> | |
</html> | |