From c910b00a32180375d0e818ca7795bf4a9e58a94e Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 12 Jul 2016 10:36:04 -0700 Subject: [PATCH] Beginning eola project --- eola/__init__.py | 0 eola/chapter0.py | 299 +++++++++++++++++++++++++++++++++++++++++++++++ eola/utils.py | 90 ++++++++++++++ 3 files changed, 389 insertions(+) create mode 100644 eola/__init__.py create mode 100644 eola/chapter0.py create mode 100644 eola/utils.py diff --git a/eola/__init__.py b/eola/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eola/chapter0.py b/eola/chapter0.py new file mode 100644 index 00000000..02654828 --- /dev/null +++ b/eola/chapter0.py @@ -0,0 +1,299 @@ +from mobject.tex_mobject import TexMobject +from mobject import Mobject +from mobject.image_mobject import ImageMobject +from mobject.vectorized_mobject import VMobject + +from animation.animation import Animation +from animation.transform import * +from animation.simple_animations import * +from animation.playground import * +from topics.geometry import * +from topics.characters import * +from topics.functions import * +from topics.number_line import * +from topics.combinatorics import * +from scene import Scene +from camera import Camera +from mobject.svg_mobject import * +from mobject.tex_mobject import * + +from eola.utils import * + +EXAMPLE_TRANFORM = [[0, 1], [-1, 1]] +TRANFORMED_VECTOR = [[1], [2]] + +class OpeningQuote(Scene): + def construct(self): + words = TextMobject( + """ + ``There is hardly any theory which is more elementary + than linear algebra, in spite of the fact that generations + of professors and textbook writers have obscured its + simplicity by preposterous calculations with matrices.'' + """, + organize_left_to_right = False + ) + words.scale_to_fit_width(2*(SPACE_WIDTH-1)) + words.to_edge(UP) + for mob in words.submobjects[48:49+13]: + mob.highlight(GREEN) + words.show() + author = TextMobject("-Hermann Weyl") + author.highlight(YELLOW) + author.next_to(words, DOWN) + + self.play(Write(words)) + self.dither() + self.play(FadeIn(author)) + self.dither() + + +class AboutLinearAlgebra(Scene): + def construct(self): + self.show_dependencies() + self.linalg_is_confusing() + self.ask_questions() + + def show_dependencies(self): + linalg = TextMobject("Linear Algebra") + subjects = map(TextMobject, [ + "Computer science", + "Physics", + "Electrical engineering", + "Mechanical engineering", + "Statistics", + "\\vdots" + ]) + prev = subjects[0] + for subject in subjects[1:]: + subject.next_to(prev, DOWN, aligned_edge = LEFT) + prev = subject + all_subs = VMobject(*subjects) + linalg.to_edge(LEFT) + all_subs.next_to(linalg, RIGHT, buff = 2) + arrows = VMobject(*[ + Arrow(linalg, sub) + for sub in subjects + ]) + + self.play(Write(linalg, run_time = 1)) + self.dither() + self.play( + ShowCreation(arrows, submobject_mode = "lagged_start"), + FadeIn(all_subs), + run_time = 2 + ) + self.dither() + self.linalg = linalg + + def linalg_is_confusing(self): + linalg = self.linalg + all_else = list(self.mobjects) + all_else.remove(linalg) + randy = Randolph() + randy.to_corner() + bubble = randy.get_bubble(width = 10) + new_linalg = bubble.position_mobject_inside(linalg.copy()) + + self.play(*map(FadeOut, all_else)) + self.remove(*all_else) + self.play( + Transform(linalg, new_linalg), + Write(bubble), + FadeIn(randy) + ) + self.play(ApplyMethod(randy.change_mode, "confused")) + self.dither() + self.play(Blink(randy)) + self.play(FadeOut(linalg)) + self.remove(linalg) + + self.randy, self.bubble = randy, bubble + + def ask_questions(self): + randy, bubble = self.randy, self.bubble + matrix_multiplication = TexMobject(""" + \\left[ + \\begin{array}{cc} + a & b \\\\ + c & d + \\end{array} + \\right] + \\left[ + \\begin{array}{cc} + e & f \\\\ + g & h + \\end{array} + \\right] + = + \\left[ + \\begin{array}{cc} + ae + bg & af + bh \\\\ + ce + dg & cf + dh + \\end{array} + \\right] + """) + + cross = TexMobject("\\vec{v} \\times \\vec{w}") + left_right_arrow = DoubleArrow(Point(LEFT), Point(RIGHT)) + det = TextMobject("Det") + q_mark = TextMobject("?") + left_right_arrow.next_to(cross) + det.next_to(left_right_arrow) + q_mark.next_to(left_right_arrow, UP) + cross_question = VMobject(cross, left_right_arrow, q_mark, det) + cross_question.get_center = lambda : left_right_arrow.get_center() + + eigen_q = TextMobject("Eigen?") + + for mob in matrix_multiplication, cross_question, eigen_q: + bubble.position_mobject_inside(mob) + self.play(FadeIn(mob)) + if randy.mode is not "pondering": + self.play(ApplyMethod(randy.change_mode, "pondering")) + self.dither() + else: + self.dither(2) + self.remove(mob) + + + +class NumericVsGeometric(Scene): + def construct(self): + self.setup() + self.specifics_concepts() + self.clear_way_for_geometric() + self.list_geometric_benefits() + + def setup(self): + numeric = TextMobject("Numeric operations") + geometric = TextMobject("Geometric intuition") + for mob in numeric, geometric: + mob.to_corner(UP+LEFT) + geometric.shift(SPACE_WIDTH*RIGHT) + hline = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT) + hline.next_to(numeric, DOWN) + hline.to_edge(LEFT, buff = 0) + vline = Line(SPACE_HEIGHT*UP, SPACE_HEIGHT*DOWN) + for mob in hline, vline: + mob.highlight(GREEN) + + self.play(ShowCreation(VMobject(hline, vline))) + digest_locals(self) + + def specifics_concepts(self): + matrix_vector_product = TexMobject(" ".join([ + matrix_to_tex_string(EXAMPLE_TRANFORM), + matrix_to_tex_string(TRANFORMED_VECTOR), + "&=", + matrix_to_tex_string([ + ["1 \\cdot 1 + 0 \\cdot 2"], + ["1 \\cdot 1 + (-1)\\cdot 2"] + ]), + "\\\\ &=", + matrix_to_tex_string([[1], [-1]]), + ])) + matrix_vector_product.scale_to_fit_width(SPACE_WIDTH-0.5) + matrix_vector_product.next_to(self.vline, LEFT) + + self.play( + Write(self.numeric), + FadeIn(matrix_vector_product), + run_time = 2 + ) + self.dither() + self.play(Write(self.geometric, run_time = 2)) + ### Paste in linear transformation + self.dither() + digest_locals(self) + + def clear_way_for_geometric(self): + new_line = Line(SPACE_HEIGHT*LEFT, SPACE_HEIGHT*RIGHT) + new_line.shift((SPACE_HEIGHT+1)*DOWN) + self.play( + Transform(self.vline, new_line), + Transform(self.hline, new_line), + ApplyMethod(self.numeric.shift, (2*SPACE_HEIGHT+1)*DOWN), + ApplyMethod( + self.matrix_vector_product.shift, + (2*SPACE_HEIGHT+1)*DOWN + ), + ApplyMethod(self.geometric.to_edge, LEFT) + ) + + def list_geometric_benefits(self): + follow_words = TextMobject("is helpful for \\dots") + follow_words.next_to(self.geometric) + #Ugly hack + diff = follow_words.submobjects[0].get_bottom()[1] - \ + self.geometric.submobjects[0].get_bottom()[1] + follow_words.shift(diff*DOWN) + randys = [ + Randolph(mode = "speaking"), + Randolph(mode = "surprised"), + Randolph(mode = "pondering") + ] + bulb = SVGMobject("light_bulb") + bulb.scale_to_fit_height(1) + bulb.highlight(YELLOW) + thoughts = [ + matrix_to_mobject(EXAMPLE_TRANFORM), + bulb, + TextMobject("So therefore...").scale(0.5) + ] + + self.play(Write(follow_words, run_time = 1.5)) + curr_randy = None + for randy, thought in zip(randys, thoughts): + randy.shift(DOWN) + thought.next_to(randy, UP+RIGHT, buff = 0) + if curr_randy: + self.play( + Transform(curr_randy, randy), + Transform(curr_thought, thought) + ) + else: + self.play( + FadeIn(randy), + Write(thought, run_time = 1) + ) + curr_randy = randy + curr_thought = thought + self.dither(1.5) + + +class ExampleTransformation(LinearTransformationScene): + def construct(self): + self.setup() + self.apply_matrix(EXAMPLE_TRANFORM) + self.dither() + + + +class NumericToComputations(Scene): + def construct(self): + top = TextMobject("Numeric understanding") + arrow = Arrow(UP, DOWN) + bottom = TextMobject("Actual computations") + top.next_to(arrow, UP) + bottom.next_to(arrow, DOWN) + + self.add(top) + self.play(ShowCreation(arrow, submobject_mode = "one_at_a_time")) + self.play(FadeIn(bottom)) + self.dither() + + + + + + + + + + + + + + + diff --git a/eola/utils.py b/eola/utils.py new file mode 100644 index 00000000..0b5e4da8 --- /dev/null +++ b/eola/utils.py @@ -0,0 +1,90 @@ +import numpy as np + +from scene import Scene +from mobject.vectorized_mobject import VMobject +from mobject.tex_mobject import TexMobject, TextMobject +from animation.transform import ApplyMatrix, ApplyMethod +from topics.number_line import NumberPlane +from topics.geometry import Vector + + +from helpers import * + +def matrix_to_tex_string(matrix): + matrix = np.array(matrix).astype("string") + n_rows, n_cols = matrix.shape + prefix = "\\left[ \\begin{array}{%s}"%("c"*n_cols) + suffix = "\\end{array} \\right]" + rows = [ + " & ".join(row) + for row in matrix + ] + return prefix + " \\\\ ".join(rows) + suffix + + +def matrix_to_mobject(matrix): + return TexMobject(matrix_to_tex_string(matrix)) + +class LinearTransformationScene(Scene): + CONFIG = { + "include_background_plane" : True, + "include_foreground_plane" : True, + "foreground_plane_kwargs" : { + "x_radius" : 2*SPACE_WIDTH, + "y_radius" : 2*SPACE_HEIGHT, + }, + "background_plane_kwargs" : {}, + "show_coordinates" : False, + "show_basis_vectors" : True, + "i_hat_color" : GREEN_B, + "j_hat_color" : RED, + } + def setup(self): + self.background_mobjects = [] + self.foreground_mobjects = [] + self.background_plane = NumberPlane( + color = GREY, + secondary_color = DARK_GREY, + **self.background_plane_kwargs + ) + + if self.show_coordinates: + self.background_plane.add_coordinates() + if self.include_background_plane: + self.add_to_background(self.background_plane) + if self.include_foreground_plane: + self.plane = NumberPlane(**self.foreground_plane_kwargs) + self.add_to_foreground(self.plane) + if self.show_basis_vectors: + i_hat = Vector(self.background_plane.num_pair_to_point((1, 0))) + j_hat = Vector(self.background_plane.num_pair_to_point((0, 1))) + i_hat.highlight(self.i_hat_color) + j_hat.highlight(self.j_hat_color) + self.add_to_foreground(i_hat, j_hat) + + def add_to_background(self, *mobjects): + for mobject in mobjects: + if mobject not in self.background_mobjects: + self.background_mobjects.append(mobject) + self.add(mobject) + + def add_to_foreground(self, *mobjects): + for mobject in mobjects: + if mobject not in self.foreground_mobjects: + self.foreground_mobjects.append(mobject) + self.add(mobject) + + def apply_matrix(self, matrix, **kwargs): + self.play(ApplyMatrix( + matrix, + VMobject(*self.foreground_mobjects), + **kwargs + )) + + + + + + + +