diff --git a/constants.py b/constants.py index f9bd37c5..1a48e8ca 100644 --- a/constants.py +++ b/constants.py @@ -132,6 +132,9 @@ COLOR_MAP = { "GREY" : "#888888", "DARK_GREY" : "#444444", "DARK_GRAY" : "#444444", + "GREY_BROWN" : "#736357", + "PINK" : "#D147BD", + "GREEN_SCREEN": "#00FF00", } PALETTE = COLOR_MAP.values() globals().update(COLOR_MAP) diff --git a/eola/chapter0.py b/eola/chapter0.py index b16c7cae..ccff52f3 100644 --- a/eola/chapter0.py +++ b/eola/chapter0.py @@ -23,6 +23,29 @@ from eola.utils import * EXAMPLE_TRANFORM = [[0, 1], [-1, 1]] TRANFORMED_VECTOR = [[1], [2]] +def matrix_multiplication(): + return 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] + """) + class OpeningQuote(Scene): def construct(self): words = TextMobject( @@ -173,27 +196,7 @@ class AboutLinearAlgebra(Scene): def get_matrix_multiplication(self): - return 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] - """) + return matrix_multiplication() def get_determinant(self): return TexMobject(""" @@ -447,22 +450,38 @@ class LinAlgPyramid(Scene): self.dither() -class IndimidatingProf(Scene): +class IntimidatingProf(Scene): def construct(self): randy = Randolph().to_corner() morty = Mortimer().to_corner(DOWN+RIGHT) morty.shift(3*LEFT) + morty_name1 = TextMobject("Professor") + morty_name2 = TextMobject("Coworker") + for name in morty_name1, morty_name2: + name.to_edge(RIGHT) + name.shift(2*UP) + arrow = Arrow(morty_name1.get_bottom(), morty) speech_bubble = SpeechBubble(height = 3).flip() speech_bubble.pin_to(morty) speech_bubble.shift(RIGHT) speech_bubble.write("And of course $B^{-1}AB$ will \\\\ also have positive eigenvalues...") - thought_bubble = ThoughtBubble(width = 4, height = 4) + thought_bubble = ThoughtBubble(width = 6, height = 5) thought_bubble.next_to(morty, UP) - thought_bubble.to_edge(RIGHT) + thought_bubble.to_edge(RIGHT, buff = -1) + thought_bubble.make_green_screen() q_marks = TextMobject("???") q_marks.next_to(randy, UP) + randy_bubble = randy.get_bubble() + randy_bubble.add_content(matrix_multiplication()) self.add(randy, morty) + self.play( + FadeIn(morty_name1), + ShowCreation(arrow, submobject_mode = "one_at_a_time") + ) + self.play(Transform(morty_name1, morty_name2)) + self.dither() + self.play(FadeOut(morty_name1), FadeOut(arrow)) self.play( FadeIn(speech_bubble), ApplyMethod(morty.change_mode, "speaking") @@ -473,6 +492,8 @@ class IndimidatingProf(Scene): ApplyMethod(randy.change_mode, "confused"), Write(q_marks, run_time = 1) ) + self.play(FadeOut(VMobject(speech_bubble, thought_bubble))) + self.play(FadeIn(randy_bubble)) self.dither() @@ -605,10 +626,10 @@ class PhysicsExample(Scene): v_label = TexMobject("\\vec{v}") v_label.shift(p1 + RIGHT*vector[0]/4 + UP*vector[1]/2) v_label.highlight(v_mob.get_color()) - vx_label = TexMobject("\\vec{v} \\cos(\\theta)") + vx_label = TexMobject("||\\vec{v}|| \\cos(\\theta)") vx_label.next_to(vx, UP) vx_label.highlight(vx.get_color()) - vy_label = TexMobject("\\vec{v} \\sin(\\theta)") + vy_label = TexMobject("||\\vec{v}|| \\sin(\\theta)") vy_label.next_to(vy, RIGHT) vy_label.highlight(vy.get_color()) @@ -782,6 +803,7 @@ class ProfessorsTry(Scene): thought_bubble = ThoughtBubble(width = 4, height = 3.5) thought_bubble.next_to(morty, UP) thought_bubble.to_edge(RIGHT) + thought_bubble.make_green_screen() randy = Randolph() randy.scale(0.8) randy.to_corner() @@ -793,7 +815,7 @@ class ProfessorsTry(Scene): FadeIn(words) ) self.play(Blink(randy)) - self.play(FadeIn(thought_bubble )) + self.play(FadeIn(thought_bubble)) self.play(Blink(morty)) @@ -890,6 +912,8 @@ class TableOfContents(Scene): ShowCreation(bubble), Transform(icons, new_icons) ) + self.remove(icons) + bubble.make_green_screen() self.dither() @@ -915,6 +939,53 @@ class ResourceForTeachers(Scene): self.play(Blink(randy)) self.dither() +class AboutPacing(Scene): + def construct(self): + words = TextMobject("About pacing...") + dots = words.split()[-3:] + words.remove(*dots) + self.play(FadeIn(words)) + self.play(Write(VMobject(*dots))) + self.dither() + +class DifferingBackgrounds(Scene): + def construct(self): + words = map(TextMobject, [ + "Just brushing up", + "Has yet to take the course", + "Supplementing course concurrently", + ]) + students = VMobject(*[ + Randolph(color = c) + for c in BLUE_D, BLUE_C, BLUE_E + ]) + modes = ["pondering", "speaking_looking_left", "sassy"] + students.arrange_submobjects(RIGHT) + students.scale(0.8) + students.center().to_edge(DOWN) + + last_word, last_arrow = None, None + for word, student, mode in zip(words, students.split(), modes): + word.shift(2*UP) + arrow = Arrow(word, student) + if last_word: + word_anim = Transform(last_word, word) + arrow_anim = Transform(last_arrow, arrow) + else: + word_anim = Write(word, run_time = 1) + arrow_anim = ShowCreation(arrow, submobject_mode = "one_at_a_time") + last_word = word + last_arrow = arrow + self.play( + word_anim, arrow_anim, + ApplyMethod(student.change_mode, mode) + ) + self.play(Blink(student)) + self.dither() + self.dither() + + + class PauseAndPonder(Scene): def construct(self): pause = TexMobject("=").rotate(np.pi/2) diff --git a/eola/chapter1.py b/eola/chapter1.py new file mode 100644 index 00000000..72d352ec --- /dev/null +++ b/eola/chapter1.py @@ -0,0 +1,149 @@ +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 mobject.vectorized_mobject import * + +from eola.utils import * + +import random + + +class Physicist(PiCreature): + CONFIG = { + "color" : PINK, + } + +class ComputerScientist(PiCreature): + CONFIG = { + "color" : PURPLE_E, + "flip_at_start" : True, + } + +class OpeningQuote(Scene): + def construct(self): + words = TextMobject( + "``The introduction of numbers as \\\\ coordinates is an act of violence.''", + ) + words.to_edge(UP) + for mob in words.submobjects[27:27+11]: + mob.highlight(GREEN) + author = TextMobject("-Hermann Weyl") + author.highlight(YELLOW) + author.next_to(words, DOWN, buff = 0.5) + + self.play(FadeIn(words)) + self.dither(1) + self.play(Write(author, run_time = 4)) + self.dither() + +class IntroVector(Scene): + def construct(self): + plane = NumberPlane() + labels = plane.get_coordinate_labels() + vector = Vector(RIGHT+2*UP, color = YELLOW) + coordinates = vector_coordinate_label(vector) + + self.play(ShowCreation( + plane, + submobject_mode = "lagged_start", + run_time = 3 + )) + self.play(ShowCreation( + vector, + submobject_mode = "one_at_a_time" + )) + self.play(Write(VMobject(*labels)), Write(coordinates)) + self.dither() + + +class DifferentConceptions(Scene): + def construct(self): + physy = Physicist() + mathy = Mathematician(mode = "pondering") + compy = ComputerScientist() + people = [physy, compy, mathy] + physy.name = TextMobject("Physics student").to_corner(DOWN+LEFT) + compy.name = TextMobject("CS student").to_corner(DOWN+RIGHT) + mathy.name = TextMobject("Mathematician").to_edge(DOWN) + names = VMobject(physy.name, mathy.name, compy.name) + names.arrange_submobjects(RIGHT, buff = 1) + names.to_corner(DOWN+LEFT) + for pi in people: + pi.next_to(pi.name, UP) + self.add(pi) + + for pi in people: + self.play(Write(pi.name), run_time = 1) + self.preview_conceptions(people) + self.physics_conception(people) + self.cs_conception(people) + self.handle_mathy(people) + + + def preview_conceptions(self, people): + arrow = Vector(2*RIGHT+ UP) + array = matrix_to_mobject([[2], [1]]) + tex = TextMobject(""" + Set $V$ with operations \\\\ + $a : V \\times V \\to V$ and \\\\ + $s : \\mathds{R} \\times V \\to V$ such that... + """) + physy, compy, mathy = people + physy.bubble = physy.get_bubble("speech") + compy.bubble = compy.get_bubble("speech") + mathy.bubble = mathy.get_bubble(width = 4) + + for pi, sym in zip(people, [arrow, array, tex]): + pi.bubble.set_fill(BLACK, opacity = 1.0) + pi.bubble.add_content(sym) + self.play(FadeIn(pi.bubble)) + self.dither() + for pi in people: + self.remove(pi.bubble) + + + def physics_conception(self, people): + pass + + def cs_conception(self, people): + pass + + def handle_mathy(self, people): + pass + + + + + + + + + + + + + + + + + + + + + + diff --git a/eola/utils.py b/eola/utils.py index 3a6bfb4b..ac7b0935 100644 --- a/eola/utils.py +++ b/eola/utils.py @@ -10,9 +10,10 @@ from animation.simple_animations import ShowCreation from topics.number_line import NumberPlane from topics.geometry import Vector, Line, Circle - from helpers import * +VECTOR_LABEL_SCALE_VAL = 0.7 + def matrix_to_tex_string(matrix): matrix = np.array(matrix).astype("string") n_rows, n_cols = matrix.shape @@ -28,6 +29,24 @@ def matrix_to_tex_string(matrix): def matrix_to_mobject(matrix): return TexMobject(matrix_to_tex_string(matrix)) +def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2): + vect = np.array(vector_mob.get_end()) + if integer_labels: + vect = vect.astype(int) + vect = vect[:n_dim] + vect = vect.reshape((n_dim, 1)) + label = matrix_to_mobject(vect) + label.scale(VECTOR_LABEL_SCALE_VAL) + + shift_dir = np.array(vector_mob.get_end()) + if shift_dir[0] > 0: #Pointing right + shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*LEFT + else: #Pointing left + shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*RIGHT + label.shift(shift_dir) + return label + + class LinearTransformationScene(Scene): CONFIG = { "include_background_plane" : True, diff --git a/topics/characters.py b/topics/characters.py index 5da9658a..8037386a 100644 --- a/topics/characters.py +++ b/topics/characters.py @@ -125,7 +125,7 @@ class Randolph(PiCreature): class Mortimer(PiCreature): CONFIG = { - "color" : "#736357", + "color" : GREY_BROWN, "flip_at_start" : True, } @@ -233,4 +233,13 @@ class ThoughtBubble(Bubble): lambda m1, m2 : int((m1.get_bottom()-m2.get_bottom())[1]) ) + def make_green_screen(self): + self.submobjects[-1].set_fill(GREEN_SCREEN, opacity = 1) + return self + + + + + + diff --git a/topics/geometry.py b/topics/geometry.py index c07ec01b..1a2c7e6d 100644 --- a/topics/geometry.py +++ b/topics/geometry.py @@ -168,7 +168,7 @@ class Arrow(Line): class Vector(Arrow): CONFIG = { - "color" : WHITE, + "color" : YELLOW, "buff" : 0, } def __init__(self, direction, **kwargs):