Python 里也能写 Three.js?这个库把 Three.js API 完整搬进了 Jupyter
做数据科学的人经常遇到一个问题:计算结果需要 3D 可视化,但 Python 现有的可视化工具处理复杂 3D 场景时要么功能有限,要么交互体验差。如果想要 WebGL 级别的渲染质量和流畅的鼠标交互,通常得另起一套 JavaScript 前端,数据还得想办法从 Python 传过去,工作流被打断。
pythreejs 想解决的就是这个问题。它是 Jupyter Widgets 团队维护的扩展,把 Three.js 的 API 完整映射成 Python 类,让开发者在 Jupyter Notebook 里直接用 Python 描述 3D 场景——渲染还是走浏览器的 WebGL,但不需要写一行 JavaScript,也不需要搭独立前端。
Three.js 是前端的工具,Jupyter Notebook 是 Python 数据科学的工具,两个本来没什么交集。pythreejs 做的事是把这两个接起来。目前 989 Star,最新版本 2.4.1。

Python 对象怎么变成 Three.js 场景
先看一个最基础的例子,在 Jupyter 里创建一个红色球体:
from pythreejs import *
from IPython.display import display
sphere = Mesh(
SphereGeometry(radius=1, widthSegments=32, heightSegments=24),
MeshLambertMaterial(color='red'),
position=[2, 1, 0]
)
camera = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0])
scene = Scene(children=[
sphere,
camera,
DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5),
AmbientLight(color='#777777')
])
renderer = Renderer(camera=camera, scene=scene, controls=[OrbitControls(controlling=camera)])
display(renderer)执行这段代码,Jupyter 单元格里直接出现一个可以鼠标旋转的 3D 球体。
这里的 Mesh、SphereGeometry、MeshLambertMaterial、PerspectiveCamera、Scene 和 Three.js 里的对象是一一对应的:
| Python 类 | 对应 Three.js 对象 |
|---|---|
Scene | THREE.Scene |
Mesh | THREE.Mesh |
PerspectiveCamera | THREE.PerspectiveCamera |
SphereGeometry | THREE.SphereGeometry |
MeshLambertMaterial | THREE.MeshLambertMaterial |
DirectionalLight | THREE.DirectionalLight |
OrbitControls | OrbitControls |
通信机制是 Jupyter Widgets 框架:Python 对象的属性变更会序列化成 JSON,通过 WebSocket 传给浏览器侧的 JavaScript,由 JavaScript 创建或更新对应的 Three.js 对象,最终在 WebGL 里渲染。渲染本身还是在浏览器里跑,Python 那边负责描述场景结构。
BufferGeometry + NumPy:给大数据集用
如果数据来自 NumPy 数组(比如点云、科学模拟结果),可以用 BufferGeometry 直接把数组传进去:
import numpy as np
from pythreejs import *
# 生成随机点云
n = 5000
positions = np.random.uniform(-5, 5, (n, 3)).astype(np.float32)
colors = np.random.uniform(0, 1, (n, 3)).astype(np.float32)
geometry = BufferGeometry(attributes={
'position': BufferAttribute(array=positions),
'color': BufferAttribute(array=colors),
})
material = PointsMaterial(vertexColors='VertexColors', size=0.1)
points = Points(geometry=geometry, material=material)
camera = PerspectiveCamera(position=[0, 0, 15])
scene = Scene(children=[points, camera, AmbientLight()])
renderer = Renderer(camera=camera, scene=scene, controls=[OrbitControls(controlling=camera)])
display(renderer)NumPy 数组直接作为 BufferAttribute 传入,不需要手动把数据转成 JavaScript 格式。pythreejs 内部处理了 NumPy 到浏览器端 TypedArray 的序列化。对于百万级顶点的数据集,这是实际可用的路径。
动态更新场景
Python 对象和浏览器里的 Three.js 对象保持同步,修改 Python 对象的属性会实时反映到场景里:
# 改变球体位置
sphere.position = [0, 2, 0]
# 改变材质颜色
sphere.material.color = 'blue'
# 改变相机位置
camera.position = [10, 10, 10]直接赋值,Jupyter 里的 3D 场景立刻更新。这个特性让在 Jupyter 里做交互式参数调试比较方便,比如配合 ipywidgets 的滑块来实时调整几何体参数。
有一个限制要提前知道
不是所有 Three.js 方法都可以直接在 Python 里调用。Three.js 对象上的方法(比如 geometry.rotateX())没有对应的 Python 方法,需要通过 exec_three_obj_method 来执行:
from pythreejs import exec_three_obj_method
import math
# 无法直接调用:geometry.rotateX(Math.PI / 2)
# 需要用这个方式:
exec_three_obj_method(geometry, 'rotateX', math.pi / 2)这是 Python/JavaScript 桥接的固有限制。pythreejs 的设计目标是让属性可读写,但方法调用需要走这个中间层。对于大部分静态场景构建没有影响,但如果需要复杂的动画逻辑或频繁调用 Three.js 方法,这个限制会比较明显。
另外需要注意版本:最新版本 2.4.1 发布于 2022 年,Three.js 本身的 API 这两年有一些变化,部分新特性(比如新的材质类型)在 pythreejs 里还没有对应的 Python 类。
安装
pip install pythreejs
# 或
conda install -c conda-forge pythreejsJupyterLab 3.0 及以上版本安装后可以直接用,不需要额外配置。旧版 JupyterLab 需要手动启用扩展:
jupyter nbextension install --py --symlink --sys-prefix pythreejs
jupyter nbextension enable --py --sys-prefix pythreejs写在最后
pythreejs 解决的问题很具体:在 Python/Jupyter 环境里需要 3D 可视化,又不想维护一套独立的 JavaScript 前端。NumPy 数组直接输入几何体、Python 对象属性变更实时同步到场景,这两点对数据科学工作流来说比较实用。
它不是要替代直接写 Three.js,两者的使用场景基本不重叠:需要部署成 Web 应用、需要完整的动画控制、需要自定义 Shader,还是得写 JavaScript。但如果工作流本身就在 Jupyter 里,需要把计算结果快速可视化成 3D 场景,pythreejs 是一个不需要切换技术栈的选项。
GitHub:https://github.com/jupyter-widgets/pythreejs (opens in a new tab)