from manimlib.imports import * #### Warning, scenes here not updated based on most recent GraphScene changes ####### class CircleScene(PiCreatureScene): CONFIG = { "radius" : 1.5, "stroke_color" : WHITE, "fill_color" : BLUE_E, "fill_opacity" : 0.5, "radial_line_color" : MAROON_B, "outer_ring_color" : GREEN_E, "dR" : 0.1, "dR_color" : YELLOW, "unwrapped_tip" : ORIGIN, "include_pi_creature" : False, "circle_corner" : UP+LEFT } def setup(self): self.circle = Circle( radius = self.radius, stroke_color = self.stroke_color, fill_color = self.fill_color, fill_opacity = self.fill_opacity, ) self.circle.to_corner(self.circle_corner, buff = MED_LARGE_BUFF) self.radius_line = Line( self.circle.get_center(), self.circle.get_right(), color = self.radial_line_color ) self.radius_brace = Brace(self.radius_line, buff = SMALL_BUFF) self.radius_label = self.radius_brace.get_text("$R$", buff = SMALL_BUFF) self.add( self.circle, self.radius_line, self.radius_brace, self.radius_label ) self.pi_creature = self.create_pi_creature() if self.include_pi_creature: self.add(self.pi_creature) else: self.pi_creature.set_fill(opacity = 0) def create_pi_creature(self): return Mortimer().to_corner(DOWN+RIGHT) def introduce_circle(self, added_anims = []): self.remove(self.circle) self.play( ShowCreation(self.radius_line), GrowFromCenter(self.radius_brace), Write(self.radius_label), ) self.circle.set_fill(opacity = 0) self.play( Rotate( self.radius_line, 2*np.pi-0.001, about_point = self.circle.get_center(), ), ShowCreation(self.circle), *added_anims, run_time = 2 ) self.play( self.circle.set_fill, self.fill_color, self.fill_opacity, Animation(self.radius_line), Animation(self.radius_brace), Animation(self.radius_label), ) def increase_radius(self, numerical_dr = True, run_time = 2): radius_mobs = VGroup( self.radius_line, self.radius_brace, self.radius_label ) nudge_line = Line( self.radius_line.get_right(), self.radius_line.get_right() + self.dR*RIGHT, color = self.dR_color ) nudge_arrow = Arrow( nudge_line.get_center() + 0.5*RIGHT+DOWN, nudge_line.get_center(), color = YELLOW, buff = SMALL_BUFF, tip_length = 0.2, ) if numerical_dr: nudge_label = TexMobject("%.01f"%self.dR) else: nudge_label = TexMobject("dr") nudge_label.set_color(self.dR_color) nudge_label.scale(0.75) nudge_label.next_to(nudge_arrow.get_start(), DOWN) radius_mobs.add(nudge_line, nudge_arrow, nudge_label) outer_ring = self.get_outer_ring() self.play( FadeIn(outer_ring), ShowCreation(nudge_line), ShowCreation(nudge_arrow), Write(nudge_label), run_time = run_time/2. ) self.wait(run_time/2.) self.nudge_line = nudge_line self.nudge_arrow = nudge_arrow self.nudge_label = nudge_label self.outer_ring = outer_ring return outer_ring def get_ring(self, radius, dR, color = GREEN): ring = Circle(radius = radius + dR).center() inner_ring = Circle(radius = radius) inner_ring.rotate(np.pi, RIGHT) ring.append_vectorized_mobject(inner_ring) ring.set_stroke(width = 0) ring.set_fill(color) ring.move_to(self.circle) ring.R = radius ring.dR = dR return ring def get_outer_ring(self): return self.get_ring( radius = self.radius, dR = self.dR, color = self.outer_ring_color ) def unwrap_ring(self, ring, **kwargs): self.unwrap_rings(ring, **kwargs) def unwrap_rings(self, *rings, **kwargs): added_anims = kwargs.get("added_anims", []) rings = VGroup(*rings) unwrapped = VGroup(*[ self.get_unwrapped(ring, **kwargs) for ring in rings ]) self.play( rings.rotate, np.pi/2, rings.next_to, unwrapped.get_bottom(), UP, run_time = 2, path_arc = np.pi/2 ) self.play( Transform(rings, unwrapped, run_time = 3), *added_anims ) def get_unwrapped(self, ring, to_edge = LEFT, **kwargs): R = ring.R R_plus_dr = ring.R + ring.dR n_anchors = ring.get_num_curves() result = VMobject() result.set_points_as_corners([ interpolate(np.pi*R_plus_dr*LEFT, np.pi*R_plus_dr*RIGHT, a) for a in np.linspace(0, 1, n_anchors/2) ]+[ interpolate(np.pi*R*RIGHT+ring.dR*UP, np.pi*R*LEFT+ring.dR*UP, a) for a in np.linspace(0, 1, n_anchors/2) ]) result.set_style_data( stroke_color = ring.get_stroke_color(), stroke_width = ring.get_stroke_width(), fill_color = ring.get_fill_color(), fill_opacity = ring.get_fill_opacity(), ) result.move_to(self.unwrapped_tip, aligned_edge = DOWN) result.shift(R_plus_dr*DOWN) result.to_edge(to_edge) return result ###################### class PatronsOnly(Scene): def construct(self): morty = Mortimer() morty.shift(2*DOWN) title = TextMobject(""" This is a draft for patrons only """) title.set_color(RED) title.scale(2) title.to_edge(UP) self.add(morty) self.play( Write(title), morty.change_mode, "wave_1" ) self.play(Blink(morty)) self.play( morty.change_mode, "pondering", morty.look_at, title ) self.play(Blink(morty)) self.wait() class Introduction(TeacherStudentsScene): def construct(self): self.show_series() self.look_to_center() self.go_through_students() self.zoom_in_on_first() def show_series(self): series = VideoSeries() series.to_edge(UP) this_video = series[0] this_video.set_color(YELLOW) this_video.save_state() this_video.set_fill(opacity = 0) this_video.center() this_video.set_height(FRAME_HEIGHT) self.this_video = this_video words = TextMobject( "Welcome to \\\\", "Essence of calculus" ) words.set_color_by_tex("Essence of calculus", YELLOW) self.remove(self.teacher) self.teacher.change_mode("happy") self.add(self.teacher) self.play( FadeIn( series, lag_ratio = 0.5, run_time = 2 ), Blink(self.get_teacher()) ) self.teacher_says(words, target_mode = "hooray") self.play( ApplyMethod(this_video.restore, run_time = 3), *[ ApplyFunction( lambda p : p.change_mode("hooray").look_at(series[1]), pi ) for pi in self.get_pi_creatures() ] ) def homotopy(x, y, z, t): alpha = (0.7*x + FRAME_X_RADIUS)/(FRAME_WIDTH) beta = squish_rate_func(smooth, alpha-0.15, alpha+0.15)(t) return (x, y - 0.3*np.sin(np.pi*beta), z) self.play( Homotopy( homotopy, series, apply_function_kwargs = {"maintain_smoothness" : False}, ), *[ ApplyMethod(pi.look_at, series[-1]) for pi in self.get_pi_creatures() ], run_time = 5 ) self.play( FadeOut(self.teacher.bubble), FadeOut(self.teacher.bubble.content), *[ ApplyMethod(pi.change_mode, "happy") for pi in self.get_pi_creatures() ] ) def look_to_center(self): anims = [] for pi in self.get_pi_creatures(): anims += [ pi.change_mode, "pondering", pi.look_at, 2*UP ] self.play(*anims) self.random_blink(6) self.play(*[ ApplyMethod(pi.change_mode, "happy") for pi in self.get_pi_creatures() ]) def go_through_students(self): pi1, pi2, pi3 = self.get_students() for pi in pi1, pi2, pi3: pi.save_state() bubble = pi1.get_bubble(width = 5) bubble.set_fill(BLACK, opacity = 1) remembered_symbols = VGroup( TexMobject("\\int_0^1 \\frac{1}{1-x^2}\\,dx").shift(UP+LEFT), TexMobject("\\frac{d}{dx} e^x = e^x").shift(DOWN+RIGHT), ) cant_wait = TextMobject("I literally \\\\ can't wait") big_derivative = TexMobject(""" \\frac{d}{dx} \\left( \\sin(x^2)2^{\\sqrt{x}} \\right) """) self.play( pi1.change_mode, "confused", pi1.look_at, bubble.get_right(), ShowCreation(bubble), pi2.fade, pi3.fade, ) bubble.add_content(remembered_symbols) self.play(Write(remembered_symbols)) self.play(ApplyMethod( remembered_symbols.fade, 0.7, lag_ratio = 0.5, run_time = 3 )) self.play( pi1.restore, pi1.fade, pi2.restore, pi2.change_mode, "hooray", pi2.look_at, bubble.get_right(), bubble.pin_to, pi2, FadeOut(remembered_symbols), ) bubble.add_content(cant_wait) self.play(Write(cant_wait, run_time = 2)) self.play(Blink(pi2)) self.play( pi2.restore, pi2.fade, pi3.restore, pi3.change_mode, "pleading", pi3.look_at, bubble.get_right(), bubble.pin_to, pi3, FadeOut(cant_wait) ) bubble.add_content(big_derivative) self.play(Write(big_derivative)) self.play(Blink(pi3)) self.wait() def zoom_in_on_first(self): this_video = self.this_video self.remove(this_video) this_video.generate_target() this_video.target.set_height(FRAME_HEIGHT) this_video.target.center() this_video.target.set_fill(opacity = 0) everything = VGroup(*self.get_mobjects()) self.play( FadeOut(everything), MoveToTarget(this_video, run_time = 2) ) class IntroduceCircle(Scene): def construct(self): circle = Circle(radius = 3, color = WHITE) circle.to_edge(LEFT) radius = Line(circle.get_center(), circle.get_right()) radius.set_color(MAROON_B) R = TexMobject("R").next_to(radius, UP) area, circumference = words = VGroup(*list(map(TextMobject, [ "Area =", "Circumference =" ]))) area.set_color(BLUE) circumference.set_color(YELLOW) words.arrange(DOWN, aligned_edge = LEFT) words.next_to(circle, RIGHT) words.to_edge(UP) pi_R, pre_squared = TexMobject("\\pi R", "{}^2") squared = TexMobject("2").replace(pre_squared) area_form = VGroup(pi_R, squared) area_form.next_to(area, RIGHT) two, pi_R = TexMobject("2", "\\pi R") circum_form = VGroup(pi_R, two) circum_form.next_to(circumference, RIGHT) derivative = TexMobject( "\\frac{d}{dR}", "\\pi R^2", "=", "2\\pi R" ) integral = TexMobject( "\\int_0^R", "2\\pi r", "\\, dR = ", "\\pi R^2" ) up_down_arrow = TexMobject("\\Updownarrow") calc_stuffs = VGroup(derivative, up_down_arrow, integral) calc_stuffs.arrange(DOWN) calc_stuffs.next_to(words, DOWN, buff = LARGE_BUFF, aligned_edge = LEFT) brace = Brace(calc_stuffs, RIGHT) to_be_explained = brace.get_text("To be \\\\ explained") VGroup(brace, to_be_explained).set_color(GREEN) self.play(ShowCreation(radius), Write(R)) self.play( Rotate(radius, 2*np.pi, about_point = circle.get_center()), ShowCreation(circle) ) self.play( FadeIn(area), Write(area_form), circle.set_fill, area.get_color(), 0.5, Animation(radius), Animation(R), ) self.wait() self.play( circle.set_stroke, circumference.get_color(), FadeIn(circumference), Animation(radius), Animation(R), ) self.play(Transform( area_form.copy(), circum_form, path_arc = -np.pi/2, run_time = 3 )) self.wait() self.play( area_form.copy().replace, derivative[1], circum_form.copy().replace, derivative[3], Write(derivative[0]), Write(derivative[2]), run_time = 1 ) self.wait() self.play( area_form.copy().replace, integral[3], Transform(circum_form.copy(), integral[1]), Write(integral[0]), Write(integral[2]), run_time = 1 ) self.wait() self.play(Write(up_down_arrow)) self.wait() self.play( GrowFromCenter(brace), Write(to_be_explained) ) self.wait() class HeartOfCalculus(GraphScene): CONFIG = { "x_labeled_nums" : [], "y_labeled_nums" : [], } def construct(self): self.setup_axes() self.graph_function(lambda x : 3*np.sin(x/2) + x) rect_sets = [ self.get_riemann_rectangles( 0, self.x_max, 1./(2**n), stroke_width = 1./(n+1) ) for n in range(6) ] rects = rect_sets.pop(0) rects.save_state() rects.stretch_to_fit_height(0) rects.shift( (self.graph_origin[1] - rects.get_center()[1])*UP ) self.play( rects.restore, lag_ratio = 0.5, run_time = 3 ) while rect_sets: self.play( Transform(rects, rect_sets.pop(0)), run_time = 2 ) class PragmatismToArt(Scene): def construct(self): morty = Mortimer() morty.to_corner(DOWN+RIGHT) morty.shift(LEFT) pragmatism = TextMobject("Pragmatism") art = TextMobject("Art") pragmatism.move_to(morty.get_corner(UP+LEFT), aligned_edge = DOWN) art.move_to(morty.get_corner(UP+RIGHT), aligned_edge = DOWN) art.shift(0.2*(LEFT+UP)) circle1 = Circle( radius = 2, fill_opacity = 1, fill_color = BLUE_E, stroke_width = 0, ) circle2 = Circle( radius = 2, stroke_color = YELLOW ) arrow = DoubleArrow(LEFT, RIGHT, color = WHITE) circle_group = VGroup(circle1, arrow, circle2) circle_group.arrange() circle_group.to_corner(UP+LEFT) circle2.save_state() circle2.move_to(circle1) q_marks = TextMobject("???").next_to(arrow, UP) self.play( morty.change_mode, "raise_right_hand", morty.look_at, pragmatism, Write(pragmatism, run_time = 1), ) self.play(Blink(morty)) self.play( morty.change_mode, "raise_left_hand", morty.look_at, art, Transform( VectorizedPoint(morty.get_corner(UP+RIGHT)), art ), pragmatism.fade, 0.7, pragmatism.rotate_in_place, np.pi/4, pragmatism.shift, DOWN+LEFT ) self.play(Blink(morty)) self.play( GrowFromCenter(circle1), morty.look_at, circle1 ) self.play(ShowCreation(circle2)) self.play( ShowCreation(arrow), Write(q_marks), circle2.restore ) self.play(Blink(morty)) class IntroduceTinyChangeInArea(CircleScene): CONFIG = { "include_pi_creature" : True, } def construct(self): new_area_form, minus, area_form = expression = TexMobject( "\\pi (R + 0.1)^2", "-", "\\pi R^2" ) VGroup(*new_area_form[4:7]).set_color(self.dR_color) expression_brace = Brace(expression, UP) change_in_area = expression_brace.get_text("Change in area") change_in_area.set_color(self.outer_ring_color) area_brace = Brace(area_form) area_word = area_brace.get_text("Area") area_word.set_color(BLUE) new_area_brace = Brace(new_area_form) new_area_word = new_area_brace.get_text("New area") group = VGroup( expression, expression_brace, change_in_area, area_brace, area_word, new_area_brace, new_area_word ) group.to_edge(UP).shift(RIGHT) group.save_state() area_group = VGroup(area_form, area_brace, area_word) area_group.save_state() area_group.next_to(self.circle, RIGHT, buff = LARGE_BUFF) self.introduce_circle( added_anims = [self.pi_creature.change_mode, "speaking"] ) self.play(Write(area_group)) self.change_mode("happy") outer_ring = self.increase_radius() self.wait() self.play( area_group.restore, GrowFromCenter(expression_brace), Write(new_area_form), Write(minus), Write(change_in_area), self.pi_creature.change_mode, "confused", ) self.play( Write(new_area_word), GrowFromCenter(new_area_brace) ) self.wait(2) self.play( group.fade, 0.7, self.pi_creature.change_mode, "happy" ) self.wait() self.play( outer_ring.set_color, YELLOW, Animation(self.nudge_arrow), Animation(self.nudge_line), rate_func = there_and_back ) self.show_unwrapping(outer_ring) self.play(group.restore) self.work_out_expression(group) self.second_unwrapping(outer_ring) insignificant = TextMobject("Insignificant") insignificant.set_color(self.dR_color) insignificant.move_to(self.error_words) self.play(Transform(self.error_words, insignificant)) self.wait() big_rect = Rectangle( width = FRAME_WIDTH, height = FRAME_HEIGHT, fill_color = BLACK, fill_opacity = 0.85, stroke_width = 0, ) self.play( FadeIn(big_rect), area_form.set_color, BLUE, self.two_pi_R.set_color, GREEN, self.pi_creature.change_mode, "happy" ) def show_unwrapping(self, outer_ring): almost_rect = outer_ring.copy() self.unwrap_ring( almost_rect, added_anims = [self.pi_creature.change_mode, "pondering"] ) circum_brace = Brace(almost_rect, UP).scale_in_place(0.95) dR_brace = TexMobject("\\}") dR_brace.stretch(0.5, 1) dR_brace.next_to(almost_rect, RIGHT) two_pi_R = circum_brace.get_text("$2\\pi R$") dR = TexMobject("$0.1$").scale(0.7).next_to(dR_brace, RIGHT) dR.set_color(self.dR_color) two_pi_R.generate_target() dR.generate_target() lp, rp = TexMobject("()") change_in_area = TextMobject( "Change in area $\\approx$" ) final_area = VGroup( change_in_area, two_pi_R.target, lp, dR.target.scale(1./0.7), rp ) final_area.arrange(RIGHT, buff = SMALL_BUFF) final_area.next_to(almost_rect, DOWN, buff = MED_LARGE_BUFF) final_area.set_color(GREEN_A) final_area[3].set_color(self.dR_color) change_in_area.shift(0.1*LEFT) self.play( GrowFromCenter(circum_brace), Write(two_pi_R) ) self.wait() self.play( GrowFromCenter(dR_brace), Write(dR) ) self.wait() self.play( MoveToTarget(two_pi_R.copy()), MoveToTarget(dR.copy()), Write(change_in_area, run_time = 1), Write(lp), Write(rp), ) self.remove(*self.get_mobjects_from_last_animation()) self.add(final_area) self.play( self.pi_creature.change_mode, "happy", self.pi_creature.look_at, final_area ) self.wait() group = VGroup( almost_rect, final_area, two_pi_R, dR, circum_brace, dR_brace ) self.play(group.fade) def work_out_expression(self, expression_group): exp, exp_brace, title, area_brace, area_word, new_area_brace, new_area_word = expression_group new_area_form, minus, area_form = exp expanded = TexMobject( "\\pi R^2", "+", "2\\pi R (0.1)", "+", "\\pi (0.1)^2", "-", "\\pi R^2", ) pi_R_squared, plus, two_pi_R_dR, plus2, pi_dR_squared, minus2, pi_R_squared2 = expanded for subset in two_pi_R_dR[4:7], pi_dR_squared[2:5]: VGroup(*subset).set_color(self.dR_color) expanded.next_to(new_area_form, DOWN, aligned_edge = LEFT, buff = MED_SMALL_BUFF) expanded.shift(LEFT/2.) faders = [area_brace, area_word, new_area_brace, new_area_word] self.play(*list(map(FadeOut, faders))) trips = [ ([0, 2, 8], pi_R_squared, plus), ([8, 0, 2, 1, 4, 5, 6, 7], two_pi_R_dR, plus2), ([0, 1, 4, 5, 6, 7, 8], pi_dR_squared, VGroup()), ] to_remove = [] for subset, target, writer in trips: starter = VGroup( *np.array(list(new_area_form.copy()))[subset] ) self.play( Transform(starter, target, run_time = 2), Write(writer) ) to_remove += self.get_mobjects_from_last_animation() self.wait() self.play( Transform(minus.copy(), minus2), Transform(area_form.copy(), pi_R_squared2), ) to_remove += self.get_mobjects_from_last_animation() self.remove(*to_remove) self.add(self.pi_creature, *expanded) self.wait(2) self.play(*[ ApplyMethod(mob.set_color, RED) for mob in (pi_R_squared, pi_R_squared2) ]) self.wait() self.play(*[ ApplyMethod(mob.fade, 0.7) for mob in (plus, pi_R_squared, pi_R_squared2, minus2) ]) self.wait() approx_brace = Brace(two_pi_R_dR) error_brace = Brace(pi_dR_squared, buff = SMALL_BUFF) error_words = error_brace.get_text("Error", buff = SMALL_BUFF) error_words.set_color(RED) self.error_words = error_words self.play( GrowFromCenter(approx_brace), self.pi_creature.change_mode, "hooray" ) self.wait() self.play( GrowFromCenter(error_brace), Write(error_words), self.pi_creature.change_mode, "confused" ) self.wait() self.two_pi_R = VGroup(*two_pi_R_dR[:3]) def second_unwrapping(self, outer_ring): almost_rect = outer_ring.copy() rect = Rectangle( width = 2*np.pi*self.radius, height = self.dR, fill_color = self.outer_ring_color, fill_opacity = 1, stroke_width = 0, ) self.play( almost_rect.set_color, YELLOW, self.pi_creature.change_mode, "pondering" ) self.unwrap_ring(almost_rect) self.wait() rect.move_to(almost_rect) self.play(FadeIn(rect)) self.wait() def create_pi_creature(self): morty = Mortimer() morty.scale(0.7) morty.to_corner(DOWN+RIGHT) return morty class CleanUpABit(TeacherStudentsScene): def construct(self): self.teacher_says(""" Let's clean that up a bit """) self.random_blink(2) class BuildToDADR(CircleScene): CONFIG = { "include_pi_creature" : True, } def construct(self): self.outer_ring = self.increase_radius() self.write_initial_terms() self.show_fractions() self.transition_to_dR() self.elaborate_on_d() self.not_infinitely_small() def create_pi_creature(self): morty = Mortimer() morty.flip() morty.to_corner(DOWN+LEFT) return morty def write_initial_terms(self): change = TextMobject("Change in area") change.set_color(GREEN_B) equals, two_pi_R, dR, plus, pi, dR2, squared = rhs = TexMobject( "=", "2 \\pi R", "(0.1)", "+", "\\pi", "(0.1)", "^2" ) VGroup(dR, dR2).set_color(self.dR_color) change.next_to(self.circle, buff = LARGE_BUFF) rhs.next_to(change) circum_brace = Brace(two_pi_R, UP) circum_text = circum_brace.get_text("Circumference") error_brace = Brace(VGroup(pi, squared), UP) error_text = error_brace.get_text("Error") error_text.set_color(RED) self.play( Write(change, run_time = 1), self.pi_creature.change_mode, "pondering", ) self.wait() self.play(*it.chain( list(map(Write, [equals, two_pi_R, dR])), list(map(FadeIn, [circum_text, circum_brace])) )) self.wait() self.play(*it.chain( list(map(Write, [plus, pi, dR2, squared])), list(map(FadeIn, [error_brace, error_text])) )) self.wait(2) self.change = change self.circum_term = VGroup(two_pi_R, dR) self.circum_term.label = VGroup(circum_brace, circum_text) self.error_term = VGroup(pi, dR2, squared) self.error_term.label = VGroup(error_brace, error_text) self.equals = equals self.plus = plus def show_fractions(self): terms = [self.change, self.circum_term, self.error_term] for term in terms: term.frac_line = TexMobject("\\frac{\\quad}{\\quad}") term.frac_line.stretch_to_fit_width(term.get_width()) term.frac_line.next_to(term, DOWN, buff = SMALL_BUFF) term.denom = TexMobject("(0.1)") term.denom.next_to(term.frac_line, DOWN, buff = SMALL_BUFF) term.denom.set_color(self.dR_color) term.denom.save_state() term.denom.replace(self.nudge_label) self.equals.generate_target() self.equals.target.next_to(self.change.frac_line, RIGHT) self.plus.generate_target() self.plus.target.next_to(self.circum_term.frac_line, RIGHT) self.play(*it.chain( [Write(term.frac_line) for term in terms], list(map(MoveToTarget, [self.equals, self.plus])) )) self.play(*[term.denom.restore for term in terms]) self.wait(2) self.play( self.outer_ring.set_color, YELLOW, rate_func = there_and_back ) self.play( self.nudge_label.scale_in_place, 2, rate_func = there_and_back ) self.wait(2) canceleres = VGroup(self.circum_term[1], self.circum_term.denom) self.play(canceleres.set_color, RED) self.play(FadeOut(canceleres)) self.remove(self.circum_term) self.play( self.circum_term[0].move_to, self.circum_term.frac_line, LEFT, self.circum_term[0].shift, 0.1*UP, FadeOut(self.circum_term.frac_line), MaintainPositionRelativeTo( self.circum_term.label, self.circum_term[0] ) ) self.circum_term = self.circum_term[0] self.wait(2) self.play( FadeOut(self.error_term[-1]), FadeOut(self.error_term.denom) ) self.error_term.remove(self.error_term[-1]) self.play( self.error_term.move_to, self.error_term.frac_line, self.error_term.shift, 0.3*LEFT + 0.15*UP, FadeOut(self.error_term.frac_line), self.plus.shift, 0.7*LEFT + 0.1*UP, MaintainPositionRelativeTo( self.error_term.label, self.error_term ) ) self.wait() def transition_to_dR(self): dRs = VGroup( self.nudge_label, self.change.denom, self.error_term[1], ) error_brace, error_text = self.error_term.label for s, width in ("(0.01)", 0.05), ("(0.001)", 0.03), ("dR", 0.03): new_dRs = VGroup(*[ TexMobject(s).move_to(mob, LEFT) for mob in dRs ]) new_dRs.set_color(self.dR_color) new_outer_ring = self.get_ring(self.radius, width) new_nudge_line = self.nudge_line.copy() new_nudge_line.set_width(width) new_nudge_line.move_to(self.nudge_line, LEFT) error_brace.target = error_brace.copy() error_brace.target.stretch_to_fit_width( VGroup(self.error_term[0], new_dRs[-1]).get_width() ) error_brace.target.move_to(error_brace, LEFT) self.play( MoveToTarget(error_brace), Transform(self.outer_ring, new_outer_ring), Transform(self.nudge_line, new_nudge_line), *[ Transform(*pair) for pair in zip(dRs, new_dRs) ] ) self.wait() if s == "(0.001)": self.plus.generate_target() self.plus.target.next_to(self.circum_term) self.error_term.generate_target() self.error_term.target.next_to(self.plus.target) error_brace.target = Brace(self.error_term.target) error_text.target = error_brace.target.get_text("Truly tiny") error_text.target.set_color(error_text.get_color()) self.play(*list(map(MoveToTarget, [ error_brace, error_text, self.plus, self.error_term ]))) self.wait() difference_text = TextMobject( "``Tiny " , "d", "ifference in ", "$R$", "''", arg_separator = "" ) difference_text.set_color_by_tex("d", self.dR_color) difference_text.next_to(self.pi_creature, UP+RIGHT) difference_arrow = Arrow(difference_text, self.change.denom) self.play( Write(difference_text, run_time = 2), ShowCreation(difference_arrow), self.pi_creature.change_mode, "speaking" ) self.wait() dA = TexMobject("dA") dA.set_color(self.change.get_color()) frac_line = self.change.frac_line frac_line.generate_target() frac_line.target.stretch_to_fit_width(dA.get_width()) frac_line.target.next_to(self.equals, LEFT) dA.next_to(frac_line.target, UP, 2*SMALL_BUFF) self.change.denom.generate_target() self.change.denom.target.next_to(frac_line.target, DOWN, 2*SMALL_BUFF) A = TexMobject("A").replace(difference_text[3]) difference_arrow.target = Arrow(difference_text, dA.get_left()) self.play( Transform(self.change, dA), MoveToTarget(frac_line), MoveToTarget(self.change.denom), Transform(difference_text[3], A), difference_text[1].set_color, dA.get_color(), MoveToTarget(difference_arrow), ) self.wait(2) self.play(*list(map(FadeOut, [difference_text, difference_arrow]))) def elaborate_on_d(self): arc = Arc(-np.pi, start_angle = -np.pi/2) arc.set_height( self.change.get_center()[1]-self.change.denom.get_center()[1] ) arc.next_to(self.change.frac_line, LEFT) arc.add_tip() self.play( ShowCreation(arc), self.pi_creature.change_mode, "sassy" ) self.wait() self.play(self.pi_creature.shrug) self.play(FadeOut(arc)) self.wait() d = TextMobject("``$d$''") arrow = TexMobject("\\Rightarrow") arrow.next_to(d) ignore_error = TextMobject("Ignore error") d_group = VGroup(d, arrow, ignore_error) d_group.arrange() d_group.next_to( self.pi_creature.get_corner(UP+RIGHT), buff = LARGE_BUFF ) error_group = VGroup( self.plus, self.error_term, self.error_term.label ) self.play( Write(d), self.pi_creature.change_mode, "speaking" ) self.play(*list(map(Write, [arrow, ignore_error]))) self.play(error_group.fade, 0.8) self.wait(2) equality_brace = Brace(VGroup(self.change.denom, self.circum_term)) equal_word = equality_brace.get_text("Equality") VGroup(equality_brace, equal_word).set_color(BLUE) self.play( GrowFromCenter(equality_brace), Write(equal_word, run_time = 1) ) self.wait(2) self.play(*list(map(FadeOut, [equality_brace, equal_word]))) less_wrong_philosophy = TextMobject("``Less wrong'' philosophy") less_wrong_philosophy.move_to(ignore_error, LEFT) self.play(Transform(ignore_error, less_wrong_philosophy)) self.wait() big_dR = 0.3 big_outer_ring = self.get_ring(self.radius, big_dR) big_nudge_line = self.nudge_line.copy() big_nudge_line.stretch_to_fit_width(big_dR) big_nudge_line.move_to(self.nudge_line, LEFT) new_nudge_arrow = Arrow(self.nudge_label, big_nudge_line, buff = SMALL_BUFF) self.outer_ring.save_state() self.nudge_line.save_state() self.nudge_arrow.save_state() self.play( Transform(self.outer_ring, big_outer_ring), Transform(self.nudge_line, big_nudge_line), Transform(self.nudge_arrow, new_nudge_arrow), ) self.play( *[ mob.restore for mob in [ self.outer_ring, self.nudge_line, self.nudge_arrow, ] ], rate_func=linear, run_time = 7 ) self.play(self.pi_creature.change_mode, "hooray") self.less_wrong_philosophy = VGroup( d, arrow, ignore_error ) def not_infinitely_small(self): randy = Randolph().flip() randy.scale(0.7) randy.to_corner(DOWN+RIGHT) bubble = SpeechBubble() bubble.write("$dR$ is infinitely small") bubble.resize_to_content() bubble.stretch(0.7, 1) bubble.pin_to(randy) bubble.set_fill(BLACK, opacity = 1) bubble.add_content(bubble.content) self.play(FadeIn(randy)) self.play( randy.change_mode, "speaking", ShowCreation(bubble), Write(bubble.content), self.pi_creature.change_mode, "confused" ) self.wait() to_infs = [self.change, self.change.denom, self.nudge_label] for mob in to_infs: mob.save_state() mob.inf = TexMobject("1/\\infty") mob.inf.set_color(mob.get_color()) mob.inf.move_to(mob) self.play(*[ Transform(mob, mob.inf) for mob in to_infs ]) self.wait() self.play(self.pi_creature.change_mode, "pleading") self.wait() self.play(*it.chain( [mob.restore for mob in to_infs], list(map(FadeOut, [bubble, bubble.content])), [randy.change_mode, "erm"], [self.pi_creature.change_mode, "happy"], )) for n in range(7): target = TexMobject("0.%s1"%("0"*n)) target.set_color(self.nudge_label.get_color()) target.move_to(self.nudge_label, LEFT) self.outer_ring.target = self.get_ring(self.radius, 0.1/(n+1)) self.nudge_line.get_center = self.nudge_line.get_left self.play( Transform(self.nudge_label, target), MoveToTarget(self.outer_ring), self.nudge_line.stretch_to_fit_width, 0.1/(n+1) ) self.wait() bubble.write("Wrong!") bubble.resize_to_content() bubble.stretch(0.7, 1) bubble.pin_to(randy) bubble.add_content(bubble.content) self.play( FadeIn(bubble), Write(bubble.content, run_time = 1), randy.change_mode, "angry", ) self.play(randy.set_color, RED) self.play(self.pi_creature.change_mode, "guilty") self.wait() new_bubble = self.pi_creature.get_bubble(SpeechBubble) new_bubble.set_fill(BLACK, opacity = 0.8) new_bubble.write("But it gets \\\\ less wrong!") new_bubble.resize_to_content() new_bubble.pin_to(self.pi_creature) self.play( FadeOut(bubble), FadeOut(bubble.content), ShowCreation(new_bubble), Write(new_bubble.content), randy.change_mode, "erm", randy.set_color, BLUE_E, self.pi_creature.change_mode, "shruggie" ) self.wait(2) class NameDerivative(IntroduceTinyChangeInArea): def construct(self): self.increase_radius(run_time = 0) self.change_nudge_label() self.name_derivative_for_cricle() self.interpret_geometrically() self.show_limiting_process() self.reference_approximation() self.emphasize_equality() def change_nudge_label(self): new_label = TexMobject("dR") new_label.move_to(self.nudge_label) new_label.to_edge(UP) new_label.set_color(self.nudge_label.get_color()) new_arrow = Arrow(new_label, self.nudge_line) self.remove(self.nudge_label, self.nudge_arrow) self.nudge_label = new_label self.nudge_arrow = new_arrow self.add(self.nudge_label, self.nudge_arrow) self.wait() def name_derivative_for_cricle(self): dA_dR, equals, d_formula_dR, equals2, two_pi_R = dArea_fom = TexMobject( "\\frac{dA}{dR}", "=", "\\frac{d(\\pi R^2)}{dR}", "=", "2\\pi R" ) dArea_fom.to_edge(UP, buff = MED_LARGE_BUFF).shift(RIGHT) dA, frac_line, dR = VGroup(*dA_dR[:2]), dA_dR[2], VGroup(*dA_dR[3:]) dA.set_color(GREEN_B) dR.set_color(self.dR_color) VGroup(*d_formula_dR[7:]).set_color(self.dR_color) dA_dR_circle = Circle() dA_dR_circle.replace(dA_dR, stretch = True) dA_dR_circle.scale_in_place(1.5) dA_dR_circle.set_color(BLUE) words = TextMobject( "``Derivative'' of $A$\\\\", "with respect to $R$" ) words.next_to(dA_dR_circle, DOWN, buff = 1.5*LARGE_BUFF) words.shift(0.5*LEFT) arrow = Arrow(words, dA_dR_circle) arrow.set_color(dA_dR_circle.get_color()) self.play(Transform(self.outer_ring.copy(), dA, run_time = 2)) self.play( Transform(self.nudge_line.copy(), dR, run_time = 2), Write(frac_line) ) self.wait() self.play( ShowCreation(dA_dR_circle), ShowCreation(arrow), Write(words) ) self.wait() self.play(Write(VGroup(equals, d_formula_dR))) self.wait() self.play(Write(VGroup(equals2, two_pi_R))) self.wait() self.dArea_fom = dArea_fom self.words = words self.two_pi_R = two_pi_R def interpret_geometrically(self): target_formula = TexMobject( "\\frac{d \\quad}{dR} = " ) VGroup(*target_formula[2:4]).set_color(self.dR_color) target_formula.scale(1.3) target_formula.next_to(self.dArea_fom, DOWN) target_formula.shift(2*RIGHT + 0.5*DOWN) area_form = VGroup(*self.dArea_fom[2][2:5]).copy() area_form.set_color(BLUE_D) circum_form = self.dArea_fom[-1] circle_width = 1 area_circle = self.circle.copy() area_circle.set_stroke(width = 0) area_circle.generate_target() area_circle.target.set_width(circle_width) area_circle.target.next_to(target_formula[0], RIGHT, buff = 0) area_circle.target.set_color(BLUE_D) circum_circle = self.circle.copy() circum_circle.set_fill(opacity = 0) circum_circle.generate_target() circum_circle.target.set_width(circle_width) circum_circle.target.next_to(target_formula) self.play( Write(target_formula), MoveToTarget(area_circle), MoveToTarget( circum_circle, run_time = 2, rate_func = squish_rate_func(smooth, 0.5, 1) ), self.pi_creature.change_mode, "hooray" ) self.wait() self.play(Transform(area_circle.copy(), area_form)) self.remove(area_form) self.play(Transform(circum_circle.copy(), circum_form)) self.change_mode("happy") def show_limiting_process(self): big_dR = 0.3 small_dR = 0.01 big_ring = self.get_ring(self.radius, big_dR) small_ring = self.get_ring(self.radius, small_dR) big_nudge_line = self.nudge_line.copy().set_width(big_dR) small_nudge_line = self.nudge_line.copy().set_width(small_dR) for line in big_nudge_line, small_nudge_line: line.move_to(self.nudge_line, LEFT) new_nudge_arrow = Arrow(self.nudge_label, big_nudge_line) small_nudge_arrow = Arrow(self.nudge_label, small_nudge_line) ring_group = VGroup(self.outer_ring, self.nudge_line, self.nudge_arrow) ring_group.save_state() big_group = VGroup(big_ring, big_nudge_line, new_nudge_arrow) small_group = VGroup(small_ring, small_nudge_line, small_nudge_arrow) fracs = VGroup() sample_dRs = [0.3, 0.1, 0.01] for dR in sample_dRs: dA = 2*np.pi*dR + np.pi*(dR**2) frac = TexMobject("\\frac{%.3f}{%.2f}"%(dA, dR)) VGroup(*frac[:5]).set_color(self.outer_ring.get_color()) VGroup(*frac[6:]).set_color(self.dR_color) fracs.add(frac) fracs.add(TexMobject("\\cdots \\rightarrow")) fracs.add(TexMobject("???")) fracs[-1].set_color_by_gradient(self.dR_color, self.outer_ring.get_color()) fracs.arrange(RIGHT, buff = MED_LARGE_BUFF) fracs.to_corner(DOWN+LEFT) arrows = VGroup() for frac in fracs[:len(sample_dRs)] + [fracs[-1]]: arrow = Arrow(self.words.get_bottom(), frac.get_top()) arrow.set_color(WHITE) if frac is fracs[-1]: check = TexMobject("\\checkmark") check.set_color(GREEN) check.next_to(arrow.get_center(), UP+RIGHT, SMALL_BUFF) arrow.add(check) else: cross = TexMobject("\\times") cross.set_color(RED) cross.move_to(arrow.get_center()) cross.set_stroke(RED, width = 5) arrow.add(cross) arrows.add(arrow) self.play( Transform(ring_group, big_group), self.pi_creature.change_mode, "sassy" ) for n, frac in enumerate(fracs): anims = [FadeIn(frac)] num_fracs = len(sample_dRs) if n < num_fracs: anims.append(ShowCreation(arrows[n])) anims.append(Transform( ring_group, small_group, rate_func = lambda t : t*(1./(num_fracs-n)), run_time = 2 )) elif n > num_fracs: anims.append(ShowCreation(arrows[-1])) self.play(*anims) self.wait(2) self.play( FadeOut(arrows), ring_group.restore, self.pi_creature.change_mode, "happy", ) self.wait() def reference_approximation(self): ring_copy = self.outer_ring.copy() self.unwrap_ring(ring_copy) self.wait() self.last_mover = ring_copy def emphasize_equality(self): equals = self.dArea_fom[-2] self.play(Transform(self.last_mover, equals)) self.remove(self.last_mover) self.play( equals.scale_in_place, 1.5, equals.set_color, GREEN, rate_func = there_and_back, run_time = 2 ) self.play( self.two_pi_R.set_stroke, YELLOW, 3, rate_func = there_and_back, run_time = 2 ) self.wait() new_words = TextMobject( "Systematically\\\\", "ignore error" ) new_words.move_to(self.words) self.play(Transform(self.words, new_words)) self.wait() class DerivativeAsTangentLine(ZoomedScene): CONFIG = { "zoomed_canvas_frame_shape" : (4, 4), "zoom_factor" : 10, "R_min" : 0, "R_max" : 2.5, "R_to_zoom_in_on" : 2, "little_rect_nudge" : 0.075*(UP+RIGHT), } def construct(self): self.setup_axes() self.show_zoomed_in_steps() self.show_tangent_lines() self.state_commonality() def setup_axes(self): x_axis = NumberLine( x_min = -0.25, x_max = 4, unit_size = 2, tick_frequency = 0.25, leftmost_tick = -0.25, numbers_with_elongated_ticks = [0, 1, 2, 3, 4], color = GREY ) x_axis.shift(2.5*DOWN) x_axis.shift(4*LEFT) x_axis.add_numbers(1, 2, 3, 4) x_label = TexMobject("R") x_label.next_to(x_axis, RIGHT+UP, buff = SMALL_BUFF) self.x_axis_label = x_label y_axis = NumberLine( x_min = -2, x_max = 20, unit_size = 0.3, tick_frequency = 2.5, leftmost_tick = 0, longer_tick_multiple = -2, numbers_with_elongated_ticks = [0, 5, 10, 15, 20], color = GREY ) y_axis.shift(x_axis.number_to_point(0)-y_axis.number_to_point(0)) y_axis.rotate(np.pi/2, about_point = y_axis.number_to_point(0)) y_axis.add_numbers(5, 10, 15, 20) y_axis.numbers.shift(0.4*UP+0.5*LEFT) y_label = TexMobject("A") y_label.next_to(y_axis.get_top(), RIGHT, buff = MED_LARGE_BUFF) def func(alpha): R = interpolate(self.R_min, self.R_max, alpha) x = x_axis.number_to_point(R)[0] output = np.pi*(R**2) y = y_axis.number_to_point(output)[1] return x*RIGHT + y*UP graph = ParametricFunction(func, color = BLUE) graph_label = TexMobject("A(R) = \\pi R^2") graph_label.set_color(BLUE) graph_label.next_to( graph.point_from_proportion(2), LEFT ) self.play(Write(VGroup(x_axis, y_axis))) self.play(ShowCreation(graph)) self.play(Write(graph_label)) self.play(Write(VGroup(x_label, y_label))) self.wait() self.x_axis, self.y_axis = x_axis, y_axis self.graph = graph self.graph_label = graph_label def graph_point(self, R): alpha = (R - self.R_min)/(self.R_max - self.R_min) return self.graph.point_from_proportion(alpha) def angle_of_tangent(self, R, dR = 0.01): vect = self.graph_point(R + dR) - self.graph_point(R) return angle_of_vector(vect) def show_zoomed_in_steps(self): R = self.R_to_zoom_in_on dR = 0.05 graph_point = self.graph_point(R) nudged_point = self.graph_point(R+dR) interim_point = nudged_point[0]*RIGHT + graph_point[1]*UP self.activate_zooming() dot = Dot(color = YELLOW) dot.scale(0.1) dot.move_to(graph_point) self.play(*list(map(FadeIn, [ self.little_rectangle, self.big_rectangle ]))) self.play( self.little_rectangle.move_to, graph_point+self.little_rect_nudge ) self.play(FadeIn(dot)) dR_line = Line(graph_point, interim_point) dR_line.set_color(YELLOW) dA_line = Line(interim_point, nudged_point) dA_line.set_color(GREEN) tiny_buff = SMALL_BUFF/self.zoom_factor for line, vect, char in (dR_line, DOWN, "R"), (dA_line, RIGHT, "A"): line.brace = Brace(Line(LEFT, RIGHT)) line.brace.scale(1./self.zoom_factor) line.brace.stretch_to_fit_width(line.get_length()) line.brace.rotate(line.get_angle()) line.brace.next_to(line, vect, buff = tiny_buff) line.text = TexMobject("d%s"%char) line.text.scale(1./self.zoom_factor) line.text.set_color(line.get_color()) line.text.next_to(line.brace, vect, buff = tiny_buff) self.play(ShowCreation(line)) self.play(Write(VGroup(line.brace, line.text))) self.wait() deriv_is_slope = TexMobject( "\\frac{dA}{dR} =", "\\text{Slope}" ) self.slope_word = deriv_is_slope[1] VGroup(*deriv_is_slope[0][:2]).set_color(GREEN) VGroup(*deriv_is_slope[0][3:5]).set_color(YELLOW) deriv_is_slope.next_to(self.y_axis, RIGHT) deriv_is_slope.shift(UP) self.play(Write(deriv_is_slope)) self.wait() ### Whoa boy, this aint' gonna be pretty self.dot = dot self.small_step_group = VGroup( dR_line, dR_line.brace, dR_line.text, dA_line, dA_line.brace, dA_line.text, ) def update_small_step_group(group): R = self.x_axis.point_to_number(dot.get_center()) graph_point = self.graph_point(R) nudged_point = self.graph_point(R+dR) interim_point = nudged_point[0]*RIGHT + graph_point[1]*UP dR_line.put_start_and_end_on(graph_point, interim_point) dA_line.put_start_and_end_on(interim_point, nudged_point) dR_line.brace.stretch_to_fit_width(dR_line.get_width()) dR_line.brace.next_to(dR_line, DOWN, buff = tiny_buff) dR_line.text.next_to(dR_line.brace, DOWN, buff = tiny_buff) dA_line.brace.stretch_to_fit_height(dA_line.get_height()) dA_line.brace.next_to(dA_line, RIGHT, buff = tiny_buff) dA_line.text.next_to(dA_line.brace, RIGHT, buff = tiny_buff) self.update_small_step_group = update_small_step_group def show_tangent_lines(self): R = self.R_to_zoom_in_on line = Line(LEFT, RIGHT).scale(FRAME_Y_RADIUS) line.set_color(MAROON_B) line.rotate(self.angle_of_tangent(R)) line.move_to(self.graph_point(R)) x_axis_y = self.x_axis.number_to_point(0)[1] two_pi_R = TexMobject("= 2\\pi R") two_pi_R.next_to(self.slope_word, DOWN, aligned_edge = RIGHT) two_pi_R.shift(0.5*LEFT) def line_update_func(line): R = self.x_axis.point_to_number(self.dot.get_center()) line.rotate( self.angle_of_tangent(R) - line.get_angle() ) line.move_to(self.dot) def update_little_rect(rect): R = self.x_axis.point_to_number(self.dot.get_center()) rect.move_to(self.graph_point(R) + self.little_rect_nudge) self.play(ShowCreation(line)) self.wait() self.note_R_value_of_point() alphas = np.arange(0, 1, 0.01) graph_points = list(map(self.graph.point_from_proportion, alphas)) curr_graph_point = self.graph_point(R) self.last_alpha = alphas[np.argmin([ get_norm(point - curr_graph_point) for point in graph_points ])] def shift_everything_to_alpha(alpha, run_time = 3): self.play( MoveAlongPath( self.dot, self.graph, rate_func = lambda t : interpolate(self.last_alpha, alpha, smooth(t)) ), UpdateFromFunc(line, line_update_func), UpdateFromFunc(self.small_step_group, self.update_small_step_group), UpdateFromFunc(self.little_rectangle, update_little_rect), run_time = run_time ) self.last_alpha = alpha for alpha in 0.95, 0.2: shift_everything_to_alpha(alpha) self.wait() self.play(Write(two_pi_R)) self.wait() shift_everything_to_alpha(0.8, 4) self.wait() def note_R_value_of_point(self): R = self.R_to_zoom_in_on point = self.graph_point(R) R_axis_point = point[0]*RIGHT + 2.5*DOWN dashed_line = DashedLine(point, R_axis_point, color = RED) dot = Dot(R_axis_point, color = RED) arrow = Arrow( self.x_axis_label.get_left(), dot, buff = SMALL_BUFF ) self.play(ShowCreation(dashed_line)) self.play(ShowCreation(dot)) self.play(ShowCreation(arrow)) self.play(dot.scale_in_place, 2, rate_func = there_and_back) self.wait() self.play(*list(map(FadeOut, [dashed_line, dot, arrow]))) def state_commonality(self): morty = Mortimer() morty.scale(0.7) morty.to_edge(DOWN).shift(2*RIGHT) bubble = morty.get_bubble(SpeechBubble, height = 2) bubble.set_fill(BLACK, opacity = 0.8) bubble.shift(0.5*DOWN) bubble.write("This is the standard view") self.play(FadeIn(morty)) self.play( ShowCreation(bubble), Write(bubble.content), morty.change_mode, "surprised" ) self.play(Blink(morty)) self.wait() new_words = TextMobject("Which is...fine...") new_words.move_to(bubble.content, RIGHT) self.play( bubble.stretch_to_fit_width, 5, bubble.shift, RIGHT, Transform(bubble.content, new_words), morty.change_mode, "hesitant" ) self.play(Blink(morty)) self.wait() class SimpleConfusedPi(Scene): def construct(self): randy = Randolph() confused = Randolph(mode = "confused") for pi in randy, confused: pi.flip() pi.look(UP+LEFT) pi.scale(2) pi.rotate(np.pi/2) self.play(Transform(randy, confused)) self.wait() class TangentLinesAreNotEverything(TeacherStudentsScene): def construct(self): self.teacher_says(""" Tangent lines are just one way to visualize derivatives """) self.change_student_modes("raise_left_hand", "pondering", "erm") self.random_blink(3) class OnToIntegrals(TeacherStudentsScene): def construct(self): self.teacher_says("On to integrals!", target_mode = "hooray") self.change_student_modes(*["happy"]*3) self.random_blink(3) class IntroduceConcentricRings(CircleScene): CONFIG = { "radius" : 2.5, "special_ring_index" : 10, "include_pi_creature" : True, } def construct(self): self.build_up_rings() self.add_up_areas() self.unwrap_special_ring() self.write_integral() self.ask_about_approx() def create_pi_creature(self): morty = Mortimer() morty.scale(0.7) morty.to_corner(DOWN+RIGHT) return morty def build_up_rings(self): self.circle.set_fill(opacity = 0) rings = VGroup(*[ self.get_ring(r, self.dR) for r in np.arange(0, self.radius, self.dR) ]) rings.set_color_by_gradient(BLUE_E, GREEN_E) rings.set_stroke(BLACK, width = 1) outermost_ring = rings[-1] dr_line = Line( rings[-2].get_top(), rings[-1].get_top(), color = YELLOW ) dr_text = TexMobject("dr") dr_text.move_to(self.circle.get_corner(UP+RIGHT)) dr_text.shift(LEFT) dr_text.set_color(YELLOW) dr_arrow = Arrow(dr_text, dr_line, buff = SMALL_BUFF) self.dr_group = VGroup(dr_text, dr_arrow, dr_line) foreground_group = VGroup(self.radius_brace, self.radius_label, self.radius_line) self.play( FadeIn(outermost_ring), Animation(foreground_group) ) self.play( Write(dr_text), ShowCreation(dr_arrow), ShowCreation(dr_line) ) foreground_group.add(dr_line, dr_arrow, dr_text) self.change_mode("pondering") self.wait() self.play( FadeIn( VGroup(*rings[:-1]), lag_ratio=1, run_time = 5 ), Animation(foreground_group) ) self.wait() self.foreground_group = foreground_group self.rings = rings def add_up_areas(self): start_rings = VGroup(*self.rings[:4]) moving_rings = start_rings.copy() moving_rings.generate_target() moving_rings.target.set_stroke(width = 0) plusses = VGroup(*[TexMobject("+") for ring in moving_rings]) area_sum = VGroup(*it.chain(*list(zip( [ring for ring in moving_rings.target], plusses )))) dots_equals_area = TexMobject("\\dots", "=", "\\pi R^2") area_sum.add(*dots_equals_area) area_sum.arrange() area_sum.to_edge(RIGHT) area_sum.to_edge(UP, buff = MED_SMALL_BUFF) dots_equals_area[-1].shift(0.1*UP) self.area_sum_rhs = dots_equals_area[-1] # start_rings.set_fill(opacity = 0.3) self.play( MoveToTarget( moving_rings, lag_ratio = 0.5, ), Write( VGroup(plusses, dots_equals_area), rate_func = squish_rate_func(smooth, 0.5, 1) ), Animation(self.foreground_group), run_time = 5, ) self.wait() self.area_sum = area_sum def unwrap_special_ring(self): rings = self.rings foreground_group = self.foreground_group special_ring = rings[self.special_ring_index] special_ring.save_state() radius = (special_ring.get_width()-2*self.dR)/2. radial_line = Line(ORIGIN, radius*RIGHT) radial_line.rotate(np.pi/4) radial_line.shift(self.circle.get_center()) radial_line.set_color(YELLOW) r_label = TexMobject("r") r_label.next_to(radial_line.get_center(), UP+LEFT, buff = SMALL_BUFF) rings.generate_target() rings.save_state() rings.target.set_fill(opacity = 0.3) rings.target.set_stroke(BLACK) rings.target[self.special_ring_index].set_fill(opacity = 1) self.play( MoveToTarget(rings), Animation(foreground_group) ) self.play(ShowCreation(radial_line)) self.play(Write(r_label)) self.foreground_group.add(radial_line, r_label) self.wait() self.unwrap_ring(special_ring, to_edge = RIGHT) brace = Brace(special_ring, UP) brace.stretch_in_place(0.9, 0) two_pi_r = brace.get_text("$2\\pi r$") left_brace = TexMobject("\\{") left_brace.stretch_to_fit_height(1.5*self.dR) left_brace.next_to(special_ring, LEFT, buff = SMALL_BUFF) dr = TexMobject("dr") dr.next_to(left_brace, LEFT, buff = SMALL_BUFF) self.play( GrowFromCenter(brace), Write(two_pi_r) ) self.play(GrowFromCenter(left_brace), Write(dr)) self.wait() think_concrete = TextMobject("Think $dr = 0.1$") think_concrete.next_to(dr, DOWN+LEFT, buff = LARGE_BUFF) arrow = Arrow(think_concrete.get_top(), dr) self.play( Write(think_concrete), ShowCreation(arrow), self.pi_creature.change_mode, "speaking" ) self.wait() less_wrong = TextMobject(""" Approximations get less wrong """) less_wrong.next_to(self.pi_creature, LEFT, aligned_edge = UP) self.play(Write(less_wrong)) self.wait() self.special_ring = special_ring self.radial_line = radial_line self.r_label = r_label self.to_fade = VGroup( brace, left_brace, two_pi_r, dr, think_concrete, arrow, less_wrong ) self.two_pi_r = two_pi_r.copy() self.dr = dr.copy() def write_integral(self): brace = Brace(self.area_sum) formula_q = brace.get_text("Nice formula?") int_sym, R, zero = def_int = TexMobject("\\int", "_0", "^R") self.two_pi_r.generate_target() self.dr.generate_target() equals_pi_R_squared = TexMobject("= \\pi R^2") integral_expression = VGroup( def_int, self.two_pi_r.target, self.dr.target, equals_pi_R_squared ) integral_expression.arrange() integral_expression.next_to(brace, DOWN) self.integral_expression = VGroup(*integral_expression[:-1]) self.play( GrowFromCenter(brace), Write(formula_q), self.pi_creature.change_mode, "pondering" ) self.wait(2) last = VMobject() last.save_state() for ring in self.rings: ring.save_state() target = ring.copy() target.set_fill(opacity = 1) self.play( last.restore, Transform(ring, target), Animation(self.foreground_group), run_time = 0.5 ) last = ring self.play(last.restore) self.wait() ghost = self.rings.copy() for mob in self.area_sum_rhs, self.two_pi_r: ghost.set_fill(opacity = 0.1) self.play(Transform(ghost, mob)) self.wait() self.remove(ghost) self.wait() self.play(FadeOut(formula_q)) self.play(Write(int_sym)) self.wait() self.rings.generate_target() self.rings.target.set_fill(opacity = 1) self.play( MoveToTarget(self.rings, rate_func = there_and_back), Animation(self.foreground_group) ) self.wait() self.grow_and_shrink_r_line(zero, R) self.wait() self.play( MoveToTarget(self.two_pi_r), MoveToTarget(self.dr), run_time = 2 ) self.wait() self.play( FadeOut(self.to_fade), ApplyMethod(self.rings.restore, run_time = 2), Animation(self.foreground_group) ) self.wait() self.play(Write(equals_pi_R_squared)) self.wait() self.equals = equals_pi_R_squared[0] self.integral_terms = VGroup( self.integral_expression[1], self.integral_expression[2], self.int_lower_bound, self.int_upper_bound, VGroup(*equals_pi_R_squared[1:]) ) def grow_and_shrink_r_line(self, zero_target, R_target): self.radial_line.get_center = self.circle.get_center self.radial_line.save_state() self.radial_line.generate_target() self.radial_line.target.scale_in_place( 0.1 / self.radial_line.get_length() ) self.r_label.generate_target() self.r_label.save_state() equals_0 = TexMobject("=0") r_equals_0 = VGroup(self.r_label.target, equals_0) r_equals_0.arrange(buff = SMALL_BUFF) r_equals_0.next_to(self.radial_line.target, UP+LEFT, buff = SMALL_BUFF) self.play( MoveToTarget(self.radial_line), MoveToTarget(self.r_label), GrowFromCenter(equals_0) ) self.play(equals_0[-1].copy().replace, zero_target) self.remove(self.get_mobjects_from_last_animation()[0]) self.add(zero_target) self.wait() self.radial_line.target.scale_in_place( self.radius/self.radial_line.get_length() ) equals_0.target = TexMobject("=R") equals_0.target.next_to( self.radial_line.target.get_center_of_mass(), UP+LEFT, buff = SMALL_BUFF ) self.r_label.target.next_to(equals_0.target, LEFT, buff = SMALL_BUFF) self.play( MoveToTarget(self.radial_line), MoveToTarget(self.r_label), MoveToTarget(equals_0) ) self.play(equals_0[-1].copy().replace, R_target) self.remove(self.get_mobjects_from_last_animation()[0]) self.add(R_target) self.wait() self.play( self.radial_line.restore, self.r_label.restore, FadeOut(equals_0) ) self.int_lower_bound, self.int_upper_bound = zero_target, R_target def ask_about_approx(self): approx = TexMobject("\\approx").replace(self.equals) self.equals.save_state() question = TextMobject( "Should this be\\\\", "an approximation?" ) question.next_to(approx, DOWN, buff = 1.3*LARGE_BUFF) arrow = Arrow(question, approx, buff = MED_SMALL_BUFF) approach_words = TextMobject("Consider\\\\", "$dr \\to 0$") approach_words.move_to(question, RIGHT) int_brace = Brace(self.integral_expression) integral_word = int_brace.get_text("``Integral''") self.play( Transform(self.equals, approx), Write(question), ShowCreation(arrow), self.pi_creature.change_mode, "confused" ) self.wait(2) self.play(*[ ApplyMethod(ring.set_stroke, ring.get_color(), width = 1) for ring in self.rings ] + [ FadeOut(self.dr_group), Animation(self.foreground_group) ]) self.wait() self.play( Transform(question, approach_words), Transform(arrow, Arrow(approach_words, approx)), self.equals.restore, self.pi_creature.change_mode, "happy" ) self.wait(2) self.play( self.integral_expression.set_color_by_gradient, BLUE, GREEN, GrowFromCenter(int_brace), Write(integral_word) ) self.wait() for term in self.integral_terms: term.save_state() self.play(term.set_color, YELLOW) self.play(term.restore) self.wait(3) class AskAboutGeneralCircles(TeacherStudentsScene): def construct(self): self.student_says(""" What about integrals beyond this circle example? """) self.change_student_modes("confused") self.random_blink(2) self.teacher_says( "All in due time", ) self.change_student_modes(*["happy"]*3) self.random_blink(2) class GraphIntegral(GraphScene): CONFIG = { "x_min" : -0.25, "x_max" : 4, "x_tick_frequency" : 0.25, "x_leftmost_tick" : -0.25, "x_labeled_nums" : list(range(1, 5)), "x_axis_label" : "r", "y_min" : -2, "y_max" : 25, "y_tick_frequency" : 2.5, "y_bottom_tick" : 0, "y_labeled_nums" : list(range(5, 30, 5)), "y_axis_label" : "", "dr" : 0.125, "R" : 3.5, } def construct(self): self.func = lambda r : 2*np.pi*r integral = TexMobject("\\int_0^R 2\\pi r \\, dr") integral.to_edge(UP).shift(LEFT) self.little_r = integral[5] self.play(Write(integral)) self.wait() self.setup_axes() self.show_horizontal_axis() self.add_rectangles() self.thinner_rectangles() self.ask_about_area() def show_horizontal_axis(self): arrows = [ Arrow(self.little_r, self.coords_to_point(*coords)) for coords in ((0, 0), (self.x_max, 0)) ] moving_arrow = arrows[0].copy() self.play( ShowCreation(moving_arrow), self.little_r.set_color, YELLOW ) for arrow in reversed(arrows): self.play(Transform(moving_arrow, arrow, run_time = 4)) self.play( FadeOut(moving_arrow), self.little_r.set_color, WHITE ) def add_rectangles(self): tick_height = 0.2 special_tick_index = 12 ticks = VGroup(*[ Line(UP, DOWN).move_to(self.coords_to_point(x, 0)) for x in np.arange(0, self.R+self.dr, self.dr) ]) ticks.stretch_to_fit_height(tick_height) ticks.set_color(YELLOW) R_label = TexMobject("R") R_label.next_to(self.coords_to_point(self.R, 0), DOWN) values_words = TextMobject("Values of $r$") values_words.shift(UP) arrows = VGroup(*[ Arrow( values_words.get_bottom(), tick.get_center(), tip_length = 0.15 ) for tick in ticks ]) dr_brace = Brace( VGroup(*ticks[special_tick_index:special_tick_index+2]), buff = SMALL_BUFF ) dr_text = dr_brace.get_text("$dr$", buff = SMALL_BUFF) # dr_text.set_color(YELLOW) rectangles = self.get_rectangles(self.dr) special_rect = rectangles[special_tick_index] left_brace = Brace(special_rect, LEFT) height_label = left_brace.get_text("$2\\pi r$") self.play( ShowCreation(ticks, lag_ratio = 0.5), Write(R_label) ) self.play( Write(values_words), ShowCreation(arrows) ) self.wait() self.play( GrowFromCenter(dr_brace), Write(dr_text) ) self.wait() rectangles.save_state() rectangles.stretch_to_fit_height(0) rectangles.move_to(self.graph_origin, DOWN+LEFT) self.play(*list(map(FadeOut, [arrows, values_words]))) self.play( rectangles.restore, Animation(ticks), run_time = 2 ) self.wait() self.play(*[ ApplyMethod(rect.fade, 0.7) for rect in rectangles if rect is not special_rect ] + [Animation(ticks)]) self.play( GrowFromCenter(left_brace), Write(height_label) ) self.wait() graph = self.graph_function( lambda r : 2*np.pi*r, animate = False ) graph_label = self.label_graph( self.graph, "f(r) = 2\\pi r", proportion = 0.5, direction = LEFT, animate = False ) self.play( rectangles.restore, Animation(ticks), FadeOut(left_brace), Transform(height_label, graph_label), ShowCreation(graph) ) self.wait(3) self.play(*list(map(FadeOut, [ticks, dr_brace, dr_text]))) self.rectangles = rectangles def thinner_rectangles(self): for x in range(2, 8): new_rects = self.get_rectangles( dr = self.dr/x, stroke_width = 1./x ) self.play(Transform(self.rectangles, new_rects)) self.wait() def ask_about_area(self): question = TextMobject("What's this \\\\ area") question.to_edge(RIGHT).shift(2*UP) arrow = Arrow( question.get_bottom(), self.rectangles, buff = SMALL_BUFF ) self.play( Write(question), ShowCreation(arrow) ) self.wait() def get_rectangles(self, dr, stroke_width = 1): return self.get_riemann_rectangles( 0, self.R, dr, stroke_width = stroke_width ) class MoreOnThisLater(TeacherStudentsScene): def construct(self): self.teacher_says(""" More details on integrals later """) self.change_student_modes( "raise_right_hand", "raise_left_hand", "raise_left_hand", ) self.random_blink(2) self.teacher_says(""" This is just a preview """) self.random_blink(2) class FundamentalTheorem(CircleScene): CONFIG = { "circle_corner" : ORIGIN, "radius" : 1.5, "area_color" : BLUE, "circum_color" : WHITE, "unwrapped_tip" : 2.5*UP, "include_pi_creature" : False } def setup(self): CircleScene.setup(self) group = VGroup( self.circle, self.radius_line, self.radius_brace, self.radius_label ) self.remove(*group) group.shift(DOWN) self.foreground_group = VGroup( self.radius_line, self.radius_brace, self.radius_label, ) def create_pi_creature(self): morty = Mortimer() morty.scale(0.7) morty.to_corner(DOWN+RIGHT) return morty def construct(self): self.add_derivative_terms() self.add_integral_terms() self.think_about_it() self.bring_in_circle() self.show_outer_ring() self.show_all_rings() self.emphasize_oposites() def add_derivative_terms(self): symbolic = TexMobject( "\\frac{d(\\pi R^2)}{dR} =", "2\\pi R" ) VGroup(*symbolic[0][2:5]).set_color(self.area_color) VGroup(*symbolic[0][7:9]).set_color(self.dR_color) symbolic[1].set_color(self.circum_color) geometric = TexMobject("\\frac{d \\quad}{dR}=") VGroup(*geometric[2:4]).set_color(self.dR_color) radius = geometric[0].get_height() area_circle = Circle( stroke_width = 0, fill_color = self.area_color, fill_opacity = 0.5, radius = radius ) area_circle.next_to(geometric[0], buff = SMALL_BUFF) circum_circle = Circle( color = self.circum_color, radius = radius ) circum_circle.next_to(geometric, RIGHT) geometric.add(area_circle, circum_circle) self.derivative_terms = VGroup(symbolic, geometric) self.derivative_terms.arrange( DOWN, buff = LARGE_BUFF, aligned_edge = LEFT ) self.derivative_terms.next_to(ORIGIN, LEFT, buff = LARGE_BUFF) self.play( Write(self.derivative_terms), self.pi_creature.change_mode, "hooray" ) self.wait() def add_integral_terms(self): symbolic = TexMobject( "\\int_0^R", "2\\pi r", "\\cdot", "dr", "=", "\\pi R^2" ) symbolic.set_color_by_tex("2\\pi r", self.circum_color) symbolic.set_color_by_tex("dr", self.dR_color) symbolic.set_color_by_tex("\\pi R^2", self.area_color) geometric = symbolic.copy() area_circle = Circle( radius = geometric[-1].get_width()/2, stroke_width = 0, fill_color = self.area_color, fill_opacity = 0.5 ) area_circle.move_to(geometric[-1]) circum_circle = Circle( radius = geometric[1].get_width()/2, color = self.circum_color ) circum_circle.move_to(geometric[1]) geometric.submobjects[1] = circum_circle geometric.submobjects[-1] = area_circle self.integral_terms = VGroup(symbolic, geometric) self.integral_terms.arrange( DOWN, buff = LARGE_BUFF, aligned_edge = LEFT ) self.integral_terms.next_to(ORIGIN, RIGHT, buff = LARGE_BUFF) self.play(Write(self.integral_terms)) self.wait() def think_about_it(self): for mode in "confused", "pondering", "surprised": self.change_mode(mode) self.wait() def bring_in_circle(self): self.play( FadeOut(self.derivative_terms[0]), FadeOut(self.integral_terms[0]), self.derivative_terms[1].to_corner, UP+LEFT, MED_LARGE_BUFF, self.integral_terms[1].to_corner, UP+RIGHT, MED_LARGE_BUFF, self.pi_creature.change_mode, "speaking" ) self.introduce_circle() def show_outer_ring(self): self.increase_radius(numerical_dr = False) self.foreground_group.add(self.nudge_line, self.nudge_arrow) self.wait() ring_copy = self.outer_ring.copy() ring_copy.save_state() self.unwrap_ring(ring_copy, to_edge = LEFT) brace = Brace(ring_copy, UP) brace.stretch_in_place(0.95, 0) deriv = brace.get_text("$\\dfrac{dA}{dR}$") VGroup(*deriv[:2]).set_color(self.outer_ring.get_color()) VGroup(*deriv[-2:]).set_color(self.dR_color) self.play( GrowFromCenter(brace), Write(deriv), self.pi_creature.change_mode, "happy" ) self.to_fade = VGroup(deriv, brace) self.to_restore = ring_copy def show_all_rings(self): rings = VGroup(*[ self.get_ring(radius = r, dR = self.dR) for r in np.arange(0, self.radius, self.dR) ]) rings.set_color_by_gradient(BLUE_E, GREEN_E) rings.save_state() integrand = self.integral_terms[1][1] for ring in rings: Transform(ring, integrand).update(1) self.play( ApplyMethod( rings.restore, lag_ratio = 0.5, run_time = 5 ), Animation(self.foreground_group), ) def emphasize_oposites(self): self.play( FadeOut(self.to_fade), self.to_restore.restore, Animation(self.foreground_group), run_time = 2 ) arrow = DoubleArrow( self.derivative_terms[1], self.integral_terms[1], ) opposites = TextMobject("Opposites") opposites.next_to(arrow, DOWN) self.play( ShowCreation(arrow), Write(opposites) ) self.wait() class NameTheFundamentalTheorem(TeacherStudentsScene): def construct(self): symbols = TexMobject( "\\frac{d}{dx} \\int_0^x f(t)dt = f(x)", ) symbols.to_corner(UP+LEFT) brace = Brace(symbols) abstract = brace.get_text("Abstract version") self.add(symbols) self.play( GrowFromCenter(brace), Write(abstract), *[ ApplyMethod(pi.look_at, symbols) for pi in self.get_pi_creatures() ] ) self.change_student_modes("pondering", "confused", "erm") self.random_blink() self.teacher_says(""" This is known as the ``fundamental theorem of calculus'' """, width = 5, height = 5, target_mode = "hooray") self.random_blink(3) self.teacher_says(""" We'll get here in due time. """) self.change_student_modes(*["happy"]*3) self.wait(2) class CalculusInANutshell(CircleScene): CONFIG = { "circle_corner" : ORIGIN, "radius" : 3, } def construct(self): self.clear() self.morph_word() self.show_remainder_of_series() def morph_word(self): calculus = TextMobject("Calculus") calculus.scale(1.5) calculus.to_edge(UP) dR = self.radius/float(len(calculus.split())) rings = VGroup(*[ self.get_ring(rad, 0.95*dR) for rad in np.arange(0, self.radius, dR) ]) for ring in rings: ring.add(ring.copy().rotate(np.pi)) for mob in calculus, rings: mob.set_color_by_gradient(BLUE, GREEN) rings.set_stroke(width = 0) self.play(Write(calculus)) self.wait() self.play(Transform( calculus, rings, lag_ratio = 0.5, run_time = 5 )) self.wait() def show_remainder_of_series(self): series = VideoSeries() first = series[0] first.set_fill(YELLOW) first.save_state() first.center() first.set_height(FRAME_Y_RADIUS*2) first.set_fill(opacity = 0) everything = VGroup(*self.get_mobjects()) everything.generate_target() everything.target.scale(series[1].get_height()/first.get_height()) everything.target.shift(first.saved_state.get_center()) everything.target.set_fill(opacity = 0.1) second = series[1] brace = Brace(second) derivatives = brace.get_text("Derivatives") self.play( MoveToTarget(everything), first.restore, run_time = 2 ) self.play(FadeIn( VGroup(*series[1:]), lag_ratio = 0.5, run_time = 2, )) self.wait() self.play( GrowFromCenter(brace), Write(derivatives) ) self.wait() class Thumbnail(CircleScene): CONFIG = { "radius" : 2, "circle_corner" : ORIGIN } def construct(self): self.clear() title = TextMobject("Essence of \\\\ calculus") title.scale(2) title.to_edge(UP) area_circle = Circle( fill_color = BLUE, fill_opacity = 0.5, stroke_width = 0, ) circum_circle = Circle( color = YELLOW ) deriv_eq = TexMobject("\\frac{d \\quad}{dR} = ") int_eq = TexMobject("\\int_0^R \\quad = ") target_height = deriv_eq[0].get_height()*2 area_circle.set_height(target_height) circum_circle.set_height(target_height) area_circle.next_to(deriv_eq[0], buff = SMALL_BUFF) circum_circle.next_to(deriv_eq) deriv_eq.add(area_circle.copy(), circum_circle.copy()) area_circle.next_to(int_eq) circum_circle.next_to(int_eq[-1], LEFT) int_eq.add(area_circle, circum_circle) for mob in deriv_eq, int_eq: mob.scale(1.5) arrow = TexMobject("\\Leftrightarrow").scale(2) arrow.shift(DOWN) deriv_eq.next_to(arrow, LEFT) int_eq.next_to(arrow, RIGHT) self.add(title, arrow, deriv_eq, int_eq)