From df13f10653164f737901e64402efeb810255d6ca Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 30 Aug 2016 22:17:07 -0700 Subject: [PATCH] Rough drafts for chapter 8 parts --- animation/transform.py | 6 + eola/chapter8.py | 135 ++++++--- eola/chapter8p2.py | 661 ++++++++++++++++++++++++++++++++++++++++- helpers.py | 4 +- topics/characters.py | 13 +- 5 files changed, 766 insertions(+), 53 deletions(-) diff --git a/animation/transform.py b/animation/transform.py index 1a291eea..6a699c78 100644 --- a/animation/transform.py +++ b/animation/transform.py @@ -61,6 +61,12 @@ class CounterclockwiseTransform(Transform): "path_arc" : np.pi } +class MoveToTarget(Transform): + def __init__(self, mobject, **kwargs): + if not hasattr(mobject, "target"): + raise Exception("MoveToTarget called on mobject without attribute 'target' ") + Transform.__init__(self, mobject, mobject.target, **kwargs) + class GrowFromCenter(Transform): def __init__(self, mobject, **kwargs): target = mobject.copy() diff --git a/eola/chapter8.py b/eola/chapter8.py index 9bf99bdf..1bdfa158 100644 --- a/eola/chapter8.py +++ b/eola/chapter8.py @@ -34,22 +34,20 @@ def get_vect_tex(*strings): else: return result +def get_perm_sign(*permutation): + identity = np.identity(len(permutation)) + return np.linalg.det(identity[list(permutation)]) + class OpeningQuote(Scene): def construct(self): - words = TextMobject( - "``And what is the use of a book,'' thought Alice,", - "``without", "pictures", "or", "conversations", "?''" - ) - words.highlight_by_tex("pictures", BLUE) - words.highlight_by_tex("conversations", MAROON_B) - words.scale_to_fit_width(2*SPACE_WIDTH - 2) + words = TextMobject("``Every dimension is special.''") words.to_edge(UP) - author = TextMobject("-Lewis Carroll (Alice in Wonderland)") + author = TextMobject("-Jeff Lagarias") author.highlight(YELLOW) author.next_to(words, DOWN, buff = 0.5) self.play(FadeIn(words)) - self.dither(4) + self.dither(1) self.play(Write(author, run_time = 3)) self.dither() @@ -76,40 +74,98 @@ class DoTheSameForCross(TeacherStudentsScene): self.change_student_modes("pondering") self.random_blink() -class ListSteps(RandolphScene): +class ListSteps(Scene): CONFIG = { "randy_corner" : DOWN+RIGHT } def construct(self): title = TextMobject("Two part chapter") - title.highlight(YELLOW) title.to_edge(UP) h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH) h_line.next_to(title, DOWN) + randy = Randolph().flip().to_corner(DOWN+RIGHT) + randy.look(UP+LEFT) step_1 = TextMobject("This video: Standard introduction") step_2 = TextMobject("Next video: Deeper understanding with ", "linear transformations") step_2.highlight_by_tex("linear transformations", BLUE) steps = Group(step_1, step_2) steps.arrange_submobjects(DOWN, aligned_edge = LEFT, buff = LARGE_BUFF) - steps.next_to(self.randy, UP) - steps.to_edge(LEFT) + steps.next_to(randy, UP) + steps.to_edge(LEFT, buff = LARGE_BUFF) self.add(title) self.play(ShowCreation(h_line)) + for step in steps: + self.play(Write(step)) + self.dither() + for step in steps: + target = step.copy() + target.scale_in_place(1.1) + target.highlight(YELLOW) + target.highlight_by_tex("linear transformations", BLUE) + step.target = target + step.save_state() + self.play(FadeIn(randy)) + self.play(Blink(randy)) self.play( - Write(step_1), - ApplyFunction( - lambda m : m.change_mode("happy").look(UP+LEFT), - self.randy + MoveToTarget(step_1), + step_2.fade, + randy.change_mode, "happy" + ) + self.play(Blink(randy)) + self.play( + Transform(step_1, step_1.copy().restore().fade()), + MoveToTarget(step_2), + randy.look, LEFT + ) + self.play(randy.change_mode, "erm") + self.dither(2) + self.play(randy.change_mode, "pondering") + self.play(Blink(randy)) + +class SimpleDefine2dCrossProduct(LinearTransformationScene): + CONFIG = { + "show_basis_vectors" : False, + "v_coords" : [3, 1], + "w_coords" : [2, -1], + } + def construct(self): + self.add_vectors() + self.show_area() + self.show_sign() + + def add_vectors(self): + self.plane.fade() + v = self.add_vector(self.v_coords, color = V_COLOR) + w = self.add_vector(self.w_coords, color = W_COLOR) + for vect, name, direction in (v, "v", "left"), (w, "w", "right"): + color = vect.get_color() + vect.label = self.label_vector( + vect, name, color = color, direction = direction, ) - ) - self.dither(1) - self.play( - Write(step_2), - self.randy.change_mode, "pondering" - ) - self.dither() + vect.coord_array = vector_coordinate_label( + vect, color = color, + ) + vect.coords = vect.coord_array.get_entries() + for vect, edge in (v, DOWN), (w, UP): + vect.coord_array.move_to( + vect.coord_array.get_center(), + aligned_edge = edge + ) + self.play(Write(vect.coord_array, run_time = 1)) + self.v, self.w = v, w + + def show_area(self): + transform = self.get_matrix_transformation(np.array([ + self.v_coords, + self.w_coords, + ]).T) + self.square.apply_function(transform) + + def show_sign(self): + pass + class ContrastDotAndCross(Scene): def construct(self): @@ -986,7 +1042,8 @@ class WriteAreaOfParallelogram(Scene): class WriteCrossProductProperties(Scene): def construct(self): - v_tex, w_tex, p_tex = get_vect_tex(*"vwp") + v_tex, w_tex, p_tex = texs = get_vect_tex(*"vwp") + v_cash, w_cash, p_cash = ["$%s$"%tex for tex in texs] cross_product = TexMobject(v_tex, "\\times", w_tex, "=", p_tex) cross_product.highlight_by_tex(v_tex, V_COLOR) cross_product.highlight_by_tex(w_tex, W_COLOR) @@ -997,15 +1054,23 @@ class WriteCrossProductProperties(Scene): brace.do_in_place(brace.stretch, 2, 0) vector = brace.get_text("vector") vector.highlight(P_COLOR) - length_words = TextMobject("With length", "2.5") - length_words.highlight_by_tex("2.5", BLUE) - length_words.next_to(vector, DOWN, buff = MED_BUFF) - perpendicular = TextMobject(""" - Perpendicular to - the""", "parallelogram" + length_words = TextMobject( + "Length of ", p_cash, "\\\\ = ", + "(parallelogram's area)" ) - perpendicular.highlight_by_tex("parallelogram", BLUE) - perpendicular.next_to(length_words, DOWN, buff = MED_BUFF) + length_words.highlight_by_tex(p_cash, P_COLOR) + length_words.scale_to_fit_width(SPACE_WIDTH - 1) + length_words.highlight_by_tex("(parallelogram's area)", BLUE) + length_words.next_to(Group(cross_product, vector), DOWN, buff = LARGE_BUFF) + perpendicular = TextMobject( + "\\centering Perpendicular to", + v_cash, "and", w_cash + ) + perpendicular.scale_to_fit_width(SPACE_WIDTH - 1) + perpendicular.highlight_by_tex(v_cash, V_COLOR) + perpendicular.highlight_by_tex(w_cash, W_COLOR) + perpendicular.next_to(length_words, DOWN, buff = LARGE_BUFF) + self.play(Write(cross_product)) self.play( @@ -1082,10 +1147,6 @@ class ShowCrossProductFormula(Scene): cross_product.arrange_submobjects() cross_product.shift(2*LEFT) - def get_perm_sign(a, b, c): - identity = np.identity(3) - return np.linalg.det(identity[[a, b, c]]) - entry_dicts = [{} for x in range(3)] movement_sets = [] for a, b, c in it.permutations(range(3)): diff --git a/eola/chapter8p2.py b/eola/chapter8p2.py index abf1b15c..a5c53cf2 100644 --- a/eola/chapter8p2.py +++ b/eola/chapter8p2.py @@ -20,8 +20,7 @@ from mobject.vectorized_mobject import * from eola.matrix import * from eola.two_d_space import * from eola.chapter5 import get_det_text -from eola.chapter8 import get_vect_tex, CrossProductRightHandRule -from eola.chapter8 import U_COLOR, V_COLOR, W_COLOR, P_COLOR +from eola.chapter8 import * class OpeningQuote(Scene): @@ -49,6 +48,26 @@ class OpeningQuote(Scene): self.play(Write(author, run_time = 3)) self.dither() +class CrossProductSymbols(Scene): + def construct(self): + v_tex, w_tex, p_tex = get_vect_tex(*"vwp") + equation = TexMobject( + v_tex, "\\times", w_tex, "=", p_tex + ) + equation.highlight_by_tex(v_tex, V_COLOR) + equation.highlight_by_tex(w_tex, W_COLOR) + equation.highlight_by_tex(p_tex, P_COLOR) + brace = Brace(equation[-1]) + brace.stretch_to_fit_width(0.7) + vector_text = brace.get_text("Vector") + vector_text.highlight(RED) + self.add(equation) + self.play(*map(Write, [brace, vector_text])) + self.dither() + +class DeterminantTrickCopy(DeterminantTrick): + pass + class BruteForceVerification(Scene): def construct(self): v = Matrix(["v_1", "v_2", "v_3"]) @@ -188,9 +207,12 @@ class DualityReview(TeacherStudentsScene): class DotProductToTransformSymbol(Scene): CONFIG = { - "vect_coords" : [4, 1] + "vect_coords" : [2, 1] } def construct(self): + v_mob = TexMobject(get_vect_tex("v")) + v_mob.highlight(V_COLOR) + matrix = Matrix([self.vect_coords]) vector = Matrix(self.vect_coords) matrix.highlight_columns(X_COLOR, Y_COLOR) @@ -210,7 +232,17 @@ class DotProductToTransformSymbol(Scene): right_words = right_brace.get_text("Transform") right_words.scale_to_fit_width(right_brace.get_width()) - self.play(*map(FadeIn, (matrix, right_input))) + right_v_brace = Brace(right_input, UP) + right_v_mob = v_mob.copy() + right_v_brace.put_at_tip(right_v_mob) + right_input.add(right_v_brace, right_v_mob) + left_v_brace = Brace(left_input, UP) + left_v_mob = v_mob.copy() + left_v_brace.put_at_tip(left_v_mob) + left_input.add(left_v_brace, left_v_mob) + + + self.add(matrix, right_input) self.play( GrowFromCenter(right_brace), Write(right_words, run_time = 1) @@ -228,11 +260,622 @@ class DotProductToTransformSymbol(Scene): ) self.dither() - - - - - +class MathematicalWild(Scene): + def construct(self): + title = TextMobject("In the mathematical wild") + title.to_edge(UP) + self.add(title) + + randy = Randolph() + randy.shift(DOWN) + bubble = ThoughtBubble(width = 5, height = 4) + bubble.write(""" + \\centering + Some linear + transformation + to the number line + """) + bubble.content.highlight(BLUE) + bubble.content.shift(MED_BUFF*UP/2) + bubble.remove(*bubble[:-1]) + bubble.add(bubble.content) + bubble.next_to(randy.get_corner(UP+RIGHT), RIGHT) + vector = Vector([1, 2]) + vector.move_to(randy.get_corner(UP+LEFT), aligned_edge = DOWN+LEFT) + dual_words = TextMobject("Dual vector") + dual_words.gradient_highlight(BLUE, YELLOW) + dual_words.next_to(vector, LEFT) + + self.add(randy) + self.play(Blink(randy)) + self.play(FadeIn(bubble)) + self.play(randy.change_mode, "sassy") + self.play(Blink(randy)) + self.dither() + self.play(randy.look, UP+LEFT) + self.play( + ShowCreation(vector), + randy.change_mode, "raise_right_hand" + ) + self.dither() + self.play(Write(dual_words)) + self.play(Blink(randy)) + self.dither() + +class ThreeStepPlan(Scene): + def construct(self): + title = TextMobject("The plan") + title.highlight(YELLOW) + title.to_edge(UP) + h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH) + h_line.next_to(title, DOWN) + + v_tex, w_tex = get_vect_tex(*"vw") + v_text, w_text, cross_text = [ + "$%s$"%s + for s in v_tex, w_tex, v_tex + "\\times" + w_tex + ] + steps = [ + TextMobject( + "1. Define a 3d-to-1d", "linear \\\\", "transformation", + "in terms of", v_text, "and", w_text + ), + TextMobject( + "2. Find its", "dual vector" + ), + TextMobject( + "3. Show that this dual is", cross_text + ) + ] + linear, transformation = steps[0][1:1+2] + steps[0].highlight_by_tex(v_text, V_COLOR) + steps[0].highlight_by_tex(w_text, W_COLOR) + steps[1][1].gradient_highlight(BLUE, YELLOW) + steps[2].highlight_by_tex(cross_text, P_COLOR) + Group(*steps).arrange_submobjects( + DOWN, aligned_edge = LEFT, buff = LARGE_BUFF + ).next_to(h_line, DOWN, buff = MED_BUFF) + + self.add(title) + self.play(ShowCreation(h_line)) + for step in steps: + self.play(Write(step, run_time = 2)) + self.dither() + + linear_transformation = TextMobject("Linear", "transformation") + linear_transformation.next_to(h_line, DOWN, MED_BUFF) + det = self.get_det() + rect = Rectangle(width = 16, height = 9, color = BLUE) + rect.scale_to_fit_height(3.5) + left_right_arrow = TexMobject("\\Leftrightarrow") + left_right_arrow.shift(DOWN) + det.next_to(left_right_arrow, LEFT) + rect.next_to(left_right_arrow, RIGHT) + + steps[0].remove(linear, transformation) + self.play( + Transform( + Group(linear, transformation), + linear_transformation + ), + *map(FadeOut, steps) + ) + self.dither() + self.play(Write(left_right_arrow)) + self.play(Write(det)) + self.play(ShowCreation(rect)) + self.dither(0) + + def get_det(self): + matrix = Matrix(np.array([ + ["\\hat{\\imath}", "\\hat{\\jmath}", "\\hat{k}"], + ["v_%d"%d for d in range(1, 4)], + ["w_%d"%d for d in range(1, 4)], + ]).T) + matrix.highlight_columns(X_COLOR, V_COLOR, W_COLOR) + matrix.get_mob_matrix()[1, 0].highlight(Y_COLOR) + matrix.get_mob_matrix()[2, 0].highlight(Z_COLOR) + Group(*matrix.get_mob_matrix()[1, 1:]).shift(0.15*DOWN) + Group(*matrix.get_mob_matrix()[2, 1:]).shift(0.35*DOWN) + det_text = get_det_text(matrix) + det_text.add(matrix) + return det_text + +class DefineDualTransform(Scene): + def construct(self): + self.add_title() + self.show_triple_cross_product() + self.write_function() + self.introduce_dual_vector() + self.expand_dot_product() + self.ask_question() + + def add_title(self): + title = TextMobject("What a student might think") + title.not_real = TextMobject("Not the real cross product") + for mob in title, title.not_real: + mob.scale_to_fit_width(SPACE_WIDTH - 1) + mob.highlight(RED) + mob.to_edge(UP) + self.add(title) + self.title = title + + def show_triple_cross_product(self): + colors = [WHITE, ORANGE, W_COLOR] + tex_mobs = map(TexMobject, get_vect_tex(*"uvw")) + u_tex, v_tex, w_tex = tex_mobs + arrays = [ + Matrix(["%s_%d"%(s, d) for d in range(1, 4)]) + for s in "uvw" + ] + defs_equals = Group() + definitions = Group() + for array, tex_mob, color in zip(arrays, tex_mobs, colors): + array.highlight_columns(color) + tex_mob.highlight(color) + equals = TexMobject("=") + definition = Group(tex_mob, equals, array) + definition.arrange_submobjects(RIGHT) + definitions.add(definition) + defs_equals.add(equals) + definitions.arrange_submobjects(buff = MED_BUFF) + definitions.shift(2*DOWN) + + mobs_with_targets = list(it.chain( + tex_mobs, *[a.get_entries() for a in arrays] + )) + for mob in mobs_with_targets: + mob.target = mob.copy() + matrix = Matrix(np.array([ + [e.target for e in array.get_entries()] + for array in arrays + ]).T) + det_text = get_det_text(matrix, background_rect = False) + syms = times1, times2, equals = [ + TexMobject(sym) + for sym in "\\times", "\\times", "=", + ] + triple_cross = Group( + u_tex.target, times1, v_tex.target, times2, w_tex.target, equals + ) + triple_cross.arrange_submobjects() + + final_mobs = Group(triple_cross, Group(det_text, matrix)) + final_mobs.arrange_submobjects() + final_mobs.next_to(self.title, DOWN, buff = MED_BUFF) + + for mob in definitions, final_mobs: + mob.scale_to_fit_width(SPACE_WIDTH - 1) + + for array in arrays: + brackets = array.get_brackets() + brackets.target = matrix.get_brackets() + mobs_with_targets.append(brackets) + for def_equals in defs_equals: + def_equals.target = equals + mobs_with_targets.append(def_equals) + + self.play(FadeIn( + definitions, + run_time = 2, + submobject_mode = "lagged_start" + )) + self.dither(2) + self.play(*[ + Transform(mob.copy(), mob.target) + for mob in tex_mobs + ] + [ + Write(times1), + Write(times2), + ]) + triple_cross.add(*self.get_mobjects_from_last_animation()[:3]) + self.play(*[ + Transform(mob.copy(), mob.target) + for mob in mobs_with_targets + if mob not in tex_mobs + ]) + u_entries = self.get_mobjects_from_last_animation()[:3] + v_entries = self.get_mobjects_from_last_animation()[3:6] + w_entries = self.get_mobjects_from_last_animation()[6:9] + self.play(Write(det_text)) + self.dither(2) + + self.det_text = det_text + self.definitions = definitions + self.u_entries = u_entries + self.v_entries = v_entries + self.w_entries = w_entries + self.matrix = matrix + self.triple_cross = triple_cross + self.v_tex, self.w_tex = v_tex, w_tex + self.equals = equals + + def write_function(self): + brace = Brace(self.det_text, DOWN) + number_text = brace.get_text("Number") + self.play(Transform(self.title, self.title.not_real)) + self.dither() + self.play(FadeOut(self.definitions)) + self.play( + GrowFromCenter(brace), + Write(number_text) + ) + self.dither() + + x, y, z = variables = map(TexMobject, "xyz") + for var, entry in zip(variables, self.u_entries): + var.scale(0.8) + var.move_to(entry) + entry.target = var + brace.target = Brace(z) + brace.target.stretch_to_fit_width(0.5) + number_text.target = brace.target.get_text("Variable") + v_brace = Brace(self.matrix.get_mob_matrix()[0, 1], UP) + w_brace = Brace(self.matrix.get_mob_matrix()[0, 2], UP) + for vect_brace, tex in (v_brace, self.v_tex), (w_brace, self.w_tex): + vect_brace.stretch_to_fit_width(brace.target.get_width()) + new_tex = tex.copy() + vect_brace.put_at_tip(new_tex) + vect_brace.tex = new_tex + func_tex = TexMobject( + "f\\left(%s\\right)"%matrix_to_tex_string(list("xyz")) + ) + func_tex.scale(0.7) + func_input = Matrix(list("xyz")) + func_input_template = Group(*func_tex[3:-2]) + func_input.scale_to_fit_height(func_input_template.get_height()) + func_input.next_to(Group(*func_tex[:3]), RIGHT) + Group(*func_tex[-2:]).next_to(func_input, RIGHT) + func_tex[0].scale_in_place(1.5) + + func_tex = Group( + Group(*[func_tex[i] for i in 0, 1, 2, -2, -1]), + func_input + ) + func_tex.next_to(self.equals, LEFT) + + self.play( + FadeOut(self.title), + FadeOut(self.triple_cross), + *[ + Transform(mob, mob.target) + for mob in [brace, number_text] + ] + ) + self.play(*[ + Transform(mob, mob.target) + for mob in self.u_entries + ]) + self.play(*[ + Write(Group(vect_brace, vect_brace.tex)) + for vect_brace in v_brace, w_brace + ]) + self.dither() + self.play(Write(func_tex)) + self.dither() + + self.func_tex = func_tex + self.variables_text = Group(brace, number_text) + + def introduce_dual_vector(self): + everything = Group(*self.get_mobjects()) + colors = [X_COLOR, Y_COLOR, Z_COLOR] + q_marks = Group(*map(TextMobject, "???")) + q_marks.scale(2) + q_marks.gradient_highlight(*colors) + + title = Group(TextMobject("This function is linear")) + title.highlight(GREEN) + title.to_edge(UP) + matrix = Matrix([list(q_marks.copy())]) + matrix.scale_to_fit_height(self.func_tex.get_height()/2) + dual_vector = Matrix(list(q_marks)) + dual_vector.scale_to_fit_height(self.func_tex.get_height()) + dual_vector.get_brackets()[0].shift(0.2*LEFT) + dual_vector.get_entries().shift(0.1*LEFT) + dual_dot = Group( + dual_vector, + TexMobject("\\cdot").next_to(dual_vector) + ) + + self.play( + Write(title, run_time = 2), + everything.shift, DOWN + ) + self.remove(everything) + self.add(*everything) + self.dither() + + func, func_input = self.func_tex + func_input.target = func_input.copy() + func_input.target.scale(1.2) + func_input.target2 = func_input.copy() + func_input.target.move_to( + self.variables_text.get_right(), + aligned_edge = UP + ) + func_input.target2.move_to(self.func_tex, aligned_edge = RIGHT) + matrix.next_to(func_input.target, LEFT) + dual_dot.next_to(func_input.target2, LEFT) + + self.play( + Transform(func, matrix), + MoveToTarget(func_input), + FadeOut(self.variables_text), + ) + self.dither() + self.play( + Transform(func, dual_vector), + Transform(func_input, func_input.target2), + Write(dual_dot[1]) + ) + self.dither() + + p_coords = Group(*map(TexMobject, [ + "p_%d"%d for d in range(1, 4) + ])) + p_coords.highlight(RED) + p_array = Matrix(list(p_coords)) + p_array.scale_to_fit_height(dual_vector.get_height()) + p_array.move_to(dual_vector, aligned_edge = RIGHT) + p_brace = Brace(p_array, UP) + p_tex = TexMobject(get_vect_tex("p")) + p_tex.highlight(P_COLOR) + p_brace.put_at_tip(p_tex) + + self.play( + GrowFromCenter(p_brace), + Write(p_tex) + ) + self.play(Transform( + func, p_array, + run_time = 2, + submobject_mode = "lagged_start" + )) + self.remove(func) + self.add(p_array) + self.dither() + self.play(FadeOut(title)) + self.dither() + + self.p_array = p_array + self.input_array = func_input + + def expand_dot_product(self): + everything = Group(*self.get_mobjects()) + self.play(everything.to_edge, UP) + self.remove(everything) + self.add(*everything) + to_fade = Group() + + p_entries = self.p_array.get_entries() + input_entries = self.input_array.get_entries() + dot_components = Group() + for p, x, i in zip(p_entries, input_entries, it.count()): + if i == 2: + x.sym = TexMobject("=") + else: + x.sym = TexMobject("+") + p.sym = TexMobject("\\cdot") + p.target = p.copy().scale(2) + x.target = x.copy().scale(2) + component = Group(p.target, p.sym, x.target, x.sym) + component.arrange_submobjects() + dot_components.add(component) + dot_components.arrange_submobjects() + dot_components.next_to(ORIGIN, LEFT) + dot_components.shift(1.5*DOWN) + dot_arrow = Arrow(self.p_array.get_corner(DOWN+RIGHT), dot_components) + to_fade.add(dot_arrow) + self.play(ShowCreation(dot_arrow)) + new_ps = Group() + for p, x in zip(p_entries, input_entries): + self.play( + MoveToTarget(p.copy()), + MoveToTarget(x.copy()), + Write(p.sym), + Write(x.sym) + ) + mobs = self.get_mobjects_from_last_animation() + new_ps.add(mobs[0]) + to_fade.add(*mobs[1:]) + self.dither() + + x, y, z = self.u_entries + v1, v2, v3 = self.v_entries + w1, w2, w3 = self.w_entries + cross_components = Group() + quints = [ + (x, v2, w3, v3, w2), + (y, v3, w1, v1, w3), + (z, v1, w2, v2, w1), + ] + quints = [ + [m.copy() for m in quint] + for quint in quints + ] + for i, quint in enumerate(quints): + sym_strings = ["(", "\\cdot", "-", "\\cdot", ")"] + if i < 2: + sym_strings[-1] += "+" + syms = map(TexMobject, sym_strings) + for mob, sym in zip(quint, syms): + mob.target = mob.copy() + mob.target.scale(1.5) + mob.sym = sym + quint_targets = [mob.target for mob in quint] + component = Group(*it.chain(*zip(quint_targets, syms))) + component.arrange_submobjects() + cross_components.add(component) + to_fade.add(syms[0], syms[-1], quint[0]) + cross_components.arrange_submobjects(DOWN, aligned_edge = LEFT, buff = MED_BUFF) + cross_components.next_to(dot_components, RIGHT) + for quint in quints: + self.play(*[ + ApplyMethod(mob.highlight, YELLOW) + for mob in quint + ]) + self.dither(0.5) + self.play(*[ + MoveToTarget(mob) + for mob in quint + ] + [ + Write(mob.sym) + for mob in quint + ]) + self.dither() + self.play( + ApplyFunction( + lambda m : m.arrange_submobjects( + DOWN, buff = MED_BUFF+SMALL_BUFF + ).next_to(cross_components, LEFT), + new_ps + ), + *map(FadeOut, to_fade) + ) + self.play(*[ + Write(TexMobject("=").next_to(p, buff = 2*SMALL_BUFF)) + for p in new_ps + ]) + equals = self.get_mobjects_from_last_animation() + self.dither(2) + everything = everything.copy() + self.play( + FadeOut(Group(*self.get_mobjects())), + Animation(everything) + ) + self.clear() + self.add(everything) + + def ask_question(self): + everything = Group(*self.get_mobjects()) + p_tex = "$%s$"%get_vect_tex("p") + question = TextMobject( + "What vector", + p_tex, + "has \\\\ the property that" + ) + question.to_edge(UP) + question.highlight(YELLOW) + question.highlight_by_tex(p_tex, P_COLOR) + everything.target = everything.copy() + everything.target.next_to( + question, DOWN, buff = MED_BUFF + ) + self.play( + MoveToTarget(everything), + Write(question) + ) + self.dither() + +class ThreeDTripleCrossProduct(Scene): + pass #Simple parallelepiped + +class ThreeDMovingVariableVector(Scene): + pass #white u moves around + +class ThreeDMovingVariableVectorWithCrossShowing(Scene): + pass #white u moves around, red p is present + +class NowForTheCoolPart(TeacherStudentsScene): + def construct(self): + self.teacher_says( + "Now for the\\\\", + "cool part" + ) + self.change_student_modes(*["happy"]*3) + self.random_blink(2) + self.teacher_says( + "Let's answer the same question,\\\\", + "but this time geometrically" + ) + self.change_student_modes(*["pondering"]*3) + self.random_blink(2) + +class ThreeDDotProductProjection(Scene): + pass # + +class DotProductWords(Scene): + def construct(self): + p_tex = "$%s$"%get_vect_tex("p") + p_mob = TextMobject(p_tex) + p_mob.scale(1.5) + p_mob.highlight(P_COLOR) + input_array = Matrix(list("xyz")) + dot_product = Group(p_mob, Dot(radius = 0.07), input_array) + dot_product.arrange_submobjects(buff = MED_BUFF/2) + equals = TexMobject("=") + dot_product.next_to(equals, LEFT) + words = Group(*it.starmap(TextMobject, [ + ("(Length of projection)",), + ("(Length of ", p_tex, ")",) + ])) + times = TexMobject("\\times") + words[1].highlight_by_tex(p_tex, P_COLOR) + words[0].next_to(equals, RIGHT) + words[1].next_to(words[0], DOWN, aligned_edge = LEFT) + times.next_to(words[0], RIGHT) + + everyone = Group(dot_product, equals, times, words) + everyone.center().scale_to_fit_width(SPACE_WIDTH - 1) + self.add(dot_product) + self.play(Write(equals)) + self.play(Write(words[0])) + self.dither() + self.play( + Write(times), + Write(words[1]) + ) + self.dither() + +class ThreeDProjectToPerpendicular(Scene): + pass # + +class GeometricVolumeWords(Scene): + def construct(self): + v_tex, w_tex = [ + "$%s$"%s + for s in get_vect_tex(*"vw") + ] + + words = Group( + TextMobject("(Area of", "parallelogram", ")$\\times$"), + TextMobject( + "(Component of $%s$"%matrix_to_tex_string(list("xyz")), + "perpendicular to", v_tex, "and", w_tex, ")" + ) + ) + words[0].highlight_by_tex("parallelogram", BLUE) + words[1].highlight_by_tex(v_tex, ORANGE) + words[1].highlight_by_tex(w_tex, W_COLOR) + words.arrange_submobjects(RIGHT) + words.scale_to_fit_width(2*SPACE_WIDTH - 1) + words.to_edge(DOWN, buff = SMALL_BUFF) + for word in words: + self.play(Write(word)) + self.dither() + +class WriteXYZ(Scene): + def construct(self): + self.play(Write(Matrix(list("xyz")))) + self.dither() + +class ThreeDDotProductWithCross(Scene): + pass + +class NextVideo(Scene): + def construct(self): + title = TextMobject(""" + Next video: Change of basis + """) + title.to_edge(UP, buff = MED_BUFF/2) + rect = Rectangle(width = 16, height = 9, color = BLUE) + rect.scale_to_fit_height(6) + rect.next_to(title, DOWN) + + self.add(title) + self.play(ShowCreation(rect)) + self.dither() diff --git a/helpers.py b/helpers.py index fdf4a128..c52b6b67 100644 --- a/helpers.py +++ b/helpers.py @@ -35,7 +35,7 @@ def play_chord(*nums): pass def play_error_sound(): - play_chord(12, 11, 8, 6, 1) + play_chord(11, 8, 6, 1) def play_finish_sound(): @@ -144,7 +144,7 @@ def bezier(points): n = len(points) - 1 return lambda t : sum([ ((1-t)**(n-k))*(t**k)*choose(n, k)*point - for point, k in zip(points, it.count()) + for k, point in enumerate(points) ]) def remove_list_redundancies(l): diff --git a/topics/characters.py b/topics/characters.py index 4ff82c35..c562aa47 100644 --- a/topics/characters.py +++ b/topics/characters.py @@ -31,6 +31,7 @@ class PiCreature(SVGMobject): "initial_scale_factor" : 0.01, "corner_scale_factor" : 0.75, "flip_at_start" : False, + "is_looking_direction_purposeful" : False, } def __init__(self, mode = "plain", **kwargs): self.parts_named = False @@ -81,18 +82,20 @@ class PiCreature(SVGMobject): def change_mode(self, mode): curr_center = self.get_center() curr_height = self.get_height() - looking_direction = None - looking_direction = self.get_looking_direction() - should_be_flipped = self.is_flipped() + should_be_flipped = self.is_flipped() + if self.is_looking_direction_purposeful: + looking_direction = self.get_looking_direction() self.__init__(mode) self.scale_to_fit_height(curr_height) self.shift(curr_center) - self.look(looking_direction) if should_be_flipped ^ self.is_flipped(): self.flip() + if self.is_looking_direction_purposeful: + self.look(looking_direction) return self def look(self, direction): + self.is_looking_direction_purposeful = True x, y = direction[:2] for pupil, eye in zip(self.pupils.split(), self.eyes.split()): pupil.move_to(eye, aligned_edge = direction) @@ -113,7 +116,7 @@ class PiCreature(SVGMobject): def get_looking_direction(self): return np.sign(np.round( self.pupils.get_center() - self.eyes.get_center(), - decimals = 1 + decimals = 2 )) def is_flipped(self):