from manimlib.imports import * DISTANCE_COLOR = BLUE TIME_COLOR = YELLOW VELOCITY_COLOR = GREEN #### Warning, scenes here not updated based on most recent GraphScene changes ####### class IncrementNumber(Succession): CONFIG = { "start_num" : 0, "changes_per_second" : 1, "run_time" : 11, } def __init__(self, num_mob, **kwargs): digest_config(self, kwargs) n_iterations = int(self.run_time * self.changes_per_second) new_num_mobs = [ TexMobject(str(num)).move_to(num_mob, LEFT) for num in range(self.start_num, self.start_num+n_iterations) ] transforms = [ Transform( num_mob, new_num_mob, run_time = 1.0/self.changes_per_second, rate_func = squish_rate_func(smooth, 0, 0.5) ) for new_num_mob in new_num_mobs ] Succession.__init__( self, *transforms, **{ "rate_func" : None, "run_time" : self.run_time, } ) class IncrementTest(Scene): def construct(self): num = TexMobject("0") num.shift(UP) self.play(IncrementNumber(num)) self.wait() ############################ class Chapter2OpeningQuote(OpeningQuote): CONFIG = { "quote" : [ "So far as the theories of mathematics are about", "reality,", "they are not", "certain;", "so far as they are", "certain,", "they are not about", "reality.", ], "highlighted_quote_terms" : { "reality," : BLUE, "certain;" : GREEN, "certain," : GREEN, "reality." : BLUE, }, "author" : "Albert Einstein" } class Introduction(TeacherStudentsScene): def construct(self): goals = TextMobject( "Goals: ", "1) Learn derivatives", ", 2) Avoid paradoxes.", arg_separator = "" ) goals[1].set_color(MAROON_B) goals[2].set_color(RED) goals[2][0].set_color(WHITE) goals.to_edge(UP) self.add(*goals[:2]) self.student_says( "What is a derivative?", run_time = 2 ) self.play(self.get_teacher().change_mode, "happy") self.wait() self.teacher_says( "It's actually a \\\\", "very subtle idea", target_mode = "well" ) self.change_student_modes(None, "pondering", "thinking") self.play(Write(goals[2], run_time = 2)) self.change_student_modes("erm") self.student_says( "Instantaneous rate of change", "?", student_index = 0, ) self.wait() bubble = self.get_students()[0].bubble phrase = bubble.content[0] bubble.content.remove(phrase) self.play( FadeOut(bubble), FadeOut(bubble.content), FadeOut(goals), phrase.center, phrase.scale, 1.5, phrase.to_edge, UP, *it.chain(*[ [ pi.change_mode, mode, pi.look_at, FRAME_Y_RADIUS*UP ] for pi, mode in zip(self.get_pi_creatures(), [ "speaking", "pondering", "confused", "confused", ]) ]) ) self.wait() change = VGroup(*phrase[-len("change"):]) instantaneous = VGroup(*phrase[:len("instantaneous")]) change_brace = Brace(change) change_description = change_brace.get_text( "Requires multiple \\\\ points in time" ) instantaneous_brace = Brace(instantaneous) instantaneous_description = instantaneous_brace.get_text( "One point \\\\ in time" ) clock = Clock() clock.next_to(change_description, DOWN) def get_clock_anim(run_time = 3): return ClockPassesTime( clock, hours_passed = 0.4*run_time, run_time = run_time, ) self.play(FadeIn(clock)) self.play( change.set_color_by_gradient, BLUE, YELLOW, GrowFromCenter(change_brace), Write(change_description), get_clock_anim() ) self.play(get_clock_anim(1)) stopped_clock = clock.copy() stopped_clock.next_to(instantaneous_description, DOWN) self.play( instantaneous.set_color, BLUE, GrowFromCenter(instantaneous_brace), Transform(change_description.copy(), instantaneous_description), clock.copy().next_to, instantaneous_description, DOWN, get_clock_anim(3) ) self.play(get_clock_anim(12)) class FathersOfCalculus(Scene): CONFIG = { "names" : [ "Barrow", "Newton", "Leibniz", "Cauchy", "Weierstrass", ], "picture_height" : 2.5, } def construct(self): title = TextMobject("(A few) Fathers of Calculus") title.to_edge(UP) self.add(title) men = Mobject() for name in self.names: image = ImageMobject(name, invert = False) image.set_height(self.picture_height) title = TextMobject(name) title.scale(0.8) title.next_to(image, DOWN) image.add(title) men.add(image) men.arrange(RIGHT, aligned_edge = UP) men.shift(DOWN) discover_brace = Brace(Mobject(*men[:3]), UP) discover = discover_brace.get_text("Discovered it") VGroup(discover_brace, discover).set_color(BLUE) rigor_brace = Brace(Mobject(*men[3:]), UP) rigor = rigor_brace.get_text("Made it rigorous") rigor.shift(0.1*DOWN) VGroup(rigor_brace, rigor).set_color(YELLOW) for man in men: self.play(FadeIn(man)) self.play( GrowFromCenter(discover_brace), Write(discover, run_time = 1) ) self.play( GrowFromCenter(rigor_brace), Write(rigor, run_time = 1) ) self.wait() class IntroduceCar(Scene): CONFIG = { "should_transition_to_graph" : True, "show_distance" : True, "point_A" : DOWN+4*LEFT, "point_B" : DOWN+5*RIGHT, } def construct(self): point_A, point_B = self.point_A, self.point_B A = Dot(point_A) B = Dot(point_B) line = Line(point_A, point_B) VGroup(A, B, line).set_color(WHITE) for dot, tex in (A, "A"), (B, "B"): label = TexMobject(tex).next_to(dot, DOWN) dot.add(label) car = Car() self.car = car #For introduce_added_mobjects use in subclasses car.move_to(point_A) front_line = car.get_front_line() time_label = TextMobject("Time (in seconds):", "0") time_label.shift(2*UP) distance_brace = Brace(line, UP) # distance_brace.set_fill(opacity = 0.5) distance = distance_brace.get_text("100m") self.add(A, B, line, car, time_label) self.play(ShowCreation(front_line)) self.play(FadeOut(front_line)) self.introduce_added_mobjects() self.play( MoveCar(car, point_B, run_time = 10), IncrementNumber(time_label[1], run_time = 11), *self.get_added_movement_anims() ) front_line = car.get_front_line() self.play(ShowCreation(front_line)) self.play(FadeOut(front_line)) if self.show_distance: self.play( GrowFromCenter(distance_brace), Write(distance) ) self.wait() if self.should_transition_to_graph: self.play( car.move_to, point_A, FadeOut(time_label), FadeOut(distance_brace), FadeOut(distance), ) graph_scene = GraphCarTrajectory(skip_animations = True) origin = graph_scene.graph_origin top = graph_scene.coords_to_point(0, 100) new_length = get_norm(top-origin) new_point_B = point_A + new_length*RIGHT car_line_group = VGroup(car, A, B, line) for mob in car_line_group: mob.generate_target() car_line_group.target = VGroup(*[ m.target for m in car_line_group ]) B = car_line_group[2] B.target.shift(new_point_B - point_B) line.target.put_start_and_end_on( point_A, new_point_B ) car_line_group.target.rotate(np.pi/2, about_point = point_A) car_line_group.target.shift(graph_scene.graph_origin - point_A) self.play(MoveToTarget(car_line_group, path_arc = np.pi/2)) self.wait() def introduce_added_mobjects(self): pass def get_added_movement_anims(self): return [] class GraphCarTrajectory(GraphScene): CONFIG = { "x_min" : 0, "x_max" : 10, "x_labeled_nums" : list(range(1, 11)), "x_axis_label" : "Time (seconds)", "y_min" : 0, "y_max" : 110, "y_tick_frequency" : 10, "y_labeled_nums" : list(range(10, 110, 10)), "y_axis_label" : "Distance traveled \\\\ (meters)", "graph_origin" : 2.5*DOWN + 5*LEFT, "default_graph_colors" : [DISTANCE_COLOR, VELOCITY_COLOR], "default_derivative_color" : VELOCITY_COLOR, "time_of_journey" : 10, "care_movement_rate_func" : smooth, } def construct(self): self.setup_axes(animate = False) graph = self.graph_sigmoid_trajectory_function() origin = self.coords_to_point(0, 0) self.introduce_graph(graph, origin) self.comment_on_slope(graph, origin) self.show_velocity_graph() self.ask_critically_about_velocity() def graph_sigmoid_trajectory_function(self, **kwargs): graph = self.get_graph( lambda t : 100*smooth(t/10.), **kwargs ) self.s_graph = graph return graph def introduce_graph(self, graph, origin): h_line, v_line = [ Line(origin, origin, color = color, stroke_width = 2) for color in (TIME_COLOR, DISTANCE_COLOR) ] def h_update(h_line, proportion = 1): end = graph.point_from_proportion(proportion) t_axis_point = end[0]*RIGHT + origin[1]*UP h_line.put_start_and_end_on(t_axis_point, end) def v_update(v_line, proportion = 1): end = graph.point_from_proportion(proportion) d_axis_point = origin[0]*RIGHT + end[1]*UP v_line.put_start_and_end_on(d_axis_point, end) car = Car() car.rotate(np.pi/2) car.move_to(origin) car_target = origin*RIGHT + graph.point_from_proportion(1)*UP self.add(car) self.play( ShowCreation( graph, rate_func=linear, ), MoveCar( car, car_target, rate_func = self.care_movement_rate_func ), UpdateFromFunc(h_line, h_update), UpdateFromFunc(v_line, v_update), run_time = self.time_of_journey, ) self.wait() self.play(*list(map(FadeOut, [h_line, v_line, car]))) #Show example vertical distance h_update(h_line, 0.6) t_dot = Dot(h_line.get_start(), color = h_line.get_color()) t_dot.save_state() t_dot.move_to(self.x_axis_label_mob) t_dot.set_fill(opacity = 0) dashed_h = DashedLine(*h_line.get_start_and_end()) dashed_h.set_color(h_line.get_color()) brace = Brace(dashed_h, RIGHT) brace_text = brace.get_text("Distance traveled") self.play(t_dot.restore) self.wait() self.play(ShowCreation(dashed_h)) self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait(2) self.play(*list(map(FadeOut, [t_dot, dashed_h, brace, brace_text]))) #Name graph s_of_t = TexMobject("s(t)") s_of_t.next_to( graph.point_from_proportion(1), DOWN+RIGHT, buff = SMALL_BUFF ) s = s_of_t[0] d = TexMobject("d") d.move_to(s, DOWN) d.set_color(DISTANCE_COLOR) self.play(Write(s_of_t)) self.wait() s.save_state() self.play(Transform(s, d)) self.wait() self.play(s.restore) def comment_on_slope(self, graph, origin): delta_t = 1 curr_time = 0 ghost_line = Line( origin, self.coords_to_point(delta_t, self.y_max) ) rect = Rectangle().replace(ghost_line, stretch = True) rect.set_stroke(width = 0) rect.set_fill(TIME_COLOR, opacity = 0.3) change_lines = self.get_change_lines(curr_time, delta_t) self.play(FadeIn(rect)) self.wait() self.play(Write(change_lines)) self.wait() for x in range(1, 10): curr_time = x new_change_lines = self.get_change_lines(curr_time, delta_t) self.play( rect.move_to, self.coords_to_point(curr_time, 0), DOWN+LEFT, Transform(change_lines, new_change_lines) ) if curr_time == 5: text = change_lines[-1].get_text( "$\\frac{\\text{meters}}{\\text{second}}$" ) self.play(Write(text)) self.wait() self.play(FadeOut(text)) else: self.wait() self.play(*list(map(FadeOut, [rect, change_lines]))) self.rect = rect def get_change_lines(self, curr_time, delta_t = 1): p1 = self.input_to_graph_point( curr_time, self.s_graph ) p2 = self.input_to_graph_point( curr_time+delta_t, self.s_graph ) interim_point = p2[0]*RIGHT + p1[1]*UP delta_t_line = Line(p1, interim_point, color = TIME_COLOR) delta_s_line = Line(interim_point, p2, color = DISTANCE_COLOR) brace = Brace(delta_s_line, RIGHT, buff = SMALL_BUFF) return VGroup(delta_t_line, delta_s_line, brace) def show_velocity_graph(self): velocity_graph = self.get_derivative_graph(self.s_graph) self.play(ShowCreation(velocity_graph)) def get_velocity_label(v_graph): result = self.get_graph_label( v_graph, label = "v(t)", direction = UP+RIGHT, x_val = 5, buff = SMALL_BUFF, ) self.remove(result) return result label = get_velocity_label(velocity_graph) self.play(Write(label)) self.wait() self.rect.move_to(self.coords_to_point(0, 0), DOWN+LEFT) self.play(FadeIn(self.rect)) self.wait() for time, show_slope in (4.5, True), (9, False): self.play( self.rect.move_to, self.coords_to_point(time, 0), DOWN+LEFT ) if show_slope: change_lines = self.get_change_lines(time) self.play(FadeIn(change_lines)) self.wait() self.play(FadeOut(change_lines)) else: self.wait() self.play(FadeOut(self.rect)) #Change distance and velocity graphs self.s_graph.save_state() velocity_graph.save_state() label.save_state() def shallow_slope(t): return 100*smooth(t/10., inflection = 4) def steep_slope(t): return 100*smooth(t/10., inflection = 25) def double_smooth_graph_function(t): if t < 5: return 50*smooth(t/5.) else: return 50*(1+smooth((t-5)/5.)) graph_funcs = [ shallow_slope, steep_slope, double_smooth_graph_function, ] for graph_func in graph_funcs: new_graph = self.get_graph( graph_func, color = DISTANCE_COLOR, ) self.remove(new_graph) new_velocity_graph = self.get_derivative_graph( graph = new_graph, ) new_velocity_label = get_velocity_label(new_velocity_graph) self.play(Transform(self.s_graph, new_graph)) self.play( Transform(velocity_graph, new_velocity_graph), Transform(label, new_velocity_label), ) self.wait(2) self.play(self.s_graph.restore) self.play( velocity_graph.restore, label.restore, ) self.wait(2) def ask_critically_about_velocity(self): morty = Mortimer().flip() morty.to_corner(DOWN+LEFT) self.play(PiCreatureSays(morty, "Think critically about \\\\", "what velocity means." )) self.play(Blink(morty)) self.wait() class ShowSpeedometer(IntroduceCar): CONFIG = { "num_ticks" : 8, "tick_length" : 0.2, "needle_width" : 0.1, "needle_height" : 0.8, "should_transition_to_graph" : False, "show_distance" : False, "speedometer_title_text" : "Speedometer", } def setup(self): start_angle = -np.pi/6 end_angle = 7*np.pi/6 speedometer = Arc( start_angle = start_angle, angle = end_angle-start_angle ) tick_angle_range = np.linspace(end_angle, start_angle, self.num_ticks) for index, angle in enumerate(tick_angle_range): vect = rotate_vector(RIGHT, angle) tick = Line((1-self.tick_length)*vect, vect) label = TexMobject(str(10*index)) label.set_height(self.tick_length) label.shift((1+self.tick_length)*vect) speedometer.add(tick, label) needle = Polygon( LEFT, UP, RIGHT, stroke_width = 0, fill_opacity = 1, fill_color = YELLOW ) needle.stretch_to_fit_width(self.needle_width) needle.stretch_to_fit_height(self.needle_height) needle.rotate(end_angle-np.pi/2) speedometer.add(needle) speedometer.needle = needle speedometer.center_offset = speedometer.get_center() speedometer_title = TextMobject(self.speedometer_title_text) speedometer_title.to_corner(UP+LEFT) speedometer.next_to(speedometer_title, DOWN) self.speedometer = speedometer self.speedometer_title = speedometer_title def introduce_added_mobjects(self): speedometer = self.speedometer speedometer_title = self.speedometer_title speedometer.save_state() speedometer.rotate(-np.pi/2, UP) speedometer.set_height(self.car.get_height()/4) speedometer.move_to(self.car) speedometer.shift((self.car.get_width()/4)*RIGHT) self.play(speedometer.restore, run_time = 2) self.play(Write(speedometer_title, run_time = 1)) def get_added_movement_anims(self, **kwargs): needle = self.speedometer.needle center = self.speedometer.get_center() - self.speedometer.center_offset default_kwargs = { "about_point" : center, "radians" : -np.pi/2, "run_time" : 10, "rate_func" : there_and_back, } default_kwargs.update(kwargs) return [Rotating(needle, **default_kwargs)] # def construct(self): # self.add(self.speedometer) # self.play(*self.get_added_movement_anims()) class VelocityInAMomentMakesNoSense(Scene): def construct(self): randy = Randolph() randy.next_to(ORIGIN, DOWN+LEFT) words = TextMobject("Velocity in \\\\ a moment") words.next_to(randy, UP+RIGHT) randy.look_at(words) q_marks = TextMobject("???") q_marks.next_to(randy, UP) self.play( randy.change_mode, "confused", Write(words) ) self.play(Blink(randy)) self.play(Write(q_marks)) self.play(Blink(randy)) self.wait() class SnapshotOfACar(Scene): def construct(self): car = Car() car.scale(1.5) car.move_to(3*LEFT+DOWN) flash_box = Rectangle( width = FRAME_WIDTH, height = FRAME_HEIGHT, stroke_width = 0, fill_color = WHITE, fill_opacity = 1, ) speed_lines = VGroup(*[ Line(point, point+0.5*LEFT) for point in [ 0.5*UP+0.25*RIGHT, ORIGIN, 0.5*DOWN+0.25*RIGHT ] ]) question = TextMobject(""" How fast is this car going? """) self.play(MoveCar( car, RIGHT+DOWN, run_time = 2, rate_func = rush_into )) car.get_tires().set_color(GREY) speed_lines.next_to(car, LEFT) self.add(speed_lines) self.play( flash_box.set_fill, None, 0, rate_func = rush_from ) question.next_to(car, UP, buff = LARGE_BUFF) self.play(Write(question, run_time = 2)) self.wait(2) class CompareTwoTimes(Scene): CONFIG = { "start_distance" : 30, "start_time" : 4, "end_distance" : 50, "end_time" : 5, "fade_at_the_end" : True, } def construct(self): self.introduce_states() self.show_equation() if self.fade_at_the_end: self.fade_all_but_one_moment() def introduce_states(self): state1 = self.get_car_state(self.start_distance, self.start_time) state2 = self.get_car_state(self.end_distance, self.end_time) state1.to_corner(UP+LEFT) state2.to_corner(DOWN+LEFT) dividers = VGroup( Line(FRAME_X_RADIUS*LEFT, RIGHT), Line(RIGHT+FRAME_Y_RADIUS*UP, RIGHT+FRAME_Y_RADIUS*DOWN), ) dividers.set_color(GREY) self.add(dividers, state1) self.wait() copied_state = state1.copy() self.play(copied_state.move_to, state2) self.play(Transform(copied_state, state2)) self.wait(2) self.keeper = state1 def show_equation(self): velocity = TextMobject("Velocity") change_over_change = TexMobject( "\\frac{\\text{Change in distance}}{\\text{Change in time}}" ) formula = TexMobject( "\\frac{(%s - %s) \\text{ meters}}{(%s - %s) \\text{ seconds}}"%( str(self.end_distance), str(self.start_distance), str(self.end_time), str(self.start_time), ) ) ed_len = len(str(self.end_distance)) sd_len = len(str(self.start_distance)) et_len = len(str(self.end_time)) st_len = len(str(self.start_time)) seconds_len = len("seconds") VGroup( VGroup(*formula[1:1+ed_len]), VGroup(*formula[2+ed_len:2+ed_len+sd_len]) ).set_color(DISTANCE_COLOR) VGroup( VGroup(*formula[-2-seconds_len-et_len-st_len:-2-seconds_len-st_len]), VGroup(*formula[-1-seconds_len-st_len:-1-seconds_len]), ).set_color(TIME_COLOR) down_arrow1 = TexMobject("\\Downarrow") down_arrow2 = TexMobject("\\Downarrow") group = VGroup( velocity, down_arrow1, change_over_change, down_arrow2, formula, ) group.arrange(DOWN) group.to_corner(UP+RIGHT) self.play(FadeIn( group, lag_ratio = 0.5, run_time = 3 )) self.wait(3) self.formula = formula def fade_all_but_one_moment(self): anims = [ ApplyMethod(mob.fade, 0.5) for mob in self.get_mobjects() ] anims.append(Animation(self.keeper.copy())) self.play(*anims) self.wait() def get_car_state(self, distance, time): line = Line(3*LEFT, 3*RIGHT) dots = list(map(Dot, line.get_start_and_end())) line.add(*dots) car = Car() car.move_to(line.get_start()) car.shift((distance/10)*RIGHT) front_line = car.get_front_line() brace = Brace(VGroup(dots[0], front_line), DOWN) distance_label = brace.get_text( str(distance), " meters" ) distance_label.set_color_by_tex(str(distance), DISTANCE_COLOR) brace.add(distance_label) time_label = TextMobject( "Time:", str(time), "seconds" ) time_label.set_color_by_tex(str(time), TIME_COLOR) time_label.next_to( VGroup(line, car), UP, aligned_edge = LEFT ) return VGroup(line, car, front_line, brace, time_label) class VelocityAtIndividualPointsVsPairs(GraphCarTrajectory): CONFIG = { "start_time" : 6.5, "end_time" : 3, "dt" : 1.0, } def construct(self): self.setup_axes(animate = False) distance_graph = self.graph_function(lambda t : 100*smooth(t/10.)) distance_label = self.label_graph( distance_graph, label = "s(t)", proportion = 1, direction = RIGHT, buff = SMALL_BUFF ) velocity_graph = self.get_derivative_graph() self.play(ShowCreation(velocity_graph)) velocity_label = self.label_graph( velocity_graph, label = "v(t)", proportion = self.start_time/10.0, direction = UP, buff = MED_SMALL_BUFF ) velocity_graph.add(velocity_label) self.show_individual_times_to_velocity(velocity_graph) self.play(velocity_graph.fade, 0.4) self.show_two_times_on_distance() self.show_confused_pi_creature() def show_individual_times_to_velocity(self, velocity_graph): start_time = self.start_time end_time = self.end_time line = self.get_vertical_line_to_graph(start_time, velocity_graph) def line_update(line, alpha): time = interpolate(start_time, end_time, alpha) line.put_start_and_end_on( self.coords_to_point(time, 0), self.input_to_graph_point(time, graph = velocity_graph) ) self.play(ShowCreation(line)) self.wait() self.play(UpdateFromAlphaFunc( line, line_update, run_time = 4, rate_func = there_and_back )) self.wait() velocity_graph.add(line) def show_two_times_on_distance(self): line1 = self.get_vertical_line_to_graph(self.start_time-self.dt/2.0) line2 = self.get_vertical_line_to_graph(self.start_time+self.dt/2.0) p1 = line1.get_end() p2 = line2.get_end() interim_point = p2[0]*RIGHT+p1[1]*UP dt_line = Line(p1, interim_point, color = TIME_COLOR) ds_line = Line(interim_point, p2, color = DISTANCE_COLOR) dt_brace = Brace(dt_line, DOWN, buff = SMALL_BUFF) ds_brace = Brace(ds_line, RIGHT, buff = SMALL_BUFF) dt_text = dt_brace.get_text("Change in time", buff = SMALL_BUFF) ds_text = ds_brace.get_text("Change in distance", buff = SMALL_BUFF) self.play(ShowCreation(VGroup(line1, line2))) for line, brace, text in (dt_line, dt_brace, dt_text), (ds_line, ds_brace, ds_text): brace.set_color(line.get_color()) text.set_color(line.get_color()) text.add_background_rectangle() self.play( ShowCreation(line), GrowFromCenter(brace), Write(text) ) self.wait() def show_confused_pi_creature(self): randy = Randolph() randy.to_corner(DOWN+LEFT) randy.shift(2*RIGHT) self.play(randy.change_mode, "confused") self.play(Blink(randy)) self.wait(2) self.play(Blink(randy)) self.play(randy.change_mode, "erm") self.wait() self.play(Blink(randy)) self.wait(2) class FirstRealWorld(TeacherStudentsScene): def construct(self): self.teacher_says("First, the real world.") self.change_student_modes( "happy", "hooray", "happy" ) self.wait(3) class SidestepParadox(Scene): def construct(self): car = Car() car.shift(DOWN) show_speedometer = ShowSpeedometer(skip_animations = True) speedometer = show_speedometer.speedometer speedometer.next_to(car, UP) title = TextMobject( "Instantaneous", "rate of change" ) title.to_edge(UP) cross = TexMobject("\\times") cross.replace(title[0], stretch = True) cross.set_fill(RED, opacity = 0.8) new_words = TextMobject("over a small time") new_words.next_to(title[1], DOWN) new_words.set_color(TIME_COLOR) self.add(title, car) self.play(Write(speedometer)) self.wait() self.play(Write(cross)) self.wait() self.play(Write(new_words)) self.wait() class CompareTwoVerySimilarTimes(CompareTwoTimes): CONFIG = { "start_distance" : 20, "start_time" : 3, "end_distance" : 20.21, "end_time" : 3.01, "fade_at_the_end" : False, } def construct(self): CompareTwoTimes.construct(self) formula = self.formula ds_symbols, dt_symbols = [ VGroup(*[ mob for mob in formula if mob.get_color() == Color(color) ]) for color in (DISTANCE_COLOR, TIME_COLOR) ] ds_brace = Brace(ds_symbols, UP) ds_text = ds_brace.get_text("$ds$", buff = SMALL_BUFF) ds_text.set_color(DISTANCE_COLOR) dt_brace = Brace(dt_symbols, DOWN) dt_text = dt_brace.get_text("$dt$", buff = SMALL_BUFF) dt_text.set_color(TIME_COLOR) self.play( GrowFromCenter(dt_brace), Write(dt_text) ) formula.add(dt_brace, dt_text) self.wait(2) formula.generate_target() VGroup( ds_brace, ds_text, formula.target ).move_to(formula, UP).shift(0.5*UP) self.play( MoveToTarget(formula), GrowFromCenter(ds_brace), Write(ds_text) ) self.wait(2) class DsOverDtGraphically(GraphCarTrajectory, ZoomedScene): CONFIG = { "dt" : 0.1, "zoom_factor" : 4,#Before being shrunk by dt "start_time" : 3, "end_time" : 7, } def construct(self): self.setup_axes(animate = False) distance_graph = self.graph_function( lambda t : 100*smooth(t/10.), animate = False, ) distance_label = self.label_graph( distance_graph, label = "s(t)", proportion = 0.9, direction = UP+LEFT, buff = SMALL_BUFF ) input_point_line = self.get_vertical_line_to_graph( self.start_time, line_kwargs = { "dash_length" : 0.02, "stroke_width" : 4, "color" : WHITE, }, ) def get_ds_dt_group(time): point1 = self.input_to_graph_point(time) point2 = self.input_to_graph_point(time+self.dt) interim_point = point2[0]*RIGHT+point1[1]*UP dt_line = Line(point1, interim_point, color = TIME_COLOR) ds_line = Line(interim_point, point2, color = DISTANCE_COLOR) result = VGroup() for line, char, vect in (dt_line, "t", DOWN), (ds_line, "s", RIGHT): line.scale(1./self.dt) brace = Brace(line, vect) text = brace.get_text("$d%s$"%char) text.next_to(brace, vect) text.set_color(line.get_color()) subgroup = VGroup(line, brace, text) subgroup.scale(self.dt) result.add(subgroup) return result def align_little_rectangle_on_ds_dt_group(rect): rect.move_to(ds_dt_group, DOWN+RIGHT) rect.shift(self.dt*(DOWN+RIGHT)/4) return rect ds_dt_group = get_ds_dt_group(self.start_time) #Initially zoom in self.play(ShowCreation(input_point_line)) self.activate_zooming() self.play(*list(map(FadeIn, [self.big_rectangle, self.little_rectangle]))) self.play( ApplyFunction( align_little_rectangle_on_ds_dt_group, self.little_rectangle ) ) self.little_rectangle.generate_target() self.little_rectangle.target.scale(self.zoom_factor*self.dt) align_little_rectangle_on_ds_dt_group( self.little_rectangle.target ) self.play( MoveToTarget(self.little_rectangle), run_time = 3 ) for subgroup in ds_dt_group: line, brace, text= subgroup self.play(ShowCreation(line)) self.play( GrowFromCenter(brace), Write(text) ) self.wait() #Show as function frac = TexMobject("\\frac{ds}{dt}") VGroup(*frac[:2]).set_color(DISTANCE_COLOR) VGroup(*frac[-2:]).set_color(TIME_COLOR) frac.next_to(self.input_to_graph_point(5.25), DOWN+RIGHT) rise_over_run = TexMobject( "=\\frac{\\text{rise}}{\\text{run}}" ) rise_over_run.next_to(frac, RIGHT) of_t = TexMobject("(t)") of_t.next_to(frac, RIGHT, buff = SMALL_BUFF) dt_choice = TexMobject("dt = 0.01") dt_choice.set_color(TIME_COLOR) dt_choice.next_to(of_t, UP, aligned_edge = LEFT, buff = LARGE_BUFF) full_formula = TexMobject( "=\\frac{s(t+dt) - s(t)}{dt}" ) full_formula.next_to(of_t) s_t_plus_dt = VGroup(*full_formula[1:8]) s_t = VGroup(*full_formula[9:13]) numerator = VGroup(*full_formula[1:13]) lower_dt = VGroup(*full_formula[-2:]) upper_dt = VGroup(*full_formula[5:7]) equals = full_formula[0] frac_line = full_formula[-3] s_t_plus_dt.set_color(DISTANCE_COLOR) s_t.set_color(DISTANCE_COLOR) lower_dt.set_color(TIME_COLOR) upper_dt.set_color(TIME_COLOR) velocity_graph = self.get_derivative_graph() t_tick_marks = VGroup(*[ Line( UP, DOWN, color = TIME_COLOR, stroke_width = 3, ).scale(0.1).move_to(self.coords_to_point(t, 0)) for t in np.linspace(0, 10, 75) ]) v_line_at_t, v_line_at_t_plus_dt = [ self.get_vertical_line_to_graph( time, line_class = Line, line_kwargs = {"color" : MAROON_B} ) for time in (self.end_time, self.end_time + self.dt) ] self.play(Write(frac)) self.play(Write(rise_over_run)) self.wait() def input_point_line_update(line, alpha): time = interpolate(self.start_time, self.end_time, alpha) line.put_start_and_end_on( self.coords_to_point(time, 0), self.input_to_graph_point(time), ) def ds_dt_group_update(group, alpha): time = interpolate(self.start_time, self.end_time, alpha) new_group = get_ds_dt_group(time) Transform(group, new_group).update(1) self.play( UpdateFromAlphaFunc(input_point_line, input_point_line_update), UpdateFromAlphaFunc(ds_dt_group, ds_dt_group_update), UpdateFromFunc(self.little_rectangle, align_little_rectangle_on_ds_dt_group), run_time = 6, ) self.play(FadeOut(input_point_line)) self.wait() self.play(FadeOut(rise_over_run)) self.play(Write(of_t)) self.wait(2) self.play(ShowCreation(velocity_graph)) velocity_label = self.label_graph( velocity_graph, label = "v(t)", proportion = 0.6, direction = DOWN+LEFT, buff = SMALL_BUFF ) self.wait(2) self.play(Write(dt_choice)) self.wait() for anim_class in FadeIn, FadeOut: self.play(anim_class( t_tick_marks, lag_ratio = 0.5, run_time = 2 )) self.play( Write(equals), Write(numerator) ) self.wait() self.play(ShowCreation(v_line_at_t)) self.wait() self.play(ShowCreation(v_line_at_t_plus_dt)) self.wait() self.play(*list(map(FadeOut, [v_line_at_t, v_line_at_t_plus_dt]))) self.play( Write(frac_line), Write(lower_dt) ) self.wait(2) #Show different curves self.disactivate_zooming() self.remove(ds_dt_group) self.graph.save_state() velocity_graph.save_state() velocity_label.save_state() def steep_slope(t): return 100*smooth(t/10., inflection = 25) def sin_wiggle(t): return (10/(2*np.pi/10.))*(np.sin(2*np.pi*t/10.) + 2*np.pi*t/10.) def double_smooth_graph_function(t): if t < 5: return 50*smooth(t/5.) else: return 50*(1+smooth((t-5)/5.)) graph_funcs = [ steep_slope, sin_wiggle, double_smooth_graph_function, ] for graph_func in graph_funcs: new_graph = self.graph_function( graph_func, color = DISTANCE_COLOR, is_main_graph = False ) self.remove(new_graph) new_velocity_graph = self.get_derivative_graph( graph = new_graph, ) self.play(Transform(self.graph, new_graph)) self.play(Transform(velocity_graph, new_velocity_graph)) self.wait(2) self.play(self.graph.restore) self.play( velocity_graph.restore, velocity_label.restore, ) #Pause and reflect randy = Randolph() randy.to_corner(DOWN+LEFT).shift(2*RIGHT) randy.look_at(frac_line) self.play(FadeIn(randy)) self.play(randy.change_mode, "pondering") self.wait() self.play(Blink(randy)) self.play(randy.change_mode, "thinking") self.wait() self.play(Blink(randy)) self.wait() class DefineTrueDerivative(Scene): def construct(self): title = TextMobject("The true derivative") title.to_edge(UP) lhs = TexMobject("\\frac{ds}{dt}(t) = ") VGroup(*lhs[:2]).set_color(DISTANCE_COLOR) VGroup(*lhs[3:5]).set_color(TIME_COLOR) lhs.shift(3*LEFT+UP) dt_rhs = self.get_fraction("dt") numerical_rhs_list = [ self.get_fraction("0.%s1"%("0"*x)) for x in range(7) ] for rhs in [dt_rhs] + numerical_rhs_list: rhs.next_to(lhs, RIGHT) brace, dt_to_zero = self.get_brace_and_text(dt_rhs) self.add(lhs, dt_rhs) self.play(Write(title)) self.wait() dt_rhs.save_state() for num_rhs in numerical_rhs_list: self.play(Transform(dt_rhs, num_rhs)) self.wait() self.play(dt_rhs.restore) self.play( GrowFromCenter(brace), Write(dt_to_zero) ) self.wait() def get_fraction(self, dt_string): tex_mob = TexMobject( "\\frac{s(t + %s) - s(t)}{%s}"%(dt_string, dt_string) ) part_lengths = [ 0, len("s(t+"), 1,#1 and -1 below are purely for transformation quirks len(dt_string)-1, len(")-s(t)_"),#Underscore represents frac_line 1, len(dt_string)-1, ] pl_cumsum = np.cumsum(part_lengths) result = VGroup(*[ VGroup(*tex_mob[i1:i2]) for i1, i2 in zip(pl_cumsum, pl_cumsum[1:]) ]) VGroup(*result[1:3]+result[4:6]).set_color(TIME_COLOR) return result def get_brace_and_text(self, deriv_frac): brace = Brace(VGroup(deriv_frac), DOWN) dt_to_zero = brace.get_text("$dt \\to 0$") VGroup(*dt_to_zero[:2]).set_color(TIME_COLOR) return brace, dt_to_zero class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative): CONFIG = { "start_time" : 6, "end_time" : 2, "alt_end_time" : 10, "start_dt" : 2, "end_dt" : 0.01, "secant_line_length" : 10, } def construct(self): self.setup_axes(animate = False) self.remove(self.y_axis_label_mob, self.x_axis_label_mob) self.add_derivative_definition(self.y_axis_label_mob) self.add_graph() self.draw_axes() self.show_tangent_line() self.best_constant_approximation_around_a_point() def get_ds_dt_group(self, dt, animate = False): points = [ self.input_to_graph_point(time, self.graph) for time in (self.curr_time, self.curr_time+dt) ] dots = list(map(Dot, points)) for dot in dots: dot.scale_in_place(0.5) secant_line = Line(*points) secant_line.set_color(VELOCITY_COLOR) secant_line.scale_in_place( self.secant_line_length/secant_line.get_length() ) interim_point = points[1][0]*RIGHT + points[0][1]*UP dt_line = Line(points[0], interim_point, color = TIME_COLOR) ds_line = Line(interim_point, points[1], color = DISTANCE_COLOR) dt = TexMobject("dt") dt.set_color(TIME_COLOR) if dt.get_width() > dt_line.get_width(): dt.scale( dt_line.get_width()/dt.get_width(), about_point = dt.get_top() ) dt.next_to(dt_line, DOWN, buff = SMALL_BUFF) ds = TexMobject("ds") ds.set_color(DISTANCE_COLOR) if ds.get_height() > ds_line.get_height(): ds.scale( ds_line.get_height()/ds.get_height(), about_point = ds.get_left() ) ds.next_to(ds_line, RIGHT, buff = SMALL_BUFF) group = VGroup( secant_line, ds_line, dt_line, ds, dt, *dots ) if animate: self.play( ShowCreation(dt_line), Write(dt), ShowCreation(dots[0]), ) self.play( ShowCreation(ds_line), Write(ds), ShowCreation(dots[1]), ) self.play( ShowCreation(secant_line), Animation(VGroup(*dots)) ) return group def add_graph(self): def double_smooth_graph_function(t): if t < 5: return 50*smooth(t/5.) else: return 50*(1+smooth((t-5)/5.)) self.graph = self.get_graph(double_smooth_graph_function) self.graph_label = self.get_graph_label( self.graph, "s(t)", x_val = self.x_max, direction = DOWN+RIGHT, buff = SMALL_BUFF, ) def add_derivative_definition(self, target_upper_left): deriv_frac = self.get_fraction("dt") lhs = TexMobject("\\frac{ds}{dt}(t)=") VGroup(*lhs[:2]).set_color(DISTANCE_COLOR) VGroup(*lhs[3:5]).set_color(TIME_COLOR) lhs.next_to(deriv_frac, LEFT) brace, text = self.get_brace_and_text(deriv_frac) deriv_def = VGroup(lhs, deriv_frac, brace, text) deriv_word = TextMobject("Derivative") deriv_word.next_to(deriv_def, UP, buff = MED_LARGE_BUFF) deriv_def.add(deriv_word) rect = Rectangle(color = WHITE) rect.replace(deriv_def, stretch = True) rect.scale_in_place(1.2) deriv_def.add(rect) deriv_def.scale(0.7) deriv_def.move_to(target_upper_left, UP+LEFT) self.add(deriv_def) return deriv_def def draw_axes(self): self.x_axis.remove(self.x_axis_label_mob) self.y_axis.remove(self.y_axis_label_mob) self.play(Write( VGroup( self.x_axis, self.y_axis, self.graph, self.graph_label ), run_time = 4 )) self.wait() def show_tangent_line(self): self.curr_time = self.start_time ds_dt_group = self.get_ds_dt_group(2, animate = True) self.wait() def update_ds_dt_group(ds_dt_group, alpha): new_dt = interpolate(self.start_dt, self.end_dt, alpha) new_group = self.get_ds_dt_group(new_dt) Transform(ds_dt_group, new_group).update(1) self.play( UpdateFromAlphaFunc(ds_dt_group, update_ds_dt_group), run_time = 15 ) self.wait() def update_as_tangent_line(ds_dt_group, alpha): self.curr_time = interpolate(self.start_time, self.end_time, alpha) new_group = self.get_ds_dt_group(self.end_dt) Transform(ds_dt_group, new_group).update(1) self.play( UpdateFromAlphaFunc(ds_dt_group, update_as_tangent_line), run_time = 8, rate_func = there_and_back ) self.wait() what_dt_is_not_text = self.what_this_is_not_saying() self.wait() self.play( UpdateFromAlphaFunc(ds_dt_group, update_ds_dt_group), run_time = 8, rate_func = lambda t : 1-there_and_back(t) ) self.wait() self.play(FadeOut(what_dt_is_not_text)) v_line = self.get_vertical_line_to_graph( self.curr_time, self.graph, line_class = Line, line_kwargs = { "color" : MAROON_B, "stroke_width" : 3 } ) def v_line_update(v_line): v_line.put_start_and_end_on( self.coords_to_point(self.curr_time, 0), self.input_to_graph_point(self.curr_time, self.graph), ) return v_line self.play(ShowCreation(v_line)) self.wait() original_end_time = self.end_time for end_time in self.alt_end_time, original_end_time, self.start_time: self.end_time = end_time self.play( UpdateFromAlphaFunc(ds_dt_group, update_as_tangent_line), UpdateFromFunc(v_line, v_line_update), run_time = abs(self.curr_time-self.end_time), ) self.start_time = end_time self.play(FadeOut(v_line)) def what_this_is_not_saying(self): phrases = [ TextMobject( "$dt$", "is", "not", s ) for s in ("``infinitely small''", "0") ] for phrase in phrases: phrase[0].set_color(TIME_COLOR) phrase[2].set_color(RED) phrases[0].shift(DOWN+2*RIGHT) phrases[1].next_to(phrases[0], DOWN, aligned_edge = LEFT) for phrase in phrases: self.play(Write(phrase)) return VGroup(*phrases) def best_constant_approximation_around_a_point(self): words = TextMobject(""" Best constant approximation around a point """) words.next_to(self.x_axis, UP, aligned_edge = RIGHT) circle = Circle( radius = 0.25, color = WHITE ).shift(self.input_to_graph_point(self.curr_time)) self.play(Write(words)) self.play(ShowCreation(circle)) self.wait() class UseOfDImpliesApproaching(TeacherStudentsScene): def construct(self): statement = TextMobject(""" Using ``$d$'' announces that $dt \\to 0$ """) VGroup(*statement[-4:-2]).set_color(TIME_COLOR) self.teacher_says(statement) self.change_student_modes(*["pondering"]*3) self.wait(4) class LeadIntoASpecificExample(TeacherStudentsScene, SecantLineToTangentLine): def setup(self): TeacherStudentsScene.setup(self) def construct(self): dot = Dot() #Just to coordinate derivative definition dot.to_corner(UP+LEFT, buff = SMALL_BUFF) deriv_def = self.add_derivative_definition(dot) self.remove(deriv_def) self.teacher_says("An example \\\\ should help.") self.wait() self.play( Write(deriv_def), *it.chain(*[ [pi.change_mode, "thinking", pi.look_at, dot] for pi in self.get_students() ]) ) self.random_blink(3) # self.teacher_says( # """ # The idea of # ``approaching'' # actually makes # things easier # """, # height = 3, # target_mode = "hooray" # ) # self.wait(2) class TCubedExample(SecantLineToTangentLine): CONFIG = { "y_axis_label" : "Distance", "y_min" : 0, "y_max" : 16, "y_tick_frequency" : 1, "y_labeled_nums" : list(range(0, 17, 2)), "x_min" : 0, "x_max" : 4, "x_labeled_nums" : list(range(1, 5)), "graph_origin" : 2.5*DOWN + 6*LEFT, "start_time" : 2, "end_time" : 0.5, "start_dt" : 0.25, "end_dt" : 0.001, "secant_line_length" : 0.01, } def construct(self): self.draw_graph() self.show_vertical_lines() self.bear_with_me() self.add_ds_dt_group() self.brace_for_details() self.show_expansion() self.react_to_simplicity() def draw_graph(self): self.setup_axes(animate = False) self.x_axis_label_mob.shift(0.5*DOWN) # self.y_axis_label_mob.next_to(self.y_axis, UP) graph = self.graph_function(lambda t : t**3, animate = True) self.label_graph( graph, label = "s(t) = t^3", proportion = 0.62, direction = LEFT, buff = SMALL_BUFF ) self.wait() def show_vertical_lines(self): for t in 1, 2: v_line = self.get_vertical_line_to_graph( t, line_kwargs = {"color" : WHITE} ) brace = Brace(v_line, RIGHT) text = TexMobject("%d^3 = %d"%(t, t**3)) text.next_to(brace, RIGHT) text.shift(0.2*UP) group = VGroup(v_line, brace, text) if t == 1: self.play(ShowCreation(v_line)) self.play( GrowFromCenter(brace), Write(text) ) last_group = group else: self.play(Transform(last_group, group)) self.wait() self.play(FadeOut(last_group)) def bear_with_me(self): morty = Mortimer() morty.to_corner(DOWN+RIGHT) self.play(FadeIn(morty)) self.play(PiCreatureSays( morty, "Bear with \\\\ me here", target_mode = "sassy" )) self.play(Blink(morty)) self.wait() self.play(*list(map( FadeOut, [morty, morty.bubble, morty.bubble.content] ))) def add_ds_dt_group(self): self.curr_time = self.start_time self.curr_dt = self.start_dt ds_dt_group = self.get_ds_dt_group(dt = self.start_dt) v_lines = self.get_vertical_lines() lhs = TexMobject("\\frac{ds}{dt}(2) = ") lhs.next_to(ds_dt_group, UP+RIGHT, buff = MED_LARGE_BUFF) ds = VGroup(*lhs[:2]) dt = VGroup(*lhs[3:5]) ds.set_color(DISTANCE_COLOR) dt.set_color(TIME_COLOR) ds.target, dt.target = ds_dt_group[3:5] for mob in ds, dt: mob.save_state() mob.move_to(mob.target) nonzero_size = TextMobject("Nonzero size...for now") nonzero_size.set_color(TIME_COLOR) nonzero_size.next_to(dt, DOWN+2*RIGHT, buff = LARGE_BUFF) arrow = Arrow(nonzero_size, dt) rhs = TexMobject( "\\frac{s(2+dt) - s(2)}{dt}" ) rhs.next_to(lhs[-1]) VGroup(*rhs[4:6]).set_color(TIME_COLOR) VGroup(*rhs[-2:]).set_color(TIME_COLOR) numerator = VGroup(*rhs[:-3]) non_numerator = VGroup(*rhs[-3:]) numerator_non_minus = VGroup(*numerator) numerator_non_minus.remove(rhs[7]) s_pair = rhs[0], rhs[8] lp_pair = rhs[6], rhs[11] for s, lp in zip(s_pair, lp_pair): s.target = TexMobject("3").scale(0.7) s.target.move_to(lp.get_corner(UP+RIGHT), LEFT) self.play(Write(ds_dt_group, run_time = 2)) self.play( FadeIn(lhs), *[mob.restore for mob in (ds, dt)] ) self.play(ShowCreation(v_lines[0])) self.wait() self.play( ShowCreation(arrow), Write(nonzero_size), ) self.wait(2) self.play(*list(map(FadeOut, [arrow, nonzero_size]))) self.play(Write(numerator)) self.play(ShowCreation(v_lines[1])) self.wait() self.play( v_lines[0].set_color, YELLOW, rate_func = there_and_back ) self.wait() self.play(Write(non_numerator)) self.wait(2) self.play( *list(map(MoveToTarget, s_pair)), **{ "path_arc" : -np.pi/2 } ) self.play(numerator_non_minus.shift, 0.2*LEFT) self.wait() self.vertical_lines = v_lines self.ds_dt_group = ds_dt_group self.lhs = lhs self.rhs = rhs def get_vertical_lines(self): return VGroup(*[ self.get_vertical_line_to_graph( time, line_class = DashedLine, line_kwargs = { "color" : WHITE, "dash_length" : 0.05, } ) for time in (self.start_time, self.start_time+self.start_dt) ]) def brace_for_details(self): morty = Mortimer() morty.next_to(self.rhs, DOWN, buff = LARGE_BUFF) self.play(FadeIn(morty)) self.play( morty.change_mode, "hooray", morty.look_at, self.rhs ) self.play(Blink(morty)) self.wait() self.play( morty.change_mode, "sassy", morty.look, OUT ) self.play(Blink(morty)) self.play(morty.change_mode, "pondering") self.wait() self.play(FadeOut(morty)) def show_expansion(self): expression = TexMobject(""" \\frac{ 2^3 + 3 (2)^2 dt + 3 (2)(dt)^2 + (dt)^3 - 2^3 }{dt} """) expression.set_width( VGroup(self.lhs, self.rhs).get_width() ) expression.next_to( self.lhs, DOWN, aligned_edge = LEFT, buff = LARGE_BUFF ) term_lens = [ len("23+"), len("3(2)2dt"), len("+3(2)(dt)2+"), len("(dt)3"), len("-23"), len("_"),#frac bar len("dt"), ] terms = [ VGroup(*expression[i1:i2]) for i1, i2 in zip( [0]+list(np.cumsum(term_lens)), np.cumsum(term_lens) ) ] dts = [ VGroup(*terms[1][-2:]), VGroup(*terms[2][6:8]), VGroup(*terms[3][1:3]), terms[-1] ] VGroup(*dts).set_color(TIME_COLOR) two_cubed_terms = terms[0], terms[4] for term in terms: self.play(FadeIn(term)) self.wait() #Cancel out two_cubed terms self.play(*it.chain(*[ [ tc.scale, 1.3, tc.get_corner(vect), tc.set_color, RED ] for tc, vect in zip( two_cubed_terms, [DOWN+RIGHT, DOWN+LEFT] ) ])) self.play(*list(map(FadeOut, two_cubed_terms))) numerator = VGroup(*terms[1:4]) self.play( numerator.scale, 1.4, numerator.get_bottom(), terms[-1].scale, 1.4, terms[-1].get_top() ) self.wait(2) #Cancel out dt #This is all way too hacky... faders = VGroup( terms[-1], VGroup(*terms[1][-2:]), #"3(2)^2 dt" terms[2][-2], # "+3(2)(dt)2+" terms[3][-1], # "(dt)3" ) new_exp = TexMobject("2").replace(faders[-1], dim_to_match = 1) self.play( faders.set_color, BLACK, FadeIn(new_exp), run_time = 2, ) self.wait() terms[3].add(new_exp) shift_val = 0.4*DOWN self.play( FadeOut(terms[-2]),#frac_line terms[1].shift, shift_val + 0.45*RIGHT, terms[2].shift, shift_val, terms[3].shift, shift_val, ) #Isolate dominant term arrow = Arrow( self.lhs[4].get_bottom(), terms[1][2].get_top(), color = WHITE, buff = MED_SMALL_BUFF ) brace = Brace(VGroup(terms[2][0], terms[3][-1]), DOWN) brace_text = brace.get_text("Contains $dt$") VGroup(*brace_text[-2:]).set_color(TIME_COLOR) self.play(ShowCreation(arrow)) self.wait() self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait(2) #Shink dt faders = VGroup(*terms[2:4] + [brace, brace_text]) def ds_dt_group_update(group, alpha): new_dt = interpolate(self.start_dt, self.end_dt, alpha) new_group = self.get_ds_dt_group(new_dt) Transform(group, new_group).update(1) self.play(FadeOut(self.vertical_lines)) self.secant_line_length = 10 self.play(Transform( self.ds_dt_group, self.get_ds_dt_group(self.start_dt) )) self.play( UpdateFromAlphaFunc(self.ds_dt_group, ds_dt_group_update), faders.fade, 0.7, run_time = 5 ) self.wait(2) #Show as derivative deriv_term = VGroup(*terms[1][:5]) deriv_term.generate_target() lhs_copy = self.lhs.copy() lhs_copy.generate_target() lhs_copy.target.shift(3*DOWN) #hack a little, hack a lot deriv_term.target.scale(1.1) deriv_term.target.next_to(lhs_copy.target) deriv_term.target.shift(0.07*DOWN) self.play( FadeOut(arrow), FadeOut(faders), MoveToTarget(deriv_term), MoveToTarget(lhs_copy), ) arrow = Arrow( self.rhs.get_bottom(), deriv_term.target.get_top(), buff = MED_SMALL_BUFF, color = WHITE ) approach_text = TextMobject("As $dt \\to 0$") approach_text.next_to(arrow.get_center(), RIGHT) VGroup(*approach_text[2:4]).set_color(TIME_COLOR) self.play( ShowCreation(arrow), Write(approach_text) ) self.wait(2) self.wait() #Ephasize slope v_line = self.vertical_lines[0] slope_text = TextMobject("Slope = $12$") slope_text.set_color(VELOCITY_COLOR) slope_text.next_to(v_line.get_end(), LEFT) self.play(Write(slope_text)) self.play( self.ds_dt_group.rotate_in_place, np.pi/24, rate_func = wiggle ) self.play(ShowCreation(v_line)) self.wait() self.play(FadeOut(v_line)) self.play(FadeOut(slope_text)) #Generalize to more t twos = [ self.lhs[6], self.rhs[2], self.rhs[10], lhs_copy[6], deriv_term[2] ] for two in twos: two.target = TexMobject("t") two.target.replace(two, dim_to_match = 1) self.play(*list(map(MoveToTarget, twos))) def update_as_tangent_line(group, alpha): self.curr_time = interpolate(self.start_time, self.end_time, alpha) new_group = self.get_ds_dt_group(self.end_dt) Transform(group, new_group).update(1) self.play( UpdateFromAlphaFunc(self.ds_dt_group, update_as_tangent_line), run_time = 5, rate_func = there_and_back ) self.wait(2) self.lhs_copy = lhs_copy self.deriv_term = deriv_term self.approach_text = approach_text def react_to_simplicity(self): morty = Mortimer().flip().to_corner(DOWN+LEFT) self.play(FadeIn(morty)) self.play(PiCreatureSays( morty, "That's \\\\ beautiful!", target_mode = "hooray" )) self.play(Blink(morty)) self.play( morty.change_mode, 'happy', *list(map(FadeOut, [morty.bubble, morty.bubble.content])) ) numerator = VGroup(*self.rhs[:12]) denominator = VGroup(*self.rhs[-2:]) for mob in numerator, denominator, self.approach_text, self.deriv_term: mob.generate_target() mob.target.scale_in_place(1.2) mob.target.set_color(MAROON_B) self.play( MoveToTarget( mob, rate_func = there_and_back, run_time = 1.5, ), morty.look_at, mob ) self.wait() self.play(Blink(morty)) self.wait() class YouWouldntDoThisEveryTime(TeacherStudentsScene): def construct(self): self.change_student_modes( "pleading", "guilty", "hesitant", run_time = 0 ) self.teacher_says( "You wouldn't do this \\\\ every time" ) self.change_student_modes(*["happy"]*3) self.wait(2) self.student_thinks( "$\\frac{d(t^3)}{dt} = 3t^2$", ) self.wait(3) series = VideoSeries() series.set_width(FRAME_WIDTH-1) series.to_edge(UP) this_video = series[1] next_video = series[2] this_video.save_state() this_video.set_color(YELLOW) self.play(FadeIn(series, lag_ratio = 0.5)) self.play( this_video.restore, next_video.set_color, YELLOW, next_video.shift, 0.5*DOWN ) self.wait(2) class ContrastConcreteDtWithLimit(Scene): def construct(self): v_line = Line(UP, DOWN).scale(FRAME_Y_RADIUS) self.add(v_line) l_title = TextMobject(""" If $dt$ has a specific size. """) VGroup(*l_title[2:4]).set_color(TIME_COLOR) r_title = TexMobject("dt \\to 0") VGroup(*r_title[:2]).set_color(TIME_COLOR) for title, vect in (l_title, LEFT), (r_title, RIGHT): title.to_edge(UP) title.shift(FRAME_X_RADIUS*vect/2) self.add(title) l_formula = TexMobject(""" \\frac{d(t^3)}{dt} = \\frac{ t^3+ 3t^2 \\, dt + 3t \\, (dt)^2 + (dt)^3 - t^3 }{dt} """) VGroup(*it.chain( l_formula[6:8], l_formula[15:17], l_formula[21:23], l_formula[27:29], l_formula[35:37], )).set_color(TIME_COLOR) l_formula.set_width(FRAME_X_RADIUS-MED_LARGE_BUFF) l_formula.to_edge(LEFT) l_brace = Brace(l_formula, DOWN) l_text = l_brace.get_text("Messy") l_text.set_color(RED) r_formula = TexMobject( "\\frac{d(t^3)}{dt} = 3t^2" ) VGroup(*r_formula[6:8]).set_color(TIME_COLOR) r_formula.shift(FRAME_X_RADIUS*RIGHT/2) r_brace = Brace(r_formula, DOWN) r_text = r_brace.get_text("Simple") r_text.set_color(GREEN) triplets = [ (l_formula, l_brace, l_text), (r_formula, r_brace, r_text), ] for formula, brace, text in triplets: self.play(Write(formula, run_time = 1)) self.play( GrowFromCenter(brace), Write(text) ) self.wait(2) class TimeForAnActualParadox(TeacherStudentsScene): def construct(self): words = TextMobject("``Instantaneous rate of change''") paradoxes = TextMobject("Paradoxes") arrow = Arrow(ORIGIN, DOWN, buff = 0) group = VGroup(words, arrow, paradoxes) group.arrange(DOWN) group.to_edge(UP) teacher = self.get_teacher() self.play( teacher.change_mode, "raise_right_hand", teacher.look_at, words, Write(words) ) self.play(*list(map(Write, [arrow, paradoxes]))) self.play(*it.chain(*[ [pi.change_mode, mode, pi.look_at, words] for pi, mode in zip( self.get_students(), ["pondering", "happy", "hesitant"] ) ])) self.wait(4) class ParadoxAtTEquals0(TCubedExample): CONFIG = { "tangent_line_length" : 20, } def construct(self): self.draw_graph() self.ask_question() self.show_derivative_text() self.show_tangent_line() self.if_not_then_when() self.single_out_question() def draw_graph(self): self.setup_axes(animate = False) self.x_axis_label_mob.set_fill(opacity = 0) graph = self.graph_function(lambda t : t**3, animate = False) graph_x_max = 3.0 graph.pointwise_become_partial(graph, 0, graph_x_max/self.x_max) origin = self.coords_to_point(0, 0) h_line = Line(LEFT, RIGHT, color = TIME_COLOR) v_line = Line(UP, DOWN, color = DISTANCE_COLOR) VGroup(h_line, v_line).set_stroke(width = 2) def h_line_update(h_line): point = graph.point_from_proportion(1) y_axis_point = origin[0]*RIGHT + point[1]*UP h_line.put_start_and_end_on(y_axis_point, point) return h_line def v_line_update(v_line): point = graph.point_from_proportion(1) x_axis_point = point[0]*RIGHT + origin[1]*UP v_line.put_start_and_end_on(x_axis_point, point) return v_line car = Car() car.rotate(np.pi/2) car.move_to(origin) self.add(car) #Should be 0, 1, but for some reason I don't know #the car was lagging the graph. car_target_point = self.coords_to_point(0, 1.15) self.play( MoveCar( car, car_target_point, rate_func = lambda t : (t*graph_x_max)**3 ), ShowCreation(graph, rate_func=linear), UpdateFromFunc(h_line, h_line_update), UpdateFromFunc(v_line, v_line_update), run_time = 5 ) self.play(*list(map(FadeOut, [h_line, v_line]))) self.label_graph( graph, label = "s(t) = t^3", proportion = 0.8, direction = RIGHT, buff = SMALL_BUFF ) self.wait() self.car = car def ask_question(self): question = TextMobject( "At time $t=0$,", "is \\\\ the car moving?" ) VGroup(*question[0][-4:-1]).set_color(RED) question.next_to( self.coords_to_point(0, 10), RIGHT ) origin = self.coords_to_point(0, 0) arrow = Arrow(question.get_bottom(), origin) self.play(Write(question[0], run_time = 1)) self.play(MoveCar(self.car, origin)) self.wait() self.play(Write(question[1])) self.play(ShowCreation(arrow)) self.wait(2) self.question = question def show_derivative_text(self): derivative = TexMobject( "\\frac{ds}{dt}(t) = 3t^2", "= 3(0)^2", "= 0", "\\frac{\\text{m}}{\\text{s}}", ) VGroup(*derivative[0][:2]).set_color(DISTANCE_COLOR) VGroup(*derivative[0][3:5]).set_color(TIME_COLOR) derivative[1][3].set_color(RED) derivative[-1].scale_in_place(0.7) derivative.to_edge(RIGHT, buff = LARGE_BUFF) derivative.shift(2*UP) self.play(Write(derivative[0])) self.wait() self.play(FadeIn(derivative[1])) self.play(*list(map(FadeIn, derivative[2:]))) self.wait(2) self.derivative = derivative def show_tangent_line(self): dot = Dot() line = Line(ORIGIN, RIGHT, color = VELOCITY_COLOR) line.scale(self.tangent_line_length) start_time = 2 end_time = 0 def get_time_and_point(alpha): time = interpolate(start_time, end_time, alpha) point = self.input_to_graph_point(time) return time, point def dot_update(dot, alpha): dot.move_to(get_time_and_point(alpha)[1]) def line_update(line, alpha): time, point = get_time_and_point(alpha) line.rotate( self.angle_of_tangent(time)-line.get_angle() ) line.move_to(point) dot_update(dot, 0) line_update(line, 0) self.play( ShowCreation(line), ShowCreation(dot) ) self.play( UpdateFromAlphaFunc(line, line_update), UpdateFromAlphaFunc(dot, dot_update), run_time = 4 ) self.wait(2) self.tangent_line = line def if_not_then_when(self): morty = Mortimer() morty.scale(0.7) morty.to_corner(DOWN+RIGHT) self.play(FadeIn(morty)) self.play(PiCreatureSays( morty, "If not at $t=0$, when?", target_mode = "maybe" )) self.play(Blink(morty)) self.play(MoveCar( self.car, self.coords_to_point(0, 1), rate_func = lambda t : (3*t)**3, run_time = 5 )) self.play( morty.change_mode, "pondering", FadeOut(morty.bubble), FadeOut(morty.bubble.content), ) self.play(MoveCar(self.car, self.coords_to_point(0, 0))) self.play(Blink(morty)) self.wait(2) self.morty = morty def single_out_question(self): morty, question = self.morty, self.question #Shouldn't need this morty.bubble.content.set_fill(opacity = 0) morty.bubble.set_fill(opacity = 0) morty.bubble.set_stroke(width = 0) change_word = VGroup(*question[1][-7:-1]) moment_word = question[0] brace = Brace(VGroup(*self.derivative[1:])) brace_text = brace.get_text("Best constant \\\\ approximation") self.remove(question, morty) pre_everything = Mobject(*self.get_mobjects()) everything = Mobject(*pre_everything.family_members_with_points()) everything.save_state() self.play( everything.fade, 0.8, question.center, morty.change_mode, "confused", morty.look_at, ORIGIN ) self.play(Blink(morty)) for word in change_word, moment_word: self.play( word.scale_in_place, 1.2, word.set_color, YELLOW, rate_func = there_and_back, run_time = 1.5 ) self.wait(2) self.play( everything.restore, FadeOut(question), morty.change_mode, "raise_right_hand", morty.look_at, self.derivative ) self.play( GrowFromCenter(brace), FadeIn(brace_text) ) self.wait() self.play( self.tangent_line.rotate_in_place, np.pi/24, rate_func = wiggle, run_time = 1 ) self.play(Blink(morty)) self.wait() class TinyMovement(ZoomedScene): CONFIG = { "distance" : 0.05, "distance_label" : "(0.1)^3 = 0.001", "time_label" : "0.1", } def construct(self): self.activate_zooming() self.show_initial_motion() self.show_ratios() def show_initial_motion(self): car = Car() car.move_to(ORIGIN) car_points = car.get_all_points() lowest_to_highest_indices = np.argsort(car_points[:,1]) wheel_point = car_points[lowest_to_highest_indices[2]] target_wheel_point = wheel_point+self.distance*RIGHT dots = VGroup(*[ Dot(point, radius = self.distance/10) for point in (wheel_point, target_wheel_point) ]) brace = Brace(Line(ORIGIN, RIGHT)) distance_label = TexMobject(self.distance_label) distance_label.next_to(brace, DOWN) distance_label.set_color(DISTANCE_COLOR) brace.add(distance_label) brace.scale(self.distance) brace.next_to(dots, DOWN, buff = self.distance/5) zoom_rect = self.little_rectangle zoom_rect.scale(2) zoom_rect.move_to(wheel_point) time_label = TextMobject("Time $t = $") time_label.next_to(car, UP, buff = LARGE_BUFF) start_time = TexMobject("0") end_time = TexMobject(self.time_label) for time in start_time, end_time: time.set_color(TIME_COLOR) time.next_to(time_label, RIGHT) self.add(car, time_label, start_time) self.play( zoom_rect.scale_in_place, 10*self.distance / zoom_rect.get_width() ) self.play(ShowCreation(dots[0])) self.play(Transform(start_time, end_time)) self.play(MoveCar(car, self.distance*RIGHT)) self.play(ShowCreation(dots[1])) self.play(Write(brace, run_time = 1)) self.play( zoom_rect.scale, 0.5, zoom_rect.move_to, brace ) self.wait() def show_ratios(self): ratios = [ self.get_ratio(n) for n in range(1, 5) ] ratio = ratios[0] self.play(FadeIn(ratio)) self.wait(2) for new_ratio in ratios[1:]: self.play(Transform(ratio, new_ratio)) self.wait() def get_ratio(self, power = 1): dt = "0.%s1"%("0"*(power-1)) ds_dt = "0.%s1"%("0"*(2*power-1)) expression = TexMobject(""" \\frac{(%s)^3 \\text{ meters}}{%s \\text{ seconds}} = %s \\frac{\\text{meters}}{\\text{second}} """%(dt, dt, ds_dt)) expression.next_to(ORIGIN, DOWN, buff = LARGE_BUFF) lengths = [ 0, len("("), len(dt), len(")3meters_"), len(dt), len("seconds="), len(ds_dt), len("meters_second") ] result = VGroup(*[ VGroup(*expression[i1:i2]) for i1, i2 in zip( np.cumsum(lengths), np.cumsum(lengths)[1:], ) ]) result[1].set_color(DISTANCE_COLOR) result[3].set_color(TIME_COLOR) result[5].set_color(VELOCITY_COLOR) return result class NextVideos(TeacherStudentsScene): def construct(self): series = VideoSeries() series.set_width(FRAME_WIDTH - 1) series.to_edge(UP) series[1].set_color(YELLOW) self.add(series) brace = Brace(VGroup(*series[2:6])) brace_text = brace.get_text("More derivative stuffs") self.play( GrowFromCenter(brace), self.get_teacher().change_mode, "raise_right_hand" ) self.play( Write(brace_text), *it.chain(*[ [pi.look_at, brace] for pi in self.get_students() ]) ) self.wait(2) self.change_student_modes(*["thinking"]*3) self.wait(3) class Chapter2PatreonThanks(PatreonThanks): CONFIG = { "specific_patrons" : [ "Meshal Alshammari", "Ali Yahya", "CrypticSwarm ", "Yu Jun", "Shelby Doolittle", "Dave Nicponski", "Damion Kistler", "Juan Benet", "Othman Alikhan", "Markus Persson", "Dan Buchoff", "Derek Dai", "Joseph Cox", "Luc Ritchie", "Mark Govea", "Guido Gambardella", "Vecht", "Jonathan Eppele", "Shimin Kuang", "Rish Kundalia", "Achille Brighton", "Kirk Werklund", "Ripta Pasay", "Felipe Diniz", ] } class Promotion(PiCreatureScene): CONFIG = { "camera_class" : ThreeDCamera, "seconds_to_blink" : 5, } def construct(self): aops_logo = AoPSLogo() aops_logo.next_to(self.pi_creature, UP+LEFT) url = TextMobject( "AoPS.com/", "3blue1brown", arg_separator = "" ) url.to_corner(UP+LEFT) url_rect = Rectangle(color = BLUE) url_rect.replace( url.get_part_by_tex("3blue1brown"), stretch = True ) url_rect.stretch_in_place(1.1, dim = 1) rect = Rectangle(height = 9, width = 16) rect.set_height(4.5) rect.next_to(url, DOWN) rect.to_edge(LEFT) mathy = Mathematician() mathy.flip() mathy.to_corner(DOWN+RIGHT) morty = self.pi_creature morty.save_state() book_spot = mathy.get_corner(UP+LEFT) + UP+LEFT mathy.get_center = mathy.get_top self.play( self.pi_creature.change_mode, "raise_right_hand", *[ DrawBorderThenFill( submob, run_time = 3, rate_func = squish_rate_func(double_smooth, a, a+0.5) ) for submob, a in zip(aops_logo, np.linspace(0, 0.5, len(aops_logo))) ] ) self.play(Write(url)) self.play( morty.change_mode, "plain", morty.flip, morty.scale, 0.7, morty.next_to, mathy, LEFT, LARGE_BUFF, morty.to_edge, DOWN, FadeIn(mathy), ) self.play( PiCreatureSays( mathy, "", bubble_kwargs = {"width" : 5}, look_at_arg = morty.eyes, ), aops_logo.shift, 1.5*UP + 0.5*RIGHT ) self.change_mode("happy") self.wait(2) self.play(Blink(mathy)) self.wait() self.play( RemovePiCreatureBubble( mathy, target_mode = "happy" ), aops_logo.to_corner, UP+RIGHT, aops_logo.shift, MED_SMALL_BUFF*DOWN, ) self.play( mathy.look_at, morty.eyes, morty.look_at, mathy.eyes, ) self.wait(2) self.play( Animation(VectorizedPoint(book_spot)), mathy.change, "raise_right_hand", book_spot, morty.change, "pondering", ) self.wait(3) self.play(Blink(mathy)) self.wait(7) self.play( ShowCreation(rect), morty.restore, morty.change, "happy", rect, FadeOut(mathy), ) self.wait(10) self.play(ShowCreation(url_rect)) self.play( FadeOut(url_rect), url.get_part_by_tex("3blue1brown").set_color, BLUE, ) self.wait(3) class Thumbnail(SecantLineToTangentLine): def construct(self): self.setup_axes(animate = False) self.add_graph() self.curr_time = 6 ds_dt_group = self.get_ds_dt_group(1) self.add(ds_dt_group) self.remove(self.x_axis_label_mob) self.remove(self.y_axis_label_mob) VGroup(*self.get_mobjects()).fade(0.4) title = TextMobject("Derivative paradox") title.set_width(FRAME_WIDTH-1) title.to_edge(UP) title.add_background_rectangle() title.set_color_by_gradient(GREEN, YELLOW) randy = Randolph(mode = "confused") randy.scale(1.7) randy.to_corner(DOWN+LEFT) randy.shift(RIGHT) deriv = TexMobject("\\frac{ds}{dt}(t)") VGroup(*deriv[:2]).set_color(DISTANCE_COLOR) VGroup(*deriv[3:5]).set_color(TIME_COLOR) deriv.scale(3) # deriv.next_to(randy, RIGHT, buff = 2) deriv.to_edge(RIGHT, buff = LARGE_BUFF) randy.look_at(deriv) self.add(title, randy, deriv)