import scipy from big_ol_pile_of_manim_imports import * from old_projects.eoc.chapter1 import Thumbnail as Chapter1Thumbnail from old_projects.eoc.chapter2 import Car, MoveCar, ShowSpeedometer, \ IncrementNumber, GraphCarTrajectory, SecantLineToTangentLine, \ VELOCITY_COLOR, TIME_COLOR, DISTANCE_COLOR def v_rate_func(t): return 4*t - 4*(t**2) def s_rate_func(t): return 3*(t**2) - 2*(t**3) def v_func(t): return t*(8-t) def s_func(t): return 4*t**2 - (t**3)/3. class Chapter8OpeningQuote(OpeningQuote, PiCreatureScene): CONFIG = { "quote" : [ " One should never try to prove anything that \\\\ is not ", "almost obvious", ". " ], "quote_arg_separator" : "", "highlighted_quote_terms" : { "almost obvious" : BLUE, }, "author" : "Alexander Grothendieck" } def construct(self): self.remove(self.pi_creature) OpeningQuote.construct(self) words_copy = self.quote.get_part_by_tex("obvious").copy() author = self.author author.save_state() formula = self.get_formula() formula.next_to(author, DOWN, MED_LARGE_BUFF) formula.to_edge(LEFT) self.revert_to_original_skipping_status() self.play(FadeIn(self.pi_creature)) self.play( author.next_to, self.pi_creature.get_corner(UP+LEFT), UP, self.pi_creature.change_mode, "raise_right_hand" ) self.wait(3) self.play( author.restore, self.pi_creature.change_mode, "plain" ) self.play( words_copy.next_to, self.pi_creature, LEFT, MED_SMALL_BUFF, UP, self.pi_creature.change_mode, "thinking" ) self.wait(2) self.play( Write(formula), self.pi_creature.change_mode, "confused" ) self.wait() def get_formula(self): result = TexMobject( "{d(\\sin(\\theta)) \\over \\,", "d\\theta}", "=", "\\lim_{", "h", " \\to 0}", "{\\sin(\\theta+", "h", ") - \\sin(\\theta) \\over", " h}", "=", "\\lim_{", "h", " \\to 0}", "{\\big[ \\sin(\\theta)\\cos(", "h", ") + ", "\\sin(", "h", ")\\cos(\\theta)\\big] - \\sin(\\theta) \\over", "h}", "= \\dots" ) result.set_color_by_tex("h", GREEN, substring = False) result.set_color_by_tex("d\\theta", GREEN) result.set_width(FRAME_WIDTH - 2*MED_SMALL_BUFF) return result class ThisVideo(TeacherStudentsScene): def construct(self): series = VideoSeries() series.to_edge(UP) this_video = series[7] this_video.save_state() next_video = series[8] deriv, integral, v_t, dt, equals, v_T = formula = TexMobject( "\\frac{d}{dT}", "\\int_0^T", "v(t)", "\\,dt", "=", "v(T)" ) formula.set_color_by_tex("v", VELOCITY_COLOR) formula.next_to(self.teacher.get_corner(UP+LEFT), UP, MED_LARGE_BUFF) self.play(FadeIn(series, submobject_mode = "lagged_start")) self.play( this_video.shift, this_video.get_height()*DOWN/2, this_video.set_color, YELLOW, self.teacher.change_mode, "raise_right_hand", ) self.play(Write(VGroup(integral, v_t, dt))) self.change_student_modes(*["erm"]*3) self.wait() self.play(Write(VGroup(deriv, equals, v_T)), ) self.change_student_modes(*["confused"]*3) self.wait(3) self.play( this_video.restore, next_video.shift, next_video.get_height()*DOWN/2, next_video.set_color, YELLOW, integral[0].copy().next_to, next_video, DOWN, MED_LARGE_BUFF, FadeOut(formula), *it.chain(*[ [pi.change_mode, "plain", pi.look_at, next_video] for pi in self.pi_creatures ]) ) self.wait(2) class InCarRestrictedView(ShowSpeedometer): CONFIG = { "speedometer_title_text" : "Your view", } def construct(self): car = Car() car.move_to(self.point_A) self.car = car car.randy.save_state() Transform(car.randy, Randolph()).update(1) car.randy.next_to(car, RIGHT, MED_LARGE_BUFF) car.randy.look_at(car) window = car[1][6].copy() window.is_subpath = False window.set_fill(BLACK, opacity = 0.75) window.set_stroke(width = 0) square = Square(stroke_color = WHITE) square.replace(VGroup(self.speedometer, self.speedometer_title)) square.scale_in_place(1.5) square.pointwise_become_partial(square, 0.25, 0.75) time_label = TextMobject("Time (in seconds):", "0") time_label.shift(2*UP) dots = VGroup(*list(map(Dot, [self.point_A, self.point_B]))) line = Line(*dots, buff = 0) line.set_color(DISTANCE_COLOR) brace = Brace(line, DOWN) brace_text = brace.get_text("Distance traveled?") #Sit in car self.add(car) self.play(Blink(car.randy)) self.play(car.randy.restore, Animation(car)) self.play(ShowCreation(window, run_time = 2)) self.wait() #Show speedometer self.introduce_added_mobjects() self.play(ShowCreation(square)) self.wait() #Travel self.play(FadeIn(time_label)) self.play( MoveCar(car, self.point_B, rate_func = s_rate_func), IncrementNumber(time_label[1], run_time = 8), MaintainPositionRelativeTo(window, car), *self.get_added_movement_anims( rate_func = v_rate_func, radians = -(16.0/70)*4*np.pi/3 ), run_time = 8 ) eight = TexMobject("8").move_to(time_label[1]) self.play(Transform( time_label[1], eight, rate_func = squish_rate_func(smooth, 0, 0.5) )) self.wait() #Ask about distance self.play(*list(map(ShowCreation, dots))) self.play(ShowCreation(line)) self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait(2) class GraphDistanceVsTime(GraphCarTrajectory): CONFIG = { "y_min" : 0, "y_max" : 100, "y_axis_height" : 6, "y_tick_frequency" : 10, "y_labeled_nums" : list(range(10, 100, 10)), "y_axis_label" : "Distance (in meters)", "x_min" : -1, "x_max" : 9, "x_axis_width" : 9, "x_tick_frequency" : 1, "x_leftmost_tick" : None, #Change if different from x_min "x_labeled_nums" : list(range(1, 9)), "x_axis_label" : "$t$", "time_of_journey" : 8, "care_movement_rate_func" : s_rate_func, "num_graph_anchor_points" : 100 } def construct(self): self.setup_axes() graph = self.get_graph( s_func, color = DISTANCE_COLOR, x_min = 0, x_max = 8, ) origin = self.coords_to_point(0, 0) graph_label = self.get_graph_label( graph, "s(t)", color = DISTANCE_COLOR ) self.introduce_graph(graph, origin) class PlotVelocity(GraphScene): CONFIG = { "x_min" : -1, "x_max" : 9, "x_axis_width" : 9, "x_tick_frequency" : 1, "x_labeled_nums" : list(range(1, 9)), "x_axis_label" : "$t$", "y_min" : 0, "y_max" : 25, "y_axis_height" : 6, "y_tick_frequency" : 5, "y_labeled_nums" : list(range(5, 30, 5)), "y_axis_label" : "Velocity in $\\frac{\\text{meters}}{\\text{second}}$", "num_graph_anchor_points" : 50, } def construct(self): self.setup_axes() self.add_speedometer() self.plot_points() self.draw_curve() def add_speedometer(self): speedometer = Speedometer() speedometer.next_to(self.y_axis_label_mob, RIGHT, LARGE_BUFF) speedometer.to_edge(UP) self.play(DrawBorderThenFill( speedometer, submobject_mode = "lagged_start", rate_func = None, )) self.speedometer = speedometer def plot_points(self): times = list(range(0, 9)) points = [ self.coords_to_point(t, v_func(t)) for t in times ] dots = VGroup(*[Dot(p, radius = 0.07) for p in points]) dots.set_color(VELOCITY_COLOR) pre_dots = VGroup() dot_intro_anims = [] for time, dot in zip(times, dots): pre_dot = dot.copy() self.speedometer.move_needle_to_velocity(v_func(time)) pre_dot.move_to(self.speedometer.get_needle_tip()) pre_dot.set_fill(opacity = 0) pre_dots.add(pre_dot) dot_intro_anims += [ ApplyMethod( pre_dot.set_fill, YELLOW, 1, run_time = 0.1, ), ReplacementTransform( pre_dot, dot, run_time = 0.9, ) ] self.speedometer.move_needle_to_velocity(0) self.play( Succession( *dot_intro_anims, rate_func = None ), ApplyMethod( self.speedometer.move_needle_to_velocity, v_func(4), rate_func = squish_rate_func( lambda t : 1-v_rate_func(t), 0, 0.95, ) ), run_time = 5 ) self.wait() def draw_curve(self): graph, label = self.get_v_graph_and_label() self.revert_to_original_skipping_status() self.play(ShowCreation(graph, run_time = 3)) self.play(Write(graph_label)) self.wait() ## def get_v_graph_and_label(self): graph = self.get_graph( v_func, x_min = 0, x_max = 8, color = VELOCITY_COLOR ) graph_label = TexMobject("v(t)", "=t(8-t)") graph_label.set_color_by_tex("v(t)", VELOCITY_COLOR) graph_label.next_to( graph.point_from_proportion(7./8.), UP+RIGHT ) self.v_graph = graph self.v_graph_label = graph_label return graph, graph_label class Chapter2Wrapper(Scene): CONFIG = { "title" : "Chapter 2: The paradox of the derivative", } def construct(self): title = TextMobject(self.title) title.to_edge(UP) rect = Rectangle(width = 16, height = 9, color = WHITE) rect.set_height(1.5*FRAME_Y_RADIUS) rect.next_to(title, DOWN) self.add(title) self.play(ShowCreation(rect)) self.wait(3) class GivenDistanceWhatIsVelocity(GraphCarTrajectory): def construct(self): self.force_skipping() self.setup_axes() 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.revert_to_original_skipping_status() self.show_velocity_graph() class DerivativeOfDistance(SecantLineToTangentLine): def construct(self): self.setup_axes() 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() class AskAboutAntiderivative(PlotVelocity): def construct(self): self.setup_axes() self.add_v_graph() self.write_s_formula() self.write_antiderivative() def add_v_graph(self): graph, label = self.get_v_graph_and_label() self.play(ShowCreation(graph)) self.play(Write(label)) self.graph = graph self.graph_label = label def write_s_formula(self): ds_dt = TexMobject("ds", "\\over\\,", "dt") ds_dt.set_color_by_tex("ds", DISTANCE_COLOR) ds_dt.set_color_by_tex("dt", TIME_COLOR) ds_dt.next_to(self.graph_label, UP, LARGE_BUFF) v_t = self.graph_label.get_part_by_tex("v(t)") arrow = Arrow( ds_dt.get_bottom(), v_t.get_top(), color = WHITE, ) self.play( Write(ds_dt, run_time = 2), ShowCreation(arrow) ) self.wait() def write_antiderivative(self): randy = Randolph() randy.to_corner(DOWN+LEFT) randy.shift(2*RIGHT) words = TexMobject( "{d(", "???", ") \\over \\,", "dt}", "=", "t(8-t)" ) words.set_color_by_tex("t(8-t)", VELOCITY_COLOR) words.set_color_by_tex("???", DISTANCE_COLOR) words.set_color_by_tex("dt", TIME_COLOR) words.scale(0.7) self.play(FadeIn(randy)) self.play(PiCreatureSays( randy, words, target_mode = "confused", bubble_kwargs = {"height" : 3, "width" : 4}, )) self.play(Blink(randy)) self.wait() class Antiderivative(PiCreatureScene): def construct(self): functions = self.get_functions("t^2", "2t") alt_functions = self.get_functions("???", "t(8-t)") top_arc, bottom_arc = arcs = self.get_arcs(functions) derivative, antiderivative = self.get_arc_labels(arcs) group = VGroup(functions, arcs, derivative, antiderivative) self.add(functions, top_arc, derivative) self.wait() self.play( ShowCreation(bottom_arc), Write(antiderivative), self.pi_creature.change_mode, "raise_right_hand" ) self.wait(2) for pair in reversed(list(zip(functions, alt_functions))): self.play( Transform(*pair), self.pi_creature.change_mode, "pondering" ) self.wait(2) self.pi_creature_says( "But first!", target_mode = "surprised", look_at_arg = 50*OUT, added_anims = [group.to_edge, LEFT], run_time = 1, ) self.wait() def get_functions(self, left_tex, right_tex): left = TexMobject(left_tex) left.shift(2*LEFT) left.set_color(DISTANCE_COLOR) right = TexMobject(right_tex) right.shift(2*RIGHT) right.set_color(VELOCITY_COLOR) result = VGroup(left, right) result.shift(UP) return result def get_arcs(self, functions): f1, f2 = functions top_line = Line(f1.get_corner(UP+RIGHT), f2.get_corner(UP+LEFT)) bottom_line = Line(f1.get_corner(DOWN+RIGHT), f2.get_corner(DOWN+LEFT)) top_arc = Arc(start_angle = 5*np.pi/6, angle = -2*np.pi/3) bottom_arc = top_arc.copy() bottom_arc.rotate(np.pi) arcs = VGroup(top_arc, bottom_arc) arcs.set_width(top_line.get_width()) for arc in arcs: arc.add_tip() top_arc.next_to(top_line, UP) bottom_arc.next_to(bottom_line, DOWN) bottom_arc.set_color(MAROON_B) return arcs def get_arc_labels(self, arcs): top_arc, bottom_arc = arcs derivative = TextMobject("Derivative") derivative.next_to(top_arc, UP) antiderivative = TextMobject("``Antiderivative''") antiderivative.next_to(bottom_arc, DOWN) antiderivative.set_color(bottom_arc.get_color()) return VGroup(derivative, antiderivative) class AreaUnderVGraph(PlotVelocity): def construct(self): self.setup_axes() self.add(*self.get_v_graph_and_label()) self.show_rects() def show_rects(self): rect_list = self.get_riemann_rectangles_list( self.v_graph, 7, max_dx = 1.0, x_min = 0, x_max = 8, ) flat_graph = self.get_graph(lambda t : 0) rects = self.get_riemann_rectangles( flat_graph, x_min = 0, x_max = 8, dx = 1.0 ) for new_rects in rect_list: new_rects.set_fill(opacity = 0.8) rects.align_submobjects(new_rects) for alt_rect in rects[::2]: alt_rect.set_fill(opacity = 0) self.play(Transform( rects, new_rects, run_time = 2, submobject_mode = "lagged_start" )) self.wait() class ConstantVelocityCar(Scene): def construct(self): car = Car() car.move_to(5*LEFT + 3*DOWN) self.add(car) self.wait() self.play(MoveCar( car, 7*RIGHT+3*DOWN, run_time = 5, rate_func = None, )) self.wait() class ConstantVelocityPlot(PlotVelocity): CONFIG = { "x_axis_label" : "Time", "units_of_area_color" : BLUE_E, } def construct(self): self.setup_axes() self.x_axis_label_mob.shift(DOWN) self.draw_graph() self.show_product() self.comment_on_area_wierdness() self.note_units() def draw_graph(self): graph = self.get_graph( lambda t : 10, x_min = 0, x_max = 8, color = VELOCITY_COLOR ) self.play(ShowCreation(graph, rate_func = None, run_time = 3)) self.wait() self.graph = graph def show_product(self): rect = Rectangle( stroke_width = 0, fill_color = DISTANCE_COLOR, fill_opacity = 0.5 ) rect.replace( VGroup(self.graph, VectorizedPoint(self.graph_origin)), stretch = True ) right_brace = Brace(rect, RIGHT) top_brace = Brace(rect, UP) v_label = right_brace.get_text( "$10 \\frac{\\text{meters}}{\\text{second}}$", ) v_label.set_color(VELOCITY_COLOR) t_label = top_brace.get_text( "8 seconds" ) t_label.set_color(TIME_COLOR) s_label = TexMobject("10", "\\times", "8", "\\text{ meters}") s_label.set_color_by_tex("10", VELOCITY_COLOR) s_label.set_color_by_tex("8", TIME_COLOR) s_label.move_to(rect) self.play( GrowFromCenter(right_brace), Write(v_label), ) self.play( GrowFromCenter(top_brace), Write(t_label), ) self.play( FadeIn(rect), Write(s_label), Animation(self.graph) ) self.wait(2) self.area_rect = rect self.s_label = s_label def comment_on_area_wierdness(self): randy = Randolph() randy.to_corner(DOWN+LEFT) bubble = randy.get_bubble( "Distance \\\\ is area?", bubble_class = ThoughtBubble, height = 3, width = 4, fill_opacity = 1, ) bubble.content.scale_in_place(0.8) bubble.content.shift(SMALL_BUFF*UP) VGroup(bubble[-1], bubble.content).shift(1.5*LEFT) self.play(FadeIn(randy)) self.play(randy.change_mode, "pondering") self.play( self.area_rect.set_color, YELLOW, *list(map(Animation, self.get_mobjects())), rate_func = there_and_back ) self.play(Blink(randy)) self.play( randy.change_mode, "confused", randy.look_at, randy.bubble, ShowCreation(bubble), Write(bubble.content), ) self.wait() self.play(Blink(randy)) self.wait() self.play( randy.change_mode, "pondering", FadeOut(bubble), FadeOut(bubble.content), ) self.randy = randy def note_units(self): x_line, y_line = lines = VGroup(*[ axis.main_line.copy() for axis in (self.x_axis, self.y_axis) ]) lines.set_color(TIME_COLOR) square = Square( stroke_color = BLACK, stroke_width = 1, fill_color = self.units_of_area_color, fill_opacity = 1, ) square.replace( VGroup(*[ VectorizedPoint(self.coords_to_point(i, i)) for i in (0, 1) ]), stretch = True ) units_of_area = VGroup(*[ square.copy().move_to( self.coords_to_point(x, y), DOWN+LEFT ) for x in range(8) for y in range(10) ]) self.play(ShowCreation(x_line)) self.play(Indicate(self.x_axis_label_mob)) self.play(FadeOut(x_line)) self.play( ShowCreation(y_line), self.randy.look_at, self.y_axis_label_mob ) self.play(Indicate(self.y_axis_label_mob)) self.play(FadeOut(y_line)) for FadeClass in FadeIn, FadeOut: self.play( FadeClass( units_of_area, submobject_mode = "lagged_start", run_time = 3 ), Animation(self.s_label), self.randy.look_at, self.area_rect ) self.play(Blink(self.randy)) self.wait() class PiecewiseConstantCar(Scene): def construct(self): car = Car() start_point = 5*LEFT car.move_to(start_point) self.add(car) self.wait() for shift in 2, 6, 12: car.randy.rotate_in_place(np.pi/8) anim = MoveCar( car, start_point+shift*RIGHT, rate_func = None ) anim.target_mobject[0].rotate_in_place(-np.pi/8) # for mob in anim.starting_mobject, anim.mobject: # mob.randy.rotate_in_place(np.pi/6) self.play(anim) self.wait() class PiecewiseConstantPlot(PlotVelocity): CONFIG = { "y_axis_label" : "", "min_graph_proportion" : 0.1, "max_graph_proportion" : 0.8, "num_riemann_approximations" : 7, "riemann_rect_fill_opacity" : 0.75, "tick_size" : 0.2, } def construct(self): self.setup_graph() self.always_changing() self.show_piecewise_constant_graph() self.compute_distance_on_each_interval() self.approximate_original_curve() self.revert_to_specific_approximation() self.show_specific_rectangle() self.show_v_dt_for_all_rectangles() self.write_integral_symbol() self.roles_of_dt() self.what_does_sum_approach() self.label_integral() def setup_graph(self): self.setup_axes() self.add(*self.get_v_graph_and_label()) def always_changing(self): dot = Dot() arrow = Arrow(LEFT, RIGHT) words = TextMobject("Always changing") group = VGroup(dot, arrow, words) def update_group(group, alpha): dot, arrow, words = group prop = interpolate( self.min_graph_proportion, self.max_graph_proportion, alpha ) graph_point = self.v_graph.point_from_proportion(prop) dot.move_to(graph_point) x_val = self.x_axis.point_to_number(graph_point) angle = self.angle_of_tangent(x_val, self.v_graph) angle += np.pi/2 vect = rotate_vector(RIGHT, angle) arrow.rotate(angle - arrow.get_angle() + np.pi) arrow.shift( graph_point + MED_SMALL_BUFF*vect - arrow.get_end() ) words.next_to(arrow.get_start(), UP) return group update_group(group, 0) self.play( Write(words), ShowCreation(arrow), DrawBorderThenFill(dot), run_time = 1 ) self.play(UpdateFromAlphaFunc( group, update_group, rate_func = there_and_back, run_time = 5 )) self.wait() self.play(FadeOut(group)) def show_piecewise_constant_graph(self): pw_constant_graph = self.get_pw_constant_graph() alt_lines = [ line.copy().set_color(YELLOW) for line in pw_constant_graph[:4] ] for line in alt_lines: line.start_dot = Dot(line.get_start()) line.end_dot = Dot(line.get_end()) VGroup(line.start_dot, line.end_dot).set_color(line.get_color()) line = alt_lines[0] faders = [self.v_graph, self.v_graph_label] for mob in faders: mob.save_state() mob.generate_target() mob.target.fade(0.7) self.play(*list(map(MoveToTarget, faders))) self.play(ShowCreation(pw_constant_graph, run_time = 2)) self.wait() self.play(ShowCreation(line)) self.wait() for new_line in alt_lines[1:]: for mob in line.end_dot, new_line.start_dot, new_line: self.play(Transform( line, mob, run_time = 1./3 )) self.remove(line) self.add(new_line) self.wait(2) line = new_line self.play(FadeOut(line)) self.pw_constant_graph = pw_constant_graph def compute_distance_on_each_interval(self): rect_list = self.get_riemann_rectangles_list( self.v_graph, self.num_riemann_approximations, max_dx = 1, x_min = 0, x_max = 8, ) for rects in rect_list: rects.set_fill(opacity = self.riemann_rect_fill_opacity) flat_rects = self.get_riemann_rectangles( self.get_graph(lambda t : 0), x_min = 0, x_max = 8, dx = 1 ) rects = rect_list[0] rect = rects[1] flat_rects.submobjects[1] = rect.copy() right_brace = Brace(rect, RIGHT) top_brace = Brace(rect, UP) right_brace.label = right_brace.get_text("$7\\frac{\\text{m}}{\\text{s}}$") top_brace.label = top_brace.get_text("$1$s") self.play(FadeIn(rect)) for brace in right_brace, top_brace: self.play( GrowFromCenter(brace), Write(brace.label, run_time = 1), ) brace.add(brace.label) self.wait() self.play( ReplacementTransform( flat_rects, rects, run_time = 2, submobject_mode = "lagged_start", ), Animation(right_brace) ) self.play(*list(map(FadeOut, [top_brace, right_brace]))) self.wait() self.rects = rects self.rect_list = rect_list def approximate_original_curve(self): rects = self.rects self.play( FadeOut(self.pw_constant_graph), *[ m.restore for m in (self.v_graph, self.v_graph_label) ]+[Animation(self.rects)] ) for new_rects in self.rect_list[1:]: self.transform_between_riemann_rects(rects, new_rects) self.wait() def revert_to_specific_approximation(self): rects = self.rects rects.save_state() target_rects = self.rect_list[2] target_rects.set_fill(opacity = 1) ticks = self.get_ticks(target_rects) tick_pair = VGroup(*ticks[4:6]) brace = Brace(tick_pair, DOWN, buff = 0) dt_label = brace.get_text("$dt$", buff = SMALL_BUFF) example_text = TextMobject( "For example, \\\\", "$dt$", "$=0.25$" ) example_text.to_corner(UP+RIGHT) example_text.set_color_by_tex("dt", YELLOW) self.play(ReplacementTransform( rects, target_rects, run_time = 2, submobject_mode = "lagged_start" )) rects.restore() self.wait() self.play( ShowCreation(ticks), FadeOut(self.x_axis.numbers) ) self.play( GrowFromCenter(brace), Write(dt_label) ) self.wait() self.play( FadeIn( example_text, run_time = 2, submobject_mode = "lagged_start", ), ReplacementTransform( dt_label.copy(), example_text.get_part_by_tex("dt") ) ) self.wait() self.rects = rects = target_rects self.ticks = ticks self.dt_brace = brace self.dt_label = dt_label self.dt_example_text = example_text def show_specific_rectangle(self): rects = self.rects rect = rects[4].copy() rect_top = Line( rect.get_corner(UP+LEFT), rect.get_corner(UP+RIGHT), color = self.v_graph.get_color() ) t_vals = [1, 1.25] t_labels = VGroup(*[ TexMobject("t=%s"%str(t)) for t in t_vals ]) t_labels.scale(0.7) t_labels.next_to(rect, DOWN) for vect, label in zip([LEFT, RIGHT], t_labels): label.shift(1.5*vect) label.add(Arrow( label.get_edge_center(-vect), rect.get_corner(DOWN+vect), buff = SMALL_BUFF, tip_length = 0.15, color = WHITE )) v_lines = VGroup() h_lines = VGroup() height_labels = VGroup() for t in t_vals: v_line = self.get_vertical_line_to_graph( t, self.v_graph, color = YELLOW ) y_axis_point = self.graph_origin[0]*RIGHT y_axis_point += v_line.get_end()[1]*UP h_line = DashedLine(v_line.get_end(), y_axis_point) label = TexMobject("%.1f"%v_func(t)) label.scale(0.5) label.next_to(h_line, LEFT, SMALL_BUFF) v_lines.add(v_line) h_lines.add(h_line) height_labels.add(label) circle = Circle(radius = 0.25, color = WHITE) circle.move_to(rect.get_top()) self.play( rects.set_fill, None, 0.25, Animation(rect) ) self.wait() for label in t_labels: self.play(FadeIn(label)) self.wait() for v_line, h_line, label in zip(v_lines, h_lines, height_labels): self.play(ShowCreation(v_line)) self.play(ShowCreation(h_line)) self.play(Write(label, run_time = 1)) self.wait() self.wait() t_label_copy = t_labels[0].copy() self.play( t_label_copy.scale, 1./0.7, t_label_copy.next_to, self.v_graph_label, DOWN+LEFT, 0 ) self.wait() self.play(FadeOut(t_label_copy)) self.wait() self.play(ShowCreation(circle)) self.play(ShowCreation(rect_top)) self.play(FadeOut(circle)) rect.add(rect_top) self.wait() for x in range(2): self.play( rect.stretch_to_fit_height, v_lines[1].get_height(), rect.move_to, rect.get_bottom(), DOWN, Animation(v_lines), run_time = 4, rate_func = there_and_back ) self.play(*list(map(FadeOut, [ group[1] for group in (v_lines, h_lines, height_labels) ]))) self.play( v_lines[0].set_color, RED, rate_func = there_and_back, ) self.wait() area = TextMobject( "7$\\frac{\\text{m}}{\\text{s}}$", "$\\times$", "0.25s", "=", "1.75m" ) area.next_to(rect, RIGHT, LARGE_BUFF) arrow = Arrow( area.get_left(), rect.get_center(), buff = 0, color = WHITE ) area.shift(SMALL_BUFF*RIGHT) self.play( Write(area), ShowCreation(arrow) ) self.wait(2) self.play(*list(map(FadeOut, [ area, arrow, v_lines[0], h_lines[0], height_labels[0], rect, t_labels ]))) def show_v_dt_for_all_rectangles(self): dt_brace_group = VGroup(self.dt_brace, self.dt_label) rects_subset = self.rects[10:20] last_rect = None for rect in rects_subset: brace = Brace(rect, LEFT, buff = 0) v_t = TexMobject("v(t)") v_t.next_to(brace, LEFT, SMALL_BUFF) anims = [ rect.set_fill, None, 1, dt_brace_group.next_to, rect, DOWN, SMALL_BUFF ] if last_rect is not None: anims += [ last_rect.set_fill, None, 0.25, ReplacementTransform(last_brace, brace), ReplacementTransform(last_v_t, v_t), ] else: anims += [ GrowFromCenter(brace), Write(v_t) ] self.play(*anims) self.wait() last_rect = rect last_brace = brace last_v_t = v_t self.v_t = last_v_t self.v_t_brace = last_brace def write_integral_symbol(self): integral = TexMobject( "\\int", "^8", "_0", "v(t)", "\\,dt" ) integral.to_corner(UP+RIGHT) int_copy = integral.get_part_by_tex("int").copy() bounds = list(map(integral.get_part_by_tex, ["0", "8"])) sum_word = TextMobject("``Sum''") sum_word.next_to(integral, DOWN, MED_LARGE_BUFF, LEFT) alt_sum_word = sum_word.copy() int_symbol = TexMobject("\\int") int_symbol.replace(alt_sum_word[1], dim_to_match = 1) alt_sum_word.submobjects[1] = int_symbol self.play(FadeOut(self.dt_example_text)) self.play(Write(integral.get_part_by_tex("int"))) self.wait() self.play(Transform(int_copy, int_symbol)) self.play(Write(alt_sum_word), Animation(int_copy)) self.remove(int_copy) self.play(ReplacementTransform(alt_sum_word, sum_word)) self.wait() for bound in bounds: self.play(Write(bound)) self.wait() for bound, num in zip(bounds, [0, 8]): bound_copy = bound.copy() point = self.coords_to_point(num, 0) self.play( bound_copy.scale, 1.5, bound_copy.next_to, point, DOWN, MED_LARGE_BUFF ) self.play(ApplyWave(self.ticks, direction = UP)) self.wait() for mob, tex in (self.v_t, "v(t)"), (self.dt_label, "dt"): self.play(ReplacementTransform( mob.copy().set_color(YELLOW), integral.get_part_by_tex(tex), run_time = 2 )) self.wait() self.integral = integral self.sum_word = sum_word def roles_of_dt(self): rects = self.rects next_rects = self.rect_list[3] morty = Mortimer().flip() morty.to_corner(DOWN+LEFT) int_dt = self.integral.get_part_by_tex("dt") dt_copy = int_dt.copy() self.play(FadeIn(morty)) self.play( morty.change_mode, "raise_right_hand", morty.look, UP+RIGHT, dt_copy.next_to, morty.get_corner(UP+RIGHT), UP, dt_copy.set_color, YELLOW ) self.play(Blink(morty)) self.play( ReplacementTransform( dt_copy.copy(), int_dt, run_time = 2 ), morty.look_at, int_dt ) self.wait(2) self.play( ReplacementTransform(dt_copy.copy(), self.dt_label), morty.look_at, self.dt_label ) self.play(*[ ApplyMethod( tick.shift, tick.get_height()*UP/2, run_time = 2, rate_func = squish_rate_func( there_and_back, alpha, alpha+0.2, ) ) for tick, alpha in zip( self.ticks, np.linspace(0, 0.8, len(self.ticks)) ) ]) self.wait() #Shrink dt just a bit self.play( morty.change_mode, "pondering", rects.set_fill, None, 0.75, *list(map(FadeOut, [ dt_copy, self.v_t, self.v_t_brace ])) ) rects.align_submobjects(next_rects) for every_other_rect in rects[::2]: every_other_rect.set_fill(opacity = 0) self.play( self.dt_brace.stretch, 0.5, 0, self.dt_brace.move_to, self.dt_brace, LEFT, ReplacementTransform( rects, next_rects, run_time = 2, submobject_mode = "lagged_start" ), Transform( self.ticks, self.get_ticks(next_rects), run_time = 2, submobject_mode = "lagged_start", ), ) self.rects = rects = next_rects self.wait() self.play(Blink(morty)) self.play(*[ ApplyFunction( lambda r : r.shift(0.2*UP).set_fill(None, 1), rect, run_time = 2, rate_func = squish_rate_func( there_and_back, alpha, alpha+0.2, ) ) for rect, alpha in zip( rects, np.linspace(0, 0.8, len(rects)) ) ]+[ morty.change_mode, "thinking", ]) self.wait() self.morty = morty def what_does_sum_approach(self): morty = self.morty rects = self.rects cross = TexMobject("\\times") cross.replace(self.sum_word, stretch = True) cross.set_color(RED) brace = Brace(self.integral, DOWN) dt_to_0 = brace.get_text("$dt \\to 0$") distance_words = TextMobject( "Area", "= Distance traveled" ) distance_words.next_to(rects, UP) arrow = Arrow( distance_words[0].get_bottom(), rects.get_center(), color = WHITE ) self.play(PiCreatureSays( morty, "Why not $\\Sigma$?", target_mode = "sassy" )) self.play(Blink(morty)) self.wait() self.play(Write(cross)) self.wait() self.play( RemovePiCreatureBubble(morty, target_mode = "plain"), *list(map(FadeOut, [ cross, self.sum_word, self.ticks, self.dt_brace, self.dt_label, ])) ) self.play(FadeIn(brace), FadeIn(dt_to_0)) for new_rects in self.rect_list[4:]: rects.align_submobjects(new_rects) for every_other_rect in rects[::2]: every_other_rect.set_fill(opacity = 0) self.play( Transform( rects, new_rects, run_time = 2, submobject_mode = "lagged_start" ), morty.look_at, rects, ) self.wait() self.play( Write(distance_words), ShowCreation(arrow), morty.change_mode, "pondering", morty.look_at, distance_words, ) self.wait() self.play(Blink(morty)) self.wait() self.area_arrow = arrow def label_integral(self): words = TextMobject("``Integral of $v(t)$''") words.to_edge(UP) arrow = Arrow( words.get_right(), self.integral.get_left() ) self.play(Indicate(self.integral)) self.play(Write(words, run_time = 2)) self.play(ShowCreation(arrow)) self.wait() self.play(*[ ApplyFunction( lambda r : r.shift(0.2*UP).set_fill(None, 1), rect, run_time = 3, rate_func = squish_rate_func( there_and_back, alpha, alpha+0.2, ) ) for rect, alpha in zip( self.rects, np.linspace(0, 0.8, len(self.rects)) ) ]+[ Animation(self.area_arrow), self.morty.change_mode, "happy", self.morty.look_at, self.rects, ]) self.wait() ##### def get_pw_constant_graph(self): result = VGroup() for left_x in range(8): xs = [left_x, left_x+1] y = self.v_graph.underlying_function(left_x) line = Line(*[ self.coords_to_point(x, y) for x in xs ]) line.set_color(self.v_graph.get_color()) result.add(line) return result def get_ticks(self, rects): ticks = VGroup(*[ Line( point+self.tick_size*UP/2, point+self.tick_size*DOWN/2 ) for t in np.linspace(0, 8, len(rects)+1) for point in [self.coords_to_point(t, 0)] ]) ticks.set_color(YELLOW) return ticks class DontKnowHowToHandleNonConstant(TeacherStudentsScene): def construct(self): self.play(*[ ApplyMethod(pi.change, "maybe", UP) for pi in self.get_pi_creatures() ]) self.wait(3) class CarJourneyApproximation(Scene): CONFIG = { "n_jumps" : 5, "bottom_words" : "Approximated motion (5 jumps)", } def construct(self): points = [5*LEFT + v for v in (UP, 2*DOWN)] cars = [Car().move_to(point) for point in points] h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS) words = [ TextMobject("Real motion (smooth)").shift(3*UP), TextMobject(self.bottom_words).shift(0.5*DOWN), ] words[1].set_color(GREEN) self.add(h_line, *cars + words) self.wait() self.play(*[ MoveCar( car, point+10*RIGHT, run_time = 5, rate_func = rf ) for car, point, rf in zip(cars, points, [ s_rate_func, self.get_approximated_rate_func(self.n_jumps) ]) ]) self.wait() def get_approximated_rate_func(self, n): new_v_rate_func = lambda t : v_rate_func(np.floor(t*n)/n) max_integral, err = scipy.integrate.quad( v_rate_func, 0, 1 ) def result(t): integral, err = scipy.integrate.quad(new_v_rate_func, 0, t) return integral/max_integral return result class LessWrongCarJourneyApproximation(CarJourneyApproximation): CONFIG = { "n_jumps" : 20, "bottom_words" : "Better approximation (20 jumps)", } class TellMeThatsNotSurprising(TeacherStudentsScene): def construct(self): self.teacher_says( "Tell me that's \\\\ not surprising!", target_mode = "hooray", run_time = 1 ) self.wait(3) class HowDoesThisHelp(TeacherStudentsScene): def construct(self): self.student_says( "How does this help\\textinterrobang", target_mode = "angry", run_time = 1 ) self.change_student_modes( "confused", "angry", "confused", ) self.wait(2) self.teacher_says( "You're right.", target_mode = "shruggie", run_time = 1 ) self.change_student_modes(*["sassy"]*3) self.wait(2) class AreaUnderACurve(GraphScene): CONFIG = { "y_max" : 4, "y_min" : 0, "num_iterations" : 7 } def construct(self): self.setup_axes() graph = self.get_graph(self.func) rect_list = self.get_riemann_rectangles_list( graph, self.num_iterations ) VGroup(*rect_list).set_fill(opacity = 0.8) rects = rect_list[0] self.play(ShowCreation(graph)) self.play(Write(rects)) for new_rects in rect_list[1:]: rects.align_submobjects(new_rects) for every_other_rect in rects[::2]: every_other_rect.set_fill(opacity = 0) self.play(Transform( rects, new_rects, run_time = 2, submobject_mode = "lagged_start" )) self.wait() def func(self, x): return np.sin(x) + 1 class AltAreaUnderCurve(AreaUnderACurve): CONFIG = { "graph_origin" : 2*DOWN, "x_min" : -3, "x_max" : 3, "x_axis_width" : 12, "y_max" : 2, "y_axis_height" : 4, } def func(self, x): return np.exp(-x**2) class Chapter1Wrapper(Chapter2Wrapper): CONFIG = { "title" : "Essence of calculus, chapter 1", } class AreaIsDerivative(PlotVelocity, ReconfigurableScene): CONFIG = { "y_axis_label" : "", "num_rects" : 400, "dT" : 0.25, "variable_point_label" : "T", "area_opacity" : 0.8, } def setup(self): PlotVelocity.setup(self) ReconfigurableScene.setup(self) self.setup_axes() self.add(*self.get_v_graph_and_label()) self.x_axis_label_mob.shift(MED_LARGE_BUFF*DOWN) self.v_graph_label.shift(MED_LARGE_BUFF*DOWN) self.foreground_mobjects = [] def construct(self): self.introduce_variable_area() self.write_integral() self.nudge_input() self.show_rectangle_approximation() def introduce_variable_area(self): area = self.area = self.get_area(0, 6) x_nums = self.x_axis.numbers self.play(Write(area, run_time = 2)) self.play(FadeOut(self.x_axis.numbers)) self.add_T_label(6) self.change_area_bounds( new_t_max = 4, rate_func = there_and_back, run_time = 2 ) self.wait() def write_integral(self): integral = TexMobject("\\int", "^T", "_0", "v(t)", "\\,dt") integral.to_corner(UP+RIGHT) integral.shift(2*LEFT) top_T = integral.get_part_by_tex("T") moving_T = self.T_label_group[0] s_T = TexMobject("s(T)", "= ") s_T.set_color_by_tex("s", DISTANCE_COLOR) s_T.next_to(integral, LEFT) int_arrow, s_arrow = [ Arrow( mob.get_left(), self.area.get_center(), color = WHITE ) for mob in (integral, s_T) ] distance_word = TextMobject("Distance") distance_word.move_to(self.area) self.play(Write(integral)) self.play(ShowCreation(int_arrow)) self.foreground_mobjects.append(int_arrow) self.wait() self.change_area_bounds( new_t_max = 8, rate_func = there_and_back, run_time = 3, ) self.play(Indicate(top_T)) self.play(ReplacementTransform( top_T.copy(), moving_T )) self.change_area_bounds( new_t_max = 3, rate_func = there_and_back, run_time = 3 ) self.wait() self.play(Write(distance_word, run_time = 2)) self.play( ReplacementTransform(int_arrow, s_arrow), FadeIn(s_T) ) self.wait() self.play(FadeOut(distance_word)) self.change_area_bounds(new_t_max = 0, run_time = 2) self.change_area_bounds( new_t_max = 8, rate_func = None, run_time = 7.9, ) self.wait() self.change_area_bounds(new_t_max = 5) self.wait() def nudge_input(self): dark_area = self.area.copy() dark_area.set_fill(BLACK, opacity = 0.5) curr_T = self.x_axis.point_to_number(self.area.get_right()) new_T = curr_T + self.dT rect = Rectangle( stroke_width = 0, fill_color = YELLOW, fill_opacity = 0.75 ) rect.replace( VGroup( VectorizedPoint(self.coords_to_point(new_T, 0)), self.right_v_line, ), stretch = True ) dT_brace = Brace(rect, DOWN, buff = 0) dT_label = dT_brace.get_text("$dT$", buff = SMALL_BUFF) dT_label_group = VGroup(dT_label, dT_brace) ds_label = TexMobject("ds") ds_label.next_to(rect, RIGHT, LARGE_BUFF, UP) ds_label.set_color(DISTANCE_COLOR) ds_arrow = Arrow(ds_label.get_left(), rect.get_left()) ds_arrow.set_color(WHITE) v_brace = Brace(rect, LEFT, buff = SMALL_BUFF) v_T_label = v_brace.get_text("$v(T)$", buff = SMALL_BUFF) self.change_area_bounds(new_t_max = new_T) self.play( FadeIn(dark_area), *list(map(Animation, self.foreground_mobjects)) ) self.play( FadeOut(self.T_label_group), FadeIn(dT_label_group) ) self.wait() self.play(Write(ds_label)) self.play(ShowCreation(ds_arrow)) self.wait(2) self.play(GrowFromCenter(v_brace)) self.play(ReplacementTransform( self.v_graph_label.get_part_by_tex("v").copy(), v_T_label, run_time = 2 )) self.wait() self.play(Indicate(dT_label)) self.wait() self.rect = rect self.dT_label_group = dT_label_group self.v_T_label_group = VGroup(v_T_label, v_brace) self.dark_area = dark_area self.ds_label = ds_label self.ds_arrow = ds_arrow def show_rectangle_approximation(self): formula1 = TexMobject("ds", "=", "v(T)", "dT") formula2 = TexMobject("{ds", "\\over\\,", "dT}", "=", "v(T)") for formula in formula1, formula2: formula.next_to(self.v_graph_label, UP, LARGE_BUFF) formula.set_color_by_tex("ds", DISTANCE_COLOR) self.play( DrawBorderThenFill(self.rect), Animation(self.ds_arrow) ) self.wait() self.play(*[ ReplacementTransform( mob, formula1.get_part_by_tex(tex), run_time = 2 ) for mob, tex in [ (self.ds_label, "ds"), (self.ds_arrow, "="), (self.v_T_label_group[0].copy(), "v(T)"), (self.dT_label_group[0].copy(), "dT"), ] ]) self.wait() self.transition_to_alt_config( dT = self.dT/5.0, transformation_kwargs = {"run_time" : 2}, ) self.wait() self.play(*[ ReplacementTransform( formula1.get_part_by_tex(tex), formula2.get_part_by_tex(tex), ) for tex in ("ds", "=", "v(T)", "dT") ] + [ Write(formula2.get_part_by_tex("over")) ]) self.wait() #### def add_T_label(self, x_val, **kwargs): triangle = RegularPolygon(n=3, start_angle = np.pi/2) triangle.set_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(WHITE, 1) triangle.set_stroke(width = 0) T_label = TexMobject(self.variable_point_label) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph( x_val, self.v_graph, color = YELLOW ) self.play( DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time = 1), **kwargs ) self.T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line def get_area(self, t_min, t_max): numerator = max(t_max - t_min, 0.01) dx = float(numerator) / self.num_rects return self.get_riemann_rectangles( self.v_graph, x_min = t_min, x_max = t_max, dx = dx, stroke_width = 0, ).set_fill(opacity = self.area_opacity) def change_area_bounds(self, new_t_min = None, new_t_max = None, **kwargs): curr_t_min = self.x_axis.point_to_number(self.area.get_left()) curr_t_max = self.x_axis.point_to_number(self.area.get_right()) if new_t_min is None: new_t_min = curr_t_min if new_t_max is None: new_t_max = curr_t_max group = VGroup(self.area, self.right_v_line, self.T_label_group) def update_group(group, alpha): area, v_line, T_label = group t_min = interpolate(curr_t_min, new_t_min, alpha) t_max = interpolate(curr_t_max, new_t_max, alpha) new_area = self.get_area(t_min, t_max) new_v_line = self.get_vertical_line_to_graph( t_max, self.v_graph ) new_v_line.set_color(v_line.get_color()) T_label.move_to(new_v_line.get_bottom(), UP) #Fade close to 0 T_label[0].set_fill(opacity = min(1, t_max)) Transform(area, new_area).update(1) Transform(v_line, new_v_line).update(1) return group self.play( UpdateFromAlphaFunc(group, update_group), *list(map(Animation, self.foreground_mobjects)), **kwargs ) class DirectInterpretationOfDsDt(TeacherStudentsScene): def construct(self): equation = TexMobject("{ds", "\\over\\,", "dT}", "(T)", "=", "v(T)") ds, over, dt, of_T, equals, v = equation equation.next_to(self.get_pi_creatures(), UP, LARGE_BUFF) equation.shift(RIGHT) v.set_color(VELOCITY_COLOR) s_words = TextMobject("Tiny change in", "distance") s_words.next_to(ds, UP+LEFT, LARGE_BUFF) s_words.shift_onto_screen() s_arrow = Arrow(s_words[1].get_bottom(), ds.get_left()) s_words.add(s_arrow) s_words.set_color(DISTANCE_COLOR) t_words = TextMobject("Tiny change in", "time") t_words.next_to(dt, DOWN+LEFT) t_words.to_edge(LEFT) t_arrow = Arrow(t_words[1].get_top(), dt.get_left()) t_words.add(t_arrow) t_words.set_color(TIME_COLOR) self.add(ds, over, dt, of_T) for words, part in (s_words, ds), (t_words, dt): self.play( FadeIn( words, run_time = 2, submobject_mode = "lagged_start", ), self.students[1].change_mode, "raise_right_hand" ) self.play(part.set_color, words.get_color()) self.wait() self.play(Write(VGroup(equals, v))) self.change_student_modes(*["pondering"]*3) self.wait(3) class FindAntiderivative(Antiderivative): def construct(self): self.introduce() self.first_part() self.second_part() self.combine() self.add_plus_C() def introduce(self): q_marks, rhs = functions = self.get_functions("???", "t(8-t)") expanded_rhs = TexMobject("8t - t^2") expanded_rhs.move_to(rhs, LEFT) expanded_rhs.set_color(rhs.get_color()) self.v_part1 = VGroup(*expanded_rhs[:2]) self.v_part2 = VGroup(*expanded_rhs[2:]) for part in self.v_part1, self.v_part2: part.save_state() top_arc, bottom_arc = arcs = self.get_arcs(functions) derivative, antiderivative = words = self.get_arc_labels(arcs) self.add(functions) self.play(*list(map(ShowCreation, arcs))) for word in words: self.play(FadeIn(word, submobject_mode = "lagged_start")) self.wait() self.change_mode("confused") self.wait(2) self.play(*[ ReplacementTransform( rhs[i], expanded_rhs[j], run_time = 2, path_arc = np.pi ) for i, j in enumerate([1, 4, 0, 2, 3, 4]) ]+[ self.pi_creature.change_mode, "hesitant" ]) self.wait() self.q_marks = q_marks self.arcs = arcs self.words = words def first_part(self): four_t_squared, two_t = self.get_functions("4t^2", "2t") four = four_t_squared[0] four.shift(UP) four.set_fill(opacity = 0) t_squared = VGroup(*four_t_squared[1:]) two_t.move_to(self.v_part1, LEFT) self.play(self.v_part2.to_corner, UP+RIGHT) self.play( self.pi_creature.change, "plain", self.v_part1 ) self.play(ApplyWave( self.q_marks, direction = UP, amplitude = SMALL_BUFF )) self.wait(2) self.play( FadeOut(self.q_marks), FadeIn(t_squared), self.v_part1.shift, DOWN+RIGHT, ) self.play(*[ ReplacementTransform( t_squared[i].copy(), two_t[1-i], run_time = 2, path_arc = -np.pi/6. ) for i in (0, 1) ]) self.change_mode("thinking") self.wait() self.play(four.set_fill, YELLOW, 1) self.play(four.shift, DOWN) self.play(FadeOut(two_t)) self.play(self.v_part1.restore) self.play(four.set_color, DISTANCE_COLOR) self.wait(2) self.s_part1 = four_t_squared def second_part(self): self.arcs_copy = self.arcs.copy() self.words_copy = self.words.copy() part1_group = VGroup( self.s_part1, self.v_part1, self.arcs_copy, self.words_copy ) neg_third_t_cubed, three_t_squared = self.get_functions( "- \\frac{1}{3} t^3", "3t^2" ) three_t_squared.move_to(self.v_part1, LEFT) neg = neg_third_t_cubed[0] third = VGroup(*neg_third_t_cubed[1:4]) t_cubed = VGroup(*neg_third_t_cubed[4:]) three = three_t_squared[0] t_squared = VGroup(*three_t_squared[1:]) self.play( part1_group.scale, 0.5, part1_group.to_corner, UP+LEFT, self.pi_creature.change_mode, "plain" ) self.play( self.v_part2.restore, self.v_part2.shift, LEFT ) self.play(FadeIn(self.q_marks)) self.wait() self.play( FadeOut(self.q_marks), FadeIn(t_cubed), self.v_part2.shift, DOWN+RIGHT ) self.play(*[ ReplacementTransform( t_cubed[i].copy(), three_t_squared[j], path_arc = -np.pi/6, run_time = 2, ) for i, j in (0, 1), (1, 0), (1, 2) ]) self.wait() self.play(FadeIn(third)) self.play(FadeOut(three)) self.wait(2) self.play(Write(neg)) self.play( FadeOut(t_squared), self.v_part2.shift, UP+LEFT ) self.wait(2) self.s_part2 = neg_third_t_cubed def combine(self): self.play( self.v_part1.restore, self.v_part2.restore, self.s_part1.scale, 2, self.s_part1.next_to, self.s_part2, LEFT, FadeOut(self.arcs_copy), FadeOut(self.words_copy), run_time = 2, ) self.change_mode("happy") self.wait(2) def add_plus_C(self): s_group = VGroup(self.s_part1, self.s_part2) plus_Cs = [ TexMobject("+%d"%d) for d in range(1, 8) ] for plus_C in plus_Cs: plus_C.set_color(YELLOW) plus_C.move_to(s_group, RIGHT) plus_C = plus_Cs[0] self.change_mode("sassy") self.wait() self.play( s_group.next_to, plus_C.copy(), LEFT, GrowFromCenter(plus_C), ) self.wait() for new_plus_C in plus_Cs[1:]: self.play(Transform(plus_C, new_plus_C)) self.wait() class GraphSPlusC(GraphDistanceVsTime): CONFIG = { "y_axis_label" : "Distance" } def construct(self): self.setup_axes() graph = self.get_graph( s_func, color = DISTANCE_COLOR, x_min = 0, x_max = 8, ) tangent = self.get_secant_slope_group( 6, graph, dx = 0.01 ).secant_line v_line = self.get_vertical_line_to_graph( 6, graph, line_class = DashedLine ) v_line.scale_in_place(2) v_line.set_color(WHITE) graph_label, plus_C = full_label = TexMobject( "s(t) = 4t^2 - \\frac{1}{3}t^3", "+C" ) plus_C.set_color(YELLOW) full_label.next_to(graph.points[-1], DOWN) full_label.to_edge(RIGHT) self.play(ShowCreation(graph)) self.play(FadeIn(graph_label)) self.wait() self.play( graph.shift, UP, run_time = 2, rate_func = there_and_back ) self.play(ShowCreation(tangent)) graph.add(tangent) self.play(ShowCreation(v_line)) self.play( graph.shift, 2*DOWN, run_time = 4, rate_func = there_and_back, ) self.play(Write(plus_C)) self.play( graph.shift, 2*UP, rate_func = there_and_back, run_time = 4, ) self.wait() class LowerBound(AreaIsDerivative): CONFIG = { "graph_origin" : 2.5*DOWN + 6*LEFT } def construct(self): self.add_integral_and_area() self.mention_lower_bound() self.drag_right_endpoint_to_zero() self.write_antiderivative_difference() self.show_alternate_antiderivative_difference() self.add_constant_to_antiderivative() def add_integral_and_area(self): self.area = self.get_area(0, 6) self.integral = self.get_integral("0", "T") self.remove(self.x_axis.numbers) self.add(self.area, self.integral) self.add_T_label(6, run_time = 0) def mention_lower_bound(self): lower_bound = self.integral.get_part_by_tex("0") circle = Circle(color = YELLOW) circle.replace(lower_bound) circle.scale_in_place(3) zero_label = lower_bound.copy() self.play(ShowCreation(circle)) self.play(Indicate(lower_bound)) self.play( zero_label.scale, 1.5, zero_label.next_to, self.graph_origin, DOWN, MED_LARGE_BUFF, FadeOut(circle) ) self.wait() self.zero_label = zero_label def drag_right_endpoint_to_zero(self): zero_integral = self.get_integral("0", "0") zero_integral[1].set_color(YELLOW) zero_int_bounds = list(reversed( zero_integral.get_parts_by_tex("0") )) for bound in zero_int_bounds: circle = Circle(color = YELLOW) circle.replace(bound) circle.scale_in_place(3) bound.circle = circle self.integral.save_state() equals_zero = TexMobject("=0") equals_zero.next_to(zero_integral, RIGHT) equals_zero.set_color(GREEN) self.change_area_bounds(0, 0, run_time = 3) self.play(ReplacementTransform( self.zero_label.copy(), equals_zero )) self.play(Transform(self.integral, zero_integral)) self.wait(2) for bound in zero_int_bounds: self.play(ShowCreation(bound.circle)) self.play(FadeOut(bound.circle)) self.play(*[ ReplacementTransform( bound.copy(), VGroup(equals_zero[1]) ) for bound in zero_int_bounds ]) self.wait(2) self.change_area_bounds(0, 5) self.play( self.integral.restore, FadeOut(equals_zero) ) self.zero_integral = zero_integral def write_antiderivative_difference(self): antideriv_diff = self.get_antiderivative_difference("0", "T") equals, at_T, minus, at_zero = antideriv_diff antideriv_diff_at_eight = self.get_antiderivative_difference("0", "8") at_eight = antideriv_diff_at_eight.left_part integral_at_eight = self.get_integral("0", "8") for part in at_T, at_zero, at_eight: part.brace = Brace(part, DOWN, buff = SMALL_BUFF) part.brace.save_state() antideriv_text = at_T.brace.get_text("Antiderivative", buff = SMALL_BUFF) antideriv_text.set_color(MAROON_B) value_at_eight = at_eight.brace.get_text( "%.2f"%s_func(8) ) happens_to_be_zero = at_zero.brace.get_text(""" Happens to equal 0 """) big_brace = Brace(VGroup(at_T, at_zero)) cancel_text = big_brace.get_text("Cancels when $T=0$") self.play(*list(map(Write, [equals, at_T]))) self.play( GrowFromCenter(at_T.brace), Write(antideriv_text, run_time = 2) ) self.change_area_bounds(0, 5.5, rate_func = there_and_back) self.wait() self.play( ReplacementTransform(at_T.copy(), at_zero), Write(minus) ) self.wait() self.play( ReplacementTransform(at_T.brace, big_brace), ReplacementTransform(antideriv_text, cancel_text) ) self.change_area_bounds(0, 0, run_time = 4) self.wait() self.play( ReplacementTransform(big_brace, at_zero.brace), ReplacementTransform(cancel_text, happens_to_be_zero), ) self.wait(2) self.change_area_bounds(0, 8, run_time = 2) self.play( Transform(self.integral, integral_at_eight), Transform(antideriv_diff, antideriv_diff_at_eight), MaintainPositionRelativeTo(at_zero.brace, at_zero), MaintainPositionRelativeTo(happens_to_be_zero, at_zero.brace), ) self.play( GrowFromCenter(at_eight.brace), Write(value_at_eight) ) self.wait(2) self.play(*list(map(FadeOut, [ at_eight.brace, value_at_eight, at_zero.brace, happens_to_be_zero, ]))) self.antideriv_diff = antideriv_diff def show_alternate_antiderivative_difference(self): new_integral = self.get_integral("1", "7") new_antideriv_diff = self.get_antiderivative_difference("1", "7") numbers = [ TexMobject("%d"%d).next_to( self.coords_to_point(d, 0), DOWN, MED_LARGE_BUFF ) for d in (1, 7) ] tex_mobs = [new_integral]+new_antideriv_diff[1::2]+numbers for tex_mob in tex_mobs: tex_mob.set_color_by_tex("1", RED) tex_mob.set_color_by_tex("7", GREEN) tex_mob.set_color_by_tex("\\frac{1}{3}", WHITE) self.change_area_bounds(1, 7, run_time = 2) self.play( self.T_label_group[0].set_fill, None, 0, *list(map(FadeIn, numbers)) ) self.play( Transform(self.integral, new_integral), Transform(self.antideriv_diff, new_antideriv_diff), ) self.wait(3) for part in self.antideriv_diff[1::2]: self.play(Indicate(part, scale_factor = 1.1)) self.wait() def add_constant_to_antiderivative(self): antideriv_diff = self.antideriv_diff plus_fives = VGroup(*[TexMobject("+5") for i in range(2)]) plus_fives.set_color(YELLOW) for five, part in zip(plus_fives, antideriv_diff[1::2]): five.next_to(part, DOWN) group = VGroup( plus_fives[0], antideriv_diff[2].copy(), plus_fives[1] ) self.play(Write(plus_fives, run_time = 2)) self.wait(2) self.play( group.arrange_submobjects, group.next_to, antideriv_diff, DOWN, MED_LARGE_BUFF ) self.wait() self.play(FadeOut(group, run_time = 2)) self.wait() ##### def get_integral(self, lower_bound, upper_bound): result = TexMobject( "\\int", "^"+upper_bound, "_"+lower_bound, "t(8-t)", "\\,dt" ) result.next_to(self.graph_origin, RIGHT, MED_LARGE_BUFF) result.to_edge(UP) return result def get_antiderivative_difference(self, lower_bound, upper_bound): strings = [] for bound in upper_bound, lower_bound: try: d = int(bound) strings.append("(%d)"%d) except: strings.append(bound) parts = [] for s in strings: part = TexMobject( "\\left(", "4", s, "^2", "-", "\\frac{1}{3}", s, "^3" "\\right))" ) part.set_color_by_tex(s, YELLOW, substring = False) parts.append(part) result = VGroup( TexMobject("="), parts[0], TexMobject("-"), parts[1], ) result.left_part, result.right_part = parts result.arrange_submobjects(RIGHT) result.scale(0.9) result.next_to(self.integral, RIGHT) return result class FundamentalTheorem(GraphScene): CONFIG = { "lower_bound" : 1, "upper_bound" : 7, "lower_bound_color" : RED, "upper_bound_color" : GREEN, "n_riemann_iterations" : 6, } def construct(self): self.add_graph_and_integral() self.show_f_dx_sum() self.show_rects_approaching_area() self.write_antiderivative() self.write_fundamental_theorem_of_calculus() self.show_integral_considering_continuum() self.show_antiderivative_considering_bounds() def add_graph_and_integral(self): self.setup_axes() integral = TexMobject("\\int", "^b", "_a", "f(x)", "\\,dx") integral.next_to(ORIGIN, LEFT) integral.to_edge(UP) integral.set_color_by_tex("a", self.lower_bound_color) integral.set_color_by_tex("b", self.upper_bound_color) graph = self.get_graph( lambda x : -0.01*x*(x-3)*(x-6)*(x-12) + 3, ) self.add(integral, graph) self.graph = graph self.integral = integral self.bound_labels = VGroup() self.v_lines = VGroup() for bound, tex in (self.lower_bound, "a"), (self.upper_bound, "b"): label = integral.get_part_by_tex(tex).copy() label.scale(1.5) label.next_to(self.coords_to_point(bound, 0), DOWN) v_line = self.get_vertical_line_to_graph( bound, graph, color = label.get_color() ) self.bound_labels.add(label) self.v_lines.add(v_line) self.add(label, v_line) def show_f_dx_sum(self): kwargs = { "x_min" : self.lower_bound, "x_max" : self.upper_bound, "fill_opacity" : 0.75, "stroke_width" : 0.25, } low_opacity = 0.25 start_rect_index = 3 num_shown_sum_steps = 5 last_rect_index = start_rect_index + num_shown_sum_steps + 1 self.rect_list = self.get_riemann_rectangles_list( self.graph, self.n_riemann_iterations, **kwargs ) rects = self.rects = self.rect_list[0] rects.save_state() start_rect = rects[start_rect_index] f_brace = Brace(start_rect, LEFT, buff = 0) dx_brace = Brace(start_rect, DOWN, buff = 0) f_brace.label = f_brace.get_text("$f(x)$") dx_brace.label = dx_brace.get_text("$dx$") flat_rects = self.get_riemann_rectangles( self.get_graph(lambda x : 0), dx = 0.5, **kwargs ) self.transform_between_riemann_rects( flat_rects, rects, replace_mobject_with_target_in_scene = True, ) self.play(*[ ApplyMethod( rect.set_fill, None, 1 if rect is start_rect else low_opacity ) for rect in rects ]) self.play(*it.chain( list(map(GrowFromCenter, [f_brace, dx_brace])), list(map(Write, [f_brace.label, dx_brace.label])), )) self.wait() for i in range(start_rect_index+1, last_rect_index): self.play( rects[i-1].set_fill, None, low_opacity, rects[i].set_fill, None, 1, f_brace.set_height, rects[i].get_height(), f_brace.next_to, rects[i], LEFT, 0, dx_brace.next_to, rects[i], DOWN, 0, *[ MaintainPositionRelativeTo(brace.label, brace) for brace in (f_brace, dx_brace) ] ) self.wait() self.play(*it.chain( list(map(FadeOut, [ f_brace, dx_brace, f_brace.label, dx_brace.label ])), [rects.set_fill, None, kwargs["fill_opacity"]] )) def show_rects_approaching_area(self): for new_rects in self.rect_list: self.transform_between_riemann_rects( self.rects, new_rects ) def write_antiderivative(self): deriv = TexMobject( "{d", "F", "\\over\\,", "dx}", "(x)", "=", "f(x)" ) deriv_F = deriv.get_part_by_tex("F") deriv.next_to(self.integral, DOWN, MED_LARGE_BUFF) rhs = TexMobject(*"=F(b)-F(a)") rhs.set_color_by_tex("a", self.lower_bound_color) rhs.set_color_by_tex("b", self.upper_bound_color) rhs.next_to(self.integral, RIGHT) self.play(Write(deriv)) self.wait(2) self.play(*it.chain( [ ReplacementTransform(deriv_F.copy(), part) for part in rhs.get_parts_by_tex("F") ], [ Write(VGroup(*rhs.get_parts_by_tex(tex))) for tex in "=()-" ] )) for tex in "b", "a": self.play(ReplacementTransform( self.integral.get_part_by_tex(tex).copy(), rhs.get_part_by_tex(tex) )) self.wait() self.wait(2) self.deriv = deriv self.rhs = rhs def write_fundamental_theorem_of_calculus(self): words = TextMobject(""" Fundamental theorem of calculus """) words.to_edge(RIGHT) self.play(Write(words, lag_factor = 3)) self.wait() def show_integral_considering_continuum(self): self.play(*[ ApplyMethod(mob.set_fill, None, 0.2) for mob in (self.deriv, self.rhs) ]) self.play( self.rects.restore, run_time = 3, rate_func = there_and_back ) self.wait() for x in range(2): self.play(*[ ApplyFunction( lambda m : m.shift(MED_SMALL_BUFF*UP).set_fill(opacity = 1), rect, run_time = 3, rate_func = squish_rate_func( there_and_back, alpha, alpha+0.2 ) ) for rect, alpha in zip( self.rects, np.linspace(0, 0.8, len(self.rects)) ) ]) self.wait() def show_antiderivative_considering_bounds(self): self.play( self.integral.set_fill, None, 0.5, self.deriv.set_fill, None, 1, self.rhs.set_fill, None, 1, ) for label, line in reversed(list(zip(self.bound_labels, self.v_lines))): new_line = line.copy().set_color(YELLOW) label.save_state() self.play(label.set_color, YELLOW) self.play(ShowCreation(new_line)) self.play(ShowCreation(line)) self.remove(new_line) self.play(label.restore) self.wait() self.play(self.integral.set_fill, None, 1) self.wait(3) class LetsRecap(TeacherStudentsScene): def construct(self): self.teacher_says( "Let's recap", target_mode = "hesitant", ) self.change_student_modes(*["happy"]*3) self.wait(3) class NegativeArea(GraphScene): CONFIG = { "x_axis_label" : "Time", "y_axis_label" : "Velocity", "graph_origin" : 1.5*DOWN + 5*LEFT, "y_min" : -3, "y_max" : 7, "small_dx" : 0.01, "sample_input" : 5, } def construct(self): self.setup_axes() self.add_graph_and_area() self.write_negative_area() self.show_negative_point() self.show_car_going_backwards() self.write_v_dt() self.show_rectangle() self.write_signed_area() def add_graph_and_area(self): graph = self.get_graph( lambda x : -0.02*(x+1)*(x-3)*(x-7)*(x-10), x_min = 0, x_max = 8, color = VELOCITY_COLOR ) area = self.get_riemann_rectangles( graph, x_min = 0, x_max = 8, dx = self.small_dx, start_color = BLUE_D, end_color = BLUE_D, fill_opacity = 0.75, stroke_width = 0, ) self .play( ShowCreation(graph), FadeIn( area, run_time = 2, submobject_mode = "lagged_start", ) ) self.graph = graph self.area = area def write_negative_area(self): words = TextMobject("Negative area") words.set_color(RED) words.next_to( self.coords_to_point(7, -2), RIGHT, ) arrow = Arrow(words, self.coords_to_point( self.sample_input, -1, )) self.play( Write(words, run_time = 2), ShowCreation(arrow) ) self.wait(2) self.play(*list(map(FadeOut, [self.area, arrow]))) self.negative_area_words = words def show_negative_point(self): v_line = self.get_vertical_line_to_graph( self.sample_input, self.graph, color = RED ) self.play(ShowCreation(v_line)) self.wait() self.v_line = v_line def show_car_going_backwards(self): car = Car() start_point = 3*RIGHT + 2*UP end_point = start_point + LEFT nudged_end_point = end_point + MED_SMALL_BUFF*LEFT car.move_to(start_point) arrow = Arrow(RIGHT, LEFT, color = RED) arrow.next_to(car, UP+LEFT) arrow.shift(MED_LARGE_BUFF*RIGHT) self.play(FadeIn(car)) self.play(ShowCreation(arrow)) self.play(MoveCar( car, end_point, moving_forward = False, run_time = 3 )) self.wait() ghost_car = car.copy().fade() right_nose_line = self.get_car_nose_line(car) self.play(ShowCreation(right_nose_line)) self.add(ghost_car) self.play(MoveCar( car, nudged_end_point, moving_forward = False )) left_nose_line = self.get_car_nose_line(car) self.play(ShowCreation(left_nose_line)) self.nose_lines = VGroup(left_nose_line, right_nose_line) self.car = car self.ghost_car = ghost_car def write_v_dt(self): brace = Brace(self.nose_lines, DOWN, buff = 0) equation = TexMobject("ds", "=", "v(t)", "dt") equation.next_to(brace, DOWN, SMALL_BUFF, LEFT) equation.set_color_by_tex("ds", DISTANCE_COLOR) equation.set_color_by_tex("dt", TIME_COLOR) negative = TextMobject("Negative") negative.set_color(RED) negative.next_to(equation.get_corner(UP+RIGHT), UP, LARGE_BUFF) ds_arrow, v_arrow = arrows = VGroup(*[ Arrow( negative.get_bottom(), equation.get_part_by_tex(tex).get_top(), color = RED, ) for tex in ("ds", "v(t)") ]) self.play( GrowFromCenter(brace), Write(equation) ) self.wait() self.play(FadeIn(negative)) self.play(ShowCreation(v_arrow)) self.wait(2) self.play(ReplacementTransform( v_arrow.copy(), ds_arrow )) self.wait(2) self.ds_equation = equation self.negative_word = negative self.negative_word_arrows = arrows def show_rectangle(self): rect_list = self.get_riemann_rectangles_list( self.graph, x_min = 0, x_max = 8, n_iterations = 6, start_color = BLUE_D, end_color = BLUE_D, fill_opacity = 0.75, ) rects = rect_list[0] rect = rects[len(rects)*self.sample_input//8] dt_brace = Brace(rect, UP, buff = 0) v_brace = Brace(rect, LEFT, buff = 0) dt_label = dt_brace.get_text("$dt$", buff = SMALL_BUFF) dt_label.set_color(YELLOW) v_label = v_brace.get_text("$v(t)$", buff = SMALL_BUFF) v_label.add_background_rectangle() self.play(FadeOut(self.v_line), FadeIn(rect)) self.play( GrowFromCenter(dt_brace), GrowFromCenter(v_brace), Write(dt_label), Write(v_label), ) self.wait(2) self.play(*it.chain( [FadeIn(r) for r in rects if r is not rect], list(map(FadeOut, [ dt_brace, v_brace, dt_label, v_label ])) )) self.wait() for new_rects in rect_list[1:]: self.transform_between_riemann_rects(rects, new_rects) self.wait() def write_signed_area(self): words = TextMobject("``Signed area''") words.next_to(self.coords_to_point(self.sample_input, 0), UP) symbols = VGroup(*[ TexMobject(sym).move_to(self.coords_to_point(*coords)) for sym, coords in [ ("+", (1, 2)), ("-", (5, -1)), ("+", (7.6, 0.5)), ] ]) self.play(Write(words)) self.play(Write(symbols)) self.wait() #### def get_car_nose_line(self, car): line = DashedLine(car.get_top(), car.get_bottom()) line.move_to(car.get_right()) return line class NextVideo(TeacherStudentsScene): def construct(self): series = VideoSeries() series.to_edge(UP) next_video = series[8] integral = TexMobject("\\int") integral.next_to(next_video, DOWN, LARGE_BUFF) self.play(FadeIn(series, submobject_mode = "lagged_start")) self.play( next_video.set_color, YELLOW, next_video.shift, next_video.get_height()*DOWN/2, self.teacher.change_mode, "raise_right_hand" ) self.play(Write(integral)) self.wait(5) class Chapter8PatreonThanks(PatreonThanks): CONFIG = { "specific_patrons" : [ "Ali Yahya", "CrypticSwarm", "Kaustuv DeBiswas", "Kathryn Schmiedicke", "Karan Bhargava", "Ankit Agarwal", "Yu Jun", "Dave Nicponski", "Damion Kistler", "Juan Benet", "Othman Alikhan", "Markus Persson", "Dan Buchoff", "Derek Dai", "Joseph John Cox", "Luc Ritchie", "Robert Teed", "Jason Hise", "Meshal Alshammari", "Bernd Sing", "Nils Schneider", "James Thornton", "Mustafa Mahdi", "Jonathan Eppele", "Mathew Bramson", "Jerry Ling", "Mark Govea", "Vecht", "Shimin Kuang", "Rish Kundalia", "Achille Brighton", "Ripta Pasay", ] } class Thumbnail(Chapter1Thumbnail): CONFIG = { "x_axis_label" : "", "y_axis_label" : "", "graph_origin" : 1.5*DOWN + 4*LEFT, "y_axis_height" : 5, "x_max" : 5, "x_axis_width" : 11, } def construct(self): self.setup_axes() self.remove(*self.x_axis.numbers) self.remove(*self.y_axis.numbers) graph = self.get_graph(self.func) rects = self.get_riemann_rectangles( graph, x_min = 0, x_max = 4, dx = 0.25, ) words = TextMobject("Integrals") words.set_width(8) words.to_edge(UP) self.add(graph, rects, words)