{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# pythreejs: 3D rendering in the browser \n", "\n", "## A Jupyter - threejs bridge\n", "\n", "## https://github.com/jupyter-widgets/pythreejs\n", "\n", "\n", "Pythreejs is a jupyter interactive widget bringing fast WebGL 3d visualization to the Jupyter notebook.\n", "\n", "- Originally authored by Jason Grout, currently maintained by Vidar Tonaas Fauske\n", "- BSD Licensed\n", "\n", "Pythreejs is *not* a 3d plotting library, it only exposes the threejs scene objects to the Jupyter kernel.\n", "\n", "**Installation:**\n", "\n", "```bash\n", "conda install -c conda-forge pythreejs\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## This notebook based on [Examples.ipynb](https://github.com/jupyter-widgets/pythreejs/blob/master/examples/Examples.ipynb) \n", "\n", "One of the many example notebooks at https://github.com/jupyter-widgets/pythreejs/tree/master/examples" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pythreejs import *\n", "import numpy as np\n", "from IPython.display import display\n", "from ipywidgets import HTML, Text, Output, VBox\n", "from traitlets import link, dlink" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple sphere" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ball = Mesh(geometry=SphereGeometry(radius=1), \n", " material=MeshLambertMaterial(color='red'),\n", " position=[2, 1, 0])\n", "\n", "c = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0],\n", " children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)])\n", "\n", "scene = Scene(children=[ball, c, AmbientLight(color='#777777')])\n", "\n", "renderer = Renderer(camera=c, \n", " scene=scene, \n", " controls=[OrbitControls(controlling=c)])\n", "display(renderer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Properties of the ball can be updated, with changes reflected immediately in the visualization." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ball.scale = (0.5,) * 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import time, math\n", "ball.material.color = '#4400dd'\n", "for i in range(1, 150, 2):\n", " ball.scale = (i / 100.,) * 3\n", " ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]\n", " time.sleep(.05)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Clickable Surface" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Generate surface data:\n", "view_width = 600\n", "view_height = 400\n", "nx, ny = (20, 20)\n", "xmax=1\n", "x = np.linspace(-xmax, xmax, nx)\n", "y = np.linspace(-xmax, xmax, ny)\n", "xx, yy = np.meshgrid(x, y)\n", "z = xx ** 2 - yy ** 2\n", "#z[6,1] = float('nan')\n", "\n", "\n", "# Generate scene objects from data:\n", "surf_g = SurfaceGeometry(z=list(z[::-1].flat), \n", " width=2 * xmax,\n", " height=2 * xmax,\n", " width_segments=nx - 1,\n", " height_segments=ny - 1)\n", "\n", "surf = Mesh(geometry=surf_g,\n", " material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n", "\n", "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),\n", " position=[0, 0, 1e-2]) # Avoid overlap by lifting grid slightly\n", "\n", "# Set up picking bojects:\n", "hover_point = Mesh(geometry=SphereGeometry(radius=0.05),\n", " material=MeshLambertMaterial(color='green'))\n", "\n", "click_picker = Picker(controlling=surf, event='dblclick')\n", "hover_picker = Picker(controlling=surf, event='mousemove')\n", "\n", "# Set up scene:\n", "key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)\n", "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,\n", " children=[key_light])\n", "\n", "scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])\n", "\n", "renderer = Renderer(camera=c, scene=scene,\n", " width=view_width, height=view_height,\n", " controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n", "\n", "\n", "# Set up picking responses:\n", "# Add a new marker when double-clicking:\n", "out = Output()\n", "def f(change):\n", " value = change['new']\n", " with out:\n", " print('Clicked on %s' % (value,))\n", " point = Mesh(geometry=SphereGeometry(radius=0.05), \n", " material=MeshLambertMaterial(color='hotpink'),\n", " position=value)\n", " scene.add(point)\n", "\n", "click_picker.observe(f, names=['point'])\n", "\n", "# Have marker follow picker point:\n", "link((hover_point, 'position'), (hover_picker, 'point'))\n", "\n", "# Show picker point coordinates as a label:\n", "h = HTML()\n", "def g(change):\n", " h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n", " h.value += ' Double-click to add marker'\n", "g({'new': hover_point.position})\n", "hover_picker.observe(g, names=['point'])\n", "\n", "display(VBox([h, renderer, out]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# when we change the z values of the geometry, we need to also change the height map\n", "surf_g.z = list((-z[::-1]).flat)\n", "surf.material.map = height_texture(-z[::-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Parametric Functions\n", "\n", "\n", "To use the ParametricGeometry class, you need to specify a javascript function as a string. The function should take two parameters that vary between 0 and 1, and return a `new THREE.Vector3(x,y,z)`.\n", "\n", "If you want to build the surface in Python, you'll need to explicitly construct the vertices and faces and build a basic geometry from the vertices and faces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = \"\"\"\n", "function f(origu,origv) {\n", " // scale u and v to the ranges I want: [0, 2*pi]\n", " var u = 2*Math.PI*origu;\n", " var v = 2*Math.PI*origv;\n", " \n", " var x = Math.sin(u);\n", " var y = Math.cos(v);\n", " var z = Math.cos(u+v);\n", " \n", " return new THREE.Vector3(x,y,z)\n", "}\n", "\"\"\"\n", "surf_g = ParametricGeometry(func=f, slices=16, stacks=16);\n", "\n", "surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))\n", "surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))\n", "c = PerspectiveCamera(position=[5, 5, 3], up=[0, 0, 1],\n", " children=[DirectionalLight(color='white',\n", " position=[3, 5, 1],\n", " intensity=0.6)])\n", "scene = Scene(children=[surf, surf2, c, AmbientLight(intensity=0.5)])\n", "renderer = Renderer(camera=c, scene=scene, controls=[OrbitControls(controlling=c)], width=400, height=400)\n", "display(renderer)" ] } ], "metadata": { "kernelspec": { "display_name": "widgets-tutorial", "language": "python", "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" }, "widgets": { "state": { "01b59842f123469f8518ef01a0a3dc2b": { "views": [ { "cell_index": 6 } ] }, "9ad3421bc8374489a73f356fa90eb605": { "views": [ { "cell_index": 3 } ] }, "ddb9e9caabe04004a81c108b889973e7": { "views": [ { "cell_index": 10 } ] }, "e372695c70254a63af0d6f485dd1f3a3": { "views": [ { "cell_index": 3 } ] } }, "version": "2.0.0-dev" } }, "nbformat": 4, "nbformat_minor": 1 }