Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets
1import numpy as np 2import imageio 3 4from .drawing import Drawing 5 6 7def render_svg_frames(frames, align_bottom=False, align_right=False, 8 bg=(255,)*4, **kwargs): 9 arr_frames = [imageio.imread(d.rasterize().pngData) 10 for d in frames] 11 max_width = max(map(lambda arr:arr.shape[1], arr_frames)) 12 max_height = max(map(lambda arr:arr.shape[0], arr_frames)) 13 14 def mod_frame(arr): 15 new_arr = np.zeros((max_height, max_width) + arr.shape[2:], 16 dtype=arr.dtype) 17 new_arr[:,:] = bg[:new_arr.shape[-1]] 18 if align_bottom: 19 slice0 = slice(-arr.shape[0], None) 20 else: 21 slice0 = slice(None, arr.shape[0]) 22 if align_right: 23 slice1 = slice(-arr.shape[1], None) 24 else: 25 slice1 = slice(None, arr.shape[1]) 26 new_arr[slice0, slice1] = arr 27 return new_arr 28 return list(map(mod_frame, arr_frames)) 29 30def save_video(frames, file, **kwargs): 31 ''' 32 Save a series of drawings as a GIF or video. 33 34 Arguments: 35 frames: A list of `Drawing`s or a list of `numpy.array`s. 36 file: File name or file like object to write the video to. The 37 extension determines the output format. 38 align_bottom: If frames are different sizes, align the bottoms of each 39 frame in the video. 40 align_right: If frames are different sizes, align the right edge of each 41 frame in the video. 42 bg: If frames are different sizes, fill the background with this color. 43 (default is white: (255, 255, 255, 255)) 44 duration: If writing a GIF, sets the duration of each frame. 45 fps: If writing a video, sets the frame rate in FPS. 46 **kwargs: Other arguments to imageio.mimsave(). 47 48 ''' 49 if isinstance(frames[0], Drawing): 50 frames = render_svg_frames(frames, **kwargs) 51 kwargs.pop('align_bottom', None) 52 kwargs.pop('align_right', None) 53 kwargs.pop('bg', None) 54 imageio.mimsave(file, frames, **kwargs)