def solve_energy(self): loss_in_potential = TextMobject("Loss in potential: ") loss_in_potential.shift(2 * UP) potential = TexMobject("m g y".split()) potential.next_to(loss_in_potential) kinetic = TexMobject(["\\dfrac{1}{2}", "m", "v", "^2", "="]) kinetic.next_to(potential, LEFT) nudge = 0.1 * UP kinetic.shift(nudge) loss_in_potential.shift(nudge) ms = Mobject(kinetic.split()[1], potential.split()[0]) two = TexMobject("2") two.shift(ms.split()[1].get_center()) half = kinetic.split()[0] sqrt = TexMobject("\\sqrt{\\phantom{2mg}}") sqrt.shift(potential.get_center()) nudge = 0.2 * LEFT sqrt.shift(nudge) squared = kinetic.split()[3] equals = kinetic.split()[-1] new_eq = equals.copy().next_to(kinetic.split()[2]) self.play( Transform(Point(loss_in_potential.get_left()), loss_in_potential), *map(GrowFromCenter, potential.split())) self.dither(2) self.play(FadeOut(loss_in_potential), GrowFromCenter(kinetic)) self.dither(2) self.play(ApplyMethod(ms.shift, 5 * UP)) self.dither() self.play(Transform(half, two, path_func=counterclockwise_path())) self.dither() self.play(Transform(squared, sqrt, path_func=clockwise_path()), Transform(equals, new_eq)) self.dither(2)
def construct(self): in_vect = Matrix(self.input_coords) out_vect = Matrix(self.output_coords) in_vect.highlight(BLUE) out_vect.highlight(GREEN) func = TexMobject("L(\\vec{\\textbf{v}})") point = VectorizedPoint(func.get_center()) in_vect.next_to(func, LEFT, buff=1) out_vect.next_to(func, RIGHT, buff=1) in_words = TextMobject("Input") in_words.next_to(in_vect, DOWN) in_words.highlight(BLUE_C) out_words = TextMobject("Output") out_words.next_to(out_vect, DOWN) out_words.highlight(GREEN_C) title = TextMobject(self.title) title.to_edge(UP) self.add(title) self.play(Write(func)) self.play(Write(in_vect), Write(in_words)) self.wait() self.add(in_vect.copy()) self.play(Transform(in_vect, point, submobject_mode="lagged_start")) self.play(Transform(in_vect, out_vect, submobject_mode="lagged_start")) self.add(out_words) self.wait()
def construct(self): in_vect = Matrix(self.input_coords) out_vect = Matrix(self.output_coords) in_vect.highlight(BLUE) out_vect.highlight(GREEN) func = TexMobject("L(\\vec{\\textbf{v}})") point = VectorizedPoint(func.get_center()) in_vect.next_to(func, LEFT, buff = 1) out_vect.next_to(func, RIGHT, buff = 1) in_words = TextMobject("Input") in_words.next_to(in_vect, DOWN) in_words.highlight(BLUE_C) out_words = TextMobject("Output") out_words.next_to(out_vect, DOWN) out_words.highlight(GREEN_C) title = TextMobject(self.title) title.to_edge(UP) self.add(title) self.play(Write(func)) self.play(Write(in_vect), Write(in_words)) self.dither() self.add(in_vect.copy()) self.play(Transform(in_vect, point, submobject_mode = "lagged_start")) self.play(Transform(in_vect, out_vect, submobject_mode = "lagged_start")) self.add(out_words) self.dither()
def construct(self): hydrogen_atom = Mobject() title = TexMobject("Hydrogen Atom") point_A = (-2,2,0) point_B = (-2,-2,0) arrow = Arrow(ORIGIN+LEFT*0.9,ORIGIN+RIGHT*0.9) add_sign = TexMobject("+", stroke_width=0.7) orbit = Circle(radius=1.3).scale(0.85) proton = Dot(radius=0.4, color="GREY").scale(0.85) elec = Dot(radius=0.2, color="RED").scale(0.85) p_charge = TexMobject("+", stroke_width=0.5) e_charge = TexMobject("-",stroke_width=0.5) title.move_to(title.get_center()+UP*2) elec.move_to(orbit.points[0]) e_charge.move_to(elec.get_center()) p_charge.move_to(proton.get_center()) self.play(ShowCreation(title)) self.play(ShowCreation(orbit)) self.play(GrowFromCenter(proton), GrowFromCenter(p_charge)) self.play(GrowFromCenter(elec), GrowFromCenter(e_charge)) self.play(MoveAlongPath(elec, orbit),MaintainPositionRelativeTo(e_charge, elec), run_time=5,rate_func=None) hydrogen_atom.add(orbit,elec, proton, e_charge, p_charge) atom_copy = hydrogen_atom.copy() h1_text = TexMobject("H").move_to(point_A+LEFT*2) h2_text = TexMobject("H").move_to(point_B+LEFT*2) names = VGroup(h1_text, h2_text) self.play(ApplyMethod(atom_copy.shift, point_A),ApplyMethod(hydrogen_atom.shift, point_B),Transform(title, names)) add_sign.move_to(atom_copy.get_center()+DOWN*2) self.play(ShowCreation(add_sign),ShowCreation(arrow)) h1_atom = atom_copy.copy().move_to(arrow.get_end()+RIGHT*3.5) h2_atom = hydrogen_atom.copy().move_to(arrow.get_end()+RIGHT*1.5) self.remove(atom_copy, hydrogen_atom) h2_atom[1].move_to(h2_atom[0].points[2]) h2_atom[3].move_to(h2_atom[1].get_center()) h1_atom[1].move_to(h1_atom[0].points[14]) h1_atom[3].move_to(h1_atom[1].get_center()) h2_molecule = VGroup(h1_atom,h2_atom) two_atoms = VGroup(atom_copy,hydrogen_atom) #org.copy() molecule_name = TexMobject("H_{2}").move_to(h2_molecule.get_center()+DOWN*2.5) self.play(Transform(two_atoms, h2_molecule), FadeOut(arrow.add(add_sign))) self.add(h2_molecule) self.remove(title,two_atoms) self.play(Transform(names, molecule_name))
def construct(self, order): if order == 2: result_tex = "(0.125, 0.75)" elif order == 3: result_tex = "(0.0758, 0.6875)" phc, arg, result = TexMobject([ "\\text{PHC}_%d"%order, "(0.3)", "= %s"%result_tex ]).to_edge(UP).split() function = TextMobject("Function", size = "\\normal") function.shift(phc.get_center()+DOWN+2*LEFT) function_arrow = Arrow(function, phc) line = Line(5*LEFT, 5*RIGHT) curve = HilbertCurve(order = order) line.match_colors(curve) grid = Grid(2**order, 2**order) grid.fade() for mob in curve, grid: mob.scale(0.7) index = int(0.3*line.get_num_points()) dot1 = Dot(line.points[index]) arrow1 = Arrow(arg, dot1, buff = 0.1) dot2 = Dot(curve.points[index]) arrow2 = Arrow(result.get_bottom(), dot2, buff = 0.1) self.add(phc) self.play( ShimmerIn(function), ShowCreation(function_arrow) ) self.wait() self.remove(function_arrow, function) self.play(ShowCreation(line)) self.wait() self.play( ShimmerIn(arg), ShowCreation(arrow1), ShowCreation(dot1) ) self.wait() self.remove(arrow1) self.play( FadeIn(grid), Transform(line, curve), Transform(dot1, dot2), run_time = 2 ) self.wait() self.play( ShimmerIn(result), ShowCreation(arrow2) ) self.wait()
def construct(self, order): if order == 2: result_tex = "(0.125, 0.75)" elif order == 3: result_tex = "(0.0758, 0.6875)" phc, arg, result = TexMobject([ "\\text{PHC}_%d"%order, "(0.3)", "= %s"%result_tex ]).to_edge(UP).split() function = TextMobject("Function", size = "\\normal") function.shift(phc.get_center()+DOWN+2*LEFT) function_arrow = Arrow(function, phc) line = Line(5*LEFT, 5*RIGHT) curve = HilbertCurve(order = order) line.match_colors(curve) grid = Grid(2**order, 2**order) grid.fade() for mob in curve, grid: mob.scale(0.7) index = int(0.3*line.get_num_points()) dot1 = Dot(line.points[index]) arrow1 = Arrow(arg, dot1, buff = 0.1) dot2 = Dot(curve.points[index]) arrow2 = Arrow(result.get_bottom(), dot2, buff = 0.1) self.add(phc) self.play( ShimmerIn(function), ShowCreation(function_arrow) ) self.dither() self.remove(function_arrow, function) self.play(ShowCreation(line)) self.dither() self.play( ShimmerIn(arg), ShowCreation(arrow1), ShowCreation(dot1) ) self.dither() self.remove(arrow1) self.play( FadeIn(grid), Transform(line, curve), Transform(dot1, dot2), run_time = 2 ) self.dither() self.play( ShimmerIn(result), ShowCreation(arrow2) ) self.dither()
def solve_energy(self): loss_in_potential = TextMobject("Loss in potential: ") loss_in_potential.shift(2*UP) potential = TexMobject("m g y".split()) potential.next_to(loss_in_potential) kinetic = TexMobject([ "\\dfrac{1}{2}","m","v","^2","=" ]) kinetic.next_to(potential, LEFT) nudge = 0.1*UP kinetic.shift(nudge) loss_in_potential.shift(nudge) ms = Mobject(kinetic.split()[1], potential.split()[0]) two = TexMobject("2") two.shift(ms.split()[1].get_center()) half = kinetic.split()[0] sqrt = TexMobject("\\sqrt{\\phantom{2mg}}") sqrt.shift(potential.get_center()) nudge = 0.2*LEFT sqrt.shift(nudge) squared = kinetic.split()[3] equals = kinetic.split()[-1] new_eq = equals.copy().next_to(kinetic.split()[2]) self.play( Transform( Point(loss_in_potential.get_left()), loss_in_potential ), *map(GrowFromCenter, potential.split()) ) self.dither(2) self.play( FadeOut(loss_in_potential), GrowFromCenter(kinetic) ) self.dither(2) self.play(ApplyMethod(ms.shift, 5*UP)) self.dither() self.play(Transform( half, two, path_func = counterclockwise_path() )) self.dither() self.play( Transform( squared, sqrt, path_func = clockwise_path() ), Transform(equals, new_eq) ) self.dither(2)
def get_top_inverse_rules(): result = [] pairs = [ #Careful of order here! (0, 2), (0, 1), (1, 0), (1, 2), (2, 0), (2, 1), ] for i, j in pairs: top = get_top_inverse(i, j) char = ["x", "y", "z"][j] eq = TexMobject("= %s" % char) eq.scale(2) eq.next_to(top, RIGHT) diff = eq.get_center() - top.triangle.get_center() eq.shift(diff[1] * UP) result.append(VMobject(top, eq)) return result
def get_top_inverse_rules(): result = [] pairs = [#Careful of order here! (0, 2), (0, 1), (1, 0), (1, 2), (2, 0), (2, 1), ] for i, j in pairs: top = get_top_inverse(i, j) char = ["x", "y", "z"][j] eq = TexMobject("= %s"%char) eq.scale(2) eq.next_to(top, RIGHT) diff = eq.get_center() - top.triangle.get_center() eq.shift(diff[1]*UP) result.append(VMobject(top, eq)) return result
def show_lighthouses_on_number_line(self): self.number_line = NumberLine( x_min=0, color=WHITE, number_at_center=1.6, stroke_width=1, numbers_with_elongated_ticks=range(1, 5), numbers_to_show=range(1, 5), unit_size=2, tick_frequency=0.2, line_to_number_buff=LARGE_BUFF, label_direction=UP, ) self.number_line.label_direction = DOWN self.number_line_labels = self.number_line.get_number_mobjects() self.add(self.number_line, self.number_line_labels) self.wait() origin_point = self.number_line.number_to_point(0) self.default_pi_creature_class = Randolph randy = self.get_primary_pi_creature() randy.scale(0.5) randy.flip() right_pupil = randy.pupils[1] randy.next_to(origin_point, LEFT, buff=0, submobject_to_align=right_pupil) light_indicator = LightIndicator( radius=INDICATOR_RADIUS, opacity_for_unit_intensity=OPACITY_FOR_UNIT_INTENSITY, color=LIGHT_COLOR) light_indicator.reading.scale(0.8) bubble = ThoughtBubble(direction=RIGHT, width=2.5, height=3.5) bubble.next_to(randy, LEFT + UP) bubble.add_content(light_indicator) self.play(randy.change, "wave_2", ShowCreation(bubble), FadeIn(light_indicator)) light_sources = [] euler_sum_above = TexMobject("1", "+", "{1\over 4}", "+", "{1\over 9}", "+", "{1\over 16}", "+", "{1\over 25}", "+", "{1\over 36}") for (i, term) in zip(range(len(euler_sum_above)), euler_sum_above): #horizontal alignment with tick marks term.next_to(self.number_line.number_to_point(0.5 * i + 1), UP, buff=2) # vertical alignment with light indicator old_y = term.get_center()[1] new_y = light_indicator.get_center()[1] term.shift([0, new_y - old_y, 0]) for i in range(1, NUM_CONES + 1): light_source = LightSource( opacity_function=inverse_quadratic(1, 2, 1), num_levels=NUM_LEVELS, radius=12.0, ) point = self.number_line.number_to_point(i) light_source.move_source_to(point) light_sources.append(light_source) for ls in light_sources: self.add_foreground_mobject(ls.lighthouse) light_indicator.set_intensity(0) intensities = np.cumsum( np.array([1. / n**2 for n in range(1, NUM_CONES + 1)])) opacities = intensities * light_indicator.opacity_for_unit_intensity self.remove_foreground_mobjects(light_indicator) # slowly switch on visible light cones and increment indicator for (i, light_source) in zip(range(NUM_VISIBLE_CONES), light_sources[:NUM_VISIBLE_CONES]): indicator_start_time = 0.4 * ( i + 1 ) * SWITCH_ON_RUN_TIME / light_source.radius * self.number_line.unit_size indicator_stop_time = indicator_start_time + INDICATOR_UPDATE_TIME indicator_rate_func = squish_rate_func(smooth, indicator_start_time, indicator_stop_time) self.play( SwitchOn(light_source.ambient_light), FadeIn(euler_sum_above[2 * i], run_time=SWITCH_ON_RUN_TIME, rate_func=indicator_rate_func), FadeIn(euler_sum_above[2 * i - 1], run_time=SWITCH_ON_RUN_TIME, rate_func=indicator_rate_func), # this last line *technically* fades in the last term, but it is off-screen ChangeDecimalToValue(light_indicator.reading, intensities[i], rate_func=indicator_rate_func, run_time=SWITCH_ON_RUN_TIME), ApplyMethod(light_indicator.foreground.set_fill, None, opacities[i])) if i == 0: # move a copy out of the thought bubble for comparison light_indicator_copy = light_indicator.copy() old_y = light_indicator_copy.get_center()[1] new_y = self.number_line.get_center()[1] self.play(light_indicator_copy.shift, [0, new_y - old_y, 0]) # quickly switch on off-screen light cones and increment indicator for (i, light_source) in zip(range(NUM_VISIBLE_CONES, NUM_CONES), light_sources[NUM_VISIBLE_CONES:NUM_CONES]): indicator_start_time = 0.5 * ( i + 1 ) * FAST_SWITCH_ON_RUN_TIME / light_source.radius * self.number_line.unit_size indicator_stop_time = indicator_start_time + FAST_INDICATOR_UPDATE_TIME indicator_rate_func = squish_rate_func( #smooth, 0.8, 0.9) smooth, indicator_start_time, indicator_stop_time) self.play( SwitchOn(light_source.ambient_light, run_time=FAST_SWITCH_ON_RUN_TIME), ChangeDecimalToValue(light_indicator.reading, intensities[i - 1], rate_func=indicator_rate_func, run_time=FAST_SWITCH_ON_RUN_TIME), ApplyMethod(light_indicator.foreground.set_fill, None, opacities[i - 1])) # show limit value in light indicator and an equals sign limit_reading = TexMobject("{\pi^2 \over 6}") limit_reading.move_to(light_indicator.reading) equals_sign = TexMobject("=") equals_sign.next_to(randy, UP) old_y = equals_sign.get_center()[1] new_y = euler_sum_above.get_center()[1] equals_sign.shift([0, new_y - old_y, 0]) self.play( FadeOut(light_indicator.reading), FadeIn(limit_reading), FadeIn(equals_sign), ) self.wait()
class IntroScene(PiCreatureScene): CONFIG = { "rect_height": 0.2, "duration": 1.0, "eq_spacing": 3 * MED_LARGE_BUFF } def construct(self): randy = self.get_primary_pi_creature() randy.scale(0.7).to_corner(DOWN + RIGHT) self.build_up_euler_sum() self.build_up_sum_on_number_line() self.show_pi_answer() self.other_pi_formulas() self.refocus_on_euler_sum() def build_up_euler_sum(self): self.euler_sum = TexMobject("1", "+", "{1 \\over 4}", "+", "{1 \\over 9}", "+", "{1 \\over 16}", "+", "{1 \\over 25}", "+", "\\cdots", "=", arg_separator=" \\, ") self.euler_sum.to_edge(UP) self.euler_sum.shift(2 * LEFT) terms = [1. / n**2 for n in range(1, 6)] partial_results_values = np.cumsum(terms) self.play(FadeIn(self.euler_sum[0], run_time=self.duration)) equals_sign = self.euler_sum.get_part_by_tex("=") self.partial_sum_decimal = DecimalNumber(partial_results_values[1], num_decimal_points=2) self.partial_sum_decimal.next_to(equals_sign, RIGHT) for i in range(4): FadeIn(self.partial_sum_decimal, run_time=self.duration) if i == 0: self.play( FadeIn(self.euler_sum[1], run_time=self.duration), FadeIn(self.euler_sum[2], run_time=self.duration), FadeIn(equals_sign, run_time=self.duration), FadeIn(self.partial_sum_decimal, run_time=self.duration)) else: self.play( FadeIn(self.euler_sum[2 * i + 1], run_time=self.duration), FadeIn(self.euler_sum[2 * i + 2], run_time=self.duration), ChangeDecimalToValue(self.partial_sum_decimal, partial_results_values[i + 1], run_time=self.duration, num_decimal_points=6, show_ellipsis=True, position_update_func=lambda m: m. next_to(equals_sign, RIGHT))) self.wait() self.q_marks = TextMobject("???").highlight(LIGHT_COLOR) self.q_marks.move_to(self.partial_sum_decimal) self.play( FadeIn(self.euler_sum[-3], run_time=self.duration), # + FadeIn(self.euler_sum[-2], run_time=self.duration), # ... ReplacementTransform(self.partial_sum_decimal, self.q_marks)) def build_up_sum_on_number_line(self): self.number_line = NumberLine( x_min=0, color=WHITE, number_at_center=1, stroke_width=1, numbers_with_elongated_ticks=[0, 1, 2, 3], numbers_to_show=np.arange(0, 5), unit_size=5, tick_frequency=0.2, line_to_number_buff=MED_LARGE_BUFF) self.number_line_labels = self.number_line.get_number_mobjects() self.add(self.number_line, self.number_line_labels) self.wait() # create slabs for series terms max_n = 10 terms = [0] + [1. / (n**2) for n in range(1, max_n + 1)] series_terms = np.cumsum(terms) lines = VGroup() self.rects = VGroup() slab_colors = [YELLOW, BLUE] * (max_n / 2) for t1, t2, color in zip(series_terms, series_terms[1:], slab_colors): line = Line(*map(self.number_line.number_to_point, [t1, t2])) rect = Rectangle() rect.stroke_width = 0 rect.fill_opacity = 1 rect.highlight(color) rect.stretch_to_fit_height(self.rect_height, ) rect.stretch_to_fit_width(line.get_width()) rect.move_to(line) self.rects.add(rect) lines.add(line) #self.rects.radial_gradient_highlight(ORIGIN, 5, YELLOW, BLUE) for i in range(5): self.play( GrowFromPoint(self.rects[i], self.euler_sum[2 * i].get_center(), run_time=self.duration)) for i in range(5, max_n): self.play( GrowFromPoint(self.rects[i], self.euler_sum[10].get_center(), run_time=self.duration)) def show_pi_answer(self): self.pi_answer = TexMobject("{\\pi^2 \\over 6}").highlight(YELLOW) self.pi_answer.move_to(self.partial_sum_decimal) self.pi_answer.next_to(self.euler_sum[-1], RIGHT, submobject_to_align=self.pi_answer[-2]) self.play(ReplacementTransform(self.q_marks, self.pi_answer)) def other_pi_formulas(self): self.play(FadeOut(self.rects), FadeOut(self.number_line_labels), FadeOut(self.number_line)) self.leibniz_sum = TexMobject( "1-{1\\over 3}+{1\\over 5}-{1\\over 7}+{1\\over 9}-\\cdots", "=", "{\\pi \\over 4}") self.wallis_product = TexMobject( "{2\\over 1} \\cdot {2\\over 3} \\cdot {4\\over 3} \\cdot {4\\over 5}" + "\\cdot {6\\over 5} \\cdot {6\\over 7} \\cdots", "=", "{\\pi \\over 2}") self.leibniz_sum.next_to( self.euler_sum.get_part_by_tex("="), DOWN, buff=self.eq_spacing, submobject_to_align=self.leibniz_sum.get_part_by_tex("=")) self.wallis_product.next_to( self.leibniz_sum.get_part_by_tex("="), DOWN, buff=self.eq_spacing, submobject_to_align=self.wallis_product.get_part_by_tex("=")) self.play(Write(self.leibniz_sum)) self.play(Write(self.wallis_product)) def refocus_on_euler_sum(self): self.euler_sum.add(self.pi_answer) self.play( FadeOut(self.leibniz_sum), FadeOut(self.wallis_product), ApplyMethod(self.euler_sum.shift, ORIGIN + 2 * UP - self.euler_sum.get_center())) # focus on pi squared pi_squared = self.euler_sum.get_part_by_tex("\\pi")[-3] self.play(ScaleInPlace(pi_squared, 2, rate_func=wiggle)) # Morty thinks of a circle q_circle = Circle(stroke_color=YELLOW, fill_color=YELLOW, fill_opacity=0.5, radius=0.4, stroke_width=10.0) q_mark = TexMobject("?") q_mark.next_to(q_circle) thought = Group(q_circle, q_mark) q_mark.scale_to_fit_height(0.8 * q_circle.get_height()) self.pi_creature_thinks(thought, target_mode="confused", bubble_kwargs={ "height": 2, "width": 3 }) self.wait()
def construct(self): top = TOP() times = top.put_in_vertex(0, TexMobject("\\times")) times.highlight(YELLOW) oplus = top.put_in_vertex(1, TexMobject("\\oplus")) oplus.highlight(BLUE) dot = top.put_in_vertex(2, Dot()) eight = top.put_on_vertex(2, TexMobject("8")) self.add(top) self.play(ShowCreation(eight)) for mob in dot, oplus, times: self.play(ShowCreation(mob)) self.wait() top.add(eight) top.add(times, oplus, dot) top1, top2, top3 = tops = [top.copy() for i in range(3)] big_oplus = TexMobject("\\oplus").scale(2).highlight(BLUE) equals = TexMobject("=") equation = VMobject(top1, big_oplus, top2, equals, top3) equation.arrange_submobjects() top3.shift(0.5 * RIGHT) x, y, xy = [ t.put_on_vertex(0, s) for t, s in zip(tops, ["x", "y", "xy"]) ] old_style_eq = TexMobject( "\\dfrac{1}{\\frac{1}{\\log_x(8)} + \\frac{1}{\\log_y(8)}} = \\log_{xy}(8)" ) old_style_eq.to_edge(UP).highlight(RED) triple_top_copy = VMobject(*[top.copy() for i in range(3)]) self.clear() self.play(Transform(triple_top_copy, VMobject(*tops)), FadeIn(VMobject(x, y, xy, big_oplus, equals))) self.remove(triple_top_copy) self.add(*tops) self.play(Write(old_style_eq)) self.wait(3) syms = VMobject(x, y, xy) new_syms = VMobject(*[ t.put_on_vertex(1, s) for t, s in zip(tops, ["x", "y", "x \\oplus y"]) ]) new_old_style_eq = TexMobject( "\\sqrt[x]{8} \\sqrt[y]{8} = \\sqrt[X]{8}") X = new_old_style_eq.split()[-4] frac = TexMobject("\\frac{1}{\\frac{1}{x} + \\frac{1}{y}}") frac.replace(X) frac_lower_right = frac.get_corner(DOWN + RIGHT) frac.scale(2) frac.shift(frac_lower_right - frac.get_corner(DOWN + RIGHT)) new_old_style_eq.submobjects[-4] = frac new_old_style_eq.to_edge(UP) new_old_style_eq.highlight(RED) big_times = TexMobject("\\times").highlight(YELLOW) big_times.shift(big_oplus.get_center()) self.play(Transform(old_style_eq, new_old_style_eq), Transform(syms, new_syms, path_arc=np.pi / 2), Transform(big_oplus, big_times)) self.wait(4)
def construct(self): top = TOP() times = top.put_in_vertex(0, TexMobject("\\times")) times.highlight(YELLOW) oplus = top.put_in_vertex(1, TexMobject("\\oplus")) oplus.highlight(BLUE) dot = top.put_in_vertex(2, Dot()) eight = top.put_on_vertex(2, TexMobject("8")) self.add(top) self.play(ShowCreation(eight)) for mob in dot, oplus, times: self.play(ShowCreation(mob)) self.dither() top.add(eight) top.add(times, oplus, dot) top1, top2, top3 = tops = [ top.copy() for i in range(3) ] big_oplus = TexMobject("\\oplus").scale(2).highlight(BLUE) equals = TexMobject("=") equation = VMobject( top1, big_oplus, top2, equals, top3 ) equation.arrange_submobjects() top3.shift(0.5*RIGHT) x, y, xy = [ t.put_on_vertex(0, s) for t, s in zip(tops, ["x", "y", "xy"]) ] old_style_eq = TexMobject( "\\dfrac{1}{\\frac{1}{\\log_x(8)} + \\frac{1}{\\log_y(8)}} = \\log_{xy}(8)" ) old_style_eq.to_edge(UP).highlight(RED) triple_top_copy = VMobject(*[ top.copy() for i in range(3) ]) self.clear() self.play( Transform(triple_top_copy, VMobject(*tops)), FadeIn(VMobject(x, y, xy, big_oplus, equals)) ) self.remove(triple_top_copy) self.add(*tops) self.play(Write(old_style_eq)) self.dither(3) syms = VMobject(x, y, xy) new_syms = VMobject(*[ t.put_on_vertex(1, s) for t, s in zip(tops, ["x", "y", "x \\oplus y"]) ]) new_old_style_eq = TexMobject( "\\sqrt[x]{8} \\sqrt[y]{8} = \\sqrt[X]{8}" ) X = new_old_style_eq.split()[-4] frac = TexMobject("\\frac{1}{\\frac{1}{x} + \\frac{1}{y}}") frac.replace(X) frac_lower_right = frac.get_corner(DOWN+RIGHT) frac.scale(2) frac.shift(frac_lower_right - frac.get_corner(DOWN+RIGHT)) new_old_style_eq.submobjects[-4] = frac new_old_style_eq.to_edge(UP) new_old_style_eq.highlight(RED) big_times = TexMobject("\\times").highlight(YELLOW) big_times.shift(big_oplus.get_center()) self.play( Transform(old_style_eq, new_old_style_eq), Transform(syms, new_syms, path_arc = np.pi/2), Transform(big_oplus, big_times) ) self.dither(4)
class Notation(Scene): def construct(self): self.introduce_notation() self.shift_to_good_and_back() self.shift_to_visuals() self.swipe_left() def introduce_notation(self): notation = TextMobject("Notation") notation.to_edge(UP) self.sum1 = TexMobject("\\sum_{n=1}^\\infty \\dfrac{1}{n}") self.prod1 = TexMobject( "\\prod_{p\\text{ prime}}\\left(1-p^{-s}\\right)") self.trigs1 = TexMobject([ ["\\sin", "(x)"], ["\\cos", "(x)"], ["\\tan", "(x)"], ], next_to_direction=DOWN) self.func1 = TexMobject("f(x) = y") symbols = [self.sum1, self.prod1, self.trigs1, self.func1] for sym, vect in zip(symbols, compass_directions(4, UP + LEFT)): sym.scale(0.5) vect[0] *= 2 sym.shift(vect) self.symbols = VMobject(*symbols) self.play(Write(notation)) self.play(Write(self.symbols)) self.wait() self.add(notation, self.symbols) def shift_to_good_and_back(self): sum2 = self.sum1.copy() sigma = sum2.submobjects[1] plus = TexMobject("+").replace(sigma) sum2.submobjects[1] = plus prod2 = self.prod1.copy() pi = prod2.submobjects[0] times = TexMobject("\\times").replace(pi) prod2.submobjects[0] = times new_sin, new_cos, new_tan = [ VMobject().set_anchor_points(corners, mode="corners").replace( trig_part.split()[0]) for corners, trig_part in zip([ [RIGHT, RIGHT + UP, LEFT], [RIGHT + UP, LEFT, RIGHT], [RIGHT + UP, RIGHT, LEFT], ], self.trigs1.split()) ] x1, x2, x3 = [ trig_part.split()[1] for trig_part in self.trigs1.split() ] trigs2 = VMobject( VMobject(new_sin, x1), VMobject(new_cos, x2), VMobject(new_tan, x3), ) x, arrow, y = TexMobject("x \\rightarrow y").split() f = TexMobject("f") f.next_to(arrow, UP) func2 = VMobject(f, VMobject(), x, VMobject(), arrow, y) func2.scale(0.5) func2.shift(self.func1.get_center()) good_symbols = VMobject(sum2, prod2, trigs2, func2) bad_symbols = self.symbols.copy() self.play(Transform(self.symbols, good_symbols, path_arc=np.pi)) self.wait(3) self.play(Transform(self.symbols, bad_symbols, path_arc=np.pi)) self.wait() def shift_to_visuals(self): sigma, prod, trig, func = self.symbols.split() new_trig = trig.copy() sin, cos, tan = [ trig_part.split()[0] for trig_part in new_trig.split() ] trig_anim = TrigAnimation() sin.highlight(trig_anim.sin_color) cos.highlight(trig_anim.cos_color) tan.highlight(trig_anim.tan_color) new_trig.to_corner(UP + RIGHT) sum_lines = self.get_harmonic_sum_lines() self.play( Transform(trig, new_trig), *it.starmap(ApplyMethod, [ (sigma.to_corner, UP + LEFT), (prod.shift, 15 * LEFT), (func.shift, 5 * UP), ])) sum_lines.next_to(sigma, DOWN) self.remove(prod, func) self.play(trig_anim, Write(sum_lines)) self.play(trig_anim) self.wait() def get_harmonic_sum_lines(self): result = VMobject() for n in range(1, 8): big_line = NumberLine(x_min=0, x_max=1.01, tick_frequency=1. / n, numbers_with_elongated_ticks=[], color=WHITE) little_line = Line(big_line.number_to_point(0), big_line.number_to_point(1. / n), color=RED) big_line.add(little_line) big_line.shift(0.5 * n * DOWN) result.add(big_line) return result def swipe_left(self): everyone = VMobject(*self.mobjects) self.play(ApplyMethod(everyone.shift, 20 * LEFT))
def solveEquation(self): leftBrace = TexMobject("[") rightBrace = TexMobject("]") xBraces = Group(leftBrace, rightBrace) xBraces.stretch(2, 0) downBrace = TexMobject("[") upBrace = TexMobject("]") yBraces = Group(downBrace, upBrace) yBraces.stretch(2, 0) yBraces.rotate(TAU / 4) lowerX = self.initial_lower_x lowerY = self.func(lowerX) upperX = self.initial_upper_x upperY = self.func(upperX) leftBrace.move_to(self.coords_to_point(lowerX, 0), aligned_edge=LEFT) leftBraceLabel = DecimalNumber(lowerX) leftBraceLabel.next_to(leftBrace, DOWN + LEFT, buff=SMALL_BUFF) leftBraceLabelAnimation = ContinualChangingDecimal( leftBraceLabel, lambda alpha: self.point_to_coords(leftBrace.get_center())[0], tracked_mobject=leftBrace) self.add(leftBraceLabelAnimation) rightBrace.move_to(self.coords_to_point(upperX, 0), aligned_edge=RIGHT) rightBraceLabel = DecimalNumber(upperX) rightBraceLabel.next_to(rightBrace, DOWN + RIGHT, buff=SMALL_BUFF) rightBraceLabelAnimation = ContinualChangingDecimal( rightBraceLabel, lambda alpha: self.point_to_coords(rightBrace.get_center())[0], tracked_mobject=rightBrace) self.add(rightBraceLabelAnimation) downBrace.move_to(self.coords_to_point(0, lowerY), aligned_edge=DOWN) downBraceLabel = DecimalNumber(lowerY) downBraceLabel.next_to(downBrace, LEFT + DOWN, buff=SMALL_BUFF) downBraceLabelAnimation = ContinualChangingDecimal( downBraceLabel, lambda alpha: self.point_to_coords(downBrace.get_center())[1], tracked_mobject=downBrace) self.add(downBraceLabelAnimation) upBrace.move_to(self.coords_to_point(0, upperY), aligned_edge=UP) upBraceLabel = DecimalNumber(upperY) upBraceLabel.next_to(upBrace, LEFT + UP, buff=SMALL_BUFF) upBraceLabelAnimation = ContinualChangingDecimal( upBraceLabel, lambda alpha: self.point_to_coords(upBrace.get_center())[1], tracked_mobject=upBrace) self.add(upBraceLabelAnimation) lowerDotPoint = self.input_to_graph_point(lowerX, self.graph) lowerDotXPoint = self.coords_to_point(lowerX, 0) lowerDotYPoint = self.coords_to_point(0, self.func(lowerX)) lowerDot = Dot(lowerDotPoint) upperDotPoint = self.input_to_graph_point(upperX, self.graph) upperDot = Dot(upperDotPoint) upperDotXPoint = self.coords_to_point(upperX, 0) upperDotYPoint = self.coords_to_point(0, self.func(upperX)) lowerXLine = Line(lowerDotXPoint, lowerDotPoint, stroke_width=1, color=YELLOW) upperXLine = Line(upperDotXPoint, upperDotPoint, stroke_width=1, color=YELLOW) lowerYLine = Line(lowerDotYPoint, lowerDotPoint, stroke_width=1, color=YELLOW) upperYLine = Line(upperDotYPoint, upperDotPoint, stroke_width=1, color=YELLOW) self.add(lowerXLine, upperXLine, lowerYLine, upperYLine) self.add(xBraces, yBraces, lowerDot, upperDot) for i in range(self.num_iterations): if i == self.iteration_at_which_to_start_zoom: self.activate_zooming() self.little_rectangle.move_to( self.coords_to_point(self.targetX, self.targetY)) inverseZoomFactor = 1 / float(self.zoom_factor) self.play(lowerDot.scale_in_place, inverseZoomFactor, upperDot.scale_in_place, inverseZoomFactor) def makeUpdater(xAtStart): def updater(group, alpha): dot, xBrace, yBrace, xLine, yLine = group newX = interpolate(xAtStart, midX, alpha) newY = self.func(newX) graphPoint = self.input_to_graph_point(newX, self.graph) dot.move_to(graphPoint) xAxisPoint = self.coords_to_point(newX, 0) xBrace.move_to(xAxisPoint) yAxisPoint = self.coords_to_point(0, newY) yBrace.move_to(yAxisPoint) xLine.put_start_and_end_on(xAxisPoint, graphPoint) yLine.put_start_and_end_on(yAxisPoint, graphPoint) return group return updater midX = (lowerX + upperX) / float(2) midY = self.func(midX) midCoords = self.coords_to_point(midX, midY) midColor = RED midXPoint = Dot(self.coords_to_point(midX, 0), color=midColor) self.play(ReplacementTransform(leftBrace.copy(), midXPoint), ReplacementTransform(rightBrace.copy(), midXPoint)) midXLine = Line(self.coords_to_point(midX, 0), midCoords, color=midColor) self.play(ShowCreation(midXLine)) midDot = Dot(midCoords, color=midColor) if (self.iteration_at_which_to_start_zoom != None and i >= self.iteration_at_which_to_start_zoom): midDot.scale_in_place(inverseZoomFactor) self.add(midDot) midYLine = Line(midCoords, self.coords_to_point(0, midY), color=midColor) self.play(ShowCreation(midYLine)) if midY < self.targetY: movingGroup = Group(lowerDot, leftBrace, downBrace, lowerXLine, lowerYLine) self.play(UpdateFromAlphaFunc(movingGroup, makeUpdater(lowerX))) lowerX = midX lowerY = midY else: movingGroup = Group(upperDot, rightBrace, upBrace, upperXLine, upperYLine) self.play(UpdateFromAlphaFunc(movingGroup, makeUpdater(upperX))) upperX = midX upperY = midY self.remove(midXLine, midDot, midYLine) self.wait()
class Notation(Scene): def construct(self): self.introduce_notation() self.shift_to_good_and_back() self.shift_to_visuals() self.swipe_left() def introduce_notation(self): notation = TextMobject("Notation") notation.to_edge(UP) self.sum1 = TexMobject("\\sum_{n=1}^\\infty \\dfrac{1}{n}") self.prod1 = TexMobject("\\prod_{p\\text{ prime}}\\left(1-p^{-s}\\right)") self.trigs1 = TexMobject([ ["\\sin", "(x)"], ["\\cos", "(x)"], ["\\tan", "(x)"], ], next_to_direction = DOWN) self.func1 = TexMobject("f(x) = y") symbols = [self.sum1, self.prod1, self.trigs1, self.func1] for sym, vect in zip(symbols, compass_directions(4, UP+LEFT)): sym.scale(0.5) vect[0] *= 2 sym.shift(vect) self.symbols = VMobject(*symbols) self.play(Write(notation)) self.play(Write(self.symbols)) self.dither() self.add(notation, self.symbols) def shift_to_good_and_back(self): sum2 = self.sum1.copy() sigma = sum2.submobjects[1] plus = TexMobject("+").replace(sigma) sum2.submobjects[1] = plus prod2 = self.prod1.copy() pi = prod2.submobjects[0] times = TexMobject("\\times").replace(pi) prod2.submobjects[0] = times new_sin, new_cos, new_tan = [ VMobject().set_anchor_points( corners, mode = "corners" ).replace(trig_part.split()[0]) for corners, trig_part in zip( [ [RIGHT, RIGHT+UP, LEFT], [RIGHT+UP, LEFT, RIGHT], [RIGHT+UP, RIGHT, LEFT], ], self.trigs1.split() ) ] x1, x2, x3 = [ trig_part.split()[1] for trig_part in self.trigs1.split() ] trigs2 = VMobject( VMobject(new_sin, x1), VMobject(new_cos, x2), VMobject(new_tan, x3), ) x, arrow, y = TexMobject("x \\rightarrow y").split() f = TexMobject("f") f.next_to(arrow, UP) func2 = VMobject(f, VMobject(), x, VMobject(), arrow, y) func2.scale(0.5) func2.shift(self.func1.get_center()) good_symbols = VMobject(sum2, prod2, trigs2, func2) bad_symbols = self.symbols.copy() self.play(Transform( self.symbols, good_symbols, path_arc = np.pi )) self.dither(3) self.play(Transform( self.symbols, bad_symbols, path_arc = np.pi )) self.dither() def shift_to_visuals(self): sigma, prod, trig, func = self.symbols.split() new_trig = trig.copy() sin, cos, tan = [ trig_part.split()[0] for trig_part in new_trig.split() ] trig_anim = TrigAnimation() sin.highlight(trig_anim.sin_color) cos.highlight(trig_anim.cos_color) tan.highlight(trig_anim.tan_color) new_trig.to_corner(UP+RIGHT) sum_lines = self.get_harmonic_sum_lines() self.play( Transform(trig, new_trig), *it.starmap(ApplyMethod, [ (sigma.to_corner, UP+LEFT), (prod.shift, 15*LEFT), (func.shift, 5*UP), ]) ) sum_lines.next_to(sigma, DOWN) self.remove(prod, func) self.play( trig_anim, Write(sum_lines) ) self.play(trig_anim) self.dither() def get_harmonic_sum_lines(self): result = VMobject() for n in range(1, 8): big_line = NumberLine( x_min = 0, x_max = 1.01, tick_frequency = 1./n, numbers_with_elongated_ticks = [], color = WHITE ) little_line = Line( big_line.number_to_point(0), big_line.number_to_point(1./n), color = RED ) big_line.add(little_line) big_line.shift(0.5*n*DOWN) result.add(big_line) return result def swipe_left(self): everyone = VMobject(*self.mobjects) self.play(ApplyMethod(everyone.shift, 20*LEFT))