Whoa boy, I've gotta get better about my commits...

This commit is contained in:
Grant Sanderson
2016-11-07 11:05:41 -08:00
parent ed3d64c614
commit c7239a035c
18 changed files with 610 additions and 190 deletions

View File

@ -106,7 +106,8 @@ class MoveAlongPath(Animation):
class Homotopy(Animation):
CONFIG = {
"run_time" : 3
"run_time" : 3,
"apply_function_kwargs" : {},
}
def __init__(self, homotopy, mobject, **kwargs):
"""
@ -120,7 +121,10 @@ class Homotopy(Animation):
def update_submobject(self, submob, start, alpha):
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):
Animation.update_mobject(self, alpha)

View File

@ -1,8 +1,8 @@
import os
import numpy as np
DEFAULT_HEIGHT = 1080
DEFAULT_WIDTH = 1920
DEFAULT_HEIGHT = 1080*2
DEFAULT_WIDTH = 1920*2
DEFAULT_FRAME_DURATION = 0.04
#There might be other configuration than pixel_shape later...

0
eoc/__init__.py Normal file
View File

277
eoc/chapter1.py Normal file
View 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()

View File

@ -9,27 +9,31 @@ class SVGMobject(VMobject):
CONFIG = {
"initial_scale_factor" : 1,
"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())
self.ensure_valid_file()
VMobject.__init__(self, **kwargs)
self.move_into_position()
def ensure_valid_file(self):
if self.file_name is None:
raise Exception("Must specify file for SVGMobject")
possible_paths = [
self.svg_file,
os.path.join(IMAGE_DIR, self.svg_file),
os.path.join(IMAGE_DIR, self.svg_file + ".svg"),
self.file_name,
os.path.join(IMAGE_DIR, self.file_name),
os.path.join(IMAGE_DIR, self.file_name + ".svg"),
]
for path in possible_paths:
if os.path.exists(path):
self.svg_file = path
self.file_name = path
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):
doc = minidom.parse(self.svg_file)
doc = minidom.parse(self.file_name)
self.ref_to_element = {}
for svg in doc.getElementsByTagName("svg"):
self.add(*self.get_mobjects_from(svg))

View File

@ -47,9 +47,12 @@ class TexMobject(SVGMobject):
self.args = args[0]
##
assert(all([isinstance(a, str) for a in self.args]))
self.tex_string = self.get_modified_expression()
VMobject.__init__(self, **kwargs)
self.move_into_position()
self.tex_string = self.get_modified_expression()
file_name = tex_to_svg_file(
self.tex_string,
self.template_tex_file
)
SVGMobject.__init__(self, file_name = file_name, **kwargs)
if self.organize_left_to_right:
self.organize_submobjects_left_to_right()
@ -61,10 +64,6 @@ class TexMobject(SVGMobject):
def generate_points(self):
self.svg_file = tex_to_svg_file(
self.tex_string,
self.template_tex_file
)
SVGMobject.generate_points(self)
if len(self.args) > 1:
self.handle_multiple_args()

View File

@ -115,7 +115,7 @@ class EigenThingsArentAllThatBad(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Eigen-things aren't \\\\ actually so bad",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.change_student_modes(
"pondering", "pondering", "erm"
@ -496,7 +496,7 @@ class CanEigenvaluesBeNegative(TeacherStudentsScene):
def construct(self):
self.student_says("Can eigenvalues be negative?")
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()
class EigenvalueNegativeOneHalf(LinearTransformationScene):
@ -659,7 +659,7 @@ class WordsOnComputation(TeacherStudentsScene):
self.teacher_says(
"I won't cover the full\\\\",
"details of computation...",
pi_creature_target_mode = "guilty"
target_mode = "guilty"
)
self.change_student_modes("angry", "sassy", "angry")
self.random_blink()

View File

@ -1427,7 +1427,7 @@ class ProposeDerivativeAsMatrix(TeacherStudentsScene):
derivative with
a matrix
""",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.random_blink()
self.change_student_modes("pondering", "confused", "erm")
@ -1975,7 +1975,7 @@ class BackToTheQuestion(TeacherStudentsScene):
this relate to what vectors
really are?
""",
pi_creature_target_mode = "confused"
target_mode = "confused"
)
self.random_blink(2)
self.teacher_says(
@ -2435,7 +2435,7 @@ class TextbooksAreAbstract(TeacherStudentsScene):
All the textbooks I found
are pretty abstract.
""",
pi_creature_target_mode = "pleading"
target_mode = "pleading"
)
self.random_blink(3)
self.teacher_says(
@ -2456,7 +2456,7 @@ class TextbooksAreAbstract(TeacherStudentsScene):
self.teacher_says(
"Only then should you\\\\",
"think from the axioms",
pi_creature_target_mode = "surprised"
target_mode = "surprised"
)
self.change_student_modes(*["pondering"]*3)
self.random_blink()
@ -2465,7 +2465,7 @@ class LastAskWhatAreVectors(TeacherStudentsScene):
def construct(self):
self.student_says(
"So...what are vectors?",
pi_creature_target_mode = "erm"
target_mode = "erm"
)
self.random_blink()
self.teacher_says(
@ -2559,7 +2559,7 @@ class GoodLuck(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Good luck with \\\\ your future learning!",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.change_student_modes(*["happy"]*3)
self.random_blink(3)

View File

@ -70,12 +70,12 @@ class NoComputations(TeacherStudentsScene):
self.setup()
self.student_says(
"Will you cover \\\\ computations?",
pi_creature_target_mode = "raise_left_hand"
target_mode = "raise_left_hand"
)
self.random_blink()
self.teacher_says(
"Well...uh...no",
pi_creature_target_mode = "guilty",
target_mode = "guilty",
)
self.play(*[
ApplyMethod(student.change_mode, mode)
@ -2037,7 +2037,7 @@ class WhatAboutNonsquareMatrices(TeacherStudentsScene):
def construct(self):
self.student_says(
"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.random_blink(6)

View File

@ -523,7 +523,7 @@ class AskAboutSymmetry(TeacherStudentsScene):
VMobject(question[3], question[5]).highlight(W_COLOR)
self.student_says(
question,
pi_creature_target_mode = "raise_left_hand"
target_mode = "raise_left_hand"
)
self.change_student_modes("confused")
self.play(self.get_teacher().change_mode, "pondering")
@ -673,7 +673,7 @@ class LurkingQuestion(TeacherStudentsScene):
# two views connected?
# """,
# student_index = 2,
# pi_creature_target_mode = "raise_left_hand",
# target_mode = "raise_left_hand",
# width = 6,
# )
self.change_student_modes(
@ -1347,7 +1347,7 @@ class WhatAboutTheGeometricView(TeacherStudentsScene):
What does this association
mean geometrically?
""",
pi_creature_target_mode = "raise_right_hand"
target_mode = "raise_right_hand"
)
self.change_student_modes("pondering", "raise_right_hand", "pondering")
self.random_blink(2)
@ -1897,7 +1897,7 @@ class AskAboutNonUnitVectors(TeacherStudentsScene):
def construct(self):
self.student_says(
"What about \\\\ non-unit vectors",
pi_creature_target_mode = "raise_left_hand"
target_mode = "raise_left_hand"
)
self.random_blink(2)
@ -2124,7 +2124,7 @@ class IsntThisBeautiful(TeacherStudentsScene):
self.teacher.look(DOWN+LEFT)
self.teacher_says(
"Isn't this", "beautiful",
pi_creature_target_mode = "surprised"
target_mode = "surprised"
)
for student in self.get_students():
self.play(student.change_mode, "happy")

View File

@ -69,7 +69,7 @@ class DoTheSameForCross(TeacherStudentsScene):
def construct(self):
words = TextMobject("Let's do the same \\\\ for", "cross products")
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.change_student_modes("pondering")
self.random_blink()
@ -429,7 +429,7 @@ class HowDoYouCompute(TeacherStudentsScene):
def construct(self):
self.student_says(
"How do you \\\\ compute this?",
pi_creature_target_mode = "raise_left_hand"
target_mode = "raise_left_hand"
)
self.random_blink(2)
@ -1478,7 +1478,7 @@ class ThisGetsWeird(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"This gets weird...",
pi_creature_target_mode = "sassy"
target_mode = "sassy"
)
self.random_blink(2)
@ -1639,7 +1639,7 @@ class ThereIsAReason(TeacherStudentsScene):
"reason", "for doing it"
)
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(
"raise_right_hand", "confused", "raise_left_hand"
)
@ -1649,7 +1649,7 @@ class RememberDuality(TeacherStudentsScene):
def construct(self):
words = TextMobject("Remember ", "duality", "?", arg_separator = "")
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)
class NextVideo(Scene):

View File

@ -201,7 +201,7 @@ class DualityReview(TeacherStudentsScene):
def construct(self):
words = TextMobject("Quick", "duality", "review")
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.random_blink(2)
@ -785,7 +785,7 @@ class WhyAreWeDoingThis(TeacherStudentsScene):
def construct(self):
self.student_says(
"Um...why are \\\\ we doing this?",
pi_creature_target_mode = "confused"
target_mode = "confused"
)
self.random_blink()
self.play(self.get_teacher().change_mode, "erm")

View File

@ -812,7 +812,7 @@ class AskAboutTranslation(TeacherStudentsScene):
def construct(self):
self.student_says(
"\\centering How do you translate \\\\ between coordinate systems?",
pi_creature_target_mode = "raise_right_hand"
target_mode = "raise_right_hand"
)
self.random_blink(3)

View File

@ -47,7 +47,7 @@ class AnotherFootnote(TeacherStudentsScene):
self.teacher.look(LEFT)
self.teacher_says(
"More footnotes!",
pi_creature_target_mode = "surprised",
target_mode = "surprised",
run_time = 1
)
self.random_blink(2)

View File

@ -352,7 +352,6 @@ class ClassWatching(TeacherStudentsScene):
self.play(self.get_teacher().change_mode, "pondering")
self.random_blink(3)
class RandolphWatching(Scene):
def construct(self):
randy = Randolph()
@ -464,7 +463,7 @@ class GrowRonaksSierpinski(Scene):
for n in range(n_layers):
ronaks_sierpinski.add(self.get_lines_at_layer(n))
ronaks_sierpinski.gradient_highlight(*self.colors)
ronaks_sierpinski.set_stroke(width = 3)
ronaks_sierpinski.set_stroke(width = 0)##TODO
return ronaks_sierpinski
def get_dots(self, n_layers):
@ -747,7 +746,7 @@ class EndScreen(TeacherStudentsScene):
See you every
other friday!
""",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.change_student_modes(*["happy"]*3)
self.random_blink()

View File

@ -5,6 +5,8 @@ from mobject.svg_mobject import SVGMobject
from mobject.vectorized_mobject import VMobject, VGroup
from mobject.tex_mobject import TextMobject, TexMobject
from topics.objects import Bubble, ThoughtBubble, SpeechBubble
from animation import Animation
from animation.transform import Transform, ApplyMethod, \
FadeOut, FadeIn, ApplyPointwiseFunction
@ -41,7 +43,7 @@ class PiCreature(SVGMobject):
"PiCreatures_%s.svg"%mode
)
digest_config(self, kwargs, locals())
SVGMobject.__init__(self, svg_file, **kwargs)
SVGMobject.__init__(self, file_name = svg_file, **kwargs)
self.init_colors()
if self.flip_at_start:
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):
CONFIG = {
"randy_kwargs" : {},
@ -384,6 +264,7 @@ class TeacherStudentsScene(Scene):
**bubble_kwargs):
bubble = pi_creature.get_bubble(bubble_type, **bubble_kwargs)
bubble.add_content(content)
bubble.resize_to_content()
if pi_creature.bubble:
content_intro_anims = [
Transform(pi_creature.bubble, bubble),
@ -398,7 +279,7 @@ class TeacherStudentsScene(Scene):
return content_intro_anims
def introduce_bubble(self, content, bubble_type, pi_creature,
pi_creature_target_mode = None,
target_mode = None,
added_anims = [],
**bubble_kwargs):
if all(map(lambda s : isinstance(s, str), content)):
@ -411,11 +292,11 @@ class TeacherStudentsScene(Scene):
content, bubble_type, pi_creature, **bubble_kwargs
)
if not pi_creature_target_mode:
if not target_mode:
if bubble_type is "speech":
pi_creature_target_mode = "speaking"
target_mode = "speaking"
else:
pi_creature_target_mode = "pondering"
target_mode = "pondering"
for p in self.get_everyone():
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 + [
ApplyMethod(
pi_creature.change_mode,
pi_creature_target_mode,
target_mode,
),
]
self.play(*anims)
@ -441,12 +322,12 @@ class TeacherStudentsScene(Scene):
)
def student_says(self, *content, **kwargs):
if "pi_creature_target_mode" not in kwargs:
if "target_mode" not in kwargs:
target_mode = random.choice([
"raise_right_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)]
return self.introduce_bubble(content, "speech", student, **kwargs)

164
topics/objects.py Normal file
View 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

118
wcat.py
View File

@ -17,6 +17,7 @@ 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 *
@ -254,7 +255,7 @@ class Introduction(TeacherStudentsScene):
self.random_blink(3)
self.teacher_says(
"Here's why \\\\ I'm excited...",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
for pi in self.get_students():
pi.target.look_at(self.get_teacher().eyes)
@ -279,7 +280,7 @@ class WhenIWasAKid(TeacherStudentsScene):
Here's why
I'm excited!
""",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.change_student_modes(*["happy"]*3)
self.dither()
@ -310,7 +311,7 @@ class WhenIWasAKid(TeacherStudentsScene):
Math! Excitement!
You are the future!
""",
pi_creature_target_mode = "hooray"
target_mode = "hooray"
)
self.play(
pi1.look_at, pi2.eyes,
@ -352,7 +353,7 @@ class WhenIWasAKid(TeacherStudentsScene):
self.student_says(
"How is this math?",
student_index = -1,
pi_creature_target_mode = "pleading",
target_mode = "pleading",
width = 5,
height = 3,
direction = RIGHT
@ -1891,7 +1892,7 @@ class ThatsTheProof(TeacherStudentsScene):
Bada boom
bada bang!
""",
pi_creature_target_mode = "hooray",
target_mode = "hooray",
width = 4
)
self.change_student_modes(*["hooray"]*3)
@ -1905,7 +1906,7 @@ class ThatsTheProof(TeacherStudentsScene):
the mobius strip
fact...
""",
pi_creature_target_mode = "guilty",
target_mode = "guilty",
width = 4,
)
self.random_blink()
@ -1949,6 +1950,7 @@ class PatreonThanks(Scene):
"Loo Yu Jun",
"Tom",
"Othman Alikhan",
"Juan Batiz-Benet",
"Markus Persson",
"Joseph John Cox",
"Achille Brighton",
@ -1981,14 +1983,19 @@ class PatreonThanks(Scene):
self.play(morty.change_mode, "gracious")
self.play(Write(special_thanks, run_time = 1))
self.play(Write(left_patrons))
self.play(Write(right_patrons))
self.play(
Write(left_patrons),
morty.look_at, left_patrons
)
self.play(
Write(right_patrons),
morty.look_at, right_patrons
)
self.play(Blink(morty))
self.play(morty.look_at, left_patrons)
self.dither()
self.play(morty.look_at, right_patrons)
self.play(Blink(morty))
for patrons in left_patrons, right_patrons:
for index in 0, -1:
self.play(morty.look_at, patrons[index])
self.dither()
class CreditTWo(Scene):
def construct(self):
@ -2033,11 +2040,96 @@ class CreditTWo(Scene):
self.play(Blink(morty))
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):
def construct(self):
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)