mirror of
https://github.com/3b1b/manim.git
synced 2025-07-31 22:13:30 +08:00
Beginning chapter 11 animations
This commit is contained in:
@ -29,7 +29,7 @@ def plane_wave_homotopy(x, y, z, t):
|
|||||||
norm = np.linalg.norm([x, y])
|
norm = np.linalg.norm([x, y])
|
||||||
tau = interpolate(5, -5, t) + norm/SPACE_WIDTH
|
tau = interpolate(5, -5, t) + norm/SPACE_WIDTH
|
||||||
alpha = sigmoid(tau)
|
alpha = sigmoid(tau)
|
||||||
return [x, y + 0.5*np.sin(2*np.pi*alpha), z]
|
return [x, y + 0.5*np.sin(2*np.pi*alpha)-t*SMALL_BUFF/2, z]
|
||||||
|
|
||||||
class Physicist(PiCreature):
|
class Physicist(PiCreature):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
@ -998,8 +998,8 @@ class NonZeroSolutionsVisually(LinearTransformationScene):
|
|||||||
equation.highlight_by_tex("\\lambda", MAROON_B)
|
equation.highlight_by_tex("\\lambda", MAROON_B)
|
||||||
equation.highlight_by_tex("\\vec{\\textbf{v}}", YELLOW)
|
equation.highlight_by_tex("\\vec{\\textbf{v}}", YELLOW)
|
||||||
equation.add_background_rectangle()
|
equation.add_background_rectangle()
|
||||||
equation.next_to(ORIGIN, LEFT, buff = MED_BUFF)
|
equation.next_to(ORIGIN, DOWN, buff = MED_BUFF)
|
||||||
equation.to_edge(UP)
|
equation.to_edge(LEFT)
|
||||||
|
|
||||||
det_equation = TexMobject(
|
det_equation = TexMobject(
|
||||||
"\\text{Squishification} \\Rightarrow",
|
"\\text{Squishification} \\Rightarrow",
|
||||||
@ -1136,7 +1136,10 @@ class TweakLambda(LinearTransformationScene):
|
|||||||
self.add(*self.lambda_vals)
|
self.add(*self.lambda_vals)
|
||||||
|
|
||||||
new_det = DecimalNumber(
|
new_det = DecimalNumber(
|
||||||
np.linalg.det(self.t_matrix - val*np.identity(2))
|
np.linalg.det([
|
||||||
|
self.i_hat.get_end()[:2],
|
||||||
|
self.j_hat.get_end()[:2],
|
||||||
|
])
|
||||||
)
|
)
|
||||||
new_det.move_to(self.det, aligned_edge = LEFT)
|
new_det.move_to(self.det, aligned_edge = LEFT)
|
||||||
new_det.highlight(self.det.get_color())
|
new_det.highlight(self.det.get_color())
|
||||||
|
997
eola/chapter11.py
Normal file
997
eola/chapter11.py
Normal file
@ -0,0 +1,997 @@
|
|||||||
|
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 topics.geometry import *
|
||||||
|
from topics.characters import *
|
||||||
|
from topics.functions import *
|
||||||
|
from topics.number_line import *
|
||||||
|
from topics.numerals import *
|
||||||
|
from scene import Scene
|
||||||
|
from mobject.svg_mobject import *
|
||||||
|
from mobject.tex_mobject import *
|
||||||
|
from mobject.vectorized_mobject import *
|
||||||
|
|
||||||
|
from eola.matrix import *
|
||||||
|
from eola.two_d_space import *
|
||||||
|
from eola.chapter1 import plane_wave_homotopy
|
||||||
|
from eola.chapter3 import ColumnsToBasisVectors
|
||||||
|
from eola.chapter5 import NameDeterminant
|
||||||
|
from eola.chapter9 import get_small_bubble
|
||||||
|
from eola.chapter10 import ExampleTranformationScene
|
||||||
|
|
||||||
|
class Student(PiCreature):
|
||||||
|
CONFIG = {
|
||||||
|
"name" : "Student"
|
||||||
|
}
|
||||||
|
def get_name(self):
|
||||||
|
text = TextMobject(self.name)
|
||||||
|
text.add_background_rectangle()
|
||||||
|
text.next_to(self, DOWN)
|
||||||
|
return text
|
||||||
|
|
||||||
|
class PhysicsStudent(Student):
|
||||||
|
CONFIG = {
|
||||||
|
"color" : PINK,
|
||||||
|
"name" : "Physics student"
|
||||||
|
}
|
||||||
|
|
||||||
|
class CSStudent(Student):
|
||||||
|
CONFIG = {
|
||||||
|
"color" : PURPLE_E,
|
||||||
|
"flip_at_start" : True,
|
||||||
|
"name" : "CS Student"
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpeningQuote(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject(
|
||||||
|
"``Such",
|
||||||
|
"axioms,",
|
||||||
|
"together with other unmotivated definitions,",
|
||||||
|
"serve mathematicians mainly by making it",
|
||||||
|
"difficult for the uninitiated",
|
||||||
|
"to master their subject, thereby elevating its authority.''",
|
||||||
|
enforce_new_line_structure = False,
|
||||||
|
alignment = "",
|
||||||
|
)
|
||||||
|
words.highlight_by_tex("axioms,", BLUE)
|
||||||
|
words.highlight_by_tex("difficult for the uninitiated", RED)
|
||||||
|
words.scale_to_fit_width(2*SPACE_WIDTH - 2)
|
||||||
|
words.to_edge(UP)
|
||||||
|
author = TextMobject("-Vladmir Arnold")
|
||||||
|
author.highlight(YELLOW)
|
||||||
|
author.next_to(words, DOWN, buff = 2*MED_BUFF)
|
||||||
|
|
||||||
|
self.play(Write(words, run_time = 8))
|
||||||
|
self.dither()
|
||||||
|
self.play(FadeIn(author))
|
||||||
|
self.dither(3)
|
||||||
|
|
||||||
|
class RevisitOriginalQuestion(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
self.teacher_says("Let's revisit \\\\ an old question")
|
||||||
|
self.random_blink()
|
||||||
|
question = TextMobject("What are ", "vectors", "?", arg_separator = "")
|
||||||
|
question.highlight_by_tex("vectors", YELLOW)
|
||||||
|
self.teacher_says(
|
||||||
|
question,
|
||||||
|
added_anims = [
|
||||||
|
ApplyMethod(self.get_students()[i].change_mode, mode)
|
||||||
|
for i, mode in enumerate([
|
||||||
|
"pondering", "raise_right_hand", "erm"
|
||||||
|
])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.random_blink(2)
|
||||||
|
|
||||||
|
class WhatIsA2DVector(LinearTransformationScene):
|
||||||
|
CONFIG = {
|
||||||
|
"v_coords" : [1, 2],
|
||||||
|
"show_basis_vectors" : False,
|
||||||
|
"include_background_plane" : False,
|
||||||
|
"foreground_plane_kwargs" : {
|
||||||
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
|
"y_radius" : 2*SPACE_HEIGHT,
|
||||||
|
"secondary_line_ratio" : 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.plane.fade()
|
||||||
|
self.introduce_vector_and_space()
|
||||||
|
self.bring_in_students()
|
||||||
|
|
||||||
|
def introduce_vector_and_space(self):
|
||||||
|
v = Vector(self.v_coords)
|
||||||
|
coords = Matrix(self.v_coords)
|
||||||
|
coords.add_to_back(BackgroundRectangle(coords))
|
||||||
|
coords.next_to(v.get_end(), RIGHT)
|
||||||
|
|
||||||
|
two_d_vector, two_d_space = words = [
|
||||||
|
TextMobject(
|
||||||
|
"``Two-dimensional ", word, "''", arg_separator = ""
|
||||||
|
).highlight_by_tex(word, color)
|
||||||
|
for word, color in ("vector", YELLOW), ("space", BLUE)
|
||||||
|
]
|
||||||
|
for word, vect in zip(words, [LEFT, RIGHT]):
|
||||||
|
word.add_background_rectangle()
|
||||||
|
word.next_to(ORIGIN, vect, buff = MED_BUFF)
|
||||||
|
word.to_edge(UP)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(two_d_vector),
|
||||||
|
ShowCreation(v),
|
||||||
|
Write(coords),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
last_mobs = self.get_mobjects_from_last_animation()
|
||||||
|
self.play(
|
||||||
|
Homotopy(plane_wave_homotopy, self.plane),
|
||||||
|
Write(two_d_space, run_time = 2),
|
||||||
|
*map(Animation, last_mobs)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.v, self.coords = v, coords
|
||||||
|
|
||||||
|
def bring_in_students(self):
|
||||||
|
everything = self.get_mobjects()
|
||||||
|
v, coords = self.v, self.coords
|
||||||
|
physics_student = PhysicsStudent()
|
||||||
|
cs_student = CSStudent()
|
||||||
|
students = [physics_student, cs_student]
|
||||||
|
for student, vect in zip(students, [LEFT, RIGHT]):
|
||||||
|
student.change_mode("confused")
|
||||||
|
student.to_corner(DOWN+vect, buff = 2*MED_BUFF)
|
||||||
|
student.look_at(v)
|
||||||
|
student.bubble = get_small_bubble(
|
||||||
|
student, height = 4, width = 4,
|
||||||
|
)
|
||||||
|
self.play(*map(FadeIn, students))
|
||||||
|
self.play(Blink(physics_student))
|
||||||
|
self.dither()
|
||||||
|
for student, vect in zip(students, [RIGHT, LEFT]):
|
||||||
|
for mob in v, coords:
|
||||||
|
mob.target = mob.copy()
|
||||||
|
mob.target.scale(0.7)
|
||||||
|
arrow = TexMobject("\\Rightarrow")
|
||||||
|
group = VGroup(v.target, arrow, coords.target)
|
||||||
|
group.arrange_submobjects(vect)
|
||||||
|
student.bubble.add_content(group)
|
||||||
|
student.v, student.coords = v.copy(), coords.copy()
|
||||||
|
student.arrow = arrow
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
student.change_mode, "pondering",
|
||||||
|
ShowCreation(student.bubble),
|
||||||
|
Write(arrow),
|
||||||
|
Transform(student.v, v.target),
|
||||||
|
Transform(student.coords, coords.target),
|
||||||
|
)
|
||||||
|
self.play(Blink(student))
|
||||||
|
self.dither()
|
||||||
|
anims = []
|
||||||
|
for student in students:
|
||||||
|
v, coords = student.v, student.coords
|
||||||
|
v.target = v.copy()
|
||||||
|
coords.target = coords.copy()
|
||||||
|
group = VGroup(v.target, coords.target)
|
||||||
|
group.arrange_submobjects(DOWN)
|
||||||
|
group.scale_to_fit_height(coords.get_height())
|
||||||
|
group.next_to(student.arrow, RIGHT)
|
||||||
|
student.q_marks = TexMobject("???")
|
||||||
|
student.q_marks.gradient_highlight(BLUE, YELLOW)
|
||||||
|
student.q_marks.next_to(student.arrow, LEFT)
|
||||||
|
anims += [
|
||||||
|
Write(student.q_marks),
|
||||||
|
MoveToTarget(v),
|
||||||
|
MoveToTarget(coords),
|
||||||
|
student.change_mode, "erm",
|
||||||
|
student.look_at, student.bubble
|
||||||
|
]
|
||||||
|
cs_student.v.save_state()
|
||||||
|
cs_student.coords.save_state()
|
||||||
|
self.play(*anims)
|
||||||
|
for student in students:
|
||||||
|
self.play(Blink(student))
|
||||||
|
self.dither()
|
||||||
|
self.play(*it.chain(
|
||||||
|
map(FadeOut, everything + [
|
||||||
|
physics_student.bubble,
|
||||||
|
physics_student.v,
|
||||||
|
physics_student.coords,
|
||||||
|
physics_student.arrow,
|
||||||
|
physics_student.q_marks,
|
||||||
|
cs_student.q_marks,
|
||||||
|
]),
|
||||||
|
[ApplyMethod(s.change_mode, "plain") for s in students],
|
||||||
|
map(Animation, [cs_student.bubble, cs_student.arrow]),
|
||||||
|
[mob.restore for mob in cs_student.v, cs_student.coords],
|
||||||
|
))
|
||||||
|
bubble = cs_student.get_bubble("speech", width = 4, height = 3)
|
||||||
|
bubble.set_fill(BLACK, opacity = 1)
|
||||||
|
bubble.next_to(cs_student, UP+LEFT)
|
||||||
|
bubble.write("Consider higher \\\\ dimensions")
|
||||||
|
self.play(
|
||||||
|
cs_student.change_mode, "speaking",
|
||||||
|
ShowCreation(bubble),
|
||||||
|
Write(bubble.content)
|
||||||
|
)
|
||||||
|
self.play(Blink(physics_student))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class HigherDimensionalVectorsNumerically(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = VGroup(*map(TextMobject, [
|
||||||
|
"4D vector",
|
||||||
|
"5D vector",
|
||||||
|
"100D vector",
|
||||||
|
]))
|
||||||
|
words.arrange_submobjects(RIGHT, buff = LARGE_BUFF*2)
|
||||||
|
words.to_edge(UP)
|
||||||
|
vectors = VGroup(*map(Matrix, [
|
||||||
|
[3, 1, 4, 1],
|
||||||
|
[5, 9, 2, 6, 5],
|
||||||
|
[3, 5, 8, "\\vdots", 0, 8, 6]
|
||||||
|
]))
|
||||||
|
colors = [YELLOW, MAROON_B, GREEN]
|
||||||
|
for word, vector, color in zip(words, vectors, colors):
|
||||||
|
vector.shift(word.get_center()[0]*RIGHT)
|
||||||
|
word.highlight(color)
|
||||||
|
vector.highlight(color)
|
||||||
|
|
||||||
|
for word in words:
|
||||||
|
self.play(FadeIn(word))
|
||||||
|
self.play(Write(vectors))
|
||||||
|
self.dither()
|
||||||
|
for index, dim, direction in (0, 4, RIGHT), (2, 100, LEFT):
|
||||||
|
v = vectors[index]
|
||||||
|
v.target = v.copy()
|
||||||
|
brace = Brace(v, direction)
|
||||||
|
brace.move_to(v)
|
||||||
|
v.target.next_to(brace, -direction)
|
||||||
|
text = brace.get_text("%d numbers"%dim)
|
||||||
|
self.play(
|
||||||
|
MoveToTarget(v),
|
||||||
|
GrowFromCenter(brace),
|
||||||
|
Write(text)
|
||||||
|
)
|
||||||
|
entries = v.get_entries()
|
||||||
|
num_entries = len(list(entries))
|
||||||
|
self.play(*[
|
||||||
|
Transform(
|
||||||
|
entries[i],
|
||||||
|
entries[i].copy().scale_in_place(1.2).highlight(WHITE),
|
||||||
|
rate_func = squish_rate_func(
|
||||||
|
there_and_back,
|
||||||
|
i/(2.*num_entries),
|
||||||
|
i/(2.*num_entries)+0.5
|
||||||
|
),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
for i in range(num_entries)
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class AskAbout4DCSStudent(Scene):
|
||||||
|
def construct(self):
|
||||||
|
cs_student = CSStudent().to_edge(DOWN).shift(2*RIGHT)
|
||||||
|
asker = PiCreature(color = MAROON_D)
|
||||||
|
asker.to_edge(DOWN).shift(2*LEFT)
|
||||||
|
for pi1, pi2 in (cs_student, asker), (asker, cs_student):
|
||||||
|
pi1.speech_bubble = pi1.get_bubble("speech")
|
||||||
|
pi1.look_at(pi2.eyes)
|
||||||
|
|
||||||
|
thought_bubble = get_small_bubble(cs_student)
|
||||||
|
thought_bubble.rotate(-np.pi/6)
|
||||||
|
thought_bubble.stretch_to_fit_height(4)
|
||||||
|
thought_bubble.next_to(
|
||||||
|
cs_student.get_corner(UP+RIGHT), UP, buff = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
vector = Matrix([3, 1, 4, 1])
|
||||||
|
vector.highlight(YELLOW)
|
||||||
|
vector.scale_to_fit_height(2)
|
||||||
|
thought_bubble.add_content(vector)
|
||||||
|
thought_bubble.add(thought_bubble.content)
|
||||||
|
asker.speech_bubble.write("""
|
||||||
|
What is this ``4d space''
|
||||||
|
you speak of?
|
||||||
|
""")
|
||||||
|
cs_student.speech_bubble.write(
|
||||||
|
"The set of all",
|
||||||
|
"ordered \\\\ quadruplets",
|
||||||
|
"of real numbers",
|
||||||
|
)
|
||||||
|
cs_student.speech_bubble.content[1].highlight(YELLOW)
|
||||||
|
for pi in asker, cs_student:
|
||||||
|
pi.speech_bubble.add(pi.speech_bubble.content)
|
||||||
|
|
||||||
|
self.add(asker, cs_student)
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "erm",
|
||||||
|
Write(asker.speech_bubble),
|
||||||
|
)
|
||||||
|
self.play(Blink(cs_student))
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "plain",
|
||||||
|
cs_student.change_mode, "speaking",
|
||||||
|
FadeOut(asker.speech_bubble),
|
||||||
|
Write(cs_student.speech_bubble),
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "pondering",
|
||||||
|
asker.look_at, thought_bubble,
|
||||||
|
Write(thought_bubble)
|
||||||
|
)
|
||||||
|
self.play(Blink(asker))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class HyperCube(VMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"color" : BLUE_C,
|
||||||
|
"color2" : BLUE_D,
|
||||||
|
"dims" : 4,
|
||||||
|
}
|
||||||
|
def generate_points(self):
|
||||||
|
corners = np.array(map(np.array, it.product(*[(-1, 1)]*self.dims)))
|
||||||
|
def project(four_d_array):
|
||||||
|
result = four_d_array[:3]
|
||||||
|
w = four_d_array[self.dims-1]
|
||||||
|
scalar = interpolate(0.8, 1.2 ,(w+1)/2.)
|
||||||
|
return scalar*result
|
||||||
|
for a1, a2 in it.combinations(corners, 2):
|
||||||
|
if sum(a1==a2) != self.dims-1:
|
||||||
|
continue
|
||||||
|
self.add(Line(project(a1), project(a2)))
|
||||||
|
self.pose_at_angle()
|
||||||
|
self.gradient_highlight(self.color, self.color2)
|
||||||
|
|
||||||
|
class AskAbout4DPhysicsStudent(Scene):
|
||||||
|
def construct(self):
|
||||||
|
physy = PhysicsStudent().flip().to_edge(DOWN).shift(2*RIGHT)
|
||||||
|
asker = PiCreature(color = MAROON_D)
|
||||||
|
asker.to_edge(DOWN).shift(2*LEFT)
|
||||||
|
for pi1, pi2 in (physy, asker), (asker, physy):
|
||||||
|
pi1.speech_bubble = pi1.get_bubble("speech")
|
||||||
|
pi1.look_at(pi2.eyes)
|
||||||
|
|
||||||
|
thought_bubble = get_small_bubble(physy)
|
||||||
|
thought_bubble.rotate(-np.pi/6)
|
||||||
|
thought_bubble.stretch_to_fit_height(5)
|
||||||
|
thought_bubble.stretch_to_fit_width(4)
|
||||||
|
thought_bubble.shift(RIGHT)
|
||||||
|
thought_bubble.next_to(
|
||||||
|
physy.get_corner(UP+RIGHT), UP, buff = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
vector = Vector([1, 2])
|
||||||
|
line = Line(LEFT, RIGHT, color = BLUE_B)
|
||||||
|
square = Square(color = BLUE_C)
|
||||||
|
cube = HyperCube(color = BLUE_D, dims = 3)
|
||||||
|
hyper_cube = HyperCube()
|
||||||
|
thought_mobs = vector, line, square, cube, hyper_cube
|
||||||
|
for mob in thought_mobs:
|
||||||
|
mob.scale_to_fit_height(2)
|
||||||
|
thought_bubble.add_content(mob)
|
||||||
|
square.scale_in_place(0.7)
|
||||||
|
asker.speech_bubble.flip()
|
||||||
|
asker.speech_bubble.stretch_to_fit_width(4.5)
|
||||||
|
asker.speech_bubble.to_edge(LEFT)
|
||||||
|
asker.speech_bubble.write("""
|
||||||
|
Well, what do \\emph{you}
|
||||||
|
think 4d space is?
|
||||||
|
""")
|
||||||
|
physy.speech_bubble.write("""
|
||||||
|
Well, it's kind of like
|
||||||
|
3d space, but with another
|
||||||
|
dimension, you know?
|
||||||
|
""")
|
||||||
|
for pi in asker, physy:
|
||||||
|
pi.speech_bubble.add(pi.speech_bubble.content)
|
||||||
|
|
||||||
|
|
||||||
|
self.add(asker, physy, thought_bubble, vector)
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "sassy",
|
||||||
|
Write(asker.speech_bubble),
|
||||||
|
)
|
||||||
|
self.play(Blink(physy))
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "plain",
|
||||||
|
physy.change_mode, "hooray",
|
||||||
|
FadeOut(asker.speech_bubble),
|
||||||
|
Write(physy.speech_bubble),
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
asker.change_mode, "confused",
|
||||||
|
asker.look_at, thought_bubble,
|
||||||
|
physy.look_at, thought_bubble,
|
||||||
|
)
|
||||||
|
for mob in thought_mobs[1:]:
|
||||||
|
self.play(Transform(vector, mob))
|
||||||
|
self.remove(vector)
|
||||||
|
vector = mob
|
||||||
|
self.add(vector)
|
||||||
|
self.dither()
|
||||||
|
self.play(Blink(asker))
|
||||||
|
asker.speech_bubble.remove(asker.speech_bubble.content)
|
||||||
|
asker.speech_bubble.write("Is that real?")
|
||||||
|
asker.speech_bubble.add(asker.speech_bubble.content)
|
||||||
|
self.play(
|
||||||
|
FadeOut(physy.speech_bubble),
|
||||||
|
FadeOut(physy.speech_bubble),
|
||||||
|
Write(asker.speech_bubble, run_time = 2),
|
||||||
|
asker.change_mode, "sassy",
|
||||||
|
physy.change_mode, "plain",
|
||||||
|
physy.look_at, asker.eyes,
|
||||||
|
)
|
||||||
|
self.play(Blink(physy))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class ManyCoordinateSystems(LinearTransformationScene):
|
||||||
|
CONFIG = {
|
||||||
|
"v_coords" : [2, 1],
|
||||||
|
"include_background_plane" : False,
|
||||||
|
"foreground_plane_kwargs" : {
|
||||||
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
|
"y_radius" : 2*SPACE_WIDTH,
|
||||||
|
"secondary_line_ratio" : 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.title = TextMobject("Many possible coordinate systems")
|
||||||
|
self.title.add_background_rectangle()
|
||||||
|
self.title.to_edge(UP)
|
||||||
|
self.add_foreground_mobject(self.title)
|
||||||
|
self.v = Vector(self.v_coords)
|
||||||
|
self.play(ShowCreation(self.v))
|
||||||
|
self.add_foreground_mobject(self.v)
|
||||||
|
|
||||||
|
t_matrices = [
|
||||||
|
[[0.5, 0.5], [-0.5, 0.5]],
|
||||||
|
[[1, -1], [-3, -1]],
|
||||||
|
[[-1, 2], [-0.5, -1]],
|
||||||
|
]
|
||||||
|
movers = [self.plane, self.i_hat, self.j_hat]
|
||||||
|
for mover in movers:
|
||||||
|
mover.save_state()
|
||||||
|
for t_matrix in t_matrices:
|
||||||
|
self.animate_coordinates()
|
||||||
|
self.play(*it.chain(
|
||||||
|
map(FadeOut, movers),
|
||||||
|
map(Animation, self.foreground_mobjects)
|
||||||
|
))
|
||||||
|
for mover in movers:
|
||||||
|
mover.restore()
|
||||||
|
self.apply_transposed_matrix(t_matrix, run_time = 0)
|
||||||
|
self.play(*it.chain(
|
||||||
|
map(FadeIn, movers),
|
||||||
|
map(Animation, self.foreground_mobjects)
|
||||||
|
))
|
||||||
|
self.animate_coordinates()
|
||||||
|
|
||||||
|
|
||||||
|
def animate_coordinates(self):
|
||||||
|
self.i_hat.save_state()
|
||||||
|
self.j_hat.save_state()
|
||||||
|
cob_matrix = np.array([
|
||||||
|
self.i_hat.get_end()[:2],
|
||||||
|
self.j_hat.get_end()[:2]
|
||||||
|
]).T
|
||||||
|
inv_cob = np.linalg.inv(cob_matrix)
|
||||||
|
coords = np.dot(inv_cob, self.v_coords)
|
||||||
|
array = Matrix(map(DecimalNumber, coords))
|
||||||
|
array.get_entries()[0].highlight(X_COLOR)
|
||||||
|
array.get_entries()[1].highlight(Y_COLOR)
|
||||||
|
array.add_to_back(BackgroundRectangle(array))
|
||||||
|
for entry in array.get_entries():
|
||||||
|
entry.add_to_back(BackgroundRectangle(entry))
|
||||||
|
array.next_to(self.title, DOWN)
|
||||||
|
|
||||||
|
self.i_hat.target = self.i_hat.copy().scale(coords[0])
|
||||||
|
self.j_hat.target = self.j_hat.copy().scale(coords[1])
|
||||||
|
coord1, coord2 = array.get_entries().copy()
|
||||||
|
for coord, vect in (coord1, self.i_hat), (coord2, self.j_hat):
|
||||||
|
coord.target = coord.copy().next_to(
|
||||||
|
vect.target.get_end()/2,
|
||||||
|
rotate_vector(vect.get_end(), -np.pi/2)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(Write(array, run_time = 1))
|
||||||
|
self.dither()
|
||||||
|
self.play(*map(MoveToTarget, [self.i_hat, coord1]))
|
||||||
|
self.play(*map(MoveToTarget, [self.j_hat, coord2]))
|
||||||
|
self.play(VGroup(self.j_hat, coord2).shift, self.i_hat.get_end())
|
||||||
|
self.dither(2)
|
||||||
|
self.play(
|
||||||
|
self.i_hat.restore,
|
||||||
|
self.j_hat.restore,
|
||||||
|
*map(FadeOut, [array, coord1, coord2])
|
||||||
|
)
|
||||||
|
|
||||||
|
class TransformationsWithCoordinates(ColumnsToBasisVectors):
|
||||||
|
CONFIG = {
|
||||||
|
"t_matrix" : [[3, 1], [1, 2]],
|
||||||
|
"include_background_plane" : False,
|
||||||
|
"foreground_plane_kwargs" : {
|
||||||
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
|
"y_radius" : 2*SPACE_HEIGHT,
|
||||||
|
"secondary_line_ratio" : 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.setup()
|
||||||
|
self.add_unit_square()
|
||||||
|
eigenvectors = VGroup(*self.get_eigenvectors())
|
||||||
|
|
||||||
|
for mob in self.square, eigenvectors:
|
||||||
|
mob.set_fill(opacity = 0)
|
||||||
|
mob.set_stroke(width = 0)
|
||||||
|
|
||||||
|
det_word = TextMobject("Determinant")
|
||||||
|
det_word.highlight(YELLOW)
|
||||||
|
det_word.to_edge(UP)
|
||||||
|
eigen_word = TextMobject("Eigenvectors")
|
||||||
|
eigen_word.highlight(MAROON_B)
|
||||||
|
eigen_word.next_to(det_word, DOWN, aligned_edge = LEFT)
|
||||||
|
for word in det_word, eigen_word:
|
||||||
|
word.add_background_rectangle()
|
||||||
|
|
||||||
|
self.move_matrix_columns(self.t_matrix)
|
||||||
|
faders = [self.matrix, self.i_coords, self.j_coords]
|
||||||
|
self.play(*map(FadeOut, faders))
|
||||||
|
FadeOut(VGroup(*faders)).update(1)
|
||||||
|
self.play(
|
||||||
|
Write(det_word, run_time = 2),
|
||||||
|
self.square.set_fill, YELLOW, 0.3,
|
||||||
|
self.square.set_stroke, YELLOW, DEFAULT_POINT_THICKNESS,
|
||||||
|
*map(Animation, [self.i_hat, self.j_hat])
|
||||||
|
)
|
||||||
|
self.add_foreground_mobject(det_word)
|
||||||
|
self.play(
|
||||||
|
Write(eigen_word, run_time = 2),
|
||||||
|
FadeIn(eigenvectors)
|
||||||
|
)
|
||||||
|
for eigenvector in eigenvectors:
|
||||||
|
self.add_vector(eigenvector, animate = False)
|
||||||
|
self.add_foreground_mobject(eigen_word)
|
||||||
|
self.apply_inverse_transpose(
|
||||||
|
self.t_matrix, rate_func = there_and_back
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_eigenvectors(self):
|
||||||
|
vals, (eig_matrix) = np.linalg.eig(self.t_matrix.T)
|
||||||
|
v1, v2 = eig_matrix.T
|
||||||
|
result = []
|
||||||
|
for v in v1, v2:
|
||||||
|
vectors = VGroup(*[
|
||||||
|
Vector(u*x*v)
|
||||||
|
for x in range(14, 0, -2)
|
||||||
|
for u in -1, 1
|
||||||
|
])
|
||||||
|
vectors.gradient_highlight(MAROON_B, YELLOW)
|
||||||
|
result += list(vectors)
|
||||||
|
return result
|
||||||
|
|
||||||
|
class NameDeterminantCopy(NameDeterminant):
|
||||||
|
pass#
|
||||||
|
|
||||||
|
class NameEigenvectorsAndEigenvaluesCopy(ExampleTranformationScene):
|
||||||
|
CONFIG = {
|
||||||
|
"show_basis_vectors" : False,
|
||||||
|
"include_background_plane" : False,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.remove(self.matrix)
|
||||||
|
self.foreground_mobjects.remove(self.matrix)
|
||||||
|
x_vectors = VGroup(*[
|
||||||
|
self.add_vector(u*x*RIGHT, animate = False)
|
||||||
|
for x in range(int(SPACE_WIDTH)+1, 0, -1)
|
||||||
|
for u in -1, 1
|
||||||
|
])
|
||||||
|
x_vectors.gradient_highlight(YELLOW, X_COLOR)
|
||||||
|
self.remove(x_vectors)
|
||||||
|
sneak_vectors = VGroup(*[
|
||||||
|
self.add_vector(u*x*(LEFT+UP), animate = False)
|
||||||
|
for x in np.arange(int(SPACE_HEIGHT), 0, -0.5)
|
||||||
|
for u in -1, 1
|
||||||
|
])
|
||||||
|
sneak_vectors.gradient_highlight(MAROON_B, YELLOW)
|
||||||
|
self.remove(sneak_vectors)
|
||||||
|
|
||||||
|
x_words = TextMobject("Stretched by 3")
|
||||||
|
sneak_words = TextMobject("Stretched by 2")
|
||||||
|
for words in x_words, sneak_words:
|
||||||
|
words.add_background_rectangle()
|
||||||
|
words.next_to(x_vectors, DOWN)
|
||||||
|
words.next_to(words.get_center(), LEFT, buff = 1.5)
|
||||||
|
eigen_word = TextMobject("Eigenvectors")
|
||||||
|
eigen_word.add_background_rectangle()
|
||||||
|
eigen_word.replace(words)
|
||||||
|
words.target = eigen_word
|
||||||
|
eigen_val_words = TextMobject(
|
||||||
|
"with eigenvalue ",
|
||||||
|
"%s"%words.get_tex_string()[-1]
|
||||||
|
)
|
||||||
|
eigen_val_words.add_background_rectangle()
|
||||||
|
eigen_val_words.next_to(words, DOWN, aligned_edge = RIGHT)
|
||||||
|
words.eigen_val_words = eigen_val_words
|
||||||
|
x_words.eigen_val_words.highlight(X_COLOR)
|
||||||
|
sneak_words.eigen_val_words.highlight(YELLOW)
|
||||||
|
|
||||||
|
VGroup(
|
||||||
|
sneak_words,
|
||||||
|
sneak_words.target,
|
||||||
|
sneak_words.eigen_val_words,
|
||||||
|
).rotate(sneak_vectors[0].get_angle())
|
||||||
|
|
||||||
|
final_words = TextMobject("""
|
||||||
|
Result doesn't care about
|
||||||
|
the coordinate system
|
||||||
|
""")
|
||||||
|
final_words.add_background_rectangle()
|
||||||
|
final_words.to_corner(UP+RIGHT)
|
||||||
|
|
||||||
|
for vectors in x_vectors, sneak_vectors:
|
||||||
|
self.play(ShowCreation(vectors, run_time = 1))
|
||||||
|
self.dither()
|
||||||
|
for words in x_words, sneak_words:
|
||||||
|
self.play(Write(words, run_time = 1.5))
|
||||||
|
self.add_foreground_mobject(words)
|
||||||
|
self.dither()
|
||||||
|
self.dither()
|
||||||
|
self.apply_transposed_matrix(
|
||||||
|
self.t_matrix,
|
||||||
|
path_arc = 0,
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
self.play(*map(MoveToTarget, [x_words, sneak_words]))
|
||||||
|
self.dither()
|
||||||
|
for words in x_words, sneak_words:
|
||||||
|
self.play(Write(words.eigen_val_words), run_time = 2)
|
||||||
|
self.add_foreground_mobject(words.eigen_val_words)
|
||||||
|
self.dither()
|
||||||
|
fade_out = FadeOut(self.plane)
|
||||||
|
self.play(fade_out, Write(final_words))
|
||||||
|
fade_out.update(1)
|
||||||
|
self.apply_inverse_transpose(
|
||||||
|
self.t_matrix,
|
||||||
|
rate_func = there_and_back,
|
||||||
|
path_arc = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
class ReallyWhatAreVectors(Scene):
|
||||||
|
def construct(self):
|
||||||
|
physy = PhysicsStudent()
|
||||||
|
physy.thought = Vector([1, 2])
|
||||||
|
physy.words = "Nature seems to \\\\ disagree with you"
|
||||||
|
compy = CSStudent()
|
||||||
|
compy.thought = Matrix([1, 2])
|
||||||
|
compy.words = "How else could you \\\\ possibly define them?"
|
||||||
|
for pi, vect in (physy, LEFT), (compy, RIGHT):
|
||||||
|
pi.to_edge(DOWN)
|
||||||
|
pi.shift(4*vect)
|
||||||
|
pi.bubble = get_small_bubble(pi)
|
||||||
|
pi.thought.highlight(YELLOW)
|
||||||
|
pi.thought.scale_to_fit_height(2)
|
||||||
|
pi.bubble.add_content(pi.thought)
|
||||||
|
pi.bubble.add(pi.thought)
|
||||||
|
|
||||||
|
pi.speech_bubble = pi.get_bubble("speech", width = 5)
|
||||||
|
pi.speech_bubble.set_fill(BLACK, opacity = 1)
|
||||||
|
pi.speech_bubble.write(pi.words)
|
||||||
|
pi.speech_bubble.add(pi.speech_bubble.content)
|
||||||
|
self.add(pi)
|
||||||
|
physy.make_eye_contact(compy)
|
||||||
|
|
||||||
|
hundred_d = Matrix(["3", "5", "\\vdots", "8", "6"])
|
||||||
|
hundred_d.highlight(GREEN)
|
||||||
|
hundred_d.scale_to_fit_height(compy.thought.get_height())
|
||||||
|
hundred_d.move_to(compy.thought)
|
||||||
|
|
||||||
|
double_speech = DoubleSpeechBubble(width = 6)
|
||||||
|
double_speech.set_fill(BLACK, opacity = 1)
|
||||||
|
double_speech.write("What \\emph{are} vectors???")
|
||||||
|
double_speech.add(double_speech.content)
|
||||||
|
double_speech.next_to(VGroup(compy, physy), UP)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
*[FadeIn(pi.bubble) for pi in physy, compy],
|
||||||
|
run_time = 1
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
Write(physy.speech_bubble),
|
||||||
|
physy.change_mode, "sassy"
|
||||||
|
)
|
||||||
|
self.play(Blink(compy))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
FadeOut(physy.speech_bubble),
|
||||||
|
Write(compy.speech_bubble),
|
||||||
|
physy.change_mode, "pondering",
|
||||||
|
compy.change_mode, "pleading"
|
||||||
|
)
|
||||||
|
self.play(Transform(compy.thought, hundred_d))
|
||||||
|
self.play(Blink(physy))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
FadeOut(compy.speech_bubble),
|
||||||
|
Write(double_speech),
|
||||||
|
compy.change_mode, "confused",
|
||||||
|
physy.change_mode, "confused",
|
||||||
|
)
|
||||||
|
self.play(*map(Blink, [compy, physy]))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class OtherVectorishThings(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject(
|
||||||
|
"There are other\\\\",
|
||||||
|
"vectorish",
|
||||||
|
"things..."
|
||||||
|
)
|
||||||
|
words.highlight_by_tex("vectorish", YELLOW)
|
||||||
|
self.teacher_says(words)
|
||||||
|
self.change_student_modes(
|
||||||
|
"pondering", "raise_right_hand", "erm"
|
||||||
|
)
|
||||||
|
self.random_blink(2)
|
||||||
|
words = TextMobject("...like", "functions")
|
||||||
|
words.highlight_by_tex("functions", PINK)
|
||||||
|
self.teacher_says(words)
|
||||||
|
self.change_student_modes(*["pondering"]*3)
|
||||||
|
self.random_blink(2)
|
||||||
|
self.teacher_thinks("")
|
||||||
|
self.zoom_in_on_thought_bubble(self.get_teacher().bubble)
|
||||||
|
|
||||||
|
class FunctionGraphScene(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"graph_colors" : [MAROON_B, YELLOW, PINK],
|
||||||
|
"default_functions" : [
|
||||||
|
lambda x : (x**3 - 9*x)/10.,
|
||||||
|
lambda x : (x**2)/8.-1
|
||||||
|
],
|
||||||
|
"default_names" : ["f", "g", "h"],
|
||||||
|
"x_min" : -4,
|
||||||
|
"x_max" : 4,
|
||||||
|
"line_to_line_buff" : 0.03
|
||||||
|
}
|
||||||
|
def setup(self):
|
||||||
|
self.axes = Axes(
|
||||||
|
x_min = self.x_min,
|
||||||
|
x_max = self.x_max,
|
||||||
|
)
|
||||||
|
self.add(self.axes)
|
||||||
|
self.graphs = []
|
||||||
|
|
||||||
|
def get_function_graph(self, func = None, animate = True,
|
||||||
|
add = True, **kwargs):
|
||||||
|
index = len(self.graphs)
|
||||||
|
if func is None:
|
||||||
|
func = self.default_functions[
|
||||||
|
index%len(self.default_functions)
|
||||||
|
]
|
||||||
|
default_color = self.graph_colors[index%len(self.graph_colors)]
|
||||||
|
kwargs["color"] = kwargs.get("color", default_color)
|
||||||
|
kwargs["x_min"] = kwargs.get("x_min", self.x_min)
|
||||||
|
kwargs["x_max"] = kwargs.get("x_max", self.x_max)
|
||||||
|
graph = FunctionGraph(func, **kwargs)
|
||||||
|
if animate:
|
||||||
|
self.play(ShowCreation(graph))
|
||||||
|
if add:
|
||||||
|
self.add(graph)
|
||||||
|
self.graphs.append(graph)
|
||||||
|
return graph
|
||||||
|
|
||||||
|
def get_index(self, function_graph):
|
||||||
|
if function_graph not in self.graphs:
|
||||||
|
self.graphs.append(function_graph)
|
||||||
|
return self.graphs.index(function_graph)
|
||||||
|
|
||||||
|
def get_output_lines(self, function_graph, num_steps = None, nudge = True):
|
||||||
|
index = self.get_index(function_graph)
|
||||||
|
num_steps = num_steps or function_graph.num_steps
|
||||||
|
lines = VGroup()
|
||||||
|
nudge_size = index*self.line_to_line_buff
|
||||||
|
x_min, x_max = function_graph.x_min, function_graph.x_max
|
||||||
|
for x in np.linspace(x_min, x_max, num_steps):
|
||||||
|
if nudge:
|
||||||
|
x += nudge_size
|
||||||
|
y = function_graph.function(x)
|
||||||
|
lines.add(Line(x*RIGHT, x*RIGHT+y*UP))
|
||||||
|
lines.highlight(function_graph.get_color())
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def add_lines(self, output_lines):
|
||||||
|
self.play(ShowCreation(
|
||||||
|
output_lines,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
run_time = 2
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def label_graph(self, function_graph, name = None, animate = True):
|
||||||
|
index = self.get_index(function_graph)
|
||||||
|
name = name or self.default_names[index%len(self.default_names)]
|
||||||
|
label = TexMobject("%s(x)"%name)
|
||||||
|
label.next_to(function_graph.point_from_proportion(1), RIGHT)
|
||||||
|
label.shift_onto_screen()
|
||||||
|
label.highlight(function_graph.get_color())
|
||||||
|
if animate:
|
||||||
|
self.play(Write(label))
|
||||||
|
else:
|
||||||
|
self.add(label)
|
||||||
|
return label
|
||||||
|
|
||||||
|
class AddTwoFunctions(FunctionGraphScene):
|
||||||
|
def construct(self):
|
||||||
|
f_graph = self.get_function_graph()
|
||||||
|
g_graph = self.get_function_graph()
|
||||||
|
def sum_func(x):
|
||||||
|
return f_graph.get_function()(x)+g_graph.get_function()(x)
|
||||||
|
sum_graph = self.get_function_graph(sum_func, animate = False)
|
||||||
|
self.remove(sum_graph)
|
||||||
|
f_label = self.label_graph(f_graph)
|
||||||
|
g_label = self.label_graph(g_graph)
|
||||||
|
|
||||||
|
f_lines = self.get_output_lines(f_graph)
|
||||||
|
g_lines = self.get_output_lines(g_graph)
|
||||||
|
sum_lines = self.get_output_lines(sum_graph, nudge = False)
|
||||||
|
for lines in f_lines, g_lines:
|
||||||
|
self.add_lines(lines)
|
||||||
|
self.play(*map(FadeOut, [f_graph, g_graph]))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
curr_x_point = f_lines[0].get_start()
|
||||||
|
sum_def = self.get_sum_definition(DecimalNumber(curr_x_point[0]))
|
||||||
|
# sum_def.scale_to_fit_width(SPACE_WIDTH-1)
|
||||||
|
sum_def.to_corner(UP+LEFT)
|
||||||
|
arrow = Arrow(sum_def[2].get_bottom(), curr_x_point, color = WHITE)
|
||||||
|
prefix = sum_def[0]
|
||||||
|
suffix = VGroup(*sum_def[1:])
|
||||||
|
rect = BackgroundRectangle(sum_def)
|
||||||
|
brace = Brace(prefix)
|
||||||
|
brace.add(brace.get_text("New function").shift_onto_screen())
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(prefix, run_time = 2),
|
||||||
|
FadeIn(brace)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(FadeOut(brace))
|
||||||
|
fg_group = VGroup(*list(f_label)+list(g_label))
|
||||||
|
self.play(
|
||||||
|
FadeIn(rect),
|
||||||
|
Animation(prefix),
|
||||||
|
Transform(fg_group, suffix),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.remove(prefix, fg_group)
|
||||||
|
self.add(sum_def)
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
|
||||||
|
self.show_line_addition(f_lines[0], g_lines[0], sum_lines[0])
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
curr_x_point = f_lines[1].get_start()
|
||||||
|
new_sum_def = self.get_sum_definition(DecimalNumber(curr_x_point[0]))
|
||||||
|
new_sum_def.to_corner(UP+LEFT)
|
||||||
|
new_arrow = Arrow(sum_def[2].get_bottom(), curr_x_point, color = WHITE)
|
||||||
|
self.play(
|
||||||
|
Transform(sum_def, new_sum_def),
|
||||||
|
Transform(arrow, new_arrow),
|
||||||
|
)
|
||||||
|
self.show_line_addition(f_lines[1], g_lines[1], sum_lines[1])
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
final_sum_def = self.get_sum_definition(TexMobject("x"))
|
||||||
|
final_sum_def.to_corner(UP+LEFT)
|
||||||
|
self.play(
|
||||||
|
FadeOut(rect),
|
||||||
|
Transform(sum_def, final_sum_def),
|
||||||
|
FadeOut(arrow)
|
||||||
|
)
|
||||||
|
self.show_line_addition(*it.starmap(VGroup, [
|
||||||
|
f_lines[2:], g_lines[2:], sum_lines[2:]
|
||||||
|
]))
|
||||||
|
self.play(ShowCreation(sum_graph))
|
||||||
|
|
||||||
|
def get_sum_definition(self, input_mob):
|
||||||
|
result = VGroup(*it.chain(
|
||||||
|
TexMobject("(f+g)", "("),
|
||||||
|
[input_mob.copy()],
|
||||||
|
TexMobject(")", "=", "f("),
|
||||||
|
[input_mob.copy()],
|
||||||
|
TexMobject(")", "+", "g("),
|
||||||
|
[input_mob.copy()],
|
||||||
|
TexMobject(")")
|
||||||
|
))
|
||||||
|
result.arrange_submobjects()
|
||||||
|
result[0].highlight(self.graph_colors[2])
|
||||||
|
VGroup(result[5], result[7]).highlight(self.graph_colors[0])
|
||||||
|
VGroup(result[9], result[11]).highlight(self.graph_colors[1])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def show_line_addition(self, f_lines, g_lines, sum_lines):
|
||||||
|
g_lines.target = g_lines.copy()
|
||||||
|
dots = VGroup()
|
||||||
|
dots.target = VGroup()
|
||||||
|
for f_line, g_line in zip(f_lines, g_lines.target):
|
||||||
|
align_perfectly = f_line.get_end()[1]*g_line.get_end()[1] > 0
|
||||||
|
dot = Dot(g_line.get_end())
|
||||||
|
g_line.shift(f_line.get_end()-g_line.get_start())
|
||||||
|
dot.target = Dot(g_line.get_end())
|
||||||
|
if not align_perfectly:
|
||||||
|
g_line.shift(self.line_to_line_buff*RIGHT)
|
||||||
|
dots.add(dot)
|
||||||
|
dots.target.add(dot.target)
|
||||||
|
for group in dots, dots.target:
|
||||||
|
group.highlight(sum_lines[0].get_color())
|
||||||
|
self.play(ShowCreation(dots))
|
||||||
|
if len(list(g_lines)) == 1:
|
||||||
|
kwargs = {}
|
||||||
|
else:
|
||||||
|
kwargs = {
|
||||||
|
"submobject_mode" : "lagged_start",
|
||||||
|
"run_time" : 3
|
||||||
|
}
|
||||||
|
self.play(*[
|
||||||
|
MoveToTarget(mob, **kwargs)
|
||||||
|
for mob in g_lines, dots
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
self.play(*map(FadeOut, [f_lines, g_lines]))
|
||||||
|
self.add_lines(sum_lines)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class ScaleFunction(FunctionGraphScene):
|
||||||
|
def construct(self):
|
||||||
|
graph = self.get_function_graph()
|
||||||
|
scaled_graph = self.get_function_graph(
|
||||||
|
lambda x : graph.get_function()(x)*2,
|
||||||
|
add = False
|
||||||
|
)
|
||||||
|
graph_lines = self.get_output_lines(graph)
|
||||||
|
scaled_lines = self.get_output_lines(scaled_graph, nudge = False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1167,6 +1167,11 @@ class ColumnsToBasisVectors(LinearTransformationScene):
|
|||||||
)
|
)
|
||||||
self.add_foreground_mobject(j_coords_start)
|
self.add_foreground_mobject(j_coords_start)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
self.matrix = VGroup(matrix_background, matrix_mob)
|
||||||
|
self.i_coords = i_coords_start
|
||||||
|
self.j_coords = j_coords_start
|
||||||
|
|
||||||
return vector if vector_coords is not None else None
|
return vector if vector_coords is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,19 +36,21 @@ class You(PiCreature):
|
|||||||
"flip_at_start" : True,
|
"flip_at_start" : True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_small_bubble(pi_creature):
|
def get_small_bubble(pi_creature, height = 4, width = 3):
|
||||||
pi_center_x = pi_creature.get_center()[0]
|
pi_center_x = pi_creature.get_center()[0]
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"height" : 4,
|
"height" : 4,
|
||||||
"bubble_center_adjustment_factor" : 1./6,
|
"bubble_center_adjustment_factor" : 1./6,
|
||||||
}
|
}
|
||||||
bubble = ThoughtBubble(**kwargs)
|
bubble = ThoughtBubble(**kwargs)
|
||||||
bubble.stretch_to_fit_width(3)
|
bubble.stretch_to_fit_width(3)##Canonical width
|
||||||
bubble.rotate(np.pi/4)
|
bubble.rotate(np.pi/4)
|
||||||
|
bubble.stretch_to_fit_width(width)
|
||||||
|
bubble.stretch_to_fit_height(height)
|
||||||
if pi_center_x < 0:
|
if pi_center_x < 0:
|
||||||
bubble.flip()
|
bubble.flip()
|
||||||
bubble.next_to(pi_creature, UP, buff = MED_BUFF)
|
bubble.next_to(pi_creature, UP, buff = MED_BUFF)
|
||||||
bubble.to_edge(pi_center_x*RIGHT, buff = SMALL_BUFF)
|
bubble.shift_onto_screen()
|
||||||
bubble.set_fill(BLACK, opacity = 0.8)
|
bubble.set_fill(BLACK, opacity = 0.8)
|
||||||
return bubble
|
return bubble
|
||||||
|
|
||||||
|
@ -114,6 +114,44 @@ class Chapter9(Scene):
|
|||||||
|
|
||||||
self.add(you, jenny, vector)
|
self.add(you, jenny, vector)
|
||||||
|
|
||||||
|
class Chapter10(LinearTransformationScene):
|
||||||
|
CONFIG = {
|
||||||
|
"foreground_plane_kwargs" : {
|
||||||
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
|
"y_radius" : 2*SPACE_HEIGHT,
|
||||||
|
"secondary_line_ratio" : 1
|
||||||
|
|
||||||
|
},
|
||||||
|
"include_background_plane" : False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
v_tex = "\\vec{\\textbf{v}}"
|
||||||
|
eq = TexMobject("A", v_tex, "=", "\\lambda", v_tex)
|
||||||
|
eq.highlight_by_tex(v_tex, YELLOW)
|
||||||
|
eq.highlight_by_tex("\\lambda", MAROON_B)
|
||||||
|
eq.scale(3)
|
||||||
|
eq.add_background_rectangle()
|
||||||
|
eq.shift(2*DOWN)
|
||||||
|
|
||||||
|
title = TextMobject(
|
||||||
|
"Eigen", "vectors \\\\",
|
||||||
|
"Eigen", "values"
|
||||||
|
, arg_separator = "")
|
||||||
|
title.scale(2.5)
|
||||||
|
title.to_edge(UP)
|
||||||
|
# title.highlight_by_tex("Eigen", MAROON_B)
|
||||||
|
title[0].highlight(YELLOW)
|
||||||
|
title[2].highlight(MAROON_B)
|
||||||
|
title.add_background_rectangle()
|
||||||
|
|
||||||
|
|
||||||
|
self.add_vector([-1, 1], color = YELLOW, animate = False)
|
||||||
|
self.apply_transposed_matrix([[3, 0], [1, 2]])
|
||||||
|
self.plane.fade()
|
||||||
|
self.remove(self.j_hat)
|
||||||
|
self.add(eq, title)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class Mobject(object):
|
|||||||
self.init_colors()
|
self.init_colors()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return str(self.name)
|
||||||
|
|
||||||
def init_points(self):
|
def init_points(self):
|
||||||
self.points = np.zeros((0, self.dim))
|
self.points = np.zeros((0, self.dim))
|
||||||
@ -101,6 +101,10 @@ class Mobject(object):
|
|||||||
def copy(self):
|
def copy(self):
|
||||||
return deepcopy(self)
|
return deepcopy(self)
|
||||||
|
|
||||||
|
def generate_target(self):
|
||||||
|
self.target = self.copy()
|
||||||
|
return self.target
|
||||||
|
|
||||||
#### Transforming operations ######
|
#### Transforming operations ######
|
||||||
|
|
||||||
def apply_to_family(self, func):
|
def apply_to_family(self, func):
|
||||||
@ -247,6 +251,7 @@ class Mobject(object):
|
|||||||
dim = np.argmax(np.abs(vect))
|
dim = np.argmax(np.abs(vect))
|
||||||
if abs(self.get_edge_center(vect)[dim]) > space_lengths[dim]:
|
if abs(self.get_edge_center(vect)[dim]) > space_lengths[dim]:
|
||||||
self.to_edge(vect, **kwargs)
|
self.to_edge(vect, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
def stretch_to_fit(self, length, dim, stretch = True):
|
def stretch_to_fit(self, length, dim, stretch = True):
|
||||||
old_length = self.length_over_dim(dim)
|
old_length = self.length_over_dim(dim)
|
||||||
|
@ -234,7 +234,7 @@ class VMobject(Mobject):
|
|||||||
def point_from_proportion(self, alpha):
|
def point_from_proportion(self, alpha):
|
||||||
num_cubics = self.get_num_anchor_points()-1
|
num_cubics = self.get_num_anchor_points()-1
|
||||||
interpoint_alpha = num_cubics*(alpha % (1./num_cubics))
|
interpoint_alpha = num_cubics*(alpha % (1./num_cubics))
|
||||||
index = 3*int(alpha*num_cubics)
|
index = min(3*int(alpha*num_cubics), 3*num_cubics)
|
||||||
cubic = bezier(self.points[index:index+4])
|
cubic = bezier(self.points[index:index+4])
|
||||||
return cubic(interpoint_alpha)
|
return cubic(interpoint_alpha)
|
||||||
|
|
||||||
|
@ -136,15 +136,16 @@ class PiCreature(SVGMobject):
|
|||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_corner(self, vect = None):
|
def to_corner(self, vect = None, **kwargs):
|
||||||
if vect is not None:
|
if vect is not None:
|
||||||
SVGMobject.to_corner(self, vect)
|
SVGMobject.to_corner(self, vect, **kwargs)
|
||||||
else:
|
else:
|
||||||
self.scale(self.corner_scale_factor)
|
self.scale(self.corner_scale_factor)
|
||||||
self.to_corner(DOWN+LEFT)
|
self.to_corner(DOWN+LEFT, **kwargs)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_bubble(self, bubble_type = "thought", **kwargs):
|
def get_bubble(self, bubble_type = "thought", **kwargs):
|
||||||
|
#TODO, change bubble_type arg to have type Bubble
|
||||||
if bubble_type == "thought":
|
if bubble_type == "thought":
|
||||||
bubble = ThoughtBubble(**kwargs)
|
bubble = ThoughtBubble(**kwargs)
|
||||||
elif bubble_type == "speech":
|
elif bubble_type == "speech":
|
||||||
@ -154,6 +155,11 @@ class PiCreature(SVGMobject):
|
|||||||
bubble.pin_to(self)
|
bubble.pin_to(self)
|
||||||
return bubble
|
return bubble
|
||||||
|
|
||||||
|
def make_eye_contact(self, pi_creature):
|
||||||
|
self.look_at(pi_creature.eyes)
|
||||||
|
pi_creature.look_at(self.eyes)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class Randolph(PiCreature):
|
class Randolph(PiCreature):
|
||||||
pass #Nothing more than an alternative name
|
pass #Nothing more than an alternative name
|
||||||
@ -262,6 +268,12 @@ class SpeechBubble(Bubble):
|
|||||||
"height" : 4
|
"height" : 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DoubleSpeechBubble(Bubble):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "Bubbles_double_speech.svg",
|
||||||
|
"height" : 4
|
||||||
|
}
|
||||||
|
|
||||||
class ThoughtBubble(Bubble):
|
class ThoughtBubble(Bubble):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"file_name" : "Bubbles_thought.svg",
|
"file_name" : "Bubbles_thought.svg",
|
||||||
@ -429,14 +441,14 @@ class TeacherStudentsScene(Scene):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def zoom_in_on_thought_bubble(self, radius = SPACE_HEIGHT+SPACE_WIDTH):
|
def zoom_in_on_thought_bubble(self, bubble = None, radius = SPACE_HEIGHT+SPACE_WIDTH):
|
||||||
bubble = None
|
|
||||||
for pi in self.get_everyone():
|
|
||||||
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
|
|
||||||
bubble = pi.bubble
|
|
||||||
break
|
|
||||||
if bubble is None:
|
if bubble is None:
|
||||||
raise Exception("No pi creatures have a thought bubble")
|
for pi in self.get_everyone():
|
||||||
|
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
|
||||||
|
bubble = pi.bubble
|
||||||
|
break
|
||||||
|
if bubble is None:
|
||||||
|
raise Exception("No pi creatures have a thought bubble")
|
||||||
vect = -bubble.get_bubble_center()
|
vect = -bubble.get_bubble_center()
|
||||||
def func(point):
|
def func(point):
|
||||||
centered = point+vect
|
centered = point+vect
|
||||||
|
@ -21,6 +21,9 @@ class FunctionGraph(VMobject):
|
|||||||
for x in np.linspace(self.x_min, self.x_max, self.num_steps)
|
for x in np.linspace(self.x_min, self.x_max, self.num_steps)
|
||||||
], mode = "smooth")
|
], mode = "smooth")
|
||||||
|
|
||||||
|
def get_function(self):
|
||||||
|
return self.function
|
||||||
|
|
||||||
|
|
||||||
class ParametricFunction(VMobject):
|
class ParametricFunction(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
Reference in New Issue
Block a user