mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Added FailureOfComposition Scene
This commit is contained in:
parent
4a47d2bca6
commit
c5f1531727
1 changed files with 410 additions and 15 deletions
|
@ -48,24 +48,129 @@ class IntroSceneWrapper(PiCreatureScene):
|
|||
"height" : 2,
|
||||
},
|
||||
"default_pi_creature_start_corner" : DOWN+LEFT,
|
||||
# "default_pi_creature_height" : 1,
|
||||
}
|
||||
def construct(self):
|
||||
self.introduce_two_words()
|
||||
self.describe_main_topic()
|
||||
self.describe_meta_topic()
|
||||
|
||||
def introduce_two_words(self):
|
||||
morty = self.pi_creature
|
||||
rect = ScreenRectangle(height = 5)
|
||||
rect.to_corner(UP+RIGHT)
|
||||
self.add(rect)
|
||||
|
||||
main_topic, meta_topic = toipcs = VGroup(
|
||||
h_line = Line(LEFT, RIGHT).scale(2)
|
||||
h_line.to_corner(UP+LEFT)
|
||||
h_line.shift(0.5*DOWN)
|
||||
|
||||
main_topic, meta_topic = topics = VGroup(
|
||||
TextMobject("Main topic"),
|
||||
TextMobject("Meta topic"),
|
||||
)
|
||||
topics.arrange_submobjects(DOWN, aligned_edge = LEFT)
|
||||
topics.next_to(morty, UP)
|
||||
topics.shift_onto_screen()
|
||||
|
||||
self.play(
|
||||
morty.change, "raise_left_hand",
|
||||
FadeInFromDown(main_topic)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
morty.change, "raise_right_hand",
|
||||
main_topic.next_to, meta_topic.get_top(), UP, MED_SMALL_BUFF,
|
||||
FadeInFromDown(meta_topic)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
morty.change, "happy",
|
||||
main_topic.next_to, h_line, UP,
|
||||
meta_topic.set_fill, {"opacity" : 0.2},
|
||||
)
|
||||
self.play(ShowCreation(h_line))
|
||||
self.wait()
|
||||
|
||||
self.set_variables_as_attrs(h_line, main_topic, meta_topic)
|
||||
|
||||
def describe_main_topic(self):
|
||||
h_line = self.h_line
|
||||
morty = self.pi_creature
|
||||
main_topic = self.main_topic
|
||||
meta_topic = self.meta_topic
|
||||
|
||||
solver = TextMobject("2d equation solver")
|
||||
solver.match_width(h_line)
|
||||
solver.next_to(h_line, DOWN)
|
||||
rainbow_solver1 = solver.copy()
|
||||
rainbow_solver2 = solver.copy()
|
||||
colors = ["RED", "ORANGE", "YELLOW", "GREEN", BLUE, "PURPLE", PINK]
|
||||
rainbow_solver1.gradient_highlight(*colors)
|
||||
rainbow_solver2.gradient_highlight(*reversed(colors))
|
||||
|
||||
|
||||
xy_equation = TexMobject(
|
||||
"y", "e", "^x", "=\\sin(|", "x", "y", "|)"
|
||||
)
|
||||
xy_equation.highlight_by_tex_to_color_map({
|
||||
"x" : BLUE,
|
||||
"y" : YELLOW
|
||||
})
|
||||
xy_equation.next_to(solver, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
z_equation = TexMobject("z", "^5", "+", "z", "+", "1", "=", "0")
|
||||
z_equation.highlight_by_tex("z", GREEN)
|
||||
z_equation.move_to(xy_equation, UP)
|
||||
|
||||
zeta = TexMobject("\\zeta(s) = 0")
|
||||
zeta[2].highlight(GREEN)
|
||||
zeta.next_to(z_equation, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(Write(solver))
|
||||
self.play(
|
||||
LaggedStart(FadeIn, xy_equation, run_time = 1),
|
||||
morty.change, "pondering"
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
FadeOut(xy_equation),
|
||||
FadeIn(z_equation)
|
||||
)
|
||||
self.wait()
|
||||
self.play(Write(zeta))
|
||||
self.wait()
|
||||
solver.save_state()
|
||||
for rainbow_solver in rainbow_solver1, rainbow_solver2:
|
||||
self.play(Transform(
|
||||
solver, rainbow_solver,
|
||||
run_time = 2,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.play(solver.restore)
|
||||
self.wait()
|
||||
|
||||
self.play(LaggedStart(
|
||||
FadeOut, VGroup(solver, z_equation, zeta)
|
||||
))
|
||||
self.play(
|
||||
main_topic.move_to, meta_topic,
|
||||
main_topic.set_fill, {"opacity" : 0.2},
|
||||
meta_topic.move_to, main_topic,
|
||||
meta_topic.set_fill, {"opacity" : 1},
|
||||
morty.change, "hesitant",
|
||||
path_arc = TAU/8,
|
||||
)
|
||||
|
||||
def describe_meta_topic(self):
|
||||
h_line = self.h_line
|
||||
morty = self.pi_creature
|
||||
|
||||
words = TextMobject("Seek constructs which \\\\ compose nicely")
|
||||
words.scale(0.7)
|
||||
words.next_to(h_line, DOWN)
|
||||
|
||||
self.play(Write(words))
|
||||
self.play(morty.change, "happy")
|
||||
self.wait(3)
|
||||
|
||||
class PiCreaturesAreIntrigued(AltTeacherStudentsScene):
|
||||
def construct(self):
|
||||
|
@ -155,6 +260,93 @@ class RewriteEquationWithTeacher(AltTeacherStudentsScene):
|
|||
self.play(dot.move_to, plane.coords_to_point(*coords))
|
||||
self.wait()
|
||||
|
||||
class TwoDScreenInOurThreeDWorld(AltTeacherStudentsScene, ThreeDScene):
|
||||
def construct(self):
|
||||
self.ask_about_2d_functions()
|
||||
self.show_3d()
|
||||
|
||||
def ask_about_2d_functions(self):
|
||||
in_plane = NumberPlane(x_radius = 2.5, y_radius = 2.5)
|
||||
in_plane.add_coordinates()
|
||||
in_plane.scale_to_fit_height(3)
|
||||
out_plane = in_plane.copy()
|
||||
|
||||
in_text = TextMobject("Input space")
|
||||
out_text = TextMobject("Output space")
|
||||
VGroup(in_text, out_text).scale(0.75)
|
||||
in_text.next_to(in_plane, UP, SMALL_BUFF)
|
||||
out_text.next_to(out_plane, UP, SMALL_BUFF)
|
||||
in_plane.add(in_text)
|
||||
out_plane.add(out_text)
|
||||
|
||||
arrow = CurvedArrow(RIGHT, LEFT, angle = TAU/4)
|
||||
arrow.pointwise_become_partial(arrow, 0.05, 1.0)
|
||||
group = VGroup(in_plane, arrow, out_plane)
|
||||
group.arrange_submobjects(RIGHT)
|
||||
arrow.shift(UP)
|
||||
group.move_to(self.students)
|
||||
group.to_edge(UP)
|
||||
|
||||
dots = VGroup()
|
||||
dots_target = VGroup()
|
||||
for x in np.arange(-2.5, 3.0, 0.5):
|
||||
for y in np.arange(-2.5, 3.0, 0.5):
|
||||
dot = Dot(radius = 0.05)
|
||||
dot.move_to(in_plane.coords_to_point(x, y))
|
||||
dot.generate_target()
|
||||
dot.target.move_to(out_plane.coords_to_point(
|
||||
x + 0.25*np.cos(5*y), y + 0.25*np.sin(3*x)
|
||||
))
|
||||
dots.add(dot)
|
||||
dots_target.add(dot.target)
|
||||
dots.gradient_highlight(YELLOW, RED)
|
||||
dots_target.gradient_highlight(YELLOW, RED)
|
||||
|
||||
self.play(
|
||||
self.teacher.change, "raise_right_hand",
|
||||
Write(in_plane, run_time = 1)
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
ReplacementTransform(
|
||||
in_plane.copy(), out_plane,
|
||||
path_arc = -TAU/4,
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
LaggedStart(GrowFromCenter, dots, run_time = 1),
|
||||
self.get_student_changes(*3*["erm"]),
|
||||
)
|
||||
self.play(LaggedStart(MoveToTarget, dots, path_arc = -TAU/4))
|
||||
self.wait(3)
|
||||
|
||||
|
||||
def show_3d(self):
|
||||
laptop = Laptop().scale(2)
|
||||
laptop.rotate(-TAU/12, DOWN)
|
||||
laptop.rotate(-5*TAU/24, LEFT)
|
||||
laptop.rotate(TAU/8, LEFT)
|
||||
laptop.scale(2.3*SPACE_WIDTH/laptop.screen_plate.get_width())
|
||||
laptop.shift(-laptop.screen_plate.get_center() + 0.1*IN)
|
||||
should_shade_in_3d(laptop)
|
||||
|
||||
everything = VGroup(laptop, *self.mobjects)
|
||||
everything.generate_target()
|
||||
# for mob in everything.target.submobject_family():
|
||||
# if isinstance(mob, PiCreature):
|
||||
# mob.change_mode("confused")
|
||||
everything.target.rotate(TAU/12, LEFT)
|
||||
everything.target.rotate(TAU/16, UP)
|
||||
everything.target.shift(4*UP)
|
||||
|
||||
self.move_camera(
|
||||
distance = 12,
|
||||
run_time = 4,
|
||||
added_anims = [MoveToTarget(everything, run_time = 4)],
|
||||
)
|
||||
self.add(AmbientRotation(everything, axis = UP, rate = 3*DEGREES))
|
||||
self.wait(10)
|
||||
|
||||
class DotsHoppingToColor(Scene):
|
||||
CONFIG = {
|
||||
"dot_radius" : 0.05,
|
||||
|
@ -247,13 +439,8 @@ class DotsHoppingToColor(Scene):
|
|||
inspector.scale(0.15)
|
||||
|
||||
inspector_image = inspector.copy()
|
||||
def point_function(point):
|
||||
in_coords = input_plane.point_to_coords(point)
|
||||
out_coords = self.func(in_coords)
|
||||
return output_plane.coords_to_point(*out_coords)
|
||||
|
||||
def update_inspector_image(inspector_image):
|
||||
inspector_image.move_to(point_function(inspector.get_center()))
|
||||
inspector_image.move_to(self.point_function(inspector.get_center()))
|
||||
|
||||
inspector_image_update_anim = UpdateFromFunc(
|
||||
inspector_image, update_inspector_image
|
||||
|
@ -361,19 +548,23 @@ class DotsHoppingToColor(Scene):
|
|||
self.wait()
|
||||
|
||||
|
||||
|
||||
###
|
||||
|
||||
def func(self, coord_pair):
|
||||
out_coords = np.array(self.non_renormalized_func(coord_pair))
|
||||
out_norm = np.linalg.norm(out_coords)
|
||||
if out_norm > 0.5:
|
||||
if out_norm > 0.01:
|
||||
angle = angle_of_vector(out_coords)
|
||||
factor = 0.5-0.1*np.cos(4*angle)
|
||||
target_norm = factor*np.log(out_norm)
|
||||
out_coords *= target_norm / out_norm
|
||||
return tuple(out_coords)
|
||||
|
||||
def point_function(self, point):
|
||||
in_coords = self.input_plane.point_to_coords(point)
|
||||
out_coords = self.func(in_coords)
|
||||
return self.output_plane.coords_to_point(*out_coords)
|
||||
|
||||
def get_colorings(self):
|
||||
in_cmos = ColorMappedObjectsScene(
|
||||
func = lambda p : self.non_renormalized_func(
|
||||
|
@ -404,11 +595,11 @@ class DotsHoppingToColor(Scene):
|
|||
return colorings
|
||||
|
||||
def get_planes(self):
|
||||
input_plane = NumberPlane(
|
||||
input_plane = self.input_plane = NumberPlane(
|
||||
x_radius = self.plane_width/2.0,
|
||||
y_radius = self.plane_height/2.0,
|
||||
)
|
||||
output_plane = input_plane.copy()
|
||||
output_plane = self.output_plane = input_plane.copy()
|
||||
planes = [input_plane, output_plane]
|
||||
vects = [LEFT, RIGHT]
|
||||
label_texts = ["Input", "Output"]
|
||||
|
@ -430,7 +621,6 @@ class DotsHoppingToColor(Scene):
|
|||
if isinstance(submob, TexMobject) and hasattr(submob, "background_rectangle"):
|
||||
submob.remove(submob.background_rectangle)
|
||||
|
||||
|
||||
return planes
|
||||
|
||||
def get_dots(self, input_plane, output_plane):
|
||||
|
@ -491,7 +681,212 @@ class PiCreatureAsksWhatWentWrong(PiCreatureScene):
|
|||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class ForeverNarrowingLoop(DotsHoppingToColor):
|
||||
CONFIG = {
|
||||
"non_renormalized_func" : plane_func_by_wind_spec(
|
||||
(-2, -1, 2),
|
||||
(1, 1, 1),
|
||||
(2, -2, -1),
|
||||
),
|
||||
}
|
||||
def construct(self):
|
||||
input_coloring, output_coloring = colorings = VGroup(*self.get_colorings())
|
||||
input_plane, output_plane = planes = VGroup(*self.get_planes())
|
||||
for plane in planes:
|
||||
plane.white_parts.highlight(BLACK)
|
||||
plane.lines_to_fade.set_stroke(width = 0)
|
||||
|
||||
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
||||
v_line.set_stroke(WHITE, 5)
|
||||
|
||||
self.add(colorings, v_line, planes)
|
||||
self.play(*it.chain(
|
||||
[
|
||||
ApplyMethod(coloring.set_fill, {"opacity" : 0.2})
|
||||
for coloring in colorings
|
||||
],
|
||||
[
|
||||
ApplyMethod(plane.white_parts.highlight, WHITE)
|
||||
for plane in planes
|
||||
]
|
||||
), run_time = 2)
|
||||
|
||||
# circle
|
||||
circle = Circle(color = WHITE, radius = 2.25)
|
||||
circle.flip(axis = RIGHT)
|
||||
circle.insert_n_anchor_points(50)
|
||||
circle.next_to(input_coloring.get_corner(UP+RIGHT), DOWN+LEFT, SMALL_BUFF)
|
||||
circle.set_stroke(width = 5)
|
||||
circle_image = circle.copy()
|
||||
circle.match_background_image_file(input_coloring)
|
||||
circle_image.match_background_image_file(output_coloring)
|
||||
|
||||
def update_circle_image(circle_image):
|
||||
circle_image.points = circle.points
|
||||
circle_image.apply_function(self.point_function)
|
||||
circle_image.make_smooth()
|
||||
|
||||
circle_image_update_anim = UpdateFromFunc(
|
||||
circle_image, update_circle_image
|
||||
)
|
||||
|
||||
self.play(
|
||||
ShowCreation(circle),
|
||||
ShowCreation(circle_image),
|
||||
run_time = 3,
|
||||
rate_func = bezier([0, 0, 1, 1])
|
||||
)
|
||||
# self.play(
|
||||
# ReplacementTransform(
|
||||
# circle.copy(),
|
||||
# circle_image.copy().match_background_image_file(
|
||||
# input_coloring
|
||||
# ).set_stroke(width = 0)
|
||||
# ),
|
||||
# ReplacementTransform(
|
||||
# circle.copy().match_background_image_file(
|
||||
# output_coloring
|
||||
# ).set_stroke(width = 0),
|
||||
# circle_image
|
||||
# ),
|
||||
# run_time = 2
|
||||
# )
|
||||
self.play(
|
||||
circle.scale, 0.015,
|
||||
circle.move_to, input_plane.coords_to_point(1, 1),
|
||||
circle_image_update_anim,
|
||||
run_time = 20,
|
||||
rate_func = bezier([0, 0, 1, 1])
|
||||
)
|
||||
|
||||
class FailureOfComposition(ColorMappedObjectsScene):
|
||||
CONFIG = {
|
||||
"func" : lambda p : (
|
||||
np.cos(TAU*p[1]/3.5),
|
||||
np.sin(TAU*p[1]/3.5)
|
||||
)
|
||||
}
|
||||
def construct(self):
|
||||
ColorMappedObjectsScene.construct(self)
|
||||
|
||||
big_square = Square(side_length = 4)
|
||||
big_square.move_to(ORIGIN, RIGHT)
|
||||
small_squares = VGroup(*[
|
||||
Square(side_length = 2) for x in range(2)
|
||||
])
|
||||
small_squares.match_width(big_square, stretch = True)
|
||||
small_squares.arrange_submobjects(DOWN, buff = 0)
|
||||
small_squares.move_to(big_square)
|
||||
small_squares.space_out_submobjects(1.1)
|
||||
all_squares = VGroup(big_square, *small_squares)
|
||||
all_squares.set_stroke(width = 6)
|
||||
|
||||
for square in all_squares:
|
||||
square.highlight(WHITE)
|
||||
square.color_using_background_image(self.background_image_file)
|
||||
|
||||
question = TextMobject("Does my border go through every color?")
|
||||
question.to_edge(UP)
|
||||
no_answers = VGroup()
|
||||
yes_answers = VGroup()
|
||||
for square in all_squares:
|
||||
if square is big_square:
|
||||
square.answer = TextMobject("Yes")
|
||||
square.answer.highlight(GREEN)
|
||||
yes_answers.add(square.answer)
|
||||
else:
|
||||
square.answer = TextMobject("No")
|
||||
square.answer.highlight(RED)
|
||||
no_answers.add(square.answer)
|
||||
square.answer.move_to(square)
|
||||
|
||||
no_answers_in_equation = no_answers.copy()
|
||||
yes_answers_in_equation = yes_answers.copy()
|
||||
plus, equals = plus_equals = TexMobject("+=")
|
||||
equation = VGroup(
|
||||
no_answers_in_equation[0], plus,
|
||||
no_answers_in_equation[1], equals,
|
||||
yes_answers_in_equation
|
||||
)
|
||||
equation.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
|
||||
equation.next_to(big_square, RIGHT, MED_LARGE_BUFF)
|
||||
q_marks = TexMobject("???")
|
||||
q_marks.next_to(equals, UP)
|
||||
|
||||
|
||||
self.add(question)
|
||||
self.play(LaggedStart(ShowCreation, small_squares, lag_ratio = 0.8))
|
||||
self.play(LaggedStart(Write, no_answers))
|
||||
self.wait()
|
||||
self.play(
|
||||
small_squares.arrange_submobjects, DOWN, {"buff" : 0},
|
||||
small_squares.move_to, big_square,
|
||||
no_answers.space_out_submobjects, 0.9,
|
||||
)
|
||||
self.add(big_square)
|
||||
no_answers_copy = no_answers.copy()
|
||||
small_squares.save_state()
|
||||
self.play(
|
||||
Transform(no_answers, no_answers_in_equation),
|
||||
Write(plus_equals),
|
||||
small_squares.set_stroke, {"width" : 0},
|
||||
)
|
||||
self.play(
|
||||
Write(yes_answers),
|
||||
Write(yes_answers_in_equation),
|
||||
)
|
||||
self.play(LaggedStart(FadeIn, q_marks, run_time = 1))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
small_squares.restore,
|
||||
FadeOut(yes_answers),
|
||||
FadeIn(no_answers_copy),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
small_squares.set_stroke, {"width" : 0},
|
||||
FadeOut(no_answers_copy),
|
||||
FadeIn(yes_answers),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# We can find a better notion of what we want
|
||||
|
||||
cross = Cross(question)
|
||||
|
||||
self.play(
|
||||
ShowCreation(cross, run_time = 2),
|
||||
FadeOut(equation),
|
||||
FadeOut(no_answers),
|
||||
FadeOut(q_marks),
|
||||
FadeOut(yes_answers),
|
||||
)
|
||||
|
||||
x, plus, y = x_plus_y = TexMobject("x+y")
|
||||
x_plus_y.move_to(big_square)
|
||||
x_plus_y.save_state()
|
||||
x.move_to(no_answers_copy[0])
|
||||
y.move_to(no_answers_copy[1])
|
||||
plus.fade(1)
|
||||
|
||||
for square, char in zip(small_squares, [x, y]):
|
||||
ghost = square.copy()
|
||||
ghost.set_stroke(width = 5)
|
||||
ghost.background_image_file = None
|
||||
self.play(
|
||||
small_squares.restore,
|
||||
ShowPassingFlash(ghost),
|
||||
Write(char)
|
||||
)
|
||||
self.wait()
|
||||
ghost = big_square.copy()
|
||||
ghost.background_image_file = None
|
||||
self.play(
|
||||
small_squares.set_stroke, {"width" : 0},
|
||||
x_plus_y.restore,
|
||||
)
|
||||
self.play(ShowPassingFlash(ghost))
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue