PiCreatureScene and TeacherStudentScene refactors

This commit is contained in:
Grant Sanderson 2017-02-14 14:00:50 -08:00
parent ef47e6e884
commit 899a911e08
20 changed files with 359 additions and 237 deletions

View file

@ -334,7 +334,6 @@ class AnimationGroup(Animation):
for anim in sub_anims:
#Use np.divide to that 1./0 = np.inf
anim.alpha_multiplier = np.divide(max_run_time, anim.run_time)
if "run_time" in kwargs:
self.run_time = kwargs.pop("run_time")
else:

View file

@ -47,7 +47,6 @@ class Transform(Animation):
self.path_arc,
self.path_arc_axis,
)
def get_all_mobjects(self):
return self.mobject, self.starting_mobject, self.target_mobject
@ -154,9 +153,6 @@ class FadeIn(Transform):
target = mobject.copy()
Transform.__init__(self, mobject, target, **kwargs)
self.starting_mobject.fade(1)
if isinstance(self.starting_mobject, VMobject):
self.starting_mobject.set_stroke(width = 0)
self.starting_mobject.set_fill(opacity = 0)
class ShimmerIn(DelayByOrder):

View file

@ -63,13 +63,13 @@ class CircleScene(PiCreatureScene):
self.radius_brace, self.radius_label
)
self.pi_creature = self.get_pi_creature()
self.pi_creature = self.create_pi_creature()
if self.include_pi_creature:
self.add(self.pi_creature)
else:
self.pi_creature.set_fill(opacity = 0)
def get_pi_creature(self):
def create_pi_creature(self):
return Mortimer().to_corner(DOWN+RIGHT)
def introduce_circle(self, added_anims = []):
@ -240,17 +240,19 @@ class OpeningQuote(Scene):
"highlighted_quote_terms" : {
"special case" : BLUE
},
"author" : "David Hilbert"
"author" : "David Hilbert",
"fade_in_kwargs" : {
"submobject_mode" : "lagged_start",
"rate_func" : None,
"lag_factor" : 3,
"run_time" : 5,
},
}
def construct(self):
quote = self.get_quote()
author = self.get_author(quote)
self.play(FadeIn(
quote,
submobject_mode = "lagged_start",
run_time = 4
))
self.play(FadeIn(quote, **self.fade_in_kwargs))
self.dither(2)
self.play(Write(author, run_time = 3))
self.dither()
@ -322,7 +324,7 @@ class Introduction(TeacherStudentsScene):
lambda p : p.change_mode("hooray").look_at(series[1]),
pi
)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
def homotopy(x, y, z, t):
@ -336,7 +338,7 @@ class Introduction(TeacherStudentsScene):
),
*[
ApplyMethod(pi.look_at, series[-1])
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
],
run_time = 5
)
@ -345,13 +347,13 @@ class Introduction(TeacherStudentsScene):
FadeOut(self.teacher.bubble.content),
*[
ApplyMethod(pi.change_mode, "happy")
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
def look_to_center(self):
anims = []
for pi in self.get_everyone():
for pi in self.get_pi_creatures():
anims += [
pi.change_mode, "pondering",
pi.look_at, 2*UP
@ -360,7 +362,7 @@ class Introduction(TeacherStudentsScene):
self.random_blink(6)
self.play(*[
ApplyMethod(pi.change_mode, "happy")
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
])
def go_through_students(self):
@ -846,7 +848,7 @@ class IntroduceTinyChangeInArea(CircleScene):
self.play(FadeIn(rect))
self.dither()
def get_pi_creature(self):
def create_pi_creature(self):
morty = Mortimer()
morty.scale(0.7)
morty.to_corner(DOWN+RIGHT)
@ -872,7 +874,7 @@ class BuildToDADR(CircleScene):
self.elaborate_on_d()
self.not_infinitely_small()
def get_pi_creature(self):
def create_pi_creature(self):
morty = Mortimer()
morty.flip()
morty.to_corner(DOWN+LEFT)
@ -1212,7 +1214,7 @@ class BuildToDADR(CircleScene):
self.play(self.pi_creature.change_mode, "guilty")
self.dither()
new_bubble = self.pi_creature.get_bubble("speech")
new_bubble = self.pi_creature.get_bubble(SpeechBubble)
new_bubble.set_fill(BLACK, opacity = 0.8)
new_bubble.write("But it gets \\\\ less wrong!")
new_bubble.resize_to_content()
@ -1682,7 +1684,7 @@ class DerivativeAsTangentLine(ZoomedScene):
morty = Mortimer()
morty.scale(0.7)
morty.to_edge(DOWN).shift(2*RIGHT)
bubble = morty.get_bubble("speech", height = 2)
bubble = morty.get_bubble(SpeechBubble, height = 2)
bubble.set_fill(BLACK, opacity = 0.8)
bubble.shift(0.5*DOWN)
bubble.write("This is the standard view")
@ -1747,7 +1749,7 @@ class IntroduceConcentricRings(CircleScene):
self.write_integral()
self.ask_about_approx()
def get_pi_creature(self):
def create_pi_creature(self):
morty = Mortimer()
morty.scale(0.7)
morty.to_corner(DOWN+RIGHT)
@ -2306,7 +2308,7 @@ class FundamentalTheorem(CircleScene):
self.radius_label,
)
def get_pi_creature(self):
def create_pi_creature(self):
morty = Mortimer()
morty.scale(0.7)
morty.to_corner(DOWN+RIGHT)
@ -2481,7 +2483,7 @@ class NameTheFundamentalTheorem(TeacherStudentsScene):
Write(abstract),
*[
ApplyMethod(pi.look_at, symbols)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.change_student_modes("pondering", "confused", "erm")

View file

@ -223,7 +223,7 @@ class Introduction(TeacherStudentsScene):
pi.change_mode, mode,
pi.look_at, SPACE_HEIGHT*UP
]
for pi, mode in zip(self.get_everyone(), [
for pi, mode in zip(self.get_pi_creatures(), [
"speaking", "pondering", "confused", "confused",
])
])

View file

@ -1901,8 +1901,8 @@ class OneOverX(PiCreatureScene, GraphScene):
########
def get_pi_creature(self):
morty = PiCreatureScene.get_pi_creature(self)
def create_pi_creature(self):
morty = PiCreatureScene.create_pi_creature(self)
morty.scale(
self.morty_scale_val,
about_point = morty.get_corner(DOWN+RIGHT)
@ -2718,7 +2718,7 @@ class NextVideo(TeacherStudentsScene):
group = VGroup(d_sum, d_product, d_composition)
group.arrange_submobjects(RIGHT, buff = 2*LARGE_BUFF)
group.next_to(VGroup(*self.get_everyone()), UP, buff = LARGE_BUFF)
group.next_to(VGroup(*self.get_pi_creatures()), UP, buff = LARGE_BUFF)
self.play(
FadeIn(
@ -2728,7 +2728,7 @@ class NextVideo(TeacherStudentsScene):
),
*[
ApplyMethod(pi.look_at, next_video)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.play(
@ -2741,7 +2741,7 @@ class NextVideo(TeacherStudentsScene):
Write(mob, run_time = 1),
*[
ApplyMethod(pi.look_at, mob)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.dither(3)

99
eoc/chapter4.py Normal file
View file

@ -0,0 +1,99 @@
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 scene.zoomed_scene import ZoomedScene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from eoc.chapter1 import OpeningQuote, PatreonThanks
from eoc.graph_scene import *
class Chapter3OpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"Using the chain rule is like peeling an onion: ",
"you have to deal with each layer at a time, and ",
"if it is too big you will start crying."
],
"author" : "(Anonymous professor)"
}
class TransitionFromLastVideo(TeacherStudentsScene):
def construct(self):
rules = power_rule, sine_rule, exp_rule = VGroup(*[
TexMobject("\\frac{d(x^3)}{dx} = 3x^2"),
TexMobject("\\frac{d(\\sin(x))}{dx} = \\cos(x)"),
TexMobject("\\frac{d(e^x)}{dx} = e^x"),
])
rules.arrange_submobjects(buff = LARGE_BUFF)
rules.next_to(self.get_teacher(), UP, buff = MED_LARGE_BUFF)
rules.to_edge(LEFT)
self.add(rules)

View file

@ -1018,14 +1018,14 @@ class MentionGenerality(TeacherStudentsScene, ThreeDScene):
Write(arrow),
*[
ApplyMethod(pi.look_at, arrow)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.change_student_modes("pondering", "erm", "confused")
self.dither()
self.play(*[
ApplyMethod(pi.look_at, arrow)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
])
self.play(Write(formula))
self.dither(3)
@ -2297,7 +2297,7 @@ class ExclaimBorsukUlam(TeacherStudentsScene):
)
self.play(*[
ApplyMethod(pi.change_mode, "hooray")
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
])
self.dither(3)

View file

@ -794,7 +794,7 @@ class ProfessorsTry(Scene):
morty = Mortimer()
morty.to_corner(DOWN+RIGHT)
morty.shift(3*LEFT)
speech_bubble = morty.get_bubble("speech", height = 4, width = 8)
speech_bubble = morty.get_bubble(SpeechBubble, height = 4, width = 8)
speech_bubble.shift(RIGHT)
words = TextMobject(
"It really is beautiful! I want you to \\\\" + \
@ -922,7 +922,7 @@ class ResourceForTeachers(Scene):
def construct(self):
morty = Mortimer(mode = "speaking")
morty.to_corner(DOWN + RIGHT)
bubble = morty.get_bubble("speech")
bubble = morty.get_bubble(SpeechBubble)
bubble.write("I'm assuming you \\\\ know linear algebra\\dots")
words = bubble.content
bubble.clear()

View file

@ -430,7 +430,7 @@ class HelpsToHaveOneThought(Scene):
randys.to_corner(DOWN+LEFT)
randy = randys.split()[1]
speech_bubble = morty.get_bubble("speech")
speech_bubble = morty.get_bubble(SpeechBubble)
words = TextMobject("Think of some vector...")
speech_bubble.position_mobject_inside(words)
thought_bubble = randy.get_bubble()
@ -1119,8 +1119,8 @@ class ItDoesntMatterWhich(Scene):
for pi in physy, compy:
pi.next_to(pi.title, UP)
self.add(pi, pi.title)
compy_speech = compy.get_bubble("speech")
physy_speech = physy.get_bubble("speech")
compy_speech = compy.get_bubble(SpeechBubble)
physy_speech = physy.get_bubble(SpeechBubble)
arrow = Vector([2, 1])
array = matrix_to_mobject([2, 1])
goes_to = TexMobject("\\Rightarrow")

View file

@ -62,7 +62,7 @@ class StudentsFindThisConfusing(TeacherStudentsScene):
Write(title),
*[
ApplyMethod(pi.look_at, title)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.play(
@ -608,7 +608,7 @@ class ContrastMatrixUnderstandingWithEigenvalue(TeacherStudentsScene):
for mob in axis_and_rotation, matrix:
mob.to_corner(UP+RIGHT)
everyone = self.get_everyone()
everyone = self.get_pi_creatures()
self.play(
Write(axis_and_rotation),
*it.chain(*zip(
@ -752,7 +752,7 @@ class SymbolicEigenvectors(Scene):
morty = Mortimer().to_edge(DOWN)
morty.change_mode("speaking")
bubble = morty.get_bubble("speech", width = 5, direction = LEFT)
bubble = morty.get_bubble(SpeechBubble, width = 5, direction = LEFT)
VGroup(morty, bubble).to_edge(RIGHT)
solve_text = TextMobject(
"Solve for \\\\",
@ -955,7 +955,7 @@ class SymbolicEigenvectors(Scene):
randy = Randolph(mode = "speaking").to_edge(DOWN)
randy.flip()
randy.look_at(self.expression)
bubble = randy.get_bubble("speech", direction = LEFT, width = 5)
bubble = randy.get_bubble(SpeechBubble, direction = LEFT, width = 5)
words = TextMobject("We need")
equation = TexMobject(
"\\det(A-", "\\lambda", "I)", "=0"

View file

@ -202,7 +202,7 @@ class WhatIsA2DVector(LinearTransformationScene):
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 = cs_student.get_bubble(SpeechBubble, width = 4, height = 3)
bubble.set_fill(BLACK, opacity = 1)
bubble.next_to(cs_student, UP+LEFT)
bubble.write("Consider higher \\\\ dimensions")
@ -293,7 +293,7 @@ class AskAbout4DPhysicsStudent(Scene):
compy = CSStudent().to_edge(DOWN).shift(2*RIGHT)
for pi1, pi2 in (physy, compy), (compy, physy):
pi1.look_at(pi2.eyes)
physy.bubble = physy.get_bubble("speech", width = 5, height = 4.5)
physy.bubble = physy.get_bubble(SpeechBubble, width = 5, height = 4.5)
line = Line(LEFT, RIGHT, color = BLUE_B)
square = Square(color = BLUE_C)
@ -541,7 +541,7 @@ class WhatIsSpace(Scene):
physy.bubble = get_small_bubble(physy)
vector = Vector([1, 2])
physy.bubble.add_content(vector)
compy.bubble = compy.get_bubble("speech", width = 6, height = 4)
compy.bubble = compy.get_bubble(SpeechBubble, width = 6, height = 4)
compy.bubble.set_fill(BLACK, opacity = 1)
compy.bubble.write("What exactly do\\\\ you mean by ``space''?")
@ -1017,7 +1017,7 @@ class TransformationsAndOperators(TeacherStudentsScene):
""", student_index = 0)
self.random_blink()
teacher = self.get_teacher()
bubble = teacher.get_bubble("speech", height = 2, width = 2)
bubble = teacher.get_bubble(SpeechBubble, height = 2, width = 2)
bubble.set_fill(BLACK, opacity = 1)
bubble.write("Yup!")
self.play(
@ -1280,7 +1280,7 @@ class FormalDefinitionOfLinear(LinearTransformationScene):
def add_words(self):
randy = Randolph().shift(LEFT).to_edge(DOWN)
bubble = randy.get_bubble("speech", width = 6, height = 4)
bubble = randy.get_bubble(SpeechBubble, width = 6, height = 4)
bubble.set_fill(BLACK, opacity = 0.8)
bubble.shift(0.5*DOWN)
VGroup(randy, bubble).to_edge(RIGHT, buff = 0)
@ -1901,7 +1901,7 @@ class MatrixVectorMultiplicationAndDerivative(TeacherStudentsScene):
arrow.highlight(BLACK)
teacher = self.get_teacher()
bubble = teacher.get_bubble("speech", height = 4)
bubble = teacher.get_bubble(SpeechBubble, height = 4)
bubble.add_content(group)
self.play(
@ -2146,7 +2146,7 @@ class MathematicianSpeakingToAll(Scene):
others.scale(0.8)
others.to_corner(DOWN+RIGHT)
bubble = mathy.get_bubble("speech")
bubble = mathy.get_bubble(SpeechBubble)
bubble.write("""
I don't want to think
about all y'all's crazy
@ -2162,7 +2162,7 @@ class MathematicianSpeakingToAll(Scene):
)
self.play(Blink(others[3]))
self.dither()
thought_bubble = mathy.get_bubble("thought")
thought_bubble = mathy.get_bubble(ThoughtBubble)
self.play(
FadeOut(bubble.content),
Transform(bubble, thought_bubble),
@ -2408,7 +2408,7 @@ class VectorSpaceOfPiCreatures(Scene):
class MathematicianDoesntHaveToThinkAboutThat(Scene):
def construct(self):
mathy = Mathematician().to_corner(DOWN+LEFT)
bubble = mathy.get_bubble("thought", height = 4)
bubble = mathy.get_bubble(ThoughtBubble, height = 4)
words = TextMobject("I don't have to worry", "\\\\ about that madness!")
bubble.add_content(words)
new_words = TextMobject("So long as I", "\\\\ work abstractly")

View file

@ -651,7 +651,7 @@ class SpeakingDifferentLanguages(JenniferScene):
jenny.coords = Matrix(["5/3", "1/3"])
jenny.text = TextMobject("Non, c'est")
for pi in jenny, you:
pi.bubble = pi.get_bubble("speech", width = 4.5, height = 3.5)
pi.bubble = pi.get_bubble(SpeechBubble, width = 4.5, height = 3.5)
if pi is you:
pi.bubble.shift(MED_SMALL_BUFF*RIGHT)
else:
@ -720,7 +720,7 @@ class JennysGrid(JenniferScene):
def construct(self):
self.add(self.jenny)
self.jenny.shift(3*RIGHT)
bubble = self.jenny.get_bubble("speech", width = 4)
bubble = self.jenny.get_bubble(SpeechBubble, width = 4)
bubble.flip()
bubble.set_fill(BLACK, opacity = 0.8)
bubble.to_edge(LEFT)

View file

@ -102,7 +102,7 @@ class Chapter9(Scene):
you.coords = Matrix([3, 2])
jenny.coords = Matrix(["5/3", "1/3"])
for pi in jenny, you:
pi.bubble = pi.get_bubble("speech", width = 3, height = 3)
pi.bubble = pi.get_bubble(SpeechBubble, width = 3, height = 3)
if pi is you:
pi.bubble.shift(MED_SMALL_BUFF*RIGHT)
else:

View file

@ -174,7 +174,7 @@ class WhatAreFractals(TeacherStudentsScene):
FadeIn(picture),
*[
ApplyMethod(pi.look_at, name)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]
)
self.dither(2)
@ -2337,7 +2337,7 @@ class DefineFractal(TeacherStudentsScene):
self.change_student_modes(*["pondering"]*3)
self.play(*[
ApplyMethod(pi.look, DOWN)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
])
self.dither(3)

View file

@ -541,7 +541,7 @@ class IntroduceKeith(Scene):
randy = Randolph().next_to(keith, LEFT, LARGE_BUFF, aligned_edge = DOWN)
randy.shift_onto_screen()
bubble = keith.get_bubble("speech", width = 7)
bubble = keith.get_bubble(SpeechBubble, width = 7)
bubble.write("01101011 $\\Rightarrow$ Towers of Hanoi")
zero_width = bubble.content[0].get_width()
one_width = bubble.content[1].get_width()
@ -555,7 +555,7 @@ class IntroduceKeith(Scene):
bubble.pin_to(keith)
VGroup(bubble, bubble.content).shift(DOWN)
randy.bubble = randy.get_bubble("speech", height = 3)
randy.bubble = randy.get_bubble(SpeechBubble, height = 3)
randy.bubble.write("Wait, what's \\\\ Towers of Hanoi?")
title = TextMobject("Keith Schwarz (Computer scientist)")
@ -803,7 +803,7 @@ class KeithShowingBinary(Scene):
keith.next_to(morty, LEFT, buff = 2*LARGE_BUFF)
randy = Randolph()
randy.next_to(keith, LEFT, buff = 2*LARGE_BUFF)
randy.bubble = randy.get_bubble("speech")
randy.bubble = randy.get_bubble(SpeechBubble)
randy.bubble.set_fill(BLACK, opacity = 1)
randy.bubble.write("Hold on...how does \\\\ binary work again?")
@ -1053,7 +1053,7 @@ class IntroduceBinaryCounting(BinaryCountingScene):
def initial_counting(self):
randy = Randolph().to_corner(DOWN+LEFT)
bubble = randy.get_bubble("thought", height = 3.4, width = 5)
bubble = randy.get_bubble(ThoughtBubble, height = 3.4, width = 5)
bubble.write(
"Not ten, not ten \\\\",
"\\quad not ten, not ten..."
@ -1436,7 +1436,7 @@ class RecursionTime(Scene):
self.add(keith, morty)
bubble = keith.get_bubble("speech", height = 2)
bubble = keith.get_bubble(SpeechBubble, height = 2)
bubble.write("Recursion time!!!")
VGroup(bubble, bubble.content).shift(UP)
@ -1704,7 +1704,7 @@ class KeithSaysBigToSmall(Scene):
def construct(self):
keith = Keith()
keith.shift(2.5*DOWN + 3*LEFT)
bubble = keith.get_bubble("speech", height = 4.5)
bubble = keith.get_bubble(SpeechBubble, height = 4.5)
bubble.write("""
Big problem
$\\Downarrow$
@ -1730,7 +1730,7 @@ class CodeThisUp(Scene):
morty.shift(2*DOWN+3*RIGHT)
keith.make_eye_contact(morty)
point = 2*UP+3*RIGHT
bubble = keith.get_bubble("speech", width = 4.5, height = 3)
bubble = keith.get_bubble(SpeechBubble, width = 4.5, height = 3)
bubble.write("This is the \\\\ most efficient")
self.add(morty, keith)
@ -1772,7 +1772,7 @@ class NoRoomForInefficiency(Scene):
def construct(self):
morty = Mortimer().flip()
morty.shift(2.5*DOWN+3*LEFT)
bubble = morty.get_bubble("speech", width = 4)
bubble = morty.get_bubble(SpeechBubble, width = 4)
bubble.write("No room for \\\\ inefficiency")
VGroup(morty, bubble, bubble.content).to_corner(DOWN+RIGHT)
@ -1792,7 +1792,7 @@ class WhyDoesBinaryAchieveThis(Scene):
morty = Mortimer()
morty.shift(2*DOWN+3*RIGHT)
keith.make_eye_contact(morty)
bubble = morty.get_bubble("speech", width = 5, height = 3)
bubble = morty.get_bubble(SpeechBubble, width = 5, height = 3)
bubble.write("""
Why does counting
in binary work?
@ -1814,7 +1814,7 @@ class BothAreSelfSimilar(Scene):
def construct(self):
morty = Mortimer().flip()
morty.shift(2.5*DOWN+3*LEFT)
bubble = morty.get_bubble("speech")
bubble = morty.get_bubble(SpeechBubble)
bubble.write("Both are self-similar")
self.add(morty)
@ -2071,7 +2071,7 @@ class StillRecruse(Scene):
morty.shift(2*DOWN+3*RIGHT)
keith.make_eye_contact(morty)
point = 2*UP+3*RIGHT
bubble = keith.get_bubble("speech", width = 4.5, height = 3)
bubble = keith.get_bubble(SpeechBubble, width = 4.5, height = 3)
bubble.write("You can still\\\\ use recursion")
self.add(morty, keith)
@ -2693,7 +2693,7 @@ class KeithAsksAboutConfigurations(Scene):
keith = Keith().shift(2*DOWN+3*LEFT)
morty = Mortimer().shift(2*DOWN+3*RIGHT)
keith.make_eye_contact(morty)
bubble = keith.get_bubble("speech")
bubble = keith.get_bubble(SpeechBubble)
bubble.write("Think about how many \\\\ configurations there are.")
self.add(keith, morty)
@ -3237,7 +3237,7 @@ class MentionFinalAnimation(Scene):
def construct(self):
morty = Mortimer()
morty.shift(2*DOWN+3*RIGHT)
bubble = morty.get_bubble("speech", width = 6)
bubble = morty.get_bubble(SpeechBubble, width = 6)
bubble.write("Before the final\\\\ animation...")
self.add(morty)

View file

@ -529,7 +529,7 @@ class KindWordsOnEoLA(TeacherStudentsScene):
ShowCreation(rect),
*[
ApplyMethod(pi.look_at, rect)
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
],
run_time = 2
)

View file

@ -148,7 +148,7 @@ class ReactionsToTattoo(PiCreatureScene):
self.dither(2)
def get_pi_creature(self):
def create_pi_creature(self):
randy = Randolph()
randy.next_to(ORIGIN, DOWN)
return randy

View file

@ -413,11 +413,11 @@ class WhenIWasAKid(TeacherStudentsScene):
speaker.to_edge(RIGHT)
return speaker
def get_everyone(self):
def get_pi_creatures(self):
if hasattr(self, "everyone"):
return self.everyone
else:
return TeacherStudentsScene.get_everyone(self)
return TeacherStudentsScene.get_pi_creatures(self)
class FormingTheMobiusStrip(Scene):
def construct(self):
@ -1438,7 +1438,7 @@ class NotHelpful(Scene):
def construct(self):
morty = Mortimer()
morty.next_to(ORIGIN, DOWN)
bubble = morty.get_bubble("speech", width = 4, height = 3)
bubble = morty.get_bubble(SpeechBubble, width = 4, height = 3)
bubble.write("Not helpful!")
self.add(morty)

View file

@ -403,7 +403,7 @@ class WhyPeopleMayKnowIt(TeacherStudentsScene):
#Thoughts
self.play(*it.chain(*[
[pi.change_mode, "pondering", pi.look_at, func_mob]
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]))
self.random_blink()
self.student_thinks(
@ -425,7 +425,7 @@ class WhyPeopleMayKnowIt(TeacherStudentsScene):
self.random_blink()
self.play(*it.chain(*[
[pi.change_mode, "confused", pi.look_at, divergent_sum]
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
]))
self.dither()
self.random_blink()
@ -934,7 +934,7 @@ class IgnoreNegatives(TeacherStudentsScene):
Write(only_s_gt_1),
*it.chain(*[
[pi.look_at, definition]
for pi in self.get_everyone()
for pi in self.get_pi_creatures()
])
)
self.random_blink(3)
@ -1270,7 +1270,7 @@ class FromRealToComplex(ComplexTransformationScene):
morty = Mortimer().flip()
morty.scale(0.7)
morty.to_corner(DOWN+LEFT)
bubble = morty.get_bubble("speech", height = 4)
bubble = morty.get_bubble(SpeechBubble, height = 4)
bubble.set_fill(BLACK, opacity = 0.5)
bubble.write("""
How can we visualize
@ -1884,7 +1884,7 @@ class VisualizingSSquared(ComplexTransformationScene):
morty = Mortimer().flip()
morty.scale(0.7)
morty.to_corner(DOWN+LEFT)
bubble = morty.get_bubble("speech", height = 2, width = 4)
bubble = morty.get_bubble(SpeechBubble, height = 2, width = 4)
bubble.set_fill(BLACK, opacity = 0.9)
bubble.write("""
It all happens
@ -1945,7 +1945,7 @@ class ShowZetaOnHalfPlane(ZetaTransformationScene):
def react_to_transformation(self):
morty = Mortimer().flip()
morty.to_corner(DOWN+LEFT)
bubble = morty.get_bubble("speech")
bubble = morty.get_bubble(SpeechBubble)
bubble.set_fill(BLACK, 0.5)
bubble.write("\\emph{Damn}!")
bubble.resize_to_content()
@ -2332,7 +2332,7 @@ class IntroduceAnglePreservation(VisualizingSSquared):
morty.to_corner(DOWN+RIGHT)
randy.make_eye_contact(morty)
for pi, words in (randy, "$f'(s) = 2s$"), (morty, "Here's some \\\\ related geometry..."):
pi.bubble = pi.get_bubble("speech")
pi.bubble = pi.get_bubble(SpeechBubble)
pi.bubble.set_fill(BLACK, opacity = 0.7)
pi.bubble.write(words)
pi.bubble.resize_to_content()
@ -3290,7 +3290,7 @@ class InventingMathPreview(Scene):
class FinalAnimationTease(Scene):
def construct(self):
morty = Mortimer().shift(2*(DOWN+RIGHT))
bubble = morty.get_bubble("speech")
bubble = morty.get_bubble(SpeechBubble)
bubble.write("""
Want to know what
$\\zeta'(s)$ looks like?

View file

@ -82,19 +82,14 @@ class PiCreature(SVGMobject):
return self
def change_mode(self, mode):
curr_eye_center = self.eyes.get_center()
curr_height = self.get_height()
should_be_flipped = self.is_flipped()
should_look = hasattr(self, "purposeful_looking_direction")
if should_look:
looking_direction = self.purposeful_looking_direction
self.__init__(mode)
self.scale_to_fit_height(curr_height)
self.shift(curr_eye_center - self.eyes.get_center())
if should_be_flipped ^ self.is_flipped():
self.flip()
if should_look:
self.look(looking_direction)
new_self = self.__class__(mode = mode)
new_self.scale_to_fit_height(self.get_height())
new_self.shift(self.eyes.get_center() - new_self.eyes.get_center())
if self.is_flipped() ^ new_self.is_flipped():
new_self.flip()
if hasattr(self, "purposeful_looking_direction"):
new_self.look(self.purposeful_looking_direction)
Transform(self, new_self).update(1)
return self
def look(self, direction):
@ -151,15 +146,14 @@ class PiCreature(SVGMobject):
self.to_corner(DOWN+LEFT, **kwargs)
return self
def get_bubble(self, bubble_type = "thought", **kwargs):
#TODO, change bubble_type arg to have type Bubble
if bubble_type == "thought":
bubble = ThoughtBubble(**kwargs)
elif bubble_type == "speech":
bubble = SpeechBubble(**kwargs)
else:
raise Exception("%s is an invalid bubble type"%bubble_type)
def get_bubble(self, bubble_class = ThoughtBubble, **kwargs):
bubble = bubble_class(**kwargs)
if "content" in kwargs:
bubble.add_content(kwargs["content"])
if "height" not in kwargs and "width" not in kwargs:
bubble.resize_to_content()
bubble.pin_to(self)
self.bubble = bubble
return bubble
def make_eye_contact(self, pi_creature):
@ -233,9 +227,10 @@ class Blink(ApplyMethod):
ApplyMethod.__init__(self, pi_creature.blink, **kwargs)
class PiCreatureSays(AnimationGroup):
class PiCreatureBubbleIntroduction(AnimationGroup):
CONFIG = {
"target_mode" : "speaking",
"bubble_class" : SpeechBubble,
"change_mode_kwargs" : {},
"bubble_creation_kwargs" : {},
"bubble_kwargs" : {},
@ -244,12 +239,15 @@ class PiCreatureSays(AnimationGroup):
}
def __init__(self, pi_creature, *content, **kwargs):
digest_config(self, kwargs)
bubble = pi_creature.get_bubble("speech", **self.bubble_kwargs)
bubble.write(*content)
if "height" not in self.bubble_kwargs and "width" not in self.bubble_kwargs:
bubble.resize_to_content()
bubble.pin_to(pi_creature)
pi_creature.bubble = bubble
if isinstance(content, Mobject):
bubble_content = content
else:
bubble_content = TextMobject(*content)
bubble = pi_creature.get_bubble(
self.bubble_class,
content = bubble_content,
**self.bubble_kwargs
)
pi_creature.generate_target()
pi_creature.target.change_mode(self.target_mode)
@ -263,102 +261,203 @@ class PiCreatureSays(AnimationGroup):
Write(bubble.content, **self.write_kwargs),
**kwargs
)
class PiCreatureSays(PiCreatureBubbleIntroduction):
CONFIG = {
"target_mode" : "speaking",
"bubble_class" : SpeechBubble,
}
class RemovePiCreatureBubble(AnimationGroup):
CONFIG = {
"target_mode" : "plain"
}
def __init__(self, pi_creature, **kwargs):
assert hasattr(pi_creature, "bubble")
digest_config(self, kwargs, locals())
AnimationGroup.__init__(
self,
ApplyMethod(pi_creature.change_mode, self.target_mode),
FadeOut(pi_creature.bubble),
FadeOut(pi_creature.bubble.content),
)
def clean_up(self):
AnimationGroup.clean_up(self)
self.pi_creature.bubble = None
class PiCreatureScene(Scene):
CONFIG = {
"total_dither_time" : 0,
"use_morty" : True,
"seconds_to_blink" : 3,
}
def setup(self):
self.pi_creature = self.get_pi_creature()
self.add(self.pi_creature)
self.pi_creatures = VGroup(*self.create_pi_creatures())
self.add(self.pi_creatures)
def get_pi_creature(self):
if self.use_morty:
return Mortimer().to_corner(DOWN+RIGHT)
else:
return Randolph().to_corner(DOWN+LEFT)
def create_pi_creatures(self):
"""
Likely updated for subclasses
"""
return VGroup(self.create_pi_creature())
def say(self, *content, **kwargs):
added_anims = kwargs.get("added_anims", [])
if "target_mode" in kwargs:
target_mode = kwargs["target_mode"]
else:
target_mode = "speaking"
added_anims += [self.pi_creature.change_mode, target_mode]
def create_pi_creature(self):
return Mortimer().to_corner(DOWN+RIGHT)
def get_pi_creatures(self):
return self.pi_creatures
def get_primary_pi_creature(self):
return self.pi_creatures[0]
def introduce_bubble(
self,
pi_creature,
bubble_class,
content = None,
target_mode = None,
bubble_kwargs = None,
bubble_removal_kwargs = None,
added_anims = None,
**kwargs
):
content = content or []
if target_mode is None:
target_mode = "thinking" if bubble_class is ThoughtBubble else "speaking"
bubble_kwargs = bubble_kwargs or dict()
bubble_removal_kwargs = bubble_removal_kwargs or dict()
added_anims = added_anims or []
pi_creatures_with_bubbles = [
pi for pi in self.get_pi_creatures()
if pi is not pi_creature
if hasattr(pi, "bubble") and pi.bubble is not None
]
added_anims += [
RemovePiCreatureBubble(pi, **bubble_removal_kwargs)
for pi in pi_creatures_with_bubbles
]
self.play(
PiCreatureSays(self.pi_creature, *content, **kwargs),
*added_anims
PiCreatureBubbleIntroduction(
pi_creature,
*content,
bubble_class = bubble_class,
bubble_kwargs = bubble_kwargs,
target_mode = target_mode
),
*added_anims,
**kwargs
)
def get_bubble_fade_anims(self, target_mode = "plain"):
def pi_creature_says(self, pi_creature, *content, **kwargs):
self.introduce_bubble(
pi_creature,
bubble_class = SpeechBubble,
content = content,
**kwargs
)
def pi_creature_thinks(self, pi_creature, *content, **kwargs):
self.introduce_bubble(
pi_creature,
bubble_class = ThoughtBubble,
content = content,
**kwargs
)
def say(self, *content, **kwargs):
self.pi_creature_says(self.get_primary_pi_creature(), *content, **kwargs)
def think(self, *content, **kwargs):
self.pi_creature_thinks(self.get_primary_pi_creature(), *content, **kwargs)
def get_bubble_fade_anims(self, **kwargs):
return [
FadeOut(self.pi_creature.bubble),
FadeOut(self.pi_creature.bubble.content),
self.pi_creature.change_mode, target_mode
RemovePiCreatureBubble(pi_creature, **kwargs)
for pi_creature in self.get_pi_creatures()
if hasattr(pi_creature.bubble)
]
def compile_play_args_to_animation_list(self, *args):
"""
Add animations so that all pi creatures look at the
first mobject being animated with each .play call
"""
animations = Scene.compile_play_args_to_animation_list(self, *args)
if self.pi_creature not in self.get_mobjects():
return animations
if len(animations) == 0:
return animations
first_anim = animations[0]
if first_anim.mobject is self.pi_creature:
if isinstance(first_anim, Blink):
return animations
#Look at ending state
first_anim.update(1)
point_of_interest = first_anim.mobject.get_center()
first_anim.update(0)
last_anim = animations[-1]
if last_anim.mobject is self.pi_creature and isinstance(last_anim, Transform):
if isinstance(animations[-1], Transform):
animations[-1].target_mobject.look_at(point_of_interest)
return animations
new_anim = ApplyMethod(self.pi_creature.look_at, point_of_interest)
return list(animations) + [new_anim]
for pi_creature in self.get_pi_creatures():
if pi_creature not in self.get_mobjects():
continue
if pi_creature in first_anim.mobject.submobject_family():
continue
anims_with_pi_creature = [
anim for anim in animations
if pi_creature in anim.mobject.submobject_family()
]
if anims_with_pi_creature:
for anim in animations:
if isinstance(anim, Transform):
index = anim.submobject_family().index(pi_creature)
target_family = anim.target_mobject.submobject_family()
target = target_family[index]
if isinstance(target, PiCreature):
target.look_at(point_of_interest)
continue
animations.append(
ApplyMethod(pi_creature.look_at, point_of_interest)
)
return animations
def blink(self):
self.play(Blink(self.pi_creature))
self.play(Blink(random.choice(self.get_pi_creatures())))
def dither(self, time = 1, blink = True):
while time > 0:
if blink and self.total_dither_time%self.seconds_to_blink == 1:
self.play(Blink(self.pi_creature))
if blink and self.total_dither_time%self.seconds_to_blink == 0:
self.blink()
else:
Scene.dither(self, time)
Scene.dither(self)
time -= 1
self.total_dither_time += 1
return self
def change_mode(self, mode):
self.play(self.pi_creature.change_mode, mode)
self.play(self.get_primary_pi_creature().change_mode, mode)
class TeacherStudentsScene(Scene):
def setup(self):
class TeacherStudentsScene(PiCreatureScene):
CONFIG = {
"student_colors" : [BLUE_D, BLUE_C, BLUE_E],
"student_scale_factor" : 0.8,
"seconds_to_blink" : 2,
}
def create_pi_creatures(self):
self.teacher = Mortimer()
self.teacher.to_corner(DOWN + RIGHT)
self.teacher.look(DOWN+LEFT)
self.students = VGroup(*[
Randolph(color = c)
for c in BLUE_D, BLUE_C, BLUE_E
for c in self.student_colors
])
self.students.arrange_submobjects(RIGHT)
self.students.scale(0.8)
self.students.scale(self.student_scale_factor)
self.students.to_corner(DOWN+LEFT)
self.teacher.look_at(self.students[-1].eyes)
for student in self.students:
student.look_at(self.teacher.eyes)
for pi_creature in self.get_everyone():
pi_creature.bubble = None
self.add(*self.get_everyone())
return [self.teacher] + list(self.students)
def get_teacher(self):
return self.teacher
@ -366,74 +465,9 @@ class TeacherStudentsScene(Scene):
def get_students(self):
return self.students
def get_everyone(self):
return [self.get_teacher()] + list(self.get_students())
def get_bubble_intro_animation(
self, content, bubble_type, pi_creature,
**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),
Transform(pi_creature.bubble.content, bubble.content)
]
else:
content_intro_anims = [
FadeIn(bubble),
Write(content),
]
pi_creature.bubble = bubble
return content_intro_anims
def introduce_bubble(
self, content, bubble_type, pi_creature,
target_mode = None,
added_anims = [],
**bubble_kwargs
):
if all(map(lambda s : isinstance(s, str), content)):
content = TextMobject(*content)
elif len(content) == 1 and isinstance(content[0], Mobject):
content = content[0]
else:
raise Exception("Invalid content type")
anims = []
#Remove other bubbles
for p in self.get_everyone():
if (p.bubble is not None) and (p is not pi_creature):
anims += [
FadeOut(p.bubble),
FadeOut(p.bubble.content)
]
p.bubble = None
anims.append(ApplyMethod(p.change_mode, "plain"))
#Bring in new bubble
anims += self.get_bubble_intro_animation(
content, bubble_type, pi_creature, **bubble_kwargs
)
#Add changing mode
if not target_mode:
if bubble_type is "speech":
target_mode = "speaking"
else:
target_mode = "pondering"
anims.append(
ApplyMethod(
pi_creature.change_mode,
target_mode,
)
)
self.play(*anims + added_anims)
return pi_creature.bubble
def teacher_says(self, *content, **kwargs):
return self.introduce_bubble(
content, "speech", self.get_teacher(), **kwargs
return self.pi_creature_says(
self.get_teacher(), *content, **kwargs
)
def student_says(self, *content, **kwargs):
@ -444,25 +478,18 @@ class TeacherStudentsScene(Scene):
])
kwargs["target_mode"] = target_mode
student = self.get_students()[kwargs.get("student_index", 1)]
return self.introduce_bubble(content, "speech", student, **kwargs)
return self.pi_creature_says(
student, *content, **kwargs
)
def teacher_thinks(self, *content, **kwargs):
return self.introduce_bubble(
content, "thought", self.get_teacher(), **kwargs
return self.pi_creature_thinks(
self.get_teacher(), *content, **kwargs
)
def student_thinks(self, *content, **kwargs):
student = self.get_students()[kwargs.get("student_index", 1)]
return self.introduce_bubble(content, "thought", student, **kwargs)
def random_blink(self, num_times = 1):
for x in range(num_times):
pi_creature = random.choice(self.get_everyone())
self.play(Blink(pi_creature))
Scene.dither(self)
def dither(self, time = 1):
self.random_blink(num_times = max(time/2, 1))
return self.pi_creature_thinks(student, *content, **kwargs)
def change_student_modes(self, *modes, **kwargs):
added_anims = kwargs.get("added_anims", [])
@ -482,10 +509,9 @@ class TeacherStudentsScene(Scene):
*added_anims
)
def zoom_in_on_thought_bubble(self, bubble = None, radius = SPACE_HEIGHT+SPACE_WIDTH):
if bubble is None:
for pi in self.get_everyone():
for pi in self.get_pi_creatures():
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
bubble = pi.bubble
break