Beginnings of TOP project

This commit is contained in:
Grant Sanderson
2016-04-23 23:36:05 -07:00
parent 2c17488fb2
commit af1ea057ad
12 changed files with 579 additions and 70 deletions

View File

@ -66,7 +66,7 @@ class ShowCreation(ShowPartial):
class ShowCreationPerSubmobject(ShowCreation): class ShowCreationPerSubmobject(ShowCreation):
CONFIG = { CONFIG = {
"submobject_mode" : "one_at_a_time", "submobject_mode" : "one_at_a_time",
"run_time" : 3 "run_time" : 1
} }
class Write(ShowCreation): class Write(ShowCreation):

View File

@ -114,7 +114,7 @@ class Camera(object):
def get_pen_and_fill(self, vmobject): def get_pen_and_fill(self, vmobject):
pen = aggdraw.Pen( pen = aggdraw.Pen(
vmobject.get_stroke_color().get_hex_l(), vmobject.get_stroke_color().get_hex_l(),
vmobject.stroke_width max(vmobject.stroke_width, 0)
) )
fill = aggdraw.Brush( fill = aggdraw.Brush(
vmobject.get_fill_color().get_hex_l(), vmobject.get_fill_color().get_hex_l(),

View File

@ -440,9 +440,9 @@ class Mobject(object):
for mob in self, mobject for mob in self, mobject
] ]
if self_has_points and not mob_has_points: if self_has_points and not mob_has_points:
self.push_self_into_submobjects() mobject.null_point_align(self)
elif mob_has_points and not self_has_points: elif mob_has_points and not self_has_points:
mob.push_self_into_submobjects() self.null_point_align(mobject)
self_count = len(self.submobjects) self_count = len(self.submobjects)
mob_count = len(mobject.submobjects) mob_count = len(mobject.submobjects)
diff = abs(self_count-mob_count) diff = abs(self_count-mob_count)
@ -452,6 +452,18 @@ class Mobject(object):
mobject.add_n_more_submobjects(diff) mobject.add_n_more_submobjects(diff)
return self return self
def null_point_align(self, mobject):
"""
If self has no points, but needs to align
with mobject, which has points
"""
if self.submobjects:
mobject.push_self_into_submobjects()
else:
self.points = np.array([mobject.points[0]])
return self
def push_self_into_submobjects(self): def push_self_into_submobjects(self):
copy = self.copy() copy = self.copy()
copy.submobjects = [] copy.submobjects = []

View File

@ -6,6 +6,10 @@ from topics.geometry import Rectangle, Circle
from helpers import * from helpers import *
class SVGMobject(VMobject): class SVGMobject(VMobject):
CONFIG = {
"initial_scale_val" : 1,
"should_center" : True,
}
def __init__(self, svg_file, **kwargs): def __init__(self, svg_file, **kwargs):
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
VMobject.__init__(self, **kwargs) VMobject.__init__(self, **kwargs)
@ -87,7 +91,7 @@ class SVGMobject(VMobject):
fill_color = WHITE, fill_color = WHITE,
fill_opacity = 1.0 fill_opacity = 1.0
) )
mob.shift(mob.get_center()-mob.get_corner(DOWN+LEFT)) mob.shift(mob.get_center()-mob.get_corner(UP+LEFT))
return mob return mob
def handle_transforms(self, element, mobject): def handle_transforms(self, element, mobject):
@ -110,7 +114,11 @@ class SVGMobject(VMobject):
self.ref_to_element.update(new_refs) self.ref_to_element.update(new_refs)
def move_into_position(self): def move_into_position(self):
pass #subclasses should tweak as needed if self.should_center:
self.center()
self.scale_in_place(self.initial_scale_val)
class VMobjectFromSVGPathstring(VMobject): class VMobjectFromSVGPathstring(VMobject):

View File

