mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Whoa boy, I've gotta get better about my commits...
This commit is contained in:
parent
ed3d64c614
commit
c7239a035c
18 changed files with 610 additions and 190 deletions
|
@ -106,7 +106,8 @@ class MoveAlongPath(Animation):
|
||||||
|
|
||||||
class Homotopy(Animation):
|
class Homotopy(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"run_time" : 3
|
"run_time" : 3,
|
||||||
|
"apply_function_kwargs" : {},
|
||||||
}
|
}
|
||||||
def __init__(self, homotopy, mobject, **kwargs):
|
def __init__(self, homotopy, mobject, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -120,7 +121,10 @@ class Homotopy(Animation):
|
||||||
|
|
||||||
def update_submobject(self, submob, start, alpha):
|
def update_submobject(self, submob, start, alpha):
|
||||||
submob.points = start.points
|
submob.points = start.points
|
||||||
submob.apply_function(self.function_at_time_t(alpha))
|
submob.apply_function(
|
||||||
|
self.function_at_time_t(alpha),
|
||||||
|
**self.apply_function_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
Animation.update_mobject(self, alpha)
|
Animation.update_mobject(self, alpha)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
DEFAULT_HEIGHT = 1080
|
DEFAULT_HEIGHT = 1080*2
|
||||||
DEFAULT_WIDTH = 1920
|
DEFAULT_WIDTH = 1920*2
|
||||||
DEFAULT_FRAME_DURATION = 0.04
|
DEFAULT_FRAME_DURATION = 0.04
|
||||||
|
|
||||||
#There might be other configuration than pixel_shape later...
|
#There might be other configuration than pixel_shape later...
|
||||||
|
|
0
eoc/__init__.py
Normal file
0
eoc/__init__.py
Normal file
277
eoc/chapter1.py
Normal file
277
eoc/chapter1.py
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
from helpers import *
|
||||||
|
|
||||||
|
from mobject.tex_mobject import TexMobject
|
||||||
|
from mobject import Mobject
|
||||||
|
from mobject.image_mobject import ImageMobject
|
||||||
|
from mobject.vectorized_mobject import *
|
||||||
|
|
||||||
|
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.fractals import *
|
||||||
|
from topics.number_line import *
|
||||||
|
from topics.combinatorics import *
|
||||||
|
from topics.numerals import *
|
||||||
|
from topics.three_dimensions import *
|
||||||
|
from topics.objects import *
|
||||||
|
from scene import Scene
|
||||||
|
from camera import Camera
|
||||||
|
from mobject.svg_mobject import *
|
||||||
|
from mobject.tex_mobject import *
|
||||||
|
|
||||||
|
class OpeningQuote(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"quote" : """
|
||||||
|
The art of doing mathematics is finding
|
||||||
|
that special case that contains all the
|
||||||
|
germs of generality.
|
||||||
|
""",
|
||||||
|
"author" : "David Hilbert"
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
quote = self.get_quote()
|
||||||
|
author = self.get_author(quote)
|
||||||
|
|
||||||
|
self.play(FadeIn(
|
||||||
|
quote,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
run_time = 2
|
||||||
|
))
|
||||||
|
self.dither(2)
|
||||||
|
self.play(Write(author, run_time = 4))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def get_quote(self):
|
||||||
|
quote = TextMobject(
|
||||||
|
"``%s''"%self.quote.strip(),
|
||||||
|
alignment = "",
|
||||||
|
)
|
||||||
|
quote.to_edge(UP)
|
||||||
|
return quote
|
||||||
|
|
||||||
|
def get_author(self, quote):
|
||||||
|
author = TextMobject("-" + self.author)
|
||||||
|
author.next_to(quote, DOWN)
|
||||||
|
author.highlight(YELLOW)
|
||||||
|
return author
|
||||||
|
|
||||||
|
class Introduction(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
self.show_series()
|
||||||
|
self.go_through_students()
|
||||||
|
self.zoom_in_on_first()
|
||||||
|
|
||||||
|
def show_series(self):
|
||||||
|
series = VideoSeries()
|
||||||
|
series.to_edge(UP)
|
||||||
|
this_video = series[0]
|
||||||
|
this_video.highlight(YELLOW)
|
||||||
|
this_video.save_state()
|
||||||
|
this_video.set_fill(opacity = 0)
|
||||||
|
this_video.center()
|
||||||
|
this_video.scale_to_fit_height(2*SPACE_HEIGHT)
|
||||||
|
self.this_video = this_video
|
||||||
|
|
||||||
|
words = TextMobject(
|
||||||
|
"Welcome to \\\\",
|
||||||
|
"Essence of calculus"
|
||||||
|
)
|
||||||
|
words.highlight_by_tex("Essence of calculus", YELLOW)
|
||||||
|
self.remove(self.teacher)
|
||||||
|
self.teacher.change_mode("happy")
|
||||||
|
self.add(self.teacher)
|
||||||
|
self.play(
|
||||||
|
FadeIn(
|
||||||
|
series,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
run_time = 2
|
||||||
|
),
|
||||||
|
Blink(self.get_teacher())
|
||||||
|
)
|
||||||
|
self.teacher_says(words, target_mode = "hooray")
|
||||||
|
self.play(
|
||||||
|
ApplyMethod(this_video.restore, run_time = 3),
|
||||||
|
*[
|
||||||
|
ApplyFunction(
|
||||||
|
lambda p : p.change_mode("hooray").look_at(series[1]),
|
||||||
|
pi
|
||||||
|
)
|
||||||
|
for pi in self.get_everyone()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def homotopy(x, y, z, t):
|
||||||
|
alpha = (0.7*x + SPACE_WIDTH)/(2*SPACE_WIDTH)
|
||||||
|
beta = squish_rate_func(smooth, alpha-0.15, alpha+0.15)(t)
|
||||||
|
return (x, y - 0.3*np.sin(np.pi*beta), z)
|
||||||
|
self.play(
|
||||||
|
Homotopy(
|
||||||
|
homotopy, series,
|
||||||
|
apply_function_kwargs = {"maintain_smoothness" : False},
|
||||||
|
),
|
||||||
|
*[
|
||||||
|
ApplyMethod(pi.look_at, series[-1])
|
||||||
|
for pi in self.get_everyone()
|
||||||
|
],
|
||||||
|
run_time = 5
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
FadeOut(self.teacher.bubble),
|
||||||
|
FadeOut(self.teacher.bubble.content),
|
||||||
|
*[
|
||||||
|
ApplyMethod(pi.change_mode, "happy")
|
||||||
|
for pi in self.get_everyone()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def go_through_students(self):
|
||||||
|
pi1, pi2, pi3 = self.get_students()
|
||||||
|
for pi in pi1, pi2, pi3:
|
||||||
|
pi.save_state()
|
||||||
|
bubble = pi1.get_bubble(width = 5)
|
||||||
|
bubble.set_fill(BLACK, opacity = 1)
|
||||||
|
remembered_symbols = VGroup(
|
||||||
|
TexMobject("\\int_0^1 \\frac{1}{1-x^2}\\,dx").shift(UP+LEFT),
|
||||||
|
TexMobject("\\frac{d}{dx} e^x = e^x").shift(DOWN+RIGHT),
|
||||||
|
)
|
||||||
|
cant_wait = TextMobject("I litterally \\\\ can't wait")
|
||||||
|
big_derivative = TexMobject("""
|
||||||
|
\\frac{d}{dx} \\left( \\sin(x^2)2^{\\sqrt{x}} \\right)
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
pi1.change_mode, "confused",
|
||||||
|
pi1.look_at, bubble.get_right(),
|
||||||
|
ShowCreation(bubble),
|
||||||
|
pi2.fade,
|
||||||
|
pi3.fade,
|
||||||
|
)
|
||||||
|
bubble.add_content(remembered_symbols)
|
||||||
|
self.play(Write(remembered_symbols))
|
||||||
|
self.play(ApplyMethod(
|
||||||
|
remembered_symbols.fade, 0.7,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
run_time = 3
|
||||||
|
))
|
||||||
|
self.play(
|
||||||
|
pi1.restore,
|
||||||
|
pi1.fade,
|
||||||
|
pi2.restore,
|
||||||
|
pi2.change_mode, "hooray",
|
||||||
|
pi2.look_at, bubble.get_right(),
|
||||||
|
bubble.pin_to, pi2,
|
||||||
|
FadeOut(remembered_symbols),
|
||||||
|
)
|
||||||
|
bubble.add_content(cant_wait)
|
||||||
|
self.play(Write(cant_wait, run_time = 2))
|
||||||
|
self.play(Blink(pi2))
|
||||||
|
self.play(
|
||||||
|
pi2.restore,
|
||||||
|
pi2.fade,
|
||||||
|
pi3.restore,
|
||||||
|
pi3.change_mode, "pleading",
|
||||||
|
pi3.look_at, bubble.get_right(),
|
||||||
|
bubble.pin_to, pi3,
|
||||||
|
FadeOut(cant_wait)
|
||||||
|
)
|
||||||
|
bubble.add_content(big_derivative)
|
||||||
|
self.play(Write(big_derivative))
|
||||||
|
self.play(Blink(pi3))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def zoom_in_on_first(self):
|
||||||
|
this_video = self.this_video
|
||||||
|
self.remove(this_video)
|
||||||
|
this_video.generate_target()
|
||||||
|
this_video.target.scale_to_fit_height(2*SPACE_HEIGHT)
|
||||||
|
this_video.target.center()
|
||||||
|
this_video.target.set_fill(opacity = 0)
|
||||||
|
|
||||||
|
everything = VGroup(*self.get_mobjects())
|
||||||
|
self.play(
|
||||||
|
FadeOut(everything),
|
||||||
|
MoveToTarget(this_video, run_time = 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
class IntroduceCircle(Scene):
|
||||||
|
def construct(self):
|
||||||
|
circle = Circle(radius = 3, color = WHITE)
|
||||||
|
circle.to_edge(LEFT)
|
||||||
|
radius = Line(circle.get_center(), circle.get_right())
|
||||||
|
radius.highlight(MAROON_B)
|
||||||
|
R = TexMobject("R").next_to(radius, UP)
|
||||||
|
|
||||||
|
area, circumference = words = VGroup(*map(TextMobject, [
|
||||||
|
"Area =", "Circumference ="
|
||||||
|
]))
|
||||||
|
area.highlight(BLUE)
|
||||||
|
circumference.highlight(YELLOW)
|
||||||
|
|
||||||
|
words.arrange_submobjects(DOWN, aligned_edge = LEFT)
|
||||||
|
words.next_to(circle, RIGHT)
|
||||||
|
pi_R, pre_squared = TexMobject("\\pi R", "{}^2")
|
||||||
|
squared = TexMobject("2").replace(pre_squared)
|
||||||
|
area_form = VGroup(pi_R, squared)
|
||||||
|
area_form.next_to(area, RIGHT)
|
||||||
|
two, pi_R = TexMobject("2", "\\pi R")
|
||||||
|
circum_form = VGroup(pi_R, two)
|
||||||
|
circum_form.next_to(circumference, RIGHT)
|
||||||
|
|
||||||
|
self.play(ShowCreation(radius), Write(R))
|
||||||
|
self.play(
|
||||||
|
Rotate(radius, 2*np.pi, about_point = circle.get_center()),
|
||||||
|
ShowCreation(circle)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
FadeIn(area),
|
||||||
|
Write(area_form),
|
||||||
|
circle.set_fill, area.get_color(), 0.5,
|
||||||
|
Animation(radius),
|
||||||
|
Animation(R),
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
circle.set_stroke, circumference.get_color(),
|
||||||
|
FadeIn(circumference),
|
||||||
|
Animation(radius),
|
||||||
|
Animation(R),
|
||||||
|
)
|
||||||
|
self.play(Transform(
|
||||||
|
area_form.copy(),
|
||||||
|
circum_form,
|
||||||
|
path_arc = -np.pi/2,
|
||||||
|
run_time = 3
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,27 +9,31 @@ class SVGMobject(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"initial_scale_factor" : 1,
|
"initial_scale_factor" : 1,
|
||||||
"should_center" : True,
|
"should_center" : True,
|
||||||
|
#Must be filled in in a subclass, or when called
|
||||||
|
"file_name" : None,
|
||||||
}
|
}
|
||||||
def __init__(self, svg_file, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
self.ensure_valid_file()
|
self.ensure_valid_file()
|
||||||
VMobject.__init__(self, **kwargs)
|
VMobject.__init__(self, **kwargs)
|
||||||
self.move_into_position()
|
self.move_into_position()
|
||||||
|
|
||||||
def ensure_valid_file(self):
|
def ensure_valid_file(self):
|
||||||
|
if self.file_name is None:
|
||||||
|
raise Exception("Must specify file for SVGMobject")
|
||||||
possible_paths = [
|
possible_paths = [
|
||||||
self.svg_file,
|
self.file_name,
|
||||||
os.path.join(IMAGE_DIR, self.svg_file),
|
os.path.join(IMAGE_DIR, self.file_name),
|
||||||
os.path.join(IMAGE_DIR, self.svg_file + ".svg"),
|
os.path.join(IMAGE_DIR, self.file_name + ".svg"),
|
||||||
]
|
]
|
||||||
for path in possible_paths:
|
for path in possible_paths:
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
self.svg_file = path
|
self.file_name = path
|
||||||
return
|
return
|
||||||
raise IOError("No file matching %s in image directory"%self.svg_file)
|
raise IOError("No file matching %s in image directory"%self.file_name)
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
doc = minidom.parse(self.svg_file)
|
doc = minidom.parse(self.file_name)
|
||||||
self.ref_to_element = {}
|
self.ref_to_element = {}
|
||||||
for svg in doc.getElementsByTagName("svg"):
|
for svg in doc.getElementsByTagName("svg"):
|
||||||
self.add(*self.get_mobjects_from(svg))
|
self.add(*self.get_mobjects_from(svg))
|
||||||
|
|
|
@ -48,8 +48,11 @@ class TexMobject(SVGMobject):
|
||||||
##
|
##
|
||||||
assert(all([isinstance(a, str) for a in self.args]))
|
assert(all([isinstance(a, str) for a in self.args]))
|
||||||
self.tex_string = self.get_modified_expression()
|
self.tex_string = self.get_modified_expression()
|
||||||
VMobject.__init__(self, **kwargs)
|
file_name = tex_to_svg_file(
|
||||||
self.move_into_position()
|
self.tex_string,
|
||||||
|
self.template_tex_file
|
||||||
|
)
|
||||||
|
SVGMobject.__init__(self, file_name = file_name, **kwargs)
|
||||||
if self.organize_left_to_right:
|
if self.organize_left_to_right:
|
||||||
self.organize_submobjects_left_to_right()
|
self.organize_submobjects_left_to_right()
|
||||||
|
|
||||||
|
@ -61,10 +64,6 @@ class TexMobject(SVGMobject):
|
||||||
|
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
self.svg_file = tex_to_svg_file(
|
|
||||||
self.tex_string,
|
|
||||||
self.template_tex_file
|
|
||||||
)
|
|
||||||
SVGMobject.generate_points(self)
|
SVGMobject.generate_points(self)
|
||||||
if len(self.args) > 1:
|
if len(self.args) > 1:
|
||||||
self.handle_multiple_args()
|
self.handle_multiple_args()
|
||||||
|
|
|
@ -115,7 +115,7 @@ class EigenThingsArentAllThatBad(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Eigen-things aren't \\\\ actually so bad",
|
"Eigen-things aren't \\\\ actually so bad",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.change_student_modes(
|
self.change_student_modes(
|
||||||
"pondering", "pondering", "erm"
|
"pondering", "pondering", "erm"
|
||||||
|
@ -496,7 +496,7 @@ class CanEigenvaluesBeNegative(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says("Can eigenvalues be negative?")
|
self.student_says("Can eigenvalues be negative?")
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
self.teacher_says("But of course!", pi_creature_target_mode = "hooray")
|
self.teacher_says("But of course!", target_mode = "hooray")
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
|
||||||
class EigenvalueNegativeOneHalf(LinearTransformationScene):
|
class EigenvalueNegativeOneHalf(LinearTransformationScene):
|
||||||
|
@ -659,7 +659,7 @@ class WordsOnComputation(TeacherStudentsScene):
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"I won't cover the full\\\\",
|
"I won't cover the full\\\\",
|
||||||
"details of computation...",
|
"details of computation...",
|
||||||
pi_creature_target_mode = "guilty"
|
target_mode = "guilty"
|
||||||
)
|
)
|
||||||
self.change_student_modes("angry", "sassy", "angry")
|
self.change_student_modes("angry", "sassy", "angry")
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
|
|
@ -1427,7 +1427,7 @@ class ProposeDerivativeAsMatrix(TeacherStudentsScene):
|
||||||
derivative with
|
derivative with
|
||||||
a matrix
|
a matrix
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
self.change_student_modes("pondering", "confused", "erm")
|
self.change_student_modes("pondering", "confused", "erm")
|
||||||
|
@ -1975,7 +1975,7 @@ class BackToTheQuestion(TeacherStudentsScene):
|
||||||
this relate to what vectors
|
this relate to what vectors
|
||||||
really are?
|
really are?
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "confused"
|
target_mode = "confused"
|
||||||
)
|
)
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
|
@ -2435,7 +2435,7 @@ class TextbooksAreAbstract(TeacherStudentsScene):
|
||||||
All the textbooks I found
|
All the textbooks I found
|
||||||
are pretty abstract.
|
are pretty abstract.
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "pleading"
|
target_mode = "pleading"
|
||||||
)
|
)
|
||||||
self.random_blink(3)
|
self.random_blink(3)
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
|
@ -2456,7 +2456,7 @@ class TextbooksAreAbstract(TeacherStudentsScene):
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Only then should you\\\\",
|
"Only then should you\\\\",
|
||||||
"think from the axioms",
|
"think from the axioms",
|
||||||
pi_creature_target_mode = "surprised"
|
target_mode = "surprised"
|
||||||
)
|
)
|
||||||
self.change_student_modes(*["pondering"]*3)
|
self.change_student_modes(*["pondering"]*3)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
@ -2465,7 +2465,7 @@ class LastAskWhatAreVectors(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"So...what are vectors?",
|
"So...what are vectors?",
|
||||||
pi_creature_target_mode = "erm"
|
target_mode = "erm"
|
||||||
)
|
)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
|
@ -2559,7 +2559,7 @@ class GoodLuck(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Good luck with \\\\ your future learning!",
|
"Good luck with \\\\ your future learning!",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.change_student_modes(*["happy"]*3)
|
self.change_student_modes(*["happy"]*3)
|
||||||
self.random_blink(3)
|
self.random_blink(3)
|
||||||
|
|
|
@ -70,12 +70,12 @@ class NoComputations(TeacherStudentsScene):
|
||||||
self.setup()
|
self.setup()
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"Will you cover \\\\ computations?",
|
"Will you cover \\\\ computations?",
|
||||||
pi_creature_target_mode = "raise_left_hand"
|
target_mode = "raise_left_hand"
|
||||||
)
|
)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Well...uh...no",
|
"Well...uh...no",
|
||||||
pi_creature_target_mode = "guilty",
|
target_mode = "guilty",
|
||||||
)
|
)
|
||||||
self.play(*[
|
self.play(*[
|
||||||
ApplyMethod(student.change_mode, mode)
|
ApplyMethod(student.change_mode, mode)
|
||||||
|
@ -2037,7 +2037,7 @@ class WhatAboutNonsquareMatrices(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"What about \\\\ nonsquare matrices?",
|
"What about \\\\ nonsquare matrices?",
|
||||||
pi_creature_target_mode = "raise_right_hand"
|
target_mode = "raise_right_hand"
|
||||||
)
|
)
|
||||||
self.play(self.get_students()[0].change_mode, "confused")
|
self.play(self.get_students()[0].change_mode, "confused")
|
||||||
self.random_blink(6)
|
self.random_blink(6)
|
||||||
|
|
|
@ -523,7 +523,7 @@ class AskAboutSymmetry(TeacherStudentsScene):
|
||||||
VMobject(question[3], question[5]).highlight(W_COLOR)
|
VMobject(question[3], question[5]).highlight(W_COLOR)
|
||||||
self.student_says(
|
self.student_says(
|
||||||
question,
|
question,
|
||||||
pi_creature_target_mode = "raise_left_hand"
|
target_mode = "raise_left_hand"
|
||||||
)
|
)
|
||||||
self.change_student_modes("confused")
|
self.change_student_modes("confused")
|
||||||
self.play(self.get_teacher().change_mode, "pondering")
|
self.play(self.get_teacher().change_mode, "pondering")
|
||||||
|
@ -673,7 +673,7 @@ class LurkingQuestion(TeacherStudentsScene):
|
||||||
# two views connected?
|
# two views connected?
|
||||||
# """,
|
# """,
|
||||||
# student_index = 2,
|
# student_index = 2,
|
||||||
# pi_creature_target_mode = "raise_left_hand",
|
# target_mode = "raise_left_hand",
|
||||||
# width = 6,
|
# width = 6,
|
||||||
# )
|
# )
|
||||||
self.change_student_modes(
|
self.change_student_modes(
|
||||||
|
@ -1347,7 +1347,7 @@ class WhatAboutTheGeometricView(TeacherStudentsScene):
|
||||||
What does this association
|
What does this association
|
||||||
mean geometrically?
|
mean geometrically?
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "raise_right_hand"
|
target_mode = "raise_right_hand"
|
||||||
)
|
)
|
||||||
self.change_student_modes("pondering", "raise_right_hand", "pondering")
|
self.change_student_modes("pondering", "raise_right_hand", "pondering")
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
@ -1897,7 +1897,7 @@ class AskAboutNonUnitVectors(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"What about \\\\ non-unit vectors",
|
"What about \\\\ non-unit vectors",
|
||||||
pi_creature_target_mode = "raise_left_hand"
|
target_mode = "raise_left_hand"
|
||||||
)
|
)
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
||||||
|
@ -2124,7 +2124,7 @@ class IsntThisBeautiful(TeacherStudentsScene):
|
||||||
self.teacher.look(DOWN+LEFT)
|
self.teacher.look(DOWN+LEFT)
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Isn't this", "beautiful",
|
"Isn't this", "beautiful",
|
||||||
pi_creature_target_mode = "surprised"
|
target_mode = "surprised"
|
||||||
)
|
)
|
||||||
for student in self.get_students():
|
for student in self.get_students():
|
||||||
self.play(student.change_mode, "happy")
|
self.play(student.change_mode, "happy")
|
||||||
|
|
|
@ -69,7 +69,7 @@ class DoTheSameForCross(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
words = TextMobject("Let's do the same \\\\ for", "cross products")
|
words = TextMobject("Let's do the same \\\\ for", "cross products")
|
||||||
words.highlight_by_tex("cross products", YELLOW)
|
words.highlight_by_tex("cross products", YELLOW)
|
||||||
self.teacher_says(words, pi_creature_target_mode = "surprised")
|
self.teacher_says(words, target_mode = "surprised")
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
self.change_student_modes("pondering")
|
self.change_student_modes("pondering")
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
@ -429,7 +429,7 @@ class HowDoYouCompute(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"How do you \\\\ compute this?",
|
"How do you \\\\ compute this?",
|
||||||
pi_creature_target_mode = "raise_left_hand"
|
target_mode = "raise_left_hand"
|
||||||
)
|
)
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
||||||
|
@ -1478,7 +1478,7 @@ class ThisGetsWeird(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"This gets weird...",
|
"This gets weird...",
|
||||||
pi_creature_target_mode = "sassy"
|
target_mode = "sassy"
|
||||||
)
|
)
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
||||||
|
@ -1639,7 +1639,7 @@ class ThereIsAReason(TeacherStudentsScene):
|
||||||
"reason", "for doing it"
|
"reason", "for doing it"
|
||||||
)
|
)
|
||||||
words.highlight_by_tex("reason", YELLOW)
|
words.highlight_by_tex("reason", YELLOW)
|
||||||
self.teacher_says(words, pi_creature_target_mode = "surprised")
|
self.teacher_says(words, target_mode = "surprised")
|
||||||
self.change_student_modes(
|
self.change_student_modes(
|
||||||
"raise_right_hand", "confused", "raise_left_hand"
|
"raise_right_hand", "confused", "raise_left_hand"
|
||||||
)
|
)
|
||||||
|
@ -1649,7 +1649,7 @@ class RememberDuality(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
words = TextMobject("Remember ", "duality", "?", arg_separator = "")
|
words = TextMobject("Remember ", "duality", "?", arg_separator = "")
|
||||||
words[1].gradient_highlight(BLUE, YELLOW)
|
words[1].gradient_highlight(BLUE, YELLOW)
|
||||||
self.teacher_says(words, pi_creature_target_mode = "sassy")
|
self.teacher_says(words, target_mode = "sassy")
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
||||||
class NextVideo(Scene):
|
class NextVideo(Scene):
|
||||||
|
|
|
@ -201,7 +201,7 @@ class DualityReview(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
words = TextMobject("Quick", "duality", "review")
|
words = TextMobject("Quick", "duality", "review")
|
||||||
words[1].gradient_highlight(BLUE, YELLOW)
|
words[1].gradient_highlight(BLUE, YELLOW)
|
||||||
self.teacher_says(words, pi_creature_target_mode = "surprised")
|
self.teacher_says(words, target_mode = "surprised")
|
||||||
self.change_student_modes("pondering")
|
self.change_student_modes("pondering")
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
||||||
|
@ -785,7 +785,7 @@ class WhyAreWeDoingThis(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"Um...why are \\\\ we doing this?",
|
"Um...why are \\\\ we doing this?",
|
||||||
pi_creature_target_mode = "confused"
|
target_mode = "confused"
|
||||||
)
|
)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
self.play(self.get_teacher().change_mode, "erm")
|
self.play(self.get_teacher().change_mode, "erm")
|
||||||
|
|
|
@ -812,7 +812,7 @@ class AskAboutTranslation(TeacherStudentsScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"\\centering How do you translate \\\\ between coordinate systems?",
|
"\\centering How do you translate \\\\ between coordinate systems?",
|
||||||
pi_creature_target_mode = "raise_right_hand"
|
target_mode = "raise_right_hand"
|
||||||
)
|
)
|
||||||
self.random_blink(3)
|
self.random_blink(3)
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ class AnotherFootnote(TeacherStudentsScene):
|
||||||
self.teacher.look(LEFT)
|
self.teacher.look(LEFT)
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"More footnotes!",
|
"More footnotes!",
|
||||||
pi_creature_target_mode = "surprised",
|
target_mode = "surprised",
|
||||||
run_time = 1
|
run_time = 1
|
||||||
)
|
)
|
||||||
self.random_blink(2)
|
self.random_blink(2)
|
||||||
|
|
|
@ -352,7 +352,6 @@ class ClassWatching(TeacherStudentsScene):
|
||||||
self.play(self.get_teacher().change_mode, "pondering")
|
self.play(self.get_teacher().change_mode, "pondering")
|
||||||
self.random_blink(3)
|
self.random_blink(3)
|
||||||
|
|
||||||
|
|
||||||
class RandolphWatching(Scene):
|
class RandolphWatching(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
randy = Randolph()
|
randy = Randolph()
|
||||||
|
@ -464,7 +463,7 @@ class GrowRonaksSierpinski(Scene):
|
||||||
for n in range(n_layers):
|
for n in range(n_layers):
|
||||||
ronaks_sierpinski.add(self.get_lines_at_layer(n))
|
ronaks_sierpinski.add(self.get_lines_at_layer(n))
|
||||||
ronaks_sierpinski.gradient_highlight(*self.colors)
|
ronaks_sierpinski.gradient_highlight(*self.colors)
|
||||||
ronaks_sierpinski.set_stroke(width = 3)
|
ronaks_sierpinski.set_stroke(width = 0)##TODO
|
||||||
return ronaks_sierpinski
|
return ronaks_sierpinski
|
||||||
|
|
||||||
def get_dots(self, n_layers):
|
def get_dots(self, n_layers):
|
||||||
|
@ -747,7 +746,7 @@ class EndScreen(TeacherStudentsScene):
|
||||||
See you every
|
See you every
|
||||||
other friday!
|
other friday!
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.change_student_modes(*["happy"]*3)
|
self.change_student_modes(*["happy"]*3)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
|
|
@ -5,6 +5,8 @@ from mobject.svg_mobject import SVGMobject
|
||||||
from mobject.vectorized_mobject import VMobject, VGroup
|
from mobject.vectorized_mobject import VMobject, VGroup
|
||||||
from mobject.tex_mobject import TextMobject, TexMobject
|
from mobject.tex_mobject import TextMobject, TexMobject
|
||||||
|
|
||||||
|
from topics.objects import Bubble, ThoughtBubble, SpeechBubble
|
||||||
|
|
||||||
from animation import Animation
|
from animation import Animation
|
||||||
from animation.transform import Transform, ApplyMethod, \
|
from animation.transform import Transform, ApplyMethod, \
|
||||||
FadeOut, FadeIn, ApplyPointwiseFunction
|
FadeOut, FadeIn, ApplyPointwiseFunction
|
||||||
|
@ -41,7 +43,7 @@ class PiCreature(SVGMobject):
|
||||||
"PiCreatures_%s.svg"%mode
|
"PiCreatures_%s.svg"%mode
|
||||||
)
|
)
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
SVGMobject.__init__(self, svg_file, **kwargs)
|
SVGMobject.__init__(self, file_name = svg_file, **kwargs)
|
||||||
self.init_colors()
|
self.init_colors()
|
||||||
if self.flip_at_start:
|
if self.flip_at_start:
|
||||||
self.flip()
|
self.flip()
|
||||||
|
@ -207,128 +209,6 @@ class Blink(ApplyMethod):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Bubble(SVGMobject):
|
|
||||||
CONFIG = {
|
|
||||||
"direction" : LEFT,
|
|
||||||
"center_point" : ORIGIN,
|
|
||||||
"content_scale_factor" : 0.75,
|
|
||||||
"height" : 5,
|
|
||||||
"width" : 8,
|
|
||||||
"bubble_center_adjustment_factor" : 1./8,
|
|
||||||
"file_name" : None,
|
|
||||||
"propogate_style_to_family" : True,
|
|
||||||
}
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
digest_config(self, kwargs)
|
|
||||||
if self.file_name is None:
|
|
||||||
raise Exception("Must invoke Bubble subclass")
|
|
||||||
svg_file = os.path.join(
|
|
||||||
IMAGE_DIR, self.file_name
|
|
||||||
)
|
|
||||||
SVGMobject.__init__(self, svg_file, **kwargs)
|
|
||||||
self.center()
|
|
||||||
self.stretch_to_fit_height(self.height)
|
|
||||||
self.stretch_to_fit_width(self.width)
|
|
||||||
if self.direction[0] > 0:
|
|
||||||
Mobject.flip(self)
|
|
||||||
self.direction_was_specified = ("direction" in kwargs)
|
|
||||||
self.content = Mobject()
|
|
||||||
|
|
||||||
def get_tip(self):
|
|
||||||
#TODO, find a better way
|
|
||||||
return self.get_corner(DOWN+self.direction)-0.6*self.direction
|
|
||||||
|
|
||||||
def get_bubble_center(self):
|
|
||||||
factor = self.bubble_center_adjustment_factor
|
|
||||||
return self.get_center() + factor*self.get_height()*UP
|
|
||||||
|
|
||||||
def move_tip_to(self, point):
|
|
||||||
self.shift(point - self.get_tip())
|
|
||||||
return self
|
|
||||||
|
|
||||||
def flip(self):
|
|
||||||
Mobject.flip(self)
|
|
||||||
self.direction = -np.array(self.direction)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def pin_to(self, mobject):
|
|
||||||
mob_center = mobject.get_center()
|
|
||||||
want_to_filp = np.sign(mob_center[0]) != np.sign(self.direction[0])
|
|
||||||
can_flip = not self.direction_was_specified
|
|
||||||
if want_to_filp and can_flip:
|
|
||||||
self.flip()
|
|
||||||
boundary_point = mobject.get_critical_point(UP-self.direction)
|
|
||||||
vector_from_center = 1.0*(boundary_point-mob_center)
|
|
||||||
self.move_tip_to(mob_center+vector_from_center)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def position_mobject_inside(self, mobject):
|
|
||||||
scaled_width = self.content_scale_factor*self.get_width()
|
|
||||||
if mobject.get_width() > scaled_width:
|
|
||||||
mobject.scale_to_fit_width(scaled_width)
|
|
||||||
mobject.shift(
|
|
||||||
self.get_bubble_center() - mobject.get_center()
|
|
||||||
)
|
|
||||||
return mobject
|
|
||||||
|
|
||||||
def add_content(self, mobject):
|
|
||||||
self.position_mobject_inside(mobject)
|
|
||||||
self.content = mobject
|
|
||||||
return self.content
|
|
||||||
|
|
||||||
def write(self, *text):
|
|
||||||
self.add_content(TextMobject(*text))
|
|
||||||
return self
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.add_content(VMobject())
|
|
||||||
return self
|
|
||||||
|
|
||||||
class SpeechBubble(Bubble):
|
|
||||||
CONFIG = {
|
|
||||||
"file_name" : "Bubbles_speech.svg",
|
|
||||||
"height" : 4
|
|
||||||
}
|
|
||||||
|
|
||||||
class DoubleSpeechBubble(Bubble):
|
|
||||||
CONFIG = {
|
|
||||||
"file_name" : "Bubbles_double_speech.svg",
|
|
||||||
"height" : 4
|
|
||||||
}
|
|
||||||
|
|
||||||
class ThoughtBubble(Bubble):
|
|
||||||
CONFIG = {
|
|
||||||
"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])
|
|
||||||
)
|
|
||||||
|
|
||||||
def make_green_screen(self):
|
|
||||||
self.submobjects[-1].set_fill(GREEN_SCREEN, opacity = 1)
|
|
||||||
return self
|
|
||||||
|
|
||||||
class Headphones(SVGMobject):
|
|
||||||
CONFIG = {
|
|
||||||
"file_name" : "headphones",
|
|
||||||
"height" : 2,
|
|
||||||
"y_stretch_factor" : 0.5,
|
|
||||||
"color" : GREY,
|
|
||||||
}
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
digest_config(self, kwargs)
|
|
||||||
SVGMobject.__init__(self, self.file_name, **kwargs)
|
|
||||||
self.stretch(self.y_stretch_factor, 1)
|
|
||||||
self.scale_to_fit_height(self.height)
|
|
||||||
self.set_stroke(width = 0)
|
|
||||||
self.set_fill(color = self.color)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RandolphScene(Scene):
|
class RandolphScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"randy_kwargs" : {},
|
"randy_kwargs" : {},
|
||||||
|
@ -384,6 +264,7 @@ class TeacherStudentsScene(Scene):
|
||||||
**bubble_kwargs):
|
**bubble_kwargs):
|
||||||
bubble = pi_creature.get_bubble(bubble_type, **bubble_kwargs)
|
bubble = pi_creature.get_bubble(bubble_type, **bubble_kwargs)
|
||||||
bubble.add_content(content)
|
bubble.add_content(content)
|
||||||
|
bubble.resize_to_content()
|
||||||
if pi_creature.bubble:
|
if pi_creature.bubble:
|
||||||
content_intro_anims = [
|
content_intro_anims = [
|
||||||
Transform(pi_creature.bubble, bubble),
|
Transform(pi_creature.bubble, bubble),
|
||||||
|
@ -398,7 +279,7 @@ class TeacherStudentsScene(Scene):
|
||||||
return content_intro_anims
|
return content_intro_anims
|
||||||
|
|
||||||
def introduce_bubble(self, content, bubble_type, pi_creature,
|
def introduce_bubble(self, content, bubble_type, pi_creature,
|
||||||
pi_creature_target_mode = None,
|
target_mode = None,
|
||||||
added_anims = [],
|
added_anims = [],
|
||||||
**bubble_kwargs):
|
**bubble_kwargs):
|
||||||
if all(map(lambda s : isinstance(s, str), content)):
|
if all(map(lambda s : isinstance(s, str), content)):
|
||||||
|
@ -411,11 +292,11 @@ class TeacherStudentsScene(Scene):
|
||||||
content, bubble_type, pi_creature, **bubble_kwargs
|
content, bubble_type, pi_creature, **bubble_kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
if not pi_creature_target_mode:
|
if not target_mode:
|
||||||
if bubble_type is "speech":
|
if bubble_type is "speech":
|
||||||
pi_creature_target_mode = "speaking"
|
target_mode = "speaking"
|
||||||
else:
|
else:
|
||||||
pi_creature_target_mode = "pondering"
|
target_mode = "pondering"
|
||||||
|
|
||||||
for p in self.get_everyone():
|
for p in self.get_everyone():
|
||||||
if (p.bubble is not None) and (p is not pi_creature):
|
if (p.bubble is not None) and (p is not pi_creature):
|
||||||
|
@ -429,7 +310,7 @@ class TeacherStudentsScene(Scene):
|
||||||
anims = added_anims + content_intro_anims + [
|
anims = added_anims + content_intro_anims + [
|
||||||
ApplyMethod(
|
ApplyMethod(
|
||||||
pi_creature.change_mode,
|
pi_creature.change_mode,
|
||||||
pi_creature_target_mode,
|
target_mode,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
self.play(*anims)
|
self.play(*anims)
|
||||||
|
@ -441,12 +322,12 @@ class TeacherStudentsScene(Scene):
|
||||||
)
|
)
|
||||||
|
|
||||||
def student_says(self, *content, **kwargs):
|
def student_says(self, *content, **kwargs):
|
||||||
if "pi_creature_target_mode" not in kwargs:
|
if "target_mode" not in kwargs:
|
||||||
target_mode = random.choice([
|
target_mode = random.choice([
|
||||||
"raise_right_hand",
|
"raise_right_hand",
|
||||||
"raise_left_hand",
|
"raise_left_hand",
|
||||||
])
|
])
|
||||||
kwargs["pi_creature_target_mode"] = target_mode
|
kwargs["target_mode"] = target_mode
|
||||||
student = self.get_students()[kwargs.get("student_index", 1)]
|
student = self.get_students()[kwargs.get("student_index", 1)]
|
||||||
return self.introduce_bubble(content, "speech", student, **kwargs)
|
return self.introduce_bubble(content, "speech", student, **kwargs)
|
||||||
|
|
||||||
|
|
164
topics/objects.py
Normal file
164
topics/objects.py
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
from helpers import *
|
||||||
|
|
||||||
|
from mobject import Mobject
|
||||||
|
from mobject.vectorized_mobject import VGroup
|
||||||
|
from mobject.svg_mobject import SVGMobject
|
||||||
|
from mobject.tex_mobject import TextMobject
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VideoIcon(SVGMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "video_icon",
|
||||||
|
"width" : 2*SPACE_WIDTH/12.,
|
||||||
|
"considered_smooth" : False,
|
||||||
|
}
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
SVGMobject.__init__(self, **kwargs)
|
||||||
|
self.center()
|
||||||
|
self.scale_to_fit_width(self.width)
|
||||||
|
self.set_stroke(color = WHITE, width = 0)
|
||||||
|
self.set_fill(color = WHITE, opacity = 1)
|
||||||
|
for mob in self:
|
||||||
|
mob.considered_smooth = False
|
||||||
|
|
||||||
|
class VideoSeries(VGroup):
|
||||||
|
CONFIG = {
|
||||||
|
"num_videos" : 10,
|
||||||
|
"gradient_colors" : [BLUE_B, BLUE_D],
|
||||||
|
}
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
digest_config(self, kwargs)
|
||||||
|
videos = [VideoIcon() for x in range(self.num_videos)]
|
||||||
|
VGroup.__init__(self, *videos, **kwargs)
|
||||||
|
self.arrange_submobjects()
|
||||||
|
self.gradient_highlight(*self.gradient_colors)
|
||||||
|
|
||||||
|
|
||||||
|
class Headphones(SVGMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "headphones",
|
||||||
|
"height" : 2,
|
||||||
|
"y_stretch_factor" : 0.5,
|
||||||
|
"color" : GREY,
|
||||||
|
}
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
digest_config(self, kwargs)
|
||||||
|
SVGMobject.__init__(self, self.file_name, **kwargs)
|
||||||
|
self.stretch(self.y_stretch_factor, 1)
|
||||||
|
self.scale_to_fit_height(self.height)
|
||||||
|
self.set_stroke(width = 0)
|
||||||
|
self.set_fill(color = self.color)
|
||||||
|
|
||||||
|
|
||||||
|
class Bubble(SVGMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"direction" : LEFT,
|
||||||
|
"center_point" : ORIGIN,
|
||||||
|
"content_scale_factor" : 0.75,
|
||||||
|
"height" : 5,
|
||||||
|
"width" : 8,
|
||||||
|
"bubble_center_adjustment_factor" : 1./8,
|
||||||
|
"file_name" : None,
|
||||||
|
"propogate_style_to_family" : True,
|
||||||
|
}
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
digest_config(self, kwargs, locals())
|
||||||
|
if self.file_name is None:
|
||||||
|
raise Exception("Must invoke Bubble subclass")
|
||||||
|
SVGMobject.__init__(self, **kwargs)
|
||||||
|
self.center()
|
||||||
|
self.stretch_to_fit_height(self.height)
|
||||||
|
self.stretch_to_fit_width(self.width)
|
||||||
|
if self.direction[0] > 0:
|
||||||
|
Mobject.flip(self)
|
||||||
|
self.direction_was_specified = ("direction" in kwargs)
|
||||||
|
self.content = Mobject()
|
||||||
|
|
||||||
|
def get_tip(self):
|
||||||
|
#TODO, find a better way
|
||||||
|
return self.get_corner(DOWN+self.direction)-0.6*self.direction
|
||||||
|
|
||||||
|
def get_bubble_center(self):
|
||||||
|
factor = self.bubble_center_adjustment_factor
|
||||||
|
return self.get_center() + factor*self.get_height()*UP
|
||||||
|
|
||||||
|
def move_tip_to(self, point):
|
||||||
|
self.shift(point - self.get_tip())
|
||||||
|
return self
|
||||||
|
|
||||||
|
def flip(self):
|
||||||
|
Mobject.flip(self)
|
||||||
|
self.direction = -np.array(self.direction)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def pin_to(self, mobject):
|
||||||
|
mob_center = mobject.get_center()
|
||||||
|
want_to_filp = np.sign(mob_center[0]) != np.sign(self.direction[0])
|
||||||
|
can_flip = not self.direction_was_specified
|
||||||
|
if want_to_filp and can_flip:
|
||||||
|
self.flip()
|
||||||
|
boundary_point = mobject.get_critical_point(UP-self.direction)
|
||||||
|
vector_from_center = 1.0*(boundary_point-mob_center)
|
||||||
|
self.move_tip_to(mob_center+vector_from_center)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def position_mobject_inside(self, mobject):
|
||||||
|
scaled_width = self.content_scale_factor*self.get_width()
|
||||||
|
if mobject.get_width() > scaled_width:
|
||||||
|
mobject.scale_to_fit_width(scaled_width)
|
||||||
|
mobject.shift(
|
||||||
|
self.get_bubble_center() - mobject.get_center()
|
||||||
|
)
|
||||||
|
return mobject
|
||||||
|
|
||||||
|
def add_content(self, mobject):
|
||||||
|
self.position_mobject_inside(mobject)
|
||||||
|
self.content = mobject
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
def write(self, *text):
|
||||||
|
self.add_content(TextMobject(*text))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def resize_to_content(self):
|
||||||
|
target_width = self.content.get_width()
|
||||||
|
target_width += max(2*MED_BUFF, 2)
|
||||||
|
target_height = self.content.get_height()
|
||||||
|
target_height += 2.5*LARGE_BUFF
|
||||||
|
tip_point = self.get_tip()
|
||||||
|
self.stretch_to_fit_width(target_width)
|
||||||
|
self.stretch_to_fit_height(target_height)
|
||||||
|
self.move_tip_to(tip_point)
|
||||||
|
self.position_mobject_inside(self.content)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.add_content(VMobject())
|
||||||
|
return self
|
||||||
|
|
||||||
|
class SpeechBubble(Bubble):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "Bubbles_speech.svg",
|
||||||
|
"height" : 4
|
||||||
|
}
|
||||||
|
|
||||||
|
class DoubleSpeechBubble(Bubble):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "Bubbles_double_speech.svg",
|
||||||
|
"height" : 4
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThoughtBubble(Bubble):
|
||||||
|
CONFIG = {
|
||||||
|
"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])
|
||||||
|
)
|
||||||
|
|
||||||
|
def make_green_screen(self):
|
||||||
|
self.submobjects[-1].set_fill(GREEN_SCREEN, opacity = 1)
|
||||||
|
return self
|
116
wcat.py
116
wcat.py
|
@ -17,6 +17,7 @@ from topics.number_line import *
|
||||||
from topics.combinatorics import *
|
from topics.combinatorics import *
|
||||||
from topics.numerals import *
|
from topics.numerals import *
|
||||||
from topics.three_dimensions import *
|
from topics.three_dimensions import *
|
||||||
|
from topics.objects import *
|
||||||
from scene import Scene
|
from scene import Scene
|
||||||
from camera import Camera
|
from camera import Camera
|
||||||
from mobject.svg_mobject import *
|
from mobject.svg_mobject import *
|
||||||
|
@ -254,7 +255,7 @@ class Introduction(TeacherStudentsScene):
|
||||||
self.random_blink(3)
|
self.random_blink(3)
|
||||||
self.teacher_says(
|
self.teacher_says(
|
||||||
"Here's why \\\\ I'm excited...",
|
"Here's why \\\\ I'm excited...",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
for pi in self.get_students():
|
for pi in self.get_students():
|
||||||
pi.target.look_at(self.get_teacher().eyes)
|
pi.target.look_at(self.get_teacher().eyes)
|
||||||
|
@ -279,7 +280,7 @@ class WhenIWasAKid(TeacherStudentsScene):
|
||||||
Here's why
|
Here's why
|
||||||
I'm excited!
|
I'm excited!
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.change_student_modes(*["happy"]*3)
|
self.change_student_modes(*["happy"]*3)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -310,7 +311,7 @@ class WhenIWasAKid(TeacherStudentsScene):
|
||||||
Math! Excitement!
|
Math! Excitement!
|
||||||
You are the future!
|
You are the future!
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "hooray"
|
target_mode = "hooray"
|
||||||
)
|
)
|
||||||
self.play(
|
self.play(
|
||||||
pi1.look_at, pi2.eyes,
|
pi1.look_at, pi2.eyes,
|
||||||
|
@ -352,7 +353,7 @@ class WhenIWasAKid(TeacherStudentsScene):
|
||||||
self.student_says(
|
self.student_says(
|
||||||
"How is this math?",
|
"How is this math?",
|
||||||
student_index = -1,
|
student_index = -1,
|
||||||
pi_creature_target_mode = "pleading",
|
target_mode = "pleading",
|
||||||
width = 5,
|
width = 5,
|
||||||
height = 3,
|
height = 3,
|
||||||
direction = RIGHT
|
direction = RIGHT
|
||||||
|
@ -1891,7 +1892,7 @@ class ThatsTheProof(TeacherStudentsScene):
|
||||||
Bada boom
|
Bada boom
|
||||||
bada bang!
|
bada bang!
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "hooray",
|
target_mode = "hooray",
|
||||||
width = 4
|
width = 4
|
||||||
)
|
)
|
||||||
self.change_student_modes(*["hooray"]*3)
|
self.change_student_modes(*["hooray"]*3)
|
||||||
|
@ -1905,7 +1906,7 @@ class ThatsTheProof(TeacherStudentsScene):
|
||||||
the mobius strip
|
the mobius strip
|
||||||
fact...
|
fact...
|
||||||
""",
|
""",
|
||||||
pi_creature_target_mode = "guilty",
|
target_mode = "guilty",
|
||||||
width = 4,
|
width = 4,
|
||||||
)
|
)
|
||||||
self.random_blink()
|
self.random_blink()
|
||||||
|
@ -1949,6 +1950,7 @@ class PatreonThanks(Scene):
|
||||||
"Loo Yu Jun",
|
"Loo Yu Jun",
|
||||||
"Tom",
|
"Tom",
|
||||||
"Othman Alikhan",
|
"Othman Alikhan",
|
||||||
|
"Juan Batiz-Benet",
|
||||||
"Markus Persson",
|
"Markus Persson",
|
||||||
"Joseph John Cox",
|
"Joseph John Cox",
|
||||||
"Achille Brighton",
|
"Achille Brighton",
|
||||||
|
@ -1981,14 +1983,19 @@ class PatreonThanks(Scene):
|
||||||
|
|
||||||
self.play(morty.change_mode, "gracious")
|
self.play(morty.change_mode, "gracious")
|
||||||
self.play(Write(special_thanks, run_time = 1))
|
self.play(Write(special_thanks, run_time = 1))
|
||||||
self.play(Write(left_patrons))
|
self.play(
|
||||||
self.play(Write(right_patrons))
|
Write(left_patrons),
|
||||||
|
morty.look_at, left_patrons
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
Write(right_patrons),
|
||||||
|
morty.look_at, right_patrons
|
||||||
|
)
|
||||||
self.play(Blink(morty))
|
self.play(Blink(morty))
|
||||||
self.play(morty.look_at, left_patrons)
|
for patrons in left_patrons, right_patrons:
|
||||||
|
for index in 0, -1:
|
||||||
|
self.play(morty.look_at, patrons[index])
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(morty.look_at, right_patrons)
|
|
||||||
self.play(Blink(morty))
|
|
||||||
|
|
||||||
|
|
||||||
class CreditTWo(Scene):
|
class CreditTWo(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -2033,11 +2040,96 @@ class CreditTWo(Scene):
|
||||||
self.play(Blink(morty))
|
self.play(Blink(morty))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
class CreditThree(Scene):
|
||||||
|
def construct(self):
|
||||||
|
logo_dot = Dot().to_edge(UP).shift(3*RIGHT)
|
||||||
|
randy = Randolph()
|
||||||
|
randy.next_to(ORIGIN, DOWN)
|
||||||
|
randy.to_edge(LEFT)
|
||||||
|
randy.look(RIGHT)
|
||||||
|
self.add(randy)
|
||||||
|
bubble = randy.get_bubble(width = 2, height = 2)
|
||||||
|
|
||||||
|
domains = VGroup(*map(TextMobject, [
|
||||||
|
"visualnumbertheory.com",
|
||||||
|
"buymywidgets.com",
|
||||||
|
"learnwhatilearn.com",
|
||||||
|
]))
|
||||||
|
domains.arrange_submobjects(DOWN, aligned_edge = LEFT)
|
||||||
|
domains.next_to(randy, UP, buff = LARGE_BUFF)
|
||||||
|
domains.shift_onto_screen()
|
||||||
|
|
||||||
|
promo_code = TextMobject("Promo code: TOPOLOGY")
|
||||||
|
promo_code.shift(3*RIGHT)
|
||||||
|
self.add(promo_code)
|
||||||
|
whois = TextMobject("Free WHOIS privacy")
|
||||||
|
whois.next_to(promo_code, DOWN, buff = LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(Blink(randy))
|
||||||
|
self.play(
|
||||||
|
randy.change_mode, "happy",
|
||||||
|
randy.look_at, logo_dot
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
ShowCreation(bubble),
|
||||||
|
randy.change_mode, "pondering",
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.play(Blink(randy))
|
||||||
|
self.play(
|
||||||
|
Transform(bubble, VectorizedPoint(randy.get_corner(UP+LEFT))),
|
||||||
|
randy.change_mode, "sad"
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
Write(domains, run_time = 5, lag_factor = 5),
|
||||||
|
randy.look_at, domains
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(Blink(randy))
|
||||||
|
self.play(
|
||||||
|
randy.change_mode, "hooray",
|
||||||
|
randy.look_at, logo_dot,
|
||||||
|
FadeOut(domains)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
Write(whois),
|
||||||
|
randy.change_mode, "confused",
|
||||||
|
randy.look_at, whois
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
self.play(randy.change_mode, "sassy")
|
||||||
|
self.dither(2)
|
||||||
|
self.play(
|
||||||
|
randy.change_mode, "happy",
|
||||||
|
randy.look_at, logo_dot
|
||||||
|
)
|
||||||
|
self.play(Blink(randy))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
class ShiftingLoopPairSurface(Scene):
|
class ShiftingLoopPairSurface(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class ThumbnailImage(ClosedLoopScene):
|
||||||
|
def construct(self):
|
||||||
|
self.add_rect_dots(square = True)
|
||||||
|
for dot in self.dots:
|
||||||
|
dot.scale_in_place(1.5)
|
||||||
|
self.add_connecting_lines(cyclic = True)
|
||||||
|
self.connecting_lines.set_stroke(width = 10)
|
||||||
|
self.loop.add(self.connecting_lines, self.dots)
|
||||||
|
|
||||||
|
title = TextMobject("Unsolved")
|
||||||
|
title.scale(2.5)
|
||||||
|
title.to_edge(UP)
|
||||||
|
title.gradient_highlight(YELLOW, MAROON_B)
|
||||||
|
self.add(title)
|
||||||
|
self.loop.next_to(title, DOWN, buff = MED_BUFF)
|
||||||
|
self.loop.shift(2*LEFT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue