Refactored tex_utils, and made TexMobject proper objects

This commit is contained in:
Grant Sanderson 2015-10-28 17:18:50 -07:00
parent 468d05d049
commit e97a8708a5
24 changed files with 598 additions and 587 deletions

View file

@ -57,7 +57,7 @@ LEFT_SIDE = SPACE_WIDTH*LEFT
RIGHT_SIDE = SPACE_WIDTH*RIGHT RIGHT_SIDE = SPACE_WIDTH*RIGHT
THIS_DIR = os.path.dirname(os.path.realpath(__file__)) THIS_DIR = os.path.dirname(os.path.realpath(__file__))
FILE_DIR = os.path.join(THIS_DIR, "files") FILE_DIR = os.path.join(THIS_DIR, os.pardir, "animation_files")
IMAGE_DIR = os.path.join(FILE_DIR, "images") IMAGE_DIR = os.path.join(FILE_DIR, "images")
GIF_DIR = os.path.join(FILE_DIR, "gifs") GIF_DIR = os.path.join(FILE_DIR, "gifs")
MOVIE_DIR = os.path.join(FILE_DIR, "movies") MOVIE_DIR = os.path.join(FILE_DIR, "movies")

3
mobject/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from mobject import *
from image_mobject import *
from tex_mobject import *

View file

@ -5,7 +5,6 @@ from PIL import Image
from random import random from random import random
from helpers import * from helpers import *
from tex_utils import tex_to_image
from mobject import Mobject from mobject import Mobject
class ImageMobject(Mobject): class ImageMobject(Mobject):

161
mobject/tex_mobject.py Normal file
View file

@ -0,0 +1,161 @@
from mobject import Mobject
from image_mobject import ImageMobject
from helpers import *
#TODO, Cleanup and refactor this file.
class TexMobject(Mobject):
DEFAULT_CONFIG = {
"template_tex_file" : TEMPLATE_TEX_FILE,
"color" : WHITE,
"point_thickness" : 1,
"should_center" : False,
}
def __init__(self, expression, **kwargs):
if "size" not in kwargs:
#Todo, make this more sophisticated.
if len("".join(expression)) < MAX_LEN_FOR_HUGE_TEX_FONT:
size = "\\Huge"
else:
size = "\\large"
digest_locals(self)
Mobject.__init__(self, **kwargs)
def generate_points(self):
image_files = tex_to_image_files(
self.expression,
self.size,
self.template_tex_file
)
for image_file in image_files:
self.add(ImageMobject(image_file))
if self.should_center:
self.center()
self.highlight(self.color)
class TextMobject(TexMobject):
DEFAULT_CONFIG = {
"template_tex_file" : TEMPLATE_TEXT_FILE,
"size" : "\\Large", #TODO, auto-adjust?
}
class Underbrace(TexMobject):
DEFAULT_CONFIG = {
"buff" : 0.2,
}
def __init__(self, left, right, **kwargs):
expression = "\\underbrace{%s}"%(14*"\\quad")
TexMobject.__init__(self, expression, **kwargs)
result.stretch_to_fit_width(right[0]-left[0])
result.shift(left - result.points[0] + buff*DOWN)
def tex_hash(expression, size):
return str(hash(expression + size))
def tex_to_image_files(expression, size, template_tex_file):
"""
Returns list of images for correpsonding with a list of expressions
"""
image_dir = os.path.join(TEX_IMAGE_DIR, tex_hash(expression, size))
if os.path.exists(image_dir):
return get_sorted_image_list(image_dir)
tex_file = generate_tex_file(expression, size, template_tex_file)
dvi_file = tex_to_dvi(tex_file)
return dvi_to_png(dvi_file)
def generate_tex_file(expression, size, template_tex_file):
if isinstance(expression, list):
expression = tex_expression_list_as_string(expression)
result = os.path.join(TEX_DIR, tex_hash(expression, size))+".tex"
if not os.path.exists(result):
print "Writing %s at size %s to %s"%(
"".join(expression), size, result
)
with open(template_tex_file, "r") as infile:
body = infile.read()
body = body.replace(SIZE_TO_REPLACE, size)
body = body.replace(TEX_TEXT_TO_REPLACE, expression)
with open(result, "w") as outfile:
outfile.write(body)
return result
def tex_to_dvi(tex_file):
result = tex_file.replace(".tex", ".dvi")
if not os.path.exists(filestem + ".dvi"):
commands = [
"latex",
"-interaction=batchmode",
"-output-directory=" + TEX_DIR,
tex_file,
"> /dev/null"
]
#TODO, Error check
os.system(" ".join(commands))
return result
def tex_expression_list_as_string(expression):
return "\n".join([
"\onslide<%d>{"%count + exp + "}"
for count, exp in zip(it.count(1), expression)
])
def dvi_to_png(dvi_file, regen_if_exists = False):
"""
Converts a dvi, which potentially has multiple slides, into a
directory full of enumerated pngs corresponding with these slides.
Returns a list of PIL Image objects for these images sorted as they
where in the dvi
"""
directory, filename = os.path.split(dvi_file)
name = filename.replace(".dvi", "")
images_dir = os.path.join(TEX_IMAGE_DIR, name)
if not os.path.exists(images_dir):
os.mkdir(images_dir)
if os.listdir(images_dir) == [] or regen_if_exists:
commands = [
"convert",
"-density",
str(PDF_DENSITY),
path,
"-size",
str(DEFAULT_WIDTH) + "x" + str(DEFAULT_HEIGHT),
os.path.join(images_dir, name + ".png")
]
os.system(" ".join(commands))
return get_sorted_image_list(images_dir)
def get_sorted_image_list(images_dir):
return sorted([
os.path.join(images_dir, name)
for name in os.listdir(images_dir)
if name.endswith(".png")
], cmp_enumerated_files)
def cmp_enumerated_files(name1, name2):
num1, num2 = [
int(name.split(".")[0].split("-")[-1])
for name in (name1, name2)
]
return num1 - num2

View file

@ -195,7 +195,7 @@ class DrawComplexAngleAndMagnitude(Scene):
def draw_number(self, tex_representation, number): def draw_number(self, tex_representation, number):
point = self.plane.number_to_point(number) point = self.plane.number_to_point(number)
dot = Dot(point) dot = Dot(point)
label = tex_mobject(tex_representation) label = TexMobject(tex_representation)
max_width = 0.8*self.plane.unit_to_spatial_width max_width = 0.8*self.plane.unit_to_spatial_width
if label.get_width() > max_width: if label.get_width() > max_width:
label.scale_to_fit_width(max_width) label.scale_to_fit_width(max_width)
@ -235,17 +235,17 @@ class DrawComplexAngleAndMagnitude(Scene):
# tex_parts = tex_representation.split("+") # tex_parts = tex_representation.split("+")
# elif "-" in tex_representation: # elif "-" in tex_representation:
# tex_parts = tex_representation.split("-") # tex_parts = tex_representation.split("-")
# x_label, y_label = map(tex_mobject, tex_parts) # x_label, y_label = map(TexMobject, tex_parts)
# for label in x_label, y_label: # for label in x_label, y_label:
# label.scale_to_fit_height(0.5) # label.scale_to_fit_height(0.5)
# x_label.next_to(x_line, point[1]*DOWN/abs(point[1])) # x_label.next_to(x_line, point[1]*DOWN/abs(point[1]))
# y_label.next_to(y_line, point[0]*RIGHT/abs(point[0])) # y_label.next_to(y_line, point[0]*RIGHT/abs(point[0]))
norm = np.linalg.norm(point) norm = np.linalg.norm(point)
brace = underbrace(ORIGIN, ORIGIN+norm*RIGHT) brace = Underbrace(ORIGIN, ORIGIN+norm*RIGHT)
if point[1] > 0: if point[1] > 0:
brace.rotate(np.pi, RIGHT) brace.rotate(np.pi, RIGHT)
brace.rotate(np.log(number).imag) brace.rotate(np.log(number).imag)
norm_label = tex_mobject("%.1f"%abs(number)) norm_label = TexMobject("%.1f"%abs(number))
norm_label.scale(0.5) norm_label.scale(0.5)
axis = OUT if point[1] > 0 else IN axis = OUT if point[1] > 0 else IN
norm_label.next_to(brace, rotate_vector(point, np.pi/2, axis)) norm_label.next_to(brace, rotate_vector(point, np.pi/2, axis))

View file

