In [ ]:
import ipywidgets as wd
from vpython import *

# For some reason, this program that uses widgets sometimes doesn't make the 3D display without a restart

# This is an experiment in using Jupyter widgets (button, slider, menu).
# Compare with the similar program in the Example programs at glowscript.org.
# Ideally, we would like to use the same widget statements in both GlowScript and Jupyter VPython.

scene.width = 350
scene.height = 300
scene.range = 1.5
scene.title = "Buttons, Sliders, and Drop-down Menus"

box_object = box(visible=True)
cone_object = cone(visible=False, radius=0.5)
pyramid_object = pyramid(visible=False)
cylinder_object = cylinder(visible=False, radius=0.5)
objects = {'box':box_object, 'cone':cone_object, 'pyramid':pyramid_object, 'cylinder':cylinder_object}

currentobject = box_object
currentobject.color = color.cyan

b = wd.Button(description='Pause')
c = wd.Button(description='Red')
m = wd.Dropdown(options=['box', 'cone', 'cylinder', 'pyramid'], value='box',
                           description='Object:')
container = wd.HBox(children=[b,c,m])
display(container)
sl = wd.FloatSlider(description='Rotation speed:', min=20, max=500, step=1, value=250)
display(sl)

running = True

def b_handler(s):
    global running
    running = not running
    if s.description == 'Run': s.description = 'Pause'
    else: s.description = 'Run'
b.on_click(b_handler)

def c_handler(s):
    if s.description == 'Red':
        s.description = 'Cyan'
        currentobject.color = color.red
    else:
        s.description = 'Red'
        currentobject.color = color.cyan
c.on_click(c_handler)

def m_handler(s):
    global currentobject
    col = currentobject.color
    currentobject.visible = False
    currentobject = objects[s['new']]
    currentobject.color = col
    currentobject.visible = True
m.observe(m_handler, names='value')

while True:
    rate(100)
    if running:
        currentobject.rotate(angle=1e-4*sl.value, axis=vec(0,1,0))

In [ ]: