mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 13:34:19 +08:00
Finished preliminary animations for eola intro video
This commit is contained in:
338
eola/chapter0.py
338
eola/chapter0.py
@ -38,13 +38,47 @@ class OpeningQuote(Scene):
|
||||
words.to_edge(UP)
|
||||
for mob in words.submobjects[48:49+13]:
|
||||
mob.highlight(GREEN)
|
||||
author = TextMobject("-Hermann Weyl")
|
||||
author = TextMobject("-Jean Dieudonn\\'e")
|
||||
author.highlight(YELLOW)
|
||||
author.next_to(words, DOWN)
|
||||
|
||||
self.play(FadeIn(words))
|
||||
self.dither(3)
|
||||
self.play(Write(author))
|
||||
self.play(Write(author, run_time = 5))
|
||||
self.dither()
|
||||
|
||||
class VideoIcon(SVGMobject):
|
||||
def __init__(self, **kwargs):
|
||||
SVGMobject.__init__(self, "video_icon", **kwargs)
|
||||
self.center()
|
||||
self.scale_to_fit_width(2*SPACE_WIDTH/12.)
|
||||
self.set_stroke(color = WHITE, width = 0)
|
||||
self.set_fill(color = WHITE, opacity = 1)
|
||||
|
||||
|
||||
|
||||
class UpcomingSeriesOfVidoes(Scene):
|
||||
def construct(self):
|
||||
icons = [VideoIcon() for x in range(10)]
|
||||
colors = Color(BLUE_A).range_to(BLUE_D, len(icons))
|
||||
for icon, color in zip(icons, colors):
|
||||
icon.set_fill(color, opacity = 1)
|
||||
icons = VMobject(*icons)
|
||||
icons.arrange_submobjects(RIGHT)
|
||||
icons.to_edge(LEFT)
|
||||
icons.shift(UP)
|
||||
icons = icons.split()
|
||||
|
||||
def rate_func_creator(offset):
|
||||
return lambda a : min(max(2*(a-offset), 0), 1)
|
||||
self.play(*[
|
||||
FadeIn(
|
||||
icon,
|
||||
run_time = 5,
|
||||
rate_func = rate_func_creator(offset)
|
||||
)
|
||||
for icon, offset in zip(icons, np.linspace(0, 0.5, len(icons)))
|
||||
])
|
||||
self.dither()
|
||||
|
||||
|
||||
@ -612,12 +646,300 @@ class PhysicsExample(Scene):
|
||||
|
||||
class LinearAlgebraIntuitions(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
title = TextMobject("Preview of core visual intuitions")
|
||||
title.to_edge(UP)
|
||||
h_line = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
|
||||
h_line.next_to(title, DOWN)
|
||||
h_line.highlight(BLUE_E)
|
||||
intuitions = [
|
||||
"Matrices transform space",
|
||||
"Matrix multiplication corresponds to applying " +
|
||||
"one transformation after another",
|
||||
"The determinant gives the factor by which areas change",
|
||||
]
|
||||
|
||||
self.play(
|
||||
Write(title),
|
||||
ShowCreation(h_line),
|
||||
run_time = 2
|
||||
)
|
||||
|
||||
for count, intuition in enumerate(intuitions, 3):
|
||||
intuition += " (details coming in chapter %d)"%count
|
||||
mob = TextMobject(intuition)
|
||||
mob.scale(0.7)
|
||||
mob.next_to(h_line, DOWN)
|
||||
self.play(FadeIn(mob))
|
||||
self.dither(4)
|
||||
self.play(FadeOut(mob))
|
||||
self.remove(mob)
|
||||
self.dither()
|
||||
|
||||
class MatricesAre(Scene):
|
||||
def construct(self):
|
||||
matrix = matrix_to_mobject([[1, -1], [1, 2]])
|
||||
matrix.scale_to_fit_height(6)
|
||||
arrow = Arrow(LEFT, RIGHT, stroke_width = 8, preserve_tip_size_when_scaling = False)
|
||||
arrow.scale(2)
|
||||
arrow.to_edge(RIGHT)
|
||||
matrix.next_to(arrow, LEFT)
|
||||
|
||||
self.play(Write(matrix, run_time = 1))
|
||||
self.play(ShowCreation(arrow, submobject_mode = "one_at_a_time"))
|
||||
self.dither()
|
||||
|
||||
class ExampleTransformationForIntuitionList(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.apply_matrix([[1, -1], [1, 2]])
|
||||
self.dither()
|
||||
|
||||
class MatrixMultiplicationIs(Scene):
|
||||
def construct(self):
|
||||
matrix1 = matrix_to_mobject([[1, -1], [1, 2]])
|
||||
matrix1.highlight(BLUE)
|
||||
matrix2 = matrix_to_mobject([[2, 1], [1, 2]])
|
||||
matrix2.highlight(GREEN)
|
||||
for m in matrix1, matrix2:
|
||||
m.scale_to_fit_height(3)
|
||||
arrow = Arrow(LEFT, RIGHT, stroke_width = 6, preserve_tip_size_when_scaling = False)
|
||||
arrow.scale(2)
|
||||
arrow.to_edge(RIGHT)
|
||||
matrix1.next_to(arrow, LEFT)
|
||||
matrix2.next_to(matrix1, LEFT)
|
||||
brace1 = Brace(matrix1, UP)
|
||||
apply_first = TextMobject("Apply first").next_to(brace1, UP)
|
||||
brace2 = Brace(matrix2, DOWN)
|
||||
apply_second = TextMobject("Apply second").next_to(brace2, DOWN)
|
||||
|
||||
self.play(
|
||||
Write(matrix1),
|
||||
ShowCreation(arrow),
|
||||
GrowFromCenter(brace1),
|
||||
Write(apply_first),
|
||||
run_time = 1
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
Write(matrix2),
|
||||
GrowFromCenter(brace2),
|
||||
Write(apply_second),
|
||||
run_time = 1
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class ComposedTransformsForIntuitionList(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.apply_matrix([[1, -1], [1, 2]])
|
||||
self.dither()
|
||||
self.apply_matrix([[2, 1], [1, 2]])
|
||||
self.dither()
|
||||
|
||||
class DeterminantsAre(Scene):
|
||||
def construct(self):
|
||||
tex_mob = TexMobject("""
|
||||
\\text{Det}\\left(\\left[
|
||||
\\begin{array}{cc}
|
||||
1 & -1 \\\\
|
||||
1 & 2
|
||||
\\end{array}
|
||||
\\right]\\right)
|
||||
""")
|
||||
tex_mob.scale_to_fit_height(4)
|
||||
arrow = Arrow(LEFT, RIGHT, stroke_width = 8, preserve_tip_size_when_scaling = False)
|
||||
arrow.scale(2)
|
||||
arrow.to_edge(RIGHT)
|
||||
tex_mob.next_to(arrow, LEFT)
|
||||
|
||||
self.play(
|
||||
Write(tex_mob),
|
||||
ShowCreation(arrow, submobject_mode = "one_at_a_time"),
|
||||
run_time = 1
|
||||
)
|
||||
|
||||
class TransformationForDeterminant(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
square = Square(side_length = 1)
|
||||
square.shift(-square.get_corner(DOWN+LEFT))
|
||||
square.set_fill(YELLOW_A, 0.5)
|
||||
self.add_transformable_mobject(square)
|
||||
self.apply_matrix([[1, -1], [1, 2]])
|
||||
|
||||
class ProfessorsTry(Scene):
|
||||
def construct(self):
|
||||
morty = Mortimer()
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
morty.shift(3*LEFT)
|
||||
speech_bubble = morty.get_bubble("speech", height = 4, width = 8)
|
||||
speech_bubble.shift(RIGHT)
|
||||
words = TextMobject(
|
||||
"It really is beautiful! I want you to \\\\" + \
|
||||
"see it the way I do...",
|
||||
)
|
||||
speech_bubble.position_mobject_inside(words)
|
||||
thought_bubble = ThoughtBubble(width = 4, height = 3.5)
|
||||
thought_bubble.next_to(morty, UP)
|
||||
thought_bubble.to_edge(RIGHT)
|
||||
randy = Randolph()
|
||||
randy.scale(0.8)
|
||||
randy.to_corner()
|
||||
|
||||
self.add(randy, morty)
|
||||
self.play(
|
||||
ApplyMethod(morty.change_mode, "speaking"),
|
||||
FadeIn(speech_bubble),
|
||||
FadeIn(words)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(FadeIn(thought_bubble ))
|
||||
self.play(Blink(morty))
|
||||
|
||||
|
||||
class ExampleMatrixMultiplication(NumericalMatrixMultiplication):
|
||||
CONFIG = {
|
||||
"left_matrix" : [[-3, 1], [2, 5]],
|
||||
"right_matrix" : [[5, 3], [7, -3]]
|
||||
}
|
||||
|
||||
class TableOfContents(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Essence of Linear Algebra")
|
||||
title.highlight(BLUE)
|
||||
title.to_corner(UP+LEFT)
|
||||
h_line = Line(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
|
||||
h_line.next_to(title, DOWN)
|
||||
h_line.to_edge(LEFT, buff = 0)
|
||||
chapters = VMobject(*map(TextMobject, [
|
||||
"Chapter 1: Vectors, what even are they?",
|
||||
"Chapter 2: Linear combinations, span and bases",
|
||||
"Chapter 3: Matrices as linear transformations",
|
||||
"Chapter 4: Matrix multiplication as composition",
|
||||
"Chapter 5: The determinant",
|
||||
"Chapter 6: Inverse matrices, column space and null space",
|
||||
"Chapter 7: Dot products and cross products",
|
||||
"Chapter 8: Change of basis",
|
||||
"Chapter 9: Eigenvectors and eigenvalues",
|
||||
"Chapter 10: Abstract vector spaces",
|
||||
]))
|
||||
chapters.arrange_submobjects(DOWN)
|
||||
chapters.scale(0.7)
|
||||
chapters.next_to(h_line, DOWN)
|
||||
|
||||
self.play(
|
||||
Write(title),
|
||||
ShowCreation(h_line)
|
||||
)
|
||||
for chapter in chapters.split():
|
||||
chapter.to_edge(LEFT, buff = 1)
|
||||
self.play(FadeIn(chapter))
|
||||
self.dither(2)
|
||||
|
||||
entry3 = chapters.split()[2]
|
||||
added_words = TextMobject("(Personally, I'm most excited \\\\ to do this one)")
|
||||
added_words.scale(0.5)
|
||||
added_words.highlight(YELLOW)
|
||||
added_words.next_to(h_line, DOWN)
|
||||
added_words.to_edge(RIGHT)
|
||||
arrow = Arrow(added_words.get_bottom(), entry3)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(entry3.highlight, YELLOW),
|
||||
ShowCreation(arrow, submobject_mode = "one_at_a_time"),
|
||||
Write(added_words),
|
||||
run_time = 1
|
||||
)
|
||||
self.dither()
|
||||
removeable = VMobject(added_words, arrow, h_line, title)
|
||||
self.play(FadeOut(removeable))
|
||||
self.remove(removeable)
|
||||
|
||||
self.series_of_videos(chapters)
|
||||
|
||||
def series_of_videos(self, chapters):
|
||||
icon = SVGMobject("video_icon")
|
||||
icon.center()
|
||||
icon.scale_to_fit_width(2*SPACE_WIDTH/12.)
|
||||
icon.set_stroke(color = WHITE, width = 0)
|
||||
icons = [icon.copy() for chapter in chapters.split()]
|
||||
colors = Color(BLUE_A).range_to(BLUE_D, len(icons))
|
||||
for icon, color in zip(icons, colors):
|
||||
icon.set_fill(color, opacity = 1)
|
||||
icons = VMobject(*icons)
|
||||
icons.arrange_submobjects(RIGHT)
|
||||
icons.to_edge(LEFT)
|
||||
icons.shift(UP)
|
||||
|
||||
randy = Randolph()
|
||||
randy.to_corner()
|
||||
bubble = randy.get_bubble()
|
||||
new_icons = icons.copy().scale(0.2)
|
||||
bubble.position_mobject_inside(new_icons)
|
||||
|
||||
self.play(Transform(
|
||||
chapters, icons,
|
||||
path_arc = np.pi/2,
|
||||
))
|
||||
self.clear()
|
||||
self.add(icons)
|
||||
self.play(FadeIn(randy))
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
self.play(
|
||||
ShowCreation(bubble),
|
||||
Transform(icons, new_icons)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
class ResourceForTeachers(Scene):
|
||||
def construct(self):
|
||||
morty = Mortimer(mode = "speaking")
|
||||
morty.to_corner(DOWN + RIGHT)
|
||||
bubble = morty.get_bubble("speech")
|
||||
bubble.write("I'm assuming you \\\\ know linear algebra\\dots")
|
||||
words = bubble.content
|
||||
bubble.clear()
|
||||
randys = VMobject(*[
|
||||
Randolph(color = c)
|
||||
for c in BLUE_D, BLUE_C, BLUE_E
|
||||
])
|
||||
randys.arrange_submobjects(RIGHT)
|
||||
randys.scale(0.8)
|
||||
randys.to_corner(DOWN+LEFT)
|
||||
|
||||
self.add(randys, morty)
|
||||
self.play(FadeIn(bubble), Write(words), run_time = 3)
|
||||
for randy in np.array(randys.split())[[2,0,1]]:
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
|
||||
class PauseAndPonder(Scene):
|
||||
def construct(self):
|
||||
pause = TexMobject("=").rotate(np.pi/2)
|
||||
pause.stretch(0.5, 1)
|
||||
pause.scale_to_fit_height(1.5)
|
||||
bubble = ThoughtBubble().scale_to_fit_height(2)
|
||||
pause.shift(LEFT)
|
||||
bubble.next_to(pause, RIGHT, buff = 1)
|
||||
|
||||
self.play(FadeIn(pause))
|
||||
self.play(ShowCreation(bubble))
|
||||
self.dither()
|
||||
|
||||
|
||||
class NextVideo(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Next video: Vectors, what even are they?")
|
||||
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()
|
||||
|
||||
|
||||
|
||||
|
208
eola/utils.py
208
eola/utils.py
@ -1,11 +1,14 @@
|
||||
import numpy as np
|
||||
|
||||
from scene import Scene
|
||||
from mobject import Mobject
|
||||
from mobject.vectorized_mobject import VMobject
|
||||
from mobject.tex_mobject import TexMobject, TextMobject
|
||||
from animation.transform import ApplyPointwiseFunction, Transform
|
||||
from animation.transform import ApplyPointwiseFunction, Transform, \
|
||||
ApplyMethod, FadeOut
|
||||
from animation.simple_animations import ShowCreation
|
||||
from topics.number_line import NumberPlane
|
||||
from topics.geometry import Vector
|
||||
from topics.geometry import Vector, Line, Circle
|
||||
|
||||
|
||||
from helpers import *
|
||||
@ -32,8 +35,13 @@ class LinearTransformationScene(Scene):
|
||||
"foreground_plane_kwargs" : {
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_HEIGHT,
|
||||
"secondary_line_ratio" : 0
|
||||
},
|
||||
"background_plane_kwargs" : {
|
||||
"color" : GREY,
|
||||
"secondary_color" : DARK_GREY,
|
||||
"axes_color" : GREY,
|
||||
},
|
||||
"background_plane_kwargs" : {},
|
||||
"show_coordinates" : False,
|
||||
"show_basis_vectors" : True,
|
||||
"i_hat_color" : GREEN_B,
|
||||
@ -45,29 +53,27 @@ class LinearTransformationScene(Scene):
|
||||
self.moving_vectors = []
|
||||
|
||||
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)
|
||||
self.add_background_mobject(self.background_plane)
|
||||
if self.include_foreground_plane:
|
||||
self.plane = NumberPlane(**self.foreground_plane_kwargs)
|
||||
self.add_to_transformable(self.plane)
|
||||
self.add_transformable_mobject(self.plane)
|
||||
if self.show_basis_vectors:
|
||||
self.add_vector((1, 0), self.i_hat_color)
|
||||
self.add_vector((0, 1), self.j_hat_color)
|
||||
|
||||
def add_to_background(self, *mobjects):
|
||||
def add_background_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.background_mobjects:
|
||||
self.background_mobjects.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_to_transformable(self, *mobjects):
|
||||
def add_transformable_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.transformable_mobject:
|
||||
self.transformable_mobject.append(mobject)
|
||||
@ -109,6 +115,190 @@ class LinearTransformationScene(Scene):
|
||||
)
|
||||
)
|
||||
|
||||
class Matrix(VMobject):
|
||||
CONFIG = {
|
||||
"v_buff" : 0.5,
|
||||
"h_buff" : 1,
|
||||
}
|
||||
def __init__(self, matrix, **kwargs):
|
||||
"""
|
||||
Matrix can either either include numbres, tex_strings,
|
||||
or mobjects
|
||||
"""
|
||||
VMobject.__init__(self, **kwargs)
|
||||
matrix = np.array(matrix)
|
||||
assert(matrix.ndim == 2)
|
||||
if not isinstance(matrix[0][0], Mobject):
|
||||
matrix = matrix.astype("string")
|
||||
matrix = self.string_matrix_to_mob_matrix(matrix)
|
||||
self.organize_mob_matrix(matrix)
|
||||
self.add(*matrix.flatten())
|
||||
self.add_brackets()
|
||||
self.center()
|
||||
self.mob_matrix = matrix
|
||||
|
||||
def string_matrix_to_mob_matrix(self, matrix):
|
||||
return np.array([
|
||||
map(TexMobject, row)
|
||||
for row in matrix
|
||||
])
|
||||
|
||||
def organize_mob_matrix(self, matrix):
|
||||
for i, row in enumerate(matrix):
|
||||
for j, elem in enumerate(row):
|
||||
mob = matrix[i][j]
|
||||
if i == 0 and j == 0:
|
||||
continue
|
||||
elif i == 0:
|
||||
mob.next_to(matrix[i][j-1], RIGHT, self.h_buff)
|
||||
else:
|
||||
mob.next_to(matrix[i-1][j], DOWN, self.v_buff)
|
||||
return self
|
||||
|
||||
def get_mob_matrix(self):
|
||||
return self.mob_matrix
|
||||
|
||||
def add_brackets(self):
|
||||
bracket_pair = TexMobject("\\big[ \\big]")
|
||||
bracket_pair.scale(2)
|
||||
bracket_pair.stretch_to_fit_height(self.get_height() + 0.5)
|
||||
l_bracket, r_bracket = bracket_pair.split()
|
||||
l_bracket.next_to(self, LEFT)
|
||||
r_bracket.next_to(self, RIGHT)
|
||||
self.add(l_bracket, r_bracket)
|
||||
return self
|
||||
|
||||
|
||||
class NumericalMatrixMultiplication(Scene):
|
||||
CONFIG = {
|
||||
"left_matrix" : [[1, 2], [3, 4]],
|
||||
"right_matrix" : [[5, 6], [7, 8]]
|
||||
}
|
||||
def construct(self):
|
||||
left_string_matrix, right_string_matrix = [
|
||||
np.array(matrix).astype("string")
|
||||
for matrix in self.left_matrix, self.right_matrix
|
||||
]
|
||||
if right_string_matrix.shape[0] != left_string_matrix.shape[1]:
|
||||
raise Exception("Incompatible shapes for matrix multiplication")
|
||||
|
||||
left = Matrix(left_string_matrix)
|
||||
right = Matrix(right_string_matrix)
|
||||
result = self.get_result_matrix(
|
||||
left_string_matrix, right_string_matrix
|
||||
)
|
||||
|
||||
self.organize_matrices(left, right, result)
|
||||
# self.add_lines(left, right)
|
||||
self.animate_product(left, right, result)
|
||||
|
||||
|
||||
def get_result_matrix(self, left, right):
|
||||
(m, k), n = left.shape, right.shape[1]
|
||||
mob_matrix = np.array([VMobject()]).repeat(m*n).reshape((m, n))
|
||||
for a in range(m):
|
||||
for b in range(n):
|
||||
parts = [
|
||||
prefix + "(%s)(%s)"%(left[a][c], right[c][b])
|
||||
for c in range(k)
|
||||
for prefix in ["" if c == 0 else "+"]
|
||||
]
|
||||
mob_matrix[a][b] = TexMobject(parts, next_to_buff = 0.1)
|
||||
return Matrix(mob_matrix)
|
||||
|
||||
def add_lines(self, left, right):
|
||||
line_kwargs = {
|
||||
"color" : BLUE,
|
||||
"stroke_width" : 2,
|
||||
}
|
||||
left_rows = [
|
||||
VMobject(*row) for row in left.get_mob_matrix()
|
||||
]
|
||||
h_lines = VMobject()
|
||||
for row in left_rows[:-1]:
|
||||
h_line = Line(row.get_left(), row.get_right(), **line_kwargs)
|
||||
h_line.next_to(row, DOWN, buff = left.v_buff/2.)
|
||||
h_lines.add(h_line)
|
||||
|
||||
right_cols = [
|
||||
VMobject(*col) for col in np.transpose(right.get_mob_matrix())
|
||||
]
|
||||
v_lines = VMobject()
|
||||
for col in right_cols[:-1]:
|
||||
v_line = Line(col.get_top(), col.get_bottom(), **line_kwargs)
|
||||
v_line.next_to(col, RIGHT, buff = right.h_buff/2.)
|
||||
v_lines.add(v_line)
|
||||
|
||||
self.play(ShowCreation(h_lines))
|
||||
self.play(ShowCreation(v_lines))
|
||||
self.dither()
|
||||
self.show_frame()
|
||||
|
||||
def organize_matrices(self, left, right, result):
|
||||
equals = TexMobject("=")
|
||||
everything = VMobject(left, right, equals, result)
|
||||
everything.arrange_submobjects()
|
||||
everything.scale_to_fit_width(2*SPACE_WIDTH-1)
|
||||
self.add(everything)
|
||||
|
||||
|
||||
def animate_product(self, left, right, result):
|
||||
l_matrix = left.get_mob_matrix()
|
||||
r_matrix = right.get_mob_matrix()
|
||||
result_matrix = result.get_mob_matrix()
|
||||
circle = Circle(
|
||||
radius = l_matrix[0][0].get_height(),
|
||||
color = GREEN
|
||||
)
|
||||
circles = VMobject(*[
|
||||
entry.get_point_mobject()
|
||||
for entry in l_matrix[0][0], r_matrix[0][0]
|
||||
])
|
||||
(m, k), n = l_matrix.shape, r_matrix.shape[1]
|
||||
for mob in result_matrix.flatten():
|
||||
mob.highlight(BLACK)
|
||||
lagging_anims = []
|
||||
for a in range(m):
|
||||
for b in range(n):
|
||||
for c in range(k):
|
||||
l_matrix[a][c].highlight(YELLOW)
|
||||
r_matrix[c][b].highlight(YELLOW)
|
||||
for c in range(k):
|
||||
start_parts = VMobject(
|
||||
l_matrix[a][c].copy(),
|
||||
r_matrix[c][b].copy()
|
||||
)
|
||||
result_entry = result_matrix[a][b].split()[c]
|
||||
|
||||
new_circles = VMobject(*[
|
||||
circle.copy().shift(part.get_center())
|
||||
for part in start_parts.split()
|
||||
])
|
||||
self.play(Transform(circles, new_circles))
|
||||
self.play(
|
||||
Transform(
|
||||
start_parts,
|
||||
result_entry.copy().highlight(YELLOW),
|
||||
path_arc = -np.pi/2
|
||||
),
|
||||
*lagging_anims
|
||||
)
|
||||
result_entry.highlight(YELLOW)
|
||||
self.remove(start_parts)
|
||||
lagging_anims = [
|
||||
ApplyMethod(result_entry.highlight, WHITE)
|
||||
]
|
||||
|
||||
for c in range(k):
|
||||
l_matrix[a][c].highlight(WHITE)
|
||||
r_matrix[c][b].highlight(WHITE)
|
||||
self.play(FadeOut(circles), *lagging_anims)
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,8 @@ from scipy import linalg
|
||||
|
||||
from constants import *
|
||||
|
||||
CLOSED_THRESHOLD = 0.01
|
||||
|
||||
def get_smooth_handle_points(points):
|
||||
num_handles = len(points) - 1
|
||||
dim = points.shape[1]
|
||||
@ -76,7 +78,7 @@ def diag_to_matrix(l_and_u, diag):
|
||||
return matrix
|
||||
|
||||
def is_closed(points):
|
||||
return np.all(points[0] == points[-1])
|
||||
return np.linalg.norm(points[0] - points[-1]) < CLOSED_THRESHOLD
|
||||
|
||||
def color_to_rgb(color):
|
||||
return np.array(Color(color).get_rgb())
|
||||
|
@ -26,6 +26,7 @@ class PiCreature(SVGMobject):
|
||||
"fill_opacity" : 1.0,
|
||||
"initial_scale_val" : 0.01,
|
||||
"corner_scale_factor" : 0.75,
|
||||
"flip_at_start" : False,
|
||||
}
|
||||
def __init__(self, mode = "plain", **kwargs):
|
||||
self.parts_named = False
|
||||
@ -36,6 +37,8 @@ class PiCreature(SVGMobject):
|
||||
digest_config(self, kwargs, locals())
|
||||
SVGMobject.__init__(self, svg_file, **kwargs)
|
||||
self.init_colors()
|
||||
if self.flip_at_start:
|
||||
self.flip()
|
||||
|
||||
def name_parts(self):
|
||||
self.mouth = self.submobjects[MOUTH_INDEX]
|
||||
@ -122,14 +125,11 @@ class Randolph(PiCreature):
|
||||
|
||||
class Mortimer(PiCreature):
|
||||
CONFIG = {
|
||||
"color" : "#736357"
|
||||
"color" : "#736357",
|
||||
"flip_at_start" : True,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
PiCreature.__init__(self, *args, **kwargs)
|
||||
self.flip()
|
||||
|
||||
|
||||
class Mathematician(PiCreature):
|
||||
CONFIG = {
|
||||
"color" : GREY,
|
||||
@ -219,6 +219,7 @@ class Bubble(SVGMobject):
|
||||
class SpeechBubble(Bubble):
|
||||
CONFIG = {
|
||||
"file_name" : "Bubbles_speech.svg",
|
||||
"height" : 4
|
||||
}
|
||||
|
||||
class ThoughtBubble(Bubble):
|
||||
@ -226,3 +227,10 @@ class ThoughtBubble(Bubble):
|
||||
"file_name" : "Bubbles_thought.svg",
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
Bubble.__init__(self, **kwargs)
|
||||
self.submobjects.sort(
|
||||
lambda m1, m2 : int((m1.get_bottom()-m2.get_bottom())[1])
|
||||
)
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ class Arc(VMobject):
|
||||
"radius" : 1.0,
|
||||
"start_angle" : 0,
|
||||
"num_anchors" : 8,
|
||||
"anchors_span_full_range" : True
|
||||
"anchors_span_full_range" : True,
|
||||
}
|
||||
def __init__(self, angle, **kwargs):
|
||||
digest_locals(self)
|
||||
@ -164,6 +164,7 @@ class Arrow(Line):
|
||||
if self.preserve_tip_size_when_scaling:
|
||||
self.remove(self.tip)
|
||||
self.add_tip()
|
||||
return self
|
||||
|
||||
class Vector(Arrow):
|
||||
CONFIG = {
|
||||
|
Reference in New Issue
Block a user