def __init__(self, width, height): super().__init__() self.is_drawing = False self._start_point = () self._image_scale = 1.0 self._bg_layer = 0 self._image_layer = 1 self._box_layer = 2 # Define each of the children... self._image = Image(layout=Layout(display='flex', justify_content='center', align_items='center', align_content='center')) self._multi_canvas = MultiCanvas(3, width=width, height=height) self._im_name_box = Label() children = [VBox([self._multi_canvas, self._im_name_box])] self.children = children draw_bg(self._multi_canvas[self._bg_layer]) # link drawing events self._multi_canvas[self._box_layer].on_mouse_move(self._update_pos) self._multi_canvas[self._box_layer].on_mouse_down(self._start_drawing) self._multi_canvas[self._box_layer].on_mouse_up(self._stop_drawing)
def setup_canvas(self): # canvas 0: topography # canvas 1: particles # canvas 2: buckets canvas_size = (self.scale * self.toposim.shape[0], self.scale * self.toposim.shape[1] + self.buckets_height) self.canvas = MultiCanvas(ncanvases=3, size=canvas_size) self.canvas.on_client_ready(self.redraw)
def __init__(self, layers, width, height): """ Initialisiert die smartiS-Instanz. layers <list (string)>: Liste mit Bezeichnungen der Canvas/Ebenen width <int>: Breite des Canvas height <int>: Höhe des Canvas """ self.canvas = MultiCanvas(len(layers), width=width, height=height) self.tmpCanvas = MultiCanvas(len(layers), width=width, height=height) self.canvasDict = {} self.tmpCanvasDict = {} for i in range(len(layers)): self.canvasDict[layers[i]] = self.canvas[i] self.tmpCanvasDict[layers[i]] = self.tmpCanvas[i]
def __init__(self, state: BBoxCanvasState, has_border: bool = False): super().__init__() self._state = state self._start_point = () self.is_drawing = False self.has_border = has_border self.canvas_bbox_coords = {} # do not stick bbox to borders self.padding = 2 # Define each of the children... self._image = Image(layout=Layout(display='flex', justify_content='center', align_items='center', align_content='center')) self.multi_canvas = MultiCanvas(len(BBoxLayer), width=self._state.width, height=self._state.height) self.im_name_box = Label() children = [VBox([self.multi_canvas, self.im_name_box])] self.children = children draw_bg(self.multi_canvas[BBoxLayer.bg]) # link drawing events self.multi_canvas[BBoxLayer.drawing].on_mouse_move(self._update_pos) self.multi_canvas[BBoxLayer.drawing].on_mouse_down(self._start_drawing) self.multi_canvas[BBoxLayer.drawing].on_mouse_up(self._stop_drawing)
def __init__(self, width=400, height=400): self.multicanvas = MultiCanvas(4, width=width, height=height) self.turtleCanvas = self.multicanvas[3] self.sc = Sidecar(title="Turtle Screen") with self.sc: display(self.multicanvas) self.turtles = []
def Single_Zone(self, Zone, fig=None, offset=np.array([0, 0])): w = self.margin wall_width = self.wall_th * self.scale Zone_w = (Zone.x_delta + 2 * w) * self.scale Zone_h = (Zone.y_delta + 2 * w) * self.scale canvas_w = Zone_w + 2 * wall_width canvas_h = Zone_h + 2 * wall_width w = w * self.scale if fig == None: canvas = MultiCanvas(4, width=canvas_w, height=canvas_h) else: canvas = fig # background canvas[0].translate(offset[0], offset[1]) Mars_img = Image.from_file('Images/Mars_surface.jpg') canvas3 = Canvas(width=1000, height=1000) canvas3.draw_image(Mars_img, 0, 0) canvas3.scale(3 * self.scale / 50) canvas[0].draw_image(canvas3, 0, 0) canvas[0].translate(-offset[0], -offset[1]) # Draw Zone canvas[1].translate(offset[0], offset[1]) canvas[1].fill_rect(0, 0, canvas_w, height=canvas_h) canvas[1].clear_rect(wall_width, wall_width, Zone_w, height=Zone_h) # Name of thr Zone canvas[1].font = '16px serif' canvas[1].fill_text(Zone.name, Zone_w / 2, 4 * wall_width) canvas[1].translate(-offset[0], -offset[1]) # Draw object insised the Zone canvas[2].translate(offset[0], offset[1]) if Zone.type == 'Landing_zone': charging = self.problem_2_canvas(Zone.charger) trash_bin = self.problem_2_canvas(Zone.deposit) canvas[2].fill_style = 'green' canvas[2].fill_rect(charging[0] - w / 2, charging[1] - w / 2, w) canvas[2].fill_style = 'blue' canvas[2].fill_rect(trash_bin[0] - w / 2, trash_bin[1] - w / 2, w) else: canvas[2].fill_style = 'brown' p_r = 0.1 x, y, radius = [], [], [] for i in range(0, Zone.max_sample): sam_coord = self.problem_2_canvas(Zone.samples_loc[i, :]) x.append(sam_coord[0]) y.append(sam_coord[1]) radius.append(p_r * self.scale) canvas[2].fill_circles(x, y, radius) for i in Zone.connections['Location']: canvas[2].fill_style = 'red' c_coord = self.problem_2_canvas(Zone.Location_2_coordinate[i]) x = c_coord[0] y = c_coord[1] canvas[2].fill_rect(x - w / 2, y - w / 2, w) canvas[2].translate(-offset[0], -offset[1]) return canvas
def all_Zones(self, canvas=None): if canvas == None: canvas = MultiCanvas(4, width=self.max_x, height=self.max_y) for i in range(0, self.number_of_Zones): offset = self.Zones[i].coordinates * self.scale canvas = self.Single_Zone(self.Zones[i], fig=canvas, offset=offset) return canvas
def image_roi(image, callback=lambda *_: None, box_shape=(4, 4), snap=(1, 1), scale=1, highlight_alpha=0.2, show=True): assert transform.isHWC(image) if transform.is_integer(image): image = transform.to_float(image) else: image = image.astype(np.float32) #must be float32... image = transform.colour(image) #requires HWC float format... image = transform.scale(image, scale, interpolation=transform.interpolation.nearest) image = transform.to_integer(image) canvas = MultiCanvas(2, width=image.shape[0], height=image.shape[1], scale=1) canvas[0].put_image_data(image, 0, 0) bw = box_shape[0] * scale bh = box_shape[1] * scale out = Output() #for printing stuff.. @out.capture() def draw_callback(x, y): canvas[1].clear() canvas[1].fill_style = 'white' canvas[1].global_alpha = highlight_alpha canvas[1].fill_rect(x, y, bw, bh) canvas[1].global_alpha = 1. canvas[1].stroke_style = 'red' canvas[1].stroke_rect(x, y, bw, bh) callback(x, y) snap = (snap[0] * scale, snap[1] * scale) max_position = (canvas.width - bw, canvas.height - bh) mmh = __IPyEventMouseMoveHandler(canvas, draw_callback, snap=snap, max_position=max_position) if show: display(VBox([canvas, out])) return canvas, mmh
def __init__(self, canvases, width, height): """ Initialisiert die smartiS-Instanz. canvases <list (string)>: Liste mit Bezeichnungen der Canvas/Ebenen width <int>: Breite des Canvas height <int>: Höhe des Canvas """ self.canvas = MultiCanvas(len(canvases), width=width, height=height) self.cdict = {} for ci in range(len(canvases)): self.cdict[canvases[ci]] = self.canvas[ci]
def launch(self): self.init_map() self.init_images() self.create_panel() n_pixels = 40 multi = MultiCanvas(2, width=3 * n_pixels, height=3 * n_pixels) multi[0].fill_style = 'black' multi[0].fill_rect(0, 0, multi.size[0], multi.size[1]) self.canvas = multi[1] self.output = widgets.Output() display(VBox([HBox([self.manage_panel, self.start_stop_panel])]), self.output)
def display(self): multi = MultiCanvas( 2, width=self.client.server['mapsize_x'] * CELL_PIXELS, height=self.client.server['mapsize_y'] * CELL_PIXELS) #multi[0].fill_style = 'black' #multi[0].fill_rect(0, 0, multi.size[0], multi.size[1]) self.canvas_base = multi[0] self.canvas = multi[1] panel = self.create_panel() self.output = widgets.Output() self.output.clear_output() #display(VBox([Image.from_file(path + '/images/header.jpg', width=200,height=40), HBox([multi])]), self.output) display(HBox([multi, panel]), self.output)
def __init__(self, image: str=None, size=(600, 300), **kwargs): """Create a Turtle drawing canvas. Arguments: image: Load the image into the canvas. size: Set the size of the canvas. """ self._size = Turtle.DimPoint(size[0], size[1]) turtle = numpy.array(PIL.Image.open(pathlib.Path(__file__).parent / "turtle.png")) self._turtle = Canvas(width=turtle.shape[0], height=turtle.shape[1]) self._turtle.put_image_data(turtle) self._canvas = MultiCanvas(n_canvases=3, width=self._size.x, height=self._size.y, **kwargs) self._reset() if image is not None: self.background(image) self.clear()
def launch(self): self.cur_level = 1 self.init_map() self.init_images() self.create_panel() multi = MultiCanvas(2, width=self.map_size * self.n_pixels, height=self.map_size * self.n_pixels) multi[0].fill_style = 'black' multi[0].fill_rect(0, 0, multi.size[0], multi.size[1]) self.canvas = multi[1] self.output = widgets.Output() display( VBox([ Image.from_file(path + '/images/header.jpg', width=200, height=40), HBox([multi]) ]), self.output)
def draw_roaming_ui(): global iter_slider, reset_button, color_it_button, juliabrot_button, canvases global drawing, uly_select, ulx_select, color_list, picker1, picker2, bump_ud_slider, hue_slider, sat_slider, val_slider global lry_select, lrx_select, color_it, modulo_slider, picker3, bump_lr_slider, zoom_slider, save_button # This establishes the size of the preview gui drawing = False color_it = True uly_select = 0 ulx_select = 0 lry_select = jgrid.settings.sizeY lrx_select = jgrid.settings.sizeX canvases = MultiCanvas(3, width=jgrid.settings.sizeX * 2.5, height=jgrid.settings.sizeY + 75) canvases[drawing_layer].font = '25px serif' canvases[drawing_layer].fill_style = '#aaaaaa' canvases[drawing_layer].line_width = 3 canvases[interaction_layer].font = '35px serif' canvases[interaction_layer].fill_style = '#eee800' canvases[interaction_layer].stroke_style = '#ffffff' canvases[interaction_layer].line_width = 3 iter_slider = FloatLogSlider(description='Iterations:', base=10, value=jgrid.settings.max_iterations, min=1, max=7, step=.01, continuous_update=False) iter_slider.observe(handler=iter_slider_handler, names='value') max_lr_bump = jgrid.settings.sizeX max_ud_bump = jgrid.settings.sizeY bump_ud_slider = IntSlider(description='Bump UD pix:', value=1, min=0, max=max_ud_bump, step=1, continuous_update=False) bump_lr_slider = IntSlider(description='Bump LR pix:', value=1, min=0, max=max_lr_bump, step=1, continuous_update=False) zoom_slider = FloatSlider(description='Zoom:', value=2.0, min=0.0, max=1000.0, step=.001, continuous_update=False) #zoom_slider.observe(handler=zoom_button_handler, names='value') hue_slider = FloatSlider(description='Hue :', value=jgrid.settings.hue, min=0.0, max=1.0, step=.001, continuous_update=False) sat_slider = FloatSlider(description='Sat:', value=jgrid.settings.sat, min=0.0, max=1.0, step=.01, continuous_update=False) val_slider = FloatSlider(description='Val:', value=jgrid.settings.val, min=0.0, max=1.0, step=.02, continuous_update=False) hue_slider.observe(handler=hue_slider_handler, names='value') sat_slider.observe(handler=sat_slider_handler, names='value') val_slider.observe(handler=val_slider_handler, names='value') modulo_slider = IntSlider(description='Modulo:', value=jgrid.settings.modulo, min=1, max=1000000, step=1, continuous_update=False) modulo_slider.observe(handler=modulo_slider_handler, names='value') canvases[interaction_layer].on_mouse_down(on_mouse_down) canvases[interaction_layer].on_mouse_move(on_mouse_move) reset_button = Button(description='Zoom', disabled=False, button_style='', tooltip='Click to use zoom slider setting for zoom', icon='') reset_button.on_click(zoom_button_handler) save_button = Button(description='Save', disabled=False, button_style='', tooltip='Click to save as JSON settings file', icon='') save_button.on_click(save_button_handler) color_it_button = Button(description='Color/BW', disabled=False, button_style='', tooltip='Click for BW or Color', icon='') color_it_button.on_click(color_button_handler) juliabrot_button = Button(description='JM Mode', disabled=False, button_style='', tooltip='Click for Julia or Mandelbrot', icon='') juliabrot_button.on_click(juliabrot_button_handler) undo_button = Button(description='Undo', disabled=False, button_style='', tooltip='Click to revert to last view', icon='') undo_button.on_click(undo_button_handler) bleft_button = Button(description='Bump L', disabled=False, button_style='', tooltip='Click to nudge left num bump LR pixels', icon='') bleft_button.on_click(bleft_button_handler) bright_button = Button(description='Bump R', disabled=False, button_style='', tooltip='Click to nudge right num bump LR pixels', icon='') bright_button.on_click(bright_button_handler) bup_button = Button(description='Bump U', disabled=False, button_style='', tooltip='Click to nudge up num bump UD pixels', icon='') bup_button.on_click(bup_button_handler) bdown_button = Button(description='Bump D', disabled=False, button_style='', tooltip='Click to nudge down bump UD pixels', icon='') bdown_button.on_click(bdown_button_handler) picker1 = ColorPicker(description='M Color:', value=jgrid.settings.m_color) #picker2 = ColorPicker(description='Color 1:', value='#fff800') #picker3 = ColorPicker(description='Color 2:', value='#fff800') picker1.observe(color_picker1_handler, names='value') #picker2.observe(color_picker2_handler, names='value') #picker3.observe(color_picker3_handler, names='value') color_list = Dropdown(disabled=False, options=[('Rainbow', 1), ('Classic', 2), ('Log', 3), ('RGB Max Iter', 4), ('Rainbow 2', 5)], value=jgrid.settings.color_mode, description='Color Mode:', tooltip='Select built-in coloring options') color_list.observe(color_select_handler, names='value') draw_fractal(canvases, jgrid.tile_list) display_info(canvases, jgrid) return AppLayout(center=canvases, header=HBox((iter_slider, bump_ud_slider, bump_lr_slider, zoom_slider)), right_sidebar=VBox( (picker1, color_list, hue_slider, sat_slider, val_slider, modulo_slider)), footer=HBox( (bleft_button, bright_button, bup_button, bdown_button, color_it_button, juliabrot_button, reset_button, undo_button, save_button)))
class Board: def __init__(self, scale=3, buckets_height=150): self.scale = scale self.buckets_height = buckets_height self.toposim = TopographySimulator() self.particles = Particles(self.toposim, scale) self.buckets = Buckets(self.particles, scale) self.setup_canvas() self.setup_play_widgets() self.setup_particles_widgets() self.setup_toposim_widgets() self.setup_layout() self.process = None self._running = False def setup_canvas(self): # canvas 0: topography # canvas 1: particles # canvas 2: buckets canvas_size = (self.scale * self.toposim.shape[0], self.scale * self.toposim.shape[1] + self.buckets_height) self.canvas = MultiCanvas(ncanvases=3, size=canvas_size) self.canvas.on_client_ready(self.redraw) def setup_play_widgets(self): self.play_widgets = { 'start': Button(description="Start", icon='play'), 'stop': Button(description="Stop/Reset", icon='stop', disabled=True) } self.play_widgets['start'].on_click(self.start) self.play_widgets['stop'].on_click(self.stop) def setup_particles_widgets(self): self.particles_labels = { 'size': Label(value='Number of particles'), 'speed': Label(value='Particle "speed"') } self.particles_widgets = { 'size': IntSlider(value=10000, min=500, max=15000, step=500), 'speed': FloatSlider(value=0.5, min=0.1, max=1., step=0.1) } self.particles_widgets['size'].observe(self.on_change_size, names='value') self.particles_widgets['speed'].observe(self.on_change_speed, names='value') def on_change_size(self, change): self.particles.n_particles = change.new self.initialize() def on_change_speed(self, change): self.particles.speed_factor = change.new def setup_toposim_widgets(self): self.toposim_labels = { 'kf': Label(value='River incision coefficient'), 'g': Label(value='River transport coefficient'), 'kd': Label(value='Hillslope diffusivity'), 'p': Label(value='Flow partition exponent'), 'u': Label(value='Plateau uplift rate') } self.toposim_widgets = { 'kf': FloatSlider(value=1e-4, min=5e-5, max=3e-4, step=1e-5, readout_format='.1e'), 'g': FloatSlider(value=1., min=0.5, max=1.5, step=0.1, readout_format='.1f'), 'kd': FloatSlider( value=0.02, min=0., max=0.1, step=0.01, ), 'p': FloatSlider(value=1., min=0., max=10., step=0.2, readout_format='.1f'), 'u': FloatSlider(value=0., min=0., max=1e-3, step=1e-5, readout_format='.1e') } def set_erosion_params(self): self.toposim.set_erosion_params(kf=self.toposim_widgets['kf'].value, g=self.toposim_widgets['g'].value, kd=self.toposim_widgets['kd'].value, p=self.toposim_widgets['p'].value, u=self.toposim_widgets['u'].value) def setup_layout(self): play_box = HBox(tuple(self.play_widgets.values())) particles_hboxes = [] for k in self.particles_widgets: self.particles_labels[k].layout = Layout(width='200px') self.particles_widgets[k].layout = Layout(width='200px') particles_hboxes.append( HBox([self.particles_labels[k], self.particles_widgets[k]])) particles_label = HTML(value='<b>Particles parameters</b>') particles_box = VBox(particles_hboxes) particles_box.layout = Layout(grid_gap='6px') toposim_hboxes = [] for k in self.toposim_widgets: self.toposim_labels[k].layout = Layout(width='200px') self.toposim_widgets[k].layout = Layout(width='200px') toposim_hboxes.append( HBox([self.toposim_labels[k], self.toposim_widgets[k]])) toposim_label = HTML( value='<b>Landscape evolution model parameters</b>') toposim_box = VBox(toposim_hboxes) toposim_box.layout = Layout(grid_gap='6px') control_box = VBox((play_box, particles_label, particles_box, toposim_label, toposim_box)) control_box.layout = Layout(grid_gap='10px') self.main_box = HBox((self.canvas, control_box)) self.main_box.layout = Layout(grid_gap='30px') def initialize(self): self.toposim.initialize() self.particles.initialize() self.buckets.initialize() self.redraw() def run(self): while self._running and not self.buckets.all_in_buckets: self.set_erosion_params() self.toposim.run_step() self.particles.run_step() self.buckets.run_step() self.redraw() self.draw_winner() self.play_widgets['stop'].description = "Reset" self.play_widgets['stop'].icon = "retweet" def toggle_disabled(self): for w in self.play_widgets.values(): w.disabled = not w.disabled w = self.particles_widgets['size'] w.disabled = not w.disabled def start(self, b): self.process = Thread(target=self.run) self._running = True self.process.start() self.toggle_disabled() def stop(self, b): self._running = False self.process.join() self.reset() self.toggle_disabled() def reset(self): self.toposim.reset() self.particles.reset() self.buckets.reset() self.redraw() self.play_widgets['stop'].description = "Stop/Reset" self.play_widgets['stop'].icon = "stop" def redraw(self): self.draw_topography() self.draw_particles() self.draw_buckets() def draw_topography(self): with hold_canvas(self.canvas[0]): self.canvas[0].save() self.canvas[0].scale(self.scale) self.canvas[0].clear() self.canvas[0].put_image_data(self.toposim.shaded_topography, 0, 0) self.canvas[0].restore() def draw_particles(self): x, y = self.particles.positions with hold_canvas(self.canvas[1]): self.canvas[1].clear() self.canvas[1].global_alpha = 0.4 self.canvas[1].fill_style = '#3378b8' self.canvas[1].fill_rects(x, y, self.particles.sizes) def draw_buckets(self): xsize, ysize = self.canvas[2].size with hold_canvas(self.canvas[2]): self.canvas[2].clear() self.canvas[2].font = '20px serif' self.canvas[2].fill_style = 'black' for i, x in enumerate(self.buckets.x_separators[0:-1]): self.canvas[2].fill_text(f"{i+1:02d}", x + 15, ysize - 120) self.canvas[2].fill_rects(self.buckets.x_separators, self.toposim.shape[0] * self.scale, 1, self.buckets_height) self.canvas[2].fill_style = '#3378b8' self.canvas[2].fill_rects(self.buckets.x_separators + 5, ysize - self.buckets.bar_heights, self.buckets.bar_width - 10, self.buckets.bar_heights) self.canvas[2].fill_style = 'black' self.canvas[2].fill_rect(0, ysize - 3, xsize, 3) self.canvas[2].fill_rect(0, ysize - 155, xsize, 10) def draw_winner(self): xsize, ysize = self.canvas[2].size winner = self.buckets.count.argmax() self.canvas[2].font = '50px serif' self.canvas[2].fill_style = '#3378b8' self.canvas[2].fill_text(f"{winner+1:02d} wins!", xsize // 3, ysize // 2.5) def show(self): self.initialize() return self.main_box
class BBoxCanvas(HBox, traitlets.HasTraits): debug_output = widgets.Output(layout={'border': '1px solid black'}) image_path = traitlets.Unicode() bbox_coords = traitlets.Dict() _canvas_bbox_coords = traitlets.Dict() _image_scale = traitlets.Float() def __init__(self, width, height): super().__init__() self.is_drawing = False self._start_point = () self._image_scale = 1.0 self._bg_layer = 0 self._image_layer = 1 self._box_layer = 2 # Define each of the children... self._image = Image(layout=Layout(display='flex', justify_content='center', align_items='center', align_content='center')) self._multi_canvas = MultiCanvas(3, width=width, height=height) self._im_name_box = Label() children = [VBox([self._multi_canvas, self._im_name_box])] self.children = children draw_bg(self._multi_canvas[self._bg_layer]) # link drawing events self._multi_canvas[self._box_layer].on_mouse_move(self._update_pos) self._multi_canvas[self._box_layer].on_mouse_down(self._start_drawing) self._multi_canvas[self._box_layer].on_mouse_up(self._stop_drawing) @debug_output.capture(clear_output=False) def _update_pos(self, x, y): if self.is_drawing: self._canvas_bbox_coords = points2bbox_coords( *self._start_point, x, y) @debug_output.capture(clear_output=True) def _start_drawing(self, x, y): self._start_point = (x, y) self.is_drawing = True @debug_output.capture(clear_output=False) def _stop_drawing(self, x, y): self.is_drawing = False self.bbox_coords = { k: v / self._image_scale for k, v in self._canvas_bbox_coords.items() } @traitlets.observe('bbox_coords') def _update_canvas_bbox_coords(self, change): self._canvas_bbox_coords = { k: v * self._image_scale for k, v in self.bbox_coords.items() } @traitlets.observe('_canvas_bbox_coords') def _draw_bbox(self, change): if not self._canvas_bbox_coords: self._clear_bbox() return coords = [ self._canvas_bbox_coords['x'], self._canvas_bbox_coords['y'], self._canvas_bbox_coords['width'], self._canvas_bbox_coords['height'] ] draw_bounding_box(self._multi_canvas[self._box_layer], coords, color='white', border_ratio=2, clear=True) def _clear_bbox(self): self._multi_canvas[self._box_layer].clear() @traitlets.observe('image_path') def _draw_image(self, image): self._image_scale = draw_img(self._multi_canvas[self._image_layer], self.image_path, clear=True) self._im_name_box.value = Path(self.image_path).name @property def image_scale(self): return self._image_scale def _clear_image(self): self._multi_canvas[self._image_layer].clear() # needed to support voila # https://ipycanvas.readthedocs.io/en/latest/advanced.html#ipycanvas-in-voila def observe_client_ready(self, cb=None): self._multi_canvas.on_client_ready(cb)
def __init__(self, size=(400, 400)): self._size = size self._canvas = MultiCanvas(width=size[0], height=size[1]) self._turtle = Image.from_file( pathlib.Path(__file__).parent / "turtle.png") self.clear()
def create_canvases(self): self.canvases = MultiCanvas(n_canvases=self.num_canvases, width=self.total_width, height=self.total_height, sync_image_data=True)
class Turtle: def __init__(self, size=(400, 400)): self._size = size self._canvas = MultiCanvas(width=size[0], height=size[1]) self._turtle = Image.from_file( pathlib.Path(__file__).parent / "turtle.png") self.clear() def clear(self): """Clear the canvas and start over.""" self._canvas.clear() self._current = (self._size[0] // 2, self._size[1] // 2) self._cur_heading = (3 * math.pi) / 2 # in Canvas Y is negative. self._pendown = True self._show = True self._draw_turtle() def _draw_turtle(self): """Update the position of the turtle.""" with hold_canvas(self._canvas[2]): self._canvas[2].clear() self._canvas[2].reset_transform() if self._show: self._canvas[2].translate(self._current[0], self._current[1]) self._canvas[2].rotate(self._cur_heading - (3 * math.pi) / 2) self._canvas[2].draw_image(self._turtle, x=-15, y=-15, \ width=30, height=30) def draw(self, distance): """Move the pen by distance.""" start = self._current self._current = (self._current[0] + math.cos(self._cur_heading) * distance, self._current[1] + math.sin(self._cur_heading) * distance) if self._pendown: self._canvas[1].begin_path() self._canvas[1].move_to(*start) self._canvas[1].line_to(*self._current) self._canvas[1].stroke() self._draw_turtle() def turn(self, degrees): """Turn the pen by degrees""" self._cur_heading = (self._cur_heading - math.radians(degrees)) % (math.pi * 2) self._draw_turtle() def goto(self, x, y): """Goto a point in the coordinate space.""" start = self._current self._current = (self._size[0] // 2 + x, self._size[1] // 2 - y) if self._pendown: self._canvas[1].begin_path() self._canvas[1].move_to(*start) self._canvas[1].line_to(*self._current) self._canvas[1].stroke() self._draw_turtle() def heading(self, heading): """Set the pen to face heading.""" self._cur_heading = -math.radians(heading) self._draw_turtle() def up(self): """Pick the pen up. Movements won't make lines.""" self._pendown = False def down(self): """Put the pen down. Movements will make lines.""" self._pendown = True def color(self, color): """Set the pen color.""" self._canvas[1].stroke_style = color def width(self, width): """Set the line thickness.""" self._canvas[1].line_width = width def show(self): """Show the turtle in the scene.""" self._show = True self._draw_turtle() def hide(self): """Hide the turtle in the scene.""" self._show = False self._draw_turtle() def background(self, filename): """Set a background image.""" img = Image.from_file(filename) self._canvas[0].draw_image(img, x=0, y=0, \ width=self._canvas[0].size[0], height=self._canvas[0].size[1]) def _ipython_display_(self): display(self._canvas)