<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Simple sphere and text
Step1:  Clickable Surface
Step2:  Design our own texture
Step3:  Lines
Step5:  Parametric Functions
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).
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.
Step6:  Indexed Geometries
The PlainGeometry lets you specify vertices and faces for a surface.
Step7:  Buffer Geometries
The PlainBufferGeometry object uses several tricks to speed up both the transfer of data and the rendering of the data.
<ASSISTANT_TASK:>
Python Code:
ball = Mesh(geometry=SphereGeometry(radius=1), 
            material=MeshLambertMaterial(color='red'),
            position=[2, 1, 0])
c = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0],
                      children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)])
scene = Scene(children=[ball, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c, 
                    scene=scene, 
                    controls=[OrbitControls(controlling=c)])
display(renderer)
ball.geometry.radius = 0.5
import time, math
ball.material.color = '#4400dd'
for i in range(1, 150, 2):
    ball.geometry.radius = i / 100.
    ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]
    time.sleep(.05)
Explanation: Simple sphere and text
End of explanation
# Generate surface data:
view_width = 600
view_height = 400
nx, ny = (20, 20)
xmax=1
x = np.linspace(-xmax, xmax, nx)
y = np.linspace(-xmax, xmax, ny)
xx, yy = np.meshgrid(x, y)
z = xx ** 2 - yy ** 2
#z[6,1] = float('nan')
# Generate scene objects from data:
surf_g = SurfaceGeometry(z=list(z[::-1].flat), 
                         width=2 * xmax,
                         height=2 * xmax,
                         width_segments=nx - 1,
                         height_segments=ny - 1)
surf = Mesh(geometry=surf_g,
            material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))
surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),
                       position=[0, 0, 1e-2])  # Avoid overlap by lifting grid slightly
# Set up picking bojects:
hover_point = Mesh(geometry=SphereGeometry(radius=0.05),
                   material=MeshLambertMaterial(color='hotpink'))
click_picker = Picker(controlling=surf, event='dblclick')
hover_picker = Picker(controlling=surf, event='mousemove')
# Set up scene:
key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)
c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,
                      children=[key_light])
scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])
renderer = Renderer(camera=c, scene=scene,
                    width=view_width, height=view_height,
                    controls=[OrbitControls(controlling=c), click_picker, hover_picker])
# Set up picking responses:
# Add a new marker when double-clicking:
out = Output()
def f(change):
    value = change['new']
    with out:
        print('Clicked on %s' % (value,))
    point = Mesh(geometry=SphereGeometry(radius=0.05), 
                 material=MeshLambertMaterial(color='red'),
                 position=value)
    scene.add(point)
click_picker.observe(f, names=['point'])
# Have marker follow picker point:
link((hover_point, 'position'), (hover_picker, 'point'))
# Show picker point coordinates as a label:
h = HTML()
def g(change):
    h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])
g({'new': hover_point.position})
hover_picker.observe(g, names=['point'])
display(VBox([h, renderer, out]))
surf_g.z = list((-z[::-1]).flat)
surf.material.map = height_texture(-z[::-1])
Explanation: Clickable Surface
End of explanation
import numpy as np
from scipy import ndimage
import matplotlib
import matplotlib.pyplot as plt
from skimage import img_as_ubyte 
jet = matplotlib.cm.get_cmap('jet')
np.random.seed(int(1)) # start random number generator
n = int(5) # starting points
size = int(32) # size of image
im = np.zeros((size,size)) # create zero image
points = size*np.random.random((2, n**2)) # locations of seed values
im[(points[0]).astype(np.int), (points[1]).astype(np.int)] = size # seed high values
im = ndimage.gaussian_filter(im, sigma=size/(float(4)*n)) # smooth high values into surrounding areas
im *= 1/np.max(im)# rescale to be in the range [0,1]
rgba_im = img_as_ubyte(jet(im)) # convert the values to rgba image using the jet colormap
t = DataTexture(data=rgba_im, format='RGBAFormat', width=size, height=size)
geometry = SphereGeometry(radius=1, widthSegments=16, heightSegments=10)#TorusKnotGeometry(radius=2, radialSegments=200)
material = MeshLambertMaterial(map=t)
myobject = Mesh(geometry=geometry, material=material)
c = PerspectiveCamera(position=[0, 3, 3], fov=40,
                      children=[DirectionalLight(color='#ffffff', position=[3, 5, 1], intensity=0.5)])