@ -3,7 +3,7 @@ from svg_mobject import SVGMobject, VMobjectFromSVGPathstring
from helpers import * from helpers import *
TEX_MOB_SCALE_VAL = 0.1 TEX_MOB_SCALE_VAL = 0.1
TEXT_MOB_SCALE_VAL = 0.2 TEXT_MOB_SCALE_VAL = 0.05
class TexSymbol(VMobjectFromSVGPathstring): class TexSymbol(VMobjectFromSVGPathstring):
@ -32,8 +32,9 @@ class TexMobject(SVGMobject):
"fill_color" : WHITE, "fill_color" : WHITE,
"should_center" : True, "should_center" : True,
"next_to_direction" : RIGHT, "next_to_direction" : RIGHT,
"next_to_buff" : 0.2, "next_to_buff" : 0.25,
"initial_scale_val" : TEX_MOB_SCALE_VAL, "initial_scale_val" : TEX_MOB_SCALE_VAL,
"propogate_style_to_family" : True,
} }
def __init__(self, expression, **kwargs): def __init__(self, expression, **kwargs):
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
@ -62,14 +63,17 @@ class TexMobject(SVGMobject):
#TODO, next_to not sufficient? #TODO, next_to not sufficient?
subs = [ subs = [
# TexMobject(expr) # TexMobject(expr)
self.__class__(expr) self.__class__(
expr
)
for expr in self.expression for expr in self.expression
] ]
self.initial_scale_val = 1
for sm1, sm2 in zip(subs, subs[1:]): for sm1, sm2 in zip(subs, subs[1:]):
sm2.next_to( sm2.next_to(
sm1, sm1,
self.next_to_direction, self.next_to_direction,
self.next_to_buff buff = self.next_to_buff
) )
self.submobjects = subs self.submobjects = subs
return self return self
@ -79,17 +83,12 @@ class TexMobject(SVGMobject):
lambda m1, m2 : int((m1.get_left()-m2.get_left())[0]) lambda m1, m2 : int((m1.get_left()-m2.get_left())[0])
) )
def move_into_position(self):
self.center()
self.scale(self.initial_scale_val)
self.init_colors()
class TextMobject(TexMobject): class TextMobject(TexMobject):
CONFIG = { CONFIG = {
"template_tex_file" : TEMPLATE_TEXT_FILE, "template_tex_file" : TEMPLATE_TEXT_FILE,
"initial_scale_val" : TEXT_MOB_SCALE_VAL, "initial_scale_val" : TEXT_MOB_SCALE_VAL
} }
@ -97,7 +96,7 @@ class Brace(TexMobject):
CONFIG = { CONFIG = {
"buff" : 0.2, "buff" : 0.2,
} }
TEX_STRING = "\\underbrace{%s}"%(14*"\\quad") TEX_STRING = "\\underbrace{%s}"%(3*"\\qquad")
def __init__(self, mobject, direction = DOWN, **kwargs): def __init__(self, mobject, direction = DOWN, **kwargs):
TexMobject.__init__(self, self.TEX_STRING, **kwargs) TexMobject.__init__(self, self.TEX_STRING, **kwargs)
angle = -np.arctan2(*direction[:2]) + np.pi angle = -np.arctan2(*direction[:2]) + np.pi
@ -105,7 +104,7 @@ class Brace(TexMobject):
left = mobject.get_corner(DOWN+LEFT) left = mobject.get_corner(DOWN+LEFT)
right = mobject.get_corner(DOWN+RIGHT) right = mobject.get_corner(DOWN+RIGHT)
self.stretch_to_fit_width(right[0]-left[0]) self.stretch_to_fit_width(right[0]-left[0])
self.shift(left - self.points[0] + self.buff*DOWN) self.shift(left - self.get_corner(UP+LEFT) + self.buff*DOWN)
for mob in mobject, self: for mob in mobject, self:
mob.rotate(angle) mob.rotate(angle)

View File

