pythreejs

repository·master·Indexed 21 days ago

https://github.com/jupyter-widgets/pythreejs

A 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.

Tokens
22.8K
Snippets
79
Records
83
Agent score
73%

What's inside pythreejs

  1. Access geometry data from generative objects

    master
    Generative geometry objects (such as 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.
  2. How Blackbox objects work for custom rendering

    master

    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:

    • Efficiency: The actual Three.js object is not synchronized across the wire. Only the parameters (traits) needed to configure it are synced. This makes it ideal for complex or procedurally generated objects (e.g., thousands of spheres) where sending the raw geometry data would be too expensive.
    • Integration: Even though the internal Three.js object is a "black box," you can still manipulate it within a pythreejs scene by transforming it, adding it as a child to other objects, or placing it in a Scene.
    • Implementation Requirement: To use a 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
        pass
  3. Understand the pythreejs rendering model

    master

    The 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:

    1. On-demand rendering: Use WebGLRenderer to render frames only when you explicitly call its .render() method. This is useful for static scenes or controlled updates.
    2. Interactive render loop: Use the 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.
  4. Uninstall pythreejs

    master

    To 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-threejs
  5. Manually install front-end extensions for Jupyter Notebook Classic

    master

    If 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 pythreejs
  6. Implement a custom Blackbox widget

    master

    To create a custom widget that renders complex Three.js objects, follow these implementation steps:

    1. Python Implementation

    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.

    2. JavaScript Implementation

    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).

    Example Implementation

    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 ...
        }
    }
  7. Migrate to pythreejs 1.x (Breaking Changes)

    master

    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:

    • Geometry Renames: 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.
    • Material Renames: Material classes have been renamed to match Three.js. For example, LambertMaterial is now MeshLambertMaterial.
  8. Link JS extensions for Jupyter Notebook Classic development

    master

    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