mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 02:35:22 +08:00
Beginnings of TOP project
This commit is contained in:
@ -66,7 +66,7 @@ class ShowCreation(ShowPartial):
|
||||
class ShowCreationPerSubmobject(ShowCreation):
|
||||
CONFIG = {
|
||||
"submobject_mode" : "one_at_a_time",
|
||||
"run_time" : 3
|
||||
"run_time" : 1
|
||||
}
|
||||
|
||||
class Write(ShowCreation):
|
||||
|
@ -114,7 +114,7 @@ class Camera(object):
|
||||
def get_pen_and_fill(self, vmobject):
|
||||
pen = aggdraw.Pen(
|
||||
vmobject.get_stroke_color().get_hex_l(),
|
||||
vmobject.stroke_width
|
||||
max(vmobject.stroke_width, 0)
|
||||
)
|
||||
fill = aggdraw.Brush(
|
||||
vmobject.get_fill_color().get_hex_l(),
|
||||
|
@ -440,9 +440,9 @@ class Mobject(object):
|
||||
for mob in self, mobject
|
||||
]
|
||||
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:
|
||||
mob.push_self_into_submobjects()
|
||||
self.null_point_align(mobject)
|
||||
self_count = len(self.submobjects)
|
||||
mob_count = len(mobject.submobjects)
|
||||
diff = abs(self_count-mob_count)
|
||||
@ -452,6 +452,18 @@ class Mobject(object):
|
||||
mobject.add_n_more_submobjects(diff)
|
||||
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):
|
||||
copy = self.copy()
|
||||
copy.submobjects = []
|
||||
|
@ -6,6 +6,10 @@ from topics.geometry import Rectangle, Circle
|
||||
from helpers import *
|
||||
|
||||
class SVGMobject(VMobject):
|
||||
CONFIG = {
|
||||
"initial_scale_val" : 1,
|
||||
"should_center" : True,
|
||||
}
|
||||
def __init__(self, svg_file, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
VMobject.__init__(self, **kwargs)
|
||||
@ -87,7 +91,7 @@ class SVGMobject(VMobject):
|
||||
fill_color = WHITE,
|
||||
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
|
||||
|
||||
def handle_transforms(self, element, mobject):
|
||||
@ -110,7 +114,11 @@ class SVGMobject(VMobject):
|
||||
self.ref_to_element.update(new_refs)
|
||||
|
||||
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):
|
||||
|
@ -3,7 +3,7 @@ from svg_mobject import SVGMobject, VMobjectFromSVGPathstring
|
||||
from helpers import *
|
||||
|
||||
TEX_MOB_SCALE_VAL = 0.1
|
||||
TEXT_MOB_SCALE_VAL = 0.2
|
||||
TEXT_MOB_SCALE_VAL = 0.05
|
||||
|
||||
|
||||
class TexSymbol(VMobjectFromSVGPathstring):
|
||||
@ -32,8 +32,9 @@ class TexMobject(SVGMobject):
|
||||
"fill_color" : WHITE,
|
||||
"should_center" : True,
|
||||
"next_to_direction" : RIGHT,
|
||||
"next_to_buff" : 0.2,
|
||||
"next_to_buff" : 0.25,
|
||||
"initial_scale_val" : TEX_MOB_SCALE_VAL,
|
||||
"propogate_style_to_family" : True,
|
||||
}
|
||||
def __init__(self, expression, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
@ -62,14 +63,17 @@ class TexMobject(SVGMobject):
|
||||
#TODO, next_to not sufficient?
|
||||
subs = [
|
||||
# TexMobject(expr)
|
||||
self.__class__(expr)
|
||||
self.__class__(
|
||||
expr
|
||||
)
|
||||
for expr in self.expression
|
||||
]
|
||||
self.initial_scale_val = 1
|
||||
for sm1, sm2 in zip(subs, subs[1:]):
|
||||
sm2.next_to(
|
||||
sm1,
|
||||
self.next_to_direction,
|
||||
self.next_to_buff
|
||||
buff = self.next_to_buff
|
||||
)
|
||||
self.submobjects = subs
|
||||
return self
|
||||
@ -79,17 +83,12 @@ class TexMobject(SVGMobject):
|
||||
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):
|
||||
CONFIG = {
|
||||
"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 = {
|
||||
"buff" : 0.2,
|
||||
}
|
||||
TEX_STRING = "\\underbrace{%s}"%(14*"\\quad")
|
||||
TEX_STRING = "\\underbrace{%s}"%(3*"\\qquad")
|
||||
def __init__(self, mobject, direction = DOWN, **kwargs):
|
||||
TexMobject.__init__(self, self.TEX_STRING, **kwargs)
|
||||
angle = -np.arctan2(*direction[:2]) + np.pi
|
||||
@ -105,7 +104,7 @@ class Brace(TexMobject):
|
||||
left = mobject.get_corner(DOWN+LEFT)
|
||||
right = mobject.get_corner(DOWN+RIGHT)
|
||||
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:
|
||||
mob.rotate(angle)
|
||||
|
||||
|
@ -13,32 +13,61 @@ class VMobject(Mobject):
|
||||
"is_subpath" : False,
|
||||
"close_new_points" : False,
|
||||
"mark_paths_closed" : False,
|
||||
"propogate_style_to_family" : False,
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
Mobject.__init__(self, *args, **kwargs)
|
||||
VMobject.init_colors(self)
|
||||
|
||||
## Colors
|
||||
def init_colors(self):
|
||||
self.set_stroke(self.color, self.stroke_width)
|
||||
self.set_fill(self.fill_color, self.fill_opacity)
|
||||
self.set_style_data(
|
||||
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
|
||||
|
||||
def set_family_attr(self, attr, value):
|
||||
for mob in self.submobject_family():
|
||||
setattr(mob, attr, value)
|
||||
|
||||
def set_fill(self, color = None, opacity = 1.0):
|
||||
if color is not None:
|
||||
self.set_family_attr("fill_rgb", color_to_rgb(color))
|
||||
self.set_family_attr("fill_opacity", opacity)
|
||||
def set_style_data(self,
|
||||
stroke_color = None,
|
||||
stroke_width = None,
|
||||
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
|
||||
|
||||
def set_stroke(self, color = None, width = None):
|
||||
if color is not None:
|
||||
self.set_family_attr("stroke_rgb", color_to_rgb(color))
|
||||
if width is not None:
|
||||
self.set_family_attr("stroke_width", width)
|
||||
return self
|
||||
def set_fill(self, color = None, opacity = 1.0, family = True):
|
||||
return self.set_style_data(
|
||||
fill_color = color,
|
||||
fill_opacity = opacity,
|
||||
family = family
|
||||
)
|
||||
|
||||
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):
|
||||
self.set_fill(color = color)
|
||||
@ -254,6 +283,9 @@ class VMobject(Mobject):
|
||||
getattr(mobject2, attr),
|
||||
alpha
|
||||
))
|
||||
if alpha == 1.0:
|
||||
# print getattr(mobject2, attr)
|
||||
setattr(self, attr, getattr(mobject2, attr))
|
||||
|
||||
def become_partial(self, mobject, a, b):
|
||||
assert(isinstance(mobject, VMobject))
|
||||
|
@ -22,6 +22,7 @@ class PiCreature(SVGMobject):
|
||||
"color" : BLUE_E,
|
||||
"stroke_width" : 0,
|
||||
"fill_opacity" : 1.0,
|
||||
"initial_scale_val" : 0.01,
|
||||
}
|
||||
def __init__(self, mode = "plain", **kwargs):
|
||||
self.parts_named = False
|
||||
@ -33,10 +34,6 @@ class PiCreature(SVGMobject):
|
||||
SVGMobject.__init__(self, svg_file, **kwargs)
|
||||
self.init_colors()
|
||||
|
||||
def move_into_position(self):
|
||||
self.scale_to_fit_height(4)
|
||||
self.center()
|
||||
|
||||
def name_parts(self):
|
||||
self.mouth = self.submobjects[MOUTH_INDEX]
|
||||
self.body = self.submobjects[BODY_INDEX]
|
||||
@ -53,7 +50,7 @@ class PiCreature(SVGMobject):
|
||||
self.parts_named = True
|
||||
|
||||
def init_colors(self):
|
||||
VMobject.init_colors(self)
|
||||
self.set_stroke(color = BLACK, width = self.stroke_width)
|
||||
if not self.parts_named:
|
||||
self.name_parts()
|
||||
self.mouth.set_fill(BLACK)
|
||||
|
@ -1,5 +1,8 @@
|
||||
from helpers import *
|
||||
|
||||
from mobject.vectorized_mobject import VMobject
|
||||
from mobject.tex_mobject import TexMobject
|
||||
|
||||
from scene import Scene
|
||||
|
||||
|
||||
@ -81,39 +84,29 @@ class CountingScene(Scene):
|
||||
self.number = num_mob
|
||||
return self
|
||||
|
||||
|
||||
BIG_N_PASCAL_ROWS = 11
|
||||
N_PASCAL_ROWS = 7
|
||||
|
||||
class PascalsTriangleScene(Scene):
|
||||
args_list = [
|
||||
(N_PASCAL_ROWS,),
|
||||
(BIG_N_PASCAL_ROWS,),
|
||||
]
|
||||
@staticmethod
|
||||
def args_to_string(*args):
|
||||
return str(args[0])
|
||||
|
||||
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)
|
||||
)
|
||||
class PascalsTriangle(VMobject):
|
||||
CONFIG = {
|
||||
"nrows" : 7,
|
||||
"height" : 2*SPACE_HEIGHT - 1,
|
||||
"width" : 1.5*SPACE_WIDTH,
|
||||
"portion_to_fill" : 0.7
|
||||
}
|
||||
def generate_points(self):
|
||||
self.cell_height = self.height / self.nrows
|
||||
self.cell_width = self.width / self.nrows
|
||||
self.bottom_left = (self.cell_width * self.nrows / 2.0)*LEFT + \
|
||||
(self.cell_height * self.nrows / 2.0)*DOWN
|
||||
num_to_num_mob = {}
|
||||
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:
|
||||
num = choose(n, k)
|
||||
center = self.coords_to_center(n, k)
|
||||
if num not in num_to_num_mob:
|
||||
num_to_num_mob[num] = TexMobject(str(num))
|
||||
num_mob = num_to_num_mob[num].copy()
|
||||
num_mob = TexMobject(str(num))
|
||||
scale_factor = min(
|
||||
1,
|
||||
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:
|
||||
self.coords_to_mobs[n] = {}
|
||||
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):
|
||||
return self.bottom_left + (
|
||||
self.cell_width * (k+self.nrows/2.0 - n/2.0),
|
||||
self.cell_height * (self.nrows - n),
|
||||
0
|
||||
)
|
||||
x_offset = self.cell_width * (k+self.nrows/2.0 - n/2.0)
|
||||
y_offset = self.cell_height * (self.nrows - n)
|
||||
return self.bottom_left + x_offset*RIGHT + y_offset*UP
|
||||
|
||||
def generate_n_choose_k_mobs(self):
|
||||
self.coords_to_n_choose_k = {}
|
||||
@ -146,6 +141,17 @@ class PascalsTriangleScene(Scene):
|
||||
if n not in self.coords_to_n_choose_k:
|
||||
self.coords_to_n_choose_k[n] = {}
|
||||
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):
|
||||
zero = TexMobject("0")
|
||||
@ -158,7 +164,7 @@ class PascalsTriangleScene(Scene):
|
||||
mob.shift(self.coords_to_center(n, k))
|
||||
self.coords_to_mobs[n][k] = mob
|
||||
self.add(mob)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
|
||||
|
@ -113,6 +113,7 @@ class Arrow(Line):
|
||||
"color" : YELLOW_C,
|
||||
"tip_length" : 0.25,
|
||||
"buff" : 0.3,
|
||||
"propogate_style_to_family" : True,
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
@ -145,6 +146,13 @@ class Vector(Arrow):
|
||||
def __init__(self, start, direction, **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):
|
||||
CONFIG = {
|
||||
"color" : YELLOW,
|
||||
|
@ -18,6 +18,7 @@ class NumberLine(VMobject):
|
||||
"numbers_with_elongated_ticks" : [0],
|
||||
"longer_tick_multiple" : 2,
|
||||
"number_at_center" : 0,
|
||||
"propogate_style_to_family" : True
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
|
0
triangle_of_power/__init__.py
Normal file
0
triangle_of_power/__init__.py
Normal file
446
triangle_of_power/intro.py
Normal file
446
triangle_of_power/intro.py
Normal 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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user