@ -13,32 +13,61 @@ class VMobject(Mobject):
"is_subpath" : False, "is_subpath" : False,
"close_new_points" : False, "close_new_points" : False,
"mark_paths_closed" : False, "mark_paths_closed" : False,
"propogate_style_to_family" : False,
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
Mobject.__init__(self, *args, **kwargs) Mobject.__init__(self, *args, **kwargs)
VMobject.init_colors(self)
## Colors ## Colors
def init_colors(self): def init_colors(self):
self.set_stroke(self.color, self.stroke_width) self.set_style_data(
self.set_fill(self.fill_color, self.fill_opacity) stroke_color = self.color,
stroke_width = self.stroke_width,
fill_color = self.fill_color,
fill_opacity = self.fill_opacity,
family = self.propogate_style_to_family
)
return self return self
def set_family_attr(self, attr, value): def set_family_attr(self, attr, value):
for mob in self.submobject_family(): for mob in self.submobject_family():
setattr(mob, attr, value) setattr(mob, attr, value)
def set_fill(self, color = None, opacity = 1.0): def set_style_data(self,
if color is not None: stroke_color = None,
self.set_family_attr("fill_rgb", color_to_rgb(color)) stroke_width = None,
self.set_family_attr("fill_opacity", opacity) fill_color = None,
fill_opacity = None,
family = True):
if family:
change_func = self.set_family_attr
else:
change_func = lambda attr, value : setattr(self, attr, value)
if stroke_color is not None:
change_func("stroke_rgb", color_to_rgb(stroke_color))
if stroke_width is not None:
change_func("stroke_width", stroke_width)
if fill_color is not None:
change_func("fill_rgb", color_to_rgb(fill_color))
if fill_opacity is not None:
change_func("fill_opacity", fill_opacity)
return self return self
def set_stroke(self, color = None, width = None): def set_fill(self, color = None, opacity = 1.0, family = True):
if color is not None: return self.set_style_data(
self.set_family_attr("stroke_rgb", color_to_rgb(color)) fill_color = color,
if width is not None: fill_opacity = opacity,
self.set_family_attr("stroke_width", width) family = family
return self )
def set_stroke(self, color = None, width = None, family = True):
return self.set_style_data(
stroke_color = color,
stroke_width = width,
family = family
)
def highlight(self, color): def highlight(self, color):
self.set_fill(color = color) self.set_fill(color = color)
@ -254,6 +283,9 @@ class VMobject(Mobject):
getattr(mobject2, attr), getattr(mobject2, attr),
alpha alpha
)) ))
if alpha == 1.0:
# print getattr(mobject2, attr)
setattr(self, attr, getattr(mobject2, attr))
def become_partial(self, mobject, a, b): def become_partial(self, mobject, a, b):
assert(isinstance(mobject, VMobject)) assert(isinstance(mobject, VMobject))

View File

@ -22,6 +22,7 @@ class PiCreature(SVGMobject):
"color" : BLUE_E, "color" : BLUE_E,
"stroke_width" : 0, "stroke_width" : 0,
"fill_opacity" : 1.0, "fill_opacity" : 1.0,
"initial_scale_val" : 0.01,
} }
def __init__(self, mode = "plain", **kwargs): def __init__(self, mode = "plain", **kwargs):
self.parts_named = False self.parts_named = False
@ -33,10 +34,6 @@ class PiCreature(SVGMobject):
SVGMobject.__init__(self, svg_file, **kwargs) SVGMobject.__init__(self, svg_file, **kwargs)
self.init_colors() self.init_colors()
def move_into_position(self):
self.scale_to_fit_height(4)
self.center()
def name_parts(self): def name_parts(self):
self.mouth = self.submobjects[MOUTH_INDEX] self.mouth = self.submobjects[MOUTH_INDEX]
self.body = self.submobjects[BODY_INDEX] self.body = self.submobjects[BODY_INDEX]
@ -53,7 +50,7 @@ class PiCreature(SVGMobject):
self.parts_named = True self.parts_named = True
def init_colors(self): def init_colors(self):
VMobject.init_colors(self) self.set_stroke(color = BLACK, width = self.stroke_width)
if not self.parts_named: if not self.parts_named:
self.name_parts() self.name_parts()
self.mouth.set_fill(BLACK) self.mouth.set_fill(BLACK)

View File

