%pylab inline from JSAnimation.IPython_display import display_animation #http://nbviewer.ipython.org/url/jakevdp.github.io/downloads/notebooks/MagicTriangle.ipynb from matplotlib import animation from scipy.spatial import Delaunay def mark_triangulation_angles(ax,triangulation): points = triangulation.points def normang(a): while(a>180): a = a - 360 while (a<-180): a = a + 360 return a def at2(v): return normang( np.rad2deg( np.arctan2(*v[::-1]) ) ) def center_ang(a1,a2): c = (a1+a2)/2.0 if (a1-a2) > 180: c += 180 return normang(c) def dist_ang(a1,a2): d = np.abs(a1 - a2) if d > 180: d = 360 - d return d for triangle in triangulation.vertices: ang0s = at2( points[triangle[1]]-points[triangle[0]] ) ang0e = at2( points[triangle[2]]-points[triangle[0]] ) ang1s = at2( points[triangle[0]]-points[triangle[1]] ) ang1e = at2( points[triangle[2]]-points[triangle[1]] ) ang2s = at2( points[triangle[0]]-points[triangle[2]] ) ang2e = at2( points[triangle[1]]-points[triangle[2]] ) angs = [ (ang0s,ang0e),(ang1s,ang1e), (ang2s,ang2e)] for i in range(len(angs)): s = min(angs[i]) e = max(angs[i]) angs[i] = (s,e) if e-s > 180: angs[i] = (e,s) for i,ang in enumerate(angs): p = matplotlib.patches.Arc(xy=points[triangle[i]],width=.4,height=.4,angle=0,theta1=ang[0],theta2=ang[1] ) center = np.deg2rad( center_ang(ang[0], ang[1]) ) xy_offset = np.array([ np.cos(center),np.sin(center) ]) xy_offset *= 48 s = r'$%4.2f^{\circ}$'%(dist_ang(ang[0],ang[1])) ax.annotate(s, xy=points[triangle[i]], xytext=xy_offset, xycoords='data', textcoords='offset points', va="center", ha="center",) p.set_color(ax._get_lines.color_cycle.next()) ax.add_patch(p) def make_frame(ax,leftness): height = .75 #leftness = 1.5 points = np.array([ [0,0],[2,0],[leftness,height],[leftness,-height]]) tri = Delaunay(points) ax.triplot(points[:,0], points[:,1], tri.vertices.copy()) ax.plot(points[:,0], points[:,1], 'o') ax.set_xlim(-.1,2.1) ax.set_ylim(-.8,.8) ax.set_aspect('equal') mark_triangulation_angles(ax,tri) ax.plot() #make_frame(plt.gca(),1.6) #static frame fig = plt.gcf() ax = plt.gca() Nframes = 10 def animate(frame): ax.clear() leftness = 1.5 + .3 * float(frame)/Nframes make_frame(ax,leftness) anim = animation.FuncAnimation(fig, animate, frames=Nframes, interval=100) display_animation(anim, default_mode='reflect') pre_pad = 3 post_pad = 3 #indirection of frames hold, forward, hold, reverse iframe = [0]*pre_pad + range(Nframes) + [Nframes-1]*post_pad + range(Nframes-1,0,-1) def animate_as_gif(nframe): return animate(iframe[nframe]) anim = animation.FuncAnimation(fig, animate_as_gif, frames=len(iframe), interval=100) anim.save('delaunay_not_minimum_edge_length.gif', writer='imagemagick')