@ -81,7 +81,7 @@ COUNT_TO_TIP_POS = {
} }
def finger_tip_power_of_2(finger_no): def finger_tip_power_of_2(finger_no):
return tex_mobject(str(2**finger_no)).shift(COUNT_TO_TIP_POS[finger_no]) return TexMobject(str(2**finger_no)).shift(COUNT_TO_TIP_POS[finger_no])
class Hand(ImageMobject): class Hand(ImageMobject):
STARTING_BOTTOM_RIGHT = [4.61111111e+00, -3.98888889e+00, 9.80454690e-16] STARTING_BOTTOM_RIGHT = [4.61111111e+00, -3.98888889e+00, 9.80454690e-16]
@ -114,7 +114,7 @@ class Hand(ImageMobject):
# ) # )
def get_algorithm(): def get_algorithm():
return text_mobject(ALGORITHM_TEXT) return TextMobject(ALGORITHM_TEXT)
def get_finger_colors(): def get_finger_colors():
return list(Color("yellow").range_to("red", 5)) return list(Color("yellow").range_to("red", 5))
@ -186,7 +186,7 @@ class ShowCounting(OverHand):
] ]
def get_counting_mob(self, count): def get_counting_mob(self, count):
mob = tex_mobject(str(count)) mob = TexMobject(str(count))
mob.scale(2) mob.scale(2)
mob.shift(LEFT) mob.shift(LEFT)
mob.to_edge(UP, buff = 0.1) mob.to_edge(UP, buff = 0.1)
@ -199,7 +199,7 @@ class ShowFrameNum(OverHand):
for frame, count in zip(self.frames, it.count()): for frame, count in zip(self.frames, it.count()):
print count, "of", len(self.frames) print count, "of", len(self.frames)
mob = CompoundMobject(*[ mob = CompoundMobject(*[
tex_mobject(char).shift(0.3*x*RIGHT) TexMobject(char).shift(0.3*x*RIGHT)
for char, x, in zip(str(count), it.count()) for char, x, in zip(str(count), it.count())
]) ])
self.frames[count] = disp.paint_mobject( self.frames[count] = disp.paint_mobject(
@ -213,7 +213,7 @@ class CountTo1023(Scene):
lh_map = get_hand_map("left") lh_map = get_hand_map("left")
def get_num(count): def get_num(count):
return CompoundMobject(*[ return CompoundMobject(*[
tex_mobject(char).shift(0.35*x*RIGHT) TexMobject(char).shift(0.35*x*RIGHT)
for char, x, in zip(str(count), it.count()) for char, x, in zip(str(count), it.count())
]).center().to_edge(UP) ]).center().to_edge(UP)
self.frames = [ self.frames = [
@ -225,7 +225,7 @@ class CountTo1023(Scene):
class Introduction(Scene): class Introduction(Scene):
def construct(self): def construct(self):
words = text_mobject(""" words = TextMobject("""
First, let's see how to count First, let's see how to count
to 31 on just one hand... to 31 on just one hand...
""") """)
@ -242,10 +242,10 @@ class Introduction(Scene):
class ShowReadingRule(Scene): class ShowReadingRule(Scene):
def construct(self): def construct(self):
sample_counts = [6, 17, 27, 31] sample_counts = [6, 17, 27, 31]
question = text_mobject(""" question = TextMobject("""
How do you recognize what number a given configuration represents? How do you recognize what number a given configuration represents?
""", size = "\\Huge").scale(0.75).to_corner(UP+LEFT) """, size = "\\Huge").scale(0.75).to_corner(UP+LEFT)
answer = text_mobject([ answer = TextMobject([
"Think of each finger as representing a power of 2, ", "Think of each finger as representing a power of 2, ",
"then add up the numbers represented by the standing fingers." "then add up the numbers represented by the standing fingers."
], size = "\\Huge").scale(0.75).to_corner(UP+LEFT).split() ], size = "\\Huge").scale(0.75).to_corner(UP+LEFT).split()
@ -278,7 +278,7 @@ class ShowReadingRule(Scene):
count_mobs[1].shift(0.2*DOWN + 0.2*LEFT) count_mobs[1].shift(0.2*DOWN + 0.2*LEFT)
if num in [6, 17]: if num in [6, 17]:
hand.shift(0.8*LEFT) hand.shift(0.8*LEFT)
sum_mobs = tex_mobject( sum_mobs = TexMobject(
" + ".join([str(2**c) for c in counts]).split(" ") + ["=%d"%num] " + ".join([str(2**c) for c in counts]).split(" ") + ["=%d"%num]
).to_corner(UP+RIGHT).split() ).to_corner(UP+RIGHT).split()
self.add(hand, *count_mobs) self.add(hand, *count_mobs)
@ -298,7 +298,7 @@ class ShowIncrementRule(Scene):
def to_left(words): def to_left(words):
return "\\begin{flushleft}" + words + "\\end{flushleft}" return "\\begin{flushleft}" + words + "\\end{flushleft}"
phrases = [ phrases = [
text_mobject(to_left(words), size = "\\Huge").scale(0.75).to_corner(UP+LEFT) TextMobject(to_left(words), size = "\\Huge").scale(0.75).to_corner(UP+LEFT)
for words in [ for words in [
"But while you're counting, you don't need to think about powers of 2.", "But while you're counting, you don't need to think about powers of 2.",
"Can you see the pattern for incrementing?", "Can you see the pattern for incrementing?",
@ -337,7 +337,7 @@ class ShowIncrementRule(Scene):
self.frames += [self.frames[-1]]*int(1.0/self.frame_duration) self.frames += [self.frames[-1]]*int(1.0/self.frame_duration)
def get_arrow_set(self, num): def get_arrow_set(self, num):
arrow = tex_mobject("\\downarrow", size = "\\Huge") arrow = TexMobject("\\downarrow", size = "\\Huge")
arrow.highlight("green") arrow.highlight("green")
arrow.shift(-arrow.get_bottom()) arrow.shift(-arrow.get_bottom())
if num == 12: if num == 12:
@ -368,17 +368,17 @@ class ShowIncrementRule(Scene):
class MindFindsShortcuts(Scene): class MindFindsShortcuts(Scene):
def construct(self): def construct(self):
words1 = text_mobject(""" words1 = TextMobject("""
Before long, your mind starts to recognize certain Before long, your mind starts to recognize certain
patterns without needing to perform the addition. patterns without needing to perform the addition.
""", size = "\\Huge").scale(0.75).to_corner(LEFT+UP) """, size = "\\Huge").scale(0.75).to_corner(LEFT+UP)
words2 = text_mobject(""" words2 = TextMobject("""
Which makes it faster to recognize other patterns... Which makes it faster to recognize other patterns...
""", size = "\\Huge").scale(0.75).to_corner(LEFT+UP) """, size = "\\Huge").scale(0.75).to_corner(LEFT+UP)
hand = Hand(7).scale(0.5).center().shift(DOWN+2*LEFT) hand = Hand(7).scale(0.5).center().shift(DOWN+2*LEFT)
sum421 = tex_mobject("4+2+1").shift(DOWN+2*RIGHT) sum421 = TexMobject("4+2+1").shift(DOWN+2*RIGHT)
seven = tex_mobject("7").shift(DOWN+6*RIGHT) seven = TexMobject("7").shift(DOWN+6*RIGHT)
compound = CompoundMobject( compound = CompoundMobject(
Arrow(hand, sum421), Arrow(hand, sum421),
sum421, sum421,
@ -393,7 +393,7 @@ class MindFindsShortcuts(Scene):
self.dither() self.dither()
self.play( self.play(
Transform(compound, Arrow(hand, seven).highlight("yellow")), Transform(compound, Arrow(hand, seven).highlight("yellow")),
ShimmerIn(text_mobject("Directly recognize").shift(1.5*DOWN+2*RIGHT)) ShimmerIn(TextMobject("Directly recognize").shift(1.5*DOWN+2*RIGHT))
) )
self.dither() self.dither()
@ -406,10 +406,10 @@ class MindFindsShortcuts(Scene):
hands[16].shift(LEFT) hands[16].shift(LEFT)
hands[7].shift(3*RIGHT) hands[7].shift(3*RIGHT)
for num in 7, 16: for num in 7, 16:
hands[num].add(tex_mobject(str(num)).shift(hands[num].get_top()+0.5*UP)) hands[num].add(TexMobject(str(num)).shift(hands[num].get_top()+0.5*UP))
plus = tex_mobject("+").shift(DOWN + RIGHT) plus = TexMobject("+").shift(DOWN + RIGHT)
equals = tex_mobject("=").shift(DOWN + 2.5*LEFT) equals = TexMobject("=").shift(DOWN + 2.5*LEFT)
equals23 = tex_mobject("=23").shift(DOWN + 5.5*RIGHT) equals23 = TexMobject("=23").shift(DOWN + 5.5*RIGHT)
self.add(words2, hands[23]) self.add(words2, hands[23])
self.dither() self.dither()
@ -434,7 +434,7 @@ class MindFindsShortcuts(Scene):
class CountingExampleSentence(ShowCounting): class CountingExampleSentence(ShowCounting):
def construct(self): def construct(self):
words = "As an example, this is me counting the number of words in this sentence on just one hand!" words = "As an example, this is me counting the number of words in this sentence on just one hand!"
self.words = text_mobject(words.split(), size = "\\Huge").scale(0.7).to_corner(UP+LEFT, buff = 0.25).split() self.words = TextMobject(words.split(), size = "\\Huge").scale(0.7).to_corner(UP+LEFT, buff = 0.25).split()
ShowCounting.construct(self) ShowCounting.construct(self)
def get_counting_mob(self, num): def get_counting_mob(self, num):
@ -443,11 +443,11 @@ class CountingExampleSentence(ShowCounting):
class FinishCountingExampleSentence(Scene): class FinishCountingExampleSentence(Scene):
def construct(self): def construct(self):
words = "As an example, this is me counting the number of words in this sentence on just one hand!" words = "As an example, this is me counting the number of words in this sentence on just one hand!"
words = text_mobject(words, size = "\\Huge").scale(0.7).to_corner(UP+LEFT, buff = 0.25) words = TextMobject(words, size = "\\Huge").scale(0.7).to_corner(UP+LEFT, buff = 0.25)
hand = Hand(18) hand = Hand(18)
sixteen = tex_mobject("16").shift([0, 2.25, 0]) sixteen = TexMobject("16").shift([0, 2.25, 0])
two = tex_mobject("2").shift([3, 3.65, 0]) two = TexMobject("2").shift([3, 3.65, 0])
eightteen = tex_mobject("18").shift([1.5, 2.5, 0]) eightteen = TexMobject("18").shift([1.5, 2.5, 0])
eightteen.sort_points() eightteen.sort_points()
comp = CompoundMobject(sixteen, two) comp = CompoundMobject(sixteen, two)
self.add(hand, comp, words) self.add(hand, comp, words)
@ -457,18 +457,18 @@ class FinishCountingExampleSentence(Scene):
class Question(Scene): class Question(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Left to ponder: Why does this rule for incrementing work?")) self.add(TextMobject("Left to ponder: Why does this rule for incrementing work?"))
class TwoHandStatement(Scene): class TwoHandStatement(Scene):
def construct(self): def construct(self):
self.add(text_mobject( self.add(TextMobject(
"With 10 fingers, you can count up to $2^{10} - 1 = 1023$..." "With 10 fingers, you can count up to $2^{10} - 1 = 1023$..."
)) ))
class WithToes(Scene): class WithToes(Scene):
def construct(self): def construct(self):
words = text_mobject([ words = TextMobject([
"If you were dexterous enough to use your toes as well,", "If you were dexterous enough to use your toes as well,",
"you could count to 1,048,575" "you could count to 1,048,575"
]).split() ]).split()

View file

@ -23,19 +23,19 @@ DUAL_CYCLE = [3, 4, 5, 6, 1, 0, 2, 3]
class EulersFormulaWords(Scene): class EulersFormulaWords(Scene):
def construct(self): def construct(self):
self.add(tex_mobject("V-E+F=2")) self.add(TexMobject("V-E+F=2"))
class TheTheoremWords(Scene): class TheTheoremWords(Scene):
def construct(self): def construct(self):
self.add(text_mobject("The Theorem:")) self.add(TextMobject("The Theorem:"))
class ProofAtLastWords(Scene): class ProofAtLastWords(Scene):
def construct(self): def construct(self):
self.add(text_mobject("The Proof At Last...")) self.add(TextMobject("The Proof At Last..."))
class DualSpanningTreeWords(Scene): class DualSpanningTreeWords(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Spanning trees have duals too!")) self.add(TextMobject("Spanning trees have duals too!"))
class PreferOtherProofDialogue(Scene): class PreferOtherProofDialogue(Scene):
def construct(self): def construct(self):
@ -63,7 +63,7 @@ class IllustrateDuality(GraphScene):
GraphScene.construct(self) GraphScene.construct(self)
self.generate_dual_graph() self.generate_dual_graph()
self.add(text_mobject("Duality").to_edge(UP)) self.add(TextMobject("Duality").to_edge(UP))
self.remove(*self.vertices) self.remove(*self.vertices)
def special_alpha(t): def special_alpha(t):
if t > 0.5: if t > 0.5:
@ -107,11 +107,11 @@ class IntroduceGraph(GraphScene):
for pair in [(4, 5), (0, 5), (1, 5), (7, 1), (8, 3)] for pair in [(4, 5), (0, 5), (1, 5), (7, 1), (8, 3)]
] ]
connected, planar, graph = text_mobject([ connected, planar, graph = TextMobject([
"Connected ", "Planar ", "Graph" "Connected ", "Planar ", "Graph"
]).to_edge(UP).split() ]).to_edge(UP).split()
not_okay = text_mobject("Not Okay").highlight("red") not_okay = TextMobject("Not Okay").highlight("red")
planar_explanation = text_mobject(""" planar_explanation = TextMobject("""
(``Planar'' just means we can draw it without (``Planar'' just means we can draw it without
intersecting lines) intersecting lines)
""", size = "\\small") """, size = "\\small")
@ -162,7 +162,7 @@ class OldIntroduceGraphs(GraphScene):
self.clear() self.clear()
self.add(*self.edges) self.add(*self.edges)
self.replace_vertices_with(Face().scale(0.4)) self.replace_vertices_with(Face().scale(0.4))
friends = text_mobject("Friends").scale(EDGE_ANNOTATION_SCALE_VAL) friends = TextMobject("Friends").scale(EDGE_ANNOTATION_SCALE_VAL)
self.annotate_edges(friends.shift((0, friends.get_height()/2, 0))) self.annotate_edges(friends.shift((0, friends.get_height()/2, 0)))
self.play(*[ self.play(*[
CounterclockwiseTransform(vertex, Dot(point)) CounterclockwiseTransform(vertex, Dot(point))
@ -178,7 +178,7 @@ class OldIntroduceGraphs(GraphScene):
class PlanarGraphDefinition(Scene): class PlanarGraphDefinition(Scene):
def construct(self): def construct(self):
Not, quote, planar, end_quote = text_mobject([ Not, quote, planar, end_quote = TextMobject([
"Not \\\\", "``", "Planar", "''", "Not \\\\", "``", "Planar", "''",
# "no matter how \\\\ hard you try" # "no matter how \\\\ hard you try"
]).split() ]).split()
@ -233,9 +233,9 @@ class TerminologyFromPolyhedra(GraphScene):
]) ])
cube.rotate(-np.pi/3, [0, 0, 1]) cube.rotate(-np.pi/3, [0, 0, 1])
cube.rotate(-np.pi/3, [0, 1, 0]) cube.rotate(-np.pi/3, [0, 1, 0])
dots_to_vertices = text_mobject("Dots $\\to$ Vertices").to_corner() dots_to_vertices = TextMobject("Dots $\\to$ Vertices").to_corner()
lines_to_edges = text_mobject("Lines $\\to$ Edges").to_corner() lines_to_edges = TextMobject("Lines $\\to$ Edges").to_corner()
regions_to_faces = text_mobject("Regions $\\to$ Faces").to_corner() regions_to_faces = TextMobject("Regions $\\to$ Faces").to_corner()
self.clear() self.clear()
# self.play(TransformAnimations( # self.play(TransformAnimations(
@ -274,7 +274,7 @@ class ThreePiecesOfTerminology(GraphScene):
def construct(self): def construct(self):
GraphScene.construct(self) GraphScene.construct(self)
terms = cycles, spanning_trees, dual_graphs = [ terms = cycles, spanning_trees, dual_graphs = [
text_mobject(phrase).shift(y*UP).to_edge() TextMobject(phrase).shift(y*UP).to_edge()
for phrase, y in [ for phrase, y in [
("Cycles", 3), ("Cycles", 3),
("Spanning Trees", 1), ("Spanning Trees", 1),
@ -355,8 +355,8 @@ class PathExamples(GraphScene):
[(0, 1), (7, 8), (5, 6),], [(0, 1), (7, 8), (5, 6),],
[(5, 0), (0, 2), (0, 1)], [(5, 0), (0, 2), (0, 1)],
] ]
valid_path = text_mobject("Valid \\\\ Path").highlight("green") valid_path = TextMobject("Valid \\\\ Path").highlight("green")
not_a_path = text_mobject("Not a \\\\ Path").highlight("red") not_a_path = TextMobject("Not a \\\\ Path").highlight("red")
for mob in valid_path, not_a_path: for mob in valid_path, not_a_path:
mob.to_edge(UP) mob.to_edge(UP)
kwargs = {"run_time" : 1.0} kwargs = {"run_time" : 1.0}
@ -413,7 +413,7 @@ class IntroduceRandolph(GraphScene):
def construct(self): def construct(self):
GraphScene.construct(self) GraphScene.construct(self)
randy = Randolph().move_to((-3, 0, 0)) randy = Randolph().move_to((-3, 0, 0))
name = text_mobject("Randolph") name = TextMobject("Randolph")
self.play(Transform( self.play(Transform(
randy, randy,
deepcopy(randy).scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]), deepcopy(randy).scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]),
@ -428,13 +428,13 @@ class DefineSpanningTree(GraphScene):
GraphScene.construct(self) GraphScene.construct(self)
randy = Randolph() randy = Randolph()
randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]) randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0])
dollar_signs = text_mobject("\\$\\$") dollar_signs = TextMobject("\\$\\$")
dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL) dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL)
dollar_signs = CompoundMobject(*[ dollar_signs = CompoundMobject(*[
deepcopy(dollar_signs).shift(edge.get_center()) deepcopy(dollar_signs).shift(edge.get_center())
for edge in self.edges for edge in self.edges
]) ])
unneeded = text_mobject("unneeded!") unneeded = TextMobject("unneeded!")
unneeded.scale(EDGE_ANNOTATION_SCALE_VAL) unneeded.scale(EDGE_ANNOTATION_SCALE_VAL)
self.generate_spanning_tree() self.generate_spanning_tree()
def green_dot_at_index(index): def green_dot_at_index(index):
@ -489,8 +489,8 @@ class NamingTree(GraphScene):
branches = self.spanning_tree.split() branches = self.spanning_tree.split()
branches_copy = deepcopy(branches) branches_copy = deepcopy(branches)
treeified_branches = self.treeified_spanning_tree.split() treeified_branches = self.treeified_spanning_tree.split()
tree = text_mobject("``Tree''").to_edge(UP) tree = TextMobject("``Tree''").to_edge(UP)
spanning_tree = text_mobject("``Spanning Tree''").to_edge(UP) spanning_tree = TextMobject("``Spanning Tree''").to_edge(UP)
self.add(*branches) self.add(*branches)
self.play( self.play(
@ -521,7 +521,7 @@ class DualGraph(GraphScene):
def construct(self): def construct(self):
GraphScene.construct(self) GraphScene.construct(self)
self.generate_dual_graph() self.generate_dual_graph()
self.add(text_mobject("Dual Graph").to_edge(UP).shift(2*LEFT)) self.add(TextMobject("Dual Graph").to_edge(UP).shift(2*LEFT))
self.play(*[ self.play(*[
ShowCreation(mob) ShowCreation(mob)
for mob in self.dual_edges + self.dual_vertices for mob in self.dual_edges + self.dual_vertices
@ -544,7 +544,7 @@ class FacebookGraph(GraphScene):
logo.shift(0.2*LEFT + 0.1*UP) logo.shift(0.2*LEFT + 0.1*UP)
account.add(logo).center() account.add(logo).center()
account.shift(0.2*LEFT + 0.1*UP) account.shift(0.2*LEFT + 0.1*UP)
friends = tex_mobject( friends = TexMobject(
"\\leftarrow \\text{friends} \\rightarrow" "\\leftarrow \\text{friends} \\rightarrow"
).scale(0.5*EDGE_ANNOTATION_SCALE_VAL) ).scale(0.5*EDGE_ANNOTATION_SCALE_VAL)
@ -591,13 +591,13 @@ class FacebookGraphAsAbstractSet(Scene):
"\\text{%s}&\\leftrightarrow\\text{%s}"%(names[i],names[j]) "\\text{%s}&\\leftrightarrow\\text{%s}"%(names[i],names[j])
for i, j in friend_pairs for i, j in friend_pairs
] + ["\\vdots"]) ] + ["\\vdots"])
names_mob = text_mobject(names_string).shift(3*LEFT) names_mob = TextMobject(names_string).shift(3*LEFT)
friends_mob = tex_mobject( friends_mob = TexMobject(
friends_string, size = "\\Large" friends_string, size = "\\Large"
).shift(3*RIGHT) ).shift(3*RIGHT)
accounts = text_mobject("\\textbf{Accounts}") accounts = TextMobject("\\textbf{Accounts}")
accounts.shift(3*LEFT).to_edge(UP) accounts.shift(3*LEFT).to_edge(UP)
friendships = text_mobject("\\textbf{Friendships}") friendships = TextMobject("\\textbf{Friendships}")
friendships.shift(3*RIGHT).to_edge(UP) friendships.shift(3*RIGHT).to_edge(UP)
lines = CompoundMobject( lines = CompoundMobject(
Line(UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT), Line(UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT),
@ -622,7 +622,7 @@ class ExamplesOfGraphs(GraphScene):
) )
GraphScene.construct(self) GraphScene.construct(self)
self.generate_regions() self.generate_regions()
objects, notions = CompoundMobject(*text_mobject( objects, notions = CompoundMobject(*TextMobject(
["Objects \\quad\\quad ", "Thing that connects objects"] ["Objects \\quad\\quad ", "Thing that connects objects"]
)).to_corner().shift(0.5*RIGHT).split() )).to_corner().shift(0.5*RIGHT).split()
horizontal_line = Line( horizontal_line = Line(
@ -649,8 +649,8 @@ class ExamplesOfGraphs(GraphScene):
self.clear() self.clear()
self.add(objects, notions, horizontal_line, vertical_line) self.add(objects, notions, horizontal_line, vertical_line)
for (obj, notion), height in zip(objects_and_notions, it.count(2, -1)): for (obj, notion), height in zip(objects_and_notions, it.count(2, -1)):
obj_mob = text_mobject(obj, size = "\\small").to_edge(LEFT) obj_mob = TextMobject(obj, size = "\\small").to_edge(LEFT)
not_mob = text_mobject(notion, size = "\\small").to_edge(LEFT) not_mob = TextMobject(notion, size = "\\small").to_edge(LEFT)
not_mob.shift((vert_line_x_val + SPACE_WIDTH)*RIGHT) not_mob.shift((vert_line_x_val + SPACE_WIDTH)*RIGHT)
obj_mob.shift(height*UP) obj_mob.shift(height*UP)
not_mob.shift(height*UP) not_mob.shift(height*UP)
@ -666,7 +666,7 @@ class ExamplesOfGraphs(GraphScene):
self.dither() self.dither()
def handle_english_words(self, words1, words2): def handle_english_words(self, words1, words2):
words = map(text_mobject, ["graph", "grape", "gape", "gripe"]) words = map(TextMobject, ["graph", "grape", "gape", "gripe"])
words[0].shift(RIGHT) words[0].shift(RIGHT)
words[1].shift(3*RIGHT) words[1].shift(3*RIGHT)
words[2].shift(3*RIGHT + 2*UP) words[2].shift(3*RIGHT + 2*UP)
@ -701,9 +701,9 @@ class ExamplesOfGraphs(GraphScene):
def handle_dual_graph(self, words1, words2): def handle_dual_graph(self, words1, words2):
words1.highlight("yellow") words1.highlight("yellow")
words2.highlight("yellow") words2.highlight("yellow")
connected = text_mobject("Connected") connected = TextMobject("Connected")
connected.highlight("lightgreen") connected.highlight("lightgreen")
not_connected = text_mobject("Not Connected") not_connected = TextMobject("Not Connected")
not_connected.highlight("red") not_connected.highlight("red")
for mob in connected, not_connected: for mob in connected, not_connected:
mob.shift(self.points[3] + UP) mob.shift(self.points[3] + UP)
@ -818,7 +818,7 @@ class EdgesAreTheSame(GraphScene):
]) ])
self.dither() self.dither()
self.add( self.add(
text_mobject(""" TextMobject("""
(Or at least I would argue they should \\\\ (Or at least I would argue they should \\\\
be thought of as the same thing.) be thought of as the same thing.)
""", size = "\\small").to_edge(UP) """, size = "\\small").to_edge(UP)
@ -839,11 +839,11 @@ class ListOfCorrespondances(Scene):
for corr in correspondances: for corr in correspondances:
corr[0] += " original graph" corr[0] += " original graph"
corr[1] += " dual graph" corr[1] += " dual graph"
arrow = tex_mobject("\\leftrightarrow", size = "\\large") arrow = TexMobject("\\leftrightarrow", size = "\\large")
lines = [] lines = []
for corr, height in zip(correspondances, it.count(3, -1)): for corr, height in zip(correspondances, it.count(3, -1)):
left = text_mobject(corr[0], size = "\\small") left = TextMobject(corr[0], size = "\\small")
right = text_mobject(corr[1], size = "\\small") right = TextMobject(corr[1], size = "\\small")
this_arrow = deepcopy(arrow) this_arrow = deepcopy(arrow)
for mob in left, right, this_arrow: for mob in left, right, this_arrow:
mob.shift(height*UP) mob.shift(height*UP)
@ -917,7 +917,7 @@ class IntroduceMortimer(GraphScene):
self.generate_regions() self.generate_regions()
randy = Randolph().shift(LEFT) randy = Randolph().shift(LEFT)
morty = Mortimer().shift(RIGHT) morty = Mortimer().shift(RIGHT)
name = text_mobject("Mortimer") name = TextMobject("Mortimer")
name.shift(morty.get_center() + 1.2*UP) name.shift(morty.get_center() + 1.2*UP)
randy_path = (0, 1, 3) randy_path = (0, 1, 3)
morty_path = (-2, -3, -4) morty_path = (-2, -3, -4)
@ -1031,7 +1031,7 @@ class MortimerCannotTraverseCycle(GraphScene):
morty = Mortimer().scale(RANDOLPH_SCALE_VAL) morty = Mortimer().scale(RANDOLPH_SCALE_VAL)
morty.move_to(self.dual_points[dual_cycle[0]]) morty.move_to(self.dual_points[dual_cycle[0]])
time_per_edge = 0.5 time_per_edge = 0.5
text = text_mobject(""" text = TextMobject("""
One of these lines must be included One of these lines must be included
in the spanning tree if those two inner in the spanning tree if those two inner
vertices are to be reached. vertices are to be reached.
@ -1073,14 +1073,14 @@ class MortimerCannotTraverseCycle(GraphScene):
class TwoPropertiesOfSpanningTree(Scene): class TwoPropertiesOfSpanningTree(Scene):
def construct(self): def construct(self):
spanning, tree = text_mobject( spanning, tree = TextMobject(
["Spanning ", "Tree"], ["Spanning ", "Tree"],
size = "\\Huge" size = "\\Huge"
).split() ).split()
spanning_explanation = text_mobject(""" spanning_explanation = TextMobject("""
Touches every vertex Touches every vertex
""").shift(spanning.get_center() + 2*DOWN) """).shift(spanning.get_center() + 2*DOWN)
tree_explanation = text_mobject(""" tree_explanation = TextMobject("""
No Cycles No Cycles
""").shift(tree.get_center() + 2*UP) """).shift(tree.get_center() + 2*UP)
@ -1111,7 +1111,7 @@ class DualSpanningTree(GraphScene):
morty.scale(RANDOLPH_SCALE_VAL) morty.scale(RANDOLPH_SCALE_VAL)
morty.move_to(self.dual_points[0]) morty.move_to(self.dual_points[0])
dual_edges = [1, 3, 4, 7, 11, 9, 13] dual_edges = [1, 3, 4, 7, 11, 9, 13]
words = text_mobject(""" words = TextMobject("""
The red edges form a spanning tree of the dual graph! The red edges form a spanning tree of the dual graph!
""").to_edge(UP) """).to_edge(UP)
@ -1125,7 +1125,7 @@ class DualSpanningTree(GraphScene):
class TreeCountFormula(Scene): class TreeCountFormula(Scene):
def construct(self): def construct(self):
time_per_branch = 0.5 time_per_branch = 0.5
text = text_mobject(""" text = TextMobject("""
In any tree: In any tree:
$$E + 1 = V$$ $$E + 1 = V$$
""") """)
@ -1157,7 +1157,7 @@ class TreeCountFormula(Scene):
class FinalSum(Scene): class FinalSum(Scene):
def construct(self): def construct(self):
lines = tex_mobject([ lines = TexMobject([
"(\\text{Number of Randolph's Edges}) + 1 &= V \\\\ \n", "(\\text{Number of Randolph's Edges}) + 1 &= V \\\\ \n",
"(\\text{Number of Mortimer's Edges}) + 1 &= F \\\\ \n", "(\\text{Number of Mortimer's Edges}) + 1 &= F \\\\ \n",
" \\Downarrow \\\\", "E","+","2","&=","V","+","F", " \\Downarrow \\\\", "E","+","2","&=","V","+","F",
@ -1167,10 +1167,10 @@ class FinalSum(Scene):
self.dither() self.dither()
self.dither() self.dither()
symbols = V, minus, E, plus, F, equals, two = tex_mobject( symbols = V, minus, E, plus, F, equals, two = TexMobject(
"V - E + F = 2".split(" ") "V - E + F = 2".split(" ")
) )
plus = tex_mobject("+") plus = TexMobject("+")
anims = [] anims = []
for mob, index in zip(symbols, [-3, -2, -7, -6, -1, -4, -5]): for mob, index in zip(symbols, [-3, -2, -7, -6, -1, -4, -5]):
copy = plus if index == -2 else deepcopy(mob) copy = plus if index == -2 else deepcopy(mob)

View file

@ -47,7 +47,7 @@ class LogoGeneration(Scene):
lambda point: np.linalg.norm(point) < \ lambda point: np.linalg.norm(point) < \
self.INNER_RADIUS_RATIO*self.LOGO_RADIUS self.INNER_RADIUS_RATIO*self.LOGO_RADIUS
) )
name = text_mobject("3Blue1Brown").center() name = TextMobject("3Blue1Brown").center()
name.highlight("grey") name.highlight("grey")
name.shift(2*DOWN) name.shift(2*DOWN)

View file

@ -76,13 +76,13 @@ NUM_INTERVAL_TICKS = 16
def divergent_sum(): def divergent_sum():
return tex_mobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2) return TexMobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2)
def convergent_sum(): def convergent_sum():
return tex_mobject(CONVERGENT_SUM_TEXT, size = "\\large").scale(2) return TexMobject(CONVERGENT_SUM_TEXT, size = "\\large").scale(2)
def underbrace(left, right): def Underbrace(left, right):
result = tex_mobject("\\underbrace{%s}"%(14*"\\quad")) result = TexMobject("\\Underbrace{%s}"%(14*"\\quad"))
result.stretch_to_fit_width(right[0]-left[0]) result.stretch_to_fit_width(right[0]-left[0])
result.shift(left - result.points[0]) result.shift(left - result.points[0])
return result return result
@ -94,8 +94,8 @@ def zero_to_one_interval():
) )
interval.elongate_tick_at(-INTERVAL_RADIUS, 4) interval.elongate_tick_at(-INTERVAL_RADIUS, 4)
interval.elongate_tick_at(INTERVAL_RADIUS, 4) interval.elongate_tick_at(INTERVAL_RADIUS, 4)
zero = tex_mobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN) zero = TexMobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN)
one = tex_mobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN) one = TexMobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN)
return CompoundMobject(interval, zero, one) return CompoundMobject(interval, zero, one)
def draw_you(with_bubble = False): def draw_you(with_bubble = False):
@ -132,7 +132,7 @@ class FlipThroughNumbers(Animation):
self.start_center = start_center self.start_center = start_center
self.end_center = end_center self.end_center = end_center
self.current_number = function(start) self.current_number = function(start)
mobject = tex_mobject(str(self.current_number)).shift(start_center) mobject = TexMobject(str(self.current_number)).shift(start_center)
Animation.__init__(self, mobject, **kwargs) Animation.__init__(self, mobject, **kwargs)
def update_mobject(self, alpha): def update_mobject(self, alpha):
@ -141,7 +141,7 @@ class FlipThroughNumbers(Animation):
) )
if new_number != self.current_number: if new_number != self.current_number:
self.current_number = new_number self.current_number = new_number
self.mobject = tex_mobject(str(new_number)).shift(self.start_center) self.mobject = TexMobject(str(new_number)).shift(self.start_center)
if not all(self.start_center == self.end_center): if not all(self.start_center == self.end_center):
self.mobject.center().shift( self.mobject.center().shift(
(1-alpha)*self.start_center + alpha*self.end_center (1-alpha)*self.start_center + alpha*self.end_center
@ -154,7 +154,7 @@ class IntroduceDivergentSum(Scene):
def construct(self): def construct(self):
equation = divergent_sum().split() equation = divergent_sum().split()
sum_value = None sum_value = None
brace = underbrace( brace = Underbrace(
equation[0].get_boundary_point(DOWN+LEFT), equation[0].get_boundary_point(DOWN+LEFT),
equation[1].get_boundary_point(DOWN+RIGHT) equation[1].get_boundary_point(DOWN+RIGHT)
).shift(0.2*DOWN) ).shift(0.2*DOWN)
@ -170,7 +170,7 @@ class IntroduceDivergentSum(Scene):
brace.to_edge(LEFT, buff = SPACE_WIDTH+min_x_coord) brace.to_edge(LEFT, buff = SPACE_WIDTH+min_x_coord)
if sum_value: if sum_value:
self.remove(sum_value) self.remove(sum_value)
sum_value = tex_mobject(str(2**(x+1) - 1)) sum_value = TexMobject(str(2**(x+1) - 1))
sum_value.shift(brace.get_center() + 0.5*DOWN) sum_value.shift(brace.get_center() + 0.5*DOWN)
self.add(brace, sum_value) self.add(brace, sum_value)
self.dither(0.75) self.dither(0.75)
@ -203,9 +203,9 @@ class ClearlyNonsense(Scene):
def construct(self): def construct(self):
number_line = NumberLine().add_numbers() number_line = NumberLine().add_numbers()
div_sum = divergent_sum() div_sum = divergent_sum()
this_way = text_mobject("Sum goes this way...") this_way = TextMobject("Sum goes this way...")
this_way.to_edge(LEFT).shift(RIGHT*(SPACE_WIDTH+1) + DOWN) this_way.to_edge(LEFT).shift(RIGHT*(SPACE_WIDTH+1) + DOWN)
how_here = text_mobject("How does it end up here?") how_here = TextMobject("How does it end up here?")
how_here.shift(1.5*UP+LEFT) how_here.shift(1.5*UP+LEFT)
neg_1_arrow = Arrow( neg_1_arrow = Arrow(
(-1, 0.3, 0), (-1, 0.3, 0),
@ -237,7 +237,7 @@ class OutlineOfVideo(Scene):
def construct(self): def construct(self):
conv_sum = convergent_sum().scale(0.5) conv_sum = convergent_sum().scale(0.5)
div_sum = divergent_sum().scale(0.5) div_sum = divergent_sum().scale(0.5)
overbrace = underbrace( overbrace = Underbrace(
conv_sum.get_left(), conv_sum.get_left(),
conv_sum.get_right() conv_sum.get_right()
).rotate(np.pi, RIGHT).shift(0.75*UP*conv_sum.get_height()) ).rotate(np.pi, RIGHT).shift(0.75*UP*conv_sum.get_height())
@ -247,14 +247,14 @@ class OutlineOfVideo(Scene):
dots.get_bottom(), dots.get_bottom(),
direction = UP+LEFT direction = UP+LEFT
) )
u_brace = underbrace(div_sum.get_left(), div_sum.get_right()) u_brace = Underbrace(div_sum.get_left(), div_sum.get_right())
u_brace.shift(1.5*div_sum.get_bottom()) u_brace.shift(1.5*div_sum.get_bottom())
for mob in conv_sum, overbrace, arrow, dots: for mob in conv_sum, overbrace, arrow, dots:
mob.shift(2*UP) mob.shift(2*UP)
for mob in div_sum, u_brace: for mob in div_sum, u_brace:
mob.shift(DOWN) mob.shift(DOWN)
texts = [ texts = [
text_mobject(words).highlight("yellow") TextMobject(words).highlight("yellow")
for words in [ for words in [
"1. Discover this", "1. Discover this",
"2. Clarify what this means", "2. Clarify what this means",
@ -288,7 +288,7 @@ class OutlineOfVideo(Scene):
# # class ReasonsForMakingVideo(Scene): # # class ReasonsForMakingVideo(Scene):
# # def construct(self): # # def construct(self):
# # text = text_mobject([ # # text = TextMobject([
# # """ # # """
# # \\begin{itemize} # # \\begin{itemize}
# # \\item Understand what ``$ # # \\item Understand what ``$
@ -320,9 +320,9 @@ class OutlineOfVideo(Scene):
# class DiscoverAndDefine(Scene): # class DiscoverAndDefine(Scene):
# def construct(self): # def construct(self):
# sum_mob = tex_mobject("\\sum_{n = 1}^\\infty a_n") # sum_mob = TexMobject("\\sum_{n = 1}^\\infty a_n")
# discover = text_mobject("What does it feel like to discover these?") # discover = TextMobject("What does it feel like to discover these?")
# define = text_mobject([ # define = TextMobject([
# "What does it feel like to", # "What does it feel like to",
# "\\emph{define} ", # "\\emph{define} ",
# "them?" # "them?"
@ -341,7 +341,7 @@ class OutlineOfVideo(Scene):
class YouAsMathematician(Scene): class YouAsMathematician(Scene):
def construct(self): def construct(self):
you, bubble = draw_you(with_bubble = True) you, bubble = draw_you(with_bubble = True)
explanation = text_mobject( explanation = TextMobject(
"You as a (questionably accurate portrayal of a) mathematician.", "You as a (questionably accurate portrayal of a) mathematician.",
size = "\\small" size = "\\small"
).shift([2, you.get_center()[1], 0]) ).shift([2, you.get_center()[1], 0])
@ -473,7 +473,7 @@ class DanceDotOnInterval(Scene):
for x in LEFT, RIGHT for x in LEFT, RIGHT
] ]
color_range = Color("green").range_to("yellow", num_written_terms) color_range = Color("green").range_to("yellow", num_written_terms)
conv_sum = tex_mobject(sum_terms, size = "\\large").split() conv_sum = TexMobject(sum_terms, size = "\\large").split()
self.add(interval) self.add(interval)
self.play(*[ self.play(*[
@ -510,7 +510,7 @@ class DanceDotOnInterval(Scene):
self.dither() self.dither()
def write_partial_sums(self): def write_partial_sums(self):
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small") partial_sums = TexMobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
partial_sums.scale(1.5).to_edge(UP) partial_sums.scale(1.5).to_edge(UP)
partial_sum_parts = partial_sums.split() partial_sum_parts = partial_sums.split()
partial_sum_parts[0].highlight("yellow") partial_sum_parts[0].highlight("yellow")
@ -525,7 +525,7 @@ class DanceDotOnInterval(Scene):
class OrganizePartialSums(Scene): class OrganizePartialSums(Scene):
def construct(self): def construct(self):
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small") partial_sums = TexMobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
partial_sums.scale(1.5).to_edge(UP) partial_sums.scale(1.5).to_edge(UP)
partial_sum_parts = partial_sums.split() partial_sum_parts = partial_sums.split()
for x in [0] + range(2, len(partial_sum_parts), 4): for x in [0] + range(2, len(partial_sum_parts), 4):
@ -549,11 +549,11 @@ class OrganizePartialSums(Scene):
for mob in partial_sum_parts for mob in partial_sum_parts
if mob not in pure_sums if mob not in pure_sums
]) ])
down_arrow = tex_mobject("\\downarrow") down_arrow = TexMobject("\\downarrow")
down_arrow.to_edge(LEFT).shift(2*RIGHT+2*DOWN) down_arrow.to_edge(LEFT).shift(2*RIGHT+2*DOWN)
dots = tex_mobject("\\vdots") dots = TexMobject("\\vdots")
dots.shift(down_arrow.get_center()+down_arrow.get_height()*UP) dots.shift(down_arrow.get_center()+down_arrow.get_height()*UP)
infinite_sum = tex_mobject("".join(CONVERGENT_SUM_TEXT[:-1]), size = "\\samll") infinite_sum = TexMobject("".join(CONVERGENT_SUM_TEXT[:-1]), size = "\\samll")
infinite_sum.scale(1.5/1.25) infinite_sum.scale(1.5/1.25)
infinite_sum.to_corner(DOWN+LEFT).shift(2*RIGHT) infinite_sum.to_corner(DOWN+LEFT).shift(2*RIGHT)
@ -589,7 +589,7 @@ class SeeNumbersApproachOne(Scene):
class OneAndInfiniteSumAreTheSameThing(Scene): class OneAndInfiniteSumAreTheSameThing(Scene):
def construct(self): def construct(self):
one, equals, inf_sum = tex_mobject([ one, equals, inf_sum = TexMobject([
"1", "=", "\\sum_{n=1}^\\infty \\frac{1}{2^n}" "1", "=", "\\sum_{n=1}^\\infty \\frac{1}{2^n}"
]).split() ]).split()
point = Point(equals.get_center()).highlight("black") point = Point(equals.get_center()).highlight("black")
@ -609,12 +609,12 @@ class OneAndInfiniteSumAreTheSameThing(Scene):
class HowDoYouDefineInfiniteSums(Scene): class HowDoYouDefineInfiniteSums(Scene):
def construct(self): def construct(self):
you = draw_you().center().rewire_part_attributes() you = draw_you().center().rewire_part_attributes()
text = text_mobject( text = TextMobject(
["How", " do", " you,\\\\", "\\emph{define}"], ["How", " do", " you,\\\\", "\\emph{define}"],
size = "\\Huge" size = "\\Huge"
).shift(UP).split() ).shift(UP).split()
text[-1].shift(3*DOWN).highlight("skyblue") text[-1].shift(3*DOWN).highlight("skyblue")
sum_mob = tex_mobject("\\sum_{n=0}^\\infty{a_n}") sum_mob = TexMobject("\\sum_{n=0}^\\infty{a_n}")
text[-1].shift(LEFT) text[-1].shift(LEFT)
sum_mob.shift(text[-1].get_center()+2*RIGHT) sum_mob.shift(text[-1].get_center()+2*RIGHT)
@ -633,18 +633,18 @@ class HowDoYouDefineInfiniteSums(Scene):
class LessAboutNewThoughts(Scene): class LessAboutNewThoughts(Scene):
def construct(self): def construct(self):
words = generating, new, thoughts, to, definitions = text_mobject([ words = generating, new, thoughts, to, definitions = TextMobject([
"Generating", " new", " thoughts", "$\\rightarrow$", "Generating", " new", " thoughts", "$\\rightarrow$",
"useful definitions" "useful definitions"
], size = "\\large").split() ], size = "\\large").split()
gen_cross = tex_mobject("\\hline").highlight("red") gen_cross = TexMobject("\\hline").highlight("red")
new_cross = deepcopy(gen_cross) new_cross = deepcopy(gen_cross)
for cross, mob in [(gen_cross, generating), (new_cross, new)]: for cross, mob in [(gen_cross, generating), (new_cross, new)]:
cross.replace(mob) cross.replace(mob)
cross.stretch_to_fit_height(0.03) cross.stretch_to_fit_height(0.03)
disecting = text_mobject("Disecting").highlight("green") disecting = TextMobject("Disecting").highlight("green")
disecting.shift(generating.get_center() + 0.6*UP) disecting.shift(generating.get_center() + 0.6*UP)
old = text_mobject("old").highlight("green") old = TextMobject("old").highlight("green")
old.shift(new.get_center()+0.6*UP) old.shift(new.get_center()+0.6*UP)
kwargs = {"run_time" : 0.25} kwargs = {"run_time" : 0.25}
@ -660,7 +660,7 @@ class LessAboutNewThoughts(Scene):
class ListOfPartialSums(Scene): class ListOfPartialSums(Scene):
def construct(self): def construct(self):
all_terms = np.array(tex_mobject( all_terms = np.array(TexMobject(
ALT_PARTIAL_SUM_TEXT, ALT_PARTIAL_SUM_TEXT,
size = "\\large" size = "\\large"
).split()) ).split())
@ -739,11 +739,11 @@ class CircleZoomInOnOne(Scene):
for n in range(10) for n in range(10)
]) ])
circle = Circle().shift(2*RIGHT) circle = Circle().shift(2*RIGHT)
text = text_mobject( text = TextMobject(
"All but finitely many dots fall inside even the tiniest circle." "All but finitely many dots fall inside even the tiniest circle."
) )
numbers = map( numbers = map(
lambda s : tex_mobject("\\frac{1}{%s}"%s), lambda s : TexMobject("\\frac{1}{%s}"%s),
["100", "1,000,000", "g_{g_{64}}"] ["100", "1,000,000", "g_{g_{64}}"]
) )
for num in numbers + [text]: for num in numbers + [text]:
@ -784,7 +784,7 @@ class ZoomInOnOne(Scene):
nl_with_nums = deepcopy(number_line).add_numbers() nl_with_nums = deepcopy(number_line).add_numbers()
self.play(ApplyMethod(nl_with_nums.shift, 2*LEFT)) self.play(ApplyMethod(nl_with_nums.shift, 2*LEFT))
zero, one, two = [ zero, one, two = [
tex_mobject(str(n)).scale(0.5).shift(0.4*DOWN+2*(-1+n)*RIGHT) TexMobject(str(n)).scale(0.5).shift(0.4*DOWN+2*(-1+n)*RIGHT)
for n in 0, 1, 2 for n in 0, 1, 2
] ]
self.play( self.play(
@ -801,7 +801,7 @@ class ZoomInOnOne(Scene):
def zoom_with_numbers(self, numbers, next_numbers): def zoom_with_numbers(self, numbers, next_numbers):
all_numbers = map( all_numbers = map(
lambda (n, u): tex_mobject(str(n)).scale(0.5).shift(0.4*DOWN+2*u*RIGHT), lambda (n, u): TexMobject(str(n)).scale(0.5).shift(0.4*DOWN+2*u*RIGHT),
zip(numbers+next_numbers, it.cycle([-1, 1])) zip(numbers+next_numbers, it.cycle([-1, 1]))
) )
@ -844,7 +844,7 @@ class DefineInfiniteSum(Scene):
def put_expression_in_corner(self): def put_expression_in_corner(self):
buff = 0.24 buff = 0.24
define, infinite_sum = tex_mobject([ define, infinite_sum = TexMobject([
"\\text{\\emph{Define} }", "\\text{\\emph{Define} }",
"\\sum_{n = 0}^\\infty a_n = X" "\\sum_{n = 0}^\\infty a_n = X"
]).split() ]).split()
@ -879,10 +879,10 @@ class DefineInfiniteSum(Scene):
] ]
for n in range(num_terms) for n in range(num_terms)
]) ])
terms = tex_mobject(term_strings, size = "\\large").split() terms = TexMobject(term_strings, size = "\\large").split()
number_line = NumberLine() number_line = NumberLine()
ex_point = 2*RIGHT ex_point = 2*RIGHT
ex = tex_mobject("X").shift(ex_point + LEFT + UP) ex = TexMobject("X").shift(ex_point + LEFT + UP)
arrow = Arrow(ex_point, tail = ex.points[-1]).nudge() arrow = Arrow(ex_point, tail = ex.points[-1]).nudge()
for term, count in zip(terms, it.count()): for term, count in zip(terms, it.count()):
@ -928,7 +928,7 @@ class DefineInfiniteSum(Scene):
class YouJustInventedSomeMath(Scene): class YouJustInventedSomeMath(Scene):
def construct(self): def construct(self):
text = text_mobject([ text = TextMobject([
"You ", "just ", "invented\\\\", "some ", "math" "You ", "just ", "invented\\\\", "some ", "math"
]).split() ]).split()
for mob in text[:3]: for mob in text[:3]:
@ -959,7 +959,7 @@ class SeekMoreGeneralTruths(Scene):
"\\frac{(-1)^n}{(2n)!}", "\\frac{(-1)^n}{(2n)!}",
"\\frac{2\sqrt{2}}{99^2}\\frac{(4n)!}{(n!)^4} \\cdot \\frac{26390n + 1103}{396^{4k}}", "\\frac{2\sqrt{2}}{99^2}\\frac{(4n)!}{(n!)^4} \\cdot \\frac{26390n + 1103}{396^{4k}}",
] ]
sums = tex_mobject([ sums = TexMobject([
"&\\sum_{n = 0}^\\infty" + summand + "= ? \\\\" "&\\sum_{n = 0}^\\infty" + summand + "= ? \\\\"
for summand in summands for summand in summands
], size = "") ], size = "")
@ -984,7 +984,7 @@ class ChopIntervalInProportions(Scene):
num_terms = 2 num_terms = 2
left_terms, right_terms = [ left_terms, right_terms = [
[ [
tex_mobject("\\frac{%d}{%d}"%(k, (10**(count+1)))) TexMobject("\\frac{%d}{%d}"%(k, (10**(count+1))))
for count in range(num_terms) for count in range(num_terms)
] ]
for k in 9, 1 for k in 9, 1
@ -992,19 +992,19 @@ class ChopIntervalInProportions(Scene):
if mode == "p": if mode == "p":
num_terms = 4 num_terms = 4
prop = 0.7 prop = 0.7
left_terms = map(tex_mobject, ["(1-p)", ["p","(1-p)"]]+[ left_terms = map(TexMobject, ["(1-p)", ["p","(1-p)"]]+[
["p^%d"%(count), "(1-p)"] ["p^%d"%(count), "(1-p)"]
for count in range(2, num_terms) for count in range(2, num_terms)
]) ])
right_terms = map(tex_mobject, ["p"] + [ right_terms = map(TexMobject, ["p"] + [
["p", "^%d"%(count+1)] ["p", "^%d"%(count+1)]
for count in range(1, num_terms) for count in range(1, num_terms)
]) ])
interval = zero_to_one_interval() interval = zero_to_one_interval()
left = INTERVAL_RADIUS*LEFT left = INTERVAL_RADIUS*LEFT
right = INTERVAL_RADIUS*RIGHT right = INTERVAL_RADIUS*RIGHT
left_paren = tex_mobject("(") left_paren = TexMobject("(")
right_paren = tex_mobject(")").shift(right + 1.1*UP) right_paren = TexMobject(")").shift(right + 1.1*UP)
curr = left.astype("float") curr = left.astype("float")
brace_to_replace = None brace_to_replace = None
term_to_replace = None term_to_replace = None
@ -1015,7 +1015,7 @@ class ChopIntervalInProportions(Scene):
last = deepcopy(curr) last = deepcopy(curr)
curr += 2*RIGHT*INTERVAL_RADIUS*(1-prop)*(prop**count) curr += 2*RIGHT*INTERVAL_RADIUS*(1-prop)*(prop**count)
braces = [ braces = [
underbrace(a, b).rotate(np.pi, RIGHT) Underbrace(a, b).rotate(np.pi, RIGHT)
for a, b in [(last, curr), (curr, right)] for a, b in [(last, curr), (curr, right)]
] ]
for term, brace, count2 in zip([lt, rt], braces, it.count()): for term, brace, count2 in zip([lt, rt], braces, it.count()):
@ -1098,7 +1098,7 @@ class ChopIntervalInProportions(Scene):
brace_to_replace = braces[1] brace_to_replace = braces[1]
term_to_replace = rt term_to_replace = rt
if mode == "9": if mode == "9":
split_100 = tex_mobject("\\frac{9}{1000}+\\frac{1}{1000}") split_100 = TexMobject("\\frac{9}{1000}+\\frac{1}{1000}")
split_100.scale(0.5) split_100.scale(0.5)
split_100.shift(right_terms[-1].get_center()) split_100.shift(right_terms[-1].get_center())
split_100.to_edge(RIGHT) split_100.to_edge(RIGHT)
@ -1166,7 +1166,7 @@ class PointNineRepeating(RearrangeEquation):
4 : 4, 4 : 4,
6 : 5, 6 : 5,
} }
for term in tex_mobject(start_terms).split(): for term in TexMobject(start_terms).split():
self.add(term) self.add(term)
self.dither(0.5) self.dither(0.5)
self.clear() self.clear()
@ -1182,11 +1182,11 @@ class PointNineRepeating(RearrangeEquation):
class PlugNumbersIntoRightside(Scene): class PlugNumbersIntoRightside(Scene):
def construct(self): def construct(self):
scale_factor = 1.5 scale_factor = 1.5
lhs, rhs = tex_mobject( lhs, rhs = TexMobject(
["1 + p + p^2 + p^3 + \\cdots = ", "\\frac{1}{1-p}"], ["1 + p + p^2 + p^3 + \\cdots = ", "\\frac{1}{1-p}"],
size = "\\large" size = "\\large"
).scale(scale_factor).split() ).scale(scale_factor).split()
rhs = tex_mobject( rhs = TexMobject(
["1 \\over 1 - ", "p"], ["1 \\over 1 - ", "p"],
size = "\\large" size = "\\large"
).replace(rhs).split() ).replace(rhs).split()
@ -1195,7 +1195,7 @@ class PlugNumbersIntoRightside(Scene):
"0.2", "27", "i" "0.2", "27", "i"
] ]
nums = [ nums = [
tex_mobject(num_string, size="\\large") TexMobject(num_string, size="\\large")
for num_string in num_strings for num_string in num_strings
] ]
for num, num_string in zip(nums, num_strings): for num, num_string in zip(nums, num_strings):
@ -1205,10 +1205,10 @@ class PlugNumbersIntoRightside(Scene):
num.highlight("green") num.highlight("green")
if num_string == "(-1)": if num_string == "(-1)":
num.shift(0.3*RIGHT) num.shift(0.3*RIGHT)
right_words = text_mobject( right_words = TextMobject(
"This side makes sense for almost any value of $p$," "This side makes sense for almost any value of $p$,"
).shift(2*UP) ).shift(2*UP)
left_words = text_mobject( left_words = TextMobject(
"even if it seems like this side will not." "even if it seems like this side will not."
).shift(2*DOWN) ).shift(2*DOWN)
right_words.add(Arrow( right_words.add(Arrow(
@ -1318,11 +1318,11 @@ class ListPartialDivergentSums(Scene):
"\\\\" "\\\\"
for n in range(num_lines) for n in range(num_lines)
] ]
terms = tex_mobject( terms = TexMobject(
list(it.chain.from_iterable(zip(rhss, lhss))) + ["\\vdots&", ""], list(it.chain.from_iterable(zip(rhss, lhss))) + ["\\vdots&", ""],
size = "\\large" size = "\\large"
).shift(RIGHT).split() ).shift(RIGHT).split()
words = text_mobject("These numbers don't \\\\ approach anything") words = TextMobject("These numbers don't \\\\ approach anything")
words.to_edge(LEFT) words.to_edge(LEFT)
arrow = Arrow(3*DOWN+2*LEFT, direction = DOWN, length = 6) arrow = Arrow(3*DOWN+2*LEFT, direction = DOWN, length = 6)
@ -1339,8 +1339,8 @@ class ListPartialDivergentSums(Scene):
class NotARobot(Scene): class NotARobot(Scene):
def construct(self): def construct(self):
you = draw_you().center() you = draw_you().center()
top_words = text_mobject("You are a mathematician,") top_words = TextMobject("You are a mathematician,")
low_words = text_mobject("not a robot.") low_words = TextMobject("not a robot.")
top_words.shift(1.5*UP) top_words.shift(1.5*UP)
low_words.shift(1.5*DOWN) low_words.shift(1.5*DOWN)
@ -1361,22 +1361,22 @@ class SumPowersOfTwoAnimation(Scene):
bottom_brace_left = left + 0.3*DOWN bottom_brace_left = left + 0.3*DOWN
circle = Circle().scale(dot_width[0]/2).shift(left+dot_width/2) circle = Circle().scale(dot_width[0]/2).shift(left+dot_width/2)
curr_dots = deepcopy(dot).shift(left+1.5*dot_width+dot_buff) curr_dots = deepcopy(dot).shift(left+1.5*dot_width+dot_buff)
topbrace = underbrace(top_brace_left, right).rotate(np.pi, RIGHT) topbrace = Underbrace(top_brace_left, right).rotate(np.pi, RIGHT)
bottombrace = underbrace(bottom_brace_left, right) bottombrace = Underbrace(bottom_brace_left, right)
colors = Color("yellow").range_to("purple", iterations) colors = Color("yellow").range_to("purple", iterations)
curr_dots.highlight(colors.next()) curr_dots.highlight(colors.next())
equation = tex_mobject( equation = TexMobject(
"1+2+4+\\cdots+2^n=2^{n+1} - 1", "1+2+4+\\cdots+2^n=2^{n+1} - 1",
size = "\\Huge" size = "\\Huge"
).shift(3*UP) ).shift(3*UP)
full_top_sum = tex_mobject(["1", "+2", "+4", "+8", "+16"]).split() full_top_sum = TexMobject(["1", "+2", "+4", "+8", "+16"]).split()
self.add(equation) self.add(equation)
self.dither() self.dither()
self.add(circle, curr_dots, topbrace, bottombrace) self.add(circle, curr_dots, topbrace, bottombrace)
for n in range(1,iterations): for n in range(1,iterations):
bottom_num = tex_mobject(str(2**n)) bottom_num = TexMobject(str(2**n))
new_bottom_num = tex_mobject(str(2**(n+1))) new_bottom_num = TexMobject(str(2**(n+1)))
bottom_num.shift(bottombrace.get_center()+0.5*DOWN) bottom_num.shift(bottombrace.get_center()+0.5*DOWN)
top_sum = CompoundMobject(*full_top_sum[:n]).center() top_sum = CompoundMobject(*full_top_sum[:n]).center()
@ -1396,8 +1396,8 @@ class SumPowersOfTwoAnimation(Scene):
alt_bottom_num = deepcopy(bottom_num).shift(shift_val) alt_bottom_num = deepcopy(bottom_num).shift(shift_val)
alt_topbrace = deepcopy(alt_bottombrace).rotate(np.pi, RIGHT) alt_topbrace = deepcopy(alt_bottombrace).rotate(np.pi, RIGHT)
top_sum_end.shift(alt_topbrace.get_center()+0.5*UP) top_sum_end.shift(alt_topbrace.get_center()+0.5*UP)
new_topbrace = underbrace(top_brace_left, right).rotate(np.pi, RIGHT) new_topbrace = Underbrace(top_brace_left, right).rotate(np.pi, RIGHT)
new_bottombrace = underbrace(bottom_brace_left, right) new_bottombrace = Underbrace(bottom_brace_left, right)
new_bottom_num.shift(new_bottombrace.get_center()+0.5*DOWN) new_bottom_num.shift(new_bottombrace.get_center()+0.5*DOWN)
new_top_sum.shift(new_topbrace.get_center()+0.5*UP) new_top_sum.shift(new_topbrace.get_center()+0.5*UP)
for exp, brace in [ for exp, brace in [
@ -1446,7 +1446,7 @@ class PretendTheyDoApproachNegativeOne(RearrangeEquation):
num_lines = 6 num_lines = 6
da = "\\downarrow" da = "\\downarrow"
columns = [ columns = [
tex_mobject("\\\\".join([ TexMobject("\\\\".join([
n_func(n) n_func(n)
for n in range(num_lines) for n in range(num_lines)
]+last_bits), size = "\\Large").to_corner(UP+LEFT) ]+last_bits), size = "\\Large").to_corner(UP+LEFT)
@ -1477,15 +1477,15 @@ class DistanceBetweenRationalNumbers(Scene):
def construct(self): def construct(self):
locii = [2*LEFT, 2*RIGHT] locii = [2*LEFT, 2*RIGHT]
nums = [ nums = [
tex_mobject(s).shift(1.3*d) TexMobject(s).shift(1.3*d)
for s, d in zip(["\\frac{1}{2}", "3"], locii) for s, d in zip(["\\frac{1}{2}", "3"], locii)
] ]
arrows = [ arrows = [
Arrow(direction, tail = ORIGIN) Arrow(direction, tail = ORIGIN)
for direction in locii for direction in locii
] ]
dist = tex_mobject("\\frac{5}{2}").scale(0.5).shift(0.5*UP) dist = TexMobject("\\frac{5}{2}").scale(0.5).shift(0.5*UP)
text = text_mobject("How we define distance between rational numbers") text = TextMobject("How we define distance between rational numbers")
text.to_edge(UP) text.to_edge(UP)
self.add(text, *nums) self.add(text, *nums)
self.play(*[ShowCreation(arrow) for arrow in arrows]) self.play(*[ShowCreation(arrow) for arrow in arrows])
@ -1497,7 +1497,7 @@ class NotTheOnlyWayToOrganize(Scene):
self.play(ShowCreation(NumberLine().add_numbers())) self.play(ShowCreation(NumberLine().add_numbers()))
self.dither() self.dither()
words = "Is there any other reasonable way to organize numbers?" words = "Is there any other reasonable way to organize numbers?"
self.play(FadeIn(text_mobject(words).shift(2*UP))) self.play(FadeIn(TextMobject(words).shift(2*UP)))
self.dither() self.dither()
class DistanceIsAFunction(Scene): class DistanceIsAFunction(Scene):
@ -1517,7 +1517,7 @@ class DistanceIsAFunction(Scene):
dist_text = "random\\_dist" dist_text = "random\\_dist"
elif mode == "2adic": elif mode == "2adic":
dist_text = "2\\_adic\\_dist" dist_text = "2\\_adic\\_dist"
dist, r_paren, arg0, comma, arg1, l_paren, equals, result = text_mobject([ dist, r_paren, arg0, comma, arg1, l_paren, equals, result = TextMobject([
dist_text, "(", "000", ",", "000", ")", "=", "000" dist_text, "(", "000", ",", "000", ")", "=", "000"
]).split() ]).split()
point_origin = comma.get_center()+0.2*UP point_origin = comma.get_center()+0.2*UP
@ -1551,9 +1551,9 @@ class DistanceIsAFunction(Scene):
self.dither() self.dither()
example_mobs = [ example_mobs = [
( (
tex_mobject(tup[0]).shift(arg0.get_center()), TexMobject(tup[0]).shift(arg0.get_center()),
tex_mobject(tup[1]).shift(arg1.get_center()), TexMobject(tup[1]).shift(arg1.get_center()),
tex_mobject(tup[2]).shift(result.get_center()) TexMobject(tup[2]).shift(result.get_center())
) )
for tup in examples for tup in examples
] ]
@ -1578,13 +1578,13 @@ class DistanceIsAFunction(Scene):
class ShiftInvarianceNumberLine(Scene): class ShiftInvarianceNumberLine(Scene):
def construct(self): def construct(self):
number_line = NumberLine().add_numbers() number_line = NumberLine().add_numbers()
topbrace = underbrace(ORIGIN, 2*RIGHT).rotate(np.pi, RIGHT) topbrace = Underbrace(ORIGIN, 2*RIGHT).rotate(np.pi, RIGHT)
dist0 = text_mobject(["dist(", "$0$", ",", "$2$",")"]) dist0 = TextMobject(["dist(", "$0$", ",", "$2$",")"])
dist1 = text_mobject(["dist(", "$2$", ",", "$4$",")"]) dist1 = TextMobject(["dist(", "$2$", ",", "$4$",")"])
for dist in dist0, dist1: for dist in dist0, dist1:
dist.shift(topbrace.get_center()+0.3*UP) dist.shift(topbrace.get_center()+0.3*UP)
dist1.shift(2*RIGHT) dist1.shift(2*RIGHT)
footnote = text_mobject(""" footnote = TextMobject("""
\\begin{flushleft} \\begin{flushleft}
*yeah yeah, I know I'm still drawing them on a line, *yeah yeah, I know I'm still drawing them on a line,
but until a few minutes from now I have no other way but until a few minutes from now I have no other way
@ -1606,19 +1606,19 @@ class ShiftInvarianceNumberLine(Scene):
class NameShiftInvarianceProperty(Scene): class NameShiftInvarianceProperty(Scene):
def construct(self): def construct(self):
prop = text_mobject([ prop = TextMobject([
"dist($A$, $B$) = dist(", "dist($A$, $B$) = dist(",
"$A+x$, $B+x$", "$A+x$, $B+x$",
") \\quad for all $x$" ") \\quad for all $x$"
]) ])
mid_part = prop.split()[1] mid_part = prop.split()[1]
u_brace = underbrace( u_brace = Underbrace(
mid_part.get_boundary_point(DOWN+LEFT), mid_part.get_boundary_point(DOWN+LEFT),
mid_part.get_boundary_point(DOWN+RIGHT) mid_part.get_boundary_point(DOWN+RIGHT)
).shift(0.3*DOWN) ).shift(0.3*DOWN)
label = text_mobject("Shifted values") label = TextMobject("Shifted values")
label.shift(u_brace.get_center()+0.5*DOWN) label.shift(u_brace.get_center()+0.5*DOWN)
name = text_mobject("``Shift Invariance''") name = TextMobject("``Shift Invariance''")
name.highlight("green").to_edge(UP) name.highlight("green").to_edge(UP)
for mob in u_brace, label: for mob in u_brace, label:
mob.highlight("yellow") mob.highlight("yellow")
@ -1634,7 +1634,7 @@ class TriangleInequality(Scene):
def construct(self): def construct(self):
symbols = ["A", "B", "C"] symbols = ["A", "B", "C"]
locations = [2*(DOWN+LEFT), UP, 4*RIGHT] locations = [2*(DOWN+LEFT), UP, 4*RIGHT]
ab, plus, bc, greater_than, ac = text_mobject([ ab, plus, bc, greater_than, ac = TextMobject([
"dist($A$, $B$)", "dist($A$, $B$)",
"$+$", "$+$",
"dist($B$, $C$)", "dist($B$, $C$)",
@ -1656,7 +1656,7 @@ class TriangleInequality(Scene):
for dist, line in zip(all_dists, all_lines) for dist, line in zip(all_dists, all_lines)
] ]
for symbol, loc in zip(symbols, locations): for symbol, loc in zip(symbols, locations):
self.add(tex_mobject(symbol).shift(loc)) self.add(TexMobject(symbol).shift(loc))
self.play(ShowCreation(ac_line), FadeIn(ac_copy)) self.play(ShowCreation(ac_line), FadeIn(ac_copy))
self.dither() self.dither()
self.play(*[ self.play(*[
@ -1679,12 +1679,12 @@ class TriangleInequality(Scene):
class StruggleToFindFrameOfMind(Scene): class StruggleToFindFrameOfMind(Scene):
def construct(self): def construct(self):
you, bubble = draw_you(with_bubble = True) you, bubble = draw_you(with_bubble = True)
questions = text_mobject("???", size = "\\Huge").scale(1.5) questions = TextMobject("???", size = "\\Huge").scale(1.5)
contents = [ contents = [
tex_mobject("2, 4, 8, 16, 32, \\dots \\rightarrow 0"), TexMobject("2, 4, 8, 16, 32, \\dots \\rightarrow 0"),
text_mobject("dist(0, 2) $<$ dist(0, 64)"), TextMobject("dist(0, 2) $<$ dist(0, 64)"),
NumberLine().sort_points(lambda p : -p[1]).add( NumberLine().sort_points(lambda p : -p[1]).add(
text_mobject("Not on a line?").shift(UP) TextMobject("Not on a line?").shift(UP)
), ),
] ]
kwargs = {"run_time" : 0.5} kwargs = {"run_time" : 0.5}
@ -1759,11 +1759,11 @@ class RoomsAndSubroomsWithNumbers(Scene):
def draw_numbers(self, zero_local, zero_one_width): def draw_numbers(self, zero_local, zero_one_width):
num_numbers = 5 num_numbers = 5
zero = tex_mobject("0").shift(zero_local) zero = TexMobject("0").shift(zero_local)
self.add(zero) self.add(zero)
nums = [] nums = []
for n in range(num_numbers): for n in range(num_numbers):
num = tex_mobject(str(2**n)) num = TexMobject(str(2**n))
num.scale(1.0/(n+1)) num.scale(1.0/(n+1))
num.shift( num.shift(
zero_local+\ zero_local+\
@ -1820,7 +1820,7 @@ class RoomsAndSubroomsWithNumbers(Scene):
for mob, count in zip(new_power_mobs, it.count(1)): for mob, count in zip(new_power_mobs, it.count(1)):
self.center_in_closest_rect(mob, small_rects) self.center_in_closest_rect(mob, small_rects)
new_power_mobs[-1].shift(DOWN) new_power_mobs[-1].shift(DOWN)
dots = tex_mobject("\\vdots") dots = TexMobject("\\vdots")
dots.scale(0.5).shift(new_zero.get_center()+0.5*DOWN) dots.scale(0.5).shift(new_zero.get_center()+0.5*DOWN)
self.play( self.play(
Transform(zero, new_zero), Transform(zero, new_zero),
@ -1859,7 +1859,7 @@ class RoomsAndSubroomsWithNumbers(Scene):
ApplyMethod(mob.shift, shift_val) ApplyMethod(mob.shift, shift_val)
for mob in zero_copy, power_mob_copy for mob in zero_copy, power_mob_copy
]) ])
num_mobs[n] = tex_mobject(str(n)) num_mobs[n] = TexMobject(str(n))
num_mobs[n].scale(1.0/(power_of_divisor(n, 2)+1)) num_mobs[n].scale(1.0/(power_of_divisor(n, 2)+1))
width_ratio = max_width / num_mobs[n].get_width() width_ratio = max_width / num_mobs[n].get_width()
if width_ratio < 1: if width_ratio < 1:
@ -1882,7 +1882,7 @@ class RoomsAndSubroomsWithNumbers(Scene):
mobject.shift(diffs[np.argmin(map(np.linalg.norm, diffs))]) mobject.shift(diffs[np.argmin(map(np.linalg.norm, diffs))])
def add_negative_one(self, num_mobs): def add_negative_one(self, num_mobs):
neg_one = tex_mobject("-1").scale(0.5) neg_one = TexMobject("-1").scale(0.5)
shift_val = num_mobs[15].get_center()-neg_one.get_center() shift_val = num_mobs[15].get_center()-neg_one.get_center()
neg_one.shift(UP) neg_one.shift(UP)
self.play(ApplyMethod(neg_one.shift, shift_val)) self.play(ApplyMethod(neg_one.shift, shift_val))
@ -1897,7 +1897,7 @@ class RoomsAndSubroomsWithNumbers(Scene):
dist_string = "1" dist_string = "1"
else: else:
dist_string = "$\\frac{1}{%d}$"%(2**count) dist_string = "$\\frac{1}{%d}$"%(2**count)
text = text_mobject( text = TextMobject(
"Any of these pairs are considered to be a distance " +\ "Any of these pairs are considered to be a distance " +\
dist_string +\ dist_string +\
" away from each other" " away from each other"
@ -1934,10 +1934,10 @@ class RoomsAndSubroomsWithNumbers(Scene):
class DeduceWhereNegativeOneFalls(Scene): class DeduceWhereNegativeOneFalls(Scene):
def construct(self): def construct(self):
part0, arg0, part1, part2, arg1, part3 = text_mobject([ part0, arg0, part1, part2, arg1, part3 = TextMobject([
"dist(-1, ", "0000", ") = ", "dist(0, ", "0000", ")" "dist(-1, ", "0000", ") = ", "dist(0, ", "0000", ")"
]).scale(1.5).split() ]).scale(1.5).split()
u_brace = underbrace( u_brace = Underbrace(
part2.get_boundary_point(DOWN+LEFT), part2.get_boundary_point(DOWN+LEFT),
part3.get_boundary_point(DOWN+RIGHT) part3.get_boundary_point(DOWN+RIGHT)
).shift(0.3+DOWN) ).shift(0.3+DOWN)
@ -1947,7 +1947,7 @@ class DeduceWhereNegativeOneFalls(Scene):
texts = [ texts = [
CompoundMobject(parts[0], parts[1].highlight(color)) CompoundMobject(parts[0], parts[1].highlight(color))
for count, color in zip(it.count(), colors) for count, color in zip(it.count(), colors)
for parts in [text_mobject([ for parts in [TextMobject([
"Represented (heuristically) \\\\ by being in the same \\\\", "Represented (heuristically) \\\\ by being in the same \\\\",
(count*"sub-")+"room" (count*"sub-")+"room"
]).split()] ]).split()]
@ -1961,7 +1961,7 @@ class DeduceWhereNegativeOneFalls(Scene):
for n in range(1, 15): for n in range(1, 15):
rest_time = 0.3 + 1.0/(n+1) rest_time = 0.3 + 1.0/(n+1)
new_args = [ new_args = [
text_mobject("$%d$"%k).scale(1.5) TextMobject("$%d$"%k).scale(1.5)
for k in 2**n-1, 2**n for k in 2**n-1, 2**n
] ]
for new_arg, old_arg in zip(new_args, last_args): for new_arg, old_arg in zip(new_args, last_args):
@ -1986,7 +1986,7 @@ class DeduceWhereNegativeOneFalls(Scene):
class OtherRationalNumbers(Scene): class OtherRationalNumbers(Scene):
def construct(self): def construct(self):
import random import random
self.add(text_mobject("Where do other \\\\ rational numbers fall?")) self.add(TextMobject("Where do other \\\\ rational numbers fall?"))
pairs = [ pairs = [
(1, 2), (1, 2),
(1, 3), (1, 3),
@ -2002,17 +2002,17 @@ class OtherRationalNumbers(Scene):
3*DOWN, 3*DOWN,
] ]
for pair, locus in zip(pairs, locii): for pair, locus in zip(pairs, locii):
fraction = tex_mobject("\\frac{%d}{%d}"%pair).shift(locus) fraction = TexMobject("\\frac{%d}{%d}"%pair).shift(locus)
self.play(ShimmerIn(fraction)) self.play(ShimmerIn(fraction))
self.dither() self.dither()
class PAdicMetric(Scene): class PAdicMetric(Scene):
def construct(self): def construct(self):
p_str, text = text_mobject(["$p$", "-adic metric"]).shift(2*UP).split() p_str, text = TextMobject(["$p$", "-adic metric"]).shift(2*UP).split()
primes = [tex_mobject(str(p)) for p in [2, 3, 5, 7, 11, 13, 17, 19, 23]] primes = [TexMobject(str(p)) for p in [2, 3, 5, 7, 11, 13, 17, 19, 23]]
p_str.highlight("yellow") p_str.highlight("yellow")
colors = Color("green").range_to("skyblue", len(primes)) colors = Color("green").range_to("skyblue", len(primes))
new_numbers = text_mobject("Completely new types of numbers!") new_numbers = TextMobject("Completely new types of numbers!")
new_numbers.highlight("skyblue").shift(2.3*DOWN) new_numbers.highlight("skyblue").shift(2.3*DOWN)
arrow = Arrow(2*DOWN, tail = 1.7*UP) arrow = Arrow(2*DOWN, tail = 1.7*UP)
@ -2048,19 +2048,19 @@ class PAdicMetric(Scene):
class FuzzyDiscoveryToNewMath(Scene): class FuzzyDiscoveryToNewMath(Scene):
def construct(self): def construct(self):
fuzzy = text_mobject("Fuzzy Discovery") fuzzy = TextMobject("Fuzzy Discovery")
fuzzy.to_edge(UP).shift(SPACE_WIDTH*LEFT/2) fuzzy.to_edge(UP).shift(SPACE_WIDTH*LEFT/2)
new_math = text_mobject("New Math") new_math = TextMobject("New Math")
new_math.to_edge(UP).shift(SPACE_WIDTH*RIGHT/2) new_math.to_edge(UP).shift(SPACE_WIDTH*RIGHT/2)
lines = CompoundMobject( lines = CompoundMobject(
Line(DOWN*SPACE_HEIGHT, UP*SPACE_HEIGHT), Line(DOWN*SPACE_HEIGHT, UP*SPACE_HEIGHT),
Line(3*UP+LEFT*SPACE_WIDTH, 3*UP+RIGHT*SPACE_WIDTH) Line(3*UP+LEFT*SPACE_WIDTH, 3*UP+RIGHT*SPACE_WIDTH)
) )
fuzzy_discoveries = [ fuzzy_discoveries = [
tex_mobject("a^2 + b^2 = c^2"), TexMobject("a^2 + b^2 = c^2"),
tex_mobject("".join(CONVERGENT_SUM_TEXT)), TexMobject("".join(CONVERGENT_SUM_TEXT)),
tex_mobject("".join(DIVERGENT_SUM_TEXT)), TexMobject("".join(DIVERGENT_SUM_TEXT)),
tex_mobject("e^{\pi i} = -1"), TexMobject("e^{\pi i} = -1"),
] ]
triangle_lines = [ triangle_lines = [
Line(ORIGIN, LEFT), Line(ORIGIN, LEFT),
@ -2069,21 +2069,21 @@ class FuzzyDiscoveryToNewMath(Scene):
] ]
for line, char in zip(triangle_lines, ["a", "c", "b"]): for line, char in zip(triangle_lines, ["a", "c", "b"]):
line.highlight("blue") line.highlight("blue")
char_mob = tex_mobject(char).scale(0.25) char_mob = TexMobject(char).scale(0.25)
line.add(char_mob.shift(line.get_center())) line.add(char_mob.shift(line.get_center()))
triangle = CompoundMobject(*triangle_lines) triangle = CompoundMobject(*triangle_lines)
triangle.center().shift(1.5*fuzzy_discoveries[0].get_right()) triangle.center().shift(1.5*fuzzy_discoveries[0].get_right())
how_length = text_mobject("But how is length defined?").scale(0.5) how_length = TextMobject("But how is length defined?").scale(0.5)
how_length.shift(0.75*DOWN) how_length.shift(0.75*DOWN)
fuzzy_discoveries[0].add(triangle, how_length) fuzzy_discoveries[0].add(triangle, how_length)
new_maths = [ new_maths = [
text_mobject(""" TextMobject("""
Define distance between points $(x_0, y_0)$ and Define distance between points $(x_0, y_0)$ and
$(x_1, y_1)$ as $\\sqrt{(x_1-x_0)^2 + (y_1-y_0)^2}$ $(x_1, y_1)$ as $\\sqrt{(x_1-x_0)^2 + (y_1-y_0)^2}$
"""), """),
text_mobject("Define ``approach'' and infinite sums"), TextMobject("Define ``approach'' and infinite sums"),
text_mobject("Discover $2$-adic numbers"), TextMobject("Discover $2$-adic numbers"),
text_mobject( TextMobject(
"Realize exponentiation is doing something much \ "Realize exponentiation is doing something much \
different from repeated multiplication" different from repeated multiplication"
) )
@ -2112,13 +2112,13 @@ class FuzzyDiscoveryToNewMath(Scene):
class DiscoveryAndInvention(Scene): class DiscoveryAndInvention(Scene):
def construct(self): def construct(self):
invention, vs, discovery = text_mobject([ invention, vs, discovery = TextMobject([
"Invention ", "vs. ", "Discovery" "Invention ", "vs. ", "Discovery"
]).split() ]).split()
nrd = text_mobject( nrd = TextMobject(
"Non-rigorous truths" "Non-rigorous truths"
).shift(2*UP) ).shift(2*UP)
rt = text_mobject( rt = TextMobject(
"Rigorous terms" "Rigorous terms"
).shift(2*DOWN) ).shift(2*DOWN)

View file

@ -37,7 +37,7 @@ class SimpleText(Scene):
return initials(filter(lambda c : c in string.letters + " ", text)) return initials(filter(lambda c : c in string.letters + " ", text))
def construct(self, text): def construct(self, text):
self.add(text_mobject(text)) self.add(TextMobject(text))
class SimpleTex(Scene): class SimpleTex(Scene):
@ -56,12 +56,12 @@ class SimpleTex(Scene):
return words return words
def construct(self, expression, words): def construct(self, expression, words):
self.add(tex_mobject(expression)) self.add(TexMobject(expression))
class OneMinusOnePoem(Scene): class OneMinusOnePoem(Scene):
def construct(self): def construct(self):
verse1 = text_mobject(""" verse1 = TextMobject("""
\\begin{flushleft} \\begin{flushleft}
When one takes one from one \\\\ When one takes one from one \\\\
plus one from one plus one \\\\ plus one from one plus one \\\\
@ -75,7 +75,7 @@ class OneMinusOnePoem(Scene):
until the infinite. \\\\ until the infinite. \\\\
\\end{flushleft} \\end{flushleft}
""").scale(0.5).to_corner(UP+LEFT) """).scale(0.5).to_corner(UP+LEFT)
verse2 = text_mobject(""" verse2 = TextMobject("""
\\begin{flushleft} \\begin{flushleft}
Lest you should think that such \\\\ Lest you should think that such \\\\
less well-known sums are much \\\\ less well-known sums are much \\\\
@ -89,7 +89,7 @@ class OneMinusOnePoem(Scene):
the universe gives ``half''. \\\\ the universe gives ``half''. \\\\
\\end{flushleft} \\end{flushleft}
""").scale(0.5).to_corner(DOWN+LEFT) """).scale(0.5).to_corner(DOWN+LEFT)
equation = tex_mobject( equation = TexMobject(
"1-1+1-1+\\cdots = \\frac{1}{2}" "1-1+1-1+\\cdots = \\frac{1}{2}"
) )
self.add(verse1, verse2, equation) self.add(verse1, verse2, equation)
@ -111,7 +111,7 @@ class PowersOfTwoSmall(Scene):
class FinalSlide(Scene): class FinalSlide(Scene):
def construct(self): def construct(self):
self.add(text_mobject(""" self.add(TextMobject("""
\\begin{flushleft} \\begin{flushleft}
Needless to say, what I said here only scratches the Needless to say, what I said here only scratches the
surface of the tip of the iceberg of the p-adic metric. surface of the tip of the iceberg of the p-adic metric.

View file

@ -17,7 +17,7 @@ def matrix_to_string(matrix):
return "--".join(["-".join(map(str, row)) for row in matrix]) return "--".join(["-".join(map(str, row)) for row in matrix])
def matrix_mobject(matrix): def matrix_mobject(matrix):
return text_mobject( return TextMobject(
""" """
\\left( \\left(
\\begin{array}{%s} \\begin{array}{%s}
@ -100,7 +100,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
return (np.sin(x) + 1.2*x, y, z) return (np.sin(x) + 1.2*x, y, z)
def shift_zero((x, y, z)): def shift_zero((x, y, z)):
return (2*x+4, y, z) return (2*x+4, y, z)
self.nonlinear = text_mobject("Not a Linear Transform") self.nonlinear = TextMobject("Not a Linear Transform")
self.nonlinear.highlight(LIGHT_RED).to_edge(UP, buff = 1.5) self.nonlinear.highlight(LIGHT_RED).to_edge(UP, buff = 1.5)
pairs = [ pairs = [
(sinx_plux_x, "numbers don't remain evenly spaced"), (sinx_plux_x, "numbers don't remain evenly spaced"),
@ -118,7 +118,7 @@ class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
"density" : 5*DEFAULT_POINT_DENSITY_1D, "density" : 5*DEFAULT_POINT_DENSITY_1D,
} }
NumberLineScene.construct(self, **config) NumberLineScene.construct(self, **config)
words = text_mobject(explanation).highlight(LIGHT_RED) words = TextMobject(explanation).highlight(LIGHT_RED)
words.next_to(self.nonlinear, DOWN, buff = 0.5) words.next_to(self.nonlinear, DOWN, buff = 0.5)
self.add(words) self.add(words)
@ -300,7 +300,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
return (x+np.sin(y), y+np.cos(x), z) return (x+np.sin(y), y+np.cos(x), z)
def shift_zero((x, y, z)): def shift_zero((x, y, z)):
return (2*x + 3*y + 4, -1*x+y+2, z) return (2*x + 3*y + 4, -1*x+y+2, z)
self.nonlinear = text_mobject("Nonlinear Transform") self.nonlinear = TextMobject("Nonlinear Transform")
self.nonlinear.highlight(LIGHT_RED) self.nonlinear.highlight(LIGHT_RED)
self.nonlinear.to_edge(UP, buff = 1.5) self.nonlinear.to_edge(UP, buff = 1.5)
pairs = [ pairs = [
@ -322,7 +322,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
} }
number_plane = NumberPlane(**config) number_plane = NumberPlane(**config)
numbers = number_plane.get_coordinate_labels() numbers = number_plane.get_coordinate_labels()
words = text_mobject(explanation) words = TextMobject(explanation)
words.highlight(LIGHT_RED) words.highlight(LIGHT_RED)
words.next_to(self.nonlinear, DOWN, buff = 0.5) words.next_to(self.nonlinear, DOWN, buff = 0.5)
@ -356,7 +356,7 @@ class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
region = region_from_polygon_vertices(*vertices) region = region_from_polygon_vertices(*vertices)
image = disp.paint_region(region, color = WHITE) image = disp.paint_region(region, color = WHITE)
self.blackness = text_mobject("") self.blackness = TextMobject("")
ImageMobject.generate_points_from_image_array(self.blackness, image) ImageMobject.generate_points_from_image_array(self.blackness, image)
self.blackness.highlight(BLACK) self.blackness.highlight(BLACK)
rectangle = Rectangle(width = 7, height=1.7) rectangle = Rectangle(width = 7, height=1.7)
@ -375,7 +375,7 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
"point_thickness" : 2*DEFAULT_POINT_THICKNESS "point_thickness" : 2*DEFAULT_POINT_THICKNESS
} }
number_plane = NumberPlane(**config) number_plane = NumberPlane(**config)
phrase1, phrase2 = text_mobject([ phrase1, phrase2 = TextMobject([
"These might look like they keep lines straight...", "These might look like they keep lines straight...",
"but diagonal lines get curved" "but diagonal lines get curved"
]).to_edge(UP, buff = 1.5).split() ]).to_edge(UP, buff = 1.5).split()
@ -427,7 +427,7 @@ class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
region = region_from_polygon_vertices(*vertices) region = region_from_polygon_vertices(*vertices)
image = disp.paint_region(region, color = WHITE) image = disp.paint_region(region, color = WHITE)
self.blackness = text_mobject("") self.blackness = TextMobject("")
ImageMobject.generate_points_from_image_array(self.blackness, image) ImageMobject.generate_points_from_image_array(self.blackness, image)
self.blackness.highlight(BLACK) self.blackness.highlight(BLACK)
rectangle = Rectangle(width = 9, height=1.5) rectangle = Rectangle(width = 9, height=1.5)

View file

@ -61,7 +61,7 @@ def count_sections(*radians):
last_num = None last_num = None
for reg, count in zip(regions, it.count(1)): for reg, count in zip(regions, it.count(1)):
number = tex_mobject(str(count)).shift((RADIUS, 3, 0)) number = TexMobject(str(count)).shift((RADIUS, 3, 0))
sc.highlight_region(reg) sc.highlight_region(reg)
rt = 1.0 / (x**0.8) rt = 1.0 / (x**0.8)
sc.add(number) sc.add(number)
@ -89,7 +89,7 @@ def summarize_pattern(*radians):
new_lines = CompoundMobject(*[ new_lines = CompoundMobject(*[
Line(points[x], points[y]) for y in xrange(x) Line(points[x], points[y]) for y in xrange(x)
]) ])
num = tex_mobject(str(moser_function(x + 1))).center() num = TexMobject(str(moser_function(x + 1))).center()
sc.animate( sc.animate(
Transform(last_num, num) if last_num else ShowCreation(num), Transform(last_num, num) if last_num else ShowCreation(num),
FadeIn(new_lines), FadeIn(new_lines),
@ -127,7 +127,7 @@ def connect_points(*radians):
def interesting_problems(): def interesting_problems():
sc = Scene() sc = Scene()
locales = [(6, 2, 0), (6, -2, 0), (-5, -2, 0)] locales = [(6, 2, 0), (6, -2, 0), (-5, -2, 0)]
fermat = CompoundMobject(*tex_mobjects(["x^n","+","y^n","=","z^n"])) fermat = CompoundMobject(*TexMobjects(["x^n","+","y^n","=","z^n"]))
fermat.scale(0.5).shift((-2.5, 0.7, 0)) fermat.scale(0.5).shift((-2.5, 0.7, 0))
face = SimpleFace() face = SimpleFace()
tb = ThoughtBubble().shift((-1.5, 1, 0)) tb = ThoughtBubble().shift((-1.5, 1, 0))
@ -274,13 +274,13 @@ if __name__ == '__main__':
# summarize_pattern(*different_radians).write_to_movie("moser/PatternWithDifferentPoints") # summarize_pattern(*different_radians).write_to_movie("moser/PatternWithDifferentPoints")
#Images #Images
# tex_mobject(r""" # TexMobject(r"""
# \underbrace{1, 2, 4, 8, 16, 31, \dots}_\text{What?} # \Underbrace{1, 2, 4, 8, 16, 31, \dots}_\text{What?}
# """).save_image("moser/NumberList31") # """).save_image("moser/NumberList31")
# tex_mobject(""" # TexMobject("""
# 1, 2, 4, 8, 16, 32, 63, \dots # 1, 2, 4, 8, 16, 32, 63, \dots
# """).save_image("moser/NumberList63") # """).save_image("moser/NumberList63")
# tex_mobject(""" # TexMobject("""
# 1, 2, 4, 8, 15, \dots # 1, 2, 4, 8, 15, \dots
# """).save_image("moser/NumberList15") # """).save_image("moser/NumberList15")

View file

@ -51,7 +51,7 @@ class CircleScene(Scene):
] ]
self.dots = [Dot(point) for point in self.points] self.dots = [Dot(point) for point in self.points]
self.lines = [Line(p1, p2) for p1, p2 in it.combinations(self.points, 2)] self.lines = [Line(p1, p2) for p1, p2 in it.combinations(self.points, 2)]
self.n_equals = tex_mobject( self.n_equals = TexMobject(
"n=%d"%len(radians), "n=%d"%len(radians),
).shift((-SPACE_WIDTH+1, SPACE_HEIGHT-1.5, 0)) ).shift((-SPACE_WIDTH+1, SPACE_HEIGHT-1.5, 0))
self.add(self.circle, self.n_equals, *self.dots + self.lines) self.add(self.circle, self.n_equals, *self.dots + self.lines)
@ -149,7 +149,7 @@ class MoserPattern(CircleScene):
def __init__(self, radians, *args, **kwargs): def __init__(self, radians, *args, **kwargs):
CircleScene.__init__(self, radians, *args, **kwargs) CircleScene.__init__(self, radians, *args, **kwargs)
self.remove(*self.dots + self.lines + [self.n_equals]) self.remove(*self.dots + self.lines + [self.n_equals])
n_equals, num = tex_mobject(["n=", "10"]).split() n_equals, num = TexMobject(["n=", "10"]).split()
for mob in n_equals, num: for mob in n_equals, num:
mob.shift((-SPACE_WIDTH + 1.5, SPACE_HEIGHT - 1.5, 0)) mob.shift((-SPACE_WIDTH + 1.5, SPACE_HEIGHT - 1.5, 0))
self.add(n_equals) self.add(n_equals)
@ -157,8 +157,8 @@ class MoserPattern(CircleScene):
self.add(*self.dots[:n]) self.add(*self.dots[:n])
self.add(*[Line(p[0], p[1]) for p in it.combinations(self.points[:n], 2)]) self.add(*[Line(p[0], p[1]) for p in it.combinations(self.points[:n], 2)])
tex_stuffs = [ tex_stuffs = [
tex_mobject(str(moser_function(n))), TexMobject(str(moser_function(n))),
tex_mobject(str(n)).shift(num.get_center()) TexMobject(str(n)).shift(num.get_center())
] ]
self.add(*tex_stuffs) self.add(*tex_stuffs)
self.dither(0.5) self.dither(0.5)
@ -176,14 +176,14 @@ class HardProblemsSimplerQuestions(Scene):
fermat = dict([ fermat = dict([
( (
sym, sym,
CompoundMobject(*tex_mobjects( CompoundMobject(*TexMobjects(
["x","^"+sym,"+","y","^"+sym,"=","z","^"+sym] ["x","^"+sym,"+","y","^"+sym,"=","z","^"+sym]
)) ))
) )
for sym in ["n", "2", "3"] for sym in ["n", "2", "3"]
]) ])
# not_that_hard = text_mobject("(maybe not that hard...)").scale(0.5) # not_that_hard = TextMobject("(maybe not that hard...)").scale(0.5)
fermat2, fermat2_jargon = tex_mobject([ fermat2, fermat2_jargon = TexMobject([
r"&x^2 + y^2 = z^2 \\", r"&x^2 + y^2 = z^2 \\",
r""" r"""
&(3, 4, 5) \\ &(3, 4, 5) \\
@ -194,7 +194,7 @@ class HardProblemsSimplerQuestions(Scene):
&\quad \vdots &\quad \vdots
""" """
]).split() ]).split()
fermat3, fermat3_jargon = tex_mobject([ fermat3, fermat3_jargon = TexMobject([
r"&x^3 + y^3 = z^3\\", r"&x^3 + y^3 = z^3\\",
r""" r"""
&y^3 = (z - x)(z - \omega x)(z - \omega^2 x) \\ &y^3 = (z - x)(z - \omega x)(z - \omega^2 x) \\
@ -237,7 +237,7 @@ class HardProblemsSimplerQuestions(Scene):
circle_grid = CompoundMobject( circle_grid = CompoundMobject(
Circle(), Circle(),
Grid(radius = 2), Grid(radius = 2),
tex_mobject(r"\mathds{R}^2").shift((2, -2, 0)) TexMobject(r"\mathds{R}^2").shift((2, -2, 0))
) )
start_line = Line((-1, 0, 0), (-1, 2, 0)) start_line = Line((-1, 0, 0), (-1, 2, 0))
end_line = Line((-1, 0, 0), (-1, -2, 0)) end_line = Line((-1, 0, 0), (-1, -2, 0))
@ -246,7 +246,7 @@ class HardProblemsSimplerQuestions(Scene):
other_grid = CompoundMobject( other_grid = CompoundMobject(
Grid(radius = 2), Grid(radius = 2),
tex_mobject(r"\mathds{C}").shift((2, -2, 0)) TexMobject(r"\mathds{C}").shift((2, -2, 0))
) )
omega = np.array((0.5, 0.5*np.sqrt(3), 0)) omega = np.array((0.5, 0.5*np.sqrt(3), 0))
dots = CompoundMobject(*[ dots = CompoundMobject(*[
@ -283,9 +283,9 @@ class CountLines(CircleScene):
#TODO, Count things explicitly? #TODO, Count things explicitly?
text_center = (self.radius + 1, self.radius -1, 0) text_center = (self.radius + 1, self.radius -1, 0)
scale_factor = 0.4 scale_factor = 0.4
text = tex_mobject(r"\text{How Many Lines?}", size = r"\large") text = TexMobject(r"\text{How Many Lines?}", size = r"\large")
n = len(radians) n = len(radians)
formula, answer = tex_mobject([ formula, answer = TexMobject([
r"{%d \choose 2} = \frac{%d(%d - 1)}{2} = "%(n, n, n), r"{%d \choose 2} = \frac{%d(%d - 1)}{2} = "%(n, n, n),
str(choose(n, 2)) str(choose(n, 2))
]) ])
@ -330,9 +330,9 @@ class CountIntersectionPoints(CircleScene):
text_center = (self.radius + 0.5, self.radius -0.5, 0) text_center = (self.radius + 0.5, self.radius -0.5, 0)
size = r"\large" size = r"\large"
scale_factor = 0.4 scale_factor = 0.4
text = tex_mobject(r"\text{How Many Intersection Points?}", size = size) text = TexMobject(r"\text{How Many Intersection Points?}", size = size)
n = len(radians) n = len(radians)
formula, answer = tex_mobject([ formula, answer = TexMobject([
r"{%d \choose 4} = \frac{%d(%d - 1)(%d - 2)(%d-3)}{1\cdot 2\cdot 3 \cdot 4}="%(n, n, n, n, n), r"{%d \choose 4} = \frac{%d(%d - 1)(%d - 2)(%d-3)}{1\cdot 2\cdot 3 \cdot 4}="%(n, n, n, n, n),
str(choose(n, 4)) str(choose(n, 4))
]).split() ]).split()
@ -369,7 +369,7 @@ class NonGeneralPosition(CircleScene):
] ]
) )
center_region center_region
text = tex_mobject(r"\text{This region disappears}", size = r"\large") text = TexMobject(r"\text{This region disappears}", size = r"\large")
text.center().scale(0.5).shift((-self.radius, self.radius-0.3, 0)) text.center().scale(0.5).shift((-self.radius, self.radius-0.3, 0))
arrow = Arrow( arrow = Arrow(
point = (-0.35, -0.1, 0), point = (-0.35, -0.1, 0),
@ -417,7 +417,7 @@ class GeneralPositionRule(Scene):
for radians, words, pairs in tuples: for radians, words, pairs in tuples:
cs = CircleScene(radians) cs = CircleScene(radians)
self.add(*cs.mobjects) self.add(*cs.mobjects)
words_mob = text_mobject(words).scale(2).shift((5, 3, 0)) words_mob = TextMobject(words).scale(2).shift((5, 3, 0))
if not first_time: if not first_time:
self.add(words_mob) self.add(words_mob)
if words == "Okay": if words == "Okay":
@ -492,8 +492,8 @@ class IllustrateNChooseK(Scene):
Scene.__init__(self, *args, **kwargs) Scene.__init__(self, *args, **kwargs)
nrange = range(1, n+1) nrange = range(1, n+1)
tuples = list(it.combinations(nrange, k)) tuples = list(it.combinations(nrange, k))
nrange_mobs = tex_mobject([str(n) + r'\;' for n in nrange]).split() nrange_mobs = TexMobject([str(n) + r'\;' for n in nrange]).split()
tuple_mobs = tex_mobjects( tuple_mobs = TexMobjects(
[ [
(r'\\&' if c%(20//k) == 0 else r'\;\;') + str(p) (r'\\&' if c%(20//k) == 0 else r'\;\;') + str(p)
for p, c in zip(tuples, it.count()) for p, c in zip(tuples, it.count())
@ -515,12 +515,12 @@ class IllustrateNChooseK(Scene):
"""%(n, k, n, n, n, n) """%(n, k, n, n, n, n)
else: else:
str1 = r"{%d \choose %d} ="%(n, k) str1 = r"{%d \choose %d} ="%(n, k)
form1, count, form2 = tex_mobject([ form1, count, form2 = TexMobject([
str1, str1,
"%d"%choose(n, k), "%d"%choose(n, k),
r" \text{ total %s}"%tuple_term r" \text{ total %s}"%tuple_term
]) ])
pronunciation = text_mobject( pronunciation = TextMobject(
"(pronounced ``%d choose %d\'\')"%(n, k) "(pronounced ``%d choose %d\'\')"%(n, k)
) )
for mob in nrange_mobs: for mob in nrange_mobs:
@ -539,7 +539,7 @@ class IllustrateNChooseK(Scene):
run_time = 6.0 run_time = 6.0
frame_time = run_time / len(tuples) frame_time = run_time / len(tuples)
for tup, count in zip(tuples, it.count()): for tup, count in zip(tuples, it.count()):
count_mob = tex_mobject(str(count+1)) count_mob = TexMobject(str(count+1))
count_mob.center().shift(count_center) count_mob.center().shift(count_center)
self.add(count_mob) self.add(count_mob)
tuple_copy = CompoundMobject(*[nrange_mobs[index-1] for index in tup]) tuple_copy = CompoundMobject(*[nrange_mobs[index-1] for index in tup])
@ -582,8 +582,8 @@ class IntersectionPointCorrespondances(CircleScene):
self.dots[p] self.dots[p]
for p in indices for p in indices
] ]
line_statement = tex_mobject(r"\text{Pair of Lines}") line_statement = TexMobject(r"\text{Pair of Lines}")
dots_statement = tex_mobject(r"&\text{Quadruplet of} \\ &\text{outer dots}") dots_statement = TexMobject(r"&\text{Quadruplet of} \\ &\text{outer dots}")
for mob in line_statement, dots_statement: for mob in line_statement, dots_statement:
mob.center() mob.center()
mob.scale(0.7) mob.scale(0.7)
@ -685,7 +685,7 @@ class GraphsAndEulersFormulaJoke(Scene):
graph.filter_out(lambda (x, y, z) : abs(y) > SPACE_HEIGHT) graph.filter_out(lambda (x, y, z) : abs(y) > SPACE_HEIGHT)
self.add(axes) self.add(axes)
self.play(ShowCreation(graph), run_time = 1.0) self.play(ShowCreation(graph), run_time = 1.0)
eulers = tex_mobject("e^{\pi i} = -1").shift((0, 3, 0)) eulers = TexMobject("e^{\pi i} = -1").shift((0, 3, 0))
self.play(CounterclockwiseTransform( self.play(CounterclockwiseTransform(
deepcopy(graph), eulers deepcopy(graph), eulers
)) ))
@ -705,8 +705,8 @@ class DefiningGraph(GraphScene):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
GraphScene.__init__(self, *args, **kwargs) GraphScene.__init__(self, *args, **kwargs)
word_center = (0, 3, 0) word_center = (0, 3, 0)
vertices_word = text_mobject("``Vertices\"").shift(word_center) vertices_word = TextMobject("``Vertices\"").shift(word_center)
edges_word = text_mobject("``Edges\"").shift(word_center) edges_word = TextMobject("``Edges\"").shift(word_center)
dots, lines = self.vertices, self.edges dots, lines = self.vertices, self.edges
self.remove(*dots + lines) self.remove(*dots + lines)
all_dots = CompoundMobject(*dots) all_dots = CompoundMobject(*dots)
@ -782,7 +782,7 @@ class EulersFormula(GraphScene):
terms = "V - E + F =2".split(" ") terms = "V - E + F =2".split(" ")
form = dict([ form = dict([
(key, mob) (key, mob)
for key, mob in zip(terms, tex_mobjects(terms)) for key, mob in zip(terms, TexMobjects(terms))
]) ])
for mob in form.values(): for mob in form.values():
mob.shift((0, SPACE_HEIGHT-0.7, 0)) mob.shift((0, SPACE_HEIGHT-0.7, 0))
@ -831,7 +831,7 @@ class CannotDirectlyApplyEulerToMoser(CircleScene):
def __init__(self, radians, *args, **kwargs): def __init__(self, radians, *args, **kwargs):
CircleScene.__init__(self, radians, *args, **kwargs) CircleScene.__init__(self, radians, *args, **kwargs)
self.remove(self.n_equals) self.remove(self.n_equals)
n_equals, intersection_count = tex_mobject([ n_equals, intersection_count = TexMobject([
r"&n = %d\\"%len(radians), r"&n = %d\\"%len(radians),
r"&{%d \choose 4} = %d"%(len(radians), choose(len(radians), 4)) r"&{%d \choose 4} = %d"%(len(radians), choose(len(radians), 4))
]).split() ]).split()
@ -854,7 +854,7 @@ class CannotDirectlyApplyEulerToMoser(CircleScene):
self.play(ShowCreation(yellow_lines)) self.play(ShowCreation(yellow_lines))
self.dither() self.dither()
self.remove(yellow_lines) self.remove(yellow_lines)
cannot_intersect = text_mobject(r""" cannot_intersect = TextMobject(r"""
Euler's formula does not apply to \\ Euler's formula does not apply to \\
graphs whose edges intersect! graphs whose edges intersect!
""" """
@ -877,8 +877,8 @@ class ShowMoserGraphLines(CircleScene):
radians = list(set(map(lambda x : x%(2*np.pi), radians))) radians = list(set(map(lambda x : x%(2*np.pi), radians)))
radians.sort() radians.sort()
CircleScene.__init__(self, radians, *args, **kwargs) CircleScene.__init__(self, radians, *args, **kwargs)
n, plus_n_choose_4 = tex_mobject(["n", "+{n \\choose 4}"]).split() n, plus_n_choose_4 = TexMobject(["n", "+{n \\choose 4}"]).split()
n_choose_2, plus_2_n_choose_4, plus_n = tex_mobject([ n_choose_2, plus_2_n_choose_4, plus_n = TexMobject([
r"{n \choose 2}",r"&+2{n \choose 4}\\",r"&+n" r"{n \choose 2}",r"&+2{n \choose 4}\\",r"&+n"
]).split() ]).split()
for mob in n, plus_n_choose_4, n_choose_2, plus_2_n_choose_4, plus_n: for mob in n, plus_n_choose_4, n_choose_2, plus_2_n_choose_4, plus_n:
@ -1028,19 +1028,19 @@ class ApplyEulerToMoser(CircleScene):
equals, two, two1, n, n1, nc2, nc4, nc41] equals, two, two1, n, n1, nc2, nc4, nc41]
V[1], minus[1], E[1], plus[1], F[1], equals[1], two[1] = \ V[1], minus[1], E[1], plus[1], F[1], equals[1], two[1] = \
tex_mobject(["V", "-", "E", "+", "F", "=", "2"]).split() TexMobject(["V", "-", "E", "+", "F", "=", "2"]).split()
F[2], equals[2], E[2], minus[2], V[2], plus[2], two[2] = \ F[2], equals[2], E[2], minus[2], V[2], plus[2], two[2] = \
tex_mobject(["F", "=", "E", "-", "V", "+", "2"]).split() TexMobject(["F", "=", "E", "-", "V", "+", "2"]).split()
F[3], equals[3], E[3], minus[3], n[3], minus1[3], nc4[3], plus[3], two[3] = \ F[3], equals[3], E[3], minus[3], n[3], minus1[3], nc4[3], plus[3], two[3] = \
tex_mobject(["F", "=", "E", "-", "n", "-", r"{n \choose 4}", "+", "2"]).split() TexMobject(["F", "=", "E", "-", "n", "-", r"{n \choose 4}", "+", "2"]).split()
F[4], equals[4], nc2[4], plus1[4], two1[4], nc41[4], plus2[4], n1[4], minus[4], n[4], minus1[4], nc4[4], plus[4], two[4] = \ F[4], equals[4], nc2[4], plus1[4], two1[4], nc41[4], plus2[4], n1[4], minus[4], n[4], minus1[4], nc4[4], plus[4], two[4] = \
tex_mobject(["F", "=", r"{n \choose 2}", "+", "2", r"{n \choose 4}", "+", "n","-", "n", "-", r"{n \choose 4}", "+", "2"]).split() TexMobject(["F", "=", r"{n \choose 2}", "+", "2", r"{n \choose 4}", "+", "n","-", "n", "-", r"{n \choose 4}", "+", "2"]).split()
F[5], equals[5], nc2[5], plus1[5], two1[5], nc41[5], minus1[5], nc4[5], plus[5], two[5] = \ F[5], equals[5], nc2[5], plus1[5], two1[5], nc41[5], minus1[5], nc4[5], plus[5], two[5] = \
tex_mobject(["F", "=", r"{n \choose 2}", "+", "2", r"{n \choose 4}", "-", r"{n \choose 4}", "+", "2"]).split() TexMobject(["F", "=", r"{n \choose 2}", "+", "2", r"{n \choose 4}", "-", r"{n \choose 4}", "+", "2"]).split()
F[6], equals[6], nc2[6], plus1[6], nc4[6], plus[6], two[6] = \ F[6], equals[6], nc2[6], plus1[6], nc4[6], plus[6], two[6] = \
tex_mobject(["F", "=", r"{n \choose 2}", "+", r"{n \choose 4}", "+", "2"]).split() TexMobject(["F", "=", r"{n \choose 2}", "+", r"{n \choose 4}", "+", "2"]).split()
F[7], equals[7], two[7], plus[7], nc2[7], plus1[7], nc4[7] = \ F[7], equals[7], two[7], plus[7], nc2[7], plus1[7], nc4[7] = \
tex_mobject(["F", "=", "2", "+", r"{n \choose 2}", "+", r"{n \choose 4}"]).split() TexMobject(["F", "=", "2", "+", r"{n \choose 2}", "+", r"{n \choose 4}"]).split()
shift_val = (0, 3, 0) shift_val = (0, 3, 0)
for d in dicts: for d in dicts:
if not d: if not d:
@ -1181,7 +1181,7 @@ class ApplyEulerToMoser(CircleScene):
self.highlight_region(self.exterior, "black") self.highlight_region(self.exterior, "black")
self.remove(two[6]) self.remove(two[6])
two = two[7] two = two[7]
one = tex_mobject("1").shift(two.get_center()) one = TexMobject("1").shift(two.get_center())
two.highlight("red") two.highlight("red")
self.add(two) self.add(two)
self.play(CounterclockwiseTransform(two, one)) self.play(CounterclockwiseTransform(two, one))
@ -1198,7 +1198,7 @@ class FormulaRelatesToPowersOfTwo(Scene):
] ]
for n in [1, 2, 3, 4, 5, 10] for n in [1, 2, 3, 4, 5, 10]
] ]
everything = tex_mobjects(sum(strings, []), size = r"\large") everything = TexMobjects(sum(strings, []), size = r"\large")
scale_factor = 1 scale_factor = 1
for mob in everything: for mob in everything:
mob.scale(scale_factor) mob.scale(scale_factor)
@ -1216,7 +1216,7 @@ class FormulaRelatesToPowersOfTwo(Scene):
for s, result in zip(sums, results) for s, result in zip(sums, results)
]) ])
powers_of_two = [ powers_of_two = [
tex_mobject("2^{%d}"%(i-1) TexMobject("2^{%d}"%(i-1)
).scale(scale_factor ).scale(scale_factor
).shift(result.get_center() ).shift(result.get_center()
).highlight() ).highlight()
@ -1260,7 +1260,7 @@ class PascalRuleExample(PascalsTriangleScene):
k = randint(1, n-1) k = randint(1, n-1)
self.coords_to_mobs[n][k].highlight("green") self.coords_to_mobs[n][k].highlight("green")
self.dither() self.dither()
plus = tex_mobject("+").scale(0.5) plus = TexMobject("+").scale(0.5)
nums_above = [self.coords_to_mobs[n-1][k-1], self.coords_to_mobs[n-1][k]] nums_above = [self.coords_to_mobs[n-1][k-1], self.coords_to_mobs[n-1][k]]
plus.center().shift(sum(map(Mobject.get_center, nums_above)) / 2) plus.center().shift(sum(map(Mobject.get_center, nums_above)) / 2)
self.add(plus) self.add(plus)
@ -1298,7 +1298,7 @@ class PascalsTriangleNChooseKExample(PascalsTriangleScene):
PascalsTriangleScene.__init__(self, nrows, *args, **kwargs) PascalsTriangleScene.__init__(self, nrows, *args, **kwargs)
dither_time = 0.5 dither_time = 0.5
triangle_terms = [self.coords_to_mobs[a][b] for a, b in self.coords] triangle_terms = [self.coords_to_mobs[a][b] for a, b in self.coords]
formula_terms = left, n_mob, k_mob, right = tex_mobject([ formula_terms = left, n_mob, k_mob, right = TexMobject([
r"\left(", str(n), r"\atop %d"%k, r"\right)" r"\left(", str(n), r"\atop %d"%k, r"\right)"
]) ])
formula_center = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0) formula_center = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0)
@ -1317,7 +1317,7 @@ class PascalsTriangleNChooseKExample(PascalsTriangleScene):
self.remove(n_mob, k_mob) self.remove(n_mob, k_mob)
for a in range(n+1): for a in range(n+1):
row = [self.coords_to_mobs[a][b] for b in range(a+1)] row = [self.coords_to_mobs[a][b] for b in range(a+1)]
a_mob = tex_mobject(str(a)) a_mob = TexMobject(str(a))
a_mob.shift(n_mob.get_center()) a_mob.shift(n_mob.get_center())
a_mob.highlight("green") a_mob.highlight("green")
self.add(a_mob) self.add(a_mob)
@ -1330,7 +1330,7 @@ class PascalsTriangleNChooseKExample(PascalsTriangleScene):
self.remove(a_mob) self.remove(a_mob)
self.dither() self.dither()
for b in range(k+1): for b in range(k+1):
b_mob = tex_mobject(str(b)) b_mob = TexMobject(str(b))
b_mob.shift(k_mob.get_center()) b_mob.shift(k_mob.get_center())
b_mob.highlight("yellow") b_mob.highlight("yellow")
self.add(b_mob) self.add(b_mob)
@ -1353,7 +1353,7 @@ class PascalsTriangleSumRows(PascalsTriangleScene):
powers_of_two = [] powers_of_two = []
equalses = [] equalses = []
powers_of_two_symbols = [] powers_of_two_symbols = []
plus = tex_mobject("+") plus = TexMobject("+")
desired_plus_width = self.coords_to_mobs[0][0].get_width() desired_plus_width = self.coords_to_mobs[0][0].get_width()
if plus.get_width() > desired_plus_width: if plus.get_width() > desired_plus_width:
plus.scale(desired_plus_width / plus.get_width()) plus.scale(desired_plus_width / plus.get_width())
@ -1364,12 +1364,12 @@ class PascalsTriangleSumRows(PascalsTriangleScene):
new_plus.center().shift(self.coords_to_mobs[n][k].get_center()) new_plus.center().shift(self.coords_to_mobs[n][k].get_center())
new_plus.shift((-self.cell_width / 2.0, 0, 0)) new_plus.shift((-self.cell_width / 2.0, 0, 0))
pluses.append(new_plus) pluses.append(new_plus)
equals = tex_mobject("=") equals = TexMobject("=")
equals.scale(min(1, 0.7 * self.cell_height / equals.get_width())) equals.scale(min(1, 0.7 * self.cell_height / equals.get_width()))
for n in range(self.nrows): for n in range(self.nrows):
new_equals = deepcopy(equals) new_equals = deepcopy(equals)
pof2 = tex_mobjects(str(2**n)) pof2 = TexMobjects(str(2**n))
symbol = tex_mobject("2^{%d}"%n) symbol = TexMobject("2^{%d}"%n)
desired_center = np.array(( desired_center = np.array((
self.diagram_width / 2.0, self.diagram_width / 2.0,
self.coords_to_mobs[n][0].get_center()[1], self.coords_to_mobs[n][0].get_center()[1],
@ -1423,7 +1423,7 @@ class MoserSolutionInPascal(PascalsTriangleScene):
term_color = "green" term_color = "green"
self.generate_n_choose_k_mobs() self.generate_n_choose_k_mobs()
self.remove(*[self.coords_to_mobs[n0][k0] for n0, k0 in self.coords]) self.remove(*[self.coords_to_mobs[n0][k0] for n0, k0 in self.coords])
terms = one, plus0, n_choose_2, plus1, n_choose_4 = tex_mobject([ terms = one, plus0, n_choose_2, plus1, n_choose_4 = TexMobject([
"1", "+", r"{%d \choose 2}"%n, "+", r"{%d \choose 4}"%n "1", "+", r"{%d \choose 2}"%n, "+", r"{%d \choose 4}"%n
]).split() ]).split()
target_terms = [] target_terms = []
@ -1485,7 +1485,7 @@ class MoserSolutionInPascal(PascalsTriangleScene):
)) ))
self.remove(*above_terms) self.remove(*above_terms)
self.dither() self.dither()
terms_sum = tex_mobject(str(moser_function(n))) terms_sum = TexMobject(str(moser_function(n)))
terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0)) terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0))
terms_sum.highlight(term_color) terms_sum.highlight(term_color)
self.play(Transform(CompoundMobject(*terms), terms_sum)) self.play(Transform(CompoundMobject(*terms), terms_sum))
@ -1527,17 +1527,17 @@ class ExplainNChoose2Formula(Scene):
def __init__(self, n, a, b, *args, **kwargs): def __init__(self, n, a, b, *args, **kwargs):
Scene.__init__(self, *args, **kwargs) Scene.__init__(self, *args, **kwargs)
r_paren, a_mob, comma, b_mob, l_paren = tex_mobjects( r_paren, a_mob, comma, b_mob, l_paren = TexMobjects(
("( %d , %d )"%(a, b)).split(" ") ("( %d , %d )"%(a, b)).split(" ")
) )
parens = CompoundMobject(r_paren, comma, l_paren) parens = CompoundMobject(r_paren, comma, l_paren)
nums = [tex_mobject(str(k)) for k in range(1, n+1)] nums = [TexMobject(str(k)) for k in range(1, n+1)]
height = 1.5*nums[0].get_height() height = 1.5*nums[0].get_height()
for x in range(n): for x in range(n):
nums[x].shift((0, x*height, 0)) nums[x].shift((0, x*height, 0))
nums_compound = CompoundMobject(*nums) nums_compound = CompoundMobject(*nums)
nums_compound.shift(a_mob.get_center() - nums[0].get_center()) nums_compound.shift(a_mob.get_center() - nums[0].get_center())
n_mob, n_minus_1, over_2 = tex_mobject([ n_mob, n_minus_1, over_2 = TexMobject([
str(n), "(%d-1)"%n, r"\over{2}" str(n), "(%d-1)"%n, r"\over{2}"
]).split() ]).split()
for part in n_mob, n_minus_1, over_2: for part in n_mob, n_minus_1, over_2:
@ -1585,7 +1585,7 @@ class ExplainNChoose2Formula(Scene):
CounterclockwiseTransform(a_mob, a_copy), CounterclockwiseTransform(a_mob, a_copy),
CounterclockwiseTransform(b_mob, b_copy), CounterclockwiseTransform(b_mob, b_copy),
FadeIn(parens_copy), FadeIn(parens_copy),
FadeIn(text_mobject("is considered the same as")) FadeIn(TextMobject("is considered the same as"))
) )
class ExplainNChoose4Formula(Scene): class ExplainNChoose4Formula(Scene):
@ -1598,17 +1598,17 @@ class ExplainNChoose4Formula(Scene):
Scene.__init__(self, *args, **kwargs) Scene.__init__(self, *args, **kwargs)
# quad = list(it.combinations(range(1,n+1), 4))[randint(0, choose(n, 4)-1)] # quad = list(it.combinations(range(1,n+1), 4))[randint(0, choose(n, 4)-1)]
quad = (4, 2, 5, 1) quad = (4, 2, 5, 1)
tuple_mobs = tex_mobjects( tuple_mobs = TexMobjects(
("( %d , %d , %d , %d )"%quad).split(" ") ("( %d , %d , %d , %d )"%quad).split(" ")
) )
quad_mobs = tuple_mobs[1::2] quad_mobs = tuple_mobs[1::2]
parens = CompoundMobject(*tuple_mobs[0::2]) parens = CompoundMobject(*tuple_mobs[0::2])
form_mobs = tex_mobject([ form_mobs = TexMobject([
str(n), "(%d-1)"%n, "(%d-2)"%n,"(%d-3)"%n, str(n), "(%d-1)"%n, "(%d-2)"%n,"(%d-3)"%n,
r"\over {4 \cdot 3 \cdot 2 \cdot 1}" r"\over {4 \cdot 3 \cdot 2 \cdot 1}"
]).split() ]).split()
form_mobs = CompoundMobject(*form_mobs).scale(0.7).shift((4, 3, 0)).split() form_mobs = CompoundMobject(*form_mobs).scale(0.7).shift((4, 3, 0)).split()
nums = [tex_mobject(str(k)) for k in range(1, n+1)] nums = [TexMobject(str(k)) for k in range(1, n+1)]
height = 1.5*nums[0].get_height() height = 1.5*nums[0].get_height()
for x in range(n): for x in range(n):
nums[x].shift((0, x*height, 0)) nums[x].shift((0, x*height, 0))
@ -1643,7 +1643,7 @@ class ExplainNChoose4Formula(Scene):
]) ])
curr_num = quad[i] curr_num = quad[i]
self.remove(*self.mobjects) self.remove(*self.mobjects)
num_perms_explain = text_mobject( num_perms_explain = TextMobject(
r"There are $(4 \cdot 3 \cdot 2 \cdot 1)$ total permutations" r"There are $(4 \cdot 3 \cdot 2 \cdot 1)$ total permutations"
).shift((0, -2, 0)) ).shift((0, -2, 0))
self.add(parens, num_perms_explain, *form_mobs) self.add(parens, num_perms_explain, *form_mobs)
@ -1685,7 +1685,7 @@ class IntersectionChoppingExamples(Scene):
for pairs, exp in [(pairs1, "3 + 2(2) = 7"), for pairs, exp in [(pairs1, "3 + 2(2) = 7"),
(pairs2, "4 + 2(3) = 10")]: (pairs2, "4 + 2(3) = 10")]:
lines = [Line(*pair).scale(2) for pair in pairs] lines = [Line(*pair).scale(2) for pair in pairs]
self.add(tex_mobject(exp).shift((0, SPACE_HEIGHT-1, 0))) self.add(TexMobject(exp).shift((0, SPACE_HEIGHT-1, 0)))
self.add(*lines) self.add(*lines)
self.dither() self.dither()
self.play(*[ self.play(*[

View file

@ -12,7 +12,7 @@ from constants import *
from region import * from region import *
from scene import Scene, NumberLineScene from scene import Scene, NumberLineScene
from script_wrapper import command_line_create_scene from script_wrapper import command_line_create_scene
from inventing_math import underbrace from inventing_math import Underbrace
import random import random
@ -46,7 +46,7 @@ def rationals():
def fraction_mobject(fraction): def fraction_mobject(fraction):
n, d = fraction.numerator, fraction.denominator n, d = fraction.numerator, fraction.denominator
return tex_mobject("\\frac{%d}{%d}"%(n, d)) return TexMobject("\\frac{%d}{%d}"%(n, d))
def continued_fraction(int_list): def continued_fraction(int_list):
if len(int_list) == 1: if len(int_list) == 1:
@ -60,13 +60,13 @@ def zero_to_one_interval():
) )
interval.elongate_tick_at(-INTERVAL_RADIUS, TICK_STRETCH_FACTOR) interval.elongate_tick_at(-INTERVAL_RADIUS, TICK_STRETCH_FACTOR)
interval.elongate_tick_at(INTERVAL_RADIUS, TICK_STRETCH_FACTOR) interval.elongate_tick_at(INTERVAL_RADIUS, TICK_STRETCH_FACTOR)
interval.add(tex_mobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN)) interval.add(TexMobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN))
interval.add(tex_mobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN)) interval.add(TexMobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN))
return interval return interval
class LeftParen(Mobject): class LeftParen(Mobject):
def generate_points(self): def generate_points(self):
self.add(tex_mobject("(")) self.add(TexMobject("("))
self.center() self.center()
def get_center(self): def get_center(self):
@ -74,7 +74,7 @@ class LeftParen(Mobject):
class RightParen(Mobject): class RightParen(Mobject):
def generate_points(self): def generate_points(self):
self.add(tex_mobject(")")) self.add(TexMobject(")"))
self.center() self.center()
def get_center(self): def get_center(self):
@ -258,17 +258,17 @@ class IntervalScene(NumberLineScene):
class TwoChallenges(Scene): class TwoChallenges(Scene):
def construct(self): def construct(self):
two_challenges = text_mobject("Two Challenges", size = "\\Huge").to_edge(UP) two_challenges = TextMobject("Two Challenges", size = "\\Huge").to_edge(UP)
one, two = map(text_mobject, ["1.", "2."]) one, two = map(TextMobject, ["1.", "2."])
one.shift(UP).to_edge(LEFT) one.shift(UP).to_edge(LEFT)
two.shift(DOWN).to_edge(LEFT) two.shift(DOWN).to_edge(LEFT)
notes = ImageMobject("musical_notes").scale(0.3) notes = ImageMobject("musical_notes").scale(0.3)
notes.next_to(one) notes.next_to(one)
notes.highlight("blue") notes.highlight("blue")
measure = text_mobject("Measure Theory").next_to(two) measure = TextMobject("Measure Theory").next_to(two)
probability = text_mobject("Probability") probability = TextMobject("Probability")
probability.next_to(measure).shift(DOWN+RIGHT) probability.next_to(measure).shift(DOWN+RIGHT)
integration = tex_mobject("\\int") integration = TexMobject("\\int")
integration.next_to(measure).shift(UP+RIGHT) integration.next_to(measure).shift(UP+RIGHT)
arrow_to_prob = Arrow(measure, probability) arrow_to_prob = Arrow(measure, probability)
arrow_to_int = Arrow(measure, integration) arrow_to_int = Arrow(measure, integration)
@ -309,7 +309,7 @@ class MeasureTheoryToHarmony(IntervalScene):
class ChallengeOne(Scene): class ChallengeOne(Scene):
def construct(self): def construct(self):
title = text_mobject("Challenge #1").to_edge(UP) title = TextMobject("Challenge #1").to_edge(UP)
start_color = Color("blue") start_color = Color("blue")
colors = start_color.range_to("white", 6) colors = start_color.range_to("white", 6)
self.bottom_vibration = VibratingString( self.bottom_vibration = VibratingString(
@ -323,14 +323,14 @@ class ChallengeOne(Scene):
) )
for freq in [1, 2, 5.0/3, 4.0/3, 2] for freq in [1, 2, 5.0/3, 4.0/3, 2]
] ]
freq_220 = text_mobject("220 Hz") freq_220 = TextMobject("220 Hz")
freq_r220 = text_mobject("$r\\times$220 Hz") freq_r220 = TextMobject("$r\\times$220 Hz")
freq_330 = text_mobject("1.5$\\times$220 Hz") freq_330 = TextMobject("1.5$\\times$220 Hz")
freq_sqrt2 = text_mobject("$\\sqrt{2}\\times$220 Hz") freq_sqrt2 = TextMobject("$\\sqrt{2}\\times$220 Hz")
freq_220.shift(1.5*DOWN) freq_220.shift(1.5*DOWN)
for freq in freq_r220, freq_330, freq_sqrt2: for freq in freq_r220, freq_330, freq_sqrt2:
freq.shift(1.5*UP) freq.shift(1.5*UP)
r_constraint = tex_mobject("(1<r<2)", size = "\\large") r_constraint = TexMobject("(1<r<2)", size = "\\large")
self.add(title) self.add(title)
self.dither() self.dither()
@ -362,8 +362,8 @@ class ChallengeOne(Scene):
one, two = 2*number_line.interval_size*RIGHT, 4*number_line.interval_size*RIGHT one, two = 2*number_line.interval_size*RIGHT, 4*number_line.interval_size*RIGHT
arrow1 = Arrow(one+UP, one) arrow1 = Arrow(one+UP, one)
arrow2 = Arrow(two+UP, two) arrow2 = Arrow(two+UP, two)
r1 = tex_mobject("r").next_to(arrow1, UP) r1 = TexMobject("r").next_to(arrow1, UP)
r2 = tex_mobject("r").next_to(arrow2, UP) r2 = TexMobject("r").next_to(arrow2, UP)
kwargs = { kwargs = {
"run_time" : 5.0, "run_time" : 5.0,
"alpha_func" : there_and_back "alpha_func" : there_and_back
@ -395,10 +395,10 @@ class JustByAnalyzingTheNumber(Scene):
1.2020569031595942, 1.2020569031595942,
] ]
last = None last = None
r_equals = tex_mobject("r=").shift(2*LEFT) r_equals = TexMobject("r=").shift(2*LEFT)
self.add(r_equals) self.add(r_equals)
for num in nums: for num in nums:
mob = tex_mobject(str(num)).next_to(r_equals) mob = TexMobject(str(num)).next_to(r_equals)
mob.highlight() mob.highlight()
mob.sort_points() mob.sort_points()
if last: if last:
@ -412,23 +412,23 @@ class JustByAnalyzingTheNumber(Scene):
class QuestionAndAnswer(Scene): class QuestionAndAnswer(Scene):
def construct(self): def construct(self):
Q = text_mobject("Q:").shift(UP).to_edge(LEFT) Q = TextMobject("Q:").shift(UP).to_edge(LEFT)
A = text_mobject("A:").shift(DOWN).to_edge(LEFT) A = TextMobject("A:").shift(DOWN).to_edge(LEFT)
string1 = VibratingString(center = 3*UP, color = "blue") string1 = VibratingString(center = 3*UP, color = "blue")
string2 = VibratingString(num_periods = 2, center = 3.5*UP, color = "green") string2 = VibratingString(num_periods = 2, center = 3.5*UP, color = "green")
twotwenty = tex_mobject("220").scale(0.25).next_to(string1.mobject, LEFT) twotwenty = TexMobject("220").scale(0.25).next_to(string1.mobject, LEFT)
r220 = tex_mobject("r\\times220").scale(0.25).next_to(string2.mobject, LEFT) r220 = TexMobject("r\\times220").scale(0.25).next_to(string2.mobject, LEFT)
question = text_mobject( question = TextMobject(
"For what values of $r$ will the frequencies 220~Hz and \ "For what values of $r$ will the frequencies 220~Hz and \
$r\\times$220~Hz sound nice together?" $r\\times$220~Hz sound nice together?"
).next_to(Q) ).next_to(Q)
answer = text_mobject([ answer = TextMobject([
"When $r$ is", "When $r$ is",
"sufficiently close to", "sufficiently close to",
"a rational number" "a rational number"
], size = "\\small").scale(1.5) ], size = "\\small").scale(1.5)
answer.next_to(A) answer.next_to(A)
correction1 = text_mobject( correction1 = TextMobject(
"with sufficiently low denominator", "with sufficiently low denominator",
size = "\\small" size = "\\small"
).scale(1.5) ).scale(1.5)
@ -476,7 +476,7 @@ class PlaySimpleRatio(Scene):
if isinstance(fraction, Fraction): if isinstance(fraction, Fraction):
mob = fraction_mobject(fraction).shift(0.5*UP) mob = fraction_mobject(fraction).shift(0.5*UP)
else: else:
mob = tex_mobject("\\frac{e^\\pi - \\pi}{15} \\approx \\frac{4}{3}") mob = TexMobject("\\frac{e^\\pi - \\pi}{15} \\approx \\frac{4}{3}")
mob.shift(0.5*UP) mob.shift(0.5*UP)
self.add(mob) self.add(mob)
self.play(string1, string2) self.play(string1, string2)
@ -496,7 +496,7 @@ class DecomposeMusicalNote(Scene):
"run_time" : 4.0, "run_time" : 4.0,
"alpha_func" : None "alpha_func" : None
} }
words = text_mobject("Imagine 220 per second...") words = TextMobject("Imagine 220 per second...")
words.shift(2*UP) words.shift(2*UP)
self.add(line) self.add(line)
@ -528,7 +528,7 @@ class DecomposeTwoFrequencies(Scene):
class MostRationalsSoundBad(Scene): class MostRationalsSoundBad(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Most rational numbers sound bad!")) self.add(TextMobject("Most rational numbers sound bad!"))
class FlashOnXProximity(Animation): class FlashOnXProximity(Animation):
def __init__(self, mobject, x_val, *close_mobjects, **kwargs): def __init__(self, mobject, x_val, *close_mobjects, **kwargs):
@ -579,7 +579,7 @@ class PatternInFrequencies(Scene):
} }
self.add(big_line) self.add(big_line)
self.add(tex_mobject("%d:%d"%(num1, num2))) self.add(TexMobject("%d:%d"%(num1, num2)))
fracs = ( fracs = (
1.0/(num_top_lines-1), 1.0/(num_top_lines-1),
1.0/(num_bot_lines-1) 1.0/(num_bot_lines-1)
@ -599,18 +599,18 @@ class CompareFractionComplexity(Scene):
def construct(self): def construct(self):
fractions = [] fractions = []
for num, den in [(4, 3), (1093,826)]: for num, den in [(4, 3), (1093,826)]:
top = tex_mobject("%d \\over"%num) top = TexMobject("%d \\over"%num)
bottom = tex_mobject(str(den)).next_to(top, DOWN, buff = 0.3) bottom = TexMobject(str(den)).next_to(top, DOWN, buff = 0.3)
fractions.append(CompoundMobject(top, bottom)) fractions.append(CompoundMobject(top, bottom))
frac0 = fractions[0].shift(3*LEFT).split() frac0 = fractions[0].shift(3*LEFT).split()
frac1 = fractions[1].shift(3*RIGHT).split() frac1 = fractions[1].shift(3*RIGHT).split()
arrow1 = Arrow(UP, ORIGIN).next_to(frac0[0], UP) arrow1 = Arrow(UP, ORIGIN).next_to(frac0[0], UP)
arrow2 = Arrow(UP, ORIGIN).next_to(frac1[0], UP) arrow2 = Arrow(UP, ORIGIN).next_to(frac1[0], UP)
simple = text_mobject("Simple").next_to(arrow1, UP) simple = TextMobject("Simple").next_to(arrow1, UP)
simple.highlight("green") simple.highlight("green")
complicated = text_mobject("Complicated").next_to(arrow2, UP) complicated = TextMobject("Complicated").next_to(arrow2, UP)
complicated.highlight("red") complicated.highlight("red")
indicates = text_mobject("Indicates complexity").shift(2*DOWN) indicates = TextMobject("Indicates complexity").shift(2*DOWN)
arrow3 = Arrow(indicates.get_top(), frac0[1]) arrow3 = Arrow(indicates.get_top(), frac0[1])
arrow4 = Arrow(indicates.get_top(), frac1[1]) arrow4 = Arrow(indicates.get_top(), frac1[1])
@ -638,9 +638,9 @@ class IrrationalGang(Scene):
randy = Randolph() randy = Randolph()
randy.mouth.highlight(randy.DEFAULT_COLOR) randy.mouth.highlight(randy.DEFAULT_COLOR)
randy.sync_parts() randy.sync_parts()
sqrt13 = tex_mobject("\\sqrt{13}").shift(2*LEFT) sqrt13 = TexMobject("\\sqrt{13}").shift(2*LEFT)
sqrt13.highlight("green") sqrt13.highlight("green")
zeta3 = tex_mobject("\\zeta(3)").shift(2*RIGHT) zeta3 = TexMobject("\\zeta(3)").shift(2*RIGHT)
zeta3.highlight("grey") zeta3.highlight("grey")
eyes = CompoundMobject(*randy.eyes) eyes = CompoundMobject(*randy.eyes)
eyes.scale(0.5) eyes.scale(0.5)
@ -691,7 +691,7 @@ class PianoTuning(Scene):
semicircles.shift(0.05*RIGHT) semicircles.shift(0.05*RIGHT)
semicircles.sort_points(lambda p : p[0]) semicircles.sort_points(lambda p : p[0])
first_jump = semicircles.split()[0] first_jump = semicircles.split()[0]
twelfth_root = tex_mobject("2^{\\left(\\frac{1}{12}\\right)}") twelfth_root = TexMobject("2^{\\left(\\frac{1}{12}\\right)}")
twelfth_root.scale(0.75).next_to(first_jump, UP, buff = 1.5) twelfth_root.scale(0.75).next_to(first_jump, UP, buff = 1.5)
line = Line(twelfth_root, first_jump).highlight("grey") line = Line(twelfth_root, first_jump).highlight("grey")
self.keys = piano.split() self.keys = piano.split()
@ -720,23 +720,23 @@ class PianoTuning(Scene):
colors = list(Color("blue").range_to("yellow", 7)) colors = list(Color("blue").range_to("yellow", 7))
low = self.keys[whole_notes_to_base] low = self.keys[whole_notes_to_base]
high = self.keys[whole_notes_to_base + interval - 1] high = self.keys[whole_notes_to_base + interval - 1]
u_brace = underbrace(low.get_bottom(), high.get_bottom()) u_brace = Underbrace(low.get_bottom(), high.get_bottom())
u_brace.highlight("yellow") u_brace.highlight("yellow")
ratio = tex_mobject("2^{\\left(\\frac{%d}{12}\\right)}"%half_steps) ratio = TexMobject("2^{\\left(\\frac{%d}{12}\\right)}"%half_steps)
ratio.next_to(u_brace, DOWN, buff = 0.2) ratio.next_to(u_brace, DOWN, buff = 0.2)
semicircles = self.semicircles[half_notes_to_base:half_notes_to_base+half_steps] semicircles = self.semicircles[half_notes_to_base:half_notes_to_base+half_steps]
product = tex_mobject( product = TexMobject(
["\\left(2^{\\left(\\frac{1}{12}\\right)}\\right)"]*half_steps, ["\\left(2^{\\left(\\frac{1}{12}\\right)}\\right)"]*half_steps,
size = "\\small" size = "\\small"
).next_to(self.piano, UP, buff = 1.0) ).next_to(self.piano, UP, buff = 1.0)
approximate_form = tex_mobject("\\approx"+str(2**(float(half_steps)/12))) approximate_form = TexMobject("\\approx"+str(2**(float(half_steps)/12)))
approximate_form.scale(0.75) approximate_form.scale(0.75)
approximate_form.next_to(ratio) approximate_form.next_to(ratio)
if interval == 5: if interval == 5:
num_den = (3, 2) num_den = (3, 2)
elif interval == 4: elif interval == 4:
num_den = (4, 3) num_den = (4, 3)
should_be = text_mobject("Should be $\\frac{%d}{%d}$"%num_den) should_be = TextMobject("Should be $\\frac{%d}{%d}$"%num_den)
should_be.next_to(u_brace, DOWN) should_be.next_to(u_brace, DOWN)
self.play(ApplyMethod(low.highlight, colors[0])) self.play(ApplyMethod(low.highlight, colors[0]))
@ -776,28 +776,28 @@ class PowersOfTwelfthRoot(Scene):
9 : Fraction(5, 3), 9 : Fraction(5, 3),
10 : Fraction(16, 9), 10 : Fraction(16, 9),
} }
approx = tex_mobject("\\approx").scale(0.5) approx = TexMobject("\\approx").scale(0.5)
curr_height = max_height*UP curr_height = max_height*UP
spacing = UP*(max_height-min_height)/(len(fraction_map)-1.0) spacing = UP*(max_height-min_height)/(len(fraction_map)-1.0)
for i in range(1, num_terms+1): for i in range(1, num_terms+1):
if i not in fraction_map: if i not in fraction_map:
continue continue
term = tex_mobject("2^{\\left(\\frac{%d}{12}\\right)}"%i) term = TexMobject("2^{\\left(\\frac{%d}{12}\\right)}"%i)
term.shift(curr_height) term.shift(curr_height)
curr_height -= spacing curr_height -= spacing
term.shift(4*LEFT) term.shift(4*LEFT)
value = 2**(i/12.0) value = 2**(i/12.0)
approx_form = tex_mobject(str(value)[:10]) approx_form = TexMobject(str(value)[:10])
approx_copy = deepcopy(approx).next_to(term) approx_copy = deepcopy(approx).next_to(term)
approx_form.scale(0.5).next_to(approx_copy) approx_form.scale(0.5).next_to(approx_copy)
words = text_mobject("is close to") words = TextMobject("is close to")
words.scale(approx_form.get_height()/words.get_height()) words.scale(approx_form.get_height()/words.get_height())
words.next_to(approx_form) words.next_to(approx_form)
frac = fraction_map[i] frac = fraction_map[i]
frac_mob = tex_mobject("%d/%d"%(frac.numerator, frac.denominator)) frac_mob = TexMobject("%d/%d"%(frac.numerator, frac.denominator))
frac_mob.scale(0.5).next_to(words) frac_mob.scale(0.5).next_to(words)
percent_error = abs(100*((value - frac) / frac)) percent_error = abs(100*((value - frac) / frac))
error_string = text_mobject([ error_string = TextMobject([
"with", str(percent_error)[:4] + "\\%", "error" "with", str(percent_error)[:4] + "\\%", "error"
]) ])
error_string = error_string.split() error_string = error_string.split()
@ -813,7 +813,7 @@ class PowersOfTwelfthRoot(Scene):
class InterestingQuestion(Scene): class InterestingQuestion(Scene):
def construct(self): def construct(self):
words = text_mobject("Interesting Question:", size = "\\Huge") words = TextMobject("Interesting Question:", size = "\\Huge")
words.scale(2.0) words.scale(2.0)
self.add(words) self.add(words)
@ -824,7 +824,7 @@ class SupposeThereIsASavant(Scene):
"who finds pleasure in all pairs of " + \ "who finds pleasure in all pairs of " + \
"notes whose frequencies have a rational ratio" "notes whose frequencies have a rational ratio"
words = words.split(" ") words = words.split(" ")
word_mobs = text_mobject(words).split() word_mobs = TextMobject(words).split()
word_mobs[4].highlight() word_mobs[4].highlight()
word_mobs[5].highlight() word_mobs[5].highlight()
for word, word_mob in zip(words, word_mobs): for word, word_mob in zip(words, word_mobs):
@ -842,8 +842,8 @@ class AllValuesBetween1And2(NumberLineScene):
) )
top_arrow = Arrow(one+UP, one) top_arrow = Arrow(one+UP, one)
bot_arrow = Arrow(irr+2*DOWN, irr) bot_arrow = Arrow(irr+2*DOWN, irr)
r = tex_mobject("r").next_to(top_arrow, UP) r = TexMobject("r").next_to(top_arrow, UP)
irr_mob = tex_mobject(str(irrational)+"\\dots").next_to(bot_arrow, DOWN) irr_mob = TexMobject(str(irrational)+"\\dots").next_to(bot_arrow, DOWN)
approximations = [ approximations = [
continued_fraction(cont_frac[:k]) continued_fraction(cont_frac[:k])
@ -893,7 +893,7 @@ class AllValuesBetween1And2(NumberLineScene):
class ChallengeTwo(Scene): class ChallengeTwo(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Challenge #2")) self.add(TextMobject("Challenge #2"))
class CoveringSetsWithOpenIntervals(IntervalScene): class CoveringSetsWithOpenIntervals(IntervalScene):
def construct(self): def construct(self):
@ -903,7 +903,7 @@ class CoveringSetsWithOpenIntervals(IntervalScene):
for num in set([0.2, 0.25, 0.45, 0.6, 0.65]) for num in set([0.2, 0.25, 0.45, 0.6, 0.65])
]) ])
theorems = [ theorems = [
text_mobject(words).shift(UP) TextMobject(words).shift(UP)
for words in [ for words in [
"Heine-Borel Theorem", "Heine-Borel Theorem",
"Lebesgue's Number Lemma", "Lebesgue's Number Lemma",
@ -931,7 +931,7 @@ class DefineOpenInterval(IntervalScene):
open_interval, line = self.add_open_interval(0.5, 0.75, run_time = 1.0) open_interval, line = self.add_open_interval(0.5, 0.75, run_time = 1.0)
left, right = open_interval.get_left(), open_interval.get_right() left, right = open_interval.get_left(), open_interval.get_right()
a, less_than1, x, less_than2, b = \ a, less_than1, x, less_than2, b = \
tex_mobject(["a", "<", "x", "<", "b"]).shift(UP).split() TexMobject(["a", "<", "x", "<", "b"]).shift(UP).split()
left_arrow = Arrow(a.get_corner(DOWN+LEFT), left) left_arrow = Arrow(a.get_corner(DOWN+LEFT), left)
right_arrow = Arrow(b.get_corner(DOWN+RIGHT), right) right_arrow = Arrow(b.get_corner(DOWN+RIGHT), right)
@ -1010,15 +1010,15 @@ class SumOfIntervalsMustBeLessThan1(IntervalScene):
self.remove(line) self.remove(line)
int_copy = deepcopy(open_interval) int_copy = deepcopy(open_interval)
int_copy.scale(0.6).next_to(last_plus, buff = 0.1) int_copy.scale(0.6).next_to(last_plus, buff = 0.1)
last_plus = tex_mobject("+").scale(0.3) last_plus = TexMobject("+").scale(0.3)
last_plus.next_to(int_copy, buff = 0.1) last_plus.next_to(int_copy, buff = 0.1)
anims.append(Transform(open_interval, int_copy)) anims.append(Transform(open_interval, int_copy))
if num < 1.0: if num < 1.0:
anims.append(FadeIn(last_plus)) anims.append(FadeIn(last_plus))
less_than1 = tex_mobject("<1").scale(0.5) less_than1 = TexMobject("<1").scale(0.5)
less_than1.next_to(int_copy) less_than1.next_to(int_copy)
dots = tex_mobject("\\dots").replace(int_copy) dots = TexMobject("\\dots").replace(int_copy)
words = text_mobject("Use infinitely many intervals") words = TextMobject("Use infinitely many intervals")
words.shift(UP) words.shift(UP)
self.dither() self.dither()
@ -1032,7 +1032,7 @@ class SumOfIntervalsMustBeLessThan1(IntervalScene):
class RationalsAreDense(IntervalScene): class RationalsAreDense(IntervalScene):
def construct(self): def construct(self):
IntervalScene.construct(self) IntervalScene.construct(self)
words = text_mobject(["Rationals are", "\\emph{dense}", "in the reals"]) words = TextMobject(["Rationals are", "\\emph{dense}", "in the reals"])
words.shift(2*UP) words.shift(2*UP)
words = words.split() words = words.split()
words[1].highlight() words[1].highlight()
@ -1057,12 +1057,12 @@ class RationalsAreDense(IntervalScene):
class SurelyItsImpossible(Scene): class SurelyItsImpossible(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Surely it's impossible!")) self.add(TextMobject("Surely it's impossible!"))
class HowCanYouNotCoverEntireInterval(IntervalScene): class HowCanYouNotCoverEntireInterval(IntervalScene):
def construct(self): def construct(self):
IntervalScene.construct(self) IntervalScene.construct(self)
small_words = text_mobject(""" small_words = TextMobject("""
In case you are wondering, it is indeed true In case you are wondering, it is indeed true
that if you cover all real numbers between 0 that if you cover all real numbers between 0
and 1 with a set of open intervals, the sum and 1 with a set of open intervals, the sum
@ -1072,7 +1072,7 @@ class HowCanYouNotCoverEntireInterval(IntervalScene):
it for yourself! it for yourself!
""") """)
small_words.scale(0.5).to_corner(UP+RIGHT) small_words.scale(0.5).to_corner(UP+RIGHT)
big_words = text_mobject(""" big_words = TextMobject("""
Covering all numbers from 0 to 1 \\emph{will} Covering all numbers from 0 to 1 \\emph{will}
force the sum of the lengths of your intervals force the sum of the lengths of your intervals
to be at least 1. to be at least 1.
@ -1105,8 +1105,8 @@ class HowCanYouNotCoverEntireInterval(IntervalScene):
class PauseNow(Scene): class PauseNow(Scene):
def construct(self): def construct(self):
top_words = text_mobject("Try for yourself!").scale(2).shift(3*UP) top_words = TextMobject("Try for yourself!").scale(2).shift(3*UP)
bot_words = text_mobject(""" bot_words = TextMobject("""
If you've never seen this before, you will get If you've never seen this before, you will get
the most out of the solution and the intuitions the most out of the solution and the intuitions
I illustrate only after pulling out a pencil and I illustrate only after pulling out a pencil and
@ -1118,7 +1118,7 @@ class StepsToSolution(IntervalScene):
def construct(self): def construct(self):
IntervalScene.construct(self) IntervalScene.construct(self)
self.spacing = 0.7 self.spacing = 0.7
steps = map(text_mobject, [ steps = map(TextMobject, [
"Enumerate all rationals in (0, 1)", "Enumerate all rationals in (0, 1)",
"Assign one interval to each rational", "Assign one interval to each rational",
"Choose sum of the form $\\mathlarger{\\sum}_{n=1}^\\infty a_n = 1$", "Choose sum of the form $\\mathlarger{\\sum}_{n=1}^\\infty a_n = 1$",
@ -1159,7 +1159,7 @@ class StepsToSolution(IntervalScene):
mob_copy = deepcopy(mob).center() mob_copy = deepcopy(mob).center()
mob_copy.shift((2.4-mob_copy.get_bottom()[1])*UP) mob_copy.shift((2.4-mob_copy.get_bottom()[1])*UP)
mob_copy.shift((-SPACE_WIDTH+self.spacing*count)*RIGHT) mob_copy.shift((-SPACE_WIDTH+self.spacing*count)*RIGHT)
comma = text_mobject(",").next_to(mob_copy, buff = 0.1, aligned_edge = DOWN) comma = TextMobject(",").next_to(mob_copy, buff = 0.1, aligned_edge = DOWN)
anims.append(Transform(mob, mob_copy)) anims.append(Transform(mob, mob_copy))
commas.add(comma) commas.add(comma)
anims.append(ShimmerIn(commas)) anims.append(ShimmerIn(commas))
@ -1215,24 +1215,24 @@ class StepsToSolution(IntervalScene):
scale_val = 0.6 scale_val = 0.6
plus = None plus = None
for count in range(1, 10): for count in range(1, 10):
frac_bottom = tex_mobject("\\over %d"%(2**count)) frac_bottom = TexMobject("\\over %d"%(2**count))
frac_bottom.scale(scale_val) frac_bottom.scale(scale_val)
one = tex_mobject("1").scale(scale_val) one = TexMobject("1").scale(scale_val)
one.next_to(frac_bottom, UP, buff = 0.1) one.next_to(frac_bottom, UP, buff = 0.1)
compound = CompoundMobject(frac_bottom, one) compound = CompoundMobject(frac_bottom, one)
if plus: if plus:
compound.next_to(plus) compound.next_to(plus)
else: else:
compound.to_edge(LEFT) compound.to_edge(LEFT)
plus = tex_mobject("+").scale(scale_val) plus = TexMobject("+").scale(scale_val)
plus.next_to(compound) plus.next_to(compound)
frac_bottom, one = compound.split() frac_bottom, one = compound.split()
self.ones.append(one) self.ones.append(one)
self.add(frac_bottom, one, plus) self.add(frac_bottom, one, plus)
self.dither(0.2) self.dither(0.2)
dots = tex_mobject("\\dots").scale(scale_val).next_to(plus) dots = TexMobject("\\dots").scale(scale_val).next_to(plus)
arrow = Arrow(ORIGIN, RIGHT).next_to(dots) arrow = Arrow(ORIGIN, RIGHT).next_to(dots)
one = tex_mobject("1").next_to(arrow) one = TexMobject("1").next_to(arrow)
self.ones.append(one) self.ones.append(one)
self.play(*[ShowCreation(mob) for mob in dots, arrow, one]) self.play(*[ShowCreation(mob) for mob in dots, arrow, one])
self.dither() self.dither()
@ -1241,7 +1241,7 @@ class StepsToSolution(IntervalScene):
self.play(*[ self.play(*[
CounterclockwiseTransform( CounterclockwiseTransform(
one, one,
tex_mobject("\\epsilon").replace(one) TexMobject("\\epsilon").replace(one)
) )
for one in self.ones for one in self.ones
]) ])
@ -1259,11 +1259,11 @@ class StepsToSolution(IntervalScene):
class OurSumCanBeArbitrarilySmall(Scene): class OurSumCanBeArbitrarilySmall(Scene):
def construct(self): def construct(self):
step_size = 0.01 step_size = 0.01
epsilon = tex_mobject("\\epsilon") epsilon = TexMobject("\\epsilon")
equals = tex_mobject("=").next_to(epsilon) equals = TexMobject("=").next_to(epsilon)
self.add(epsilon, equals) self.add(epsilon, equals)
for num in np.arange(1, 0, -step_size): for num in np.arange(1, 0, -step_size):
parts = map(tex_mobject, str(num)) parts = map(TexMobject, str(num))
parts[0].next_to(equals) parts[0].next_to(equals)
for i in range(1, len(parts)): for i in range(1, len(parts)):
parts[i].next_to(parts[i-1], buff = 0.1, aligned_edge = DOWN) parts[i].next_to(parts[i-1], buff = 0.1, aligned_edge = DOWN)
@ -1272,7 +1272,7 @@ class OurSumCanBeArbitrarilySmall(Scene):
self.remove(*parts) self.remove(*parts)
self.dither() self.dither()
self.clear() self.clear()
words = text_mobject([ words = TextMobject([
"Not only can the sum be $< 1$,\\\\", "Not only can the sum be $< 1$,\\\\",
"it can be \\emph{arbitrarily small} !" "it can be \\emph{arbitrarily small} !"
]).split() ]).split()
@ -1283,13 +1283,13 @@ class OurSumCanBeArbitrarilySmall(Scene):
class ProofDoesNotEqualIntuition(Scene): class ProofDoesNotEqualIntuition(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Proof $\\ne$ Intuition")) self.add(TextMobject("Proof $\\ne$ Intuition"))
class StillFeelsCounterintuitive(IntervalScene): class StillFeelsCounterintuitive(IntervalScene):
def construct(self): def construct(self):
IntervalScene.construct(self) IntervalScene.construct(self)
ticks = self.add_fraction_ticks(run_time = 1.0) ticks = self.add_fraction_ticks(run_time = 1.0)
epsilon, equals, num = map(tex_mobject, ["\\epsilon", "=", "0.3"]) epsilon, equals, num = map(TexMobject, ["\\epsilon", "=", "0.3"])
epsilon.shift(2*UP) epsilon.shift(2*UP)
equals.next_to(epsilon) equals.next_to(epsilon)
num.next_to(equals) num.next_to(equals)
@ -1303,11 +1303,11 @@ class StillFeelsCounterintuitive(IntervalScene):
class VisualIntuition(Scene): class VisualIntuition(Scene):
def construct(self): def construct(self):
self.add(text_mobject("Visual Intuition:")) self.add(TextMobject("Visual Intuition:"))
class SideNote(Scene): class SideNote(Scene):
def construct(self): def construct(self):
self.add(text_mobject("(Brief Sidenote)")) self.add(TextMobject("(Brief Sidenote)"))
class TroubleDrawingSmallInterval(IntervalScene): class TroubleDrawingSmallInterval(IntervalScene):
def construct(self): def construct(self):
@ -1319,7 +1319,7 @@ class TroubleDrawingSmallInterval(IntervalScene):
shrunk = deepcopy(big).scale_in_place(0.01/0.5) shrunk = deepcopy(big).scale_in_place(0.01/0.5)
self.clear() self.clear()
IntervalScene.construct(self) IntervalScene.construct(self)
words = text_mobject("This tiny stretch") words = TextMobject("This tiny stretch")
words.shift(2*UP+2*LEFT) words.shift(2*UP+2*LEFT)
arrow = Arrow(words, line) arrow = Arrow(words, line)
@ -1344,20 +1344,20 @@ class TroubleDrawingSmallInterval(IntervalScene):
class WhatDoesItLookLikeToBeOutside(Scene): class WhatDoesItLookLikeToBeOutside(Scene):
def construct(self): def construct(self):
self.add(text_mobject( self.add(TextMobject(
"What does it look like for a number to be outside a dense set of intervals?" "What does it look like for a number to be outside a dense set of intervals?"
)) ))
class ZoomInOnSqrt2Over2(IntervalScene): class ZoomInOnSqrt2Over2(IntervalScene):
def construct(self): def construct(self):
IntervalScene.construct(self) IntervalScene.construct(self)
epsilon, equals, num = map(tex_mobject, ["\\epsilon", "=", "0.3"]) epsilon, equals, num = map(TexMobject, ["\\epsilon", "=", "0.3"])
equals.next_to(epsilon) equals.next_to(epsilon)
num.next_to(equals) num.next_to(equals)
self.add(CompoundMobject(epsilon, equals, num).center().shift(2*UP)) self.add(CompoundMobject(epsilon, equals, num).center().shift(2*UP))
intervals, lines = self.cover_fractions() intervals, lines = self.cover_fractions()
self.remove(*lines) self.remove(*lines)
irr = tex_mobject("\\frac{\\sqrt{2}}{2}") irr = TexMobject("\\frac{\\sqrt{2}}{2}")
point = self.number_line.number_to_point(np.sqrt(2)/2) point = self.number_line.number_to_point(np.sqrt(2)/2)
arrow = Arrow(point+UP, point) arrow = Arrow(point+UP, point)
irr.next_to(arrow, UP) irr.next_to(arrow, UP)
@ -1372,9 +1372,9 @@ class ZoomInOnSqrt2Over2(IntervalScene):
class NotCoveredMeansCacophonous(Scene): class NotCoveredMeansCacophonous(Scene):
def construct(self): def construct(self):
statement1 = text_mobject("$\\frac{\\sqrt{2}}{2}$ is not covered") statement1 = TextMobject("$\\frac{\\sqrt{2}}{2}$ is not covered")
implies = tex_mobject("\\Rightarrow") implies = TexMobject("\\Rightarrow")
statement2 = text_mobject("Rationals which are close to $\\frac{\\sqrt{2}}{2}$ must have large denominators") statement2 = TextMobject("Rationals which are close to $\\frac{\\sqrt{2}}{2}$ must have large denominators")
statement1.to_edge(LEFT) statement1.to_edge(LEFT)
implies.next_to(statement1) implies.next_to(statement1)
statement2.next_to(implies) statement2.next_to(implies)
@ -1401,7 +1401,7 @@ class ShiftSetupByOne(IntervalScene):
self.add(new_interval) self.add(new_interval)
self.number_line.add_numbers(0) self.number_line.add_numbers(0)
self.remove(*self.number_mobs) self.remove(*self.number_mobs)
epsilon_mob = tex_mobject("\\epsilon = 0.01").to_edge(UP) epsilon_mob = TexMobject("\\epsilon = 0.01").to_edge(UP)
self.add(epsilon_mob) self.add(epsilon_mob)
fraction_ticks = self.add_fraction_ticks() fraction_ticks = self.add_fraction_ticks()
self.remove(fraction_ticks) self.remove(fraction_ticks)
@ -1438,7 +1438,7 @@ class ShiftSetupByOne(IntervalScene):
]) ])
self.number_line = new_interval self.number_line = new_interval
self.dither() self.dither()
words = text_mobject( words = TextMobject(
"Almost all the covered numbers are harmonious!", "Almost all the covered numbers are harmonious!",
size = "\\small" size = "\\small"
).shift(2*UP) ).shift(2*UP)
@ -1447,20 +1447,20 @@ class ShiftSetupByOne(IntervalScene):
for num in [7, 5]: for num in [7, 5]:
point = self.number_line.number_to_point(2**(num/12.)) point = self.number_line.number_to_point(2**(num/12.))
arrow = Arrow(point+DOWN, point) arrow = Arrow(point+DOWN, point)
mob = tex_mobject( mob = TexMobject(
"2^{\\left(\\frac{%d}{12}\\right)}"%num "2^{\\left(\\frac{%d}{12}\\right)}"%num
).next_to(arrow, DOWN) ).next_to(arrow, DOWN)
self.play(ShimmerIn(mob), ShowCreation(arrow)) self.play(ShimmerIn(mob), ShowCreation(arrow))
self.dither() self.dither()
self.remove(mob, arrow) self.remove(mob, arrow)
self.remove(words) self.remove(words)
words = text_mobject( words = TextMobject(
"Cacophonous covered numbers:", "Cacophonous covered numbers:",
size = "\\small" size = "\\small"
) )
words.shift(2*UP) words.shift(2*UP)
answer1 = text_mobject("Complicated rationals,", size = "\\small") answer1 = TextMobject("Complicated rationals,", size = "\\small")
answer2 = text_mobject( answer2 = TextMobject(
"real numbers \\emph{very very very} close to them", "real numbers \\emph{very very very} close to them",
size = "\\small" size = "\\small"
) )
@ -1476,7 +1476,7 @@ class ShiftSetupByOne(IntervalScene):
self.add(answer2) self.add(answer2)
self.dither() self.dither()
self.remove(words, answer1, answer2) self.remove(words, answer1, answer2)
words = text_mobject([ words = TextMobject([
"To a", "savant,", "harmonious numbers could be ", "To a", "savant,", "harmonious numbers could be ",
"\\emph{precisely}", "those 1\\% covered by the intervals" "\\emph{precisely}", "those 1\\% covered by the intervals"
]).shift(2*UP) ]).shift(2*UP)
@ -1503,9 +1503,9 @@ class FinalEquivalence(IntervalScene):
interval.scale_in_place(2.0/frac.denominator) interval.scale_in_place(2.0/frac.denominator)
self.remove(*intervals+lines) self.remove(*intervals+lines)
intervals = CompoundMobject(*intervals) intervals = CompoundMobject(*intervals)
arrow = tex_mobject("\\Leftrightarrow") arrow = TexMobject("\\Leftrightarrow")
top_words = text_mobject("Harmonious numbers are rare,") top_words = TextMobject("Harmonious numbers are rare,")
bot_words = text_mobject("even for the savant") bot_words = TextMobject("even for the savant")
bot_words.highlight().next_to(top_words, DOWN) bot_words.highlight().next_to(top_words, DOWN)
words = CompoundMobject(top_words, bot_words) words = CompoundMobject(top_words, bot_words)
words.next_to(arrow) words.next_to(arrow)

View file

@ -187,7 +187,7 @@ class ShowCounting(SceneFromVideo):
total_time = len(self.frames)*self.frame_duration total_time = len(self.frames)*self.frame_duration
for count in range(32): for count in range(32):
print count print count
mob = tex_mobject(str(count)).scale(1.5) mob = TexMobject(str(count)).scale(1.5)
mob.shift(0.3*LEFT).to_edge(UP, buff = 0.1) mob.shift(0.3*LEFT).to_edge(UP, buff = 0.1)
index_range = range( index_range = range(
max(COUNT_TO_FRAME_NUM[count]-10, 0), max(COUNT_TO_FRAME_NUM[count]-10, 0),
@ -212,7 +212,7 @@ class ShowFrameNum(SceneFromVideo):
for frame, count in zip(self.frames, it.count()): for frame, count in zip(self.frames, it.count()):
print count, "of", len(self.frames) print count, "of", len(self.frames)
mob = CompoundMobject(*[ mob = CompoundMobject(*[
tex_mobject(char).shift(0.3*x*RIGHT) TexMobject(char).shift(0.3*x*RIGHT)
for char, x, in zip(str(count), it.count()) for char, x, in zip(str(count), it.count())
]) ])
self.frames[count] = disp.paint_mobject( self.frames[count] = disp.paint_mobject(

View file

@ -47,7 +47,7 @@ class Triangle(Polygon):
return self return self
def add_letter(self, char, nudge = 0.3): def add_letter(self, char, nudge = 0.3):
mob = tex_mobject(char).scale(TEX_MOB_SCALE_VAL) mob = TexMobject(char).scale(TEX_MOB_SCALE_VAL)
if char == "a": if char == "a":
points = self.get_vertices()[[0, 2, 1]] points = self.get_vertices()[[0, 2, 1]]
elif char == "b": elif char == "b":
@ -89,7 +89,7 @@ def c_square(**kwargs):
class DrawPointsReference(Scene): class DrawPointsReference(Scene):
def construct(self): def construct(self):
for point, count in zip(POINTS, it.count()): for point, count in zip(POINTS, it.count()):
mob = tex_mobject(str(count)).scale(TEX_MOB_SCALE_VAL) mob = TexMobject(str(count)).scale(TEX_MOB_SCALE_VAL)
mob.shift(POINTS[count]) mob.shift(POINTS[count])
self.add(mob) self.add(mob)
@ -104,7 +104,7 @@ class DrawAllThreeSquares(Scene):
c = c_square() c = c_square()
self.add(Triangle(), a, b, c) self.add(Triangle(), a, b, c)
for letter, mob in zip("abc", [a, b, c]): for letter, mob in zip("abc", [a, b, c]):
char_mob = tex_mobject(letter+"^2").scale(TEX_MOB_SCALE_VAL) char_mob = TexMobject(letter+"^2").scale(TEX_MOB_SCALE_VAL)
char_mob.shift(mob.get_center()) char_mob.shift(mob.get_center())
self.add(char_mob) self.add(char_mob)
@ -230,13 +230,13 @@ class ShowBigRectangleDimensions(DrawAllThreeSquaresWithMoreTriangles):
args_list = [(10, False)] args_list = [(10, False)]
def construct(self, num, fill): def construct(self, num, fill):
DrawAllThreeSquaresWithMoreTriangles.construct(self, num, fill) DrawAllThreeSquaresWithMoreTriangles.construct(self, num, fill)
u_brace = underbrace((-3, -2, 0), (4, -2, 0)) u_brace = Underbrace((-3, -2, 0), (4, -2, 0))
side_brace = underbrace((-3, -3, 0), (2, -3, 0)) side_brace = Underbrace((-3, -3, 0), (2, -3, 0))
for brace in u_brace, side_brace: for brace in u_brace, side_brace:
brace.shift(0.2*DOWN) brace.shift(0.2*DOWN)
side_brace.rotate(-np.pi/2) side_brace.rotate(-np.pi/2)
a_plus_2b = tex_mobject("a+2b").scale(TEX_MOB_SCALE_VAL) a_plus_2b = TexMobject("a+2b").scale(TEX_MOB_SCALE_VAL)
b_plus_2a = tex_mobject("b+2a").scale(TEX_MOB_SCALE_VAL) b_plus_2a = TexMobject("b+2a").scale(TEX_MOB_SCALE_VAL)
a_plus_2b.next_to(u_brace, DOWN) a_plus_2b.next_to(u_brace, DOWN)
b_plus_2a.next_to(side_brace, LEFT) b_plus_2a.next_to(side_brace, LEFT)
self.add_local_mobjects() self.add_local_mobjects()
@ -263,7 +263,7 @@ class DrawOnlyABSquares(Scene):
a = a_square() a = a_square()
b = b_square() b = b_square()
for char, mob in zip("ab", [a, b]): for char, mob in zip("ab", [a, b]):
symobl = tex_mobject(char+"^2").scale(TEX_MOB_SCALE_VAL) symobl = TexMobject(char+"^2").scale(TEX_MOB_SCALE_VAL)
symobl.shift(mob.get_center()) symobl.shift(mob.get_center())
self.add(symobl) self.add(symobl)
triangle = Triangle() triangle = Triangle()
@ -394,8 +394,8 @@ class ZoomInOnTroublePoint(Scene):
for mob in self.mobjects: for mob in self.mobjects:
mob.rotate(np.pi/2) mob.rotate(np.pi/2)
if with_labels: if with_labels:
alpha = tex_mobject("\\alpha").scale(TEX_MOB_SCALE_VAL) alpha = TexMobject("\\alpha").scale(TEX_MOB_SCALE_VAL)
beta = tex_mobject("90-\\alpha").scale(TEX_MOB_SCALE_VAL) beta = TexMobject("90-\\alpha").scale(TEX_MOB_SCALE_VAL)
if rotate: if rotate:
alpha.next_to(angle1_arc, UP+0.1*LEFT) alpha.next_to(angle1_arc, UP+0.1*LEFT)
beta.next_to(angle2_arc, DOWN+0.5*LEFT) beta.next_to(angle2_arc, DOWN+0.5*LEFT)
@ -427,8 +427,8 @@ class DrawTriangleWithAngles(Scene):
angle2_arc = Circle(radius = 0.2, **kwargs).filter_out( angle2_arc = Circle(radius = 0.2, **kwargs).filter_out(
lambda (x, y, z) : not(x < 0 and y > 0 and y < -3*x) lambda (x, y, z) : not(x < 0 and y > 0 and y < -3*x)
).shift(vertices[2]) ).shift(vertices[2])
alpha = tex_mobject("\\alpha") alpha = TexMobject("\\alpha")
beta = tex_mobject("90-\\alpha") beta = TexMobject("90-\\alpha")
alpha.shift(vertices[1]+3*RIGHT+DOWN) alpha.shift(vertices[1]+3*RIGHT+DOWN)
beta.shift(vertices[2]+3*RIGHT+UP) beta.shift(vertices[2]+3*RIGHT+UP)
arrow1 = Arrow(alpha, angle1_arc) arrow1 = Arrow(alpha, angle1_arc)
@ -442,11 +442,11 @@ class LabelLargeSquare(DrawCSquareWithAllTraingles):
def construct(self): def construct(self):
DrawCSquareWithAllTraingles.construct(self) DrawCSquareWithAllTraingles.construct(self)
everything = CompoundMobject(*self.mobjects) everything = CompoundMobject(*self.mobjects)
u_brace = underbrace(2*(DOWN+LEFT), 2*(DOWN+RIGHT)) u_brace = Underbrace(2*(DOWN+LEFT), 2*(DOWN+RIGHT))
u_brace.shift(0.2*DOWN) u_brace.shift(0.2*DOWN)
side_brace = deepcopy(u_brace).rotate(np.pi/2) side_brace = deepcopy(u_brace).rotate(np.pi/2)
upper_brace = deepcopy(u_brace).rotate(np.pi) upper_brace = deepcopy(u_brace).rotate(np.pi)
a_plus_b = tex_mobject("a+b").scale(TEX_MOB_SCALE_VAL) a_plus_b = TexMobject("a+b").scale(TEX_MOB_SCALE_VAL)
upper_brace.add(a_plus_b.next_to(upper_brace, UP)) upper_brace.add(a_plus_b.next_to(upper_brace, UP))
side_brace.add(a_plus_b.next_to(side_brace, RIGHT)) side_brace.add(a_plus_b.next_to(side_brace, RIGHT))
self.add(upper_brace, side_brace) self.add(upper_brace, side_brace)

View file

@ -73,12 +73,12 @@ MOVIE_PREFIX = "tau_poem/"
class Welcome(LogoGeneration): class Welcome(LogoGeneration):
def construct(self): def construct(self):
text = "Happy $\\tau$ Day, from 3Blue1Brown!" text = "Happy $\\tau$ Day, from 3Blue1Brown!"
self.add(text_mobject(text).to_edge(UP)) self.add(TextMobject(text).to_edge(UP))
LogoGeneration.construct(self) LogoGeneration.construct(self)
class HappyTauDayWords(Scene): class HappyTauDayWords(Scene):
def construct(self): def construct(self):
words = text_mobject("Happy Tau Day Everybody!").scale(2) words = TextMobject("Happy Tau Day Everybody!").scale(2)
tau = TauCreature().move_to(2*LEFT + UP) tau = TauCreature().move_to(2*LEFT + UP)
pi = PiCreature().move_to(2*RIGHT + 3*DOWN) pi = PiCreature().move_to(2*RIGHT + 3*DOWN)
pi.highlight("red") pi.highlight("red")
@ -128,7 +128,7 @@ class TauPoem(Scene):
self.first_word_to_last_digit() self.first_word_to_last_digit()
def add_line_and_number(self): def add_line_and_number(self):
self.first_digits, new_digit, last_digits = tex_mobject([ self.first_digits, new_digit, last_digits = TexMobject([
"".join(DIGITS[:self.line_num]), "".join(DIGITS[:self.line_num]),
DIGITS[self.line_num], DIGITS[self.line_num],
"".join(DIGITS[(self.line_num+1):]), "".join(DIGITS[(self.line_num+1):]),
@ -140,11 +140,11 @@ class TauPoem(Scene):
index = line_str.index("ders") index = line_str.index("ders")
else: else:
index = line_str.index(" ") index = line_str.index(" ")
first_word, rest_of_line = text_mobject( first_word, rest_of_line = TextMobject(
[line_str[:index], line_str[index:]] [line_str[:index], line_str[index:]]
).to_edge(UP).shift(BUFF*DOWN).split() ).to_edge(UP).shift(BUFF*DOWN).split()
first_word.shift(0.15*RIGHT) #Stupid first_word.shift(0.15*RIGHT) #Stupid
number_word = text_mobject(DIGIT_TO_WORD[DIGITS[self.line_num][-1]]) number_word = TextMobject(DIGIT_TO_WORD[DIGITS[self.line_num][-1]])
number_word.shift(first_word.get_center()) number_word.shift(first_word.get_center())
number_word.shift(BUFF * UP / 2) number_word.shift(BUFF * UP / 2)
@ -178,7 +178,7 @@ class TauPoem(Scene):
) )
def line0(self): def line0(self):
two, pi = tex_mobject(["2", "\\pi"]).scale(2).split() two, pi = TexMobject(["2", "\\pi"]).scale(2).split()
self.add(two, pi) self.add(two, pi)
two_copy = deepcopy(two).rotate(np.pi/10).highlight("yellow") two_copy = deepcopy(two).rotate(np.pi/10).highlight("yellow")
self.play(Transform( self.play(Transform(
@ -191,7 +191,7 @@ class TauPoem(Scene):
)) ))
def line1(self): def line1(self):
two_pi = tex_mobject(["2", "\\pi"]).scale(2) two_pi = TexMobject(["2", "\\pi"]).scale(2)
tau = TauCreature() tau = TauCreature()
tau.to_symbol() tau.to_symbol()
sphere = Mobject() sphere = Mobject()
@ -277,7 +277,7 @@ class TauPoem(Scene):
""") """)
self.add(pi, bubble) self.add(pi, bubble)
formulae = tex_mobject(FORMULAE, size = "\\small") formulae = TexMobject(FORMULAE, size = "\\small")
formulae.scale(1.25) formulae.scale(1.25)
formulae.to_corner([1, -1, 0]) formulae.to_corner([1, -1, 0])
self.play(FadeIn(formulae)) self.play(FadeIn(formulae))
@ -349,12 +349,12 @@ class TauPoem(Scene):
self.play(WaveArm(tau),Transform(pi, new_pi)) self.play(WaveArm(tau),Transform(pi, new_pi))
def line10(self): def line10(self):
formulae = tex_mobject(FORMULAE, "\\small") formulae = TexMobject(FORMULAE, "\\small")
formulae.scale(1.5).to_edge(DOWN) formulae.scale(1.5).to_edge(DOWN)
self.add(formulae) self.add(formulae)
def line11(self): def line11(self):
formulae = tex_mobject(FORMULAE, "\\small") formulae = TexMobject(FORMULAE, "\\small")
formulae.scale(1.5).to_edge(DOWN) formulae.scale(1.5).to_edge(DOWN)
formulae = formulae.split() formulae = formulae.split()
f_copy = deepcopy(formulae) f_copy = deepcopy(formulae)
@ -391,14 +391,14 @@ class TauPoem(Scene):
) )
grid = Grid(radius = radius).shift(grid_center) grid = Grid(radius = radius).shift(grid_center)
circle = Circle().scale(interval_size).shift(grid_center) circle = Circle().scale(interval_size).shift(grid_center)
grid.add(tex_mobject("e^{ix}").shift(grid_center+UP+RIGHT)) grid.add(TexMobject("e^{ix}").shift(grid_center+UP+RIGHT))
circle.highlight("white") circle.highlight("white")
tau_line = Line( tau_line = Line(
*[np.pi*interval_size*vect for vect in LEFT, RIGHT], *[np.pi*interval_size*vect for vect in LEFT, RIGHT],
density = 5*DEFAULT_POINT_DENSITY_1D density = 5*DEFAULT_POINT_DENSITY_1D
) )
tau_line.highlight("red") tau_line.highlight("red")
tau = tex_mobject("\\tau") tau = TexMobject("\\tau")
tau.shift(tau_line.get_center() + 0.5*UP) tau.shift(tau_line.get_center() + 0.5*UP)
self.add(axes, grid) self.add(axes, grid)
@ -423,7 +423,7 @@ class TauPoem(Scene):
def line13(self): def line13(self):
formula = form_start, two_pi, form_end = tex_mobject([ formula = form_start, two_pi, form_end = TexMobject([
"\\hat{f^{(n)}}(\\xi) = (", "\\hat{f^{(n)}}(\\xi) = (",
"2\\pi", "2\\pi",
"i\\xi)^n \\hat{f}(\\xi)" "i\\xi)^n \\hat{f}(\\xi)"
@ -453,7 +453,7 @@ class TauPoem(Scene):
pi, bubble = self.pi_speaking( pi, bubble = self.pi_speaking(
"sticks oddly \\\\ to one half when \\\\ tau's preferred." "sticks oddly \\\\ to one half when \\\\ tau's preferred."
) )
formula = form_start, half, form_end = tex_mobject([ formula = form_start, half, form_end = TexMobject([
"A = ", "A = ",
"\\frac{1}{2}", "\\frac{1}{2}",
"\\tau r^2" "\\tau r^2"
@ -464,7 +464,7 @@ class TauPoem(Scene):
self.play(ApplyMethod(half.highlight, "yellow")) self.play(ApplyMethod(half.highlight, "yellow"))
def line16(self): def line16(self):
self.add(tex_mobject( self.add(TexMobject(
"\\frac{1}{2}\\tau r^2" "\\frac{1}{2}\\tau r^2"
).scale(2).shift(DOWN)) ).scale(2).shift(DOWN))
@ -489,8 +489,8 @@ class TauPoem(Scene):
-norm, -norm,
0 0
) )
tau_r = tex_mobject("\\tau r").shift(1.3*DOWN) tau_r = TexMobject("\\tau r").shift(1.3*DOWN)
r = tex_mobject("r").shift(0.2*RIGHT + 0.7*DOWN) r = TexMobject("r").shift(0.2*RIGHT + 0.7*DOWN)
lines = [ lines = [
Line(DOWN+np.pi*LEFT, DOWN+np.pi*RIGHT), Line(DOWN+np.pi*LEFT, DOWN+np.pi*RIGHT),
Line(ORIGIN, DOWN) Line(ORIGIN, DOWN)

View file

@ -1,153 +0,0 @@
from image_mobject import ImageMobject
from helpers import *
#TODO, Cleanup and refactor this file.
#TODO, Make both of these proper mobject classes
def text_mobject(text, size = None):
size = size or "\\Large" #TODO, auto-adjust?
return tex_mobject(text, size, TEMPLATE_TEXT_FILE)
def tex_mobject(expression,
size = None,
template_tex_file = TEMPLATE_TEX_FILE):
if size == None:
if len("".join(expression)) < MAX_LEN_FOR_HUGE_TEX_FONT:
size = "\\Huge"
else:
size = "\\large"
#Todo, make this more sophisticated.
image_files = tex_to_image(expression, size, template_tex_file)
config = {
"point_thickness" : 1,
"should_center" : False,
}
if isinstance(image_files, list):
#TODO, is checking listiness really the best here?
result = CompoundMobject(*[
ImageMobject(f, **config)
for f in image_files
])
else:
result = ImageMobject(image_files, **config)
return result.center().highlight("white")
def underbrace(left, right, buff = 0.2):
result = tex_mobject("\\underbrace{%s}"%(14*"\\quad"))
result.stretch_to_fit_width(right[0]-left[0])
result.shift(left - result.points[0] + buff*DOWN)
return result
def tex_to_image(expression,
size = "\HUGE",
template_tex_file = TEMPLATE_TEX_FILE):
"""
Returns list of images for correpsonding with a list of expressions
"""
return_list = isinstance(expression, list)
simple_tex = "".join(expression)
if return_list:
expression = tex_expression_list_as_string(expression)
exp_hash = str(hash(expression + size))
image_dir = os.path.join(TEX_IMAGE_DIR, exp_hash)
if os.path.exists(image_dir):
result = [
os.path.join(image_dir, png_file)
for png_file in sorted(
os.listdir(image_dir),
cmp_enumerated_files
)
]
else:
filestem = os.path.join(TEX_DIR, exp_hash)
if not os.path.exists(filestem + ".tex"):
print "Writing %s at size %s to %s.tex"%(
simple_tex, size, filestem
)
with open(template_tex_file, "r") as infile:
body = infile.read()
body = body.replace(SIZE_TO_REPLACE, size)
body = body.replace(TEX_TEXT_TO_REPLACE, expression)
with open(filestem + ".tex", "w") as outfile:
outfile.write(body)
if not os.path.exists(filestem + ".dvi"):
commands = [
"latex",
"-interaction=batchmode",
"-output-directory=" + TEX_DIR,
filestem + ".tex",
"> /dev/null"
]
#TODO, Error check
os.system(" ".join(commands))
result = dvi_to_png(filestem + ".dvi")
return result if return_list else result[0]
def tex_expression_list_as_string(expression):
return "\n".join([
"\onslide<%d>{"%count + exp + "}"
for count, exp in zip(it.count(1), expression)
])
def dvi_to_png(filename, regen_if_exists = False):
"""
Converts a dvi, which potentially has multiple slides, into a
directory full of enumerated pngs corresponding with these slides.
Returns a list of PIL Image objects for these images sorted as they
where in the dvi
"""
possible_paths = [
filename,
os.path.join(TEX_DIR, filename),
os.path.join(TEX_DIR, filename + ".dvi"),
]
for path in possible_paths:
if os.path.exists(path):
directory, filename = os.path.split(path)
name = filename.split(".")[0]
images_dir = os.path.join(TEX_IMAGE_DIR, name)
if not os.path.exists(images_dir):
os.mkdir(images_dir)
if os.listdir(images_dir) == [] or regen_if_exists:
commands = [
"convert",
"-density",
str(PDF_DENSITY),
path,
"-size",
str(DEFAULT_WIDTH) + "x" + str(DEFAULT_HEIGHT),
os.path.join(images_dir, name + ".png")
]
os.system(" ".join(commands))
image_paths = [
os.path.join(images_dir, name)
for name in os.listdir(images_dir)
if name.endswith(".png")
]
image_paths.sort(cmp_enumerated_files)
return image_paths
raise IOError("File not Found")
def cmp_enumerated_files(name1, name2):
num1, num2 = [
int(name.split(".")[0].split("-")[-1])
for name in (name1, name2)
]
return num1 - num2

View file

@ -4,6 +4,7 @@ import itertools as it
from helpers import * from helpers import *
from scene import Scene from scene import Scene
from animation import Animation from animation import Animation
from mobject import TexMobject
class RearrangeEquation(Scene): class RearrangeEquation(Scene):
def construct( def construct(
@ -67,8 +68,8 @@ class RearrangeEquation(Scene):
""" """
num_start_terms = len(start_terms) num_start_terms = len(start_terms)
all_mobs = np.array( all_mobs = np.array(
tex_mobject(start_terms, size = size).split() + \ TexMobject(start_terms, size = size).split() + \
tex_mobject(end_terms, size = size).split() TexMobject(end_terms, size = size).split()
) )
all_terms = np.array(start_terms+end_terms) all_terms = np.array(start_terms+end_terms)
for term in set(all_terms): for term in set(all_terms):
@ -88,7 +89,7 @@ class FlipThroughSymbols(Animation):
"end_center" : ORIGIN, "end_center" : ORIGIN,
} }
def __init__(self, tex_list, **kwargs): def __init__(self, tex_list, **kwargs):
mobject = tex_mobject(self.curr_tex).shift(start_center) mobject = TexMobject(self.curr_tex).shift(start_center)
Animation.__init__(self, mobject, **kwargs) Animation.__init__(self, mobject, **kwargs)
def update_mobject(self, alpha): def update_mobject(self, alpha):
@ -96,7 +97,7 @@ class FlipThroughSymbols(Animation):
if new_tex != self.curr_tex: if new_tex != self.curr_tex:
self.curr_tex = new_tex self.curr_tex = new_tex
self.mobject = tex_mobject(new_tex).shift(self.start_center) self.mobject = TexMobject(new_tex).shift(self.start_center)
if not all(self.start_center == self.end_center): if not all(self.start_center == self.end_center):
self.mobject.center().shift( self.mobject.center().shift(
(1-alpha)*self.start_center + alpha*self.end_center (1-alpha)*self.start_center + alpha*self.end_center

View file

@ -33,7 +33,7 @@ class PiCreature(CompoundMobject):
self.mouth.center() self.mouth.center()
self.smile = deepcopy(self.mouth) self.smile = deepcopy(self.mouth)
self.frown = deepcopy(self.mouth).rotate(np.pi, RIGHT) self.frown = deepcopy(self.mouth).rotate(np.pi, RIGHT)
self.straight_mouth = tex_mobject("-").scale(0.5) self.straight_mouth = TexMobject("-").scale(0.5)
for mouth_name in ["mouth"] + self.MOUTH_NAMES: for mouth_name in ["mouth"] + self.MOUTH_NAMES:
mouth = getattr(self, mouth_name) mouth = getattr(self, mouth_name)
mouth.sort_points(lambda p : p[0]) mouth.sort_points(lambda p : p[0])
@ -211,7 +211,7 @@ class Bubble(Mobject):
return self return self
def write(self, text): def write(self, text):
self.add_content(text_mobject(text)) self.add_content(TextMobject(text))
return self return self
def clear(self): def clear(self):

View file

@ -40,7 +40,7 @@ class CountingScene(Scene):
self.add(*mobjects) self.add(*mobjects)
for mob, num in zip(mobjects, it.count(1)): for mob, num in zip(mobjects, it.count(1)):
if display_numbers: if display_numbers:
num_mob = tex_mobject(str(num)) num_mob = TexMobject(str(num))
num_mob.center().shift(num_offset) num_mob.center().shift(num_offset)
self.add(num_mob) self.add(num_mob)
if mode == "highlight": if mode == "highlight":
@ -69,7 +69,7 @@ class CountingScene(Scene):
raise Warning("Unknown mode") raise Warning("Unknown mode")
frame_time = run_time / (len(regions)) frame_time = run_time / (len(regions))
for region, count in zip(regions, it.count(1)): for region, count in zip(regions, it.count(1)):
num_mob = tex_mobject(str(count)) num_mob = TexMobject(str(count))
num_mob.center().shift(num_offset) num_mob.center().shift(num_offset)
self.add(num_mob) self.add(num_mob)
self.highlight_region(region) self.highlight_region(region)
@ -112,7 +112,7 @@ class PascalsTriangleScene(Scene):
num = choose(n, k) num = choose(n, k)
center = self.coords_to_center(n, k) center = self.coords_to_center(n, k)
if num not in num_to_num_mob: if num not in num_to_num_mob:
num_to_num_mob[num] = tex_mobject(str(num)) num_to_num_mob[num] = TexMobject(str(num))
num_mob = deepcopy(num_to_num_mob[num]) num_mob = deepcopy(num_to_num_mob[num])
scale_factor = min( scale_factor = min(
1, 1,
@ -135,7 +135,7 @@ class PascalsTriangleScene(Scene):
def generate_n_choose_k_mobs(self): def generate_n_choose_k_mobs(self):
self.coords_to_n_choose_k = {} self.coords_to_n_choose_k = {}
for n, k in self.coords: for n, k in self.coords:
nck_mob = tex_mobject(r"{%d \choose %d}"%(n, k)) nck_mob = TexMobject(r"{%d \choose %d}"%(n, k))
scale_factor = min( scale_factor = min(
1, 1,
self.portion_to_fill * self.cell_height / nck_mob.get_height(), self.portion_to_fill * self.cell_height / nck_mob.get_height(),
@ -148,7 +148,7 @@ class PascalsTriangleScene(Scene):
self.coords_to_n_choose_k[n][k] = nck_mob self.coords_to_n_choose_k[n][k] = nck_mob
def generate_sea_of_zeros(self): def generate_sea_of_zeros(self):
zero = tex_mobject("0") zero = TexMobject("0")
self.sea_of_zeros = [] self.sea_of_zeros = []
for n in range(self.nrows): for n in range(self.nrows):
for a in range((self.nrows - n)/2 + 1): for a in range((self.nrows - n)/2 + 1):

View file

@ -49,7 +49,7 @@ class ComplexPlane(NumberPlane):
num_str = "0" num_str = "0"
else: else:
num_str = str(number).replace("j", "i") num_str = str(number).replace("j", "i")
num = tex_mobject(num_str) num = TexMobject(num_str)
num.scale(self.number_scale_factor) num.scale(self.number_scale_factor)
num.shift(point-num.get_corner(UP+LEFT)+nudge) num.shift(point-num.get_corner(UP+LEFT)+nudge)
result.append(num) result.append(num)
@ -167,7 +167,7 @@ class ComplexMultiplication(Scene):
radius = 0.1*self.plane.unit_to_spatial_width, radius = 0.1*self.plane.unit_to_spatial_width,
color = BLUE if value == 1 else YELLOW color = BLUE if value == 1 else YELLOW
) )
label = tex_mobject(tex_string) label = TexMobject(tex_string)
label.shift(dot.get_center()+1.5*UP+RIGHT) label.shift(dot.get_center()+1.5*UP+RIGHT)
arrow = Arrow(label, dot) arrow = Arrow(label, dot)
self.add(label) self.add(label)

View file

@ -1,6 +1,6 @@
from helpers import * from helpers import *
from mobject import Mobject1D from mobject import Mobject1D, TexMobject
from scene import Scene from scene import Scene
class NumberLine(Mobject1D): class NumberLine(Mobject1D):
@ -80,7 +80,7 @@ class NumberLine(Mobject1D):
numbers = self.default_numbers_to_display() numbers = self.default_numbers_to_display()
result = [] result = []
for number in numbers: for number in numbers:
mob = tex_mobject(str(int(number))) mob = TexMobject(str(int(number)))
vert_scale = 2*self.tick_size/mob.get_height() vert_scale = 2*self.tick_size/mob.get_height()
hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width() hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width()
mob.scale(min(vert_scale, hori_scale)) mob.scale(min(vert_scale, hori_scale))
@ -187,7 +187,7 @@ class NumberPlane(Mobject1D):
for val in vals: for val in vals:
num_pair[index] = val num_pair[index] = val
point = self.num_pair_to_point(num_pair) point = self.num_pair_to_point(num_pair)
num = tex_mobject(str(val)) num = TexMobject(str(val))
num.scale(self.number_scale_factor) num.scale(self.number_scale_factor)
num.shift(point-num.get_corner(UP+LEFT)+nudge) num.shift(point-num.get_corner(UP+LEFT)+nudge)
result.append(num) result.append(num)