mirror of
https://github.com/3b1b/videos.git
synced 2025-08-31 21:58:59 +00:00
1862 lines
58 KiB
Python
1862 lines
58 KiB
Python
from manim_imports_ext import *
|
|
|
|
|
|
class PhotographVsHologram(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
title = Text("Single piece of film")
|
|
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
photo = VGroup(
|
|
Text("Photograph"),
|
|
Text("One point of view"),
|
|
)
|
|
holo = VGroup(
|
|
Text("Our Recording"),
|
|
Text("Many points of view"),
|
|
)
|
|
for part, x in zip([photo, holo], [-1, 1]):
|
|
part[1].scale(0.7)
|
|
part[1].set_color(GREY_A)
|
|
part.arrange(DOWN)
|
|
part.set_x(x * FRAME_WIDTH / 4)
|
|
part.set_y(2)
|
|
part.add_to_back(Arrow(title.get_edge_center(x * RIGHT), part.get_top(), path_arc=-x * 60 * DEGREES))
|
|
|
|
self.add(title)
|
|
|
|
for part in [photo, holo]:
|
|
self.play(
|
|
GrowArrow(part[0]),
|
|
FadeInFromPoint(part[1], part[0].get_start()),
|
|
)
|
|
self.wait()
|
|
self.play(Write(part[2]))
|
|
self.wait()
|
|
|
|
|
|
class GlintArrow(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
circle = Circle(radius=0.25)
|
|
circle.set_stroke(RED, 4)
|
|
circle.insert_n_curves(20)
|
|
arrow = Vector(DR, thickness=5, fill_color=RED)
|
|
arrow.next_to(circle, UL, buff=0)
|
|
self.play(
|
|
GrowArrow(arrow),
|
|
VShowPassingFlash(circle, time_width=1.5, time_span=(0.5, 1.5)),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class WriteHologram(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
title = Text("Hologram", font_size=96)
|
|
title.to_edge(UP)
|
|
self.play(Write(title, stroke_color=GREEN_SCREEN, stroke_width=3, lag_ratio=0.1, run_time=3))
|
|
self.wait()
|
|
|
|
|
|
class WriteTransmissionHologram(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
title = Text("Transmission Hologram", font_size=96)
|
|
title.to_edge(UP)
|
|
self.play(Write(title, stroke_color=GREEN_SCREEN, stroke_width=3, lag_ratio=0.1, run_time=3))
|
|
self.wait()
|
|
|
|
|
|
class WriteWhiteLightReflectionHologram(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
title = Text("White Light Reflection Hologram", font_size=72)
|
|
title.to_edge(UP)
|
|
self.play(Write(title, stroke_color=WHITE, stroke_width=3, lag_ratio=0.1, run_time=3))
|
|
self.wait()
|
|
|
|
|
|
class IndicationOnPhotograph(InteractiveScene):
|
|
def construct(self):
|
|
# Image
|
|
image = ImageMobject("ContrastWithPhotography")
|
|
image.set_height(FRAME_HEIGHT)
|
|
# self.add(image)
|
|
|
|
# Dots
|
|
p0 = (-3.82, 2.11, 0.0)
|
|
p1 = (-3.14, 2.17, 0.0)
|
|
p2 = (2.61, 2.82, 0.0)
|
|
p3 = (3.53, 2.24, 0.0)
|
|
|
|
dot1 = GlowDot(p0, color=TEAL)
|
|
dot2 = GlowDot(p2, color=TEAL)
|
|
|
|
arrow = StrokeArrow(p0, p2, buff=SMALL_BUFF, path_arc=-30 * DEGREES)
|
|
arrow.set_stroke(TEAL)
|
|
|
|
self.play(FadeIn(dot1), FlashAround(dot1, stroke_width=5, time_width=2, color=TEAL))
|
|
self.play(
|
|
TransformFromCopy(dot1, dot2, path_arc=-30 * DEGREES),
|
|
ShowCreation(arrow, run_time=2),
|
|
)
|
|
self.play(
|
|
dot1.animate.move_to(p1),
|
|
dot2.animate.move_to(p3),
|
|
arrow.animate.match_points(StrokeArrow(p1, p3, buff=0.1, path_arc=-30 * DEGREES)),
|
|
rate_func=there_and_back,
|
|
run_time=3
|
|
)
|
|
self.play(
|
|
FadeOut(dot1),
|
|
FadeOut(dot2),
|
|
FadeOut(arrow),
|
|
)
|
|
|
|
|
|
class ContrastPhotographyAndHolography(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
title = Text("Information lost in ordinary photography", font_size=60)
|
|
title.to_edge(UP)
|
|
underline = Underline(title, buff=-0.05)
|
|
|
|
points = BulletedList(
|
|
"All but one viewing angle",
|
|
"Phase",
|
|
buff=LARGE_BUFF
|
|
)
|
|
|
|
points.scale(1.25)
|
|
points.next_to(underline, DOWN, buff=1.5)
|
|
points.shift(2 * LEFT)
|
|
self.add(*(p[0] for p in points))
|
|
|
|
self.play(
|
|
FadeIn(title),
|
|
ShowCreation(underline)
|
|
)
|
|
|
|
for point in points:
|
|
self.wait()
|
|
self.play(Write(point[1:]))
|
|
|
|
self.play(
|
|
FlashAround(points[1], color=TEAL, time_width=1.5, run_time=2),
|
|
points[1].animate.set_color(TEAL)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class Outline(InteractiveScene):
|
|
def construct(self):
|
|
# Add top part
|
|
frame = self.frame
|
|
frame.set_y(2)
|
|
|
|
background = FullScreenRectangle()
|
|
background.fix_in_frame()
|
|
self.add(background)
|
|
|
|
top_outlines = ScreenRectangle().replicate(3)
|
|
top_outlines.arrange(RIGHT, buff=1.5)
|
|
top_outlines.set_width(13)
|
|
top_outlines.set_stroke(WHITE, 2)
|
|
top_outlines.set_fill(BLACK, 1)
|
|
top_outlines.to_edge(UP, buff=LARGE_BUFF)
|
|
|
|
top_images = Group(
|
|
ImageMobject("HologramProcess.jpg"),
|
|
ImageMobject("SimplestHologram.jpg"),
|
|
ImageMobject("HologramEquation.png"),
|
|
)
|
|
top_rects = Group(
|
|
Group(outline, image.replace(outline))
|
|
for outline, image in zip(top_outlines, top_images)
|
|
)
|
|
|
|
top_titles = VGroup(
|
|
Text("The process"),
|
|
Text("The simplest hologram"),
|
|
Text("The general derivation"),
|
|
)
|
|
top_titles.scale(0.75)
|
|
|
|
for rect, title in zip(top_rects, top_titles):
|
|
title.next_to(rect, UP, SMALL_BUFF)
|
|
self.play(
|
|
FadeIn(rect),
|
|
FadeIn(title, 0.25 * UP)
|
|
)
|
|
self.wait()
|
|
|
|
# Highlight process
|
|
self.play(
|
|
FadeOut(top_rects[1:]),
|
|
FadeOut(top_titles[1:]),
|
|
frame.animate.set_height(4).move_to(top_rects[0]),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(top_rects[1:]),
|
|
FadeIn(top_titles[1:]),
|
|
frame.animate.to_default_state().set_y(2),
|
|
run_time=2
|
|
)
|
|
|
|
# Isolation animation
|
|
def isolate(rects, titles, index, faded_opacity=0.15):
|
|
return AnimationGroup(
|
|
*(
|
|
title.animate.set_opacity(1 if i == index else faded_opacity)
|
|
for i, title in enumerate(titles)
|
|
),
|
|
*(
|
|
rect.animate.set_opacity(1 if i == index else faded_opacity)
|
|
for i, rect in enumerate(rects)
|
|
),
|
|
)
|
|
|
|
self.play(isolate(top_rects, top_titles, 0))
|
|
self.wait()
|
|
self.play(isolate(top_rects, top_titles, 1))
|
|
self.wait()
|
|
|
|
# Break down middle step
|
|
mid_outlines = top_outlines.copy()
|
|
mid_outlines.set_opacity(1)
|
|
mid_outlines.next_to(top_rects, DOWN, buff=1.5)
|
|
outer_lines = VGroup(
|
|
CubicBezier(
|
|
top_rects[1].get_corner(DL),
|
|
top_rects[1].get_corner(DL) + DOWN,
|
|
mid_outlines[0].get_corner(UL) + 2 * UP,
|
|
mid_outlines[0].get_corner(UL),
|
|
),
|
|
CubicBezier(
|
|
top_rects[1].get_corner(DR),
|
|
top_rects[1].get_corner(DR) + DOWN,
|
|
mid_outlines[2].get_corner(UR) + 2 * UP,
|
|
mid_outlines[2].get_corner(UR),
|
|
),
|
|
)
|
|
mid_images = Group(
|
|
ImageMobject("ZonePlateExposure"),
|
|
ImageMobject("DotReconstruction"),
|
|
ImageMobject("MultipleDotHologram"),
|
|
)
|
|
|
|
mid_rects = Group(
|
|
Group(outline, image.replace(outline))
|
|
for outline, image in zip(mid_outlines, mid_images)
|
|
)
|
|
|
|
mid_titles = VGroup(
|
|
Text("Exposure pattern"),
|
|
Text("Reconstruction"),
|
|
Text("Added complexity"),
|
|
)
|
|
mid_titles.scale(0.75)
|
|
for rect, title in zip(mid_rects, mid_titles):
|
|
title.next_to(rect, UP, SMALL_BUFF)
|
|
rect.save_state()
|
|
rect.replace(top_rects[1])
|
|
rect.set_opacity(0)
|
|
|
|
self.play(
|
|
LaggedStartMap(Restore, mid_rects),
|
|
ShowCreation(outer_lines, lag_ratio=0),
|
|
frame.animate.set_y(0),
|
|
FadeIn(mid_titles, time_span=(1.5, 2.0), lag_ratio=0.025),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
for index in range(3):
|
|
self.play(isolate(mid_rects, mid_titles, index))
|
|
self.wait()
|
|
self.play(isolate(mid_rects, mid_titles, 0))
|
|
self.wait()
|
|
|
|
# Minilesson
|
|
low_outline = mid_outlines[1].copy()
|
|
low_outline.next_to(mid_rects[1], DOWN, buff=1.5)
|
|
|
|
low_image = ImageMobject("DiffractionGrating")
|
|
low_image.replace(low_outline)
|
|
low_rect = Group(low_outline, low_image)
|
|
low_rect.shift(1.5 * LEFT)
|
|
|
|
in_arrow = Arrow(mid_rects[0].get_bottom() + LEFT, low_rect.get_left(), path_arc=PI / 2, thickness=5, buff=0.15)
|
|
up_arrow = Arrow(low_rect, mid_rects[1], thickness=5, buff=0.15)
|
|
|
|
low_title = Text("Mini-lesson on\nDiffraction Gratings")
|
|
low_title.next_to(low_rect, DOWN)
|
|
|
|
self.play(
|
|
frame.animate.set_y(-4),
|
|
FadeIn(low_rect, DOWN),
|
|
FadeIn(low_title, DOWN),
|
|
GrowArrow(in_arrow),
|
|
run_time=2
|
|
)
|
|
self.play(GrowArrow(up_arrow))
|
|
self.wait()
|
|
|
|
# Zoom in on mini-lesson
|
|
frame.save_state()
|
|
self.play(
|
|
frame.animate.set_height(4).move_to(Group(low_rect, low_title)),
|
|
FadeOut(VGroup(in_arrow, up_arrow)),
|
|
run_time=2,
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
Restore(frame),
|
|
FadeIn(VGroup(in_arrow, up_arrow)),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
|
|
# Back to the middle
|
|
self.play(
|
|
LaggedStartMap(FadeOut, Group(low_title, low_rect, arrow), lag_ratio=0.1, run_time=1),
|
|
frame.animate.set_y(0).set_anim_args(run_time=2),
|
|
)
|
|
self.wait()
|
|
self.play(isolate(mid_rects, mid_titles, 2))
|
|
self.wait()
|
|
|
|
# Back to the top
|
|
self.play(
|
|
LaggedStart(
|
|
(mid_rect.animate.replace(top_rects[1]).set_opacity(0)
|
|
for mid_rect in mid_rects),
|
|
lag_ratio=0.05,
|
|
group_type=Group
|
|
),
|
|
FadeOut(mid_titles),
|
|
Uncreate(outer_lines, lag_ratio=0),
|
|
frame.animate.set_y(2),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
self.play(isolate(top_rects, top_titles, 2))
|
|
self.wait()
|
|
|
|
|
|
class GoalOfRediscovery(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
morty = self.teacher
|
|
self.play(
|
|
self.change_students("pondering", "confused", "maybe", look_at=self.screen),
|
|
morty.change("guilty"),
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
morty.says("I want this to\nfeel rediscovered"),
|
|
self.change_students("tease", "erm", "pondering", look_at=morty.eyes)
|
|
)
|
|
self.wait(2)
|
|
self.look_at(self.screen)
|
|
self.play(self.change_students("thinking", "pondering", "thinking"))
|
|
self.wait(4)
|
|
|
|
|
|
class NameCraigAndSally(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
image = ImageMobject("CraigSallyPaulGrant")
|
|
image.set_height(FRAME_HEIGHT)
|
|
|
|
craig_point = (1.2, 2.0, 0)
|
|
sally_point = (3.9, 1.3, 0)
|
|
|
|
craig_arrow = Vector(DR, thickness=5)
|
|
craig_arrow.next_to(craig_point, UL)
|
|
craig_name = Text("Craig Newswanger")
|
|
craig_name.next_to(craig_arrow.get_start(), UP, buff=SMALL_BUFF)
|
|
|
|
sally_arrow = Vector(DL, thickness=5)
|
|
sally_arrow.next_to(sally_point, UR)
|
|
sally_name = Text("Sally Weber")
|
|
sally_name.next_to(sally_arrow.get_start(), UP, buff=SMALL_BUFF)
|
|
|
|
VGroup(craig_arrow, craig_name, sally_arrow, sally_name).set_fill(WHITE).set_backstroke(BLACK, 5)
|
|
|
|
self.play(
|
|
GrowArrow(craig_arrow),
|
|
FadeIn(craig_name),
|
|
)
|
|
self.play(
|
|
GrowArrow(sally_arrow),
|
|
FadeIn(sally_name),
|
|
)
|
|
|
|
|
|
class ShowALens(InteractiveScene):
|
|
def construct(self):
|
|
# Add lens
|
|
arc = Arc(-30 * DEGREES, 60 * DEGREES)
|
|
flipped = arc.copy().rotate(PI).next_to(arc, LEFT, buff=0)
|
|
arc.append_vectorized_mobject(flipped)
|
|
lens = arc
|
|
lens.set_stroke(WHITE, 2)
|
|
lens.set_fill(GREY_E, 1)
|
|
lens.set_shading(0.1, 0.5, 0)
|
|
lens.set_height(3)
|
|
|
|
# Add lines
|
|
n_lines = 20
|
|
points = np.linspace(lens.get_top(), lens.get_bottom(), n_lines)
|
|
focal_point = lens.get_left() + 2 * LEFT
|
|
in_lines = VGroup(Line(point + 8 * RIGHT, point) for point in points)
|
|
out_lines = VGroup(Line(point, focal_point) for point in points)
|
|
for in_line, out_line in zip(in_lines, out_lines):
|
|
out_line.scale(1.25, about_point=out_line.get_start())
|
|
in_line.append_vectorized_mobject(out_line)
|
|
|
|
in_lines.set_stroke(WHITE, 1)
|
|
in_lines.insert_n_curves(100)
|
|
|
|
self.add(in_lines, lens)
|
|
self.play(ShowCreation(in_lines, lag_ratio=0.01, run_time=2, rate_func=linear))
|
|
self.wait()
|
|
|
|
# Label viewing angle
|
|
text = Text("Single viewing angle")
|
|
text.next_to(lens.get_top(), UR)
|
|
arrow = Vector(RIGHT).next_to(text, RIGHT)
|
|
|
|
self.play(LaggedStart(Write(text, run_time=1), GrowArrow(arrow), lag_ratio=0.5))
|
|
self.wait()
|
|
|
|
|
|
class AskAboutRecordingPhase(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
morty = Mortimer()
|
|
morty.to_corner(DR)
|
|
randy = Randolph(height=2.5)
|
|
randy.next_to(morty, LEFT, buff=1.5, aligned_edge=DOWN)
|
|
for pi in [morty, randy]:
|
|
pi.body.insert_n_curves(100)
|
|
|
|
self.add(morty, randy)
|
|
self.play(
|
|
morty.says(
|
|
Text("""
|
|
How could you
|
|
detect this phase
|
|
difference?
|
|
"""),
|
|
look_at=randy.eyes,
|
|
),
|
|
randy.change("pondering", morty.eyes)
|
|
)
|
|
self.play(Blink(randy))
|
|
self.play(
|
|
randy.animate.look_at(3 * UL),
|
|
morty.change("tease", 3 * UL),
|
|
)
|
|
self.play(randy.change("erm", 3 * UL))
|
|
self.play(Blink(morty))
|
|
self.play(Blink(randy))
|
|
self.wait(2)
|
|
self.play(randy.change("confused", 3 * UL))
|
|
self.play(morty.change("pondering", 3 * UL))
|
|
self.play(Blink(randy))
|
|
self.wait(3)
|
|
self.play(randy.change("thinking", 3 * LEFT))
|
|
self.play(Blink(randy))
|
|
self.play(Blink(morty))
|
|
self.wait(2)
|
|
|
|
|
|
class HowIsThisHelpful(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
stds = self.students
|
|
morty = self.teacher
|
|
self.play(LaggedStart(
|
|
stds[1].says("What does this have\nto do with recording 3d?", mode="maybe", look_at=self.screen),
|
|
stds[0].change("confused", self.screen),
|
|
stds[2].change("erm", self.screen),
|
|
lag_ratio=0.25,
|
|
run_time=2
|
|
))
|
|
self.play(morty.change('well'))
|
|
self.wait(2)
|
|
self.play(self.change_students("maybe", "confused", "pondering", look_at=self.screen))
|
|
self.wait(5)
|
|
|
|
|
|
class NoWhiteLight(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
white_label = VGroup(
|
|
Text("White light", font_size=60),
|
|
Text("(many frequencies)").set_color(GREY_B)
|
|
)
|
|
white_label.arrange(DOWN)
|
|
white_label.to_edge(UP).set_x(-3)
|
|
laser_label = VGroup(
|
|
Text("Laser", font_size=60).set_color(GREEN_SCREEN),
|
|
Text("(single frequency)").set_color(GREY_B),
|
|
)
|
|
laser_label.arrange(DOWN)
|
|
laser_label.move_to(white_label, UP)
|
|
|
|
cross = Cross(white_label, stroke_width=(0, 7, 7, 7, 0))
|
|
|
|
self.add(white_label)
|
|
self.wait()
|
|
self.play(ShowCreation(cross))
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(VGroup(white_label, cross), DR),
|
|
FadeIn(laser_label, DR),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class AnnotateSetup(InteractiveScene):
|
|
def construct(self):
|
|
# Add iamge
|
|
image = ImageMobject("CraigSallyHologramSetup")
|
|
image.set_height(FRAME_HEIGHT)
|
|
# self.add(image)
|
|
|
|
# Reference polarization
|
|
pol_words = Text("Correct the polarization")
|
|
pol_words.set_backstroke(BLACK, 5)
|
|
point = (-0.5, 1.2, 0)
|
|
pol_words.next_to(point, UR, buff=1.5).shift(LEFT)
|
|
pol_arrow = Arrow(pol_words["Correct"].get_bottom(), point)
|
|
|
|
self.play(
|
|
Write(pol_words),
|
|
GrowArrow(pol_arrow)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(pol_words),
|
|
FadeOut(pol_arrow),
|
|
)
|
|
|
|
# Show object beam
|
|
obj_beam_points = [
|
|
(-1.625, 2.167, 0),
|
|
(-1.625, 1.264, 0),
|
|
(0.375, 1.264, 0),
|
|
(-0.625, -3.625, 0),
|
|
(-0.111, -3.167, 0),
|
|
]
|
|
|
|
obj_beam = VMobject().set_points_as_corners(obj_beam_points)
|
|
obj_beam.set_stroke(GREEN_SCREEN, 4)
|
|
obj_beam_name = Text("Object beam")
|
|
obj_beam_name.set_color(GREEN_SCREEN)
|
|
obj_beam_name.next_to(obj_beam.pfp(0.5), RIGHT)
|
|
|
|
scene_point = (1.278, -1.972, 0)
|
|
scene_circle = Circle(radius=0.75).shift(scene_point)
|
|
obj_beam_spread = VGroup(
|
|
Line(obj_beam_points[-1], scene_circle.pfp(a) + np.random.uniform(-0.025, 0.025, 3))
|
|
for a in np.arange(0, 1, 0.001)
|
|
)
|
|
obj_beam_spread.set_stroke(GREEN_SCREEN, 1, 0.25)
|
|
|
|
self.play(
|
|
ShowCreation(obj_beam, rate_func=linear),
|
|
FadeIn(obj_beam_name, lag_ratio=0.1),
|
|
)
|
|
self.play(ShowCreation(obj_beam_spread, lag_ratio=0, rate_func=rush_from))
|
|
self.wait()
|
|
|
|
# Show reference beam
|
|
ref_beam_points = [
|
|
obj_beam_points[0],
|
|
(-1.61, -1.39, 0),
|
|
(-1.056, -1.809, 0),
|
|
]
|
|
ref_beam = obj_beam.copy()
|
|
ref_beam.set_points_as_corners(ref_beam_points)
|
|
ref_beam_name = Text("Reference beam")
|
|
ref_beam_name.match_style(obj_beam_name)
|
|
ref_beam_name.next_to(ref_beam.pfp(0.5), LEFT)
|
|
|
|
ref_circle = Circle(radius=0.5)
|
|
ref_circle.rotate(PI / 2, RIGHT)
|
|
ref_circle.move_to((1.23, -3.39, 0))
|
|
ref_beam_spread = VGroup(
|
|
Line(ref_beam_points[-1], ref_circle.pfp(a) + np.random.uniform(-0.025, 0.025, 3))
|
|
for a in np.arange(0, 1, 0.001)
|
|
)
|
|
ref_beam_spread.match_style(obj_beam_spread)
|
|
|
|
self.play(
|
|
FadeTransform(obj_beam_name, ref_beam_name),
|
|
ReplacementTransform(obj_beam, ref_beam),
|
|
ReplacementTransform(obj_beam_spread, ref_beam_spread),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ArrowWithQMark(InteractiveScene):
|
|
def construct(self):
|
|
arrow = Arrow(3 * LEFT, 3 * RIGHT, path_arc=-PI / 2)
|
|
q_marks = Tex(R"???", font_size=72)
|
|
q_marks.next_to(arrow, UP)
|
|
|
|
self.play(
|
|
Write(arrow),
|
|
Write(q_marks),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ProblemSolvingTipNumber1(InteractiveScene):
|
|
def construct(self):
|
|
# Title
|
|
title = Text("Universal problem-solving tip #1", font_size=72)
|
|
title.to_edge(UP, buff=LARGE_BUFF)
|
|
underline = Underline(title, buff=-SMALL_BUFF)
|
|
parts = VGroup(title[text][0] for text in re.split(" |-", title.text))
|
|
|
|
words = Text("Start with the simplest\nversion of your problem", font_size=72)
|
|
words.set_color(YELLOW)
|
|
|
|
self.play(LaggedStartMap(FadeIn, parts, shift=0.25 * UP, lag_ratio=0.25, run_time=2))
|
|
self.play(ShowCreation(underline))
|
|
self.wait()
|
|
self.play(Write(words), run_time=3)
|
|
self.wait()
|
|
|
|
|
|
class NameElectromagneticField(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
name1 = Text("Electromagetic Field")
|
|
name2 = Text("Electric Field")
|
|
for name in [name1, name2]:
|
|
name.set_backstroke(BLACK, 5)
|
|
name.scale(1.5)
|
|
name.to_edge(UP)
|
|
|
|
expl = Text("3d Vector\nat each point")
|
|
expl.set_x(FRAME_WIDTH / 4)
|
|
expl.to_edge(UP)
|
|
arrow = Vector(RIGHT)
|
|
arrow = Vector(2 * RIGHT)
|
|
arrow.next_to(expl, LEFT)
|
|
|
|
self.play(Write(name1), run_time=1)
|
|
self.wait()
|
|
self.play(TransformMatchingStrings(name1, name2), run_time=1)
|
|
self.wait()
|
|
self.play(
|
|
name2.animate.next_to(arrow, LEFT),
|
|
GrowArrow(arrow),
|
|
FadeIn(expl, RIGHT),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class HoldUpDiffractionEquationInAnticipation(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
equation = Tex(R"d \cdot \sin(\theta) = n \lambda", font_size=60)
|
|
equation.move_to(self.hold_up_spot, DOWN)
|
|
name = TexText("Diffraction equation")
|
|
name.next_to(equation, UP, buff=1.5)
|
|
arrow = Arrow(name, equation)
|
|
|
|
morty = self.teacher
|
|
morty.body.insert_n_curves(100)
|
|
|
|
self.play(
|
|
morty.change("raise_right_hand", equation),
|
|
FadeIn(equation, UP),
|
|
self.change_students("confused", "confused", "erm", equation)
|
|
)
|
|
self.play(
|
|
Write(name),
|
|
GrowArrow(arrow),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
self.change_students("maybe", "confused", "sassy", look_at=self.screen)
|
|
)
|
|
self.wait(3)
|
|
self.play(
|
|
morty.says("You can discover\nthis yourself", mode="hooray"),
|
|
LaggedStartMap(FadeOut, VGroup(equation, arrow, name), shift=UR, lag_ratio=0.2, run_time=2),
|
|
self.change_students("pondering", "pondering", "thinking", look_at=morty.eyes)
|
|
)
|
|
self.wait(3)
|
|
|
|
|
|
class HowLongIsThatSnippet(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.play(
|
|
self.teacher.says("How long is\nthat snippet?"),
|
|
self.change_students("happy", "tease", "thinking", look_at=self.screen)
|
|
)
|
|
self.wait(3)
|
|
|
|
|
|
class HoldUpDiffractionEquation(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
morty = self.teacher
|
|
|
|
equation = Tex(R"d \cdot \sin(\theta) = \lambda", t2c={R"\lambda": TEAL}, font_size=60)
|
|
equation.move_to(self.hold_up_spot, DOWN)
|
|
|
|
words = Text("Remember this")
|
|
words.next_to(equation, UP, 1.5)
|
|
equation.to_edge(RIGHT)
|
|
arrow = Arrow(words, equation)
|
|
|
|
self.play(
|
|
morty.change("raise_left_hand", look_at=equation),
|
|
FadeIn(equation, UP),
|
|
self.change_students("pondering", "pondering", "pondering", equation)
|
|
)
|
|
self.play(
|
|
FadeIn(words, lag_ratio=0.1),
|
|
GrowArrow(arrow),
|
|
)
|
|
self.play(morty.change("tease"))
|
|
self.wait(3)
|
|
|
|
morty.body.insert_n_curves(100)
|
|
self.play(
|
|
self.change_students("thinking", "erm", "pondering", look_at=self.screen),
|
|
morty.change("raise_right_hand", look_at=self.screen),
|
|
)
|
|
self.wait(4)
|
|
|
|
|
|
class AskAboutCenterBeam(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
randy = Randolph()
|
|
randy.to_edge(DOWN)
|
|
self.play(
|
|
randy.thinks("Why is there a\ncentral beam?", mode="confused")
|
|
)
|
|
self.play(Blink(randy))
|
|
self.play(randy.animate.look_at(3 * UR))
|
|
self.play(randy.animate.look_at(3 * DR))
|
|
|
|
|
|
class DistanceApproximation(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
expr = Tex(R"\sqrt{L^2 + x^2} \approx L + \frac{x^2}{2L}")
|
|
expr.to_corner(UL)
|
|
|
|
circle = SurroundingRectangle(expr[R"\frac{x^2}{2L}"])
|
|
circle.round_corners()
|
|
circle.set_stroke(RED)
|
|
words = Text("First order\nTaylor approx.")
|
|
words.next_to(circle, DOWN, LARGE_BUFF)
|
|
words.set_color(RED)
|
|
words.set_backstroke(BLACK, 5)
|
|
arrow = Arrow(words.get_top(), circle.get_bottom())
|
|
arrow.set_color(RED)
|
|
|
|
self.play(Write(expr))
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(circle),
|
|
GrowArrow(arrow),
|
|
FadeIn(words)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class CircleDiffractionEquation(InteractiveScene):
|
|
def construct(self):
|
|
# Add equation
|
|
self.add(FullScreenRectangle())
|
|
equation = Tex(
|
|
R"{d} \cdot \sin(\theta) = n \lambda",
|
|
font_size=72,
|
|
t2c={R"{d}": BLUE, R"\theta": YELLOW, R"\lambda": TEAL}
|
|
)
|
|
equation.set_backstroke(BLACK)
|
|
title = Text("The Diffraction Equation", font_size=60)
|
|
title.set_color(GREY_A)
|
|
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
equation.next_to(title, DOWN, MED_LARGE_BUFF)
|
|
|
|
self.add(title)
|
|
self.add(equation)
|
|
self.play(
|
|
FlashAround(equation, run_time=4, time_width=1.5, buff=MED_SMALL_BUFF),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class DiffractionGratingGreenLaserExampleNumbers(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
lines = VGroup(
|
|
VGroup(
|
|
Text("Grating: 500 lines / mm"),
|
|
Tex(R"\Rightarrow d = 2 \times 10^{-6} \text{m}"),
|
|
).arrange(RIGHT),
|
|
VGroup(
|
|
Text("Green light wavelength: 500 nm "),
|
|
Tex(R"\Rightarrow \lambda = 5 \times 10^{-7} \text{m}"),
|
|
).arrange(RIGHT),
|
|
Tex(R"\theta = \sin^{-1}(\lambda / d) = \sin^{-1}\left(5 \times 10^{-7} / 2 \times 10^{-6} \right) \approx 14.5^\circ")
|
|
)
|
|
lines.arrange(DOWN, aligned_edge=LEFT, buff=LARGE_BUFF)
|
|
lines.to_edge(LEFT)
|
|
lines[0][1].align_to(lines[1][1], LEFT)
|
|
self.add(lines)
|
|
|
|
|
|
class AnnotateZerothOrderBeam2(InteractiveScene):
|
|
def construct(self):
|
|
image = ImageMobject("DiffractionGratingGreenLaser.jpg")
|
|
# self.add(image.set_height(FRAME_HEIGHT))
|
|
|
|
# Names
|
|
points = [
|
|
(-0.67, 1.64, 0.0),
|
|
(3.64, 1.9, 0.0),
|
|
(-4.9, 1.85, 0.0),
|
|
(-5.4, 1.01),
|
|
(2.42, 0.028),
|
|
]
|
|
|
|
names = VGroup(
|
|
Text("Zeroth-order beam"),
|
|
Text("First-order beams"),
|
|
Text("Second-order beams"),
|
|
)
|
|
names.next_to(points[0], UP, buff=2.5)
|
|
names.shift_onto_screen()
|
|
arrow0 = Arrow(names[0], points[0])
|
|
arrows1 = VGroup(
|
|
Arrow(names[1].get_bottom(), points[1]),
|
|
Arrow(names[1].get_bottom(), points[2]),
|
|
)
|
|
arrows2 = VGroup(
|
|
Arrow(names[2].get_bottom(), points[3]),
|
|
Arrow(names[2].get_bottom(), points[4]),
|
|
)
|
|
VGroup(names, arrow0, arrows1, arrows2).set_fill(GREY_E)
|
|
|
|
self.play(
|
|
Write(names[0]),
|
|
GrowArrow(arrow0),
|
|
run_time=1
|
|
)
|
|
self.wait()
|
|
self.remove(arrow0)
|
|
self.play(
|
|
TransformMatchingStrings(names[0], names[1], key_map={"Zeroth": "First", "m": "ms"}),
|
|
TransformFromCopy(arrow0.replicate(2), arrows1),
|
|
run_time=1
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
TransformMatchingStrings(names[1], names[2], key_map={"First": "Second"}),
|
|
ReplacementTransform(arrows1, arrows2),
|
|
run_time=1
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ExactSpacingQuestion(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
question = Text("What is the exact spacing?", font_size=72)
|
|
question.set_backstroke()
|
|
question.to_edge(UP)
|
|
subq = TexText(R"As a function of $\theta'$")
|
|
subq.set_color(GREY_A)
|
|
|
|
self.play(Write(question, stroke_color=WHITE))
|
|
self.wait()
|
|
self.play(question.animate.scale(48 / 72).set_x(-0.25 * FRAME_WIDTH))
|
|
self.wait()
|
|
subq.next_to(question, DOWN)
|
|
self.play(FadeIn(subq, 0.5 * DOWN))
|
|
self.wait()
|
|
|
|
|
|
class DejaVu(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
stds = self.students
|
|
self.play(
|
|
stds[0].change("pondering", self.screen),
|
|
stds[1].change("pondering", self.screen),
|
|
stds[2].says("That looks\nfamiliar", bubble_config=dict(direction=LEFT), look_at=self.screen),
|
|
self.teacher.change("tease"),
|
|
)
|
|
self.wait(2)
|
|
|
|
diff_eq = Tex(R"d \cdot \sin(\theta) = \lambda")
|
|
diff_eq.next_to(stds[0], UR)
|
|
self.play(
|
|
stds[1].change("raise_left_hand", look_at=diff_eq),
|
|
FadeIn(diff_eq, UP)
|
|
)
|
|
self.look_at(diff_eq)
|
|
self.play(stds[2].change("pondering", diff_eq))
|
|
self.wait(3)
|
|
|
|
|
|
class WhatAHologramReconstructs(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
self.add(FullScreenRectangle())
|
|
title = Text("What a Hologram reproduces", font_size=60)
|
|
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
underline = Underline(title, buff=-0.05)
|
|
|
|
items = VGroup(
|
|
Text("1) Copy of the reference wave"),
|
|
Text("2) Copy of the object wave"),
|
|
TexText(R"3) Reflection$^*$ of the object wave"),
|
|
)
|
|
items.scale(0.8)
|
|
items.arrange(DOWN, buff=1.75, aligned_edge=LEFT)
|
|
items.next_to(underline, DOWN, LARGE_BUFF)
|
|
items.to_edge(LEFT)
|
|
|
|
self.play(
|
|
FadeIn(title),
|
|
ShowCreation(underline)
|
|
)
|
|
|
|
self.play(
|
|
LaggedStart(
|
|
(FadeIn(item[:2])
|
|
for item in items),
|
|
lag_ratio=0.05,
|
|
)
|
|
)
|
|
self.wait()
|
|
for n, item in enumerate(items):
|
|
self.play(
|
|
items[:n].animate.set_opacity(0.25),
|
|
FadeIn(item[2:], lag_ratio=0.1)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class AskAboutHigherOrderBeams(TeacherStudentsScene):
|
|
def construct(self):
|
|
stds = self.students
|
|
morty = self.teacher
|
|
self.play(LaggedStart(
|
|
stds[0].change('pondering', self.screen),
|
|
stds[1].says("What about higher\norder beams?", look_at=self.screen),
|
|
stds[2].change("confused", self.screen),
|
|
morty.change("tease")
|
|
))
|
|
self.wait()
|
|
self.play(stds[1].change("sassy", morty.eyes))
|
|
self.wait(6)
|
|
|
|
|
|
class BinaryVsSinusoidalDiffraction(InteractiveScene):
|
|
def construct(self):
|
|
# Add axes
|
|
top_axes, low_axes = two_axes = VGroup(
|
|
Axes((0, 4, 0.5), (0, 1, 0.5), width=6, height=1.5)
|
|
for _ in range(2)
|
|
)
|
|
two_axes.arrange(DOWN, buff=2.0)
|
|
two_axes.to_edge(LEFT, buff=1.5)
|
|
|
|
for axes in two_axes:
|
|
y_label = Text("Opacity", font_size=30)
|
|
y_label.next_to(axes.y_axis, UP, buff=MED_SMALL_BUFF)
|
|
axes.add(y_label)
|
|
axes.y_axis.add_numbers(font_size=16, num_decimal_places=1)
|
|
|
|
self.add(two_axes)
|
|
|
|
# Add graphs
|
|
discontinuities = [*np.arange(5), *(np.arange(5) + 0.2)]
|
|
discontinuities.sort()
|
|
top_graph = top_axes.get_graph(self.func1, x_range=(0, 3.99), discontinuities=discontinuities)
|
|
top_graph.set_stroke(TEAL, 2)
|
|
|
|
low_axes.num_sampled_graph_points_per_tick = 20
|
|
low_graph = low_axes.get_graph(self.func2)
|
|
low_graph.set_stroke(BLUE, 2)
|
|
|
|
graphs = VGroup(top_graph, low_graph)
|
|
|
|
# Add gratings
|
|
top_grating = self.get_grating(top_axes, self.func1, 1000)
|
|
low_grating = self.get_grating(low_axes, self.func2, 1000)
|
|
gratings = VGroup(top_grating, low_grating)
|
|
|
|
# Animate in
|
|
graphs.set_stroke(width=1)
|
|
self.add(graphs)
|
|
for graph, grating in [(top_graph, top_grating), (low_graph, low_grating)]:
|
|
self.add(grating, graph)
|
|
self.play(
|
|
graph.animate.set_stroke(width=2),
|
|
VShowPassingFlash(graph.copy().set_stroke(width=5), time_width=3, rate_func=linear),
|
|
# ShowCreation(graph, rate_func=linear),
|
|
FadeIn(grating, lag_ratio=1e-3),
|
|
run_time=2
|
|
)
|
|
self.play(
|
|
grating.animate.next_to(grating, RIGHT, MED_LARGE_BUFF),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
|
|
# Labels
|
|
high_beam_labels = VGroup(
|
|
Text("Higher order beams", font_size=36).next_to(grating, UP)
|
|
for grating in gratings
|
|
)
|
|
check = Checkmark().set_color(GREEN).scale(1.5)
|
|
check.next_to(high_beam_labels[0])
|
|
ex = Exmark().set_color(RED).scale(1.5)
|
|
ex.next_to(high_beam_labels[1])
|
|
|
|
self.play(LaggedStart(
|
|
FadeIn(high_beam_labels),
|
|
Write(check),
|
|
Write(ex),
|
|
lag_ratio=0.5
|
|
))
|
|
self.wait()
|
|
|
|
def get_grating(self, axes, func, n_slits):
|
|
grating = Rectangle().replicate(n_slits)
|
|
grating.set_stroke(width=0)
|
|
grating.set_fill(GREY_D)
|
|
grating.set_shading(0.25, 0.25, 0)
|
|
grating.arrange(RIGHT, buff=0)
|
|
grating.set_shape(axes.x_axis.get_width(), axes.y_axis.get_height())
|
|
grating.move_to(axes.c2p(0, 0), DL)
|
|
|
|
for mob in grating:
|
|
mob.set_opacity(func(axes.x_axis.p2n(mob.get_center())))
|
|
|
|
# grating.next_to(grating, RIGHT, MED_LARGE_BUFF)
|
|
|
|
return grating
|
|
|
|
def func1(self, x):
|
|
return 0 if x % 1 < 0.2 else 1
|
|
|
|
def func2(self, x):
|
|
return math.sin(TAU * x)**2
|
|
|
|
|
|
class AskWhyForSinusoidalGratingFact(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
stds = self.students
|
|
morty = self.teacher
|
|
|
|
for pi in self.pi_creatures:
|
|
pi.body.insert_n_curves(100)
|
|
|
|
self.play(LaggedStart(
|
|
stds[1].says("Wait, why?", mode="confused", look_at=self.screen),
|
|
stds[0].change("pondering", self.screen),
|
|
stds[2].change("maybe", self.screen),
|
|
))
|
|
self.wait()
|
|
|
|
implication = VGroup(
|
|
Tex(R"\Leftarrow").scale(2),
|
|
Text("More formal\nholography explanation")
|
|
)
|
|
implication.arrange(RIGHT, buff=0.25)
|
|
implication.move_to(2.5 * UP + 2.5 * RIGHT)
|
|
|
|
self.play(
|
|
morty.change("raise_right_hand"),
|
|
GrowFromPoint(implication, morty.get_corner(UL))
|
|
)
|
|
self.play(self.change_students("thinking", "sassy", "erm"))
|
|
self.look_at(self.screen)
|
|
self.play(stds[1].change("pondering", self.screen))
|
|
self.wait(4)
|
|
|
|
|
|
class NeedsMoreRigor(TeacherStudentsScene):
|
|
def construct(self):
|
|
morty = self.teacher
|
|
|
|
arrow = Vector(LEFT, thickness=4)
|
|
arrow.move_to(2.5 * UP)
|
|
words = Text("Sketchy and non-rigorous")
|
|
words.next_to(arrow)
|
|
|
|
self.play(
|
|
morty.change("guilty"),
|
|
self.change_students("erm", "hesitant", "sassy", look_at=self.screen)
|
|
)
|
|
self.play(
|
|
GrowArrow(arrow),
|
|
Write(words)
|
|
)
|
|
self.wait(4)
|
|
|
|
|
|
class CompareFilmTypes(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
categories = VGroup(
|
|
Text("Polaroid instant film"),
|
|
Text("Microfilm"),
|
|
Text("What we used (Bayfol HX200)"),
|
|
)
|
|
categories[2]["(Bayfol HX200)"].set_color(GREY_B)
|
|
|
|
resolutions = VGroup(
|
|
Text("10-20 lines per mm"),
|
|
Text("100-200 lines per mm"),
|
|
Text("> 5,000 lines per mm"),
|
|
)
|
|
|
|
arrows = Vector(RIGHT, thickness=4).replicate(3)
|
|
|
|
last_group = VGroup()
|
|
for text, res, arrow in zip(categories, resolutions, arrows):
|
|
arrow = Vector(RIGHT)
|
|
group = VGroup(text, arrow, res)
|
|
group.arrange(RIGHT)
|
|
res.align_to(text, UP)
|
|
group.to_edge(UP)
|
|
|
|
text.save_state()
|
|
text.set_x(0)
|
|
|
|
self.play(
|
|
FadeOut(last_group, 0.5 * UP),
|
|
FadeIn(text, 0.5 * UP),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
Restore(text),
|
|
GrowArrow(arrow),
|
|
FadeIn(res, RIGHT)
|
|
)
|
|
self.wait()
|
|
|
|
last_group = group
|
|
|
|
|
|
class TheresADeeperIssue(TeacherStudentsScene):
|
|
def construct(self):
|
|
for std in self.students:
|
|
std.change_mode("pondering")
|
|
std.look_at(self.screen)
|
|
self.play(
|
|
self.teacher.says("There's a\ndeeper issue"),
|
|
self.change_students("erm", "guilty", "hesitant", look_at=self.teacher.eyes)
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
self.change_students("pondering", "pondering", 'pondering', look_at=self.screen)
|
|
)
|
|
self.wait(2)
|
|
|
|
|
|
class SharpMindedViewer(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
self.add(FullScreenRectangle())
|
|
randy = Randolph()
|
|
randy.to_edge(LEFT)
|
|
randy.shift(DOWN)
|
|
|
|
self.play(randy.change("sassy", RIGHT))
|
|
self.play(Blink(randy))
|
|
self.wait(2)
|
|
self.play(randy.change("confused", RIGHT))
|
|
self.wait()
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
|
|
|
|
class WhatThisExplanationLacks(InteractiveScene):
|
|
def construct(self):
|
|
# Title
|
|
title = Text("Gaps in the single-point explanation", font_size=60)
|
|
title.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
underline = Underline(title, buff=-0.05)
|
|
|
|
self.play(
|
|
FadeIn(title, lag_ratio=0.1),
|
|
ShowCreation(underline),
|
|
)
|
|
self.wait()
|
|
|
|
# Add points
|
|
points = BulletedList(
|
|
"How do errors in the various approximations accumulate?",
|
|
"Why don't higher order beams exist?",
|
|
"What happens when you change the reference beam angle?",
|
|
buff=0.5,
|
|
font_size=48,
|
|
)
|
|
points.next_to(underline, DOWN, buff=0.5)
|
|
points.to_edge(LEFT, buff=LARGE_BUFF)
|
|
|
|
self.play(
|
|
LaggedStartMap(FadeIn, points, shift=UP, lag_ratio=0.5)
|
|
)
|
|
self.wait()
|
|
self.play(points[:2].animate.set_opacity(0.5))
|
|
self.wait()
|
|
|
|
|
|
class SimplicityToGenerality(InteractiveScene):
|
|
def construct(self):
|
|
# Initialize little triangles
|
|
frame = self.frame
|
|
surface = Torus(resolution=(49, 49))
|
|
surface.set_width(4)
|
|
verts = surface.get_shader_data()['point']
|
|
triangles = VGroup(
|
|
Polygon(*tri)
|
|
for tri in zip(verts[0::3], verts[1::3], verts[2::3])
|
|
)
|
|
triangles.set_stroke(WHITE, 0.5, 0.5)
|
|
|
|
tri1 = triangles[3500]
|
|
dists = [get_norm(tri.get_center() - tri1.get_center()) for tri in triangles]
|
|
neighbors = VGroup(triangles[idx] for idx in np.argsort(dists))
|
|
ng1 = neighbors[1:10]
|
|
ng2 = neighbors[10:200]
|
|
ng3 = neighbors[200:]
|
|
for group in [ng1, ng2, ng3]:
|
|
group.save_state()
|
|
for tri in group:
|
|
tri.become(tri1)
|
|
tri.set_stroke(width=0.1, opacity=0.25)
|
|
ng3.set_stroke(opacity=0.05)
|
|
|
|
frame.reorient(4, 83, 0, (-0.11, -0.05, -0.34), 1.91)
|
|
|
|
self.add(tri1)
|
|
self.play(
|
|
LaggedStart(
|
|
Restore(ng1, lag_ratio=0.3),
|
|
Restore(ng2, lag_ratio=0.02),
|
|
Restore(ng3, lag_ratio=3e-4),
|
|
lag_ratio=0.4
|
|
),
|
|
frame.animate.reorient(29, 64, 0, (-0.15, 0.02, -0.43), 3.21),
|
|
run_time=9,
|
|
)
|
|
self.add(triangles)
|
|
|
|
# True surface
|
|
equation = Tex(R"\left(x^2+y^2+z^2+R^2-r^2\right)^2=4 R^2\left(x^2+y^2\right)")
|
|
equation.fix_in_frame()
|
|
equation.to_edge(UP, buff=0.35)
|
|
|
|
new_surface = ParametricSurface(
|
|
lambda u, v: surface.uv_func(v, u),
|
|
u_range=(0, TAU),
|
|
v_range=(0, TAU),
|
|
resolution=(250, 250)
|
|
)
|
|
new_surface.set_width(4)
|
|
new_surface.set_opacity(0.5)
|
|
new_surface.always_sort_to_camera(self.camera)
|
|
|
|
triangles.shuffle()
|
|
self.play(
|
|
FadeOut(triangles, scale=0.8, lag_ratio=3e-4),
|
|
frame.animate.reorient(77, 62, 0, (-0.27, -0.05, -0.23), 4.29),
|
|
run_time=2
|
|
)
|
|
self.play(
|
|
ShowCreation(new_surface, run_time=3),
|
|
frame.animate.reorient(58, 66, 0, (-0.27, -0.05, -0.23), 4.29).set_anim_args(run_time=4),
|
|
)
|
|
self.play(frame.animate.reorient(50, 79, 0, (-0.27, -0.05, -0.23), 4.29), run_time=3)
|
|
|
|
|
|
class ModeledAs2D(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
words = Text("Modeled as 2D")
|
|
words.to_edge(UP)
|
|
point = 1.5 * RIGHT
|
|
arrow = Arrow(words.get_right(), point, path_arc=-180 * DEGREES, thickness=4)
|
|
|
|
self.play(
|
|
FadeIn(words, 0.25 * UP),
|
|
DrawBorderThenFill(arrow, run_time=2)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ThinkingAboutRediscovery(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
randy = Randolph()
|
|
randy.body.insert_n_curves(100)
|
|
randy.to_corner(DL)
|
|
bubble = ThoughtBubble(filler_shape=(5, 2))
|
|
bubble.pin_to(randy)
|
|
bubble = bubble[0]
|
|
bubble.set_fill(opacity=0)
|
|
|
|
rect = FullScreenRectangle().set_fill(BLACK, 1)
|
|
rect.append_points([rect.get_points()[-1], *bubble[-1].get_points()])
|
|
self.add(rect, randy)
|
|
|
|
self.play(
|
|
randy.change('pondering'),
|
|
Write(bubble, stroke_color=WHITE, lag_ratio=0.2)
|
|
)
|
|
self.play(Blink(randy))
|
|
self.wait(2)
|
|
self.play(randy.change('thinking', bubble.get_top()))
|
|
self.play(Blink(randy))
|
|
self.play(randy.change('tease', bubble.get_top()))
|
|
for _ in range(2):
|
|
self.play(Blink(randy))
|
|
self.wait(2)
|
|
|
|
|
|
class IntroduceFormalSection(TeacherStudentsScene):
|
|
def construct(self):
|
|
# Test
|
|
morty = self.teacher
|
|
stds = self.students
|
|
|
|
self.play(LaggedStart(
|
|
stds[0].change("sassy", morty.eyes),
|
|
stds[1].says("Okay but really, why\ndoes it work?", look_at=morty.eyes),
|
|
stds[2].change("angry", look_at=morty.eyes),
|
|
morty.change("guilty"),
|
|
))
|
|
self.wait(2)
|
|
self.play(LaggedStart(
|
|
morty.change("tease"),
|
|
stds[0].change("well"),
|
|
stds[1].debubble(),
|
|
stds[2].change("hesitant"),
|
|
lag_ratio=0.5
|
|
))
|
|
self.wait(2)
|
|
|
|
# Show complex plane
|
|
plane = ComplexPlane((-3, 3), (-3, 3))
|
|
plane.faded_lines.set_stroke(BLUE_E, 1, 0.5)
|
|
plane.axes.set_stroke(width=1)
|
|
plane.background_lines.set_stroke(width=1)
|
|
plane.set_width(3)
|
|
plane.next_to(self.hold_up_spot, UP)
|
|
|
|
a, b = (2, 1.5)
|
|
z = complex(a, b)
|
|
z_dot = GlowDot(plane.n2p(0), color=WHITE)
|
|
z_dot.set_z_index(1)
|
|
h_line = Line(plane.n2p(0), plane.n2p(a))
|
|
v_line = Line(plane.n2p(a), plane.n2p(z))
|
|
h_line.set_stroke(YELLOW, 3)
|
|
v_line.set_stroke(RED, 3)
|
|
a_label = Tex(R"a", font_size=24)
|
|
a_label.match_color(h_line)
|
|
a_label.next_to(h_line, DOWN, buff=0.1)
|
|
b_label = Tex(R"bi", font_size=24)
|
|
b_label.match_color(v_line)
|
|
b_label.next_to(v_line, RIGHT, buff=0.1)
|
|
z_label = Tex(R"a + bi", font_size=24)
|
|
z_label.next_to(v_line.get_end(), UR, SMALL_BUFF)
|
|
VGroup(a_label, b_label, z_label).set_backstroke(BLACK, 3)
|
|
|
|
self.play(
|
|
morty.change("raise_right_hand", plane),
|
|
self.change_students(*3 * ["pondering"], look_at=plane),
|
|
FadeIn(plane, UP),
|
|
)
|
|
self.play(
|
|
ShowCreation(h_line),
|
|
FadeIn(a_label, 0.5 * RIGHT),
|
|
z_dot.animate.move_to(plane.n2p(a)),
|
|
)
|
|
self.play(
|
|
ShowCreation(v_line),
|
|
FadeIn(b_label, 0.5 * UP),
|
|
z_dot.animate.move_to(plane.n2p(z)),
|
|
)
|
|
self.play(
|
|
TransformMatchingShapes(VGroup(a_label, b_label).copy(), z_label)
|
|
)
|
|
self.play(self.change_students("erm", "thinking", "well", look_at=plane))
|
|
self.wait(2)
|
|
|
|
|
|
class HoldUpEquation(InteractiveScene):
|
|
def construct(self):
|
|
pass
|
|
|
|
|
|
class GaborQuote(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
quote = TexText(R"""
|
|
``This was an exercise\\
|
|
in serendipity, the art of\\
|
|
looking for something and\\
|
|
finding something else''
|
|
""", font_size=60, alignment="")
|
|
quote.to_edge(RIGHT)
|
|
|
|
self.play(Write(quote), run_time=2, lag_ratio=0.01)
|
|
self.play(quote["looking for something"].animate.set_color(BLUE), lag_ratio=0.1)
|
|
self.play(quote["finding something else"].animate.set_color(TEAL), lag_ratio=0.1)
|
|
self.wait()
|
|
|
|
|
|
class GaborQuote2(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
quote = TexText(R"""
|
|
``In holography, nature\\
|
|
is on the inventor's side''
|
|
""", font_size=60, alignment="")
|
|
quote.to_edge(RIGHT)
|
|
|
|
self.play(Write(quote), run_time=2, lag_ratio=0.1)
|
|
self.wait()
|
|
|
|
|
|
class ComplexConjugateFact(InteractiveScene):
|
|
def construct(self):
|
|
# Show conjugate
|
|
z = complex(2, 1)
|
|
plane = ComplexPlane(
|
|
(-6, 6), (-4, 4),
|
|
faded_line_ratio=4,
|
|
background_line_style=dict(
|
|
stroke_color=BLUE_D,
|
|
stroke_width=1,
|
|
),
|
|
faded_line_style=dict(
|
|
stroke_color=BLUE_E,
|
|
stroke_width=1,
|
|
stroke_opacity=0.5,
|
|
),
|
|
)
|
|
plane.set_height(7)
|
|
plane.to_edge(DOWN, buff=0.25)
|
|
plane.add_coordinate_labels(font_size=16)
|
|
title = Text("Complex plane")
|
|
title.next_to(plane, UP, buff=SMALL_BUFF)
|
|
|
|
z_arrow = Arrow(plane.get_origin(), plane.n2p(z), buff=0)
|
|
z_arrow.set_color(YELLOW)
|
|
z_label = Tex(R"z = a + bi")
|
|
z_label.next_to(z_arrow.get_end(), UP)
|
|
|
|
z_conj = complex(z.real, -z.imag)
|
|
z_conj_arrow = Arrow(plane.get_origin(), plane.n2p(z_conj), buff=0)
|
|
z_conj_arrow.set_color(TEAL)
|
|
z_conj_label = Tex("z^* = a - bi")
|
|
z_conj_label.next_to(z_conj_arrow.get_end(), DOWN)
|
|
|
|
conj_label = Text("Complex conjugate")
|
|
conj_label.next_to(z_conj_label, DOWN, aligned_edge=LEFT)
|
|
conj_label.set_backstroke(BLACK, 5)
|
|
|
|
self.add(plane, title)
|
|
self.add(z_arrow, z_label)
|
|
self.wait()
|
|
self.play(Write(conj_label, stroke_color=WHITE))
|
|
self.play(
|
|
TransformFromCopy(z_arrow, z_conj_arrow, path_arc=-PI / 2),
|
|
TransformMatchingStrings(z_label.copy(), z_conj_label, path_arc=-PI / 2),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
|
|
# Show product
|
|
product_arrow = Arrow(plane.get_origin(), plane.n2p(z * z_conj), buff=0)
|
|
product_arrow.set_color(WHITE)
|
|
product_label = Tex(R"z \cdot z^* = |z|^2")
|
|
product_label.next_to(product_arrow.get_end(), UP)
|
|
product_label.shift(0.75 * RIGHT)
|
|
|
|
self.play(
|
|
TransformFromCopy(z_label[0], product_label[R"z \cdot"][0]),
|
|
TransformFromCopy(z_conj_label[:2], product_label["z^*"][0]),
|
|
TransformFromCopy(z_arrow, product_arrow),
|
|
TransformFromCopy(z_conj_arrow, product_arrow),
|
|
)
|
|
self.play(Write(product_label["= |z|^2"][0]))
|
|
self.wait()
|
|
|
|
|
|
class PrepareComplexAlgebra(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
lines = VGroup(
|
|
Tex(R"R \cdot (1 - \text{Opacity})"),
|
|
Tex(R"R \cdot (1 - c|R + O|^2)"),
|
|
Tex(R"R - c R \cdot |R + O|^2"),
|
|
)
|
|
lines.arrange(DOWN, buff=0.75)
|
|
lines.to_edge(UP)
|
|
|
|
label = Text("Wave beyond\nthe film")
|
|
arrow = Vector(LEFT)
|
|
arrow.next_to(lines[0], RIGHT)
|
|
label.next_to(arrow, RIGHT)
|
|
|
|
rect = SurroundingRectangle(lines[2][R"R \cdot |R + O|^2"], buff=0.05)
|
|
rect.set_stroke(TEAL, 2)
|
|
|
|
self.play(
|
|
FadeIn(label, lag_ratio=0.1),
|
|
GrowArrow(arrow),
|
|
FadeIn(lines[0], LEFT),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
TransformMatchingStrings(lines[0].copy(), lines[1]),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
TransformMatchingStrings(lines[1].copy(), lines[2]),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(rect),
|
|
lines[:2].animate.set_opacity(0.5),
|
|
lines[2][R"R - c"].animate.set_opacity(0.5),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ComplexAlgebra(InteractiveScene):
|
|
def construct(self):
|
|
# Add first lines
|
|
lines = VGroup(
|
|
Tex(R"R \cdot |R + O|^2"),
|
|
Tex(R"R \cdot (R + O)(R^* + O^*)"),
|
|
Tex(R"R \cdot R \cdot R^* + R \cdot R^* \cdot O + R \cdot R \cdot O^*+ R \cdot O \cdot O^*"),
|
|
Tex(R"\left(|R|^2 + |O|^2 \right) \cdot R + |R|^2 \cdot O + R^2 \cdot O^*"),
|
|
)
|
|
lines[2].scale(0.75)
|
|
lines.arrange(DOWN, buff=LARGE_BUFF)
|
|
lines.to_edge(UP)
|
|
|
|
label = Text("Part of the wave\nbeyond the film", font_size=36)
|
|
arrow = Vector(LEFT)
|
|
arrow.next_to(lines[0], RIGHT)
|
|
label.next_to(arrow, RIGHT)
|
|
label.shift_onto_screen()
|
|
|
|
self.add(lines[0])
|
|
self.play(
|
|
Write(label),
|
|
GrowArrow(arrow)
|
|
)
|
|
self.wait()
|
|
self.play(LaggedStart(
|
|
TransformFromCopy(lines[0][:-1], lines[1][R"R \cdot (R + O)"][0]),
|
|
TransformFromCopy(lines[0]["|R + O|"][0].copy(), lines[1]["(R^* + O^*)"][0]),
|
|
lag_ratio=0.1,
|
|
run_time=2
|
|
))
|
|
self.wait()
|
|
|
|
# FOIL expansion
|
|
R0 = lines[1]["R"][0]
|
|
R = lines[1]["R"][1]
|
|
O = lines[1]["O"][0]
|
|
Rc = lines[1]["R^*"][0]
|
|
Oc = lines[1]["O^*"][0]
|
|
l1_groups = [
|
|
VGroup(R0, R, Rc),
|
|
VGroup(R0, O, Rc),
|
|
VGroup(R0, R, Oc),
|
|
VGroup(R0, O, Oc),
|
|
]
|
|
l2_groups = [
|
|
lines[2][substr]
|
|
for substr in [
|
|
R"R \cdot R \cdot R^*",
|
|
R"R \cdot R^* \cdot O",
|
|
R"R \cdot R \cdot O^*",
|
|
R"R \cdot O \cdot O^*",
|
|
]
|
|
]
|
|
plusses = lines[2]["+"]
|
|
plusses.add_to_back(VectorizedPoint())
|
|
|
|
pre_rects = VGroup(map(self.get_term_rect, l1_groups[0]))
|
|
post_rect = self.get_term_rect(l2_groups[0])
|
|
VGroup(pre_rects, post_rect).set_stroke(width=0, opacity=0)
|
|
self.add(pre_rects, post_rect)
|
|
|
|
for l1_group, l2_group, plus in zip(l1_groups, l2_groups, plusses):
|
|
self.play(
|
|
Transform(pre_rects, VGroup(map(self.get_term_rect, l1_group))),
|
|
Transform(post_rect, self.get_term_rect(l2_group)),
|
|
FadeIn(l2_group),
|
|
FadeIn(plus),
|
|
)
|
|
self.wait(0.5)
|
|
|
|
self.add(lines[2])
|
|
self.play(
|
|
FadeOut(pre_rects),
|
|
FadeOut(post_rect),
|
|
)
|
|
self.wait()
|
|
|
|
# Highlight conjugate pairs
|
|
pair_rects = VGroup(
|
|
self.get_term_rect(lines[2][R"R \cdot R^*"][0]),
|
|
self.get_term_rect(lines[2][R"R \cdot R^*"][1]),
|
|
self.get_term_rect(lines[2][R"O \cdot O^*"]),
|
|
)
|
|
pair_rects.set_stroke(RED, 2)
|
|
|
|
real_label = Text("Real numbers")
|
|
real_label.next_to(lines[2], DOWN, buff=1.5)
|
|
real_label.set_color(RED)
|
|
arrows = VGroup(
|
|
Arrow(real_label, rect.get_bottom())
|
|
for rect in pair_rects
|
|
)
|
|
arrows.set_color(RED)
|
|
|
|
self.play(ShowCreation(pair_rects, lag_ratio=0.1))
|
|
self.play(
|
|
FadeIn(real_label, lag_ratio=0.1),
|
|
LaggedStartMap(GrowArrow, arrows)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(real_label),
|
|
FadeOut(arrows),
|
|
FadeOut(pair_rects),
|
|
)
|
|
self.wait()
|
|
|
|
# Organize into the last line
|
|
lines[3].next_to(lines[2], DOWN, buff=1.5)
|
|
lines[3].set_opacity(1)
|
|
l3_groups = [
|
|
lines[3][R"\left(|R|^2 + |O|^2 \right) \cdot R"],
|
|
lines[3][R"|R|^2 \cdot O"],
|
|
lines[3][R"R^2 \cdot O^*"],
|
|
]
|
|
l2_plusses = lines[2]["+"]
|
|
l3_plusses = lines[3]["+"]
|
|
|
|
l2_rects = VGroup(map(self.get_term_rect, l2_groups))
|
|
l3_rects = VGroup(map(self.get_term_rect, l3_groups))
|
|
l3_rects[2].match_height(l3_rects, stretch=True, about_edge=UP)
|
|
|
|
box1_lines = VGroup(
|
|
self.connecting_line(l2_rects[0], l3_rects[0]),
|
|
self.connecting_line(l2_rects[3], l3_rects[0]),
|
|
)
|
|
box2_line = self.connecting_line(l2_rects[1], l3_rects[1])
|
|
box3_line = self.connecting_line(l2_rects[2], l3_rects[2])
|
|
|
|
real_brace1 = Brace(lines[3][R"\left(|R|^2 + |O|^2 \right)"], DOWN)
|
|
real_brace2 = Brace(lines[3][R"|R|^2"][1], DOWN)
|
|
real_label = real_brace1.get_text("Some real number", font_size=36)
|
|
|
|
fade_opacity = 0.5
|
|
|
|
self.play(
|
|
ShowCreation(box1_lines, lag_ratio=0.5),
|
|
FadeIn(l2_rects[0]),
|
|
FadeIn(l2_rects[3]),
|
|
FadeTransform(l2_groups[0].copy(), l3_groups[0], time_span=(0.5, 2)),
|
|
FadeTransform(l2_groups[3].copy(), l3_groups[0], time_span=(1, 2)),
|
|
FadeIn(l3_rects[0], time_span=(1, 2)),
|
|
l2_groups[1].animate.set_opacity(fade_opacity),
|
|
l2_groups[2].animate.set_opacity(fade_opacity),
|
|
l2_plusses.animate.set_opacity(fade_opacity),
|
|
run_time=2
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
GrowFromCenter(real_brace1),
|
|
FadeIn(real_label, shift=0.25 * DOWN)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
box1_lines.animate.set_stroke(WHITE, 1, 0.5),
|
|
VGroup(l2_rects[0], l2_rects[3], l3_rects[0]).animate.set_stroke(GREY, 1, 0.5),
|
|
l2_groups[1].animate.set_opacity(1),
|
|
l2_groups[0].animate.set_opacity(fade_opacity),
|
|
l2_groups[3].animate.set_opacity(fade_opacity),
|
|
l3_groups[0].animate.set_opacity(fade_opacity),
|
|
FadeOut(real_brace1),
|
|
real_label.animate.set_opacity(fade_opacity),
|
|
)
|
|
self.play(
|
|
FadeIn(l2_rects[1]),
|
|
ShowCreation(box2_line),
|
|
FadeIn(l3_rects[1], time_span=(0.5, 1.5)),
|
|
TransformMatchingShapes(l2_groups[1].copy(), l3_groups[1], run_time=1),
|
|
FadeIn(l3_plusses[1]),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
GrowFromCenter(real_brace2),
|
|
real_label.animate.next_to(real_brace2, DOWN).set_opacity(1)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
box2_line.animate.set_stroke(WHITE, 1, 0.5),
|
|
VGroup(l2_rects[1], l3_rects[1]).animate.set_stroke(GREY, 1, 0.5),
|
|
l2_groups[2].animate.set_opacity(1),
|
|
l2_groups[1].animate.set_opacity(fade_opacity),
|
|
l3_groups[1].animate.set_opacity(fade_opacity),
|
|
l3_plusses[1].animate.set_opacity(fade_opacity),
|
|
FadeOut(real_brace2),
|
|
FadeOut(real_label),
|
|
)
|
|
self.play(
|
|
FadeTransform(l2_groups[2].copy(), l3_groups[2], run_time=1.5),
|
|
ShowCreation(box3_line, run_time=1.5),
|
|
FadeIn(l2_rects[1]),
|
|
FadeIn(l3_rects[2], time_span=(0.5, 1.5)),
|
|
FadeIn(l3_plusses[2])
|
|
)
|
|
self.wait()
|
|
|
|
# Bring back
|
|
self.play(
|
|
FadeOut(VGroup(box1_lines, box2_line, box3_line)),
|
|
FadeOut(l2_rects),
|
|
l3_rects.animate.set_stroke(TEAL, 1, 1),
|
|
lines[2].animate.set_opacity(0.5),
|
|
lines[3].animate.set_opacity(1),
|
|
)
|
|
self.wait()
|
|
|
|
def get_term_rect(self, term):
|
|
rect = SurroundingRectangle(term)
|
|
rect.round_corners()
|
|
rect.set_stroke(TEAL, 2)
|
|
return rect
|
|
|
|
def connecting_line(self, high_box, low_box):
|
|
return CubicBezier(
|
|
high_box.get_bottom(),
|
|
high_box.get_bottom() + 1.0 * DOWN,
|
|
low_box.get_top() + 1.0 * UP,
|
|
low_box.get_top(),
|
|
).set_stroke(WHITE, 2)
|
|
|
|
|
|
class PlaneAfterFilm(InteractiveScene):
|
|
def construct(self):
|
|
# Test
|
|
image = ImageMobject("FilmFromBehind")
|
|
image.set_height(FRAME_HEIGHT)
|
|
image.set_height(FRAME_HEIGHT)
|
|
image.fix_in_frame()
|
|
# self.add(image)
|
|
|
|
rect = Polygon(
|
|
(2.56, -0.12, 0.0),
|
|
(5.69, -2.51, 0.0),
|
|
(6.25, 1.31, 0.0),
|
|
(2.72, 2.62, 0.0),
|
|
)
|
|
rect.set_fill(BLACK, 0.75)
|
|
rect.set_stroke(BLUE, 10)
|
|
rect.fix_in_frame()
|
|
words = Text("True on this\n2D Plane")
|
|
|
|
self.set_floor_plane("xz")
|
|
self.frame.reorient(73, -24, 0, (-1.53, -0.68, 4.14), 9.19)
|
|
|
|
self.play(
|
|
DrawBorderThenFill(rect),
|
|
FadeIn(words),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class LookingAtScreen(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.play(
|
|
self.change_students("confused", "pondering", "maybe", look_at=self.screen),
|
|
self.teacher.change("well")
|
|
)
|
|
self.wait(5)
|
|
|
|
|
|
class EndScreen(PatreonEndScreen):
|
|
pass
|
|
|
|
|
|
# Old stubs
|
|
|
|
class DoubleSlitSupplementaryGraphs(InteractiveScene):
|
|
def construct(self):
|
|
# Setup all three axes, with labels
|
|
|
|
# Show constructive interference
|
|
|
|
# Show destructive interference
|
|
...
|
|
|
|
|
|
class DistApproximations(InteractiveScene):
|
|
def construct(self):
|
|
# Show sqrt(L^2 + x^2) approx L + x/(2L) approx L
|
|
pass
|
|
|
|
|
|
class DiffractionEquation(InteractiveScene):
|
|
def construct(self):
|
|
# Add equation
|
|
equation = Tex(R"{d} \cdot \sin(\theta) = \lambda", font_size=60)
|
|
equation.set_backstroke(BLACK)
|
|
arrow = Vector(DOWN, thickness=4)
|
|
arrow.set_color(BLUE)
|
|
|
|
d, theta, lam = syms = [equation[s][0] for s in [R"{d}", R"\theta", R"\lambda"]]
|
|
colors = [BLUE, YELLOW, TEAL]
|
|
|
|
arrow.next_to(d, UP, LARGE_BUFF)
|
|
arrow.set_fill(opacity=0)
|
|
|
|
self.add(equation)
|
|
|
|
for sym, color in zip(syms, colors):
|
|
self.play(
|
|
FlashAround(sym, color=color, time_span=(0.25, 1.25)),
|
|
sym.animate.set_fill(color),
|
|
arrow.animate.next_to(sym, UP).set_fill(color, 1),
|
|
)
|
|
self.wait()
|
|
self.play(FadeOut(arrow))
|