diff --git a/animation/animation.py b/animation/animation.py index dcd72f6d..5e502cdf 100644 --- a/animation/animation.py +++ b/animation/animation.py @@ -35,6 +35,8 @@ class Animation(object): def update_config(self, **kwargs): digest_config(self, kwargs) + if "rate_func" in kwargs and kwargs["rate_func"] is None: + self.rate_func = (lambda x : x) return self def __str__(self): diff --git a/animation/transform.py b/animation/transform.py index 66d80bbc..72dfb48c 100644 --- a/animation/transform.py +++ b/animation/transform.py @@ -137,7 +137,8 @@ class Rotate(ApplyMethod): "in_place" : False, } def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs): - kwargs["path_arc"] = angle + if "path_arc" not in kwargs: + kwargs["path_arc"] = angle digest_config(self, kwargs, locals()) if self.in_place: method = mobject.rotate_in_place diff --git a/eola/chapter5.py b/eola/chapter5.py index 8e132873..2c4f2bf1 100644 --- a/eola/chapter5.py +++ b/eola/chapter5.py @@ -21,6 +21,24 @@ from eola.matrix import * from eola.two_d_space import * from eola.chapter3 import MatrixVectorMultiplicationAbstract +def get_det_text(matrix, determinant = None): + parens = TexMobject(["(", ")"]) + parens.scale(2) + parens.stretch_to_fit_height(matrix.get_height()) + l_paren, r_paren = parens.split() + l_paren.next_to(matrix, LEFT, buff = 0.1) + r_paren.next_to(matrix, RIGHT, buff = 0.1) + det = TextMobject("det").next_to(l_paren, LEFT, buff = 0.1) + det.add_background_rectangle() + det_text = VMobject(det, l_paren, r_paren) + if determinant is not None: + eq = TexMobject("=") + eq.next_to(r_paren, RIGHT, buff = 0.1) + result = TexMobject(str(determinant)) + result.next_to(eq, RIGHT, buff = 0.2) + det_text.add(eq, result) + return det_text + class Blob(Circle): CONFIG = { "stroke_color" : TEAL, @@ -49,6 +67,15 @@ class Blob(Circle): ) return sum(in_center_direction) <= 2 +class RightHand(VMobject): + def __init__(self, **kwargs): + hand = SVGMobject("RightHandOutline") + self.inlines = VMobject(*hand.split()[:-4]) + self.outline = VMobject(*hand.split()[-4:]) + self.outline.set_stroke(color = WHITE, width = 5) + self.inlines.set_stroke(color = DARK_GREY, width = 3) + VMobject.__init__(self, self.outline, self.inlines) + self.center().scale_to_fit_height(3) class OpeningQuote(Scene): def construct(self): @@ -378,20 +405,15 @@ class NameDeterminant(LinearTransformationScene): matrix.next_to(self.title, DOWN, buff = 0.5) matrix.shift(2*LEFT) matrix_background = BackgroundRectangle(matrix) - - braces = TexMobject("()") - braces.scale(2) - braces.stretch_to_fit_height(matrix.get_height()) - l_brace, r_brace = braces.split() - l_brace.next_to(matrix, LEFT, buff = 0.1) - r_brace.next_to(matrix, RIGHT, buff = 0.1) - det = TextMobject("det").next_to(l_brace, LEFT, buff = 0.1) - det.add_background_rectangle() - eq = TexMobject("=").next_to(r_brace, RIGHT, buff = 0.1) - - det_text = VMobject(det, l_brace, r_brace, eq) + det_text = get_det_text(matrix, 0) + det_text.remove(det_text.split()[-1]) return matrix_background, matrix, det_text +class DeterminantIsThree(NameDeterminant): + CONFIG = { + "t_matrix" : [[0, -1.5], [2, 1]] + } + class DeterminantIsOneHalf(NameDeterminant): CONFIG = { "t_matrix" : [[0.5, -0.5], [0.5, 0.5]], @@ -404,9 +426,707 @@ class DeterminantIsOneHalf(NameDeterminant): class DeterminantIsZero(NameDeterminant): CONFIG = { - "t_matrix" : [[2, 1], [2, 1]], + "t_matrix" : [[4, 2], [2, 1]], } +class NextFewVideos(Scene): + def construct(self): + icon = SVGMobject("video_icon") + icon.center() + icon.scale_to_fit_width(2*SPACE_WIDTH/12.) + icon.set_stroke(color = WHITE, width = 0) + icon.set_fill(WHITE, opacity = 1) + icons = VMobject(*[icon.copy() for x in range(10)]) + icons.submobject_gradient_highlight(BLUE_A, BLUE_D) + icons.arrange_submobjects(RIGHT) + icons.to_edge(LEFT) + + self.play( + FadeIn(icons, submobject_mode = "lagged_start"), + run_time = 3 + ) + self.dither() + +class WhatIveSaidSoFar(TeacherStudentsScene): + def construct(self): + self.setup() + self.teacher_says(""" + What I've said so far + is not quite right... + """) + self.dither() + +class NegativeDeterminant(Scene): + def construct(self): + numerical_matrix = [[1, 2], [3, 4]] + matrix = Matrix(numerical_matrix) + matrix.highlight_columns(X_COLOR, Y_COLOR) + det_text = get_det_text(matrix, np.linalg.det(numerical_matrix)) + words = TextMobject(""" + How can you scale area + by a negative number? + """) + words.highlight(YELLOW) + words.to_corner(UP+RIGHT) + det_num = det_text.split()[-1] + arrow = Arrow(words.get_bottom(), det_num) + + self.add(matrix) + self.play(Write(det_text)) + self.dither() + self.play( + Write(words, run_time = 2), + ShowCreation(arrow) + ) + self.play(det_num.highlight, YELLOW) + self.dither() + +class FlipSpaceOver(Scene): + def construct(self): + plane1 = NumberPlane(y_radius = SPACE_WIDTH) + plane2 = NumberPlane( + y_radius = SPACE_WIDTH, + color = RED_D, secondary_color = RED_E + ) + axis = UP + for word, plane in ("Front", plane1), ("Back", plane2): + text = TextMobject(word) + if word == "Back": + text.rotate(np.pi, axis = axis) + text.scale(2) + text.next_to(ORIGIN, RIGHT).to_edge(UP) + text.add_background_rectangle() + plane.add(text) + + self.play(ShowCreation( + plane1, submobject_mode = "lagged_start", + run_time = 1 + )) + self.dither() + self.play(Rotate( + plane1, axis = axis, + rate_func = lambda t : smooth(t/2), + run_time = 1.5, + path_arc = np.pi/2, + )) + self.remove(plane1) + self.play(Rotate( + plane2, axis = axis, + rate_func = lambda t : smooth((t+1)/2), + run_time = 1.5, + path_arc = np.pi/2, + )) + self.dither() + +class RandyThinking(Scene): + def construct(self): + randy = Randolph().to_corner() + bubble = randy.get_bubble() + bubble.make_green_screen() + + self.play( + randy.change_mode, "pondering", + ShowCreation(bubble) + ) + self.dither() + self.play(Blink(randy)) + self.dither(2) + self.play(Blink(randy)) + +class NegativeDeterminantTransformation(LinearTransformationScene): + CONFIG = { + "t_matrix" : [[1, 1], [2, -1]], + } + def construct(self): + self.setup() + self.add_title("Feels like flipping space") + self.dither() + self.apply_transposed_matrix(self.t_matrix) + self.dither() + +class ThinkAboutFlippingPaper(Scene): + def construct(self): + pass + +class NegativeDeterminantTransformation2(NegativeDeterminantTransformation): + CONFIG ={ + "t_matrix" : [[-2, 1], [2, 1]] + } + +class IHatJHatOrientation(NegativeDeterminantTransformation): + def construct(self): + self.setup() + i_label, j_label = self.get_basis_vector_labels() + self.add_transformable_label(self.i_hat, i_label, color = X_COLOR) + self.add_transformable_label(self.j_hat, j_label, color = Y_COLOR) + + arc = Arc(start_angle = 0, angle = np.pi/2, color = YELLOW) + arc.shift(0.5*(RIGHT+UP)).scale(1/1.6) + arc.add_tip() + words1 = TextMobject([ + "$\\hat{\\jmath}$", + "is to the", + "left", + "of", + "$\\hat{\\imath}$", + ]) + words1.split()[0].highlight(Y_COLOR) + words1.split()[2].highlight(YELLOW) + words1.split()[-1].highlight(X_COLOR) + words1.add_background_rectangle() + words1.next_to(arc, UP+RIGHT) + + words2 = TextMobject([ + "$L(\\hat{\\jmath})$", + "is to the \\\\", + "\\emph{right}", + "of", + "$L(\\hat{\\imath})$", + ]) + words2.split()[0].highlight(Y_COLOR) + words2.split()[2].highlight(YELLOW) + words2.split()[-1].highlight(X_COLOR) + words2.add_background_rectangle() + + + self.play(ShowCreation(arc)) + self.play(Write(words1)) + self.dither() + self.remove(words1, arc) + self.apply_transposed_matrix(self.t_matrix) + arc.submobjects = [] + arc.apply_function(self.get_matrix_transformation(self.t_matrix)) + arc.add_tip() + words2.next_to(arc, RIGHT) + self.play( + ShowCreation(arc), + Write(words2, run_time = 2), + ) + self.dither() + title = TextMobject("Orientation has been reversed") + title.to_edge(UP) + title.add_background_rectangle() + self.play(Write(title, run_time = 1)) + self.dither() + +class WriteNegativeDeterminant(NegativeDeterminantTransformation): + def construct(self): + self.setup() + self.add_unit_square() + matrix = Matrix(np.array(self.t_matrix).transpose()) + matrix.next_to(ORIGIN, LEFT) + matrix.to_edge(UP) + matrix.highlight_columns(X_COLOR, Y_COLOR) + + det_text = get_det_text( + matrix, determinant = np.linalg.det(self.t_matrix) + ) + three = VMobject(*det_text.split()[-1].split()[1:]) + for mob in det_text.split(): + if isinstance(mob, TexMobject): + mob.add_background_rectangle() + matrix_background = BackgroundRectangle(matrix) + self.play( + ShowCreation(matrix_background), + Write(matrix), + Write(det_text), + ) + self.add_foreground_mobject(matrix_background, matrix, det_text) + self.dither() + self.apply_transposed_matrix(self.t_matrix) + + self.play(three.copy().move_to, self.square) + self.dither() + +class AltWriteNegativeDeterminant(WriteNegativeDeterminant): + CONFIG = { + "t_matrix" : [[2, -1], [1, -3]] + } + +class WhyNegativeScaling(TeacherStudentsScene): + def construct(self): + self.setup() + self.student_says(""" + Why does negative area + relate to orientation-flipping? + """) + other_students = np.array(self.get_students())[[0, 2]] + self.play(*[ + ApplyMethod(student.change_mode, "confused") + for student in other_students + ]) + self.random_blink() + self.dither() + self.random_blink() + +class SlowlyRotateIHat(LinearTransformationScene): + def construct(self): + self.setup() + self.add_unit_square() + self.apply_transposed_matrix( + [[-1, 0], [0, 1]], + path_arc = np.pi, + run_time = 30, + rate_func = None, + ) + +class DeterminantGraphForRotatingIHat(Scene): + def construct(self): + t_axis = NumberLine( + numbers_with_elongated_ticks = [], + x_min = 0, + x_max = 10, + color = WHITE, + ) + det_axis = NumberLine( + numbers_with_elongated_ticks = [], + x_min = -2, + x_max = 2, + color = WHITE + ) + det_axis.rotate(np.pi/2) + t_axis.next_to(ORIGIN, RIGHT, buff = 0) + det_axis.move_to(t_axis.get_left()) + axes = VMobject(det_axis, t_axis) + graph = FunctionGraph(np.cos, x_min = 0, x_max = np.pi) + graph.next_to(det_axis, RIGHT, buff = 0) + graph.highlight(YELLOW) + det_word = TextMobject("Det") + det_word.next_to(det_axis, RIGHT, aligned_edge = UP) + time_word = TextMobject("time") + time_word.next_to(t_axis, UP) + time_word.to_edge(RIGHT) + everything = VMobject(axes, det_word, time_word, graph) + everything.scale(1.5) + + self.add(axes, det_word, time_word) + self.play(ShowCreation( + graph, rate_func = None, run_time = 10 + )) + +class WhatAboutThreeDimensions(TeacherStudentsScene): + def construct(self): + self.setup() + self.student_says(""" + What about 3D + transformations? + """) + self.random_blink() + self.dither() + self.random_blink() + +class Transforming3DCube(Scene): + def construct(self): + pass + +class NameParallelepiped(Scene): + def construct(self): + word = TextMobject("``Parallelepiped''") + word.scale(2) + pp_part1 = VMobject(*word.split()[:len(word.split())/2]) + pp_part2 = VMobject(*word.split()[len(word.split())/2:]) + pp_part1.submobject_gradient_highlight(X_COLOR, Y_COLOR) + pp_part2.submobject_gradient_highlight(Y_COLOR, Z_COLOR) + self.play(Write(word)) + self.dither(2) + +class DeterminantIsVolumeOfParallelepiped(Scene): + def construct(self): + matrix = Matrix([[1, 0, 0.5], [0.5, 1, 0], [1, 0, 1]]) + matrix.shift(3*LEFT) + matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR) + det_text = get_det_text(matrix) + eq = TexMobject("=") + eq.next_to(det_text, RIGHT) + words = TextMobject([ + "Volume of this\\\\", + "parallelepiped" + ]) + pp = words.split()[1] + pp_part1 = VMobject(*pp.split()[:len(pp.split())/2]) + pp_part2 = VMobject(*pp.split()[len(pp.split())/2:]) + pp_part1.submobject_gradient_highlight(X_COLOR, Y_COLOR) + pp_part2.submobject_gradient_highlight(Y_COLOR, Z_COLOR) + + words.next_to(eq, RIGHT) + + self.play(Write(matrix)) + self.dither() + self.play(Write(det_text), Write(words), Write(eq)) + self.dither() + +class Degenerate3DTransformation(Scene): + def construct(self): + pass + +class WriteZeroDeterminant(Scene): + def construct(self): + matrix = Matrix([[1, 0, 1], [0.5, 1, 1.5], [1, 0, 1]]) + matrix.shift(2*LEFT) + matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR) + det_text = get_det_text(matrix, 0) + brace = Brace(matrix, DOWN) + words = TextMobject(""" + Columns must be + linearly dependent + """) + words.highlight(YELLOW) + words.next_to(brace, DOWN) + + self.play(Write(matrix)) + self.dither() + self.play(Write(det_text)) + self.dither() + self.play( + GrowFromCenter(brace), + Write(words, run_time = 2) + ) + self.dither() + +class AskAboutNegaive3DDeterminant(TeacherStudentsScene): + def construct(self): + self.setup() + self.student_says(""" + What would det$(M) < 0$ mean? + """) + self.random_blink() + self.play(self.teacher.change_mode, "pondering") + self.dither() + self.random_blink() + +class OrientationReversing3DTransformation(Scene): + def construct(self): + pass + +class RightHandRule(Scene): + CONFIG = { + "flip" : False + } + def construct(self): + hand = RightHand() + i_hat = Vector([-1.75, 0.5]) + j_hat = Vector([-1.4, -0.7]) + k_hat = Vector([0, 1.7]) + i_label, j_label, k_label = [ + TexMobject("\\hat{%s}"%s).scale(1.5) + for s in "\\imath", "\\jmath", "k" + ] + i_label.next_to(i_hat.get_end(), UP) + j_label.next_to(j_hat.get_end(), DOWN) + k_label.next_to(k_hat.get_end(), UP) + + vects = [i_hat, j_hat, k_hat] + labels = [i_label, j_label, k_label] + colors = [X_COLOR, Y_COLOR, Z_COLOR] + + if self.flip: + VMobject(hand, *vects+labels).flip() + + # self.add(NumberPlane()) + self.play( + ShowCreation(hand.outline, run_time = 2, rate_func = None), + FadeIn(hand.inlines) + ) + self.dither() + for vect, label, color in zip(vects, labels, colors): + vect.highlight(color) + label.highlight(color) + vect.set_stroke(width = 8) + self.play(ShowCreation(vect)) + self.play(Write(label)) + self.dither() + +class LeftHandRule(RightHandRule): + CONFIG = { + "flip" : True + } + +class TwoDDeterminantFormula(Scene): + def construct(self): + eq = TextMobject("=") + matrix = Matrix([["a", "b"], ["c", "d"]]) + matrix.highlight_columns(X_COLOR, Y_COLOR) + ma, mb, mc, md = matrix.get_entries().split() + ma.shift(0.1*DOWN) + mc.shift(0.7*mc.get_height()*DOWN) + det_text = get_det_text(matrix) + VMobject(matrix, det_text).next_to(eq, LEFT) + formula = TexMobject(list("ad-bc")) + formula.next_to(eq, RIGHT) + formula.shift(0.2*UP) + + a, d, minus, b, c = formula.split() + VMobject(a, c).highlight(X_COLOR) + VMobject(b, d).highlight(Y_COLOR) + + for mob in mb, mc, b, c: + if mob is c: + mob.zero = TexMobject("\\cdot 0") + else: + mob.zero = TexMobject("0") + mob.zero.move_to(mob, side_to_align = DOWN+LEFT) + mob.zero.highlight(mob.get_color()) + mob.original = mob.copy() + c.zero.shift(0.1*RIGHT) + + self.add(matrix) + self.play(Write(det_text, run_time = 1)) + self.play(Write(eq), Write(formula)) + self.dither() + self.play(*[ + Transform(m, m.zero) + for m in mb, mc, b, c + ]) + self.dither() + for pair in (mc, c), (mb, b): + self.play(*[ + Transform(m, m.original) + for m in pair + ]) + self.dither() + +class TwoDDeterminantFormulaIntuition(LinearTransformationScene): + def construct(self): + self.setup() + self.add_unit_square() + a, b, c, d = 3, 2, 3.5, 2 + + self.dither() + self.apply_transposed_matrix([[a, 0], [0, 1]]) + i_brace = Brace(self.i_hat, DOWN) + width = TexMobject("a").scale(1.5) + i_brace.put_at_tip(width) + width.highlight(X_COLOR) + width.add_background_rectangle() + self.play(GrowFromCenter(i_brace), Write(width)) + self.dither() + + self.apply_transposed_matrix([[1, 0], [0, d]]) + side_brace = Brace(self.square, RIGHT) + height = TexMobject("d").scale(1.5) + side_brace.put_at_tip(height) + height.highlight(Y_COLOR) + height.add_background_rectangle() + self.play(GrowFromCenter(side_brace), Write(height)) + self.dither() + + self.apply_transposed_matrix( + [[1, 0], [float(b)/d, 1]], + added_anims = [ + ApplyMethod(m.shift, b*RIGHT) + for m in side_brace, height + ] + ) + self.dither() + self.play(*map(FadeOut, [i_brace, side_brace, width, height])) + matrix1 = np.dot( + [[a, b], [c, d]], + np.linalg.inv([[a, b], [0, d]]) + ) + matrix2 = np.dot( + [[a, b], [-c, d]], + np.linalg.inv([[a, b], [c, d]]) + ) + self.apply_transposed_matrix(matrix1.transpose(), path_arc = 0) + self.dither() + self.apply_transposed_matrix(matrix2.transpose(), path_arc = 0) + self.dither() + +class FullFormulaExplanation(LinearTransformationScene): + def construct(self): + self.setup() + self.add_unit_square() + self.apply_transposed_matrix([[3, 1], [1, 2]], run_time = 0) + self.add_braces() + self.add_polygons() + self.show_formula() + + def get_matrix(self): + matrix = Matrix([["a", "b"], ["c", "d"]]) + matrix.highlight_columns(X_COLOR, Y_COLOR) + ma, mb, mc, md = matrix.get_entries().split() + ma.shift(0.1*DOWN) + mc.shift(0.7*mc.get_height()*DOWN) + matrix.shift(2*DOWN+4*LEFT) + return matrix + + def add_polygons(self): + a = self.i_hat.get_end()[0]*RIGHT + b = self.j_hat.get_end()[0]*RIGHT + c = self.i_hat.get_end()[1]*UP + d = self.j_hat.get_end()[1]*UP + + shapes_colors_and_tex = [ + (Polygon(ORIGIN, a, a+c), TEAL, "bd/2"), + (Polygon(ORIGIN, d+b, d), TEAL, "\\dfrac{bd}{2}"), + (Polygon(a+c, a+b+c, a+b+c+d), MAROON, "\\dfrac{ac}{2}"), + (Polygon(b+d, a+b+c+d, b+c+d), MAROON, "ac/2"), + (Polygon(a, a+b, a+b+c, a+c), PINK, "bc"), + (Polygon(d, d+b, d+b+c, d+c), PINK, "bc"), + ] + everyone = VMobject() + for shape, color, tex in shapes_colors_and_tex: + shape.set_stroke(width = 0) + shape.set_fill(color = color, opacity = 0.7) + tex_mob = TexMobject(tex) + tex_mob.scale(0.7) + tex_mob.move_to(shape.get_center_of_mass()) + everyone.add(shape, tex_mob) + self.play(FadeIn( + everyone, + submobject_mode = "lagged_start", + run_time = 1 + )) + + + + def add_braces(self): + a = self.i_hat.get_end()[0]*RIGHT + b = self.j_hat.get_end()[0]*RIGHT + c = self.i_hat.get_end()[1]*UP + d = self.j_hat.get_end()[1]*UP + + quads = [ + (ORIGIN, a, DOWN, "a"), + (a, a+b, DOWN, "b"), + (a+b, a+b+c, RIGHT, "c"), + (a+b+c, a+b+c+d, RIGHT, "d"), + (a+b+c+d, a+c+d, UP, "a"), + (a+c+d, d+c, UP, "b"), + (d+c, d, LEFT, "c"), + (d, ORIGIN, LEFT, "d"), + ] + everyone = VMobject() + for p1, p2, direction, char in quads: + line = Line(p1, p2) + brace = Brace(line, direction, buff = 0) + text = brace.get_text(char) + text.add_background_rectangle() + if char in ["a", "c"]: + text.highlight(X_COLOR) + else: + text.highlight(Y_COLOR) + everyone.add(brace, text) + self.play(Write(everyone), run_time = 1) + + + def show_formula(self): + matrix = self.get_matrix() + det_text = get_det_text(matrix) + f_str = "=(a+b)(c+d)-ac-bd-2bc=ad-bc" + formula = TexMobject(f_str) + + formula.next_to(det_text, RIGHT) + everyone = VMobject(det_text, matrix, formula) + everyone.scale_to_fit_width(2*SPACE_WIDTH - 1) + everyone.next_to(DOWN, DOWN) + background_rect = BackgroundRectangle(everyone) + self.play( + ShowCreation(background_rect), + Write(everyone) + ) + self.dither() + +class ThreeDDetFormula(Scene): + def construct(self): + matrix = Matrix([list("abc"), list("def"), list("ghi")]) + matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR) + m1 = Matrix([["e", "f"], ["h", "i"]]) + m1.highlight_columns(Y_COLOR, Z_COLOR) + m2 = Matrix([["d", "f"], ["g", "i"]]) + m2.highlight_columns(X_COLOR, Z_COLOR) + m3 = Matrix([["d", "e"], ["g", "h"]]) + m3.highlight_columns(X_COLOR, Y_COLOR) + + for m in matrix, m1, m2, m3: + m.add(get_det_text(m)) + a, b, c = matrix.get_entries().split()[:3] + parts = it.starmap(VMobject, [ + [matrix], + [TexMobject("="), a.copy(), m1], + [TexMobject("-"), b.copy(), m2], + [TexMobject("+"), c.copy(), m3], + ]) + parts = list(parts) + for part in parts: + part.arrange_submobjects(RIGHT, buff = 0.2) + parts[1].next_to(parts[0], RIGHT) + parts[2].next_to(parts[1], DOWN, aligned_edge = LEFT) + parts[3].next_to(parts[2], DOWN, aligned_edge = LEFT) + everyone = VMobject(*parts) + everyone.center().to_edge(UP) + for part in parts: + self.play(Write(part)) + self.dither(2) + +class QuizTime(TeacherStudentsScene): + def construct(self): + self.setup() + self.teacher_says("Quiz time!") + self.random_blink() + self.dither() + self.random_blink() + +class ProductProperty(Scene): + def construct(self): + lhs = TexMobject([ + "\\text{det}(", + "M_1", + "M_2", + ")" + ]) + det, m1, m2, rp = lhs.split() + m1.highlight(TEAL) + m2.highlight(PINK) + + rhs = TexMobject([ + "=\\text{det}(", + "M_1", + ")\\text{det}(", + "M_2", + ")" + ]) + rhs.split()[1].highlight(TEAL) + rhs.split()[3].highlight(PINK) + + rhs.next_to(lhs, RIGHT) + formula = VMobject(lhs, rhs) + formula.center() + + title = TextMobject("Explain in one sentence") + title.highlight(YELLOW) + title.next_to(formula, UP, buff = 0.5) + + self.play(Write(m1)) + self.play(Write(m2)) + self.dither() + self.play(Write(det), Write(rp)) + self.play(Write(rhs)) + self.dither(2) + self.play(Write(title)) + self.dither(2) + +class NextVideo(Scene): + def construct(self): + title = TextMobject(""" + Next video: Inverse matrices, column space and null space + """) + title.scale_to_fit_width(2*SPACE_WIDTH - 2) + title.to_edge(UP) + 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/mobject/tex_mobject.py b/mobject/tex_mobject.py index dd146213..51df553b 100644 --- a/mobject/tex_mobject.py +++ b/mobject/tex_mobject.py @@ -103,7 +103,10 @@ class TexMobject(SVGMobject): ) def add_background_rectangle(self, color = BLACK, opacity = 0.75): - rect = BackgroundRectangle(self, color = color, opacity = opacity) + rect = BackgroundRectangle( + self, color = color, + fill_opacity = opacity + ) letters = VMobject(*self.submobjects) self.submobjects = [rect, letters] return self @@ -123,6 +126,7 @@ class Brace(TexMobject): } TEX_STRING = "\\underbrace{%s}"%(3*"\\qquad") def __init__(self, mobject, direction = DOWN, **kwargs): + digest_config(self, kwargs, locals()) TexMobject.__init__(self, self.TEX_STRING, **kwargs) angle = -np.arctan2(*direction[:2]) + np.pi mobject.rotate(-angle) @@ -133,6 +137,16 @@ class Brace(TexMobject): for mob in mobject, self: mob.rotate(angle) + def put_at_tip(self, mob, **kwargs): + mob.next_to(self, self.direction, **kwargs) + return self + + def get_text(self, text, **kwargs): + text_mob = TextMobject(text) + self.put_at_tip(text_mob, **kwargs) + return text_mob + + def tex_hash(expression, template_tex_file): return str(hash(expression + template_tex_file)) diff --git a/topics/geometry.py b/topics/geometry.py index dff36478..136b80ad 100644 --- a/topics/geometry.py +++ b/topics/geometry.py @@ -31,6 +31,14 @@ class Arc(VMobject): ) ] + def add_tip(self): + #TODO, do this a better way + arrow = Arrow(*self.points[-2:]) + self.add(arrow.split()[-1]) + self.highlight(self.get_color()) + return self + + class Circle(Arc): CONFIG = { "color" : RED,