VPython

repository·master·Indexed 41 days ago

https://github.com/vpython/vpython-jupyter

VPython enables real-time 3D animations in a browser using the GlowScript VPython API. It integrates with Jupyter notebooks and JupyterLab via the jupyterlab_vpython extension (version 3.1.6), allowing 3D scenes to render directly within cells. The library provides tools for creating 3D primitives, managing camera controls, and integrating with ipywidgets for interactive UI elements.

Tokens
18.8K
Snippets
75
Records
85
Agent score
47%

What's inside VPython

  1. Rerunning VPython in Jupyter notebooks

    master

    By default, to re-run a VPython program in a Jupyter notebook, you must restart the kernel (circular arrow icon), click the red-highlighted button, click the first cell, and then click the run icon.

    Tip: To avoid restarting the kernel every time you rerun a program, insert scene = canvas() at the start of your code. This allows for seamless reruns.

    from vpython import *
    scene = canvas()  # Allows rerunning without restarting the kernel
    sphere()
  2. Develop jupyterlab_vpython from source

    master

    To develop the extension locally, follow these steps to set up a dedicated Conda environment and build the extension from the cloned repository.

    1. Environment Setup

    Create and activate a Conda environment with the necessary dependencies:

    conda create -n jupyterlab-ext --override-channels --strict-channel-priority -c conda-forge -c nodefaults jupyterlab=4 nodejs=18 git copier=7 jinja2-time
    conda activate jupyterlab-ext

    2. Clone and Prepare Repository

    Clone the repository and navigate to the directory:

    git clone https://github.com/jcoady/jupyterlab_vpython.git
    cd jupyterlab_vpython

    3. Install Dependencies and Build

    Use jlpm to install required JupyterLab and Lumino packages, copy the necessary VPython library/data files, and run the build process:

    jlpm install
    jlpm add @jupyterlab/application
    jlpm add @jupyterlab/apputils
    jlpm add @jupyterlab/coreutils
    jlpm add @jupyterlab/docregistry
    jlpm add @jupyterlab/notebook
    jlpm add @lumino/disposable
    jlpm add file-loader
    jlpm add plotly.js-dist-min
    jlpm add script-loader
    
    # Copy VPython libraries and data from the parent directory
    cp -r ../../vpython/vpython_{libraries,data} .
    
    jlpm run build

    4. Install and Run

    Install the extension in editable mode and launch JupyterLab:

    pip install -ve .
    
    # In a new terminal:
    conda activate jupyterlab-ext
    jupyter lab
  3. Install VPython

    master

    You can install VPython using either conda or pip depending on your Python distribution.

    • Anaconda distribution: Use conda install -c vpython vpython.
    • Other distributions: Use pip install vpython.

    For more detailed instructions, visit vpython.org.

    # For Anaconda users
    conda install -c vpython vpython
    
    # For other distributions
    pip install vpython
  4. Install VPython from source

    master

    To install VPython from the package source:

    1. Install Cython: It is recommended to install Cython so that the fast version of the vector class can be compiled. Use conda install cython or pip install cython.
    2. Install a Compiler: You may need command line tools (Mac) or Visual Studio Community Edition (Windows) for optimal performance. Without a compiler, VPython will still work, but vector-heavy code may be slower.
    3. Run Installation: From the source directory, run:
      pip install -e .
      The -e flag installs the code with symbolic links, so changes you make to the source are reflected immediately without needing to reinstall.

    If you require the JupyterLab extension, refer to the instructions in the labextension folder.

    pip install -e .
  5. Package the jupyterlab_vpython extension

    master

    To create distributable packages for the extension, first install the build tool, then use the build module to generate source or wheel packages.

    Install build tool

    pip install build

    Generate packages

    • Python source package (.tar.gz): Creates a source distribution in the dist/ directory.
    • Python wheel package (.whl): Creates a built distribution in the dist/ directory.
    # Create a Python source package (.tar.gz)
    python -m build -s
    
    # Create a Python wheel package (.whl)
    python -m build
  6. Create a 3D surface plot using the plot3D pattern

    master

    To plot a function $z = f(x, y)$, you can implement a class that manages a grid of vertex objects and connects them using quad objects.

    Key steps in the pattern:

    1. Initialize Vertices: Create an $L \times L$ grid of vertex objects. Note that the demo uses a coordinate mapping where the x-axis is labeled $y$, the z-axis is labeled $x$, and the y-axis is labeled $z$ to follow standard plotting conventions.
    2. Create Quads: Iterate through the vertex grid to create quad(vs=[v0, v1, v2, v3]) objects, which form the visible surface.
    3. Calculate Normals: For lighting to work correctly, calculate the normal for each vertex using the cross product of vectors pointing to adjacent vertices.
    4. Update/Replot: To animate the surface, update the pos attribute of the existing vertices and recalculate the normals.
    # Example of the pattern used in the demo
    class plot3D:
        def __init__(self, f, xmin, xmax, ymin, ymax, zmin, zmax):
            self.f = f
            # ... initialization of bounds ...
            # ... creation of vertices ...
            self.make_quads()
            self.make_normals()
    
        def replot(self):
            # Update vertex positions based on function evaluation
            for i in range(L*L):
                v = self.vertices[i]
                v.pos.y = self.evaluate(x, y)
            self.make_normals()
  7. Create complex surfaces using vertices and quads

    master

    To create a dynamic or textured surface (like a rug or terrain), you can compose a grid of vertex objects and connect them using quad objects.

    Key Concept: Shared Vertices When multiple quad objects share the same vertex object, changing the position or normal of that single vertex automatically updates all connected quads. This is the standard way to implement smooth, deformable surfaces.

    Example Workflow:

    1. Create a list of vertex objects in a grid.
    2. Use quad(v0=..., v1=..., v2=..., v3=...) to define the faces using those vertices.
    3. Update the .pos or .normal attributes of the vertices in a loop to animate the surface.
    # 1. Create vertices
    verts = []
    for y in range(h+1):
        verts.append([])
        for x in range(w+1):
            verts[y].append(vertex(pos=vector(x, y, 0), normal=vector(0,0,1)))
    
    # 2. Create quads connecting vertices
    for y in range(h):
        for x in range(w):
            quad(v0=verts[y][x], v1=verts[y][x+1], v2=verts[y+1][x+1], v3=verts[y+1][x], texture=textures.rug)
    
    # 3. Animate by updating vertex positions
    verts[y][x].pos.z = new_height
  8. Interact with the VPython scene camera

    master

    VPython scenes support several mouse and touch gestures for navigating the 3D view:

    • Rotate Camera: Right-button drag or Ctrl-drag.
    • Zoom In/Out: Middle-button drag or Alt-drag (up/down).
    • Two-button Mouse: The middle button is often mapped to left + right click.
    • Touch Screen: Use pinch/extend to zoom and swipe or two-finger gestures to rotate.
  9. Rotate and zoom the 3D camera

    master

    VPython provides built-in mouse and touch interactions for navigating the 3D scene:

    Mouse Interactions:

    • Rotate: Drag with the right mouse button, or hold Ctrl and drag.
    • Zoom: Drag with both left and right mouse buttons, or hold Alt/Option and drag, or use the mouse wheel.

    Touch Screen Interactions:

    • Zoom: Pinch or extend fingers.
    • Rotate: Swipe or use two-finger rotation.
  10. How to use textures in VPython

    master

    VPython provides built-in texture and bump map assets that can be applied to geometric primitives.

    Texture Application

    Textures are applied by assigning a dictionary to the .texture attribute of an object. The dictionary keys are:

    • file: The texture asset (e.g., textures.wood).
    • bumpmap: The bump map asset (e.g., bumpmaps.rock).

    Common Assets

    Based on the demo, common assets include:

    • Textures: textures.flower, textures.granite, textures.gravel, textures.metal, textures.rock, textures.rough, textures.rug, textures.stones, textures.stucco, textures.wood, textures.wood_old, textures.earth.
    • Bump Maps: bumpmaps.gravel, bumpmaps.rock, bumpmaps.stones, bumpmaps.stucco, bumpmaps.wood_old.

    Note: Bump maps are most visible when the light source moves or the object is rotated.

    # Applying a texture with a bump map
    obj.texture = dict(file=textures.wood, bumpmap=bumpmaps.wood_old)