def construct(self): GraphScene.construct(self) self.generate_spanning_tree() self.generate_treeified_spanning_tree() branches = self.spanning_tree.split() branches_copy = deepcopy(branches) treeified_branches = self.treeified_spanning_tree.split() tree = TextMobject("``Tree''").to_edge(UP) spanning_tree = TextMobject("``Spanning Tree''").to_edge(UP) self.add(*branches) self.play( FadeOut(Mobject(*self.edges + self.vertices)), Animation(Mobject(*branches)), ) self.clear() self.add(tree, *branches) self.wait() self.play(*[ Transform(b1, b2, run_time=2) for b1, b2 in zip(branches, treeified_branches) ]) self.wait() self.play(*[FadeIn(mob) for mob in self.edges + self.vertices] + [ Transform(b1, b2, run_time=2) for b1, b2 in zip(branches, branches_copy) ]) self.accent_vertices(run_time=2) self.remove(tree) self.add(spanning_tree) self.wait(2)
def construct(self): time_per_branch = 0.5 text = TextMobject( """ In any tree: $$E + 1 = V$$ """ ) gs = GraphScene(SampleGraph()) gs.generate_treeified_spanning_tree() branches = gs.treeified_spanning_tree.to_edge(LEFT).split() all_dots = [Dot(branches[0].points[0])] self.add(text, all_dots[0]) for branch in branches: self.play(ShowCreation(branch), run_time=time_per_branch) dot = Dot(branch.points[-1]) self.add(dot) all_dots.append(dot) self.dither() self.remove(*all_dots) self.play( FadeOut(text), FadeIn(Mobject(*gs.edges + gs.vertices)), *[Transform(*pair) for pair in zip(branches, gs.spanning_tree.split())] )
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.add(TextMobject("Duality").to_edge(UP)) self.remove(*self.vertices) def special_alpha(t): if t > 0.5: t = 1 - t if t < 0.25: return smooth(4 * t) else: return 1 kwargs = {"run_time": 5.0, "rate_func": special_alpha} self.play(*[ Transform(*edge_pair, **kwargs) for edge_pair in zip(self.edges, self.dual_edges) ] + [ Transform(Mobject(*[self.vertices[index] for index in cycle]), dv, **kwargs) for cycle, dv in zip(self.graph.region_cycles, self.dual_vertices) ]) self.wait()
def construct(self): GraphScene.construct(self) rot_kwargs = {"radians": np.pi / 3, "run_time": 5.0} vertices = [point / 2 + OUT if abs(point[0]) == 2 else point + IN for point in self.points] cube = Mobject(*[Line(vertices[edge[0]], vertices[edge[1]]) for edge in self.graph.edges]) cube.rotate(-np.pi / 3, [0, 0, 1]) cube.rotate(-np.pi / 3, [0, 1, 0]) dots_to_vertices = TextMobject("Dots $\\to$ Vertices").to_corner() lines_to_edges = TextMobject("Lines $\\to$ Edges").to_corner() regions_to_faces = TextMobject("Regions $\\to$ Faces").to_corner() self.clear() # self.play(TransformAnimations( # Rotating(Dodecahedron(), **rot_kwargs), # Rotating(cube, **rot_kwargs) # )) self.play(Rotating(cube, **rot_kwargs)) self.clear() self.play(*[Transform(l1, l2) for l1, l2 in zip(cube.split(), self.edges)]) self.dither() self.add(dots_to_vertices) self.play(*[ShowCreation(dot, run_time=1.0) for dot in self.vertices]) self.dither(2) self.remove(dots_to_vertices, *self.vertices) self.add(lines_to_edges) self.play(ApplyMethod(Mobject(*self.edges).highlight, "yellow")) self.dither(2) self.clear() self.add(*self.edges) self.add(regions_to_faces) self.generate_regions() for region in self.regions: self.highlight_region(region) self.dither(3.0)
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.add(TextMobject("Duality").to_edge(UP)) self.remove(*self.vertices) def special_alpha(t): if t > 0.5: t = 1 - t if t < 0.25: return smooth(4*t) else: return 1 kwargs = { "run_time" : 5.0, "rate_func" : special_alpha } self.play(*[ Transform(*edge_pair, **kwargs) for edge_pair in zip(self.edges, self.dual_edges) ] + [ Transform( Mobject(*[ self.vertices[index] for index in cycle ]), dv, **kwargs ) for cycle, dv in zip( self.graph.region_cycles, self.dual_vertices ) ]) self.dither()
def construct(self): GraphScene.construct(self) paths = [(1, 2, 4, 5, 6), (6, 7, 1, 3)] non_paths = [[(0, 1), (7, 8), (5, 6)], [(5, 0), (0, 2), (0, 1)]] valid_path = TextMobject("Valid \\\\ Path").highlight("green") not_a_path = TextMobject("Not a \\\\ Path").highlight("red") for mob in valid_path, not_a_path: mob.to_edge(UP) kwargs = {"run_time": 1.0} for path, non_path in zip(paths, non_paths): path_lines = Mobject( *[ Line(self.points[path[i]], self.points[path[i + 1]]).highlight("yellow") for i in range(len(path) - 1) ] ) non_path_lines = Mobject( *[Line(self.points[pp[0]], self.points[pp[1]]).highlight("yellow") for pp in non_path] ) self.remove(not_a_path) self.add(valid_path) self.play(ShowCreation(path_lines, **kwargs)) self.dither(2) self.remove(path_lines) self.remove(valid_path) self.add(not_a_path) self.play(ShowCreation(non_path_lines, **kwargs)) self.dither(2) self.remove(non_path_lines)
def construct(self): GraphScene.construct(self) account = ImageMobject("facebook_silhouette", invert = False) account.scale(0.05) logo = ImageMobject("facebook_logo", invert = False) logo.scale(0.1) logo.shift(0.2*LEFT + 0.1*UP) account.add(logo).center() account.shift(0.2*LEFT + 0.1*UP) friends = TexMobject( "\\leftarrow \\text{friends} \\rightarrow" ).scale(0.5*EDGE_ANNOTATION_SCALE_VAL) self.clear() accounts = [ deepcopy(account).shift(point) for point in self.points ] self.add(*accounts) self.dither() self.annotate_edges(friends) self.dither() self.play(*[ CounterclockwiseTransform(account, vertex) for account, vertex in zip(accounts, self.vertices) ]) self.dither() self.play(*[ Transform(ann, edge) for ann, edge in zip(self.edge_annotations, self.edges) ]) self.dither()
def construct(self): GraphScene.construct(self) self.generate_spanning_tree() self.generate_treeified_spanning_tree() branches = self.spanning_tree.split() branches_copy = deepcopy(branches) treeified_branches = self.treeified_spanning_tree.split() tree = TextMobject("``Tree''").to_edge(UP) spanning_tree = TextMobject("``Spanning Tree''").to_edge(UP) self.add(*branches) self.play(FadeOut(Mobject(*self.edges + self.vertices)), Animation(Mobject(*branches))) self.clear() self.add(tree, *branches) self.dither() self.play(*[Transform(b1, b2, run_time=2) for b1, b2 in zip(branches, treeified_branches)]) self.dither() self.play( *[FadeIn(mob) for mob in self.edges + self.vertices] + [Transform(b1, b2, run_time=2) for b1, b2 in zip(branches, branches_copy)] ) self.accent_vertices(run_time=2) self.remove(tree) self.add(spanning_tree) self.dither(2)
def construct(self): GraphScene.construct(self) self.generate_regions() self.generate_dual_graph() region_mobs = [ImageMobject(disp.paint_region(reg, self.background), invert=False) for reg in self.regions] for region, mob in zip(self.regions, region_mobs): self.highlight_region(region, mob.get_color()) outer_region = self.regions.pop() outer_region_mob = region_mobs.pop() outer_dual_vertex = self.dual_vertices.pop() internal_edges = filter( lambda e: abs(e.start[0]) < SPACE_WIDTH and abs(e.end[0]) < SPACE_WIDTH and abs(e.start[1]) < SPACE_HEIGHT and abs(e.end[1]) < SPACE_HEIGHT, self.dual_edges, ) external_edges = filter(lambda e: e not in internal_edges, self.dual_edges) self.dither() self.reset_background() self.highlight_region(outer_region, outer_region_mob.get_color()) self.play(*[Transform(reg_mob, dot) for reg_mob, dot in zip(region_mobs, self.dual_vertices)]) self.dither() self.reset_background() self.play(ApplyFunction(lambda p: (SPACE_WIDTH + SPACE_HEIGHT) * p / np.linalg.norm(p), outer_region_mob)) self.dither() for edges in internal_edges, external_edges: self.play(*[ShowCreation(edge, run_time=2.0) for edge in edges]) self.dither()
def construct(self): GraphScene.construct(self) account = ImageMobject("facebook_silhouette", invert=False) account.scale(0.05) logo = ImageMobject("facebook_logo", invert=False) logo.scale(0.1) logo.shift(0.2 * LEFT + 0.1 * UP) account.add(logo).center() account.shift(0.2 * LEFT + 0.1 * UP) friends = TexMobject("\\leftarrow \\text{friends} \\rightarrow").scale( 0.5 * EDGE_ANNOTATION_SCALE_FACTOR) self.clear() accounts = [deepcopy(account).shift(point) for point in self.points] self.add(*accounts) self.wait() self.annotate_edges(friends) self.wait() self.play(*[ CounterclockwiseTransform(account, vertex) for account, vertex in zip(accounts, self.vertices) ]) self.wait() self.play(*[ Transform(ann, edge) for ann, edge in zip(self.edge_annotations, self.edges) ]) self.wait()
class GraphWidget(QtGui.QGraphicsView): def __init__(self, index, parent=None): super(GraphWidget, self).__init__(parent) self.index = index self.createWidgets() self.updateWidgets() def mouseMoveEvent(self, event): super(GraphWidget, self).mouseMoveEvent(event) pt = event.pos() self.statusBarShowMessage('Coordinate (%2.f, %2.f)' % (pt.x(), pt.y())) def createWidgets(self): self.scene = GraphScene(self) self.scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex) self.scene.setSceneRect(-200, -200, 400, 400) def updateWidgets(self): self.setObjectName('GraphWidget-%d' % self.index) self.setScene(self.scene) self.setRenderHint(QtGui.QPainter.Antialiasing) self.scale(0.8, 0.8) self.setMinimumSize(400, 400) self.setWindowTitle( QtGui.QApplication.translate('GraphWidget-%d' % self.index, 'Polygon Area', None, QtGui.QApplication.UnicodeUTF8)) self.setMouseTracking(True) def statusBarShowMessage(self, st): qst = QtCore.QString(st) mainWindow = QtGui.qApp.mainWindow mainWindow.statusBar().showMessage(qst)
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.generate_regions() randy = Randolph().shift(LEFT) morty = Mortimer().shift(RIGHT) name = TextMobject("Mortimer") name.shift(morty.get_center() + 1.2*UP) randy_path = (0, 1, 3) morty_path = (-2, -3, -4) morty_crossed_lines = [ Line(self.points[i], self.points[j]).highlight("red") for i, j in [(7, 1), (1, 5)] ] kwargs = {"run_time" : 1.0} self.clear() self.add(randy) self.dither() self.add(morty, name) self.dither() self.remove(name) small_randy = deepcopy(randy).scale(RANDOLPH_SCALE_VAL) small_morty = deepcopy(morty).scale(RANDOLPH_SCALE_VAL) small_randy.move_to(self.points[randy_path[0]]) small_morty.move_to(self.dual_points[morty_path[0]]) self.play(*[ FadeIn(mob) for mob in self.vertices + self.edges ] + [ Transform(randy, small_randy), Transform(morty, small_morty), ], **kwargs) self.dither() self.highlight_region(self.regions[morty_path[0]]) for last, next in zip(morty_path, morty_path[1:]): self.play(WalkPiCreature(morty, self.dual_points[next]),**kwargs) self.highlight_region(self.regions[next]) self.dither() for last, next in zip(randy_path, randy_path[1:]): line = Line(self.points[last], self.points[next]) line.highlight("yellow") self.play( WalkPiCreature(randy, self.points[next]), ShowCreation(line), **kwargs ) self.dither() self.play(*[ ApplyMethod( line.rotate_in_place, np.pi/10, rate_func = wiggle) for line in morty_crossed_lines ], **kwargs) self.dither()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.add(TextMobject("Dual Graph").to_edge(UP).shift(2 * LEFT)) self.play(*[ ShowCreation(mob) for mob in self.dual_edges + self.dual_vertices ]) self.wait()
def construct(self): GraphScene.construct(self) point_path = [self.points[i] for i in self.path] randy = Randolph() randy.scale(RANDOLPH_SCALE_VAL) randy.move_to(point_path[0]) for next, last in zip(point_path[1:], point_path): self.play(WalkPiCreature(randy, next), ShowCreation(Line(last, next).highlight("yellow")), run_time=2.0) self.randy = randy
def construct(self): GraphScene.construct(self) randy = Randolph().move_to((-3, 0, 0)) name = TextMobject("Randolph") self.play(Transform(randy, deepcopy(randy).scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]))) self.dither() name.shift((0, 1, 0)) self.add(name) self.dither()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.add(TextMobject("Dual Graph").to_edge(UP).shift(2*LEFT)) self.play(*[ ShowCreation(mob) for mob in self.dual_edges + self.dual_vertices ]) self.dither()
def construct(self): GraphScene.construct(self) randy = Randolph() randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]) dollar_signs = TextMobject("\\$\\$") dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL) dollar_signs = Mobject(*[ deepcopy(dollar_signs).shift(edge.get_center()) for edge in self.edges ]) unneeded = TextMobject("unneeded!") unneeded.scale(EDGE_ANNOTATION_SCALE_VAL) self.generate_spanning_tree() def green_dot_at_index(index): return Dot( self.points[index], radius = 2*Dot.DEFAULT_RADIUS, color = "lightgreen", ) def out_of_spanning_set(point_pair): stip = self.spanning_tree_index_pairs return point_pair not in stip and \ tuple(reversed(point_pair)) not in stip self.add(randy) self.accent_vertices(run_time = 2.0) self.add(dollar_signs) self.dither(2) self.remove(dollar_signs) run_time_per_branch = 0.5 self.play( ShowCreation(green_dot_at_index(0)), run_time = run_time_per_branch ) for pair in self.spanning_tree_index_pairs: self.play(ShowCreation( Line( self.points[pair[0]], self.points[pair[1]] ).highlight("yellow"), run_time = run_time_per_branch )) self.play(ShowCreation( green_dot_at_index(pair[1]), run_time = run_time_per_branch )) self.dither(2) unneeded_edges = filter(out_of_spanning_set, self.graph.edges) for edge, limit in zip(unneeded_edges, range(5)): line = Line(self.points[edge[0]], self.points[edge[1]]) line.highlight("red") self.play(ShowCreation(line, run_time = 1.0)) self.add(unneeded.center().shift(line.get_center() + 0.2*UP)) self.dither() self.remove(line, unneeded)
def construct(self): GraphScene.construct(self) tweaked_graph = deepcopy(self.graph) for index in 2, 4: tweaked_graph.vertices[index] += 2.8*RIGHT + 1.8*DOWN tweaked_self = GraphScene(tweaked_graph) edges_to_remove = [ self.edges[self.graph.edges.index(pair)] for pair in [(4, 5), (0, 5), (1, 5), (7, 1), (8, 3)] ] connected, planar, graph = TextMobject([ "Connected ", "Planar ", "Graph" ]).to_edge(UP).split() not_okay = TextMobject("Not Okay").highlight("red") planar_explanation = TextMobject(""" (``Planar'' just means we can draw it without intersecting lines) """, size = "\\small") planar_explanation.shift(planar.get_center() + 0.5*DOWN) self.draw_vertices() self.draw_edges() self.clear() self.add(*self.vertices + self.edges) self.dither() self.add(graph) self.dither() kwargs = { "rate_func" : there_and_back, "run_time" : 5.0 } self.add(not_okay) self.play(*[ Transform(*pair, **kwargs) for pair in zip( self.edges + self.vertices, tweaked_self.edges + tweaked_self.vertices, ) ]) self.remove(not_okay) self.add(planar, planar_explanation) self.dither(2) self.remove(planar_explanation) self.add(not_okay) self.remove(*edges_to_remove) self.play(ShowCreation( Mobject(*edges_to_remove), rate_func = lambda t : 1 - t, run_time = 1.0 )) self.dither(2) self.remove(not_okay) self.add(connected, *edges_to_remove) self.dither()
def construct(self): GraphScene.construct(self) self.generate_spanning_tree() self.generate_dual_graph() self.generate_regions() randy = Randolph().scale(RANDOLPH_SCALE_VAL) morty = Mortimer().scale(RANDOLPH_SCALE_VAL) randy.move_to(self.points[0]) morty.move_to(self.dual_points[0]) attempted_dual_point_index = 2 region_ordering = [0, 1, 7, 2, 3, 5, 4, 6] dual_edges = [1, 3, 4, 7, 11, 9, 13] time_per_dual_edge = 0.5 self.add(randy, morty) self.play(ShowCreation(self.spanning_tree)) self.dither() self.play( WalkPiCreature( morty, self.dual_points[attempted_dual_point_index], alpha_func=lambda t: 0.3 * there_and_back(t), run_time=2.0, ) ) self.dither() for index in range(len(self.regions)): # if index > 0: # edge = self.edges[dual_edges[index-1]] # midpoint = edge.get_center() # self.play(*[ # ShowCreation(Line( # midpoint, # tip # ).highlight("red")) # for tip in edge.start, edge.end # ], run_time = time_per_dual_edge) self.highlight_region(self.regions[region_ordering[index]]) self.dither(time_per_dual_edge) self.dither() cycle_index = region_ordering[-1] cycle = self.graph.region_cycles[cycle_index] self.highlight_region(self.regions[cycle_index], "black") self.play( ShowCreation( Mobject( *[ Line(self.points[last], self.points[next]).highlight("green") for last, next in zip(cycle, list(cycle)[1:] + [cycle[0]]) ] ) ) ) self.dither()
def construct(self): GraphScene.construct(self) point_path = [self.points[i] for i in self.path] randy = Randolph() randy.scale(RANDOLPH_SCALE_FACTOR) randy.move_to(point_path[0]) for next, last in zip(point_path[1:], point_path): self.play(WalkPiCreature(randy, next), ShowCreation(Line(last, next).highlight("yellow")), run_time=2.0) self.randy = randy
def construct(self): GraphScene.construct(self) self.generate_spanning_tree() self.generate_dual_graph() self.generate_regions() randy = Randolph().scale(RANDOLPH_SCALE_FACTOR) morty = Mortimer().scale(RANDOLPH_SCALE_FACTOR) randy.move_to(self.points[0]) morty.move_to(self.dual_points[0]) attempted_dual_point_index = 2 region_ordering = [0, 1, 7, 2, 3, 5, 4, 6] dual_edges = [1, 3, 4, 7, 11, 9, 13] time_per_dual_edge = 0.5 self.add(randy, morty) self.play(ShowCreation(self.spanning_tree)) self.wait() self.play( WalkPiCreature( morty, self.dual_points[attempted_dual_point_index], rate_func=lambda t: 0.3 * there_and_back(t), run_time=2.0, )) self.wait() for index in range(len(self.regions)): # if index > 0: # edge = self.edges[dual_edges[index-1]] # midpoint = edge.get_center() # self.play(*[ # ShowCreation(Line( # midpoint, # tip # ).highlight("red")) # for tip in edge.start, edge.end # ], run_time = time_per_dual_edge) self.highlight_region(self.regions[region_ordering[index]]) self.wait(time_per_dual_edge) self.wait() cycle_index = region_ordering[-1] cycle = self.graph.region_cycles[cycle_index] self.highlight_region(self.regions[cycle_index], "black") self.play( ShowCreation( Mobject(*[ Line(self.points[last], self.points[next]).highlight( "green") for last, next in zip(cycle, list(cycle)[1:] + [cycle[0]]) ]))) self.wait()
def construct(self): GraphScene.construct(self) randy = Randolph() randy.scale(RANDOLPH_SCALE_FACTOR).move_to(self.points[0]) dollar_signs = TextMobject("\\$\\$") dollar_signs.scale(EDGE_ANNOTATION_SCALE_FACTOR) dollar_signs = Mobject(*[ deepcopy(dollar_signs).shift(edge.get_center()) for edge in self.edges ]) unneeded = TextMobject("unneeded!") unneeded.scale(EDGE_ANNOTATION_SCALE_FACTOR) self.generate_spanning_tree() def green_dot_at_index(index): return Dot( self.points[index], radius=2 * Dot.DEFAULT_RADIUS, color="lightgreen", ) def out_of_spanning_set(point_pair): stip = self.spanning_tree_index_pairs return point_pair not in stip and \ tuple(reversed(point_pair)) not in stip self.add(randy) self.accent_vertices(run_time=2.0) self.add(dollar_signs) self.wait(2) self.remove(dollar_signs) run_time_per_branch = 0.5 self.play(ShowCreation(green_dot_at_index(0)), run_time=run_time_per_branch) for pair in self.spanning_tree_index_pairs: self.play( ShowCreation(Line(self.points[pair[0]], self.points[pair[1]]).highlight("yellow"), run_time=run_time_per_branch)) self.play( ShowCreation(green_dot_at_index(pair[1]), run_time=run_time_per_branch)) self.wait(2) unneeded_edges = filter(out_of_spanning_set, self.graph.edges) for edge, limit in zip(unneeded_edges, range(5)): line = Line(self.points[edge[0]], self.points[edge[1]]) line.highlight("red") self.play(ShowCreation(line, run_time=1.0)) self.add(unneeded.center().shift(line.get_center() + 0.2 * UP)) self.wait() self.remove(line, unneeded)
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.generate_regions() randy = Randolph().shift(LEFT) morty = Mortimer().shift(RIGHT) name = TextMobject("Mortimer") name.shift(morty.get_center() + 1.2 * UP) randy_path = (0, 1, 3) morty_path = (-2, -3, -4) morty_crossed_lines = [ Line(self.points[i], self.points[j]).highlight("red") for i, j in [(7, 1), (1, 5)] ] kwargs = {"run_time": 1.0} self.clear() self.add(randy) self.wait() self.add(morty, name) self.wait() self.remove(name) small_randy = deepcopy(randy).scale(RANDOLPH_SCALE_FACTOR) small_morty = deepcopy(morty).scale(RANDOLPH_SCALE_FACTOR) small_randy.move_to(self.points[randy_path[0]]) small_morty.move_to(self.dual_points[morty_path[0]]) self.play( *[FadeIn(mob) for mob in self.vertices + self.edges] + [ Transform(randy, small_randy), Transform(morty, small_morty), ], **kwargs) self.wait() self.highlight_region(self.regions[morty_path[0]]) for last, next in zip(morty_path, morty_path[1:]): self.play(WalkPiCreature(morty, self.dual_points[next]), **kwargs) self.highlight_region(self.regions[next]) self.wait() for last, next in zip(randy_path, randy_path[1:]): line = Line(self.points[last], self.points[next]) line.highlight("yellow") self.play(WalkPiCreature(randy, self.points[next]), ShowCreation(line), **kwargs) self.wait() self.play( *[ ApplyMethod(line.rotate_in_place, np.pi / 10, rate_func=wiggle) for line in morty_crossed_lines ], **kwargs) self.wait()
def construct(self): GraphScene.construct(self) tweaked_graph = deepcopy(self.graph) for index in 2, 4: tweaked_graph.vertices[index] += 2.8 * RIGHT + 1.8 * DOWN tweaked_self = GraphScene(tweaked_graph) edges_to_remove = [ self.edges[self.graph.edges.index(pair)] for pair in [(4, 5), (0, 5), (1, 5), (7, 1), (8, 3)] ] connected, planar, graph = TextMobject( ["Connected ", "Planar ", "Graph"]).to_edge(UP).split() not_okay = TextMobject("Not Okay").highlight("red") planar_explanation = TextMobject(""" (``Planar'' just means we can draw it without intersecting lines) """, size="\\small") planar_explanation.shift(planar.get_center() + 0.5 * DOWN) self.draw_vertices() self.draw_edges() self.clear() self.add(*self.vertices + self.edges) self.wait() self.add(graph) self.wait() kwargs = {"rate_func": there_and_back, "run_time": 5.0} self.add(not_okay) self.play(*[ Transform(*pair, **kwargs) for pair in zip( self.edges + self.vertices, tweaked_self.edges + tweaked_self.vertices, ) ]) self.remove(not_okay) self.add(planar, planar_explanation) self.wait(2) self.remove(planar_explanation) self.add(not_okay) self.remove(*edges_to_remove) self.play( ShowCreation(Mobject(*edges_to_remove), rate_func=lambda t: 1 - t, run_time=1.0)) self.wait(2) self.remove(not_okay) self.add(connected, *edges_to_remove) self.wait()
def construct(self): buff = 0.5 self.graph.vertices = map( lambda v : v + DOWN + RIGHT, self.graph.vertices ) GraphScene.construct(self) self.generate_regions() objects, notions = Mobject(*TextMobject( ["Objects \\quad\\quad ", "Thing that connects objects"] )).to_corner().shift(0.5*RIGHT).split() horizontal_line = Line( (-SPACE_WIDTH, SPACE_HEIGHT-1, 0), (max(notions.points[:,0]), SPACE_HEIGHT-1, 0) ) vert_line_x_val = min(notions.points[:,0]) - buff vertical_line = Line( (vert_line_x_val, SPACE_HEIGHT, 0), (vert_line_x_val,-SPACE_HEIGHT, 0) ) objects_and_notions = [ ("Facebook accounts", "Friendship"), ("English Words", "Differ by One Letter"), ("Mathematicians", "Coauthorship"), ("Neurons", "Synapses"), ( "Regions our graph \\\\ cuts the plane into", "Shared edges" ) ] self.clear() self.add(objects, notions, horizontal_line, vertical_line) for (obj, notion), height in zip(objects_and_notions, it.count(2, -1)): obj_mob = TextMobject(obj, size = "\\small").to_edge(LEFT) not_mob = TextMobject(notion, size = "\\small").to_edge(LEFT) not_mob.shift((vert_line_x_val + SPACE_WIDTH)*RIGHT) obj_mob.shift(height*UP) not_mob.shift(height*UP) if obj.startswith("Regions"): self.handle_dual_graph(obj_mob, not_mob) elif obj.startswith("English"): self.handle_english_words(obj_mob, not_mob) else: self.add(obj_mob) self.dither() self.add(not_mob) self.dither()
def construct(self): GraphScene.construct(self) randy = Randolph().move_to((-3, 0, 0)) name = TextMobject("Randolph") self.play( Transform( randy, deepcopy(randy).scale(RANDOLPH_SCALE_FACTOR).move_to( self.points[0]), )) self.wait() name.shift((0, 1, 0)) self.add(name) self.wait()
def construct(self): GraphScene.construct(self) self.draw_vertices() self.draw_edges() self.dither() self.clear() self.add(*self.edges) self.replace_vertices_with(Face().scale(0.4)) friends = TextMobject("Friends").scale(EDGE_ANNOTATION_SCALE_VAL) self.annotate_edges(friends.shift((0, friends.get_height() / 2, 0))) self.play( *[CounterclockwiseTransform(vertex, Dot(point)) for vertex, point in zip(self.vertices, self.points)] + [Transform(ann, line) for ann, line in zip(self.edge_annotations, self.edges)] ) self.dither()
def construct(self): Not, quote, planar, end_quote = TextMobject([ "Not \\\\", "``", "Planar", "''", # "no matter how \\\\ hard you try" ]).split() shift_val = Mobject(Not, planar).to_corner().get_center() Not.highlight("red").shift(shift_val) graphs = [ Mobject(*GraphScene(g).mobjects) for g in [CubeGraph(), CompleteGraph(5), OctohedronGraph()] ] self.add(quote, planar, end_quote) self.wait() self.play(FadeOut(quote), FadeOut(end_quote), ApplyMethod(planar.shift, shift_val), FadeIn(graphs[0]), run_time=1.5) self.wait() self.remove(graphs[0]) self.add(graphs[1]) planar.highlight("red") self.add(Not) self.wait(2) planar.highlight("white") self.remove(Not) self.remove(graphs[1]) self.add(graphs[2]) self.wait(2)
def construct(self): GraphScene.construct(self) self.generate_dual_graph() dual_cycle = DUAL_CYCLE trapped_points = [0, 1] morty = Mortimer().scale(RANDOLPH_SCALE_VAL) morty.move_to(self.dual_points[dual_cycle[0]]) time_per_edge = 0.5 text = TextMobject(""" One of these lines must be included in the spanning tree if those two inner vertices are to be reached. """).scale(0.7).to_edge(UP) all_lines = [] matching_edges = [] kwargs = {"run_time" : time_per_edge, "rate_func" : None} for last, next in zip(dual_cycle, dual_cycle[1:]): line = Line(self.dual_points[last], self.dual_points[next]) line.highlight("red") self.play( WalkPiCreature(morty, self.dual_points[next], **kwargs), ShowCreation(line, **kwargs), ) all_lines.append(line) center = line.get_center() distances = map( lambda e : np.linalg.norm(center - e.get_center()), self.edges ) matching_edges.append( self.edges[distances.index(min(distances))] ) self.play(*[ Transform(v, Dot( v.get_center(), radius = 3*Dot.DEFAULT_RADIUS, color = "green" )) for v in np.array(self.vertices)[trapped_points] ]) self.add(text) self.play(*[ Transform(line, deepcopy(edge).highlight(line.get_color())) for line, edge in zip(all_lines, matching_edges) ]) self.dither()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.remove(*self.vertices) self.add(*self.dual_edges) self.wait() self.play(*[ Transform(*pair, run_time=2.0) for pair in zip(self.dual_edges, self.edges) ]) self.wait() self.add( TextMobject(""" (Or at least I would argue they should \\\\ be thought of as the same thing.) """, size="\\small").to_edge(UP)) self.wait()
def construct(self): GraphScene.construct(self) self.draw_vertices() self.draw_edges() self.wait() self.clear() self.add(*self.edges) self.replace_vertices_with(Face().scale(0.4)) friends = TextMobject("Friends").scale(EDGE_ANNOTATION_SCALE_FACTOR) self.annotate_edges(friends.shift((0, friends.get_height() / 2, 0))) self.play(*[ CounterclockwiseTransform(vertex, Dot(point)) for vertex, point in zip(self.vertices, self.points) ] + [ Transform(ann, line) for ann, line in zip(self.edge_annotations, self.edges) ]) self.wait()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.remove(*self.vertices) self.add(*self.dual_edges) self.dither() self.play(*[Transform(*pair, run_time=2.0) for pair in zip(self.dual_edges, self.edges)]) self.dither() self.add( TextMobject( """ (Or at least I would argue they should \\\\ be thought of as the same thing.) """, size="\\small", ).to_edge(UP) ) self.dither()
def construct(self): GraphScene.construct(self) terms = cycles, spanning_trees, dual_graphs = [ TextMobject(phrase).shift(y*UP).to_edge() for phrase, y in [ ("Cycles", 3), ("Spanning Trees", 1), ("Dual Graphs", -1), ] ] self.generate_spanning_tree() scale_val = 1.2 def accent(mobject, color = "yellow"): return mobject.scale_in_place(scale_val).highlight(color) def tone_down(mobject): return mobject.scale_in_place(1.0/scale_val).highlight("white") self.add(accent(cycles)) self.trace_cycle(run_time = 1.0) self.dither() tone_down(cycles) self.remove(self.traced_cycle) self.add(accent(spanning_trees)) self.play(ShowCreation(self.spanning_tree), run_time = 1.0) self.dither() tone_down(spanning_trees) self.remove(self.spanning_tree) self.add(accent(dual_graphs, "red")) self.generate_dual_graph() for mob in self.mobjects: mob.fade self.play(*[ ShowCreation(mob, run_time = 1.0) for mob in self.dual_vertices + self.dual_edges ]) self.dither() self.clear() self.play(ApplyMethod( Mobject(*terms).center )) self.dither()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() dual_cycle = DUAL_CYCLE trapped_points = [0, 1] morty = Mortimer().scale(RANDOLPH_SCALE_FACTOR) morty.move_to(self.dual_points[dual_cycle[0]]) time_per_edge = 0.5 text = TextMobject(""" One of these lines must be included in the spanning tree if those two inner vertices are to be reached. """).scale(0.7).to_edge(UP) all_lines = [] matching_edges = [] kwargs = {"run_time": time_per_edge, "rate_func": None} for last, next in zip(dual_cycle, dual_cycle[1:]): line = Line(self.dual_points[last], self.dual_points[next]) line.highlight("red") self.play( WalkPiCreature(morty, self.dual_points[next], **kwargs), ShowCreation(line, **kwargs), ) all_lines.append(line) center = line.get_center() distances = map(lambda e: np.linalg.norm(center - e.get_center()), self.edges) matching_edges.append(self.edges[distances.index(min(distances))]) self.play(*[ Transform( v, Dot(v.get_center(), radius=3 * Dot.DEFAULT_RADIUS, color="green")) for v in np.array(self.vertices)[trapped_points] ]) self.add(text) self.play(*[ Transform(line, deepcopy(edge).highlight(line.get_color())) for line, edge in zip(all_lines, matching_edges) ]) self.wait()
def construct(self): GraphScene.construct(self) terms = cycles, spanning_trees, dual_graphs = [ TextMobject(phrase).shift(y * UP).to_edge() for phrase, y in [ ("Cycles", 3), ("Spanning Trees", 1), ("Dual Graphs", -1), ] ] self.generate_spanning_tree() scale_factor = 1.2 def accent(mobject, color="yellow"): return mobject.scale_in_place(scale_factor).highlight(color) def tone_down(mobject): return mobject.scale_in_place(1.0 / scale_factor).highlight("white") self.add(accent(cycles)) self.trace_cycle(run_time=1.0) self.wait() tone_down(cycles) self.remove(self.traced_cycle) self.add(accent(spanning_trees)) self.play(ShowCreation(self.spanning_tree), run_time=1.0) self.wait() tone_down(spanning_trees) self.remove(self.spanning_tree) self.add(accent(dual_graphs, "red")) self.generate_dual_graph() for mob in self.mobjects: mob.fade self.play(*[ ShowCreation(mob, run_time=1.0) for mob in self.dual_vertices + self.dual_edges ]) self.wait() self.clear() self.play(ApplyMethod(Mobject(*terms).center)) self.wait()
def construct(self): GraphScene.construct(self) self.generate_regions() self.generate_dual_graph() cycle = [4, 2, 1, 5, 4] enclosed_regions = [0, 2, 3, 4] dual_cycle = DUAL_CYCLE enclosed_vertices = [0, 1] randy = Randolph() randy.scale(RANDOLPH_SCALE_VAL) randy.move_to(self.points[cycle[0]]) lines_to_remove = [] for last, next in zip(cycle, cycle[1:]): line = Line(self.points[last], self.points[next]) line.highlight("yellow") self.play( ShowCreation(line), WalkPiCreature(randy, self.points[next]), run_time = 1.0 ) lines_to_remove.append(line) self.dither() self.remove(randy, *lines_to_remove) for region in np.array(self.regions)[enclosed_regions]: self.highlight_region(region) self.dither(2) self.reset_background() lines = Mobject(*[ Line(self.dual_points[last], self.dual_points[next]) for last, next in zip(dual_cycle, dual_cycle[1:]) ]).highlight("red") self.play(ShowCreation(lines)) self.play(*[ Transform(v, Dot( v.get_center(), radius = 3*Dot.DEFAULT_RADIUS ).highlight("green")) for v in np.array(self.vertices)[enclosed_vertices] ] + [ ApplyMethod(self.edges[0].highlight, "green") ]) self.dither()
def construct(self): GraphScene.construct(self) paths = [ (1, 2, 4, 5, 6), (6, 7, 1, 3), ] non_paths = [ [ (0, 1), (7, 8), (5, 6), ], [(5, 0), (0, 2), (0, 1)], ] valid_path = TextMobject("Valid \\\\ Path").highlight("green") not_a_path = TextMobject("Not a \\\\ Path").highlight("red") for mob in valid_path, not_a_path: mob.to_edge(UP) kwargs = {"run_time": 1.0} for path, non_path in zip(paths, non_paths): path_lines = Mobject(*[ Line(self.points[path[i]], self.points[path[i + 1]]).highlight( "yellow") for i in range(len(path) - 1) ]) non_path_lines = Mobject(*[ Line( self.points[pp[0]], self.points[pp[1]], ).highlight("yellow") for pp in non_path ]) self.remove(not_a_path) self.add(valid_path) self.play(ShowCreation(path_lines, **kwargs)) self.wait(2) self.remove(path_lines) self.remove(valid_path) self.add(not_a_path) self.play(ShowCreation(non_path_lines, **kwargs)) self.wait(2) self.remove(non_path_lines)
def construct(self): GraphScene.construct(self) rot_kwargs = {"radians": np.pi / 3, "run_time": 5.0} vertices = [ point / 2 + OUT if abs(point[0]) == 2 else point + IN for point in self.points ] cube = Mobject(*[ Line(vertices[edge[0]], vertices[edge[1]]) for edge in self.graph.edges ]) cube.rotate(-np.pi / 3, [0, 0, 1]) cube.rotate(-np.pi / 3, [0, 1, 0]) dots_to_vertices = TextMobject("Dots $\\to$ Vertices").to_corner() lines_to_edges = TextMobject("Lines $\\to$ Edges").to_corner() regions_to_faces = TextMobject("Regions $\\to$ Faces").to_corner() self.clear() # self.play(TransformAnimations( # Rotating(Dodecahedron(), **rot_kwargs), # Rotating(cube, **rot_kwargs) # )) self.play(Rotating(cube, **rot_kwargs)) self.clear() self.play( *[Transform(l1, l2) for l1, l2 in zip(cube.split(), self.edges)]) self.wait() self.add(dots_to_vertices) self.play(*[ShowCreation(dot, run_time=1.0) for dot in self.vertices]) self.wait(2) self.remove(dots_to_vertices, *self.vertices) self.add(lines_to_edges) self.play(ApplyMethod(Mobject(*self.edges).highlight, "yellow")) self.wait(2) self.clear() self.add(*self.edges) self.add(regions_to_faces) self.generate_regions() for region in self.regions: self.highlight_region(region) self.wait(3.0)
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.generate_spanning_tree() randy = Randolph() randy.scale(RANDOLPH_SCALE_VAL) randy.move_to(self.points[0]) morty = Mortimer() morty.scale(RANDOLPH_SCALE_VAL) morty.move_to(self.dual_points[0]) dual_edges = [1, 3, 4, 7, 11, 9, 13] words = TextMobject( """ The red edges form a spanning tree of the dual graph! """ ).to_edge(UP) self.add(self.spanning_tree, randy, morty) self.play(ShowCreation(Mobject(*np.array(self.edges)[dual_edges]).highlight("red"))) self.add(words) self.dither()
def construct(self): GraphScene.construct(self) self.generate_dual_graph() self.generate_spanning_tree() randy = Randolph() randy.scale(RANDOLPH_SCALE_FACTOR) randy.move_to(self.points[0]) morty = Mortimer() morty.scale(RANDOLPH_SCALE_FACTOR) morty.move_to(self.dual_points[0]) dual_edges = [1, 3, 4, 7, 11, 9, 13] words = TextMobject(""" The red edges form a spanning tree of the dual graph! """).to_edge(UP) self.add(self.spanning_tree, randy, morty) self.play( ShowCreation( Mobject(*np.array(self.edges)[dual_edges]).highlight("red"))) self.add(words) self.wait()
def construct(self): buff = 0.5 self.graph.vertices = map(lambda v: v + DOWN + RIGHT, self.graph.vertices) GraphScene.construct(self) self.generate_regions() objects, notions = Mobject(*TextMobject([ "Objects \\quad\\quad ", "Thing that connects objects" ])).to_corner().shift(0.5 * RIGHT).split() horizontal_line = Line( (-SPACE_WIDTH, SPACE_HEIGHT - 1, 0), (max(notions.points[:, 0]), SPACE_HEIGHT - 1, 0)) vert_line_x_val = min(notions.points[:, 0]) - buff vertical_line = Line((vert_line_x_val, SPACE_HEIGHT, 0), (vert_line_x_val, -SPACE_HEIGHT, 0)) objects_and_notions = [("Facebook accounts", "Friendship"), ("English Words", "Differ by One Letter"), ("Mathematicians", "Coauthorship"), ("Neurons", "Synapses"), ("Regions our graph \\\\ cuts the plane into", "Shared edges")] self.clear() self.add(objects, notions, horizontal_line, vertical_line) for (obj, notion), height in zip(objects_and_notions, it.count(2, -1)): obj_mob = TextMobject(obj, size="\\small").to_edge(LEFT) not_mob = TextMobject(notion, size="\\small").to_edge(LEFT) not_mob.shift((vert_line_x_val + SPACE_WIDTH) * RIGHT) obj_mob.shift(height * UP) not_mob.shift(height * UP) if obj.startswith("Regions"): self.handle_dual_graph(obj_mob, not_mob) elif obj.startswith("English"): self.handle_english_words(obj_mob, not_mob) else: self.add(obj_mob) self.wait() self.add(not_mob) self.wait()
def construct(self): GraphScene.construct(self) self.generate_regions() self.generate_dual_graph() region_mobs = [ ImageMobject(disp.paint_region(reg, self.background), invert=False) for reg in self.regions ] for region, mob in zip(self.regions, region_mobs): self.highlight_region(region, mob.get_color()) outer_region = self.regions.pop() outer_region_mob = region_mobs.pop() outer_dual_vertex = self.dual_vertices.pop() internal_edges = filter( lambda e : abs(e.start[0]) < SPACE_WIDTH and \ abs(e.end[0]) < SPACE_WIDTH and \ abs(e.start[1]) < SPACE_HEIGHT and \ abs(e.end[1]) < SPACE_HEIGHT, self.dual_edges ) external_edges = filter(lambda e: e not in internal_edges, self.dual_edges) self.wait() self.reset_background() self.highlight_region(outer_region, outer_region_mob.get_color()) self.play(*[ Transform(reg_mob, dot) for reg_mob, dot in zip(region_mobs, self.dual_vertices) ]) self.wait() self.reset_background() self.play( ApplyFunction( lambda p: (SPACE_WIDTH + SPACE_HEIGHT) * p / np.linalg.norm(p), outer_region_mob)) self.wait() for edges in internal_edges, external_edges: self.play(*[ShowCreation(edge, run_time=2.0) for edge in edges]) self.wait()
def construct(self): GraphScene.construct(self) self.generate_regions() self.generate_dual_graph() cycle = [4, 2, 1, 5, 4] enclosed_regions = [0, 2, 3, 4] dual_cycle = DUAL_CYCLE enclosed_vertices = [0, 1] randy = Randolph() randy.scale(RANDOLPH_SCALE_FACTOR) randy.move_to(self.points[cycle[0]]) lines_to_remove = [] for last, next in zip(cycle, cycle[1:]): line = Line(self.points[last], self.points[next]) line.highlight("yellow") self.play(ShowCreation(line), WalkPiCreature(randy, self.points[next]), run_time=1.0) lines_to_remove.append(line) self.wait() self.remove(randy, *lines_to_remove) for region in np.array(self.regions)[enclosed_regions]: self.highlight_region(region) self.wait(2) self.reset_background() lines = Mobject(*[ Line(self.dual_points[last], self.dual_points[next]) for last, next in zip(dual_cycle, dual_cycle[1:]) ]).highlight("red") self.play(ShowCreation(lines)) self.play(*[ Transform( v, Dot(v.get_center(), radius=3 * Dot.DEFAULT_RADIUS).highlight("green")) for v in np.array(self.vertices)[enclosed_vertices] ] + [ApplyMethod(self.edges[0].highlight, "green")]) self.wait()
def construct(self): time_per_branch = 0.5 text = TextMobject(""" In any tree: $$E + 1 = V$$ """) gs = GraphScene(SampleGraph()) gs.generate_treeified_spanning_tree() branches = gs.treeified_spanning_tree.to_edge(LEFT).split() all_dots = [Dot(branches[0].points[0])] self.add(text, all_dots[0]) for branch in branches: self.play(ShowCreation(branch), run_time=time_per_branch) dot = Dot(branch.points[-1]) self.add(dot) all_dots.append(dot) self.wait() self.remove(*all_dots) self.play( FadeOut(text), FadeIn(Mobject(*gs.edges + gs.vertices)), *[ Transform(*pair) for pair in zip(branches, gs.spanning_tree.split()) ])
def createWidgets(self): self.scene = GraphScene(self) self.scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex) self.scene.setSceneRect(-200, -200, 400, 400)
def __init__(self, graph, path, *args, **kwargs): self.path = path GraphScene.__init__(self, graph, *args, **kwargs)