@ -1,5 +1,8 @@
from helpers import * from helpers import *
from mobject.vectorized_mobject import VMobject
from mobject.tex_mobject import TexMobject
from scene import Scene from scene import Scene
@ -81,39 +84,29 @@ class CountingScene(Scene):
self.number = num_mob self.number = num_mob
return self return self
class PascalsTriangle(VMobject):
BIG_N_PASCAL_ROWS = 11 CONFIG = {
N_PASCAL_ROWS = 7 "nrows" : 7,
"height" : 2*SPACE_HEIGHT - 1,
class PascalsTriangleScene(Scene): "width" : 1.5*SPACE_WIDTH,
args_list = [ "portion_to_fill" : 0.7
(N_PASCAL_ROWS,), }
(BIG_N_PASCAL_ROWS,), def generate_points(self):
] self.cell_height = self.height / self.nrows
@staticmethod self.cell_width = self.width / self.nrows
def args_to_string(*args): self.bottom_left = (self.cell_width * self.nrows / 2.0)*LEFT + \
return str(args[0]) (self.cell_height * self.nrows / 2.0)*DOWN
def __init__(self, nrows, *args, **kwargs):
Scene.__init__(self, *args, **kwargs)
self.nrows = nrows
self.diagram_height = 2*SPACE_HEIGHT - 1
self.diagram_width = 1.5*SPACE_WIDTH
self.cell_height = self.diagram_height / nrows
self.cell_width = self.diagram_width / nrows
self.portion_to_fill = 0.7
self.bottom_left = np.array(
(-self.cell_width * nrows / 2.0, -self.cell_height * nrows / 2.0, 0)
)
num_to_num_mob = {} num_to_num_mob = {}
self.coords_to_mobs = {} self.coords_to_mobs = {}
self.coords = [(n, k) for n in range(nrows) for k in range(n+1)] self.coords = [
(n, k)
for n in range(self.nrows)
for k in range(n+1)
]
for n, k in self.coords: for n, k in self.coords:
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: num_mob = TexMobject(str(num))
num_to_num_mob[num] = TexMobject(str(num))
num_mob = num_to_num_mob[num].copy()
scale_factor = min( scale_factor = min(
1, 1,
self.portion_to_fill * self.cell_height / num_mob.get_height(), self.portion_to_fill * self.cell_height / num_mob.get_height(),
@ -123,14 +116,16 @@ class PascalsTriangleScene(Scene):
if n not in self.coords_to_mobs: if n not in self.coords_to_mobs:
self.coords_to_mobs[n] = {} self.coords_to_mobs[n] = {}
self.coords_to_mobs[n][k] = num_mob self.coords_to_mobs[n][k] = num_mob
self.add(*[self.coords_to_mobs[n][k] for n, k in self.coords]) self.add(*[
self.coords_to_mobs[n][k]
for n, k in self.coords
])
return self
def coords_to_center(self, n, k): def coords_to_center(self, n, k):
return self.bottom_left + ( x_offset = self.cell_width * (k+self.nrows/2.0 - n/2.0)
self.cell_width * (k+self.nrows/2.0 - n/2.0), y_offset = self.cell_height * (self.nrows - n)
self.cell_height * (self.nrows - n), return self.bottom_left + x_offset*RIGHT + y_offset*UP
0
)
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 = {}
@ -146,6 +141,17 @@ class PascalsTriangleScene(Scene):
if n not in self.coords_to_n_choose_k: if n not in self.coords_to_n_choose_k:
self.coords_to_n_choose_k[n] = {} self.coords_to_n_choose_k[n] = {}
self.coords_to_n_choose_k[n][k] = nck_mob self.coords_to_n_choose_k[n][k] = nck_mob
return self
def fill_with_n_choose_k(self):
if not hasattr(self, "coords_to_n_choose_k"):
self.generate_n_choose_k_mobs()
self.submobjects = []
self.add(*[
self.coords_to_n_choose_k[n][k]
for n, k in self.coords
])
return self
def generate_sea_of_zeros(self): def generate_sea_of_zeros(self):
zero = TexMobject("0") zero = TexMobject("0")
@ -158,7 +164,7 @@ class PascalsTriangleScene(Scene):
mob.shift(self.coords_to_center(n, k)) mob.shift(self.coords_to_center(n, k))
self.coords_to_mobs[n][k] = mob self.coords_to_mobs[n][k] = mob
self.add(mob) self.add(mob)
return self

View File

@ -113,6 +113,7 @@ class Arrow(Line):
"color" : YELLOW_C, "color" : YELLOW_C,
"tip_length" : 0.25, "tip_length" : 0.25,
"buff" : 0.3, "buff" : 0.3,
"propogate_style_to_family" : True,
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if len(args) == 1: if len(args) == 1:
@ -145,6 +146,13 @@ class Vector(Arrow):
def __init__(self, start, direction, **kwargs): def __init__(self, start, direction, **kwargs):
Arrow.__init__(self, start, end, **kwargs) Arrow.__init__(self, start, end, **kwargs)
class DoubleArrow(Arrow):
def __init__(self, *args, **kwargs):
Arrow.__init__(self, *args, **kwargs)
self.start, self.end = self.end, self.start
self.add_tip()
self.start, self.end = self.end, self.start
class Cross(VMobject): class Cross(VMobject):
CONFIG = { CONFIG = {
"color" : YELLOW, "color" : YELLOW,

View File

@ -18,6 +18,7 @@ class NumberLine(VMobject):
"numbers_with_elongated_ticks" : [0], "numbers_with_elongated_ticks" : [0],
"longer_tick_multiple" : 2, "longer_tick_multiple" : 2,
"number_at_center" : 0, "number_at_center" : 0,
"propogate_style_to_family" : True
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
digest_config(self, kwargs) digest_config(self, kwargs)

View File

446
triangle_of_power/intro.py Normal file
View File

@ -0,0 +1,446 @@
from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from animation.playground import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.number_line import *
from topics.combinatorics import PascalsTriangle
from scene import Scene
# from scene.zoomed_scene import ZoomedScene
from camera import Camera, MovingCamera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
class TrigAnimation(Animation):
CONFIG = {
"rate_func" : None,
"run_time" : 5,
"sin_color" : BLUE,
"cos_color" : RED,
"tan_color" : GREEN
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
x_axis = NumberLine(
x_min = -3,
x_max = 3,
color = BLUE_E
)
y_axis = x_axis.copy().rotate(np.pi/2)
circle = Circle(color = WHITE)
self.trig_lines = [
Line(ORIGIN, RIGHT, color = color)
for color in self.sin_color, self.cos_color, self.tan_color
]
mobject = VMobject(
x_axis, y_axis, circle,
*self.trig_lines
)
mobject.to_edge(RIGHT)
self.center = mobject.get_center()
Animation.__init__(self, mobject, **kwargs)
def update_mobject(self, alpha):
theta = 2*np.pi*alpha
circle_point = np.cos(theta)*RIGHT+np.sin(theta)*UP+self.center
points = [
circle_point[0]*RIGHT,
circle_point[1]*UP+self.center,
(
np.sign(np.cos(theta))*np.sqrt(
np.tan(theta)**2 - np.sin(theta)**2
) + np.cos(theta)
)*RIGHT + self.center,
]
for line, point in zip(self.trig_lines, points):
line.set_anchor_points(
[circle_point, point],
mode = "corners"
)
class Notation(Scene):
def construct(self):
self.introduce_notation()
self.shift_to_good_and_back()
self.shift_to_visuals()
self.swipe_left()
def introduce_notation(self):
notation = TextMobject("Notation")
notation.to_edge(UP)
self.sum1 = TexMobject("\\sum_{n=1}^\\infty \\dfrac{1}{n}")
self.prod1 = TexMobject("\\prod_{p\\text{ prime}}\\left(1-p^{-s}\\right)")
self.trigs1 = TexMobject([
["\\sin", "(x)"],
["\\cos", "(x)"],
["\\tan", "(x)"],
], next_to_direction = DOWN)
self.func1 = TexMobject("f(x) = y")
symbols = [self.sum1, self.prod1, self.trigs1, self.func1]
for sym, vect in zip(symbols, compass_directions(4, UP+LEFT)):
sym.scale(0.5)
vect[0] *= 2
sym.shift(vect)
self.symbols = VMobject(*symbols)
self.play(Write(notation))
self.play(Write(self.symbols))
self.dither()
self.add(notation, self.symbols)
def shift_to_good_and_back(self):
sum2 = self.sum1.copy()
sigma = sum2.submobjects[1]
plus = TexMobject("+").replace(sigma)
sum2.submobjects[1] = plus
prod2 = self.prod1.copy()
pi = prod2.submobjects[0]
times = TexMobject("\\times").replace(pi)
prod2.submobjects[0] = times
new_sin, new_cos, new_tan = [
VMobject().set_anchor_points(
corners, mode = "corners"
).replace(trig_part.split()[0])
for corners, trig_part in zip(
[
[RIGHT, RIGHT+UP, LEFT],
[RIGHT+UP, LEFT, RIGHT],
[RIGHT+UP, RIGHT, LEFT],
],
self.trigs1.split()
)
]
x1, x2, x3 = [
trig_part.split()[1]
for trig_part in self.trigs1.split()
]
trigs2 = VMobject(
VMobject(new_sin, x1),
VMobject(new_cos, x2),
VMobject(new_tan, x3),
)
x, arrow, y = TexMobject("x \\rightarrow y").split()
f = TexMobject("f")
f.next_to(arrow, UP)
func2 = VMobject(f, VMobject(), x, VMobject(), arrow, y)
func2.scale(0.5)
func2.shift(self.func1.get_center())
good_symbols = VMobject(sum2, prod2, trigs2, func2)
bad_symbols = self.symbols.copy()
self.play(Transform(
self.symbols, good_symbols,
path_arc = np.pi
))
self.dither(3)
self.play(Transform(
self.symbols, bad_symbols,
path_arc = np.pi
))
self.dither()
def shift_to_visuals(self):
sigma, prod, trig, func = self.symbols.split()
new_trig = trig.copy()
sin, cos, tan = [
trig_part.split()[0]
for trig_part in new_trig.split()
]
trig_anim = TrigAnimation()
sin.highlight(trig_anim.sin_color)
cos.highlight(trig_anim.cos_color)
tan.highlight(trig_anim.tan_color)
new_trig.to_corner(UP+RIGHT)
sum_lines = self.get_harmonic_sum_lines()
self.play(
Transform(trig, new_trig),
*it.starmap(ApplyMethod, [
(sigma.to_corner, UP+LEFT),
(prod.shift, 15*LEFT),
(func.shift, 5*UP),
])
)
sum_lines.next_to(sigma, DOWN)
self.remove(prod, func)
self.play(
trig_anim,
Write(sum_lines)
)
self.play(trig_anim)
self.dither()
def get_harmonic_sum_lines(self):
result = VMobject()
for n in range(1, 8):
big_line = NumberLine(
x_min = 0,
x_max = 1.01,
tick_frequency = 1./n,
numbers_with_elongated_ticks = [],
color = WHITE
)
little_line = Line(
big_line.number_to_point(0),
big_line.number_to_point(1./n),
color = RED
)
big_line.add(little_line)
big_line.shift(0.5*n*DOWN)
result.add(big_line)
return result
def swipe_left(self):
everyone = VMobject(*self.mobjects)
self.play(ApplyMethod(everyone.shift, 20*LEFT))
class ButDots(Scene):
def construct(self):
but = TextMobject("but")
dots = TexMobject("\\dots")
dots.next_to(but, aligned_edge = DOWN)
but.shift(20*RIGHT)
self.play(ApplyMethod(but.shift, 20*LEFT))
self.play(Write(dots, run_time = 5))
self.dither()
class ThreesomeOfNotation(Scene):
def construct(self):
exp = TexMobject("x^y = z")
log = TexMobject("\\log_x(z) = y")
rad = TexMobject("\\sqrt[y]{z} = x")
exp.to_edge(LEFT).shift(2*UP)
rad.to_edge(RIGHT).shift(2*DOWN)
x1, y1, eq, z1 = exp.split()
l, o, g, x2, p, z2, p, eq, y2 = log.split()
y3, r, r, z3, eq, x3 = rad.split()
vars1 = VMobject(x1, y1, z1).copy()
vars2 = VMobject(x2, y2, z2)
vars3 = VMobject(x3, y3, z3)
self.play(Write(exp))
self.play(Transform(vars1, vars2, path_arc = -np.pi))
self.play(Write(log))
self.play(Transform(vars1, vars3, path_arc = -np.pi))
self.play(Write(rad))
self.dither()
class TwoThreeEightExample(Scene):
def construct(self):
start = TexMobject("2 \\cdot 2 \\cdot 2 = 8")
two1, dot1, two2, dot2, two3, eq, eight = start.split()
brace = Brace(VMobject(two1, two3), DOWN)
three = TexMobject("3").next_to(brace, DOWN, buff = 0.2)
rogue_two = two1.copy()
self.add(two1)
self.play(
Transform(rogue_two, two2),
Write(dot1),
run_time = 0.5
)
self.add(two2)
self.play(
Transform(rogue_two, two3),
Write(dot2),
run_time = 0.5
)
self.add(two3)
self.remove(rogue_two)
self.play(
Write(eq), Write(eight),
GrowFromCenter(brace),
Write(three),
run_time = 1
)
self.dither()
exp = TexMobject("2^3")
exp.next_to(eq, LEFT)
exp.shift(0.2*UP)
base_two, exp_three = exp.split()
self.play(
Transform(
VMobject(two1, dot1, two2, dot2, brace, three),
exp_three,
path_arc = -np.pi/2
),
Transform(two3, base_two)
)
self.clear()
self.add(base_two, exp_three, eq, eight)
self.dither(3)
rad_three, rad1, rad2, rad_eight, rad_eq, rad_two = \
TexMobject("\\sqrt[3]{8} = 2").split()
self.play(*[
Transform(*pair, path_arc = np.pi/2)
for pair in [
(exp_three, rad_three),
(VMobject(), rad1),
(VMobject(), rad2),
(eight, rad_eight),
(eq, rad_eq),
(base_two, rad_two)
]
])
self.dither()
self.play(ApplyMethod(
VMobject(rad1, rad2).highlight, RED,
rate_func = there_and_back,
run_time = 2
))
self.remove(rad1, rad2)
self.dither()
l, o, g, log_two, p1, log_eight, p2, log_eq, log_three = \
TexMobject("\\log_2(8) = 3").split()
self.clear()
self.play(*[
Transform(*pair, path_arc = np.pi/2)
for pair in [
(rad1, l),
(rad2, o),
(rad2.copy(), g),
(rad_two, log_two),
(VMobject(), p1),
(rad_eight, log_eight),
(VMobject(), p2),
(rad_eq, log_eq),
(rad_three, log_three)
]
])
self.dither()
self.play(ApplyMethod(
VMobject(l, o, g).highlight, RED,
rate_func = there_and_back,
run_time = 2
))
self.dither()
class WhatTheHell(Scene):
def construct(self):
randy = Randolph()
randy.to_corner(DOWN+LEFT)
exp, rad, log = map(TexMobject,[
"2^3 = 8",
"\\sqrt[3]{8} = 2",
"\\log_2(8) = 3",
])
# exp.highlight(BLUE_D)
# rad.highlight(RED_D)
# log.highlight(GREEN_D)
arrow1 = DoubleArrow(DOWN, UP)
arrow2 = arrow1.copy()
last = exp
for mob in arrow1, rad, arrow2, log:
mob.next_to(last, DOWN)
last = mob
q_marks = VMobject(*[
TexMobject("?!").next_to(arrow, RIGHT)
for arrow in arrow1, arrow2
])
q_marks.highlight(RED_D)
everyone = VMobject(exp, rad, log, arrow1, arrow2, q_marks)
everyone.scale(0.7)
everyone.to_corner(UP+RIGHT)
phrases = [
TextMobject(
["Communicate with", words]
).next_to(mob, LEFT, buff = 1)
for words, mob in [
("position", exp),
("a new symbol", rad),
("a word", log)
]
]
for phrase, color in zip(phrases, [BLUE, RED, GREEN]):
phrase.split()[1].highlight(color)
self.play(ApplyMethod(randy.change_mode, "angry"))
self.play(FadeIn(VMobject(exp, rad, log)))
self.play(
ShowCreationPerSubmobject(arrow1),
ShowCreationPerSubmobject(arrow2)
)
self.play(Write(q_marks))
self.dither()
self.remove(randy)
self.play(Write(VMobject(*phrases)))
self.dither()
class Countermathematical(Scene):
def construct(self):
counterintuitive = TextMobject("Counterintuitive")
mathematical = TextMobject("mathematical")
intuitive = VMobject(*counterintuitive.split()[7:])
mathematical.shift(intuitive.get_left()-mathematical.get_left())
self.add(counterintuitive)
self.dither()
self.play(Transform(intuitive, mathematical))
self.dither()
class PascalsCollision(Scene):
def construct(self):
pascals_triangle = PascalsTriangle()
pascals_triangle.scale(0.5)
final_triangle = PascalsTriangle()
final_triangle.fill_with_n_choose_k()
pascals_triangle.to_corner(UP+LEFT)
final_triangle.scale(0.7)
final_triangle.to_edge(UP)
equation = TexMobject([
"{n \\choose k}",
" = \\dfrac{n!}{(n-k)!k!}"
])
equation.scale(0.5)
equation.to_corner(UP+RIGHT)
n_choose_k, formula = equation.split()
words = TextMobject("Seemingly unrelated")
words.shift(2*DOWN)
to_remove = VMobject(*words.split()[:-7])
self.add(pascals_triangle, n_choose_k, formula)
self.play(Write(words))
self.dither()
self.play(
Transform(pascals_triangle, final_triangle),
Transform(n_choose_k, final_triangle),
FadeOut(formula),
ApplyMethod(to_remove.shift, 5*DOWN)
)
self.dither()