Py.Cafe

kolibril13/

tutorial_juneE

Interactive 3D Voxel Visualization

DocsPricing
  • app.py
  • requirements.txt
  • widget.css
  • widget.js
widget.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import * as THREE from "https://esm.sh/three";
import { OrbitControls } from "https://esm.sh/three/examples/jsm/controls/OrbitControls.js";

function render({ model, el }) {

  let container = document.createElement("div");
  container.style.height = "800px";
  container.style.width = "800px";
  el.appendChild(container);

  const scene = new THREE.Scene();
  scene.background = new THREE.Color("white");
  const camera = new THREE.PerspectiveCamera(
    75,
    container.clientWidth / container.clientHeight,
    0.1,
    1000
  );
  camera.position.z = 20;



  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(container.clientWidth, container.clientHeight);
  container.appendChild(renderer.domElement);

  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.screenSpacePanning = false;
  controls.minDistance = 5;
  controls.maxDistance = 50;


  const data = model.get("voxel_data");
  drawVoxels(data);


  animate();
  

  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }

  function getColor(value) {
    const minColor = new THREE.Color("yellow");
    const maxColor = new THREE.Color("blue");
    const color = minColor.lerp(maxColor, value / 255);
    const opacity = value / 255; // Fixed opacity based on voxel value
    return { color, opacity };
  }

  function drawVoxels(data) {
    const offsetX = data.length / 2;
    const offsetY = data[0].length / 2;
    const offsetZ = data[0][0].length / 2;
    const geometry = new THREE.BoxGeometry();

    for (let x = 0; x < data.length; x++) {
      for (let y = 0; y < data[x].length; y++) {
        for (let z = 0; z < data[x][y].length; z++) {
          if (data[x][y][z] > 0) {
            const { color, opacity } = getColor(data[x][y][z]);
            const material = new THREE.MeshBasicMaterial({ color, transparent: true, opacity });
            const cube = new THREE.Mesh(geometry, material);
            cube.position.set(x - offsetX, y - offsetY, z - offsetZ);
            scene.add(cube);
          }
        }
      }
    }
  }

}

export default { render };
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import anywidget
from traitlets import  List
from pathlib import Path
import numpy as np

size = 17


def f(i,j,k):
    return (1+np.cos(i*j*0.1))*0.5

voxelarray = np.fromfunction(f, (size, size, size))

# voxelarray = np.random.rand(size, size, size)

voxelarray_int = np.uint8(voxelarray * 255)

class HelloWidget(anywidget.AnyWidget):
    _esm = Path("widget.js")
    voxel_data = List().tag(sync=True)


voxel_data_list = voxelarray_int.tolist()

three_viewer = HelloWidget()

three_viewer.voxel_data = voxel_data_list
page = three_viewer