mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
More inventing math progress
This commit is contained in:
@ -5,7 +5,7 @@ import copy
|
|||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from animation import Animation
|
from animation import Animation
|
||||||
from mobject import Mobject
|
from mobject import Mobject, Point
|
||||||
from constants import *
|
from constants import *
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
@ -121,6 +121,9 @@ def rush_into(t):
|
|||||||
def rush_from(t):
|
def rush_from(t):
|
||||||
return 2*high_inflection_0_to_1(t/2.0+0.5) - 1
|
return 2*high_inflection_0_to_1(t/2.0+0.5) - 1
|
||||||
|
|
||||||
|
def slow_into(t):
|
||||||
|
return np.sqrt(1-(1-t)*(1-t))
|
||||||
|
|
||||||
def there_and_back(t, inflection = 10.0):
|
def there_and_back(t, inflection = 10.0):
|
||||||
new_t = 2*t if t < 0.5 else 2*(1 - t)
|
new_t = 2*t if t < 0.5 else 2*(1 - t)
|
||||||
return high_inflection_0_to_1(new_t, inflection)
|
return high_inflection_0_to_1(new_t, inflection)
|
||||||
|
@ -65,6 +65,7 @@ class PiCreature(Mobject):
|
|||||||
part.points = self.points[curr:curr+n_points,:]
|
part.points = self.points[curr:curr+n_points,:]
|
||||||
part.rgbs = self.rgbs[curr:curr+n_points,:]
|
part.rgbs = self.rgbs[curr:curr+n_points,:]
|
||||||
curr += n_points
|
curr += n_points
|
||||||
|
return self
|
||||||
|
|
||||||
def reload_from_parts(self):
|
def reload_from_parts(self):
|
||||||
self.rewire_part_attributes(self_from_parts = True)
|
self.rewire_part_attributes(self_from_parts = True)
|
||||||
|
@ -177,9 +177,13 @@ class Mobject(object):
|
|||||||
self.rotate(np.pi / 7, [1, 0, 0])
|
self.rotate(np.pi / 7, [1, 0, 0])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def replace(self, other_mobject):
|
def replace(self, mobject, stretch = False):
|
||||||
self.scale(other_mobject.get_width()/self.get_width())
|
if stretch:
|
||||||
self.center().shift(other_mobject.get_center())
|
self.stretch_to_fit_width(mobject.get_width())
|
||||||
|
self.stretch_to_fit_height(mobject.get_height())
|
||||||
|
else:
|
||||||
|
self.scale(mobject.get_width()/self.get_width())
|
||||||
|
self.center().shift(mobject.get_center())
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def apply_function(self, function):
|
def apply_function(self, function):
|
||||||
|
@ -93,7 +93,7 @@ class Line(Mobject1D):
|
|||||||
def __init__(self, start, end, density = DEFAULT_POINT_DENSITY_1D, *args, **kwargs):
|
def __init__(self, start, end, density = DEFAULT_POINT_DENSITY_1D, *args, **kwargs):
|
||||||
self.start = np.array(start)
|
self.start = np.array(start)
|
||||||
self.end = np.array(end)
|
self.end = np.array(end)
|
||||||
density *= self.get_length()
|
density *= max(self.get_length(), 0.1)
|
||||||
Mobject1D.__init__(self, density = density, *args, **kwargs)
|
Mobject1D.__init__(self, density = density, *args, **kwargs)
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
|
@ -21,6 +21,7 @@ DEFAULT_COUNT_RUN_TIME = 5.0
|
|||||||
class Scene(object):
|
class Scene(object):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
display_config = PRODUCTION_QUALITY_DISPLAY_CONFIG,
|
display_config = PRODUCTION_QUALITY_DISPLAY_CONFIG,
|
||||||
|
construct_args = [],
|
||||||
background = None,
|
background = None,
|
||||||
start_dither_time = DEFAULT_DITHER_TIME):
|
start_dither_time = DEFAULT_DITHER_TIME):
|
||||||
self.display_config = display_config
|
self.display_config = display_config
|
||||||
@ -38,7 +39,7 @@ class Scene(object):
|
|||||||
self.background = self.original_background
|
self.background = self.original_background
|
||||||
self.shape = self.background.shape[:2]
|
self.shape = self.background.shape[:2]
|
||||||
#TODO, space shape
|
#TODO, space shape
|
||||||
self.construct()
|
self.construct(*construct_args)
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass #To be implemented in subclasses
|
pass #To be implemented in subclasses
|
||||||
|
@ -106,7 +106,10 @@ def command_line_create_scene(movie_prefix = ""):
|
|||||||
)
|
)
|
||||||
name = SceneClass.__name__ + SceneClass.args_to_string(*args)
|
name = SceneClass.__name__ + SceneClass.args_to_string(*args)
|
||||||
print "Constructing %s..."%name
|
print "Constructing %s..."%name
|
||||||
scene = SceneClass(*args, display_config = display_config)
|
scene = SceneClass(
|
||||||
|
display_config = display_config,
|
||||||
|
construct_args = args
|
||||||
|
)
|
||||||
if action == "write":
|
if action == "write":
|
||||||
scene.write_to_movie(os.path.join(movie_prefix, name))
|
scene.write_to_movie(os.path.join(movie_prefix, name))
|
||||||
elif action == "preview":
|
elif action == "preview":
|
||||||
|
@ -4,6 +4,7 @@ import numpy as np
|
|||||||
import itertools as it
|
import itertools as it
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import sys
|
import sys
|
||||||
|
import operator as op
|
||||||
|
|
||||||
|
|
||||||
from animation import *
|
from animation import *
|
||||||
@ -18,7 +19,8 @@ DIVERGENT_SUM_TEXT = [
|
|||||||
"1",
|
"1",
|
||||||
"+2",
|
"+2",
|
||||||
"+4",
|
"+4",
|
||||||
"+8", "+\\cdots",
|
"+8",
|
||||||
|
"+\\cdots",
|
||||||
"+2^n",
|
"+2^n",
|
||||||
"+\\cdots",
|
"+\\cdots",
|
||||||
"= -1",
|
"= -1",
|
||||||
@ -29,15 +31,47 @@ CONVERGENT_SUM_TEXT = [
|
|||||||
"+\\frac{1}{4}",
|
"+\\frac{1}{4}",
|
||||||
"+\\frac{1}{8}",
|
"+\\frac{1}{8}",
|
||||||
"+\\frac{1}{16}",
|
"+\\frac{1}{16}",
|
||||||
"+\\cdots+",
|
"+\\cdots",
|
||||||
"\\frac{1}{2^n}",
|
"+\\frac{1}{2^n}",
|
||||||
"+\\cdots",
|
"+\\cdots",
|
||||||
"=1",
|
"=1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CONVERGENT_SUM_TERMS = [
|
||||||
|
"\\frac{1}{2}",
|
||||||
|
"\\frac{1}{4}",
|
||||||
|
"\\frac{1}{8}",
|
||||||
|
"\\frac{1}{16}",
|
||||||
|
]
|
||||||
|
|
||||||
|
PARTIAL_CONVERGENT_SUMS_TEXT = [
|
||||||
|
"\\frac{1}{2}",
|
||||||
|
"", "", ",\\quad",
|
||||||
|
"\\frac{1}{2} + \\frac{1}{4}",
|
||||||
|
"=", "\\frac{3}{4}", ",\\quad",
|
||||||
|
"\\frac{1}{2} + \\frac{1}{4} + \\frac{1}{8}",
|
||||||
|
"=", "\\frac{7}{8}", ",\\quad",
|
||||||
|
"\\frac{1}{2} + \\frac{1}{4} + \\frac{1}{8} + \\frac{1}{16}",
|
||||||
|
"=", "\\frac{15}{16}", ",\\dots"
|
||||||
|
]
|
||||||
|
|
||||||
|
def partial_sum(n):
|
||||||
|
return sum([1.0/2**(k+1) for k in range(n)])
|
||||||
|
|
||||||
|
ALT_PARTIAL_SUM_TEXT = reduce(op.add, [
|
||||||
|
[str(partial_sum(n)), "&=", "+".join(CONVERGENT_SUM_TERMS[:n])+"\\\\"]
|
||||||
|
for n in range(1, len(CONVERGENT_SUM_TERMS)+1)
|
||||||
|
])+ [
|
||||||
|
"\\vdots", "&", "\\\\",
|
||||||
|
"1.0", "&=", "+".join(CONVERGENT_SUM_TERMS)+"+\\cdots+\\frac{1}{2^n}+\\cdots"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
NUM_WRITTEN_TERMS = 4
|
NUM_WRITTEN_TERMS = 4
|
||||||
INTERVAL_RADIUS = 5
|
INTERVAL_RADIUS = 5
|
||||||
NUM_INTERVAL_TICKS = 16
|
NUM_INTERVAL_TICKS = 16
|
||||||
|
|
||||||
|
|
||||||
def divergent_sum():
|
def divergent_sum():
|
||||||
return tex_mobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2)
|
return tex_mobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2)
|
||||||
|
|
||||||
@ -216,6 +250,26 @@ class ReasonsForMakingVideo(Scene):
|
|||||||
self.add(line_two)
|
self.add(line_two)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
class DiscoverAndDefine(Scene):
|
||||||
|
def construct(self):
|
||||||
|
sum_mob = tex_mobject("\\sum_{n = 1}^\\infty a_n")
|
||||||
|
discover = text_mobject("What does it feel like to discover these?")
|
||||||
|
define = text_mobject([
|
||||||
|
"What does it feel like to",
|
||||||
|
"\\emph{define} ",
|
||||||
|
"them?"
|
||||||
|
])
|
||||||
|
sum_mob.shift(2*UP)
|
||||||
|
define.shift(2*DOWN)
|
||||||
|
define_parts = define.split()
|
||||||
|
define_parts[1].highlight("skyblue")
|
||||||
|
|
||||||
|
self.add(sum_mob)
|
||||||
|
self.animate(FadeIn(discover))
|
||||||
|
self.dither()
|
||||||
|
self.animate(FadeIn(CompoundMobject(*define_parts)))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
class YouAsMathematician(Scene):
|
class YouAsMathematician(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
you = draw_you()
|
you = draw_you()
|
||||||
@ -323,13 +377,17 @@ class ZoomInOnInterval(Scene):
|
|||||||
|
|
||||||
class DanceDotOnInterval(Scene):
|
class DanceDotOnInterval(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
num_height = 1.3*DOWN
|
||||||
interval = zero_to_one_interval()
|
interval = zero_to_one_interval()
|
||||||
dots = [
|
dots = [
|
||||||
Dot(radius = 3*Dot.DEFAULT_RADIUS).shift(INTERVAL_RADIUS*x+UP)
|
Dot(radius = 3*Dot.DEFAULT_RADIUS).shift(INTERVAL_RADIUS*x+UP)
|
||||||
for x in LEFT, RIGHT
|
for x in LEFT, RIGHT
|
||||||
]
|
]
|
||||||
color_range = Color("green").range_to("grey", NUM_WRITTEN_TERMS)
|
color_range = Color("green").range_to("yellow", NUM_WRITTEN_TERMS)
|
||||||
conv_sum = convergent_sum().split()
|
conv_sum = convergent_sum().split()
|
||||||
|
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
|
||||||
|
partial_sums.scale(1.5).to_edge(UP)
|
||||||
|
partial_sum_parts = partial_sums.split()
|
||||||
|
|
||||||
self.add(interval)
|
self.add(interval)
|
||||||
self.animate(*[
|
self.animate(*[
|
||||||
@ -346,17 +404,219 @@ class DanceDotOnInterval(Scene):
|
|||||||
ApplyMethod(dots[0].shift, shift_val),
|
ApplyMethod(dots[0].shift, shift_val),
|
||||||
ShowCreation(line)
|
ShowCreation(line)
|
||||||
)
|
)
|
||||||
num = conv_sum[count]
|
num = conv_sum[count].scale(0.75)
|
||||||
num.shift(RIGHT*(line.get_center()[0]-num.get_center()[0]))
|
num.shift(RIGHT*(line.get_center()[0]-num.get_center()[0]))
|
||||||
if num.get_width() > line.get_length():
|
if num.get_width() > line.get_length():
|
||||||
num.stretch_to_fit_width(line.get_length())
|
num.stretch_to_fit_width(line.get_length())
|
||||||
num.shift(3*DOWN)
|
num.shift(num_height)
|
||||||
self.animate(
|
self.animate(
|
||||||
ApplyMethod(line.shift, 2*DOWN),
|
ApplyMethod(line.shift, 2*DOWN),
|
||||||
FadeIn(num)
|
FadeIn(num)
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.animate(FadeIn(conv_sum[NUM_WRITTEN_TERMS]))
|
partial_sum_parts[0].highlight("yellow")
|
||||||
|
for x in range(0, len(partial_sum_parts), 4):
|
||||||
|
partial_sum_parts[x+2].highlight("yellow")
|
||||||
|
self.animate(*[
|
||||||
|
FadeIn(partial_sum_parts[y])
|
||||||
|
for y in range(x, x+4)
|
||||||
|
])
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
class OrganizePartialSums(Scene):
|
||||||
|
def construct(self):
|
||||||
|
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
|
||||||
|
partial_sums.scale(1.5).to_edge(UP)
|
||||||
|
partial_sum_parts = partial_sums.split()
|
||||||
|
for x in [0] + range(2, len(partial_sum_parts), 4):
|
||||||
|
partial_sum_parts[x].highlight("yellow")
|
||||||
|
pure_sums = [
|
||||||
|
partial_sum_parts[x]
|
||||||
|
for x in range(0, len(partial_sum_parts), 4)
|
||||||
|
]
|
||||||
|
new_pure_sums = deepcopy(pure_sums)
|
||||||
|
for pure_sum, count in zip(new_pure_sums, it.count(3, -1.2)):
|
||||||
|
pure_sum.center().scale(1/1.25).highlight("white")
|
||||||
|
pure_sum.to_edge(LEFT).shift(2*RIGHT+count*UP)
|
||||||
|
|
||||||
|
self.add(*partial_sum_parts)
|
||||||
|
self.dither()
|
||||||
|
self.animate(*[
|
||||||
|
SemiCircleTransform(*pair, counterclockwise=False)
|
||||||
|
for pair in zip(pure_sums, new_pure_sums)
|
||||||
|
]+[
|
||||||
|
FadeOut(mob)
|
||||||
|
for mob in partial_sum_parts
|
||||||
|
if mob not in pure_sums
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
down_arrow = tex_mobject("\\downarrow")
|
||||||
|
down_arrow.to_edge(LEFT).shift(2*RIGHT+2*DOWN)
|
||||||
|
infinite_sum = tex_mobject("".join(CONVERGENT_SUM_TEXT[:-1]), size = "\\samll")
|
||||||
|
infinite_sum.scale(1.5/1.25)
|
||||||
|
infinite_sum.to_corner(DOWN+LEFT).shift(2*RIGHT)
|
||||||
|
self.animate(FadeIn(CompoundMobject(down_arrow, infinite_sum)))
|
||||||
|
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class SeeNumbersApproachOne(Scene):
|
||||||
|
def construct(self):
|
||||||
|
interval = zero_to_one_interval()
|
||||||
|
arrow = Arrow(INTERVAL_RADIUS*RIGHT, tail=ORIGIN).nudge()
|
||||||
|
arrow.shift(DOWN).highlight("yellow")
|
||||||
|
num_dots = 6
|
||||||
|
colors = Color("green").range_to("yellow", num_dots)
|
||||||
|
dots = CompoundMobject(*[
|
||||||
|
Dot(
|
||||||
|
density = 2*DEFAULT_POINT_DENSITY_1D
|
||||||
|
).scale(1+1.0/2.0**x).shift(
|
||||||
|
INTERVAL_RADIUS*RIGHT +\
|
||||||
|
(INTERVAL_RADIUS/2.0**x)*LEFT
|
||||||
|
).highlight(colors.next())
|
||||||
|
for x in range(num_dots)
|
||||||
|
])
|
||||||
|
|
||||||
|
self.add(interval)
|
||||||
|
self.animate(
|
||||||
|
ShowCreation(arrow),
|
||||||
|
ShowCreation(dots),
|
||||||
|
run_time = 2.0
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class HowDoYouDefineInfiniteSums(Scene):
|
||||||
|
def construct(self):
|
||||||
|
you = draw_you().center().rewire_part_attributes()
|
||||||
|
text = text_mobject(
|
||||||
|
["How", " do", " you,\\\\", "\\emph{define}"],
|
||||||
|
size = "\\Huge"
|
||||||
|
).shift(UP).split()
|
||||||
|
text[-1].shift(3*DOWN).highlight("skyblue")
|
||||||
|
sum_mob = tex_mobject("\\sum_{n=0}^\\infty{a_n}")
|
||||||
|
text[-1].shift(LEFT)
|
||||||
|
sum_mob.shift(text[-1].get_center()+2*RIGHT)
|
||||||
|
|
||||||
|
self.add(you)
|
||||||
|
self.dither()
|
||||||
|
for mob in text[:-1]:
|
||||||
|
self.add(mob)
|
||||||
|
self.dither(0.1)
|
||||||
|
self.animate(BlinkPiCreature(you))
|
||||||
|
self.dither()
|
||||||
|
self.add(text[-1])
|
||||||
|
self.dither()
|
||||||
|
self.add(sum_mob)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class LessAboutNewThoughts(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = generating, new, thoughts, to, definitions = text_mobject([
|
||||||
|
"Generating", " new", " thoughts", "$\\rightarrow$",
|
||||||
|
"useful definitions"
|
||||||
|
], size = "\\large").split()
|
||||||
|
gen_cross = ImageMobject("cross").highlight("red")
|
||||||
|
new_cross = deepcopy(gen_cross)
|
||||||
|
for cross, mob in [(gen_cross, generating), (new_cross, new)]:
|
||||||
|
cross.replace(mob, stretch = True)
|
||||||
|
disecting = text_mobject("Disecting")
|
||||||
|
disecting.shift(generating.get_center() + 0.7*UP)
|
||||||
|
old = text_mobject("old")
|
||||||
|
old.shift(new.get_center()+0.7*DOWN)
|
||||||
|
|
||||||
|
kwargs = {"run_time" : 0.25}
|
||||||
|
self.add(*words)
|
||||||
|
self.dither()
|
||||||
|
self.animate(ShowCreation(gen_cross, **kwargs))
|
||||||
|
self.animate(ShowCreation(new_cross, **kwargs))
|
||||||
|
self.dither()
|
||||||
|
self.add(disecting)
|
||||||
|
self.dither(0.25)
|
||||||
|
self.add(old)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class ListOfPartialSums(Scene):
|
||||||
|
def construct(self):
|
||||||
|
all_terms = np.array(tex_mobject(
|
||||||
|
ALT_PARTIAL_SUM_TEXT,
|
||||||
|
size = "\\large"
|
||||||
|
).split())
|
||||||
|
numbers, equals, sums = [
|
||||||
|
all_terms[range(k, 12, 3)]
|
||||||
|
for k in 0, 1, 2
|
||||||
|
]
|
||||||
|
dots = all_terms[12]
|
||||||
|
one = all_terms[-3]
|
||||||
|
last_equal = all_terms[-2]
|
||||||
|
infinite_sum = all_terms[-1]
|
||||||
|
|
||||||
|
self.count(
|
||||||
|
numbers,
|
||||||
|
mode = "show",
|
||||||
|
display_numbers = False,
|
||||||
|
run_time = 1.0
|
||||||
|
)
|
||||||
|
self.animate(ShowCreation(dots))
|
||||||
|
self.dither()
|
||||||
|
self.animate(
|
||||||
|
FadeIn(CompoundMobject(*equals)),
|
||||||
|
*[
|
||||||
|
Transform(deepcopy(number), finite_sum)
|
||||||
|
for number, finite_sum in zip(numbers, sums)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.animate(*[
|
||||||
|
ApplyMethod(s.highlight, "yellow", alpha_func = there_and_back)
|
||||||
|
for s in sums
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
self.add(one.highlight("green"))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class ShowDecreasingDistance(Scene):
|
||||||
|
args_list = [(1,), (2,)]
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string(num):
|
||||||
|
return str(num)
|
||||||
|
|
||||||
|
def construct(self, num):
|
||||||
|
number_line = NumberLine(interval_size = 1).add_numbers()
|
||||||
|
vert_line0 = Line(0.5*UP, UP)
|
||||||
|
vert_line1 = Line(0.5*UP+num*RIGHT, UP+num*RIGHT)
|
||||||
|
horiz_line = Line(UP, UP+num*RIGHT)
|
||||||
|
lines = [vert_line0, vert_line1, horiz_line]
|
||||||
|
for line in lines:
|
||||||
|
line.highlight("green")
|
||||||
|
|
||||||
|
self.add(number_line, *lines)
|
||||||
|
self.dither()
|
||||||
|
self.animate(
|
||||||
|
ApplyMethod(vert_line0.shift, RIGHT),
|
||||||
|
Transform(
|
||||||
|
horiz_line,
|
||||||
|
Line(vert_line0.end+RIGHT, vert_line1.end).highlight("green")
|
||||||
|
),
|
||||||
|
run_time = 2.5
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ def tex_to_image(expression,
|
|||||||
if os.path.exists(image_dir):
|
if os.path.exists(image_dir):
|
||||||
result = [
|
result = [
|
||||||
Image.open(os.path.join(image_dir, png_file)).convert('RGB')
|
Image.open(os.path.join(image_dir, png_file)).convert('RGB')
|
||||||
for png_file in os.listdir(image_dir)
|
for png_file in sorted(
|
||||||
|
os.listdir(image_dir),
|
||||||
|
cmp_enumerated_files
|
||||||
|
)
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
filestem = os.path.join(TEX_DIR, exp_hash)
|
filestem = os.path.join(TEX_DIR, exp_hash)
|
||||||
|
Reference in New Issue
Block a user