{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Using pythreejs with the SageMath kernel\n", "\n", "This example is taken from [pythreejs GitHub page](https://github.com/jovyan/pythreejs/blob/master/examples/Examples.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**pythreejs** has been installed by\n", "\n", " sage -pip install pythreejs\n", " sage -sh jupyter nbextension enable --py --sys-prefix pythreejs\n", " sage -pip install scikit-image\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The version of SageMath:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'SageMath version 7.5.beta4, Release Date: 2016-11-24'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "version()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:58: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " data = List(CInt).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:88: DeprecationWarning: metadata {'sync': True} was set from the constructor. Metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')\n", " string = Unicode(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:24: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " return List(trait_type, default_value=default, minlen=3, maxlen=3, **kwargs)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:102: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " quaternion = List(CFloat).tag(sync=True) # [x,y,z,w]\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:249: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " picked = List(Dict).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:272: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " colors = List(Color).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:273: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " faces = List(List(CFloat)).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:403: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " vertices = List(List(CFloat)).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:404: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " faces = List(List(CInt)).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:426: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " z = List(CFloat, [0] * 100).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:440: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " vertices = List(CFloat).tag(sync=True) # [x0, y0, z0, x1, y1, z1, x2, y2, z2, ...]\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:441: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " face3 = List(CInt).tag(sync=True) # [v0,v1,v2, v0,v1,v2, v0,v1,v2, ...]\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:442: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " face4 = List(CInt).tag(sync=True) # [v0,v1,v2,v3, v0,v1,v2,v3, v0,v1,v2,v3, ...]\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:443: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " facen = List(List(CInt)).tag(sync=True) # [[v0,v1,v2,...,vn], [v0,v1,v2,...,vn], [v0,v1,v2,...,vn], ...]\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:450: DeprecationWarning: metadata {'sync': True} was set from the constructor. Metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')\n", " func = Unicode(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:462: DeprecationWarning: metadata {'sync': True} was set from the constructor. Metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')\n", " name = Unicode(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:615: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " uvScale = List(CFloat).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:618: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " uvOffset = List(CFloat).tag(sync=True)\n", "/home/eric/sage/7.5.beta4/local/lib/python2.7/site-packages/pythreejs/pythreejs.py:622: DeprecationWarning: Traits should be given as instances, not types (for example, `Int()`, not `Int`)\n", " alignment = List(CFloat).tag(sync=True)\n" ] } ], "source": [ "from pythreejs import *\n", "import numpy as np\n", "from IPython.display import display\n", "from ipywidgets import HTML, Text\n", "from traitlets import link, dlink" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Simple sphere and text" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ball = Mesh(geometry=SphereGeometry(radius=1), \n", " material=LambertMaterial(color='red'),\n", " position=[2, 1, 0])\n", "\n", "scene = Scene(children=[ball, AmbientLight(color='#777777')])\n", "\n", "c = PerspectiveCamera(position=[0, 5, 5], up=[0, 0, 1],\n", " children=[DirectionalLight(color='white', \n", " position=[3, 5, 1], \n", " intensity=0.5)])\n", "renderer = Renderer(camera=c, \n", " scene=scene, \n", " controls=[OrbitControls(controlling=c)])\n", "display(renderer)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "ball.geometry.radius = 0.5" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import time, math\n", "ball.material.color = '#4400dd'\n", "for i in range(1, 150, 2):\n", " ball.geometry.radius = i / 100.\n", " ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]\n", " time.sleep(.05)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Clickable Surface\n", "\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [], "source": [ "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", "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, material=LambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n", "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'))\n", "hover_point = Mesh(geometry=SphereGeometry(radius=0.05), material=LambertMaterial(color='hotpink'))\n", "scene = Scene(children=[surf, surfgrid, hover_point, AmbientLight(color='#777777')])\n", "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], \n", " children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.6)])\n", "click_picker = Picker(root=surf, event='dblclick')\n", "hover_picker = Picker(root=surf, event='mousemove')\n", "renderer = Renderer(camera=c, scene = scene, controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n", "\n", "def f(change):\n", " value = change['new']\n", " print('Clicked on %s' % value)\n", " point = Mesh(geometry=SphereGeometry(radius=0.05), \n", " material=LambertMaterial(color='red'),\n", " position=value)\n", " scene.children = list(scene.children) + [point]\n", "\n", "click_picker.observe(f, names=['point'])\n", "\n", "link((hover_point, 'position'), (hover_picker, 'point'))\n", "\n", "h = HTML()\n", "def g(change):\n", " h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n", "g({'new': hover_point.position})\n", "hover_picker.observe(g, names=['point'])\n", "display(h)\n", "display(renderer)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "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": [ "# Design our own texture" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np\n", "from scipy import ndimage\n", "import matplotlib\n", "import matplotlib.pyplot as plt\n", "from skimage import img_as_ubyte \n", "\n", "jet = matplotlib.cm.get_cmap('jet')\n", "\n", "np.random.seed(int(1)) # start random number generator\n", "n = int(5) # starting points\n", "size = int(32) # size of image\n", "im = np.zeros((size,size)) # create zero image\n", "points = size*np.random.random((2, n**2)) # locations of seed values\n", "im[(points[0]).astype(np.int), (points[1]).astype(np.int)] = size # seed high values\n", "im = ndimage.gaussian_filter(im, sigma=size/(float(4)*n)) # smooth high values into surrounding areas\n", "im *= 1/np.max(im)# rescale to be in the range [0,1]\n", "rgba_im = img_as_ubyte(jet(im)) # convert the values to rgba image using the jet colormap\n", "rgba_list = list(rgba_im.flat) # make a flat list\n", "\n", "t = DataTexture(data=rgba_list, format='RGBAFormat', width=size, height=size)\n", "\n", "geometry = SphereGeometry()#TorusKnotGeometry(radius=2, radialSegments=200)\n", "material = LambertMaterial(map=t)\n", "\n", "myobject = Mesh(geometry=geometry, material=material)\n", "c = PerspectiveCamera(position=[0, 3, 3], fov=40,\n", " children=[DirectionalLight(color='#ffffff', position=[3, 5, 1], intensity=0.5)])\n", "scene = Scene(children=[myobject, AmbientLight(color='#777777')])\n", "\n", "renderer = Renderer(camera=c, scene = scene, controls=[OrbitControls(controlling=c)])\n", "display(renderer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Lines" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# On windows, linewidth of the material has no effect\n", "size = 4\n", "linesgeom = PlainGeometry(vertices=[[0, 0, 0],\n", " [size, 0, 0],\n", " [0, 0, 0],\n", " [0, size, 0],\n", " [0, 0, 0],\n", " [0, 0, size]],\n", " colors = ['red', 'red', 'green', 'green', 'white', 'orange'])\n", "lines = Line(geometry=linesgeom, \n", " material=LineBasicMaterial(linewidth=5, vertexColors='VertexColors'), \n", " type='LinePieces')\n", "scene = Scene(children=[lines, DirectionalLight(color='#ccaabb', position=[0,10,0]),AmbientLight(color='#cccccc')])\n", "c = PerspectiveCamera(position=[0, 10, 10])\n", "renderer = Renderer(camera=c, scene = scene, controls=[OrbitControls(controlling=c)])\n", "display(renderer)" ] }, { "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": 10, "metadata": { "collapsed": false }, "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);\n", "\n", "surf = Mesh(geometry=surf_g, material=LambertMaterial(color='green', side='FrontSide'))\n", "surf2 = Mesh(geometry=surf_g, material=LambertMaterial(color='yellow', side='BackSide'))\n", "scene = Scene(children=[surf, surf2, AmbientLight(color='#777777')])\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", "renderer = Renderer(camera=c, scene=scene, controls=[OrbitControls(controlling=c)])\n", "display(renderer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Examples to do\n", "- image texture (with webcam picture!)\n", "- animate something through space\n", "- scaled object: point that doesn't change size\n", "- vertex shade\n", "- parametric geometry\n", "- switch between phong, lambert, depth, and wireframe materials, normalmaterial" ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 7.5.beta4", "language": "", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" }, "widgets": { "state": { "5101f963765a4591bd1730ca369b862f": { "views": [ { "cell_index": 17 } ] }, "51781e0fa2ab412aa52d58fa9129e57d": { "views": [ { "cell_index": 13 } ] }, "703eeeaba4bf4f5180a0722f396f23d9": { "views": [ { "cell_index": 10 } ] }, "7548be744e4a411b8b3cc7d2b29090ae": { "views": [ { "cell_index": 15 } ] }, "812428758d6c45ef8619f7c74e6b739b": { "views": [ { "cell_index": 10 } ] }, "d82da7d89fac45c68b15aff5c2d4ee83": { "views": [ { "cell_index": 6 } ] } }, "version": "1.2.0" } }, "nbformat": 4, "nbformat_minor": 1 }