import numpy as np
from ipycanvas import Canvas, hold_canvas
from ipywidgets import FloatSlider
This module is local to the Notebook
from py3d_engine import OrbitCamera, project_vector
class Plot3d(Canvas):
def __init__(self):
super(Plot3d, self).__init__(width=500, height=500)
self.dragging = False
self.n = 200
self.x = np.random.rand(self.n) - 0.5
self.y = np.random.rand(self.n) - 0.5
self.z = np.random.rand(self.n) - 0.5
self.dx = 0
self.dy = 0
self.radius = 10
self.camera = OrbitCamera(self.radius, [0, 0, 0], self.width/self.height)
self.x2, self.y2, self.z2 = project_vector(self.x, self.y, self.z, self.camera.matrix)
self.draw()
self.on_mouse_down(self.mouse_down_handler)
self.on_mouse_move(self.mouse_move_handler)
self.on_mouse_up(self.mouse_up_handler)
self.on_mouse_out(self.mouse_out_handler)
def update_matrix(self, dx=None, dy=None, radius=None):
dx = dx if dx is not None else self.dx
dy = dy if dy is not None else self.dy
self.radius = radius if radius is not None else self.radius
self.camera.radius = self.radius
self.camera.update_position(dy, dx)
self.x2, self.y2, self.z2 = project_vector(self.x, self.y, self.z, self.camera.matrix)
self.draw()
def draw(self):
x = self.x2 * self.width + self.width / 2
y = self.y2 * self.height + self.height / 2
with hold_canvas(self):
self.clear()
self.fill_circles(x, y, 2)
def mouse_down_handler(self, pixel_x, pixel_y):
self.dragging = True
self.x_mouse = pixel_x
self.y_mouse = pixel_y
def mouse_move_handler(self, pixel_x, pixel_y):
if self.dragging:
self.dx_new = self.dx + pixel_x - self.x_mouse
self.dy_new = self.dy + pixel_y - self.y_mouse
self.update_matrix(self.dx_new, self.dy_new)
def mouse_up_handler(self, pixel_x, pixel_y):
if self.dragging:
self.dragging = False
self.dx = self.dx_new
self.dy = self.dy_new
def mouse_out_handler(self, pixel_x, pixel_y):
if self.dragging:
self.dragging = False
self.dx = self.dx_new
self.dy = self.dy_new
p = Plot3d()
p
# Link Camera position to a slider widget
slider = FloatSlider(description='Radius:', min=1., max=7., value=p.radius)
def on_slider_move(change):
slider_value = change['new']
p.update_matrix(radius=slider_value)
slider.observe(on_slider_move, 'value')
slider