mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
Beginning eola project
This commit is contained in:
0
eola/__init__.py
Normal file
0
eola/__init__.py
Normal file
299
eola/chapter0.py
Normal file
299
eola/chapter0.py
Normal file
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
90
eola/utils.py
Normal file
90
eola/utils.py
Normal file
@ -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
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user