Use numpy arrays for buffers
masternumpy arrays. Because numpy arrays carry shape and dtype information, many pythreejs APIs that accept buffers require fewer explicit configuration options than the original three.js API.repository·master·Indexed 21 days ago
https://github.com/jupyter-widgets/pythreejsA Python/ThreeJS bridge for Jupyter Widgets that allows users to render interactive 3D graphics within Jupyter environments. It provides the ThreeWidget class as a primary entry point for 3D scenes and the RenderableWidget base class for visual components like geometries, materials, and lights. The library also supports custom high-performance rendering via Blackbox objects, which synchronize only necessary parameters between Python and JavaScript.
numpy arrays. Because numpy arrays carry shape and dtype information, many pythreejs APIs that accept buffers require fewer explicit configuration options than the original three.js API.SphereGeometry or BoxBufferGeometry) do not sync their vertex or attribute data to the Python side by default. To access this generated data in Python, you must convert them to a Geometry or BufferGeometry type using the BufferGeometry.from_geometry factory method.A Blackbox is a specialized widget type used to integrate custom, high-performance Three.js objects into a pythreejs scene. It inherits from Object3D on both the Python and JavaScript sides.
Key Characteristics:
pythreejs scene by transforming it, adding it as a child to other objects, or placing it in a Scene.Blackbox, you must implement a corresponding class on both the Python side (inheriting from pythreejs.Blackbox) and the JavaScript side (inheriting from BlackboxModel in jupyter-threejs).import pythreejs
# Python side
class MyCustomObject(pythreejs.Blackbox):
# Add traits here
passThe pythreejs API mimics the three.js API, but differs significantly in how the render loop is handled to avoid excessive communication with the Jupyter kernel.
There are two primary ways to render:
WebGLRenderer to render frames only when you explicitly call its .render() method. This is useful for static scenes or controlled updates.Renderer class to set up a continuous loop. This is required if you want to use interactive_controls or animation views, as it allows the scene to update smoothly in response to user input without kernel round-trips.To install a developer version of pythreejs from source, clone the repository and use pip install -e . to perform an editable installation. This allows changes to the Python code to take effect without re-installing.
git clone https://github.com/jupyter-widgets/pythreejs.git
cd pythreejs
pip install -e .Interactive controls (like OrbitControls for camera movement or Picker for mouse interaction) are managed by passing them as a list to the controls argument of a Renderer instance.
Renderer(controls=[OrbitControls(...), ...], ...)To install the core pythreejs package, use pip. This package provides the Python bindings to three.js via the jupyter-widgets infrastructure.
pip install pythreejsTo remove pythreejs, use your package manager (pip or conda). If you performed manual installation steps for Jupyter Notebook Classic or JupyterLab, you should also disable or uninstall the extensions manually.
# Remove the python package
pip uninstall pythreejs
# OR
conda uninstall pythreejs
# If manually enabled in Jupyter Notebook Classic
jupyter nbextension disable --py --sys-prefix pythreejs
# If manually installed in JupyterLab
jupyter labextension uninstall jupyter-threejsIf the front-end extensions were not automatically enabled (for example, if your notebook server and kernel are in different environments), you can manually install and enable them for Jupyter Notebook Classic using the jupyter nbextension command. You must use the appropriate flag (--sys-prefix, --user, or --system) depending on your environment setup.
jupyter nbextension install [--sys-prefix / --user / --system] --py pythreejs
jupyter nbextension enable [--sys-prefix / --user / --system] --py pythreejsTo create a custom widget that renders complex Three.js objects, follow these implementation steps:
Inherit from pythreejs.Blackbox and define traitlets for any parameters you want to sync. You must include _model_name and _model_module to link the Python class to the JavaScript class.
Inherit from BlackboxModel (from jupyter-threejs). You must implement two critical methods:
constructThreeObject(): Called to create the initial Three.js object. It should return the Three.js object (e.g., a THREE.Group or THREE.Mesh).onChange(model, options): Called whenever synced traits change. Use this to update the Three.js object (e.g., rebuilding geometry or updating positions).This example demonstrates a CubicLattice that tiles a basis structure in 3D space.
### Python
import traitlets
import pythreejs
class CubicLattice(pythreejs.Blackbox):
_model_name = traitlets.Unicode('CubicLatticeModel').tag(sync=True)
_model_module = traitlets.Unicode('my_module_name').tag(sync=True)
basis = traitlets.List(
trait=pythreejs.Vector3(),
default_value=[[0, 0, 0]],
max_length=5
).tag(sync=True)
repetitions = traitlets.List(
trait=traitlets.Int(),
default_value=[5, 5, 5],
min_length=3,
max_length=3
).tag(sync=True)
### JavaScript
import * as THREE from "three";
import { BlackboxModel } from 'jupyter-threejs';
export class CubicLatticeModel extends BlackboxModel {
defaults() {
return {...super.defaults(), ...{
_model_name: 'CubicLatticeModel',
_model_module: 'my_module_name',
basis: [[0, 0, 0]],
repetitions: [5, 5, 5],
}};
}
constructThreeObject() {
const root = new THREE.Group();
this.createLattice(root);
return root;
}
onChange(model, options) {
super.onChange(model, options);
this.createLattice();
}
createLattice(obj) {
obj = obj || this.obj;
// ... logic to build the Three.js object ...
}
}When upgrading from a version prior to 1.0 to version 1.x, note the following backwards-incompatible renames designed to align with Three.js naming conventions:
Plain[Buffer]Geometry is now [Buffer]Geometry. The base classes for geometry are now named Base[Buffer]Geometry. This change avoids confusion with Plane[Buffer]Geometry.LambertMaterial is now MeshLambertMaterial.If you are developing the JavaScript/frontend code for pythreejs and using Jupyter Notebook Classic, you must link the extensions instead of a standard install. Use the --symlink flag with jupyter nbextension install and then enable the extension. Use the appropriate flag (--sys-prefix, --user, or --system) based on your environment configuration.
# Install with symlink
jupyter nbextension install [--sys-prefix / --user / --system] --symlink --py pythreejs
# Enable the extension
jupyter nbextension enable [--sys-prefix / --user / --system] --py pythreejs