3b1b-manim/old_projects/bell.py
2017-09-13 11:35:37 -07:00

2497 lines
77 KiB
Python

from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import *
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.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from topics.probability import *
from topics.complex_numbers import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from tqdm import tqdm as ProgressDisplay
from waves import *
#force_skipping
#revert_to_original_skipping_status
class PhotonPassesCompletelyOrNotAtAll(DirectionOfPolarizationScene):
CONFIG = {
"pol_filter_configs" : [{
"include_arrow_label" : False,
"label_tex" : "\\text{Filter}",
}],
"EMWave_config" : {
"wave_number" : 0,
"A_vect" : [0, 1, 1],
"start_point" : SPACE_WIDTH*LEFT + DOWN + 1.5*OUT,
},
"start_theta" : -0.9*np.pi,
"target_theta" : -0.6*np.pi,
"apply_filter" : True,
"lower_portion_shift" : 3*IN,
"show_M_vects" : True,
}
def setup(self):
DirectionOfPolarizationScene.setup(self)
if not self.show_M_vects:
for M_vect in self.em_wave.M_vects:
M_vect.set_fill(opacity = 0)
self.continual_update()
for vect in it.chain(self.em_wave.E_vects, self.em_wave.M_vects):
vect.reset_normal_vector()
self.remove(self.em_wave)
def construct(self):
pol_filter = self.pol_filter
pol_filter.shift(0.5*OUT)
lower_filter = pol_filter.copy()
lower_filter.save_state()
pol_filter.remove(pol_filter.label)
passing_words = TextMobject("Photon", "passes through\\\\", "entirely")
passing_words.highlight(GREEN)
filtered_words = TextMobject("Photon", "is blocked\\\\", "entirely")
filtered_words.highlight(RED)
for words in passing_words, filtered_words:
words.next_to(ORIGIN, UP+LEFT)
words.shift(2*UP)
words.add_background_rectangle()
words.rotate(np.pi/2, RIGHT)
filtered_words.shift(self.lower_portion_shift)
passing_photon = WavePacket(
run_time = 2,
get_filtered = False,
em_wave = self.em_wave.copy()
)
lower_em_wave = self.em_wave.copy()
lower_em_wave.mobject.shift(self.lower_portion_shift)
lower_em_wave.start_point += self.lower_portion_shift
filtered_photon = WavePacket(
run_time = 2,
get_filtered = True,
em_wave = lower_em_wave.copy()
)
green_flash = ApplyMethod(
pol_filter.set_fill, GREEN,
rate_func = squish_rate_func(there_and_back, 0.4, 0.6),
run_time = passing_photon.run_time
)
self.play(
DrawBorderThenFill(pol_filter),
Write(pol_filter.label, run_time = 2),
)
self.move_camera(theta = self.target_theta)
self.play(
FadeIn(passing_words),
passing_photon,
green_flash,
)
self.play(
lower_filter.restore,
lower_filter.shift, self.lower_portion_shift,
FadeIn(filtered_words)
)
red_flash = ApplyMethod(
lower_filter.set_fill, RED,
rate_func = squish_rate_func(there_and_back, 0.4, 0.6),
run_time = filtered_photon.run_time
)
for x in range(4):
self.play(
passing_photon,
filtered_photon,
green_flash,
red_flash,
)
self.dither()
class PhotonPassesCompletelyOrNotAtAllForWavesVideo(PhotonPassesCompletelyOrNotAtAll):
CONFIG = {
"show_M_vects" : False,
}
class DirectionOfPolarization(DirectionOfPolarizationScene):
def construct(self):
self.remove(self.pol_filter)
self.axes.z_axis.rotate(np.pi/2, OUT)
words = TextMobject("Polarization direction")
words.next_to(ORIGIN, UP+RIGHT, LARGE_BUFF)
words.shift(2*UP)
words.rotate(np.pi/2, RIGHT)
words.rotate(-np.pi/2, OUT)
em_wave = self.em_wave
self.add(em_wave)
self.dither(2)
self.move_camera(
phi = self.target_phi,
theta = self.target_theta
)
self.play(Write(words, run_time = 1))
for angle in 2*np.pi/3, -np.pi/3, np.pi/4:
self.change_polarization_direction(angle)
self.dither()
self.dither(2)
class PhotonsThroughPerpendicularFilters(PhotonPassesCompletelyOrNotAtAll):
CONFIG = {
"filter_x_coordinates" : [-2, 2],
"pol_filter_configs" : [
{"filter_angle" : 0},
{"filter_angle" : np.pi/2},
],
"start_theta" : -0.9*np.pi,
"target_theta" : -0.6*np.pi,
"EMWave_config" : {
"A_vect" : [0, 0, 1],
"start_point" : SPACE_WIDTH*LEFT + DOWN + OUT,
},
"apply_filter" : False,
}
def construct(self):
photons = self.get_photons()
prob_text = self.get_probability_text()
self.pol_filters = VGroup(*reversed(self.pol_filters))
ninety_filter, zero_filter = self.pol_filters
self.remove(*self.pol_filters)
self.play(DrawBorderThenFill(zero_filter), run_time = 1)
self.add_foreground_mobject(zero_filter)
self.move_camera(
theta = self.target_theta,
added_anims = [ApplyFunction(
self.reposition_filter_label,
zero_filter
)]
)
self.reposition_filter_label(ninety_filter)
self.play(self.get_photons()[2])
self.play(FadeIn(ninety_filter))
self.add_foreground_mobject(ninety_filter)
self.shoot_photon()
self.shoot_photon()
self.play(FadeIn(prob_text))
for x in range(6):
self.shoot_photon()
def reposition_filter_label(self, pf):
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
pf.arrow_label.next_to(pf.arrow, RIGHT)
return pf
def shoot_photon(self, *added_anims):
photon = self.get_photons()[1]
pol_filter = self.pol_filters[0]
absorption = self.get_filter_absorption_animation(pol_filter, photon)
self.play(photon, absorption)
def get_photons(self):
self.reference_line.rotate(np.pi/4)
self.continual_update()
return [
WavePacket(
filter_distance = SPACE_WIDTH + x,
get_filtered = True,
em_wave = self.em_wave.copy(),
run_time = 1,
)
for x in -2, 2, 10
]
def get_probability_text(self, prob = 0):
prob_text = TexMobject(
"P(", "\\substack", "{\\text{photons that make it} \\\\ ",
" \\text{here } ", "\\text{make it}",
" \\text{ here} }", ")", "=", str(int(prob*100)), "\\%",
arg_separator = ""
)
here1, here2 = prob_text.get_parts_by_tex("here")
here1.highlight(GREEN)
here2.highlight(RED)
prob_text.add_background_rectangle()
prob_text.next_to(ORIGIN, UP+RIGHT)
prob_text.shift(2.5*UP+LEFT)
prob_text.rotate(np.pi/2, RIGHT)
arrows = [
Arrow(
here.get_edge_center(IN),
DOWN+OUT + x*RIGHT,
color = here.get_color(),
normal_vector = DOWN+OUT,
)
for here, x in (here1, 0), (here2, 4)
]
prob_text.add(*arrows)
return prob_text
class MoreFiltersMoreLight(FilterScene):
CONFIG = {
"filter_x_coordinates" : range(-2, 3),
"pol_filter_configs" : [
{
"include_arrow_label" : False,
"filter_angle" : angle
}
for angle in np.linspace(0, np.pi/2, 5)
],
"ambient_rotation_rate" : 0,
"arrow_rgb" : (0, 0, 0),
"background_rgb" : (245, 245, 245),
}
def construct(self):
self.remove(self.axes)
pfs = VGroup(*reversed(self.pol_filters))
self.color_filters(pfs)
self.remove(pfs)
self.build_color_map(pfs)
self.add(pfs[0], pfs[2], pfs[4])
pfs.center().scale(1.5)
self.move_camera(
phi = 0.9*np.pi/2,
theta = -0.95*np.pi,
)
self.play(
Animation(pfs[0]),
pfs[2].shift, 3*OUT,
Animation(pfs[4]),
)
self.dither()
self.play(
Animation(pfs[0]),
pfs[2].shift, 3*IN,
Animation(pfs[4]),
)
pfs[1].shift(8*OUT)
self.play(
Animation(pfs[0]),
pfs[1].shift, 8*IN,
Animation(VGroup(pfs[2], pfs[4])),
run_time = 2
)
self.dither()
pfs[3].shift(8*OUT)
self.play(
Animation(VGroup(*pfs[:3])),
pfs[3].shift, 8*IN,
Animation(VGroup(*pfs[4:])),
run_time = 2
)
self.dither()
def color_filters(self, pfs):
colors = [RED, GREEN, BLUE, MAROON_B, PURPLE_C]
for pf, color in zip(pfs, colors):
pf.set_fill(color, 0.5)
pf.arrow.set_fill(WHITE, 1)
turn_off_3d_shading(pfs)
def build_color_map(self, pfs):
phi, theta = self.camera.get_phi(), self.camera.get_theta()
self.set_camera_position(np.pi/2, -np.pi)
self.original_rgbs = [(255, 255, 255)]
self.new_rgbs = [self.arrow_rgb]
for bool_array in it.product(*5*[[True, False]]):
pfs_to_use = VGroup(*[
pf
for pf, b in zip(pfs, bool_array)
if b
])
self.camera.capture_mobject(pfs_to_use)
frame = self.camera.get_image()
h, w, three = frame.shape
rgb = frame[3*h/8, 7*w/12]
self.original_rgbs.append(rgb)
angles = [pf.filter_angle for pf in pfs_to_use]
p = 0.5
for a1, a2 in zip(angles, angles[1:]):
p *= np.cos(a2 - a1)**2
new_rgb = (255*p*np.ones(3)).astype(int)
if not any(bool_array):
new_rgb = self.background_rgb
self.new_rgbs.append(new_rgb)
self.camera.reset()
self.set_camera_position(phi, theta)
def update_frame(self, mobjects = None, image = None):
FilterScene.update_frame(self, mobjects)
def get_frame(self):
frame = FilterScene.get_frame(self)
bool_arrays = [
(frame[:,:,0] == r) & (frame[:,:,1] == g) & (frame[:,:,2] == b)
for (r, g, b) in self.original_rgbs
]
for ba, new_rgb in zip(bool_arrays, self.new_rgbs):
frame[ba] = new_rgb
covered = reduce(
lambda b1, b2 : b1 | b2,
bool_arrays
)
frame[~covered] = [65, 65, 65]
return frame
class MoreFiltersMoreLightBlackBackground(MoreFiltersMoreLight):
CONFIG = {
"arrow_rgb" : (255, 255, 255),
"background_rgb" : (0, 0, 0),
}
class ConfusedPiCreature(Scene):
def construct(self):
randy = Randolph()
self.play(
randy.change, "confused", 3*(UP+RIGHT),
)
self.play(Blink(randy))
self.dither(2)
self.play(Blink(randy))
self.dither(2)
class AngryPiCreature(PiCreatureScene):
def construct(self):
self.pi_creature_says(
"No, \\emph{locality} \\\\ must be wrong!",
target_mode = "angry",
look_at_arg = 2*RIGHT,
run_time = 1
)
self.dither(3)
def create_pi_creature(self):
return Randolph().shift(DOWN+3*LEFT)
class ShowALittleMath(TeacherStudentsScene):
def construct(self):
exp1 = TexMobject(
"|", "\\psi", "\\rangle = ",
"\\alpha", "|\\uparrow\\rangle",
"+", "\\beta", "|\\rightarrow\\rangle"
)
exp2 = TexMobject(
"|| \\langle", "\\psi", "|", "\\psi", "\\rangle ||^2",
"= ", "\\alpha", "^2", "+", "\\beta", "^2"
)
color_map = {
"alpha" : GREEN,
"beta" : RED,
"psi" : BLUE
}
for exp in exp1, exp2:
exp.highlight_by_tex_to_color_map(color_map)
exp1.next_to(self.teacher.get_corner(UP+LEFT), UP, LARGE_BUFF)
exp2.move_to(exp1)
self.play(
Write(exp1, run_time = 2),
self.teacher.change, "raise_right_hand"
)
self.play(exp1.shift, UP)
self.play(*[
ReplacementTransform(
exp1.get_parts_by_tex(tex).copy(),
exp2.get_parts_by_tex(tex).copy(),
)
for tex in color_map.keys()
] + [Write(exp2, run_time = 2)])
self.change_student_modes(
*["pondering"]*3,
look_at_arg = exp2
)
self.dither(2)
class SecondVideoWrapper(Scene):
def construct(self):
title = TextMobject("Some light quantum mechanics")
title.to_edge(UP)
self.add(title)
screen_rect = ScreenRectangle(height = 6)
screen_rect.next_to(title, DOWN)
self.play(ShowCreation(screen_rect))
self.dither(3)
class BasicsOfPolarization(DirectionOfPolarizationScene):
CONFIG = {
"apply_filter" : True,
}
def construct(self):
self.setup_rectangles()
self.show_continual_wave()
self.show_photons()
def show_continual_wave(self):
em_wave = self.em_wave
title = TextMobject("Waves in the ``electromagnetic field''")
title.to_edge(UP)
subtitle = TextMobject("Polarization = Direction of", "wiggling")
subtitle.highlight_by_tex("wiggling", BLUE)
subtitle.next_to(title, DOWN)
for words in title, subtitle:
words.add_background_rectangle()
words.rotate(np.pi/2, RIGHT)
self.play(Write(title))
self.dither(2)
self.play(
Write(subtitle, run_time = 2),
FadeIn(self.rectangles)
)
self.change_polarization_direction(np.pi/2, run_time = 3)
self.dither()
self.change_polarization_direction(-np.pi/12, run_time = 2)
self.move_camera(theta = -0.95*np.pi)
self.change_polarization_direction(-np.pi/6, run_time = 2)
self.change_polarization_direction(np.pi/6, run_time = 2)
self.move_camera(theta = -0.6*np.pi)
self.change_polarization_direction(-np.pi/6, run_time = 2)
self.change_polarization_direction(np.pi/6, run_time = 2)
self.change_polarization_direction(-5*np.pi/12, run_time = 2)
self.play(
FadeOut(em_wave.mobject),
FadeOut(self.rectangles),
)
self.remove(em_wave)
self.reference_line.put_start_and_end_on(ORIGIN, RIGHT)
def show_photons(self):
quantum_left_words = TextMobject(
"Quantum", "$\\Rightarrow$",
)
quantum_left_words.next_to(ORIGIN, UP+RIGHT)
quantum_left_words.shift(UP)
quantum_right_words = TextMobject(
"Completely through", "or \\\\",
"Completely blocked",
)
quantum_right_words.scale(0.8)
quantum_right_words.next_to(quantum_left_words, buff = 0)
quantum_right_words.highlight_by_tex("through", GREEN)
quantum_right_words.highlight_by_tex("blocked", RED)
quantum_words = VGroup(quantum_left_words, quantum_right_words)
quantum_words.rotate(np.pi/2, RIGHT)
prob_eq = TexMobject(
"&P(", "\\text{Pass}", ")", "=", "p\\\\",
"&P(", "\\text{Blocked}", ")", "=", "1-p",
)
prob_eq.highlight_by_tex_to_color_map({
"Pass" : GREEN,
"Blocked" : RED,
})
prob_eq.next_to(ORIGIN, DOWN+RIGHT)
prob_eq.shift(RIGHT)
prob_eq.rotate(np.pi/2, RIGHT)
config = dict(self.EMWave_config)
config.update({
"wave_number" : 0,
"A_vect" : [0, 1, -1],
})
self.em_wave = EMWave(**config)
self.continual_update()
passing_photon = WavePacket(
em_wave = self.em_wave.copy(),
run_time = 1.5,
)
filtered_photon = WavePacket(
em_wave = self.em_wave.copy(),
get_filtered = True,
run_time = 1.5,
)
self.play(FadeIn(
quantum_words,
run_time = 2,
submobject_mode = "lagged_start"
))
anim_sets = [
[passing_photon],
[
filtered_photon,
self.get_filter_absorption_animation(
self.pol_filter,
filtered_photon
)
],
]
for index in 0, 1:
self.play(*anim_sets[index])
self.play(
# FadeIn(prob_eq, submobject_mode = "lagged_start"),
passing_photon
)
for index in 1, 0, 0, 1:
self.play(*anim_sets[index])
class AngleToProbabilityChart(Scene):
def construct(self):
left_title = TextMobject("Angle between \\\\ filters")
left_title.to_corner(UP+LEFT)
right_title = TextMobject(
"Probability that photons passing \\\\",
"through the first pass through the second"
)
right_title.next_to(left_title, RIGHT, LARGE_BUFF)
h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH)
h_line.to_edge(UP, buff = 2)
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
v_line.next_to(left_title, RIGHT, MED_LARGE_BUFF)
v_line.to_edge(UP, buff = 0)
VGroup(h_line, v_line).highlight(BLUE)
self.add(left_title, right_title, h_line, v_line)
angles = [0, 22.5, 45, 67.5, 90]
angle_mobs = VGroup(*[
TexMobject(str(angle) + "^\\circ")
for angle in angles
])
angle_mobs.arrange_submobjects(DOWN, buff = MED_LARGE_BUFF)
angle_mobs.next_to(left_title, DOWN, LARGE_BUFF)
probs = [
np.cos(angle*np.pi/180.0)**2
for angle in angles
]
prob_mobs = VGroup(*[
TexMobject("%.1f"%(100*prob) + "\\%")
for prob in probs
])
prob_mobs.highlight(YELLOW)
angle_prob_pairs = zip(angle_mobs, prob_mobs)
for angle_mob, prob_mob in angle_prob_pairs:
prob_mob.next_to(angle_mob, RIGHT, buff = 3)
for prob_mob in prob_mobs[1:]:
prob_mob.align_to(prob_mobs[0], LEFT)
for i in [0, 4, 2, 1, 3]:
self.play(FadeIn(angle_mobs[i]))
self.play(ReplacementTransform(
angle_mobs[i].copy(), prob_mobs[i]
))
explanation = TextMobject("Based on $\\cos(\\theta)^2$")
explanation.next_to(prob_mobs, RIGHT, LARGE_BUFF)
self.play(Write(explanation, run_time = 2))
self.dither()
class ShowVariousFilterPairsWithPhotonsOverTime(PhotonsThroughPerpendicularFilters):
CONFIG = {
"filter_x_coordinates" : [-2, 2, 2, 2, 2],
"pol_filter_configs" : [
{"filter_angle" : angle}
for angle in 0, 0, np.pi/2, np.pi/4, np.pi/8
],
"apply_filter" : False,
}
def setup(self):
PhotonsThroughPerpendicularFilters.setup(self)
self.new_filters = self.pol_filters[2:]
self.remove(*self.new_filters)
self.pol_filters = self.pol_filters[:2]
def construct(self):
self.photons = self.get_photons()
self.add_filters()
self.add_probability_text()
self.show_photons()
for pol_filter in self.new_filters:
self.change_to_new_filter(pol_filter)
self.show_photons()
def add_filters(self):
self.remove(*self.pol_filters[1:])
self.dither()
self.play(ReplacementTransform(
self.pol_filters[0].copy().set_fill(BLACK, 1),
self.pol_filters[1]
))
self.move_camera(
theta = -0.65*np.pi,
added_anims = list(it.chain(*[
[
pf.arrow_label.rotate_in_place, np.pi/2, OUT,
pf.arrow_label.next_to, pf.arrow, RIGHT
]
for pf in self.pol_filters[:2]
]))
)
for pf in self.new_filters:
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
pf.arrow_label.next_to(pf.arrow, RIGHT)
self.second_filter = self.pol_filters[1]
self.add_foreground_mobject(self.second_filter)
def add_probability_text(self):
prob_text = self.get_probability_text(self.get_prob())
self.play(FadeIn(prob_text))
self.prob_text = prob_text
def show_photons(self, n_photons = 5):
p = self.get_prob()
blocked_photon = copy.deepcopy(self.photons[0])
blocked_photon.rate_func = squish_rate_func(
lambda x : x, 0, 0.5,
)
first_absorption = self.get_filter_absorption_animation(
self.pol_filters[0], blocked_photon
)
first_absorption.rate_func = squish_rate_func(
first_absorption.rate_func, 0, 0.5,
)
photons = [
copy.deepcopy(self.photons[2 if q <= p else 1])
for q in np.arange(0, 1, 1./n_photons)
]
random.shuffle(photons)
for photon in photons:
photon.rate_func = squish_rate_func(
lambda x : x, 0.5, 1
)
added_anims = []
if photon.filter_distance == SPACE_WIDTH + 2:
absorption = self.get_filter_absorption_animation(
self.second_filter, photon
)
absorption.rate_func = squish_rate_func(
absorption.rate_func, 0.5, 1
)
added_anims.append(absorption)
self.play(
blocked_photon,
first_absorption,
photon,
*added_anims
)
self.dither()
def change_to_new_filter(self, pol_filter, added_anims = None):
if added_anims is None:
added_anims = []
self.play(
Transform(self.second_filter, pol_filter),
*added_anims
)
self.second_filter.filter_angle = pol_filter.filter_angle
new_prob_text = self.get_probability_text(self.get_prob())
new_prob_text[1][-2].highlight(YELLOW)
self.play(Transform(self.prob_text, new_prob_text))
####
def get_prob(self, pol_filter = None):
if pol_filter is None:
pol_filter = self.second_filter
return np.cos(pol_filter.filter_angle)**2
class ShowVariousFilterPairs(ShowVariousFilterPairsWithPhotonsOverTime):
CONFIG = {
"filter_x_coordinates" : [],
"filter_z_coordinates" : [2.5, 0, -2.5],
"angles" : [0, np.pi/4, np.pi/2],
"n_lines" : 20,
"new_group_shift_val" : 2.5*IN,
"prev_group_shift_val" : 1.75*IN,
"ambient_rotation_rate" : 0.015,
"line_start_length" : 16,
"line_end_length" : 16,
"lines_depth" : 1.2,
"lines_shift_vect" : SMALL_BUFF*OUT,
}
def setup(self):
ShowVariousFilterPairsWithPhotonsOverTime.setup(self)
self.remove(*self.pol_filters)
self.prev_groups = VGroup()
self.remove(self.axes)
self.setup_filters()
self.stop_ambient_camera_rotation()
self.prob_texts = VGroup()
def setup_filters(self):
self.filter_pairs = []
zs = self.filter_z_coordinates
for non_zero_angle, z in zip(self.angles, zs):
filter_pair = VGroup()
for angle, x in (0, -3), (non_zero_angle, 3):
pf = PolarizingFilter(filter_angle = angle)
pf.scale(0.7)
pf.rotate(np.pi/2, RIGHT)
pf.rotate(np.pi/2, IN)
pf.shift(x*RIGHT + z*OUT)
pf.arrow_label.rotate(np.pi/2, OUT)
pf.arrow_label.next_to(pf.arrow, RIGHT, SMALL_BUFF)
filter_pair.add(pf)
self.filter_pairs.append(filter_pair)
def construct(self):
self.add_top_filters()
self.show_light(self.filter_pairs[0])
self.turn_one_filter_pair_into_another(0, 2)
self.show_light(self.filter_pairs[2])
self.turn_one_filter_pair_into_another(2, 1)
self.show_light(self.filter_pairs[1])
def add_top_filters(self):
pf1, pf2 = pair = self.filter_pairs[0]
for pf in pair:
pf.save_state()
pf.arrow_label.rotate(np.pi/2, IN)
pf.arrow_label.next_to(pf.arrow, UP, SMALL_BUFF)
pf.shift(2*IN)
self.add(pf1)
self.play(
ReplacementTransform(pf1.copy().fade(1), pf2),
Animation(pf1)
)
self.move_camera(
0.9*np.pi/2, -0.6*np.pi,
added_anims = [
pf.restore
for pf in pair
]
)
def show_light(self, filter_pair):
pf1, pf2 = filter_pair
lines_to_pf1 = self.get_lines(None, pf1)
vect = lines_to_pf1[1].get_center() - lines_to_pf1[0].get_center()
lines_to_pf1.add(*lines_to_pf1.copy().shift(vect/2))
lines_to_pf2 = self.get_lines(pf1, pf2)
lines_from_pf2 = self.get_lines(pf2)
prob = self.get_prob(pf2)
n_black = int(prob*len(lines_from_pf2))
VGroup(*lines_from_pf2[n_black:]).set_stroke(BLACK, 0)
kwargs = {
"rate_func" : None,
"submobject_mode" : "all_at_once",
}
self.play(ShowCreation(lines_to_pf1, run_time = 2./3, **kwargs))
self.play(
ShowCreation(lines_to_pf2, **kwargs),
Animation(VGroup(pf1, lines_to_pf1)),
run_time = 1./6,
)
self.play(
ShowCreation(lines_from_pf2, **kwargs),
Animation(VGroup(pf2, lines_to_pf2, pf1, lines_to_pf1)),
run_time = 2./3,
)
group = VGroup(
lines_from_pf2, pf2, lines_to_pf2, pf1, lines_to_pf2
)
#Write probability
prob_text = self.get_probability_text(pf2)
self.play(Write(prob_text, run_time = 1))
self.dither()
self.prob_texts.add(prob_text)
def turn_one_filter_pair_into_another(self, i1, i2):
mover = self.filter_pairs[i1].copy()
mover.set_stroke(width = 0)
mover.set_fill(opacity = 0)
target = self.filter_pairs[i2]
self.play(ReplacementTransform(mover, target))
def get_probability_text(self, pol_filter = None):
if pol_filter is None:
pol_filter = self.second_filter
prob = self.get_prob(pol_filter)
prob_mob = TextMobject(str(int(prob*100)) + "\\%", " pass")
prob_mob.scale(0.7)
prob_mob.rotate(np.pi/2, RIGHT)
prob_mob.next_to(pol_filter.arrow_label, RIGHT)
prob_mob.highlight(
list(Color(RED).range_to(GREEN, 11))[int(prob*10)]
)
return prob_mob
#####
def get_lines(
self, filter1 = None, filter2 = None,
ratio = 1.0,
remove_from_bottom = False,
):
# n = int(ratio*self.n_lines)
n = self.n_lines
start, end = [
(f.point_from_proportion(0.75) if f is not None else None)
for f in filter1, filter2
]
if start is None:
start = end + self.line_start_length*LEFT
if end is None:
end = start + self.line_end_length*RIGHT
nudge = (float(self.lines_depth)/self.n_lines)*OUT
lines = VGroup(*[
Line(start, end).shift(z*nudge)
for z in range(n)
])
lines.set_stroke(YELLOW, 2)
lines.move_to(start, IN+LEFT)
lines.shift(self.lines_shift_vect)
n_to_block = int((1-ratio)*self.n_lines)
if remove_from_bottom:
to_block = lines[:n_to_block]
else:
to_block = lines[len(lines)-n_to_block:]
VGroup(*to_block).set_stroke(width = 0)
return lines
class ShowVariousFilterPairsFrom0To45(ShowVariousFilterPairs):
CONFIG = {
"angles" : [0, np.pi/8, np.pi/4]
}
def construct(self):
ShowVariousFilterPairs.construct(self)
self.mention_probabilities()
def mention_probabilities(self):
rects = VGroup()
for prob_text in self.prob_texts:
prob_text.rotate(np.pi/2, LEFT)
rect = SurroundingRectangle(prob_text, color = BLUE)
VGroup(prob_text, rect).rotate(np.pi/2, RIGHT)
rects.add(rect)
cosines = VGroup(*[
TexMobject("\\cos^2(%s^\\circ)"%str(x))
for x in 45, 22.5
])
cosines.scale(0.8)
# cosines.highlight(BLUE)
cosines.rotate(np.pi/2, RIGHT)
for cos, rect in zip(cosines, rects[1:]):
cos.next_to(rect, OUT, SMALL_BUFF)
self.play(LaggedStart(ShowCreation, rects))
self.dither()
self.play(*map(Write, cosines), run_time = 2)
self.dither()
class ForgetPreviousActions(ShowVariousFilterPairs):
CONFIG = {
"filter_x_coordinates" : [-6, -2, 2, 2, 2],
"pol_filter_configs" : [
{"filter_angle" : angle}
for angle in np.pi/4, 0, np.pi/4, np.pi/3, np.pi/6
],
"start_theta" : -0.6*np.pi,
"EMWave_config" : {
"wave_number" : 0,
"start_point" : SPACE_WIDTH*LEFT + DOWN,
},
"apply_filter" : False,
}
def setup(self):
PhotonsThroughPerpendicularFilters.setup(self)
self.remove(self.axes)
VGroup(*self.pol_filters).shift(IN)
for pf in self.pol_filters:
pf.arrow_label.rotate_in_place(np.pi/2, OUT)
pf.arrow_label.next_to(pf.arrow, RIGHT)
self.stop_ambient_camera_rotation()
def construct(self):
front_filter = self.pol_filters[0]
first_filter = self.pol_filters[1]
possible_second_filters = self.pol_filters[2:]
for pf in possible_second_filters:
prob_text = self.get_probability_text(pf)
prob_text.scale(1.3, about_point = prob_text.get_left())
pf.add(prob_text)
second_filter = possible_second_filters[0].copy()
self.second_filter = second_filter
self.pol_filters = VGroup(
first_filter, second_filter
)
self.remove(front_filter)
self.remove(*possible_second_filters)
self.add(second_filter)
self.apply_filter = True
self.continual_update()
self.photons = self.get_photons()[1:]
group = VGroup(*self.pol_filters)
rect1 = SurroundingRectangle(group)
rect1.rotate_in_place(np.pi/2, RIGHT)
rect1.rescale_to_fit(group.get_depth()+MED_SMALL_BUFF, 2, True)
rect1.stretch_in_place(1.2, 0)
prob_words = TextMobject(
"Probabilities depend only\\\\",
"on this angle difference"
)
prob_words.add_background_rectangle()
prob_words.rotate(np.pi/2, RIGHT)
prob_words.next_to(rect1, OUT)
self.add(rect1)
self.play(FadeIn(prob_words))
for index in 1, 2:
self.shoot_photon()
self.play(Transform(
second_filter, possible_second_filters[index]
))
rect2 = SurroundingRectangle(front_filter, color = RED)
rect2.rotate_in_place(np.pi/2, RIGHT)
rect2.rescale_to_fit(front_filter.get_depth()+MED_SMALL_BUFF, 2, True)
rect2.stretch_in_place(1.5, 0)
ignore_words = TextMobject("Photon \\\\", "``forgets'' this")
ignore_words.add_background_rectangle()
ignore_words.rotate(np.pi/2, RIGHT)
ignore_words.next_to(rect2, OUT)
self.play(
ShowCreation(rect2),
Write(ignore_words, run_time = 1),
FadeIn(front_filter),
run_time = 1.5,
)
self.shoot_photon()
for index in 0, 1, 2:
self.play(Transform(
second_filter, possible_second_filters[index]
))
self.shoot_photon()
def shoot_photon(self):
photon = random.choice(self.photons)
added_anims = []
if photon.filter_distance == SPACE_WIDTH + 2:
added_anims.append(
ApplyMethod(
self.second_filter.highlight, RED,
rate_func = squish_rate_func(there_and_back, 0.5, 0.7)
)
)
self.play(photon, *added_anims, run_time = 1.5)
class IntroduceLabeledFilters(ShowVariousFilterPairs):
CONFIG = {
"filter_x_coordinates" : [-5, -2, 1],
"pol_filter_configs" : [
{"filter_angle" : angle}
for angle in [0, np.pi/8, np.pi/4]
],
"start_phi" : 0.9*np.pi/2,
"start_theta" : -0.85*np.pi,
"target_theta" : -0.65*np.pi,
"lines_depth" : 1.7,
"lines_shift_vect" : MED_SMALL_BUFF*OUT,
"line_start_length" : 3,
"line_end_length" : 9,
"ambient_rotation_rate" : 0.005,
}
def setup(self):
PhotonsThroughPerpendicularFilters.setup(self)
self.remove(self.axes)
def construct(self):
self.add_letters_to_labels()
self.introduce_filters()
self.reposition_camera()
self.separate_cases()
self.show_bottom_lines()
self.comment_on_half_blocked_by_C()
self.show_top_lines()
self.comment_on_those_blocked_by_B()
self.show_sum()
def add_letters_to_labels(self):
for char, pf, color in zip("ABC", self.pol_filters, [RED, GREEN, BLUE]):
label = TextMobject(char)
label.scale(0.9)
label.add_background_rectangle()
label.highlight(color)
label.rotate(np.pi/2, RIGHT)
label.rotate(np.pi/2, IN)
label.next_to(pf.arrow_label, UP)
pf.arrow_label.add(label)
pf.arrow_label.next_to(pf.arrow, OUT, SMALL_BUFF)
self.remove(*self.pol_filters)
def introduce_filters(self):
self.A_filter, self.B_filter, self.C_filter = self.pol_filters
for pf in self.pol_filters:
pf.save_state()
pf.shift(4*OUT)
pf.fade(1)
self.play(pf.restore)
self.dither()
def reposition_camera(self):
self.move_camera(
theta = self.target_theta,
added_anims = list(it.chain(*[
[
pf.arrow_label.rotate, np.pi/2, OUT,
pf.arrow_label.next_to, pf.arrow, RIGHT
]
for pf in self.pol_filters
]))
)
def separate_cases(self):
self.lower_pol_filters = VGroup(
self.A_filter.deepcopy(),
self.C_filter.deepcopy(),
)
self.lower_pol_filters.save_state()
self.lower_pol_filters.fade(1)
self.play(
self.lower_pol_filters.restore,
self.lower_pol_filters.shift, 3*IN,
self.pol_filters.shift, 1.5*OUT,
)
self.dither()
def show_bottom_lines(self):
A, C = self.lower_pol_filters
lines_to_A = self.get_lines(None, A)
vect = lines_to_A[1].get_center() - lines_to_A[0].get_center()
lines_to_A.add(*lines_to_A.copy().shift(vect/2))
lines_to_C = self.get_lines(A, C)
lines_from_C = self.get_lines(C, ratio = 0.5)
kwargs = {
"rate_func" : None,
"submobject_mode" : "all_at_once",
"run_time" : 1./3,
}
self.play(
ShowCreation(lines_to_A),
**kwargs
)
self.play(
ShowCreation(lines_to_C),
Animation(VGroup(A, lines_to_A)),
**kwargs
)
kwargs["run_time"] = 3*kwargs["run_time"]
self.play(
ShowCreation(lines_from_C),
Animation(VGroup(C, lines_to_C, A, lines_to_A)),
**kwargs
)
line_group = VGroup(lines_from_C, C, lines_to_C, A, lines_to_A)
self.remove(*line_group)
self.add_foreground_mobject(line_group)
self.bottom_lines_group = line_group
def comment_on_half_blocked_by_C(self):
arrow = Arrow(
ORIGIN, 3.5*RIGHT,
path_arc = -0.9*np.pi,
use_rectangular_stem = False,
color = BLUE,
stroke_width = 5,
)
words = TextMobject("50\\% blocked")
words.highlight(BLUE)
words.next_to(arrow, RIGHT, buff = 0)
group = VGroup(arrow, words)
group.rotate(np.pi/2, RIGHT)
group.shift(1.7*IN + 0.5*RIGHT)
self.play(
Write(words, run_time = 2),
ShowCreation(arrow)
)
self.dither(2)
self.blocked_at_C_words = words
self.blocked_at_C_label_group = VGroup(arrow, words)
def show_top_lines(self):
A, B, C = self.pol_filters
lines_to_A = self.get_lines(None, A)
vect = lines_to_A[1].get_center() - lines_to_A[0].get_center()
lines_to_A.add(*lines_to_A.copy().shift(vect/2))
lines_to_B = self.get_lines(A, B)
lines_to_C = self.get_lines(B, C, ratio = 0.85, remove_from_bottom = True)
lines_from_C = self.get_lines(C, ratio = 0.85**2, remove_from_bottom = True)
kwargs = {
"rate_func" : None,
"submobject_mode" : "all_at_once",
"run_time" : 1./5,
}
self.play(
ShowCreation(lines_to_A),
**kwargs
)
self.play(
ShowCreation(lines_to_B),
Animation(VGroup(A, lines_to_A)),
**kwargs
)
self.play(
ShowCreation(lines_to_C),
Animation(VGroup(B, lines_to_B, A, lines_to_A)),
**kwargs
)
kwargs["run_time"] = 3*kwargs["run_time"]
self.play(
ShowCreation(lines_from_C),
Animation(VGroup(C, lines_to_C, B, lines_to_B, A, lines_to_A)),
**kwargs
)
line_group = VGroup(
lines_from_C, C, lines_to_C, B, lines_to_B, A, lines_to_A
)
self.remove(*line_group)
self.add_foreground_mobject(line_group)
self.top_lines_group = line_group
def comment_on_those_blocked_by_B(self):
arrow0 = Arrow(
2*LEFT, 0.5*(UP+RIGHT),
path_arc = 0.8*np.pi,
use_rectangular_stem = False,
color = WHITE,
stroke_width = 5,
buff = 0
)
arrow1 = Arrow(
2*LEFT, ORIGIN,
path_arc = 0.8*np.pi,
use_rectangular_stem = False,
color = GREEN,
stroke_width = 5,
buff = 0
)
arrow2 = arrow1.copy()
arrow2.next_to(arrow1, RIGHT, buff = LARGE_BUFF)
words1 = TextMobject("15\\%", "blocked")
words1.highlight(GREEN)
words2 = words1.copy()
words1.next_to(arrow1, DOWN, buff = SMALL_BUFF)
words2.next_to(arrow2, DOWN, buff = SMALL_BUFF)
words2.shift(MED_LARGE_BUFF*RIGHT)
words0 = TextMobject("85\\%", "pass")
words0.move_to(words1)
group = VGroup(arrow0, arrow1, arrow2, words0, words1, words2)
group.rotate(np.pi/2, RIGHT)
group.shift(0.8*LEFT+1.5*OUT)
self.play(
ShowCreation(arrow0),
Write(words0, run_time = 1)
)
self.dither()
self.play(
ReplacementTransform(words0, words1),
ReplacementTransform(arrow0, arrow1),
)
self.dither()
self.play(
ShowCreation(arrow2),
Write(words2)
)
self.dither(2)
self.fifteens = VGroup(words1, words2)
self.blocked_at_B_label_group = VGroup(
words1, words2, arrow1, arrow2
)
def show_sum(self):
fifteen1, fifteen2 = self.fifteens
fifty = self.blocked_at_C_words
plus = TexMobject("+").rotate(np.pi/2, RIGHT)
plus.move_to(Line(fifteen1.get_right(), fifteen2.get_left()))
equals = TexMobject("=").rotate(np.pi/2, RIGHT)
equals.next_to(fifteen2, RIGHT, 2*SMALL_BUFF)
q_mark = TexMobject("?").rotate(np.pi/2, RIGHT)
q_mark.next_to(equals, OUT, SMALL_BUFF)
q_mark.highlight(RED)
randy = Randolph(mode = "confused").flip()
randy.scale(0.7)
randy.rotate(np.pi/2, RIGHT)
randy.move_to(fifty)
randy.shift(0.5*RIGHT)
randy.look_at(equals)
blinked = randy.copy()
blinked.rotate(np.pi/2, LEFT)
blinked.blink()
blinked.rotate(np.pi/2, RIGHT)
self.play(
fifteen1.highlight, YELLOW,
Write(plus)
)
self.play(
fifteen2.highlight, YELLOW,
Write(equals)
)
self.play(
fifty.next_to, equals, RIGHT, 2*SMALL_BUFF,
Write(q_mark),
FadeIn(randy)
)
self.play(Transform(
randy, blinked,
rate_func = squish_rate_func(there_and_back)
))
self.dither(3)
class IntroduceLabeledFiltersNoRotation(IntroduceLabeledFilters):
CONFIG = {
"ambient_rotation_rate" : 0,
"target_theta" : -0.55*np.pi,
}
class RemoveBFromLabeledFilters(IntroduceLabeledFiltersNoRotation):
def construct(self):
self.force_skipping()
IntroduceLabeledFiltersNoRotation.construct(self)
self.revert_to_original_skipping_status()
self.setup_start()
self.show_filter_B_removal()
self.fade_in_labels()
def show_sum(self):
pass
def setup_start(self):
self.remove(self.blocked_at_C_label_group)
self.remove(self.blocked_at_B_label_group)
self.remove(self.bottom_lines_group)
self.top_lines_group.save_state()
self.top_lines_group.shift(2*IN)
def show_filter_B_removal(self):
top_lines_group = self.top_lines_group
bottom_lines_group = self.bottom_lines_group
mover = top_lines_group.copy()
mover.save_state()
mover.fade(1)
sl1, sC, sl2, sB, sl3, sA, sl4 = mover
tl1, tC, tl2, tA, tl3 = bottom_lines_group
for line in tl2:
line.scale(0.5, about_point = line.get_end())
kwargs = {
"submobject_mode" : "all_at_once",
"rate_func" : None,
}
self.play(
top_lines_group.shift, 2*OUT,
mover.restore,
mover.shift, 2.5*IN,
)
self.dither()
self.play(
ApplyMethod(sB.shift, 4*IN, rate_func = running_start),
FadeOut(sl1),
Animation(sC),
FadeOut(sl2),
)
self.play(ShowCreation(tl2, run_time = 0.25, **kwargs))
self.play(
ShowCreation(tl1, run_time = 0.5, **kwargs),
Animation(sC),
Animation(tl2),
)
self.dither()
def fade_in_labels(self):
self.play(*map(FadeIn, [
self.blocked_at_B_label_group,
self.blocked_at_C_label_group,
]))
self.dither()
class NumbersSuggestHiddenVariablesAreImpossible(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"These numbers suggest\\\\",
"no hidden variables"
)
self.change_student_modes("erm", "sassy", "confused")
self.dither(3)
class VennDiagramProofByContradiction(Scene):
CONFIG = {
"circle_colors" : [RED, GREEN, BLUE]
}
def construct(self):
self.setup_venn_diagram_sections()
self.draw_venn_diagram()
self.show_100_photons()
self.show_one_photon_answering_questions()
self.put_all_photons_in_A()
self.separate_by_B()
self.separate_by_C()
self.show_two_relevant_subsets()
def draw_venn_diagram(self, send_to_corner = True):
A, B, C = venn_diagram = VGroup(*[
Circle(
radius = 3,
stroke_width = 3,
stroke_color = c,
fill_opacity = 0.2,
fill_color = c,
).shift(vect)
for c, vect in zip(
self.circle_colors,
compass_directions(3, UP)
)
])
self.A_to_B_vect = B.get_center() - A.get_center()
self.A_to_C_vect = C.get_center() - A.get_center()
venn_diagram.center()
labels = VGroup()
alt_labels = VGroup()
props = [1./12, 0.5, 0]
angles = [0, np.pi/8, np.pi/4]
for circle, char, prop, angle in zip(venn_diagram, "ABC", props, angles):
label, alt_label = [
TextMobject(
"%s \\\\"%start,
"through", char + "$\\! \\uparrow$"
).highlight_by_tex(char, circle.get_color())
for start in "Would pass", "Pass"
]
for mob in label, alt_label:
mob[-1][-1].rotate_in_place(-angle)
mob[-1][-1].shift(0.5*SMALL_BUFF*UP)
center = circle.get_center()
label.move_to(center)
label.generate_target()
point = circle.point_from_proportion(prop)
alt_label.scale(2)
for mob in label.target, alt_label:
mob.next_to(point, point-center, SMALL_BUFF)
circle.label = label
circle.alt_label = alt_label
labels.add(label)
alt_labels.add(alt_label)
last_circle = None
for circle in venn_diagram:
added_anims = []
if last_circle:
added_anims.append(MoveToTarget(last_circle.label))
self.play(
DrawBorderThenFill(circle, run_time = 2),
Write(circle.label, run_time = 2),
*added_anims
)
last_circle = circle
self.play(MoveToTarget(last_circle.label))
self.dither()
if hasattr(self, "A_segments"):
A.add(self.A_segments)
if send_to_corner:
group = VGroup(venn_diagram, labels)
target = VGroup(venn_diagram.copy(), alt_labels)
target.scale(0.25)
target.to_corner(UP+RIGHT)
self.play(Transform(group, target))
self.remove(group)
for circle in venn_diagram:
circle.label = circle.alt_label
self.add(circle)
for circle in venn_diagram:
self.add(circle.label)
self.venn_diagram = venn_diagram
def show_100_photons(self):
photon = FunctionGraph(
lambda x : -np.cos(3*np.pi*x)*np.exp(-x*x),
x_min = -2,
x_max = 2,
color = YELLOW,
stroke_width = 2,
)
photon.shift(LEFT + 2*UP)
eyes = Eyes(photon)
photon.eyes = eyes
hundred, photon_word, s = words = TextMobject(
"100 ", "Photon", "s",
arg_separator = ""
)
words.next_to(eyes, UP)
self.play(
ShowCreation(photon),
FadeIn(photon.eyes),
Write(photon_word, run_time = 1.5)
)
photon.add(photon.eyes)
#Split to hundred
photons = VGroup(*[photon.deepcopy() for x in range(100)])
self.arrange_photons_in_circle(photons)
photons.scale_to_fit_height(6)
photons.next_to(words, DOWN)
photons.to_edge(LEFT)
self.play(
Write(hundred), Write(s),
ReplacementTransform(
VGroup(photon), photons,
submobject_mode = "lagged_start"
)
)
self.photons = photons
self.photon_words = words
def show_one_photon_answering_questions(self):
photon = self.photons[89]
photon.save_state()
photon.generate_target()
answers = TextMobject(
"Pass through A?", "Yes\\\\",
"Pass through B?", "No\\\\",
"Pass through C?", "No\\\\",
)
answers.highlight_by_tex_to_color_map({
"Yes" : GREEN,
"No" : RED,
})
bubble = ThoughtBubble()
bubble.add_content(answers)
bubble.resize_to_content()
answers.shift(SMALL_BUFF*(RIGHT+UP))
bubble_group = VGroup(bubble, answers)
bubble_group.scale(0.25)
bubble_group.next_to(photon, UP+RIGHT, buff = 0)
group = VGroup(photon, bubble_group)
group.save_state()
bubble_group.set_fill(opacity = 0)
bubble_group.set_stroke(width = 0)
self.play(
group.restore,
group.scale, 4,
group.to_corner, DOWN + RIGHT,
)
self.play(photon.eyes.blink_anim())
self.dither()
self.play(
FadeOut(bubble_group),
photon.restore,
)
def put_all_photons_in_A(self):
A, B, C = circles = self.venn_diagram[:3]
A_group, B_group, C_group = [
VGroup(circle, circle.label)
for circle in circles
]
B_group.save_state()
C_group.save_state()
A.generate_target()
A.target.scale(4)
A.target.shift(
(SPACE_HEIGHT-MED_LARGE_BUFF)*UP - \
A.target.get_top()
)
A.label.generate_target()
A.label.target.scale(2)
A.label.target.next_to(
A.target.point_from_proportion(0.1),
UP+RIGHT, SMALL_BUFF
)
self.play(
B_group.fade, 1,
C_group.fade, 1,
MoveToTarget(A),
MoveToTarget(A.label),
FadeOut(self.photon_words),
self.photons.scale_to_fit_height,
0.85*A.target.get_height(),
self.photons.space_out_submobjects, 0.8,
self.photons.move_to, A.target,
)
self.dither()
self.A_group = A_group
self.B_group = B_group
self.C_group = C_group
def separate_by_B(self):
A_group = self.A_group
B_group = self.B_group
photons = self.photons
B = B_group[0]
B.target, B.label.target = B_group.saved_state
B.target.scale(4)
B.target.move_to(A_group[0])
B.target.shift(self.A_to_B_vect)
B.label.target.scale(2)
B.label.target.next_to(
B.target.point_from_proportion(0.55),
LEFT, SMALL_BUFF
)
B_center = B.target.get_center()
photons.sort_submobjects(
lambda p : np.linalg.norm(p-B_center)
)
in_B = VGroup(*photons[:85])
out_of_B = VGroup(*photons[85:])
out_of_B.sort_submobjects(lambda p : np.dot(p, 2*UP+LEFT))
self.play(
MoveToTarget(B),
MoveToTarget(B.label),
in_B.shift, 0.5*DOWN+0.2*LEFT,
out_of_B.scale_in_place, 1./0.8,
out_of_B.shift, 0.15*(UP+RIGHT),
)
words1 = TextMobject("85 also \\\\", "pass ", "B")
words1.highlight_by_tex("B", GREEN)
words1.scale(0.8)
words1.next_to(A_group, LEFT, LARGE_BUFF).shift(UP)
arrow1 = Arrow(
words1.get_right(),
in_B.get_corner(UP+LEFT) + MED_LARGE_BUFF*(DOWN+RIGHT)
)
arrow1.highlight(GREEN)
words2 = TextMobject("15 blocked \\\\", "by ", "B")
words2.highlight_by_tex("B", GREEN)
words2.scale(0.8)
words2.next_to(A_group, LEFT, MED_LARGE_BUFF, UP)
arrow2 = Arrow(words2.get_right(), out_of_B[-1])
arrow2.highlight(RED)
self.play(
Write(words1, run_time = 1),
ShowCreation(arrow1),
self.in_A_in_B.set_fill, GREEN, 0.5,
Animation(in_B),
)
self.dither()
self.play(
ReplacementTransform(words1, words2),
ReplacementTransform(arrow1, arrow2),
self.in_A_in_B.set_fill, None, 0,
Animation(in_B),
self.in_A_out_B.set_fill, RED, 0.5,
Animation(out_of_B)
)
self.dither()
self.play(ApplyMethod(
VGroup(self.in_A_out_B, out_of_B).shift,
MED_LARGE_BUFF*UP,
rate_func = wiggle,
run_time = 1.5,
))
self.dither(0.5)
self.in_B = in_B
self.out_of_B = out_of_B
self.out_of_B_words = words2
self.out_of_B_arrow = arrow2
def separate_by_C(self):
A_group = self.A_group
B_group = self.B_group
C_group = self.C_group
in_B = self.in_B
A, B, C = self.venn_diagram
C.target, C.label.target = C_group.saved_state
C.target.scale(4)
C.target.move_to(A)
C.target.shift(self.A_to_C_vect)
C_center = C.target.get_center()
C.label.target.scale(2)
C.label.target.next_to(
C.target.point_from_proportion(0),
DOWN+RIGHT, buff = SMALL_BUFF
)
in_B.sort_submobjects(
lambda p : np.linalg.norm(p - C_center)
)
in_C = VGroup(*in_B[:-11])
out_of_C = VGroup(*in_B[-11:])
in_C_out_B = VGroup(*self.out_of_B[:6])
words = TextMobject(
"$15\\%$", "passing", "B \\\\",
"get blocked by ", "C",
)
words.scale(0.8)
words.highlight_by_tex_to_color_map({
"B" : GREEN,
"C" : BLUE,
})
words.next_to(self.out_of_B_words, DOWN, LARGE_BUFF)
words.to_edge(LEFT)
percent = words[0]
pound = TexMobject("\\#")
pound.move_to(percent, RIGHT)
less_than_15 = TexMobject("<15")
less_than_15.next_to(words, DOWN)
arrow = Arrow(words.get_right(), out_of_C)
arrow.highlight(GREEN)
C_copy = C.copy()
C_copy.set_fill(BLACK, opacity = 1)
self.play(
self.in_A_in_B.set_fill, GREEN, 0.5,
rate_func = there_and_back,
)
self.play(
MoveToTarget(C),
MoveToTarget(C.label),
in_C.shift, 0.2*DOWN+0.15*RIGHT,
out_of_C.shift, SMALL_BUFF*(UP+LEFT),
in_C_out_B.shift, 0.3*DOWN
)
self.play(
self.in_A_in_B_out_C.set_fill, GREEN, 0.5,
Write(words, run_time = 1),
ShowCreation(arrow),
Animation(out_of_C),
)
self.play(ApplyMethod(
VGroup(self.in_A_in_B_out_C, out_of_C).shift,
MED_LARGE_BUFF*UP,
rate_func = wiggle
))
self.dither()
C.save_state()
self.play(C.set_fill, BLACK, 1)
self.dither()
self.play(C.restore)
self.dither(2)
self.play(Transform(percent, pound))
self.play(Write(less_than_15, run_time = 1))
self.dither()
self.in_C = in_C
self.out_of_C = out_of_C
words.add(less_than_15)
self.out_of_C_words = words
self.out_of_C_arrow = arrow
def show_two_relevant_subsets(self):
A, B, C = self.venn_diagram
all_out_of_C = VGroup(*it.chain(
self.out_of_B[6:],
self.out_of_C,
))
everything = VGroup(*self.get_top_level_mobjects())
photon_groups = [all_out_of_C, self.out_of_C, self.out_of_B]
regions = [self.in_A_out_C, self.in_A_in_B_out_C, self.in_A_out_B]
self.play(*[
ApplyMethod(
m.scale, 0.7,
method_kwargs = {
"about_point" : SPACE_HEIGHT*DOWN
}
)
for m in everything
])
terms = VGroup(
TexMobject("N(", "A", "\\checkmark", ",", "C", ")", "\\le"),
TexMobject(
"N(", "A", "\\checkmark", ",",
"B", "\\checkmark", ",", "C", ")"
),
TexMobject("+\\, N(", "A", "\\checkmark", ",", "B", ")"),
)
terms.arrange_submobjects(RIGHT)
terms.to_edge(UP)
for term, index, group in zip(terms, [-3, -2, -2], photon_groups):
term.highlight_by_tex("checkmark", "#00ff00")
cross = Cross(term[index])
cross.highlight("#ff0000")
cross.set_stroke(width = 8)
term[index].add(cross)
less_than = terms[0][-1]
terms[0].remove(less_than)
plus = terms[2][0][0]
terms[2][0].remove(plus)
rects = map(SurroundingRectangle, terms)
terms[2][0].add_to_back(plus)
last_rects = VGroup(*rects[1:])
should_be_50 = TextMobject("Should be 50 \\\\", "...somehow")
should_be_50.scale(0.8)
should_be_50.next_to(rects[0], DOWN)
lt_fifteen = VGroup(self.out_of_C_words[-1]).copy()
something_lt_15 = TextMobject("(Something", "$<15$", ")")
something_lt_15.scale(0.8)
something_lt_15.next_to(rects[1], DOWN)
lt_fifteen.target = something_lt_15
fifteen = VGroup(*self.out_of_B_words[0][:2]).copy()
fifteen.generate_target()
fifteen.target.scale(1.5)
fifteen.target.next_to(rects[2], DOWN)
nums = [should_be_50, lt_fifteen, fifteen]
cross = Cross(less_than)
cross.highlight("#ff0000")
cross.set_stroke(width = 8)
tweaser_group = VGroup(
self.in_A_in_B_out_C.copy(),
self.in_A_out_B.copy(),
)
tweaser_group.set_fill(TEAL, 1)
tweaser_group.set_stroke(TEAL, 5)
#Fade out B circle
faders = VGroup(
B, B.label,
self.out_of_B_words, self.out_of_C_words,
self.out_of_B_arrow, self.out_of_C_arrow,
*regions[1:]
)
faders.save_state()
self.play(faders.fade, 1)
self.play(Write(terms[0]), run_time = 1)
self.dither()
self.photon_thinks_in_A_out_C()
regions[0].set_stroke(YELLOW, width = 8)
regions[0].set_fill(YELLOW, opacity = 0.25)
self.play(
VGroup(regions[0], all_out_of_C).shift, 0.5*UP,
run_time = 1.5,
rate_func = wiggle,
)
self.dither(2)
#Photons jump
self.photons.save_state()
self.play(Write(should_be_50[0], run_time = 1))
self.photons_jump_to_A_not_C_region()
self.dither()
self.play(
faders.restore,
self.photons.restore,
)
self.play(
faders.restore,
regions[0].set_fill, None, 0,
Animation(self.photons)
)
#Funny business
everything_copy = everything.copy().scale(1./3)
braces = VGroup(
Brace(everything_copy, LEFT),
Brace(everything_copy, RIGHT),
).scale(3)
funny_business = TextMobject("Funny business")
funny_business.scale(1.5)
funny_business.to_edge(UP)
funny_business.shift(RIGHT)
self.play(
FadeIn(funny_business),
*map(Write, braces),
run_time = 1
)
self.dither()
self.play(
FadeIn(less_than),
*map(FadeOut, [funny_business, braces])
)
for term, group, region, num in zip(terms, photon_groups, regions, nums)[1:]:
group.set_stroke(WHITE)
self.play(Write(term, run_time = 1))
self.dither()
self.play(
ApplyMethod(
VGroup(region, group).shift, 0.5*UP,
rate_func = wiggle,
run_time = 1.5,
),
)
self.play(MoveToTarget(num))
self.dither()
self.dither()
self.play(ShowCreation(rects[0]))
self.play(
VGroup(regions[0], all_out_of_C).shift, 0.5*UP,
run_time = 1.5,
rate_func = wiggle,
)
self.dither()
self.play(Transform(rects[0], last_rects))
self.in_A_out_B.save_state()
self.in_A_in_B_out_C.save_state()
self.play(
self.in_A_out_B.set_fill, YELLOW, 0.5,
self.in_A_in_B_out_C.set_fill, YELLOW, 0.5,
Animation(self.photons)
)
self.dither()
self.play(
FadeOut(rects[0]),
self.in_A_out_B.restore,
self.in_A_in_B_out_C.restore,
Animation(self.in_A_out_C),
Animation(self.photons)
)
self.dither()
self.play(
FadeIn(should_be_50[1]),
ShowCreation(cross)
)
morty = Mortimer()
morty.to_corner(DOWN+RIGHT)
contradiction = TextMobject("Contradiction!")
contradiction.next_to(morty, UP, aligned_edge = RIGHT)
contradiction.highlight(RED)
self.play(FadeIn(morty))
self.play(
morty.change, "confused", should_be_50,
Write(contradiction, run_time = 1)
)
self.play(Blink(morty))
self.dither()
def photons_jump_to_A_not_C_region(self):
in_C = self.in_C
in_C.sort_submobjects(lambda p : np.dot(p, DOWN+RIGHT))
movers = VGroup(*self.in_C[:30])
for mover in movers:
mover.generate_target()
mover.target.shift(1.2*UP + 0.6*LEFT)
mover.target.set_stroke(WHITE)
self.play(LaggedStart(
MoveToTarget, movers,
path_arc = np.pi,
lag_ratio = 0.3
))
def photon_thinks_in_A_out_C(self):
photon = self.photons[-1]
photon.save_state()
photon.generate_target()
photon.target.scale(4)
photon.target.center().to_edge(LEFT).shift(DOWN)
bubble = ThoughtBubble()
content = TexMobject("A", "\\checkmark", ",", "C")
content.highlight_by_tex("checkmark", "#00ff00")
cross = Cross(content[-1])
cross.highlight("#ff0000")
content.add(cross)
bubble.add_content(content)
bubble.resize_to_content()
bubble.add(bubble.content)
bubble.pin_to(photon.target).shift(SMALL_BUFF*RIGHT)
bubble.save_state()
bubble.scale(0.25)
bubble.move_to(photon.get_corner(UP+RIGHT), DOWN+LEFT)
bubble.fade()
self.play(
MoveToTarget(photon),
bubble.restore,
)
self.play(photon.eyes.blink_anim())
self.play(
photon.restore,
FadeOut(bubble)
)
#######
def setup_venn_diagram_sections(self):
in_A_out_B, in_A_in_B_out_C, in_A_out_C, in_A_in_B = segments = VGroup(*[
SVGMobject(
file_name = "VennDiagram_" + s,
stroke_width = 0,
fill_opacity = 0.5,
fill_color = YELLOW,
)
for s in "in_A_out_B", "in_A_in_B_out_C", "in_A_out_C", "in_A_in_B"
])
in_A_out_B.scale(2.59)
in_A_out_B.move_to(3.74*UP + 2.97*RIGHT, UP+RIGHT)
in_A_in_B_out_C.scale(1.84)
in_A_in_B_out_C.move_to(2.23*UP, UP+RIGHT)
in_A_out_C.scale(2.56)
in_A_out_C.move_to(3*LEFT + (3.69)*UP, UP+LEFT)
in_A_in_B.scale(2.24)
in_A_in_B.move_to(2.23*UP + 3*LEFT, UP+LEFT)
segments.set_fill(BLACK, opacity = 0)
self.in_A_out_B = in_A_out_B
self.in_A_in_B_out_C = in_A_in_B_out_C
self.in_A_out_C = in_A_out_C
self.in_A_in_B = in_A_in_B
self.A_segments = segments
def arrange_photons_in_circle(self, photons):
R = np.sqrt(len(photons) / np.pi)
pairs = []
rejected = []
for x, y in it.product(*[range(-int(R)-1, int(R)+2)]*2):
if x**2 + y**2 < R**2:
pairs.append((x, y))
else:
rejected.append((x, y))
rejected.sort(
lambda (x1, y1), (x2, y2) : (x2**2 + y2**2) - (x1**2 + y1**2)
)
for i in range(len(photons) - len(pairs)):
pairs.append(rejected.pop())
for photon, (x, y) in zip(photons, pairs):
photon.scale_to_fit_width(0.7)
photon.move_to(x*RIGHT + y*UP)
return photons
class PonderingPiCreature(Scene):
def construct(self):
randy = Randolph()
randy.to_edge(DOWN).shift(3*LEFT)
self.play(randy.change, "pondering", UP+RIGHT)
self.play(Blink(randy))
self.dither(2)
self.play(Blink(randy))
self.dither(2)
class ReEmphasizeVennDiagram(VennDiagramProofByContradiction):
def construct(self):
self.draw_venn_diagram(send_to_corner = False)
self.rescale_diagram()
self.setup_faded_circles()
self.shift_B_circle()
self.shift_C_circle()
self.show_A_not_C_region()
self.shorten_labels()
self.show_inequality_with_circle()
# self.emphasize_containment()
self.write_50_percent()
self.write_assumption()
self.adjust_circles()
def rescale_diagram(self):
group = VGroup(self.venn_diagram, *[
c.label for c in self.venn_diagram
])
self.play(
group.scale, 0.7,
group.to_edge, DOWN, MED_SMALL_BUFF,
)
self.clear()
self.add_foreground_mobjects(*group)
def setup_faded_circles(self):
self.circles = self.venn_diagram[:3]
self.black_circles = VGroup(*[
circ.copy().set_stroke(width = 0).set_fill(BLACK, 1)
for circ in self.circles
])
self.filled_circles = VGroup(*[
circ.copy().set_stroke(width = 0).set_fill(circ.get_color(), 1)
for circ in self.circles
])
def shift_B_circle(self):
A, B, C = self.circles
A0, B0, C0 = self.black_circles
A1, B1, C1 = self.filled_circles
words = TextMobject("Should be 15\\% \\\\ of circle ", "A")
words.scale(0.7)
words.highlight_by_tex("A", RED)
words.next_to(A, UP, LARGE_BUFF)
words.shift(RIGHT)
arrow = Arrow(
words.get_bottom(),
A.get_top() + MED_SMALL_BUFF*RIGHT,
color = RED
)
self.play(FadeIn(A1))
self.play(FadeIn(B0))
self.play(
FadeIn(words, submobject_mode = "lagged_start"),
ShowCreation(arrow)
)
self.dither()
vect = 0.6*(A.get_center() - B.get_center())
self.play(
B0.shift, vect,
B.shift, vect,
B.label.shift, vect,
run_time = 2,
rate_func = running_start,
)
B1.shift(vect)
self.dither()
self.in_A_out_B_words = words
self.in_A_out_B_arrow = arrow
for mob in words, arrow:
mob.save_state()
def shift_C_circle(self):
A, B, C = self.circles
A0, B0, C0 = self.black_circles
A1, B1, C1 = self.filled_circles
words = TextMobject("Should be 15\\% \\\\ of circle ", "B")
words.scale(0.7)
words.highlight_by_tex("B", GREEN)
words.next_to(B, LEFT)
words.shift(2.5*UP)
arrow = Arrow(
words.get_bottom(),
B.point_from_proportion(0.4),
color = GREEN
)
self.play(
FadeOut(A1),
FadeOut(B0),
self.in_A_out_B_words.fade, 1,
self.in_A_out_B_arrow.fade, 1,
FadeIn(B1),
FadeIn(words, submobject_mode = "lagged_start"),
ShowCreation(arrow)
)
self.play(FadeIn(C0))
self.dither(2)
vect = 0.5*(B.get_center() - C.get_center())
self.play(
C0.shift, vect,
C.shift, vect,
C.label.shift, vect,
run_time = 2,
rate_func = running_start,
)
C1.shift(vect)
self.dither()
for mob in words, arrow:
mob.save_state()
self.in_B_out_C_words = words
self.in_B_out_C_arrow = arrow
def show_A_not_C_region(self):
A, B, C = self.circles
A0, B0, C0 = self.black_circles
A1, B1, C1 = self.filled_circles
A1_yellow_copy = A1.copy().set_fill(YELLOW)
self.play(
FadeOut(B1),
FadeOut(C0),
self.in_B_out_C_words.fade, 1,
self.in_B_out_C_arrow.fade, 1,
FadeIn(A1_yellow_copy)
)
self.play(FadeIn(C0))
self.dither()
self.A1_yellow_copy = A1_yellow_copy
def shorten_labels(self):
A, B, C = self.circles
A0, B0, C0 = self.black_circles
A1, B1, C1 = self.filled_circles
for circle in A, B, C:
circle.pre_label = VGroup(*circle.label[:-1])
circle.letter = circle.label[-1]
self.play(
A.pre_label.fade, 1,
A.letter.scale, 2,
A.letter.move_to, A.pre_label, LEFT,
B.pre_label.fade, 1,
B.letter.scale, 2, B.letter.get_right(),
C.pre_label.fade, 1,
C.letter.scale, 2,
C.letter.move_to, C.pre_label, LEFT,
C.letter.shift, DOWN+0.5*LEFT,
)
for circle in A, B, C:
circle.remove(circle.label)
self.remove(circle.label)
circle.add(circle.letter)
self.add(circle.letter)
def show_inequality_with_circle(self):
A, B, C = self.circles
A0, B0, C0 = self.black_circles
A1, B1, C1 = self.filled_circles
A1_yellow_copy = self.A1_yellow_copy
inequality = VGroup(
TexMobject("N(", "A", "\\checkmark", ",", "C", ")"),
TexMobject("N(", "B", "\\checkmark", ",", "C", ")"),
TexMobject("N(", "A", "\\checkmark", ",", "B", ")"),
)
inequality.arrange_submobjects(RIGHT)
for tex in inequality:
tex.highlight_by_tex("checkmark", "#00ff00")
if len(tex) > 1:
cross = Cross(tex[-2], color = "#ff0000")
cross.set_stroke(width = 8)
tex[-2].add(cross)
inequality.space_out_submobjects(2.1)
big_le = TexMobject("\\le").scale(2)
big_plus = TexMobject("+").scale(2)
big_le.move_to(2.75*LEFT)
big_plus.move_to(2.25*RIGHT)
groups = VGroup(*[
VGroup(
m2.copy(), m1.copy(),
VGroup(*self.circles).copy()
)
for m1, m2 in (C0, A1_yellow_copy), (C0, B1), (B0, A1)
])
for group, vect in zip(groups[1:], [UP, 5*RIGHT+UP]):
group.scale_in_place(0.5)
group.shift(vect)
group.save_state()
group.shift(-vect[0]*RIGHT + 5*LEFT)
inequality.shift(2.25*DOWN + 0.25*LEFT)
self.in_B_out_C_words.restore()
self.in_B_out_C_words.move_to(2*UP)
self.in_A_out_B_words.restore()
self.in_A_out_B_words.move_to(5*RIGHT+2*UP)
self.clear()
self.play(
groups[0].scale_in_place, 0.5,
groups[0].shift, 5*LEFT + UP,
Write(inequality[0], run_time = 1),
FadeIn(big_le),
)
self.dither()
self.play(FadeIn(groups[1]))
self.play(
groups[1].restore,
FadeIn(inequality[1]),
FadeIn(self.in_B_out_C_words),
FadeIn(big_plus),
)
self.play(FadeIn(groups[2]))
self.play(
groups[2].restore,
FadeIn(inequality[2]),
FadeIn(self.in_A_out_B_words),
)
self.dither(2)
self.groups = groups
self.inequality = inequality
def emphasize_containment(self):
groups = self.groups
c1, c2 = [VGroup(*group[:2]).copy() for group in groups[1:]]
foreground = VGroup(groups[0][-1], *groups[1:])
rect = SurroundingRectangle(groups[0])
self.play(ShowCreation(rect))
self.play(FadeOut(rect))
self.play(
ApplyMethod(
c1.shift, 4*LEFT,
path_arc = -np.pi/2,
),
Animation(foreground)
)
self.play(
ApplyMethod(
c2.shift, 8*LEFT,
path_arc = -np.pi/2,
),
Animation(c1),
Animation(foreground),
run_time = 1.5
)
self.play(
FadeOut(c2),
FadeOut(c1),
Animation(foreground),
run_time = 2
)
self.dither()
def write_50_percent(self):
words = TextMobject(
"Should be 50\\% \\\\ of circle ", "A",
"...somehow"
)
words.scale(0.7)
words.highlight_by_tex("A", RED)
words.move_to(5*LEFT + 2*UP)
self.play(Write(words))
self.dither()
def write_assumption(self):
words = TextMobject("Assume circles have the same size$^*$")
words.scale(0.8)
words.to_edge(UP)
footnote = TextMobject("""
*If you prefer, you can avoid the need for that
assumption by swapping the roles of A and C here
and writing a second inequality for added constraint.
""")
footnote.scale(0.5)
footnote.to_corner(DOWN+RIGHT)
footnote.add(words[-1])
words.remove(words[-1])
self.footnote = footnote
self.play(FadeIn(words))
def adjust_circles(self):
groups = self.groups
A_group = VGroup(
groups[0][0],
groups[2][0],
groups[0][2][0],
groups[1][2][0],
groups[2][2][0],
)
B_group = VGroup(
groups[1][0],
groups[2][1],
groups[0][2][1],
groups[1][2][1],
groups[2][2][1],
)
C_group = VGroup(
groups[0][1],
groups[1][1],
groups[0][2][2],
groups[1][2][2],
groups[2][2][2],
)
def center_of_mass(mob):
return np.apply_along_axis(np.mean, 0, mob.points)
movers = [A_group, B_group, C_group]
A_ref, B_ref, C_ref = [g[4] for g in movers]
B_center = center_of_mass(B_ref)
B_to_A = center_of_mass(A_ref) - B_center
B_to_C = center_of_mass(C_ref) - B_center
A_freq = 1
C_freq = -0.7
self.time = 0
dt = self.frame_duration
def move_around(total_time):
self.time
t_range = range(int(total_time/dt))
for x in ProgressDisplay(t_range):
self.time += dt
new_B_to_A = rotate_vector(B_to_A, self.time*A_freq)
new_B_to_C = rotate_vector(B_to_C, self.time*C_freq)
A_group.shift(B_center + new_B_to_A - center_of_mass(A_ref))
C_group.shift(B_center + new_B_to_C - center_of_mass(C_ref))
self.dither(self.frame_duration)
move_around(3)
self.add(self.footnote)
move_around(1)
self.remove(self.footnote)
move_around(15)
class NoFirstMeasurementPreferenceBasedOnDirection(ShowVariousFilterPairs):
CONFIG = {
"filter_x_coordinates" : [0, 0, 0],
"pol_filter_configs" : [
{"filter_angle" : angle}
for angle in 0, np.pi/8, np.pi/4
],
"lines_depth" : 1.2,
"lines_shift_vect" : SMALL_BUFF*OUT,
"n_lines" : 30,
}
def setup(self):
DirectionOfPolarization.setup(self)
self.remove(self.axes, self.em_wave)
zs = [2.5, 0, -2.5]
chars = "ABC"
colors = [RED, GREEN, BLUE]
for z, char, color, pf in zip(zs, chars, colors, self.pol_filters):
pf.scale_in_place(0.7)
pf.move_to(z*OUT)
label = TextMobject(char)
label.add_background_rectangle()
label.highlight(color)
label.scale(0.7)
label.rotate(np.pi/2, RIGHT)
label.rotate(-np.pi/2, OUT)
label.next_to(pf.arrow_label, UP, SMALL_BUFF)
pf.arrow_label.add(label)
self.add_foreground_mobject(pf)
def construct(self):
self.reposition_camera()
self.show_lines()
def reposition_camera(self):
words = TextMobject("No statistical preference")
words.to_corner(UP+LEFT)
words.rotate(np.pi/2, RIGHT)
self.move_camera(
theta = -0.6*np.pi,
added_anims = list(it.chain(*[
[
pf.arrow_label.rotate, np.pi/2, OUT,
pf.arrow_label.next_to, pf.arrow, OUT+RIGHT, SMALL_BUFF
]
for pf in self.pol_filters
] + [[FadeIn(words)]]))
)
def show_lines(self):
all_pre_lines = VGroup()
all_post_lines = VGroup()
for pf in self.pol_filters:
pre_lines = self.get_lines(None, pf)
post_lines = self.get_lines(pf, None)
VGroup(
*random.sample(post_lines, self.n_lines/2)
).set_stroke(BLACK, 0)
all_pre_lines.add(*pre_lines)
all_post_lines.add(*post_lines)
kwargs = {
"rate_func" : None,
"submobject_mode" : "all_at_once"
}
self.play(ShowCreation(all_pre_lines, **kwargs))
self.play(
ShowCreation(all_post_lines, **kwargs),
Animation(self.pol_filters),
Animation(all_pre_lines),
)
self.add_foreground_mobject(all_pre_lines)
self.dither(7)