diff --git a/eoc/chapter1.py b/eoc/chapter1.py index 1590237c..e7ee2116 100644 --- a/eoc/chapter1.py +++ b/eoc/chapter1.py @@ -2582,16 +2582,17 @@ class PatreonThanks(Scene): "Kirk Werklund", "Ripta Pasay", "Felipe Diniz", - ] + ], + "max_patrons_height" : 2*SPACE_HEIGHT - 1, } def construct(self): morty = Mortimer() morty.next_to(ORIGIN, DOWN) n_patrons = len(self.specific_patrons) - special_thanks = TextMobject("Special thanks to:") + special_thanks = TextMobject("Special thanks") special_thanks.highlight(YELLOW) - special_thanks.shift(2*UP) + special_thanks.to_edge(UP) left_patrons = VGroup(*map(TextMobject, self.specific_patrons[:n_patrons/2] @@ -2599,10 +2600,26 @@ class PatreonThanks(Scene): right_patrons = VGroup(*map(TextMobject, self.specific_patrons[n_patrons/2:] )) + for patrons in left_patrons, right_patrons: + patrons.arrange_submobjects( + DOWN, aligned_edge = LEFT, + buff = 1.5*MED_BUFF + ) + all_patrons = VGroup(left_patrons, right_patrons) + if all_patrons.get_height() > self.max_patrons_height: + all_patrons.scale_to_fit_height(self.max_patrons_height) for patrons, vect in (left_patrons, LEFT), (right_patrons, RIGHT): - patrons.arrange_submobjects(DOWN, aligned_edge = LEFT) - patrons.next_to(special_thanks, DOWN) - patrons.to_edge(vect, buff = LARGE_BUFF) + patrons.to_edge(vect, buff = MED_BUFF) + + # shift_distance = max( + # 0, 1-SPACE_HEIGHT-all_patrons.get_bottom()[1] + # ) + # velocity = shift_distance/8 + # def get_shift_anim(): + # return ApplyMethod( + # all_patrons.shift, velocity*UP, + # rate_func = None + # ) self.play(morty.change_mode, "gracious") self.play(Write(special_thanks, run_time = 1)) @@ -2617,7 +2634,9 @@ class PatreonThanks(Scene): self.play(Blink(morty)) for patrons in left_patrons, right_patrons: for index in 0, -1: - self.play(morty.look_at, patrons[index]) + self.play( + morty.look_at, patrons[index], + ) self.dither() class Thumbnail(CircleScene): diff --git a/eoc/chapter2.py b/eoc/chapter2.py index 3db2189d..2f9d4d96 100644 --- a/eoc/chapter2.py +++ b/eoc/chapter2.py @@ -24,7 +24,7 @@ from camera import Camera from mobject.svg_mobject import * from mobject.tex_mobject import * -from eoc.chapter1 import OpeningQuote +from eoc.chapter1 import OpeningQuote, PatreonThanks from eoc.graph_scene import * DISTANCE_COLOR = BLUE @@ -172,8 +172,21 @@ class Chapter2OpeningQuote(OpeningQuote): class Introduction(TeacherStudentsScene): def construct(self): + goals = TextMobject( + "Goals: ", + "1) Learn derivatives", + ", 2) Avoid paradoxes.", + arg_separator = "" + ) + goals[1].highlight(MAROON_B) + goals[2].highlight(RED) + goals[2][0].highlight(WHITE) + goals.to_edge(UP) + self.add(*goals[:2]) + self.student_says( - "What is a derivative?" + "What is a derivative?", + run_time = 2 ) self.play(self.get_teacher().change_mode, "happy") self.dither() @@ -183,24 +196,24 @@ class Introduction(TeacherStudentsScene): target_mode = "well" ) self.change_student_modes(None, "pondering", "thinking") - self.dither() + self.play(Write(goals[2], run_time = 2)) self.change_student_modes("erm") self.student_says( - "Doesn't the derivative measure\\\\", - "instantaneous rate of change", "?", + "Instantaneous rate of change", "?", student_index = 0, ) self.dither() bubble = self.get_students()[0].bubble - phrase = bubble.content[1] + 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, - FadeOut(bubble), - FadeOut(bubble.content), *it.chain(*[ [ pi.change_mode, mode, @@ -247,7 +260,7 @@ class Introduction(TeacherStudentsScene): clock.copy().next_to, instantaneous_description, DOWN, get_clock_anim(3) ) - self.play(get_clock_anim(6)) + self.play(get_clock_anim(12)) class FathersOfCalculus(Scene): CONFIG = { @@ -584,6 +597,7 @@ class GraphCarTrajectory(GraphScene): for graph_func in graph_funcs: new_graph = self.graph_function( graph_func, + color = DISTANCE_COLOR, is_main_graph = False ) self.remove(new_graph) @@ -1513,6 +1527,18 @@ class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative): self.play(ShowCreation(circle)) self.dither() +class UseOfDImpliesApproaching(TeacherStudentsScene): + def construct(self): + statement = TextMobject(""" + Using ``$d$'' + announces that + $dt \\to 0$ + """) + VGroup(*statement[-4:-2]).highlight(TIME_COLOR) + self.teacher_says(statement) + self.change_student_modes(*["pondering"]*3) + self.dither(4) + class LeadIntoASpecificExample(TeacherStudentsScene, SecantLineToTangentLine): def setup(self): TeacherStudentsScene.setup(self) @@ -1799,10 +1825,10 @@ class TCubedExample(SecantLineToTangentLine): new_exp = TexMobject("2").replace(faders[-1], dim_to_match = 1) self.play( faders.highlight, BLACK, - run_time = 3, - submobject_mode = "lagged_start" + FadeIn(new_exp), + run_time = 2, ) - self.play(FadeIn(new_exp)) + self.dither() terms[3].add(new_exp) shift_val = 0.4*DOWN self.play( @@ -2020,19 +2046,430 @@ class ContrastConcreteDtWithLimit(Scene): r_text = r_brace.get_text("Simple") r_text.highlight(GREEN) - self.add(r_formula, r_brace, r_text, l_formula, l_brace, l_text) - - - - - - - - - - - - + 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.dither(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_submobjects(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(*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.dither(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 = None), + UpdateFromFunc(h_line, h_line_update), + UpdateFromFunc(v_line, v_line_update), + run_time = 5 + ) + self.play(*map(FadeOut, [h_line, v_line])) + + self.label_graph( + graph, + label = "s(t) = t^3", + proportion = 0.8, + direction = RIGHT, + buff = SMALL_BUFF + ) + self.dither() + + self.car = car + + def ask_question(self): + question = TextMobject( + "At time $t=0$,", + "is \\\\ the car moving?" + ) + VGroup(*question[0][-4:-1]).highlight(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.dither() + self.play(Write(question[1])) + self.play(ShowCreation(arrow)) + self.dither(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]).highlight(DISTANCE_COLOR) + VGroup(*derivative[0][3:5]).highlight(TIME_COLOR) + derivative[1][3].highlight(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.dither() + self.play(FadeIn(derivative[1])) + self.play(*map(FadeIn, derivative[2:])) + self.dither(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.dither(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.dither(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.highlight, YELLOW, + rate_func = there_and_back, + run_time = 1.5 + ) + self.dither(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.dither() + self.play( + self.tangent_line.rotate_in_place, np.pi/24, + rate_func = wiggle, + run_time = 1 + ) + self.play(Blink(morty)) + self.dither() + +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.highlight(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.highlight(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.dither() + + def show_ratios(self): + ratios = [ + self.get_ratio(n) + for n in range(1, 5) + ] + ratio = ratios[0] + self.play(FadeIn(ratio)) + self.dither(2) + for new_ratio in ratios[1:]: + self.play(Transform(ratio, new_ratio)) + self.dither() + + 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].highlight(DISTANCE_COLOR) + result[3].highlight(TIME_COLOR) + result[5].highlight(VELOCITY_COLOR) + + return result + +class NextVideos(TeacherStudentsScene): + def construct(self): + series = VideoSeries() + series.scale_to_fit_width(2*SPACE_WIDTH - 1) + series.to_edge(UP) + series[1].highlight(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.dither(2) + self.change_student_modes(*["thinking"]*3) + self.dither(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", + ] + }