from big_ol_pile_of_manim_imports import * from old_projects.eoc.chapter2 import DISTANCE_COLOR, TIME_COLOR, \ VELOCITY_COLOR, Car, MoveCar OUTPUT_COLOR = DISTANCE_COLOR INPUT_COLOR = TIME_COLOR DERIVATIVE_COLOR = VELOCITY_COLOR class Chapter3OpeningQuote(OpeningQuote): CONFIG = { "quote" : [ "You know, for a mathematician, he did not have \\\\ enough", "imagination.", "But he has become a poet and \\\\ now he is fine.", ], "highlighted_quote_terms" : { "imagination." : BLUE, }, "author" : "David Hilbert" } class PoseAbstractDerivative(TeacherStudentsScene): def construct(self): self.teacher_says(""" Given $f(x) = x^2 \\sin(x)$, \\\\ compute $\\frac{df}{dx}(x)$ """) content_copy = self.teacher.bubble.content.copy() self.change_student_modes("sad", "confused", "erm") self.wait() self.student_says( "Why?", target_mode = "sassy", added_anims = [ content_copy.scale, 0.8, content_copy.to_corner, UP+LEFT ] ) self.play(self.teacher.change_mode, "pondering") self.wait(2) class ContrastAbstractAndConcrete(Scene): def construct(self): v_line = Line(UP, DOWN).scale(FRAME_Y_RADIUS) l_title = TextMobject("Abstract functions") l_title.shift(FRAME_X_RADIUS*LEFT/2) l_title.to_edge(UP) r_title = TextMobject("Applications") r_title.shift(FRAME_X_RADIUS*RIGHT/2) r_title.to_edge(UP) h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS) h_line.shift((r_title.get_bottom()[1]-MED_SMALL_BUFF)*UP) functions = VGroup(*list(map(TexMobject, [ "f(x) = 2x^2 - x^3", "f(x) = \\sin(x)", "f(x) = e^x", "\\v_dots" ]))) functions.arrange( DOWN, aligned_edge = LEFT, buff = LARGE_BUFF ) functions.shift(FRAME_X_RADIUS*LEFT/2) functions[-1].shift(MED_LARGE_BUFF*RIGHT) self.add(l_title, r_title) self.play(*list(map(ShowCreation, [h_line, v_line]))) self.play(Write(functions)) self.wait() anims = [ method(func_mob) for func_mob, method in zip(functions, [ self.get_car_anim, self.get_spring_anim, self.get_population_anim, ]) ] for anim in anims: self.play(FadeIn(anim.mobject)) self.play(anim) self.play(FadeOut(anim.mobject)) def get_car_anim(self, alignement_mob): car = Car() point = 2*RIGHT + alignement_mob.get_bottom()[1]*UP target_point = point + 5*RIGHT car.move_to(point) return MoveCar( car, target_point, run_time = 5, ) def get_spring_anim(self, alignement_mob): compact_spring, extended_spring = [ ParametricFunction( lambda t : (t/denom)*RIGHT+np.sin(t)*UP+np.cos(t)*OUT, t_max = 12*np.pi, ) for denom in (12.0, 4.0) ] for spring in compact_spring, extended_spring: spring.scale(0.5) spring.rotate(np.pi/6, UP) spring.set_color(GREY) spring.next_to(ORIGIN, RIGHT) spring.shift( alignement_mob.get_center()[1]*UP + SMALL_BUFF*RIGHT \ -spring.points[0] ) weight = Square( side_length = 0.5, stroke_width = 0, fill_color = LIGHT_GREY, fill_opacity = 1, ) weight.move_to(spring.points[-1]) spring.add(weight) return Transform( compact_spring, extended_spring, rate_func = lambda t : 1+np.sin(6*np.pi*t), run_time = 5 ) def get_population_anim(self, alignement_mob): colors = color_gradient([BLUE_B, BLUE_E], 12) pis = VGroup(*[ Randolph( mode = "happy", color = random.choice(colors) ).shift( 4*x*RIGHT + 4*y*UP + \ 2*random.random()*RIGHT + \ 2*random.random()*UP ) for x in range(20) for y in range(10) ]) pis.set_height(3) pis.center() pis.to_edge(DOWN, buff = SMALL_BUFF) pis.shift(FRAME_X_RADIUS*RIGHT/2.) anims = [] for index, pi in enumerate(pis): if index < 2: anims.append(FadeIn(pi)) continue mom_index, dad_index = random.choice( list(it.combinations(list(range(index)), 2)) ) pi.parents = VGroup(pis[mom_index], pis[dad_index]).copy() pi.parents.set_fill(opacity = 0) exp = 1 while 2**exp < len(pis): low_index = 2**exp high_index = min(2**(exp+1), len(pis)) these_pis = pis[low_index:high_index] anims.append(Transform( VGroup(*[pi.parents for pi in these_pis]), VGroup(*[VGroup(pi, pi.copy()) for pi in these_pis]), submobject_mode = "lagged_start", run_time = 2, )) exp += 1 return Succession(*anims, rate_func=linear) class ApplicationNames(Scene): def construct(self): for name in "Velocity", "Oscillation", "Population growth": mob = TextMobject(name) mob.scale(2) self.play(Write(mob)) self.wait(2) self.play(FadeOut(mob)) class ListOfRules(PiCreatureScene): CONFIG = { "use_morty" : False, } def construct(self): rules = VGroup(*list(map(TexMobject, [ "\\frac{d}{dx} x^n = nx^{n-1}", "\\frac{d}{dx} \\sin(x) = \\cos(x)", "\\frac{d}{dx} \\cos(x) = -\\sin(x)", "\\frac{d}{dx} a^x = \\ln(a) a^x", "\\vdots" ]))) rules.arrange( DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT, ) rules[-1].shift(MED_LARGE_BUFF*RIGHT) rules.set_height(FRAME_HEIGHT-1) rules.next_to(self.pi_creature, RIGHT) rules.to_edge(DOWN) self.play( Write(rules), self.pi_creature.change_mode, "pleading", ) self.change_mode("tired") self.wait() class DerivativeOfXSquaredAsGraph(GraphScene, ZoomedScene, PiCreatureScene): CONFIG = { "start_x" : 2, "big_x" : 3, "dx" : 0.1, "x_min" : -9, "x_labeled_nums" : list(range(-8, 0, 2)) + list(range(2, 10, 2)), "y_labeled_nums" : list(range(2, 12, 2)), "little_rect_nudge" : 0.5*(1.5*UP+RIGHT), "graph_origin" : 2.5*DOWN + LEFT, "zoomed_canvas_corner" : UP+LEFT, "zoomed_canvas_frame_shape" : (4, 4), } def construct(self): self.draw_graph() self.ask_about_df_dx() self.show_differing_slopes() self.mention_alternate_view() def draw_graph(self): self.setup_axes(animate = True) graph = self.get_graph(lambda x : x**2) label = self.get_graph_label( graph, "f(x) = x^2", ) self.play(ShowCreation(graph)) self.play(Write(label)) self.wait() self.graph = graph def ask_about_df_dx(self): ss_group = self.get_secant_slope_group( self.start_x, self.graph, dx = self.dx, dx_label = "dx", df_label = "df", ) secant_line = ss_group.secant_line ss_group.remove(secant_line) v_line, nudged_v_line = [ self.get_vertical_line_to_graph( x, self.graph, line_class = DashedLine, color = RED, dashed_segment_length = 0.025 ) for x in (self.start_x, self.start_x+self.dx) ] df_dx = TexMobject("\\frac{df}{dx} ?") VGroup(*df_dx[:2]).set_color(ss_group.df_line.get_color()) VGroup(*df_dx[3:5]).set_color(ss_group.dx_line.get_color()) df_dx.next_to( self.input_to_graph_point(self.start_x, self.graph), DOWN+RIGHT, buff = MED_SMALL_BUFF ) derivative_q = TextMobject("Derivative?") derivative_q.next_to(self.pi_creature.get_corner(UP+LEFT), UP) self.play( Write(derivative_q, run_time = 1), self.pi_creature.change_mode, "speaking" ) self.wait() self.play( FadeOut(derivative_q), self.pi_creature.change_mode, "plain" ) self.play(ShowCreation(v_line)) self.wait() self.play(Transform(v_line.copy(), nudged_v_line)) self.remove(self.get_mobjects_from_last_animation()[0]) self.add(nudged_v_line) self.wait() self.activate_zooming() self.little_rectangle.replace(self.big_rectangle) self.play( FadeIn(self.little_rectangle), FadeIn(self.big_rectangle), ) self.play( ApplyFunction( lambda r : self.position_little_rectangle(r, ss_group), self.little_rectangle ), self.pi_creature.change_mode, "pondering", self.pi_creature.look_at, ss_group ) self.play( ShowCreation(ss_group.dx_line), Write(ss_group.dx_label), ) self.wait() self.play( ShowCreation(ss_group.df_line), Write(ss_group.df_label), ) self.wait() self.play(Write(df_dx)) self.wait() self.play(*list(map(FadeOut, [ v_line, nudged_v_line, ]))) self.ss_group = ss_group def position_little_rectangle(self, rect, ss_group): rect.set_width(3*self.dx) rect.move_to( ss_group.dx_line.get_left() ) rect.shift( self.dx*self.little_rect_nudge ) return rect def show_differing_slopes(self): ss_group = self.ss_group def rect_update(rect): self.position_little_rectangle(rect, ss_group) self.play( ShowCreation(ss_group.secant_line), self.pi_creature.change_mode, "thinking" ) ss_group.add(ss_group.secant_line) self.wait() for target_x in self.big_x, -self.dx/2, 1, 2: self.animate_secant_slope_group_change( ss_group, target_x = target_x, added_anims = [ UpdateFromFunc(self.little_rectangle, rect_update) ] ) self.wait() def mention_alternate_view(self): self.remove(self.pi_creature) everything = VGroup(*self.get_mobjects()) self.add(self.pi_creature) self.disactivate_zooming() self.play( ApplyMethod( everything.shift, FRAME_WIDTH*LEFT, rate_func = lambda t : running_start(t, -0.1) ), self.pi_creature.change_mode, "happy" ) self.say("Let's try \\\\ another view.", target_mode = "speaking") self.wait(2) class NudgeSideLengthOfSquare(PiCreatureScene): CONFIG = { "square_width" : 3, "alt_square_width" : 5, "dx" : 0.25, "alt_dx" : 0.01, "square_color" : GREEN, "square_fill_opacity" : 0.75, "three_color" : GREEN, "dx_color" : BLUE_B, "is_recursing_on_dx" : False, "is_recursing_on_square_width" : False, } def construct(self): ApplyMethod(self.pi_creature.change_mode, "speaking").update(1) self.add_function_label() self.introduce_square() self.increase_area() self.write_df_equation() self.set_color_shapes() self.examine_thin_rectangles() self.examine_tiny_square() self.show_smaller_dx() self.rule_of_thumb() self.write_out_derivative() def add_function_label(self): label = TexMobject("f(x) = x^2") label.next_to(ORIGIN, RIGHT, buff = (self.square_width-3)/2.) label.to_edge(UP) self.add(label) self.function_label = label def introduce_square(self): square = Square( side_length = self.square_width, stroke_width = 0, fill_opacity = self.square_fill_opacity, fill_color = self.square_color, ) square.to_corner(UP+LEFT, buff = LARGE_BUFF) x_squared = TexMobject("x^2") x_squared.move_to(square) braces = VGroup() for vect in RIGHT, DOWN: brace = Brace(square, vect) text = brace.get_text("$x$") brace.add(text) braces.add(brace) self.play( DrawBorderThenFill(square), self.pi_creature.change_mode, "plain" ) self.play(*list(map(GrowFromCenter, braces))) self.play(Write(x_squared)) self.change_mode("pondering") self.wait() self.square = square self.side_braces = braces def increase_area(self): color_kwargs = { "fill_color" : YELLOW, "fill_opacity" : self.square_fill_opacity, "stroke_width" : 0, } right_rect = Rectangle( width = self.dx, height = self.square_width, **color_kwargs ) bottom_rect = right_rect.copy().rotate(-np.pi/2) right_rect.next_to(self.square, RIGHT, buff = 0) bottom_rect.next_to(self.square, DOWN, buff = 0) corner_square = Square( side_length = self.dx, **color_kwargs ) corner_square.next_to(self.square, DOWN+RIGHT, buff = 0) right_line = Line( self.square.get_corner(UP+RIGHT), self.square.get_corner(DOWN+RIGHT), stroke_width = 0 ) bottom_line = Line( self.square.get_corner(DOWN+RIGHT), self.square.get_corner(DOWN+LEFT), stroke_width = 0 ) corner_point = VectorizedPoint( self.square.get_corner(DOWN+RIGHT) ) little_braces = VGroup() for vect in RIGHT, DOWN: brace = Brace( corner_square, vect, buff = SMALL_BUFF, ) text = brace.get_text("$dx$", buff = SMALL_BUFF) text.set_color(self.dx_color) brace.add(text) little_braces.add(brace) right_brace, bottom_brace = self.side_braces self.play( Transform(right_line, right_rect), Transform(bottom_line, bottom_rect), Transform(corner_point, corner_square), right_brace.next_to, right_rect, RIGHT, SMALL_BUFF, bottom_brace.next_to, bottom_rect, DOWN, SMALL_BUFF, ) self.remove(corner_point, bottom_line, right_line) self.add(corner_square, bottom_rect, right_rect) self.play(*list(map(GrowFromCenter, little_braces))) self.wait() self.play(*it.chain(*[ [mob.shift, vect*SMALL_BUFF] for mob, vect in [ (right_rect, RIGHT), (bottom_rect, DOWN), (corner_square, DOWN+RIGHT), (right_brace, RIGHT), (bottom_brace, DOWN), (little_braces, DOWN+RIGHT) ] ])) self.change_mode("thinking") self.wait() self.right_rect = right_rect self.bottom_rect = bottom_rect self.corner_square = corner_square self.little_braces = little_braces def write_df_equation(self): right_rect = self.right_rect bottom_rect = self.bottom_rect corner_square = self.corner_square df_equation = VGroup( TexMobject("df").set_color(right_rect.get_color()), TexMobject("="), right_rect.copy(), TextMobject("+"), right_rect.copy(), TexMobject("+"), corner_square.copy() ) df_equation.arrange() df_equation.next_to( self.function_label, DOWN, aligned_edge = LEFT, buff = SMALL_BUFF ) df, equals, r1, plus1, r2, plus2, s = df_equation pairs = [ (df, self.function_label[0]), (r1, right_rect), (r2, bottom_rect), (s, corner_square), ] for mover, origin in pairs: mover.save_state() Transform(mover, origin).update(1) self.play(df.restore) self.wait() self.play( *[ mob.restore for mob in (r1, r2, s) ]+[ Write(symbol) for symbol in (equals, plus1, plus2) ], run_time = 2 ) self.change_mode("happy") self.wait() self.df_equation = df_equation def set_color_shapes(self): df, equals, r1, plus1, r2, plus2, s = self.df_equation tups = [ (self.right_rect, self.bottom_rect, r1, r2), (self.corner_square, s) ] for tup in tups: self.play( *it.chain(*[ [m.scale_in_place, 1.2, m.set_color, RED] for m in tup ]), rate_func = there_and_back ) self.wait() def examine_thin_rectangles(self): df, equals, r1, plus1, r2, plus2, s = self.df_equation rects = VGroup(r1, r2) thin_rect_brace = Brace(rects, DOWN) text = thin_rect_brace.get_text("$2x \\, dx$") VGroup(*text[-2:]).set_color(self.dx_color) text.save_state() alt_text = thin_rect_brace.get_text("$2(3)(0.01)$") alt_text[2].set_color(self.three_color) VGroup(*alt_text[-5:-1]).set_color(self.dx_color) example_value = TexMobject("=0.06") example_value.next_to(alt_text, DOWN) self.play(GrowFromCenter(thin_rect_brace)) self.play( Write(text), self.pi_creature.change_mode, "pondering" ) self.wait() xs = VGroup(*[ brace[-1] for brace in self.side_braces ]) dxs = VGroup(*[ brace[-1] for brace in self.little_braces ]) for group, tex, color in (xs, "3", self.three_color), (dxs, "0.01", self.dx_color): group.save_state() group.generate_target() for submob in group.target: number = TexMobject(tex) number.set_color(color) number.move_to(submob, LEFT) Transform(submob, number).update(1) self.play(MoveToTarget(xs)) self.play(MoveToTarget(dxs)) self.wait() self.play(Transform(text, alt_text)) self.wait() self.play(Write(example_value)) self.wait() self.play( FadeOut(example_value), *[ mob.restore for mob in (xs, dxs, text) ] ) self.remove(text) text.restore() self.add(text) self.wait() self.dxs = dxs self.thin_rect_brace = thin_rect_brace self.thin_rect_area = text def examine_tiny_square(self): text = TexMobject("dx^2") VGroup(*text[:2]).set_color(self.dx_color) text.next_to(self.df_equation[-1], UP) text.save_state() alt_text = TextMobject("0.0001") alt_text.move_to(text) self.play(Write(text)) self.change_mode("surprised") self.wait() self.play( MoveToTarget(self.dxs), self.pi_creature.change_mode, "plain" ) for submob in self.dxs.target: number = TexMobject("0.01") number.set_color(self.dx_color) number.move_to(submob, LEFT) Transform(submob, number).update(1) self.play(MoveToTarget(self.dxs)) self.play( Transform(text, alt_text), self.pi_creature.change_mode, "raise_right_hand" ) self.wait(2) self.play(*[ mob.restore for mob in (self.dxs, text) ] + [ self.pi_creature.change_mode, "erm" ]) self.dx_squared = text def show_smaller_dx(self): self.mobjects_at_start_of_show_smaller_dx = [ mob.copy() for mob in self.get_mobjects() ] if self.is_recursing_on_dx: return alt_scene = self.__class__( skip_animations = True, dx = self.alt_dx, is_recursing_on_dx = True ) for mob in self.get_mobjects(): mob.save_state() self.play(*[ Transform(*pair) for pair in zip( self.get_mobjects(), alt_scene.mobjects_at_start_of_show_smaller_dx, ) ]) self.wait() self.play(*[ mob.restore for mob in self.get_mobjects() ]) self.change_mode("happy") self.wait() def rule_of_thumb(self): circle = Circle(color = RED) dx_squared_group = VGroup(self.dx_squared, self.df_equation[-1]) circle.replace(dx_squared_group, stretch = True) dx_squared_group.add(self.df_equation[-2]) circle.scale_in_place(1.5) safe_to_ignore = TextMobject("Safe to ignore") safe_to_ignore.next_to(circle, DOWN, aligned_edge = LEFT) safe_to_ignore.set_color(circle.get_color()) self.play(ShowCreation(circle)) self.play( Write(safe_to_ignore, run_time = 2), self.pi_creature.change_mode, "raise_right_hand" ) self.play( FadeOut(circle), FadeOut(safe_to_ignore), dx_squared_group.fade, 0.5, dx_squared_group.to_corner, UP+RIGHT, self.pi_creature.change_mode, "plain" ) self.wait() def write_out_derivative(self): df, equals, r1, plus1, r2, plus2, s = self.df_equation frac_line = TexMobject("-") frac_line.stretch_to_fit_width(df.get_width()) frac_line.move_to(df) dx = VGroup(*self.thin_rect_area[-2:]) x = self.thin_rect_area[1] self.play( Transform(r1, self.right_rect), Transform(r2, self.bottom_rect), FadeOut(plus1), FadeOut(self.thin_rect_brace) ) self.play( self.thin_rect_area.next_to, VGroup(df, equals), RIGHT, MED_SMALL_BUFF, UP, self.pi_creature.change_mode, "thinking" ) self.wait(2) self.play( ApplyMethod(df.next_to, frac_line, UP, SMALL_BUFF), ApplyMethod(dx.next_to, frac_line, DOWN, SMALL_BUFF), Write(frac_line), path_arc = -np.pi ) self.wait() brace_xs = [ brace[-1] for brace in self.side_braces ] xs = list(brace_xs) + [x] for x_mob in xs: number = TexMobject("(%d)"%self.square_width) number.move_to(x_mob, LEFT) number.shift( (x_mob.get_bottom()[1] - number[1].get_bottom()[1])*UP ) x_mob.save_state() x_mob.target = number self.play(*list(map(MoveToTarget, xs))) self.wait(2) #Recursively transform to what would have happened #with a wider square width self.mobjects_at_end_of_write_out_derivative = self.get_mobjects() if self.is_recursing_on_square_width or self.is_recursing_on_dx: return alt_scene = self.__class__( skip_animations = True, square_width = self.alt_square_width, is_recursing_on_square_width = True, ) self.play(*[ Transform(*pair) for pair in zip( self.mobjects_at_end_of_write_out_derivative, alt_scene.mobjects_at_end_of_write_out_derivative ) ]) self.change_mode("happy") self.wait(2) class ChangeInAreaOverChangeInX(Scene): def construct(self): fractions = [] for pair in ("Change in area", "Change in $x$"), ("$d(x^2)$", "$dx$"): top, bottom = list(map(TextMobject, pair)) top.set_color(YELLOW) bottom.set_color(BLUE_B) frac_line = TexMobject("-") frac_line.stretch_to_fit_width(top.get_width()) top.next_to(frac_line, UP, SMALL_BUFF) bottom.next_to(frac_line, DOWN, SMALL_BUFF) fractions.append(VGroup( top, frac_line, bottom )) words, symbols = fractions self.play(Write(words[0], run_time = 1)) self.play(*list(map(Write, words[1:])), run_time = 1) self.wait() self.play(Transform(words, symbols)) self.wait() class NudgeSideLengthOfCube(Scene): CONFIG = { "x_color" : BLUE, "dx_color" : GREEN, "df_color" : YELLOW, "use_morty" : False, "x" : 3, "dx" : 0.2, "alt_dx" : 0.02, "offset_vect" : OUT, "pose_angle" : np.pi/12, "pose_axis" : UP+RIGHT, "small_piece_scaling_factor" : 0.7, "allow_recursion" : True, } def construct(self): self.states = dict() if self.allow_recursion: self.alt_scene = self.__class__( skip_animations = True, allow_recursion = False, dx = self.alt_dx, ) self.add_title() self.introduce_cube() self.write_df_equation() self.write_derivative() def add_title(self): title = TexMobject("f(x) = x^3") title.shift(FRAME_X_RADIUS*LEFT/2) title.to_edge(UP) self.play(Write(title)) self.wait() def introduce_cube(self): cube = self.get_cube() cube.to_edge(LEFT, buff = 2*LARGE_BUFF) cube.shift(DOWN) dv_pieces = self.get_dv_pices(cube) original_dx = self.dx self.dx = 0 alt_dv_pieces = self.get_dv_pices(cube) self.dx = original_dx alt_dv_pieces.set_fill(opacity = 0) x_brace = Brace(cube, LEFT, buff = SMALL_BUFF) dx_brace = Brace( dv_pieces[1], LEFT, buff = SMALL_BUFF, ) dx_brace.stretch_in_place(1.5, 1) for brace, tex in (x_brace, "x"), (dx_brace, "dx"): brace.scale_in_place(0.95) brace.rotate_in_place(-np.pi/96) brace.shift(0.3*(UP+LEFT)) brace.add(brace.get_text("$%s$"%tex)) cube_group = VGroup(cube, dv_pieces, alt_dv_pieces) self.pose_3d_mobject(cube_group) self.play(DrawBorderThenFill(cube)) self.play(GrowFromCenter(x_brace)) self.wait() self.play(Transform(alt_dv_pieces, dv_pieces)) self.remove(alt_dv_pieces) self.add(dv_pieces) self.play(GrowFromCenter(dx_brace)) self.wait() for piece in dv_pieces: piece.on_cube_state = piece.copy() self.play(*[ ApplyMethod( piece.shift, 0.5*(piece.get_center()-cube.get_center()) ) for piece in dv_pieces ]+[ ApplyMethod(dx_brace.shift, 0.7*UP) ]) self.wait() self.cube = cube self.dx_brace = dx_brace self.faces, self.bars, self.corner_cube = [ VGroup(*[ piece for piece in dv_pieces if piece.type == target_type ]) for target_type in ("face", "bar", "corner_cube") ] def write_df_equation(self): df_equation = VGroup( TexMobject("df"), TexMobject("="), self.organize_faces(self.faces.copy()), TexMobject("+"), self.organize_bars(self.bars.copy()), TexMobject("+"), self.corner_cube.copy() ) df, equals, faces, plus1, bars, plus2, corner_cube = df_equation df.set_color(self.df_color) for three_d_mob in faces, bars, corner_cube: three_d_mob.scale(self.small_piece_scaling_factor) # self.pose_3d_mobject(three_d_mob) faces.set_fill(opacity = 0.3) df_equation.arrange(RIGHT) df_equation.next_to(ORIGIN, RIGHT) df_equation.to_edge(UP) faces_brace = Brace(faces, DOWN) derivative = faces_brace.get_tex("3x^2", "\\, dx") extras_brace = Brace(VGroup(bars, corner_cube), DOWN) ignore_text = extras_brace.get_text( "Multiple \\\\ of $dx^2$" ) ignore_text.scale_in_place(0.7) x_squared_dx = TexMobject("x^2", "\\, dx") self.play(*list(map(Write, [df, equals]))) self.grab_pieces(self.faces, faces) self.wait() self.shrink_dx("Faces are introduced") face = self.faces[0] face.save_state() self.play(face.shift, FRAME_X_RADIUS*RIGHT) x_squared_dx.next_to(face, LEFT) self.play(Write(x_squared_dx, run_time = 1)) self.wait() for submob, sides in zip(x_squared_dx, [face[0], VGroup(*face[1:])]): self.play( submob.set_color, RED, sides.set_color, RED, rate_func = there_and_back ) self.wait() self.play( face.restore, Transform( x_squared_dx, derivative, replace_mobject_with_target_in_scene = True ), GrowFromCenter(faces_brace) ) self.wait() self.grab_pieces(self.bars, bars, plus1) self.grab_pieces(self.corner_cube, corner_cube, plus2) self.play( GrowFromCenter(extras_brace), Write(ignore_text) ) self.wait() self.play(*[ ApplyMethod(mob.fade, 0.7) for mob in [ plus1, bars, plus2, corner_cube, extras_brace, ignore_text ] ]) self.wait() self.df_equation = df_equation self.derivative = derivative def write_derivative(self): df, equals, faces, plus1, bars, plus2, corner_cube = self.df_equation df = df.copy() equals = equals.copy() df_equals = VGroup(df, equals) derivative = self.derivative.copy() dx = derivative[1] extra_stuff = TexMobject("+(\\dots)", "dx^2") dx_squared = extra_stuff[1] derivative.generate_target() derivative.target.shift(2*DOWN) extra_stuff.next_to(derivative.target) self.play( MoveToTarget(derivative), df_equals.next_to, derivative.target[0], LEFT, df_equals.shift, 0.07*DOWN ) self.play(Write(extra_stuff)) self.wait() frac_line = TexMobject("-") frac_line.replace(df) extra_stuff.generate_target() extra_stuff.target.next_to(derivative[0]) frac_line2 = TexMobject("-") frac_line2.stretch_to_fit_width( extra_stuff.target[1].get_width() ) frac_line2.move_to(extra_stuff.target[1]) extra_stuff.target[1].next_to(frac_line2, UP, buff = SMALL_BUFF) dx_below_dx_squared = TexMobject("dx") dx_below_dx_squared.next_to(frac_line2, DOWN, buff = SMALL_BUFF) self.play( FadeIn(frac_line), FadeIn(frac_line2), df.next_to, frac_line, UP, SMALL_BUFF, dx.next_to, frac_line, DOWN, SMALL_BUFF, MoveToTarget(extra_stuff), Write(dx_below_dx_squared), path_arc = -np.pi ) self.wait() inner_dx = VGroup(*dx_squared[:-1]) self.play( FadeOut(frac_line2), FadeOut(dx_below_dx_squared), dx_squared[-1].set_color, BLACK, inner_dx.next_to, extra_stuff[0], RIGHT, SMALL_BUFF ) self.wait() self.shrink_dx("Derivative is written", restore = False) self.play(*[ ApplyMethod(mob.fade, 0.7) for mob in (extra_stuff, inner_dx) ]) self.wait(2) anims = [] for mob in list(self.faces)+list(self.bars)+list(self.corner_cube): vect = mob.get_center()-self.cube.get_center() anims += [ mob.shift, -(1./3)*vect ] anims += self.dx_brace.shift, 0.7*DOWN self.play(*anims) self.wait() def grab_pieces(self, start_pieces, end_pices, to_write = None): for piece in start_pieces: piece.generate_target() piece.target.rotate_in_place( np.pi/12, piece.get_center()-self.cube.get_center() ) piece.target.set_color(RED) self.play(*list(map(MoveToTarget, start_pieces)), rate_func = wiggle) self.wait() added_anims = [] if to_write is not None: added_anims.append(Write(to_write)) self.play( Transform(start_pieces.copy(), end_pices), *added_anims ) def shrink_dx(self, state_name, restore = True): mobjects = self.get_mobjects() mobjects_with_points = [ m for m in mobjects if m.get_num_points() > 0 ] #Alt_scene will reach this point, and save copy of self #in states dict self.states[state_name] = [ mob.copy() for mob in mobjects_with_points ] if not self.allow_recursion: return if restore: movers = self.states[state_name] for mob in movers: mob.save_state() self.remove(*mobjects) else: movers = mobjects_with_points self.play(*[ Transform(*pair) for pair in zip( movers, self.alt_scene.states[state_name] ) ]) self.wait() if restore: self.play(*[m.restore for m in movers]) self.remove(*movers) self.mobjects = mobjects def get_cube(self): cube = self.get_prism(self.x, self.x, self.x) cube.set_fill(color = BLUE, opacity = 0.3) cube.set_stroke(color = WHITE, width = 1) return cube def get_dv_pices(self, cube): pieces = VGroup() for vect in it.product([0, 1], [0, 1], [0, 1]): if np.all(vect == ORIGIN): continue args = [ self.x if bit is 0 else self.dx for bit in vect ] piece = self.get_prism(*args) piece.next_to(cube, np.array(vect), buff = 0) pieces.add(piece) if sum(vect) == 1: piece.type = "face" elif sum(vect) == 2: piece.type = "bar" else: piece.type = "corner_cube" return pieces def organize_faces(self, faces): self.unpose_3d_mobject(faces) for face in faces: dimensions = [ face.length_over_dim(dim) for dim in range(3) ] thin_dim = np.argmin(dimensions) if thin_dim == 0: face.rotate(np.pi/2, DOWN) elif thin_dim == 1: face.rotate(np.pi/2, RIGHT) faces.arrange(OUT, buff = LARGE_BUFF) self.pose_3d_mobject(faces) return faces def organize_bars(self, bars): self.unpose_3d_mobject(bars) for bar in bars: dimensions = [ bar.length_over_dim(dim) for dim in range(3) ] thick_dim = np.argmax(dimensions) if thick_dim == 0: bar.rotate(np.pi/2, OUT) elif thick_dim == 2: bar.rotate(np.pi/2, LEFT) bars.arrange(OUT, buff = LARGE_BUFF) self.pose_3d_mobject(bars) return bars def get_corner_cube(self): return self.get_prism(self.dx, self.dx, self.dx) def get_prism(self, width, height, depth): color_kwargs = { "fill_color" : YELLOW, "fill_opacity" : 0.4, "stroke_color" : WHITE, "stroke_width" : 0.1, } front = Rectangle( width = width, height = height, **color_kwargs ) face = VGroup(front) for vect in LEFT, RIGHT, UP, DOWN: if vect is LEFT or vect is RIGHT: side = Rectangle( height = height, width = depth, **color_kwargs ) else: side = Rectangle( height = depth, width = width, **color_kwargs ) side.next_to(front, vect, buff = 0) side.rotate( np.pi/2, rotate_vector(vect, -np.pi/2), about_point = front.get_edge_center(vect) ) face.add(side) return face def pose_3d_mobject(self, mobject): mobject.rotate_in_place(self.pose_angle, self.pose_axis) return mobject def unpose_3d_mobject(self, mobject): mobject.rotate_in_place(-self.pose_angle, self.pose_axis) return mobject class ShowCubeDVIn3D(Scene): def construct(self): raise Exception("This scene is only here for the stage_scenes script.") class GraphOfXCubed(GraphScene): CONFIG = { "x_min" : -6, "x_max" : 6, "x_axis_width" : FRAME_WIDTH, "x_labeled_nums" : list(range(-6, 7)), "y_min" : -35, "y_max" : 35, "y_axis_height" : FRAME_HEIGHT, "y_tick_frequency" : 5, "y_labeled_nums" : list(range(-30, 40, 10)), "graph_origin" : ORIGIN, "dx" : 0.2, "deriv_x_min" : -3, "deriv_x_max" : 3, } def construct(self): self.setup_axes(animate = False) graph = self.get_graph(lambda x : x**3) label = self.get_graph_label( graph, "f(x) = x^3", direction = LEFT, ) deriv_graph, full_deriv_graph = [ self.get_derivative_graph( graph, color = DERIVATIVE_COLOR, x_min = low_x, x_max = high_x, ) for low_x, high_x in [ (self.deriv_x_min, self.deriv_x_max), (self.x_min, self.x_max), ] ] deriv_label = self.get_graph_label( deriv_graph, "\\frac{df}{dx}(x) = 3x^2", x_val = -3, direction = LEFT ) deriv_label.shift(0.5*DOWN) ss_group = self.get_secant_slope_group( self.deriv_x_min, graph, dx = self.dx, dx_line_color = WHITE, df_line_color = WHITE, secant_line_color = YELLOW, ) self.play(ShowCreation(graph)) self.play(Write(label, run_time = 1)) self.wait() self.play(Write(deriv_label, run_time = 1)) self.play(ShowCreation(ss_group, submobject_mode = "all_at_once")) self.animate_secant_slope_group_change( ss_group, target_x = self.deriv_x_max, run_time = 10, added_anims = [ ShowCreation(deriv_graph, run_time = 10) ] ) self.play(FadeIn(full_deriv_graph)) self.wait() for x_val in -2, -self.dx/2, 2: self.animate_secant_slope_group_change( ss_group, target_x = x_val, run_time = 2 ) if x_val != -self.dx/2: v_line = self.get_vertical_line_to_graph( x_val, deriv_graph, line_class = DashedLine ) self.play(ShowCreation(v_line)) self.play(FadeOut(v_line)) class PatternForPowerRule(PiCreatureScene): CONFIG = { "num_exponents" : 5, } def construct(self): self.introduce_pattern() self.generalize_pattern() self.show_hopping() def introduce_pattern(self): exp_range = list(range(1, 1+self.num_exponents)) colors = color_gradient([BLUE_D, YELLOW], self.num_exponents) derivatives = VGroup() for exponent, color in zip(exp_range, colors): derivative = TexMobject( "\\frac{d(x^%d)}{dx} = "%exponent, "%d x^{%d}"%(exponent, exponent-1) ) VGroup(*derivative[0][2:4]).set_color(color) derivatives.add(derivative) derivatives.arrange( DOWN, aligned_edge = LEFT, buff = MED_LARGE_BUFF ) derivatives.set_height(FRAME_HEIGHT-1) derivatives.to_edge(LEFT) self.play(FadeIn(derivatives[0])) for d1, d2 in zip(derivatives, derivatives[1:]): self.play(Transform( d1.copy(), d2, replace_mobject_with_target_in_scene = True )) self.change_mode("thinking") self.wait() for derivative in derivatives[-2:]: derivative.save_state() self.play( derivative.scale, 2, derivative.next_to, derivative, RIGHT, SMALL_BUFF, DOWN, ) self.wait(2) self.play(derivative.restore) self.remove(derivative) derivative.restore() self.add(derivative) self.derivatives = derivatives self.colors = colors def generalize_pattern(self): derivatives = self.derivatives power_rule = TexMobject( "\\frac{d (x^n)}{dx} = ", "nx^{n-1}" ) title = TextMobject("``Power rule''") title.next_to(power_rule, UP, MED_LARGE_BUFF) lines = VGroup(*[ Line( deriv.get_right(), power_rule.get_left(), buff = MED_SMALL_BUFF, color = deriv[0][2].get_color() ) for deriv in derivatives ]) self.play( Transform( VGroup(*[d[0].copy() for d in derivatives]), VGroup(power_rule[0]), replace_mobject_with_target_in_scene = True ), ShowCreation(lines), submobject_mode = "lagged_start", run_time = 2, ) self.wait() self.play(Write(power_rule[1])) self.wait() self.play( Write(title), self.pi_creature.change_mode, "speaking" ) self.wait() def show_hopping(self): exp_range = list(range(2, 2+self.num_exponents-1)) self.change_mode("tired") for exp, color in zip(exp_range, self.colors[1:]): form = TexMobject( "x^", str(exp), "\\rightarrow", str(exp), "x^", str(exp-1) ) form.set_color(color) form.to_corner(UP+RIGHT, buff = LARGE_BUFF) lhs = VGroup(*form[:2]) lhs_copy = lhs.copy() rhs = VGroup(*form[-2:]) arrow = form[2] self.play(Write(lhs)) self.play( lhs_copy.move_to, rhs, DOWN+LEFT, Write(arrow) ) self.wait() self.play( ApplyMethod( lhs_copy[1].replace, form[3], path_arc = np.pi, rate_func = running_start, ), FadeIn( form[5], rate_func = squish_rate_func(smooth, 0.5, 1) ) ) self.wait() self.play( self.pi_creature.change_mode, "hesitant", self.pi_creature.look_at, lhs_copy ) self.play(*list(map(FadeOut, [form, lhs_copy]))) class PowerRuleAlgebra(Scene): CONFIG = { "dx_color" : YELLOW, "x_color" : BLUE, } def construct(self): x_to_n = TexMobject("x^n") down_arrow = Arrow(UP, DOWN, buff = MED_LARGE_BUFF) paren_strings = ["(", "x", "+", "dx", ")"] x_dx_to_n = TexMobject(*paren_strings +["^n"]) equals = TexMobject("=") equals2 = TexMobject("=") full_product = TexMobject( *paren_strings*3+["\\cdots"]+paren_strings ) x_to_n.set_color(self.x_color) for mob in x_dx_to_n, full_product: mob.set_color_by_tex("dx", self.dx_color) mob.set_color_by_tex("x", self.x_color) nudge_group = VGroup(x_to_n, down_arrow, x_dx_to_n) nudge_group.arrange(DOWN) nudge_group.to_corner(UP+LEFT) down_arrow.next_to(x_to_n[0], DOWN) equals.next_to(x_dx_to_n) full_product.next_to(equals) equals2.next_to(equals, DOWN, 1.5*LARGE_BUFF) nudge_brace = Brace(x_dx_to_n, DOWN) nudged_output = nudge_brace.get_text("Nudged \\\\ output") product_brace = Brace(full_product, UP) product_brace.add(product_brace.get_text("$n$ times")) self.add(x_to_n) self.play(ShowCreation(down_arrow)) self.play( FadeIn(x_dx_to_n), GrowFromCenter(nudge_brace), GrowFromCenter(nudged_output) ) self.wait() self.play( Write(VGroup(equals, full_product)), GrowFromCenter( product_brace, rate_func = squish_rate_func(smooth, 0.6, 1) ), run_time = 3 ) self.wait() self.workout_product(equals2, full_product) def workout_product(self, equals, full_product): product_part_tex_pairs = list(zip(full_product, full_product.expression_parts)) xs, dxs = [ VGroup(*[ submob for submob, tex in product_part_tex_pairs if tex == target_tex ]) for target_tex in ("x", "dx") ] x_to_n = TexMobject("x^n") extra_stuff = TexMobject("+(\\text{Multiple of }\\, dx^2)") # extra_stuff.scale(0.8) VGroup(*extra_stuff[-4:-2]).set_color(self.dx_color) x_to_n.next_to(equals, RIGHT, align_using_submobjects = True) x_to_n.set_color(self.x_color) xs_copy = xs.copy() full_product.save_state() self.play(full_product.set_color, WHITE) self.play(xs_copy.set_color, self.x_color) self.play( Write(equals), Transform(xs_copy, x_to_n) ) self.wait() brace, derivative_term = self.pull_out_linear_terms( x_to_n, product_part_tex_pairs, xs, dxs ) self.wait() circle = Circle(color = DERIVATIVE_COLOR) circle.replace(derivative_term, stretch = True) circle.scale_in_place(1.4) circle.rotate_in_place( Line( derivative_term.get_corner(DOWN+LEFT), derivative_term.get_corner(UP+RIGHT), ).get_angle() ) extra_stuff.next_to(brace, aligned_edge = UP) self.play(Write(extra_stuff), full_product.restore) self.wait() self.play(ShowCreation(circle)) self.wait() def pull_out_linear_terms(self, x_to_n, product_part_tex_pairs, xs, dxs): last_group = None all_linear_terms = VGroup() for dx_index, dx in enumerate(dxs): if dx is dxs[-1]: v_dots = TexMobject("\\vdots") v_dots.next_to(last_group[0], DOWN) h_dots_list = [ submob for submob, tex in product_part_tex_pairs if tex == "\\cdots" ] h_dots_copy = h_dots_list[0].copy() self.play(ReplacementTransform( h_dots_copy, v_dots, )) last_group.add(v_dots) all_linear_terms.add(v_dots) dx_copy = dx.copy() xs_copy = xs.copy() xs_copy.remove(xs_copy[dx_index]) self.play( dx_copy.set_color, self.dx_color, xs_copy.set_color, self.x_color, rate_func = squish_rate_func(smooth, 0, 0.5) ) dx_copy.generate_target() xs_copy.generate_target() target_list = [dx_copy.target] + list(xs_copy.target) target_list.sort( key=lambda m: m.get_center()[0] ) dots = TexMobject("+", ".", ".", "\\dots") for dot_index, dot in enumerate(dots): target_list.insert(2*dot_index, dot) group = VGroup(*target_list) group.arrange(RIGHT, SMALL_BUFF) if last_group is None: group.next_to(x_to_n, RIGHT) else: group.next_to(last_group, DOWN, aligned_edge = LEFT) last_group = group self.play( MoveToTarget(dx_copy), MoveToTarget(xs_copy), Write(dots) ) all_linear_terms.add(dx_copy, xs_copy, dots) all_linear_terms.generate_target() all_linear_terms.target.scale(0.7) brace = Brace(all_linear_terms.target, UP) compact = TexMobject("+\\,", "n", "x^{n-1}", "\\,dx") compact.set_color_by_tex("x^{n-1}", self.x_color) compact.set_color_by_tex("\\,dx", self.dx_color) compact.next_to(brace, UP) brace.add(compact) derivative_term = VGroup(*compact[1:3]) VGroup(brace, all_linear_terms.target).shift( x_to_n[0].get_right()+MED_LARGE_BUFF*RIGHT - \ compact[0].get_left() ) self.play(MoveToTarget(all_linear_terms)) self.play(Write(brace, run_time = 1)) return brace, derivative_term class ReactToFullExpansion(Scene): def construct(self): randy = Randolph() self.add(randy) self.play(randy.change_mode, "pleading") self.play(Blink(randy)) self.play(randy.change_mode, "angry") self.wait() self.play(randy.change_mode, "thinking") self.play(Blink(randy)) self.wait() class OneOverX(PiCreatureScene, GraphScene): CONFIG = { "unit_length" : 3.0, "graph_origin" : (FRAME_X_RADIUS - LARGE_BUFF)*LEFT + 2*DOWN, "rectangle_color_kwargs" : { "fill_color" : BLUE, "fill_opacity" : 0.5, "stroke_width" : 1, "stroke_color" : WHITE, }, "x_axis_label" : "", "y_axis_label" : "", "x_min" : 0, "y_min" : 0, "x_tick_frequency" : 0.5, "y_tick_frequency" : 0.5, "x_labeled_nums" : list(range(0, 4)), "y_labeled_nums" : [1], "y_axis_height" : 10, "morty_scale_val" : 0.8, "area_label_scale_factor" : 0.75, "dx" : 0.1, "start_x_value" : 1.3, "dx_color" : GREEN, "df_color" : RED, } def setup(self): for c in self.__class__.__bases__: c.setup(self) self.x_max = self.x_axis_width/self.unit_length self.y_max = self.y_axis_height/self.unit_length def construct(self): self.force_skipping() self.introduce_function() self.introduce_puddle() self.introduce_graph() self.perform_nudge() def introduce_function(self): func = TexMobject("f(x) = ", "\\frac{1}{x}") func.to_edge(UP) recip_copy = func[1].copy() x_to_neg_one = TexMobject("x^{-1}") x_to_neg_one.submobjects.reverse() neg_one = VGroup(*x_to_neg_one[:2]) neg_two = TexMobject("-2") self.play( Write(func), self.pi_creature.change_mode, "pondering" ) self.wait() self.play( recip_copy.next_to, self.pi_creature, UP+LEFT, self.pi_creature.change_mode, "raise_right_hand" ) x_to_neg_one.move_to(recip_copy) neg_two.replace(neg_one) self.play(ReplacementTransform(recip_copy, x_to_neg_one)) self.wait() self.play( neg_one.scale, 1.5, neg_one.next_to, x_to_neg_one, LEFT, SMALL_BUFF, DOWN, rate_func = running_start, path_arc = np.pi ) self.play(FadeIn(neg_two)) self.wait() self.say( "More geometry!", target_mode = "hooray", added_anims = [ FadeOut(x_to_neg_one), FadeOut(neg_two), ], run_time = 2 ) self.wait() self.play(RemovePiCreatureBubble(self.pi_creature)) def introduce_puddle(self): rect_group = self.get_rectangle_group(self.start_x_value) self.play( DrawBorderThenFill(rect_group.rectangle), Write(rect_group.area_label), self.pi_creature.change_mode, "thinking" ) self.play( GrowFromCenter(rect_group.x_brace), Write(rect_group.x_label), ) self.wait() self.play( GrowFromCenter(rect_group.recip_brace), Write(rect_group.recip_label), ) self.setup_axes(animate = True) self.wait() for d in 2, 3: self.change_rectangle_group( rect_group, d, target_group_kwargs = { "x_label" : str(d), "one_over_x_label" : "\\frac{1}{%d}"%d, }, run_time = 2 ) self.wait() self.change_rectangle_group(rect_group, 3) self.wait() self.rect_group = rect_group def introduce_graph(self): rect_group = self.rect_group graph = self.get_graph(lambda x : 1./x) graph.points = np.array(list(reversed(graph.points))) self.change_rectangle_group( rect_group, 0.01, added_anims = [ ShowCreation(graph) ], run_time = 5, ) self.change_mode("happy") self.change_rectangle_group(rect_group, self.start_x_value) self.wait() self.graph = graph def perform_nudge(self): rect_group = self.rect_group graph = self.graph rect_copy = rect_group.rectangle.copy() rect_copy.set_fill(opacity = 0) new_rect = self.get_rectangle( self.start_x_value + self.dx ) recip_brace = rect_group.recip_brace recip_brace.generate_target() recip_brace.target.next_to( new_rect, RIGHT, buff = SMALL_BUFF, aligned_edge = DOWN, ) recip_label = rect_group.recip_label recip_label.generate_target() recip_label.target.next_to(recip_brace.target, RIGHT) h_lines = VGroup(*[ DashedLine( ORIGIN, (rect_copy.get_width()+LARGE_BUFF)*RIGHT, color = self.df_color, stroke_width = 2 ).move_to(rect.get_corner(UP+LEFT), LEFT) for rect in (rect_group.rectangle, new_rect) ]) v_lines = VGroup(*[ DashedLine( ORIGIN, (rect_copy.get_height()+MED_LARGE_BUFF)*UP, color = self.dx_color, stroke_width = 2 ).move_to(rect.get_corner(DOWN+RIGHT), DOWN) for rect in (rect_group.rectangle, new_rect) ]) dx_brace = Brace(v_lines, UP, buff = 0) dx_label = dx_brace.get_text("$dx$") dx_brace.add(dx_label) df_brace = Brace(h_lines, RIGHT, buff = 0) df_label = df_brace.get_text("$d\\left(\\frac{1}{x}\\right)$") df_brace.add(df_label) negative = TextMobject("Negative") negative.set_color(RED) negative.next_to(df_label, UP+RIGHT) negative.shift(RIGHT) negative_arrow = Arrow( negative.get_left(), df_label.get_corner(UP+RIGHT), color = RED ) area_changes = VGroup() point_pairs = [ (new_rect.get_corner(UP+RIGHT), rect_copy.get_corner(DOWN+RIGHT)), (new_rect.get_corner(UP+LEFT), rect_copy.get_corner(UP+RIGHT)) ] for color, point_pair in zip([self.dx_color, self.df_color], point_pairs): area_change_rect = Rectangle( fill_opacity = 1, fill_color = color, stroke_width = 0 ) area_change_rect.replace( VGroup(*list(map(VectorizedPoint, point_pair))), stretch = True ) area_changes.add(area_change_rect) area_gained, area_lost = area_changes area_gained_label = TextMobject("Area gained") area_gained_label.scale(0.75) area_gained_label.next_to( rect_copy.get_corner(DOWN+RIGHT), UP+LEFT, buff = SMALL_BUFF ) area_gained_arrow = Arrow( area_gained_label.get_top(), area_gained.get_center(), buff = 0, color = WHITE ) area_lost_label = TextMobject("Area lost") area_lost_label.scale(0.75) area_lost_label.next_to(rect_copy.get_left(), RIGHT) area_lost_arrow = Arrow( area_lost_label.get_top(), area_lost.get_center(), buff = 0, color = WHITE ) question = TexMobject( "\\frac{d(1/x)}{dx} = ???" ) question.next_to( self.pi_creature.get_corner(UP+LEFT), UP, buff = MED_SMALL_BUFF, ) self.play( FadeOut(rect_group.area_label), ReplacementTransform(rect_copy, new_rect), MoveToTarget(recip_brace), MoveToTarget(recip_label), self.pi_creature.change_mode, "pondering" ) self.play( GrowFromCenter(dx_brace), *list(map(ShowCreation, v_lines)) ) self.wait() self.play( GrowFromCenter(df_brace), *list(map(ShowCreation, h_lines)) ) self.change_mode("confused") self.wait() self.play( FadeIn(area_gained), Write(area_gained_label, run_time = 2), ShowCreation(area_gained_arrow) ) self.wait() self.play( FadeIn(area_lost), Write(area_lost_label, run_time = 2), ShowCreation(area_lost_arrow) ) self.wait() self.revert_to_original_skipping_status()### self.play( Write(negative), ShowCreation(negative_arrow) ) self.wait() self.play( Write(question), self.pi_creature.change_mode, "raise_right_hand" ) self.wait(2) ######## def create_pi_creature(self): morty = PiCreatureScene.create_pi_creature(self) morty.scale( self.morty_scale_val, about_point = morty.get_corner(DOWN+RIGHT) ) return morty def draw_graph(self): self.setup_axes() graph = self.get_graph(lambda x : 1./x) rect_group = self.get_rectangle_group(0.5) self.add(rect_group) self.wait() self.change_rectangle_group( rect_group, 2, target_group_kwargs = { "x_label" : "2", "one_over_x_label" : "\\frac{1}{2}", }, added_anims = [ShowCreation(graph)] ) self.wait() def get_rectangle_group( self, x, x_label = "x", one_over_x_label = "\\frac{1}{x}" ): result = VGroup() result.x_val = x result.rectangle = self.get_rectangle(x) result.x_brace, result.recip_brace = braces = [ Brace(result.rectangle, vect) for vect in (UP, RIGHT) ] result.labels = VGroup() for brace, label in zip(braces, [x_label, one_over_x_label]): brace.get_text("$%s$"%label) result.labels.add(brace.get_text("$%s$"%label)) result.x_label, result.recip_label = result.labels area_label = TextMobject("Area = 1") area_label.scale(self.area_label_scale_factor) max_width = max(result.rectangle.get_width()-2*SMALL_BUFF, 0) if area_label.get_width() > max_width: area_label.set_width(max_width) area_label.move_to(result.rectangle) result.area_label = area_label result.add( result.rectangle, result.x_brace, result.recip_brace, result.labels, result.area_label, ) return result def get_rectangle(self, x): try: y = 1./x except ZeroDivisionError: y = 100 rectangle = Rectangle( width = x*self.unit_length, height = y*self.unit_length, **self.rectangle_color_kwargs ) rectangle.move_to(self.graph_origin, DOWN+LEFT) return rectangle def change_rectangle_group( self, rect_group, target_x, target_group_kwargs = None, added_anims = [], **anim_kwargs ): target_group_kwargs = target_group_kwargs or {} if "run_time" not in anim_kwargs: anim_kwargs["run_time"] = 3 target_group = self.get_rectangle_group(target_x, **target_group_kwargs) target_labels = target_group.labels labels_transform = Transform( rect_group.labels, target_group.labels ) start_x = float(rect_group.x_val) def update_rect_group(group, alpha): x = interpolate(start_x, target_x, alpha) new_group = self.get_rectangle_group(x, **target_group_kwargs) Transform(group, new_group).update(1) labels_transform.update(alpha) for l1, l2 in zip(rect_group.labels, new_group.labels): l1.move_to(l2) return rect_group self.play( UpdateFromAlphaFunc(rect_group, update_rect_group), *added_anims, **anim_kwargs ) rect_group.x_val = target_x class AskRecipriocalQuestion(Scene): def construct(self): tex = TexMobject( "(\\text{What number?})", "\\cdot x = 1" ) arrow = Arrow(DOWN+LEFT, UP+RIGHT) arrow.move_to(tex[0].get_top(), DOWN+LEFT) self.play(Write(tex)) self.play(ShowCreation(arrow)) self.wait() class SquareRootOfX(Scene): CONFIG = { "square_color_kwargs" : { "stroke_color" : WHITE, "stroke_width" : 1, "fill_color" : BLUE_E, "fill_opacity" : 1, }, "bigger_square_color_kwargs" : { "stroke_color" : WHITE, "stroke_width" : 1, "fill_color" : YELLOW, "fill_opacity" : 0.7, }, "square_corner" : 6*LEFT+3*UP, "square_width" : 3, "d_sqrt_x" : 0.3, } def construct(self): self.add_title() self.introduce_square() self.nudge_square() def add_title(self): title = TexMobject("f(x) = \\sqrt{x}") title.next_to(ORIGIN, RIGHT) title.to_edge(UP) self.add(title) def introduce_square(self): square = Square( side_length = self.square_width, **self.square_color_kwargs ) square.move_to(self.square_corner, UP+LEFT) area_label = TextMobject("Area $ = x$") area_label.move_to(square) bottom_brace, right_brace = braces = VGroup(*[ Brace(square, vect) for vect in (DOWN, RIGHT) ]) for brace in braces: brace.add(brace.get_text("$\\sqrt{x}$")) self.play( DrawBorderThenFill(square), Write(area_label) ) self.play(*list(map(FadeIn, braces))) self.wait() self.square = square self.area_label = area_label self.braces = braces def nudge_square(self): square = self.square area_label = self.area_label bottom_brace, right_brace = self.braces bigger_square = Square( side_length = self.square_width + self.d_sqrt_x, **self.bigger_square_color_kwargs ) bigger_square.move_to(self.square_corner, UP+LEFT) square_copy = square.copy() lines = VGroup(*[ DashedLine( ORIGIN, (self.square_width + MED_LARGE_BUFF)*vect, color = WHITE, stroke_width = 3 ).shift(s.get_corner(corner)) for corner, vect in [(DOWN+LEFT, RIGHT), (UP+RIGHT, DOWN)] for s in [square, bigger_square] ]) little_braces = VGroup(*[ Brace(VGroup(*line_pair), vect, buff = 0) for line_pair, vect in [(lines[:2], RIGHT), (lines[2:], DOWN)] ]) for brace in little_braces: tex = brace.get_text("$d\\sqrt{x}$", buff = SMALL_BUFF) tex.scale_in_place(0.8) brace.add(tex) area_increase = TextMobject("$dx$ = New area") area_increase.set_color(bigger_square.get_color()) area_increase.next_to(square, RIGHT, 4) question = TexMobject("\\frac{d\\sqrt{x}}{dx} = ???") VGroup(*question[5:7]).set_color(bigger_square.get_color()) question.next_to( area_increase, DOWN, aligned_edge = LEFT, buff = LARGE_BUFF ) self.play( Transform(square_copy, bigger_square), Animation(square), Animation(area_label), bottom_brace.next_to, bigger_square, DOWN, SMALL_BUFF, LEFT, right_brace.next_to, bigger_square, RIGHT, SMALL_BUFF, UP, ) self.play(Write(area_increase)) self.play(*it.chain( list(map(ShowCreation, lines)), list(map(FadeIn, little_braces)) )) self.play(Write(question)) self.wait() class MentionSine(TeacherStudentsScene): def construct(self): self.teacher_says("Let's tackle $\\sin(\\theta)$") self.change_student_modes("pondering", "hooray", "erm") self.wait(2) self.student_thinks("") self.zoom_in_on_thought_bubble() class NameUnitCircle(Scene): def construct(self): words = TextMobject("Unit circle") words.scale(2) words.set_color(BLUE) self.play(Write(words)) self.wait() class DerivativeOfSineIsSlope(Scene): def construct(self): tex = TexMobject( "\\frac{d(\\sin(\\theta))}{d\\theta} = ", "\\text{Slope of this graph}" ) tex.set_width(FRAME_WIDTH-1) tex.to_edge(DOWN) VGroup(*tex[0][2:8]).set_color(BLUE) VGroup(*tex[1][-9:]).set_color(BLUE) self.play(Write(tex, run_time = 2)) self.wait() class IntroduceUnitCircleWithSine(GraphScene): CONFIG = { "unit_length" : 2.5, "graph_origin" : ORIGIN, "x_axis_width" : 15, "y_axis_height" : 10, "x_min" : -3, "x_max" : 3, "y_min" : -2, "y_max" : 2, "x_labeled_nums" : [-2, -1, 1, 2], "y_labeled_nums" : [-1, 1], "x_tick_frequency" : 0.5, "y_tick_frequency" : 0.5, "circle_color" : BLUE, "example_radians" : 0.8, "rotations_per_second" : 0.25, "include_radial_line_dot" : True, "remove_angle_label" : True, "line_class" : DashedLine, "theta_label" : "= 0.8", } def construct(self): self.setup_axes() self.add_title() self.introduce_unit_circle() self.draw_example_radians() self.label_sine() self.walk_around_circle() def add_title(self): title = TexMobject("f(\\theta) = \\sin(\\theta)") title.to_corner(UP+LEFT) self.add(title) self.title = title def introduce_unit_circle(self): circle = self.get_unit_circle() radial_line = Line(ORIGIN, self.unit_length*RIGHT) radial_line.set_color(RED) if self.include_radial_line_dot: dot = Dot() dot.move_to(radial_line.get_end()) radial_line.add(dot) self.play(ShowCreation(radial_line)) self.play( ShowCreation(circle), Rotate(radial_line, 2*np.pi), run_time = 2, ) self.wait() self.circle = circle self.radial_line = radial_line def draw_example_radians(self): circle = self.circle radial_line = self.radial_line line = Line( ORIGIN, self.example_radians*self.unit_length*UP, color = YELLOW, ) line.shift(FRAME_X_RADIUS*RIGHT/3).to_edge(UP) line.insert_n_curves(10) line.make_smooth() arc = Arc( self.example_radians, radius = self.unit_length, color = line.get_color(), ) arc_copy = arc.copy().set_color(WHITE) brace = Brace(line, RIGHT) brace_text = brace.get_text("$\\theta%s$"%self.theta_label) brace_text.set_color(line.get_color()) theta_copy = brace_text[0].copy() self.play( GrowFromCenter(line), GrowFromCenter(brace), ) self.play(Write(brace_text)) self.wait() self.play( line.move_to, radial_line.get_end(), DOWN, FadeOut(brace) ) self.play(ReplacementTransform(line, arc)) self.wait() self.play( Rotate(radial_line, self.example_radians), ShowCreation(arc_copy) ) self.wait() arc_copy.generate_target() arc_copy.target.scale(0.2) theta_copy.generate_target() theta_copy.target.next_to( arc_copy.target, RIGHT, aligned_edge = DOWN, buff = SMALL_BUFF ) theta_copy.target.shift(SMALL_BUFF*UP) self.play(*list(map(MoveToTarget, [arc_copy, theta_copy]))) self.wait() self.angle_label = VGroup(arc_copy, theta_copy) self.example_theta_equation = brace_text def label_sine(self): radial_line = self.radial_line drop_point = radial_line.get_end()[0]*RIGHT v_line = self.line_class(radial_line.get_end(), drop_point) brace = Brace(v_line, RIGHT) brace_text = brace.get_text("$\\sin(\\theta)$") brace_text[-2].set_color(YELLOW) self.play(ShowCreation(v_line)) self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait() faders = [brace, brace_text, self.example_theta_equation] if self.remove_angle_label: faders += self.angle_label self.play(*list(map(FadeOut, faders))) self.v_line = v_line def walk_around_circle(self): radial_line = self.radial_line v_line = self.v_line def v_line_update(v_line): drop_point = radial_line.get_end()[0]*RIGHT v_line.put_start_and_end_on( radial_line.get_end(), drop_point ) return v_line filler_arc = self.circle.copy() filler_arc.set_color(YELLOW) curr_arc_portion = self.example_radians/(2*np.pi) filler_portion = 1 - curr_arc_portion filler_arc.pointwise_become_partial(filler_arc, curr_arc_portion, 1) self.play( Rotate(radial_line, filler_portion*2*np.pi), ShowCreation(filler_arc), UpdateFromFunc(v_line, v_line_update), run_time = filler_portion/self.rotations_per_second, rate_func=linear, ) for x in range(5): self.play( Rotate(radial_line, 2*np.pi), UpdateFromFunc(v_line, v_line_update), run_time = 1./self.rotations_per_second, rate_func=linear, ) ############## def setup_axes(self): GraphScene.setup_axes(self) VGroup(*self.x_axis.numbers[:2]).shift(MED_SMALL_BUFF*LEFT) VGroup(*self.x_axis.numbers[2:]).shift(SMALL_BUFF*RIGHT) self.y_axis.numbers[0].shift(MED_SMALL_BUFF*DOWN) self.y_axis.numbers[1].shift(MED_SMALL_BUFF*UP) def get_unit_circle(self): return Circle( radius = self.unit_length, color = self.circle_color, ) class DerivativeIntuitionFromSineGraph(GraphScene): CONFIG = { "graph_origin" : 6*LEFT, "x_axis_width" : 11, "x_min" : 0, "x_max" : 4*np.pi, "x_labeled_nums" : np.arange(0, 4*np.pi, np.pi), "x_tick_frequency" : np.pi/4, "x_axis_label" : "$\\theta$", "y_axis_height" : 6, "y_min" : -2, "y_max" : 2, "y_tick_frequency" : 0.5, "y_axis_label" : "", } def construct(self): self.setup_axes() self.draw_sine_graph() self.draw_derivative_from_slopes() self.alter_derivative_graph() def draw_sine_graph(self): graph = self.get_graph(np.sin) v_line = DashedLine(ORIGIN, UP) rps = IntroduceUnitCircleWithSine.CONFIG["rotations_per_second"] self.play( ShowCreation(graph), UpdateFromFunc(v_line, lambda v : self.v_line_update(v, graph)), run_time = 2./rps, rate_func=linear ) self.wait() self.graph = graph def draw_derivative_from_slopes(self): ss_group = self.get_secant_slope_group( 0, self.graph, dx = 0.01, secant_line_color = RED, ) deriv_graph = self.get_graph(np.cos, color = DERIVATIVE_COLOR) v_line = DashedLine( self.graph_origin, self.coords_to_point(0, 1), color = RED ) self.play(ShowCreation(ss_group, submobject_mode = "all_at_once")) self.play(ShowCreation(v_line)) self.wait() last_theta = 0 next_theta = np.pi/2 while last_theta < self.x_max: deriv_copy = deriv_graph.copy() self.animate_secant_slope_group_change( ss_group, target_x = next_theta, added_anims = [ ShowCreation( deriv_copy, rate_func = lambda t : interpolate( last_theta/self.x_max, next_theta/self.x_max, smooth(t) ), run_time = 3, ), UpdateFromFunc( v_line, lambda v : self.v_line_update(v, deriv_copy), run_time = 3 ), ] ) self.wait() if next_theta == 2*np.pi: words = TextMobject("Looks a lot like $\\cos(\\theta)$") words.next_to(self.graph_origin, RIGHT) words.to_edge(UP) arrow = Arrow( words.get_bottom(), deriv_graph.point_from_proportion(0.45) ) VGroup(words, arrow).set_color(deriv_graph.get_color()) self.play( Write(words), ShowCreation(arrow) ) self.remove(deriv_copy) last_theta = next_theta next_theta += np.pi/2 self.add(deriv_copy) self.deriv_graph = deriv_copy def alter_derivative_graph(self): func_list = [ lambda x : 0.5*(np.cos(x)**3 + np.cos(x)), lambda x : 0.75*(np.sign(np.cos(x))*np.cos(x)**2 + np.cos(x)), lambda x : 2*np.cos(x), lambda x : np.cos(x), ] for func in func_list: new_graph = self.get_graph(func, color = DERIVATIVE_COLOR) self.play( Transform(self.deriv_graph, new_graph), run_time = 2 ) self.wait() ###### def v_line_update(self, v_line, graph): point = graph.point_from_proportion(1) drop_point = point[0]*RIGHT v_line.put_start_and_end_on(drop_point, point) return v_line def setup_axes(self): GraphScene.setup_axes(self) self.x_axis.remove(self.x_axis.numbers) self.remove(self.x_axis.numbers) for x in range(1, 4): if x == 1: label = TexMobject("\\pi") else: label = TexMobject("%d\\pi"%x) label.next_to(self.coords_to_point(x*np.pi, 0), DOWN, MED_LARGE_BUFF) self.add(label) self.x_axis_label_mob.set_color(YELLOW) class LookToFunctionsMeaning(TeacherStudentsScene): def construct(self): self.teacher_says(""" Look to the function's actual meaning """) self.change_student_modes(*["pondering"]*3) self.wait(3) class DerivativeFromZoomingInOnSine(IntroduceUnitCircleWithSine, ZoomedScene): CONFIG = { "zoom_factor" : 10, "zoomed_canvas_frame_shape" : (3, 4.5), "include_radial_line_dot" : False, "remove_angle_label" : False, "theta_label" : "", "line_class" : Line, "example_radians" : 1.0, "zoomed_canvas_corner_buff" : SMALL_BUFF, "d_theta" : 0.05, } def construct(self): self.setup_axes() self.add_title() self.introduce_unit_circle() self.draw_example_radians() self.label_sine() self.zoom_in() self.perform_nudge() self.show_similar_triangles() self.analyze_ratios() def zoom_in(self): self.activate_zooming() self.little_rectangle.next_to(self.radial_line.get_end(), UP, LARGE_BUFF) self.play(*list(map(FadeIn, [ self.little_rectangle, self.big_rectangle ]))) self.play( self.little_rectangle.move_to, self.radial_line.get_end(), DOWN+RIGHT, self.little_rectangle.shift, SMALL_BUFF*(DOWN+RIGHT) ) self.wait() def perform_nudge(self): d_theta_arc = Arc( start_angle = self.example_radians, angle = self.d_theta, radius = self.unit_length, color = MAROON_B, stroke_width = 6 ) d_theta_arc.scale(self.zoom_factor) d_theta_brace = Brace( d_theta_arc, rotate_vector(RIGHT, self.example_radians) ) d_theta_label = TexMobject("d\\theta") d_theta_label.next_to( d_theta_brace.get_center(), d_theta_brace.direction, MED_LARGE_BUFF ) d_theta_label.set_color(d_theta_arc.get_color()) group = VGroup(d_theta_arc, d_theta_brace, d_theta_label) group.scale(1./self.zoom_factor) point = self.radial_line.get_end() nudged_point = d_theta_arc.point_from_proportion(1) interim_point = nudged_point[0]*RIGHT+point[1]*UP h_line = DashedLine( interim_point, point, dashed_segment_length = 0.01 ) d_sine_line = Line(interim_point, nudged_point, color = DERIVATIVE_COLOR) d_sine_brace = Brace(Line(ORIGIN, UP), LEFT) d_sine_brace.set_height(d_sine_line.get_height()) d_sine_brace.next_to(d_sine_line, LEFT, buff = SMALL_BUFF/self.zoom_factor) d_sine = TexMobject("d(\\sin(\\theta))") d_sine.set_color(d_sine_line.get_color()) d_sine.set_width(1.5*self.d_theta*self.unit_length) d_sine.next_to(d_sine_brace, LEFT, SMALL_BUFF/self.zoom_factor) self.play(ShowCreation(d_theta_arc)) self.play( GrowFromCenter(d_theta_brace), FadeIn(d_theta_label) ) self.wait() self.play( ShowCreation(h_line), ShowCreation(d_sine_line) ) self.play( GrowFromCenter(d_sine_brace), Write(d_sine) ) self.wait() self.little_triangle = Polygon( nudged_point, point, interim_point ) self.d_theta_group = VGroup(d_theta_brace, d_theta_label) self.d_sine_group = VGroup(d_sine_brace, d_sine) def show_similar_triangles(self): little_triangle = self.little_triangle big_triangle = Polygon( self.graph_origin, self.radial_line.get_end(), self.radial_line.get_end()[0]*RIGHT, ) for triangle in little_triangle, big_triangle: triangle.set_color(GREEN) triangle.set_fill(GREEN, opacity = 0.5) big_triangle_copy = big_triangle.copy() big_triangle_copy.next_to(ORIGIN, UP+LEFT) new_angle_label = self.angle_label.copy() new_angle_label.scale( little_triangle.get_width()/big_triangle.get_height() ) new_angle_label.rotate(-np.pi/2) new_angle_label.shift(little_triangle.points[0]) new_angle_label[1].rotate_in_place(np.pi/2) little_triangle_lines = VGroup(*[ Line(*list(map(little_triangle.get_corner, pair))) for pair in [ (DOWN+RIGHT, UP+LEFT), (UP+LEFT, DOWN+LEFT) ] ]) little_triangle_lines.set_color(little_triangle.get_color()) self.play(DrawBorderThenFill(little_triangle)) self.play( little_triangle.scale, 2, little_triangle.get_corner(DOWN+RIGHT), little_triangle.set_color, YELLOW, rate_func = there_and_back ) self.wait() groups = [self.d_theta_group, self.d_sine_group] for group, line in zip(groups, little_triangle_lines): self.play(ApplyMethod( line.rotate_in_place, np.pi/12, rate_func = wiggle, remover = True, )) self.play( group.scale, 1.2, group.get_corner(DOWN+RIGHT), group.set_color, YELLOW, rate_func = there_and_back, ) self.wait() self.play(ReplacementTransform( little_triangle.copy().set_fill(opacity = 0), big_triangle_copy, path_arc = np.pi/2, run_time = 2 )) self.wait() self.play( ReplacementTransform(big_triangle_copy, big_triangle), Animation(self.angle_label) ) self.wait() self.play( self.radial_line.rotate_in_place, np.pi/12, Animation(big_triangle), rate_func = wiggle, ) self.wait() self.play( ReplacementTransform( big_triangle.copy().set_fill(opacity = 0), little_triangle, path_arc = -np.pi/2, run_time = 3, ), ReplacementTransform( self.angle_label.copy(), new_angle_label, path_arc = -np.pi/2, run_time = 3, ), ) self.play( new_angle_label.scale_in_place, 2, new_angle_label.set_color, RED, rate_func = there_and_back ) self.wait() def analyze_ratios(self): d_ratio = TexMobject("\\frac{d(\\sin(\\theta))}{d\\theta} = ") VGroup(*d_ratio[:9]).set_color(GREEN) VGroup(*d_ratio[10:12]).set_color(MAROON_B) trig_ratio = TexMobject("\\frac{\\text{Adj.}}{\\text{Hyp.}}") VGroup(*trig_ratio[:4]).set_color(GREEN) VGroup(*trig_ratio[5:9]).set_color(MAROON_B) cos = TexMobject("= \\cos(\\theta)") cos.add_background_rectangle() group = VGroup(d_ratio, trig_ratio, cos) group.arrange() group.next_to( self.title, DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT ) for mob in group: self.play(Write(mob)) self.wait() class TryWithCos(Scene): def construct(self): words = TextMobject("What about $\\cos(\\theta)$?") words.set_color(YELLOW) self.play(Write(words)) self.wait() class NextVideo(TeacherStudentsScene): def construct(self): series = VideoSeries() next_video = series[3] series.to_edge(UP) d_sum = TexMobject("\\frac{d}{dx}(x^3 + x^2)") d_product = TexMobject("\\frac{d}{dx} \\sin(x)x^2") d_composition = TexMobject("\\frac{d}{dx} \\cos\\left(\\frac{1}{x}\\right)") group = VGroup(d_sum, d_product, d_composition) group.arrange(RIGHT, buff = 2*LARGE_BUFF) group.next_to(VGroup(*self.get_pi_creatures()), UP, buff = LARGE_BUFF) self.play( FadeIn( series, submobject_mode = "lagged_start", run_time = 3, ), *[ ApplyMethod(pi.look_at, next_video) for pi in self.get_pi_creatures() ] ) self.play( next_video.set_color, YELLOW, next_video.shift, MED_LARGE_BUFF*DOWN ) self.wait() for mob in group: self.play( Write(mob, run_time = 1), *[ ApplyMethod(pi.look_at, mob) for pi in self.get_pi_creatures() ] ) self.wait(3) class Chapter3PatreonThanks(PatreonThanks): CONFIG = { "specific_patrons" : [ "Ali Yahya", "CrypticSwarm ", "Yu Jun", "Shelby Doolittle", "Dave Nicponski", "Damion Kistler", "Juan Benet", "Othman Alikhan", "Markus Persson", "Dan Buchoff", "Derek Dai", "Joseph John Cox", "Luc Ritchie", "Guido Gambardella", "Jerry Ling", "Mark Govea", "Vecht ", "Jonathan Eppele", "Shimin Kuang", "Rish Kundalia", "Achille Brighton", "Kirk Werklund", "Ripta Pasay", "Felipe Diniz", ] } class Promotion(PiCreatureScene): CONFIG = { "seconds_to_blink" : 5, } def construct(self): url = TextMobject("https://brilliant.org/3b1b/") url.to_corner(UP+LEFT) rect = Rectangle(height = 9, width = 16) rect.set_height(5.5) rect.next_to(url, DOWN) rect.to_edge(LEFT) self.play( Write(url), self.pi_creature.change, "raise_right_hand" ) self.play(ShowCreation(rect)) self.wait(2) self.change_mode("thinking") self.wait() self.look_at(url) self.wait(10) self.change_mode("happy") self.wait(10) self.change_mode("raise_right_hand") self.wait(10) class Thumbnail(NudgeSideLengthOfCube): def construct(self): self.introduce_cube() VGroup(*self.get_mobjects()).to_edge(DOWN) formula = TexMobject( "\\frac{d(x^3)}{dx} = 3x^2" ) VGroup(*formula[:5]).set_color(YELLOW) VGroup(*formula[-3:]).set_color(GREEN_B) formula.set_width(FRAME_X_RADIUS-1) formula.to_edge(RIGHT) self.add(formula) title = TextMobject("Geometric derivatives") title.set_width(FRAME_WIDTH-1) title.to_edge(UP) self.add(title)