From cffc75d1a9ed262fdb963e70ec0076aeb26eace0 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 21 Mar 2017 15:53:41 -0700 Subject: [PATCH] Preliminary end to exp_footnote --- eoc/exp_footnote.py | 249 ++++++++++++++++++++++++++++++++++++++------ eoc/graph_scene.py | 1 - topics/functions.py | 4 +- topics/objects.py | 3 +- 4 files changed, 224 insertions(+), 33 deletions(-) diff --git a/eoc/exp_footnote.py b/eoc/exp_footnote.py index 0a07e95b..a8edd361 100644 --- a/eoc/exp_footnote.py +++ b/eoc/exp_footnote.py @@ -25,19 +25,30 @@ from camera import Camera from mobject.svg_mobject import * from mobject.tex_mobject import * +from topics.common_scenes import OpeningQuote + from eoc.graph_scene import * +class ExpFootnoteOpeningQuote(OpeningQuote): + CONFIG = { + "quote" : [ + "Who has not be amazed to learn that the function", + "$y = e^x$,", "like a phoenix rising again from its own", + "ashes, is its own derivative?", + ], + "highlighted_quote_terms" : { + "$y = e^x$" : MAROON_B + }, + "author" : "Francois le Lionnais" + } + class LastVideo(TeacherStudentsScene): def construct(self): series = VideoSeries() series.to_edge(UP) last_video = series[2] - next_video = series[3] - last_video_color = last_video[0].get_fill_color() - early_videos = VGroup(*series[:3]) - later_videos = VGroup(*series[3:]) - this_video = VideoIcon().scale(0.5) - this_video.move_to(VGroup(last_video, next_video), DOWN) + last_video.save_state() + this_video = series[3] known_formulas = VGroup(*map(TexMobject, [ "\\frac{d(x^n)}{dx} = nx^{n-1}", @@ -69,32 +80,20 @@ class LastVideo(TeacherStudentsScene): ) self.dither(2) self.play(known_formulas.replace, last_video) - last_video.add(known_formulas) - this_video_copy = this_video.copy() + self.play(last_video_brace.next_to, this_video, DOWN) self.play( - early_videos.stretch_to_fit_width, - early_videos.get_width() - this_video_copy.get_width(), - early_videos.next_to, this_video_copy, LEFT, SMALL_BUFF, DOWN, - later_videos.stretch_to_fit_width, - later_videos.get_width() - this_video_copy.get_width(), - later_videos.next_to, this_video_copy, RIGHT, SMALL_BUFF, DOWN, - last_video_brace.stretch_to_fit_width, - this_video_copy.get_width(), - last_video_brace.next_to, this_video_copy, DOWN, SMALL_BUFF, - GrowFromCenter(this_video) - ) - self.play( - last_video.highlight, last_video_color, + last_video.restore, this_video.highlight, YELLOW ) - self.play( - FadeOut(self.get_students()[-1].bubble), + self.play( exp_question.next_to, last_video_brace, DOWN, - *[ - ApplyMethod(pi.change_mode, "pondering") - for pi in self.get_students() - ] + FadeOut(self.get_students()[-1].bubble), ) + self.change_student_modes( + *["pondering"]*3, + look_at_arg = exp_question + ) + self.dither() class PopulationSizeGraphVsPopulationMassGraph(Scene): def construct(self): @@ -476,6 +475,131 @@ class DoublingPopulation(PiCreatureScene): return top_words, bottom_words +class GraphOfTwoToT(GraphScene): + CONFIG = { + "x_axis_label" : "$t$", + "y_axis_label" : "$M$", + "x_labeled_nums" : range(1, 7), + "y_labeled_nums" : range(8, 40, 8), + "x_max" : 6, + "y_min" : 0, + "y_max" : 32, + "y_tick_frequency" : 2, + "graph_origin" : 2.5*DOWN + 5*LEFT, + } + def construct(self): + self.setup_axes() + example_t = 3 + graph = self.get_graph(lambda t : 2**t, color = BLUE_C) + self.graph = graph + graph_label = self.get_graph_label( + graph, "M(t) = 2^t", + direction = LEFT, + ) + label_group = self.get_label_group(example_t) + v_line, brace, height_label, ss_group, slope_label = label_group + self.animate_secant_slope_group_change( + ss_group, + target_dx = 1, + run_time = 0 + ) + self.remove(ss_group) + + #Draw graph and revert to tangent + self.play(ShowCreation(graph)) + self.play(Write(graph_label)) + self.dither() + self.play(Write(ss_group)) + self.dither() + for target_dx in 0.01, 1, 0.01: + self.animate_secant_slope_group_change( + ss_group, + target_dx = target_dx + ) + self.dither() + + #Mark up with values + + self.play(ShowCreation(v_line)) + self.play( + GrowFromCenter(brace), + Write(height_label, run_time = 1) + ) + self.dither() + self.play( + FadeIn( + slope_label, + run_time = 4, + submobject_mode = "lagged_start" + ), + ReplacementTransform( + height_label.copy(), + slope_label.get_part_by_tex("2^") + ) + ) + self.dither() + + #Vary value + threes = VGroup(height_label[1], slope_label[2][1]) + ts = VGroup(*[ + TexMobject("t").highlight(YELLOW).scale(0.75).move_to(three) + for three in threes + ]) + self.play(Transform(threes, ts)) + + alt_example_t = example_t+1 + def update_label_group(group, alpha): + t = interpolate(example_t, alt_example_t, alpha) + new_group = self.get_label_group(t) + Transform(group, new_group).update(1) + for t, three in zip(ts, threes): + t.move_to(three) + Transform(threes, ts).update(1) + return group + + self.play(UpdateFromAlphaFunc( + label_group, update_label_group, + run_time = 3, + )) + self.play(UpdateFromAlphaFunc( + label_group, update_label_group, + run_time = 3, + rate_func = lambda t : 1 - 1.5*smooth(t) + )) + + def get_label_group(self, t): + graph = self.graph + + v_line = self.get_vertical_line_to_graph( + t, graph, + color = YELLOW, + ) + brace = Brace(v_line, RIGHT) + height_label = brace.get_text("$2^%d$"%t) + + ss_group = self.get_secant_slope_group( + t, graph, dx = 0.01, + df_label = "dM", + dx_label = "dt", + dx_line_color = GREEN, + secant_line_color = RED, + ) + slope_label = TexMobject( + "\\text{Slope}", "=", + "2^%d"%t, + "(%.7f\\dots)"%np.log(2) + ) + slope_label.next_to( + ss_group.secant_line.point_from_proportion(0.65), + DOWN+RIGHT, + buff = 0 + ) + slope_label.highlight_by_tex("Slope", RED) + return VGroup( + v_line, brace, height_label, + ss_group, slope_label + ) + class AnalyzeExponentRatio(PiCreatureScene): CONFIG = { "base" : 2, @@ -698,6 +822,12 @@ class AnalyzeExponentRatio(PiCreatureScene): self.change_mode("confused") self.dither() + #Indicate distinction between dt group and t group again + for mob in limit_term, extracted_two_to_t: + self.play(FocusOn(mob)) + self.play(Indicate(mob)) + self.dither() + #hold_final_value derivative = VGroup( lhs, extracted_two_to_t, parens, constant @@ -765,8 +895,8 @@ class ExponentRatioWithThree(AnalyzeExponentRatio): class ExponentRatioWithSeven(AnalyzeExponentRatio): CONFIG = { - "base" : 3, - "base_str" : "3", + "base" : 7, + "base_str" : "7", } class ExponentRatioWithE(AnalyzeExponentRatio): @@ -904,6 +1034,67 @@ class NaturalLog(Scene): expression.add(brace, brace_text) return expression +class NextVideo(TeacherStudentsScene): + def construct(self): + series = VideoSeries() + series.to_edge(UP) + this_video = series[3] + next_video = series[4] + brace = Brace(this_video, DOWN) + this_video.save_state() + this_video.highlight(YELLOW) + + this_tex = TexMobject( + "{d(", "a^t", ") \\over dt} = ", "a^t", "\\ln(a)" + ) + this_tex[1][1].highlight(YELLOW) + this_tex[3][1].highlight(YELLOW) + this_tex.next_to(brace, DOWN) + + next_tex = VGroup(*map(TextMobject, [ + "Chain rule", "Product rule", "$\\vdots$" + ])) + next_tex.arrange_submobjects(DOWN) + next_tex.next_to(brace, DOWN) + next_tex.shift( + next_video.get_center()[0]*RIGHT\ + -next_tex.get_center()[0]*RIGHT + ) + + self.add(series, brace, *this_tex[:3]) + self.change_student_modes( + "confused", "pondering", "erm", + look_at_arg = this_tex + ) + self.play(ReplacementTransform( + this_tex[1].copy(), this_tex[3] + )) + self.dither() + self.play( + Write(this_tex[4]), + ReplacementTransform( + this_tex[3][0].copy(), + this_tex[4][3], + path_arc = np.pi, + remover = True + ) + ) + self.dither(2) + self.play(this_tex.replace, this_video) + self.play( + brace.next_to, next_video, DOWN, + this_video.restore, + Animation(this_tex), + next_video.highlight, YELLOW, + Write(next_tex), + self.get_teacher().change_mode, "raise_right_hand" + ) + self.change_student_modes( + *["pondering"]*3, + look_at_arg = next_tex + ) + self.dither(3) + diff --git a/eoc/graph_scene.py b/eoc/graph_scene.py index 1966666a..4967c1c2 100644 --- a/eoc/graph_scene.py +++ b/eoc/graph_scene.py @@ -237,7 +237,6 @@ class GraphScene(Scene): dx = None, dx_line_color = None, df_line_color = None, - slope_line_color = None, dx_label = None, df_label = None, include_secant_line = True, diff --git a/topics/functions.py b/topics/functions.py index e2b96f6c..7ae68c28 100644 --- a/topics/functions.py +++ b/topics/functions.py @@ -44,9 +44,9 @@ class ParametricFunction(VMobject): t_values = np.linspace( self.t_min, self.t_max, self.num_anchor_points ) - points = self.function(t_values) + points = np.array(map(self.function, t_values)) okay_indices = np.apply_along_axis(np.all, 1, np.isfinite(points)) - point = point[okay_indices] + points = points[okay_indices] self.set_anchor_points(points, mode = "smooth") diff --git a/topics/objects.py b/topics/objects.py index b21bf337..db35a527 100644 --- a/topics/objects.py +++ b/topics/objects.py @@ -153,7 +153,7 @@ class VideoIcon(SVGMobject): class VideoSeries(VGroup): CONFIG = { - "num_videos" : 10, + "num_videos" : 11, "gradient_colors" : [BLUE_B, BLUE_D], } def __init__(self, **kwargs): @@ -161,6 +161,7 @@ class VideoSeries(VGroup): videos = [VideoIcon() for x in range(self.num_videos)] VGroup.__init__(self, *videos, **kwargs) self.arrange_submobjects() + self.scale_to_fit_width(2*SPACE_WIDTH-MED_LARGE_BUFF) self.gradient_highlight(*self.gradient_colors)