3b1b-manim/transform_article.py

218 lines
5.9 KiB
Python
Raw Normal View History

from topics import *
from animation import *
def half_plane():
plane = NumberPlane(
x_radius = SPACE_WIDTH/2,
x_unit_to_spatial_width = 0.5,
y_unit_to_spatial_height = 0.5,
density = 2*DEFAULT_POINT_DENSITY_1D,
)
plane.add_coordinates(
x_vals = range(-6, 7, 2),
y_vals = range(-6, 7, 2)
)
return plane
class SingleVariableFunction(Scene):
args_list = [
(lambda x : x**2 - 3, "ShiftedSquare", True),
(lambda x : x**2 - 3, "ShiftedSquare", False),
]
@staticmethod
def args_to_string(func, name, separate_lines):
return name + ("SeparateLines" if separate_lines else "")
def construct(self, func, name, separate_lines):
base_line = NumberLine(color = "grey")
moving_line = NumberLine(
tick_frequency = 1,
density = 3*DEFAULT_POINT_DENSITY_1D
)
base_line.add_numbers()
def point_function((x, y, z)):
return (func(x), y, z)
target = moving_line.copy().apply_function(point_function)
transform_config = {
"run_time" : 3,
"interpolation_function" : path_along_arc(np.pi/4)
}
if separate_lines:
numbers = moving_line.get_number_mobjects(*range(-7, 7))
negative_numbers = []
for number in numbers:
number.highlight(GREEN_E)
number.shift(-2*moving_line.get_vertical_number_offset())
center = number.get_center()
target_num = number.copy()
target_num.shift(point_function(center) - center)
target.add(target_num)
if center[0] < -0.5:
negative_numbers.append(number)
moving_line.add(*numbers)
base_line.shift(DOWN)
target.shift(DOWN)
moving_line.shift(UP)
self.add(base_line, moving_line)
self.dither(3)
self.play(Transform(moving_line, target, **transform_config))
if separate_lines:
self.play(*[
ApplyMethod(mob.shift, 0.4*UP)
for mob in negative_numbers
])
self.dither(3)
class LineToPlaneFunction(Scene):
args_list = [
(lambda x : (np.cos(x), 0.5*x*np.sin(x)), "Swirl", {}),
(lambda x : (np.cos(x), 0.5*x*np.sin(x)), "Swirl", {
"0" : 0,
"\\frac{\\pi}{2}" : np.pi/2,
"\\pi" : np.pi
})
]
@staticmethod
def args_to_string(func, name, numbers_to_follow):
return name + ("FollowingNumbers" if numbers_to_follow else "")
def construct(self, func, name, numbers_to_follow):
line = NumberLine(
unit_length_to_spatial_width = 0.5,
tick_frequency = 1,
number_at_center = 6,
numerical_radius = 6,
numbers_with_elongated_ticks = [0, 12],
density = 3*DEFAULT_POINT_DENSITY_1D
)
line.to_edge(LEFT)
line_copy = line.copy()
line.add_numbers(*range(0, 14, 2))
divider = Line(SPACE_HEIGHT*UP, SPACE_HEIGHT*DOWN)
plane = half_plane()
plane.shift(0.5*SPACE_WIDTH*RIGHT)
self.add(line, divider, plane)
def point_function(point):
x, y = func(line.point_to_number(point))
return plane.num_pair_to_point((x, y))
target = line_copy.copy().apply_function(point_function)
target.highlight()
anim_config = {"run_time" : 3}
anims = [Transform(line_copy, target, **anim_config)]
colors = iter([BLUE_B, GREEN_D, RED_D])
for tex, number in numbers_to_follow.items():
center = line.number_to_point(number)
dot = Dot(center, color = colors.next())
anims.append(ApplyMethod(
dot.shift,
point_function(center) - center,
**anim_config
))
label = TexMobject(tex)
label.shift(center + 2*UP)
arrow = Arrow(label, dot)
self.add(label)
self.play(ShowCreation(arrow), ShowCreation(dot))
self.dither()
self.remove(arrow, label)
self.dither(2)
self.play(*anims)
self.dither()
class PlaneToPlaneFunctionSeparatePlanes(Scene):
args_list = [
(lambda (x, y) : (x**2+y**2, x**2-y**2), "Quadratic")
]
@staticmethod
def args_to_string(func, name):
return name
def construct(self, func, name):
shift_factor = 0.55
in_plane = half_plane().shift(shift_factor*SPACE_WIDTH*LEFT)
out_plane = half_plane().shift(shift_factor*SPACE_WIDTH*RIGHT)
divider = Line(SPACE_HEIGHT*UP, SPACE_HEIGHT*DOWN)
self.add(in_plane, out_plane, divider)
plane_copy = in_plane.copy()
plane_copy.sub_mobjects = []
def point_function(point):
result = np.array(func((point*2 + 2*shift_factor*SPACE_WIDTH*RIGHT)[:2]))
result = np.append(result/2, [0])
return result + shift_factor*SPACE_WIDTH*RIGHT
target = plane_copy.copy().apply_function(point_function)
target.highlight(GREEN_B)
anim_config = {"run_time" : 5}
self.dither()
self.play(Transform(plane_copy, target, **anim_config))
self.dither()
class PlaneToPlaneFunction(Scene):
args_list = [
(lambda (x, y) : (x**2+y**2, x**2-y**2), "Quadratic")
]
@staticmethod
def args_to_string(func, name):
return name
def construct(self, func, name):
plane = NumberPlane()
background = NumberPlane(color = "grey")
background.add_coordinates()
anim_config = {"run_time" : 3}
def point_function(point):
return np.append(func(point[:2]), [0])
self.add(background, plane)
self.dither(2)
self.play(ApplyPointwiseFunction(point_function, plane, **anim_config))
self.dither(3)