def animated_bars(sort_func, data, interval): """Create a sort animation showing each list element as a vertical bar.""" # Run the entire sort, remembering all intermediate states states = [list(data)] def save_state(*_): states.append(list(data)) sort.run(sort_func, data, save_state) save_state() # Final state fig = plt.figure() ax = fig.add_subplot(1, 1, 1) bars = ax.bar(x=range(len(data)), height=list(data)) plt.xticks([]) plt.yticks([]) plt.close() def animate(i): for b, h in zip(bars, states[i]): b.set_height(h) return bars return FuncAnimation(fig, animate, frames=len(states), interval=interval)
def __init__(self, fig, sort_func, data): # Create the animation objects # Artists are scaled according to aspect ratio. We'll need to undo # this to draw circles. xsize, ysize = fig.get_size_inches() yscale = xsize / ysize # This magic invisible line makes the figure show up fig.lines.append( lines.Line2D([0, 0], [0, 1], transform=fig.transFigure, figure=fig, color='white')) self._spacing = 1.0 / (len(data) + 1) self._radius = 0.8 * self._spacing smallest = min(*data) largest = max(*data) def scaled_radius(value): interp = (value - smallest) / (largest - smallest) return self._radius * (0.6 + interp * 0.4) def create_artists(i, v): x = (i + 0.5) * self._spacing y = 0.5 r = scaled_radius(v) c = patches.Ellipse((x, y), r, yscale * r, transform=fig.transFigure, figure=fig, fill=False) t = text.Text(x, y, str(v), transform=fig.transFigure, figure=fig, verticalalignment='center', horizontalalignment='center', fontsize=300 * r) return c, t def create_arrow(): return patches.Polygon(self._arrow_points(), closed=True, transform=fig.transFigure, figure=fig, visible=False) self._circles, self._texts = map( list, zip(*[create_artists(i, v) for i, v in enumerate(data)])) self._arrows = [create_arrow(), create_arrow()] fig.patches.extend(self._circles) fig.patches.extend(self._arrows) fig.texts.extend(self._texts) self._label = text.Text(0, 0.9, transform=fig.transFigure, figure=fig, verticalalignment='top', horizontalalignment='left', fontsize=200 * self._spacing) fig.texts.append(self._label) # Collect effects and generate animation frames effects = [] sort.run(sort_func, data, lambda *e: effects.append(e)) self._generate_frames(effects) self._focused = []
def test_sort_works(self, xs): correct = list(sorted(xs)) sort.run(sort.quicksort, xs) self.assertEqual(correct, xs)
def test_sort_works(self, xs): correct = list(sorted(xs)) sort.run(sort.merge_sort, xs) assert correct == xs