scene = Scene(children=[myobject, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c, scene = scene, controls=[OrbitControls(controlling=c)], width=400, height=400)
display(renderer)
Explanation: Design our own texture
End of explanation
# On windows, linewidth of the material has no effect
size = 4
linesgeom = Geometry(vertices=[[0, 0, 0],
                                    [size, 0, 0],
                                    [0, 0, 0],
                                    [0, size, 0],
                                    [0, 0, 0],
                                    [0, 0, size]],
                          colors = ['red', 'red', 'green', 'green', 'white', 'orange'])
lines = Line(geometry=linesgeom, 
             material=LineBasicMaterial(linewidth=5, vertexColors='VertexColors'), 
             type='LinePieces',
            )
scene = Scene(children=[
    lines,
    DirectionalLight(color='#ccaabb', position=[0,10,0]),
    AmbientLight(color='#cccccc'),
    ])
c = PerspectiveCamera(position=[10, 10, 10])
renderer = Renderer(camera=c, background='black', background_opacity=1, scene=scene, controls=[OrbitControls(controlling=c)],
                    width=400, height=400)
display(renderer)
Explanation: Lines
End of explanation
f = 
function f(origu,origv) {
    // scale u and v to the ranges I want: [0, 2*pi]
    var u = 2*Math.PI*origu;
    var v = 2*Math.PI*origv;
    
    var x = Math.sin(u);
    var y = Math.cos(v);
    var z = Math.cos(u+v);
    
    return new THREE.Vector3(x,y,z)
}
surf_g = ParametricGeometry(func=f, slices=16, stacks=16);
surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))
surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))
c = PerspectiveCamera(position=[5, 5, 3], up=[0, 0, 1],
                      children=[DirectionalLight(color='white',
                                                 position=[3, 5, 1],
                                                 intensity=0.6)])
scene = Scene(children=[surf, surf2, c, AmbientLight(intensity=0.5)])
renderer = Renderer(camera=c, scene=scene, controls=[OrbitControls(controlling=c)], width=400, height=400)
display(renderer)
Explanation: Parametric Functions
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).
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.
End of explanation
from pythreejs import *
from IPython.display import display
vertices = [
    [0, 0, 0],
    [0, 0, 1],
    [0, 1, 0],
    [0, 1, 1],
    [1, 0, 0],
    [1, 0, 1],
    [1, 1, 0],
    [1, 1, 1]
]
faces = [
    [0, 1, 3],
    [0, 3, 2],
    [0, 2, 4],
    [2, 6, 4],
    [0, 4, 1],
    [1, 4, 5],
    [2, 3, 6],
    [3, 7, 6],
    [1, 5, 3],
    [3, 5, 7],
    [4, 6, 5],
    [5, 6, 7]
]
vertexcolors = ['#000000', '#0000ff', '#00ff00', '#ff0000',
                '#00ffff', '#ff00ff', '#ffff00', '#ffffff']
# Map the vertex colors into the 'color' slot of the faces
faces = [f + [None, [vertexcolors[i] for i in f]] for f in faces]
# Create the geometry:
cubeGeometry = Geometry(vertices=vertices,
    faces=faces,
    colors=vertexcolors)
# Calculate normals per face, for nice crisp edges:
cubeGeometry.exec_three_obj_method('computeFaceNormals')
# Create a mesh. Note that the material need to be told to use the vertex colors.
myobjectCube = Mesh(
    geometry=cubeGeometry,
    material=MeshLambertMaterial(vertexColors='VertexColors'),
    position=[-0.5, -0.5, -0.5],   # Center the cube
)
# Set up a scene and render it:
cCube = PerspectiveCamera(position=[3, 3, 3], fov=20,
                      children=[DirectionalLight(color='#ffffff', position=[-3, 5, 1], intensity=0.5)])
sceneCube = Scene(children=[myobjectCube, cCube, AmbientLight(color='#dddddd')])
rendererCube = Renderer(camera=cCube, background='black', background_opacity=1,
                        scene=sceneCube, controls=[OrbitControls(controlling=cCube)])
display(rendererCube)
Explanation: Indexed Geometries
The PlainGeometry lets you specify vertices and faces for a surface.
End of explanation
from pythreejs import *
import numpy as np
from IPython.display import display
vertices = np.asarray([
    [0, 0, 0],
    [0, 0, 1],
    [0, 1, 0],
    [0, 1, 1],
    [1, 0, 0],
    [1, 0, 1],
    [1, 1, 0],
    [1, 1, 1]
], dtype='float32')
faces = np.asarray([
    [0, 1, 3],
    [0, 3, 2],
    [0, 2, 4],
    [2, 6, 4],
    [0, 4, 1],
    [1, 4, 5],
    [2, 3, 6],
    [3, 7, 6],
    [1, 5, 3],
    [3, 5, 7],
    [4, 6, 5],
    [5, 6, 7]
], dtype='uint16').ravel()  # We need to flatten index array
vertexcolors = np.asarray([(0,0,0), (0,0,1), (0,1,0), (1,0,0),
                           (0,1,1), (1,0,1), (1,1,0), (1,1,1)], dtype='float32')
cubeGeometry = BufferGeometry(attributes=dict(
    position=BufferAttribute(vertices, normalized=False),
    index=BufferAttribute(faces, normalized=False),
    color=BufferAttribute(vertexcolors),
))
myobjectCube = Mesh(
    geometry=cubeGeometry,
    material=MeshLambertMaterial(vertexColors='VertexColors'),
    position=[-0.5, -0.5, -0.5]   # Center the cube
)
cCube = PerspectiveCamera(
    position=[3, 3, 3], fov=20,
    children=[DirectionalLight(color='#ffffff', position=[-3, 5, 1], intensity=0.5)])
sceneCube = Scene(children=[myobjectCube, cCube, AmbientLight(color='#dddddd')])
rendererCube = Renderer(camera=cCube, background='black', background_opacity=1,
                        scene = sceneCube, controls=[OrbitControls(controlling=cCube)])
display(rendererCube)
Explanation: Buffer Geometries
The PlainBufferGeometry object uses several tricks to speed up both the transfer of data and the rendering of the data.
End of explanation
<END_TASK>