From 5300bf24d2d59e1966ecabeed2350e9af56fe949 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Fri, 14 Apr 2017 16:15:39 -0700 Subject: [PATCH] Preliminary end to eoc8 --- eoc/chapter2.py | 5 + eoc/chapter8.py | 249 +++++++++++++++++++++++++++++++++++++++++++-- eoc/graph_scene.py | 17 +++- helpers.py | 3 + 4 files changed, 262 insertions(+), 12 deletions(-) diff --git a/eoc/chapter2.py b/eoc/chapter2.py index e8ad119a..17596dee 100644 --- a/eoc/chapter2.py +++ b/eoc/chapter2.py @@ -99,10 +99,15 @@ class Car(SVGMobject): return VGroup(self[1][1], self[1][3]) class MoveCar(ApplyMethod): + CONFIG = { + "moving_forward" : True, + } def __init__(self, car, target_point, **kwargs): ApplyMethod.__init__(self, car.move_to, target_point, **kwargs) displacement = self.target_mobject.get_right()-self.starting_mobject.get_right() distance = np.linalg.norm(displacement) + if not self.moving_forward: + distance *= -1 tire_radius = car.get_tires()[0].get_width()/2 self.total_tire_radians = -distance/tire_radius diff --git a/eoc/chapter8.py b/eoc/chapter8.py index 799594eb..f323d77d 100644 --- a/eoc/chapter8.py +++ b/eoc/chapter8.py @@ -1429,6 +1429,15 @@ class LessWrongCarJourneyApproximation(CarJourneyApproximation): "n_jumps" : 20, } +class TellMeThatsNotSurprising(TeacherStudentsScene): + def construct(self): + self.teacher_says( + "Tell me that's \\\\ not surprising!", + target_mode = "hooray", + run_time = 1 + ) + self.dither(3) + class HowDoesThisHelp(TeacherStudentsScene): def construct(self): self.student_says( @@ -1763,7 +1772,6 @@ class AreaIsDerivative(PlotVelocity, ReconfigurableScene): **kwargs ) - class DirectInterpretationOfDsDt(TeacherStudentsScene): def construct(self): equation = TexMobject("{ds", "\\over\\,", "dT}", "(T)", "=", "v(T)") @@ -2473,12 +2481,239 @@ class FundamentalTheorem(GraphScene): self.play(self.integral.set_fill, None, 1) self.dither(3) - - - - - - +class LetsRecap(TeacherStudentsScene): + def construct(self): + self.teacher_says( + "Let's recap", + target_mode = "hesitant", + ) + self.change_student_modes(*["happy"]*3) + self.dither(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.highlight(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.dither(2) + self.play(*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.dither() + 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.dither() + 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.highlight_by_tex("ds", DISTANCE_COLOR) + equation.highlight_by_tex("dt", TIME_COLOR) + + negative = TextMobject("Negative") + negative.highlight(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.dither() + self.play(FadeIn(negative)) + self.play(ShowCreation(v_arrow)) + self.dither(2) + self.play(ReplacementTransform( + v_arrow.copy(), + ds_arrow + )) + self.dither(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.highlight(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.dither(2) + self.play(*it.chain( + [FadeIn(r) for r in rects if r is not rect], + map(FadeOut, [ + dt_brace, v_brace, dt_label, v_label + ]) + )) + self.dither() + for new_rects in rect_list[1:]: + self.transform_between_riemann_rects(rects, new_rects) + self.dither() + + 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.dither() + + #### + + 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.highlight, YELLOW, + next_video.shift, next_video.get_height()*DOWN/2, + self.teacher.change_mode, "raise_right_hand" + ) + self.play(Write(integral)) + self.dither(5) diff --git a/eoc/graph_scene.py b/eoc/graph_scene.py index 86011e54..7af36ad7 100644 --- a/eoc/graph_scene.py +++ b/eoc/graph_scene.py @@ -196,11 +196,15 @@ class GraphScene(Scene): stroke_width = 1, fill_opacity = 1, start_color = BLUE, - end_color = GREEN): + end_color = GREEN, + show_signed_area = True, + ): x_min = x_min if x_min is not None else self.x_min x_max = x_max if x_max is not None else self.x_max rectangles = VGroup() - for x in np.arange(x_min, x_max, dx): + x_range = np.arange(x_min, x_max, dx) + colors = color_gradient([start_color, end_color], len(x_range)) + for x, color in zip(x_range, colors): if input_sample_type == "left": sample_input = x elif input_sample_type == "right": @@ -216,10 +220,13 @@ class GraphScene(Scene): rect = Rectangle() rect.replace(points, stretch = True) - rect.set_fill(opacity = fill_opacity) + if graph_point[1] < self.graph_origin[1] and show_signed_area: + fill_color = invert_color(color) + else: + fill_color = color + rect.set_fill(fill_color, opacity = fill_opacity) + rect.set_stroke(BLACK, width = stroke_width) rectangles.add(rect) - rectangles.gradient_highlight(start_color, end_color) - rectangles.set_stroke(BLACK, width = stroke_width) return rectangles def get_riemann_rectangles_list( diff --git a/helpers.py b/helpers.py index 3e085957..758a05e4 100644 --- a/helpers.py +++ b/helpers.py @@ -118,6 +118,9 @@ def rgb_to_color(rgb): except: return Color(WHITE) +def invert_color(color): + return rgb_to_color(1.0 - color_to_rgb(color)) + def color_to_int_rgb(color): return (255*color_to_rgb(color)).astype('uint8')