3b1b-manim/old_projects/highD.py
2019-05-02 20:36:14 -07:00

3628 lines
113 KiB
Python

from manimlib.imports import *
##########
#force_skipping
#revert_to_original_skipping_status
##########
class Slider(NumberLine):
CONFIG = {
"color" : WHITE,
"x_min" : -1,
"x_max" : 1,
"unit_size" : 2,
"center_value" : 0,
"number_scale_val" : 0.75,
"label_scale_val" : 1,
"numbers_with_elongated_ticks" : [],
"line_to_number_vect" : LEFT,
"line_to_number_buff" : MED_LARGE_BUFF,
"dial_radius" : 0.1,
"dial_color" : YELLOW,
"include_real_estate_ticks" : True,
}
def __init__(self, **kwargs):
NumberLine.__init__(self, **kwargs)
self.rotate(np.pi/2)
self.init_dial()
if self.include_real_estate_ticks:
self.add_real_estate_ticks()
def init_dial(self):
dial = Dot(
radius = self.dial_radius,
color = self.dial_color,
)
dial.move_to(self.number_to_point(self.center_value))
re_dial = dial.copy()
re_dial.set_fill(opacity = 0)
self.add(dial, re_dial)
self.dial = dial
self.re_dial = re_dial
self.last_sign = -1
def add_label(self, tex):
label = TexMobject(tex)
label.scale(self.label_scale_val)
label.move_to(self.get_top())
label.shift(MED_LARGE_BUFF*UP)
self.add(label)
self.label = label
def add_real_estate_ticks(
self,
re_per_tick = 0.05,
colors = [BLUE, RED],
max_real_estate = 1,
):
self.real_estate_ticks = VGroup(*[
self.get_tick(self.center_value + u*np.sqrt(x + re_per_tick))
for x in np.arange(0, max_real_estate, re_per_tick)
for u in [-1, 1]
])
self.real_estate_ticks.set_stroke(width = 3)
self.real_estate_ticks.set_color_by_gradient(*colors)
self.add(self.real_estate_ticks)
self.add(self.dial)
return self.real_estate_ticks
def set_value(self, x):
re = (x - self.center_value)**2
for dial, val in (self.dial, x), (self.re_dial, re):
dial.move_to(self.number_to_point(val))
return self
def set_center_value(self, x):
self.center_value = x
return self
def change_real_estate(self, d_re):
left_over = 0
curr_re = self.get_real_estate()
if d_re < -curr_re:
left_over = d_re + curr_re
d_re = -curr_re
self.set_real_estate(curr_re + d_re)
return left_over
def set_real_estate(self, target_re):
if target_re < 0:
raise Exception("Cannot set real estate below 0")
self.re_dial.move_to(self.number_to_point(target_re))
self.update_dial_by_re_dial()
return self
def get_dial_supplement_animation(self):
return UpdateFromFunc(self.dial, self.update_dial_by_re_dial)
def update_dial_by_re_dial(self, dial = None):
dial = dial or self.dial
re = self.get_real_estate()
sign = np.sign(self.get_value() - self.center_value)
if sign == 0:
sign = -self.last_sign
self.last_sign *= -1
dial.move_to(self.number_to_point(
self.center_value + sign*np.sqrt(abs(re))
))
return dial
def get_value(self):
return self.point_to_number(self.dial.get_center())
def get_real_estate(self):
return self.point_to_number(self.re_dial.get_center())
def copy(self):
return self.deepcopy()
class SliderScene(Scene):
CONFIG = {
"n_sliders" : 4,
"slider_spacing" : MED_LARGE_BUFF,
"slider_config" : {},
"center_point" : None,
"total_real_estate" : 1,
"ambiently_change_sliders" : False,
"ambient_velocity_magnitude" : 1.0,
"ambient_acceleration_magnitude" : 1.0,
"ambient_jerk_magnitude" : 1.0/2,
}
def setup(self):
if self.center_point is None:
self.center_point = np.zeros(self.n_sliders)
sliders = VGroup(*[
Slider(center_value = cv, **self.slider_config)
for cv in self.center_point
])
sliders.arrange(RIGHT, buff = self.slider_spacing)
sliders[0].add_numbers()
sliders[0].set_value(
self.center_point[0] + np.sqrt(self.total_real_estate)
)
self.sliders = sliders
self.add_labels_to_sliders()
self.add(sliders)
def add_labels_to_sliders(self):
if len(self.sliders) <= 4:
for slider, char in zip(self.sliders, "xyzw"):
slider.add_label(char)
for slider in self.sliders[1:]:
slider.label.align_to(self.sliders[0].label, UP)
else:
for i, slider in enumerate(self.sliders):
slider.add_label("x_{%d}"%(i+1))
return self
def reset_dials(self, values, run_time = 1, **kwargs):
target_vector = self.get_target_vect_from_subset_of_values(values, **kwargs)
radius = np.sqrt(self.total_real_estate)
def update_sliders(sliders):
curr_vect = self.get_vector()
curr_vect -= self.center_point
curr_vect *= radius/get_norm(curr_vect)
curr_vect += self.center_point
self.set_to_vector(curr_vect)
return sliders
self.play(*[
ApplyMethod(slider.set_value, value)
for value, slider in zip(target_vector, self.sliders)
] + [
UpdateFromFunc(self.sliders, update_sliders)
], run_time = run_time)
def get_target_vect_from_subset_of_values(self, values, fixed_indices = None):
if fixed_indices is None:
fixed_indices = []
curr_vector = self.get_vector()
target_vector = np.array(self.center_point, dtype = 'float')
unspecified_vector = np.array(self.center_point, dtype = 'float')
unspecified_indices = []
for i in range(len(curr_vector)):
if i < len(values) and values[i] is not None:
target_vector[i] = values[i]
else:
unspecified_indices.append(i)
unspecified_vector[i] = curr_vector[i]
used_re = get_norm(target_vector - self.center_point)**2
left_over_re = self.total_real_estate - used_re
if left_over_re < -0.001:
raise Exception("Overspecified reset")
uv_norm = get_norm(unspecified_vector - self.center_point)
if uv_norm == 0 and left_over_re > 0:
unspecified_vector[unspecified_indices] = 1
uv_norm = get_norm(unspecified_vector - self.center_point)
if uv_norm > 0:
unspecified_vector -= self.center_point
unspecified_vector *= np.sqrt(left_over_re)/uv_norm
unspecified_vector += self.center_point
return target_vector + unspecified_vector - self.center_point
def set_to_vector(self, vect):
assert len(vect) == len(self.sliders)
for slider, value in zip(self.sliders, vect):
slider.set_value(value)
def get_vector(self):
return np.array([slider.get_value() for slider in self.sliders])
def get_center_point(self):
return np.array([slider.center_value for slider in self.sliders])
def set_center_point(self, new_center_point):
self.center_point = np.array(new_center_point)
for x, slider in zip(new_center_point, self.sliders):
slider.set_center_value(x)
return self
def get_current_total_real_estate(self):
return sum([
slider.get_real_estate()
for slider in self.sliders
])
def get_all_dial_supplement_animations(self):
return [
slider.get_dial_supplement_animation()
for slider in self.sliders
]
def initialize_ambiant_slider_movement(self):
self.ambiently_change_sliders = True
self.ambient_change_end_time = np.inf
self.ambient_change_time = 0
self.ambient_velocity, self.ambient_acceleration, self.ambient_jerk = [
self.get_random_vector(magnitude)
for magnitude in [
self.ambient_velocity_magnitude,
self.ambient_acceleration_magnitude,
self.ambient_jerk_magnitude,
]
]
##Ensure counterclockwise rotations in 2D
if len(self.ambient_velocity) == 2:
cross = np.cross(self.get_vector(), self.ambient_velocity)
if cross < 0:
self.ambient_velocity *= -1
self.add_foreground_mobjects(self.sliders)
def wind_down_ambient_movement(self, time = 1, wait = True):
self.ambient_change_end_time = self.ambient_change_time + time
if wait:
self.wait(time)
if self.skip_animations:
self.ambient_change_time += time
def ambient_slider_movement_update(self):
#Set velocity_magnitude based on start up or wind down
velocity_magnitude = float(self.ambient_velocity_magnitude)
if self.ambient_change_time <= 1:
velocity_magnitude *= smooth(self.ambient_change_time)
time_until_end = self.ambient_change_end_time - self.ambient_change_time
if time_until_end <= 1:
velocity_magnitude *= smooth(time_until_end)
if time_until_end < 0:
self.ambiently_change_sliders = False
return
center_point = self.get_center_point()
target_vector = self.get_vector() - center_point
if get_norm(target_vector) == 0:
return
vectors_and_magnitudes = [
(self.ambient_acceleration, self.ambient_acceleration_magnitude),
(self.ambient_velocity, velocity_magnitude),
(target_vector, np.sqrt(self.total_real_estate)),
]
jerk = self.get_random_vector(self.ambient_jerk_magnitude)
deriv = jerk
for vect, mag in vectors_and_magnitudes:
vect += self.frame_duration*deriv
if vect is self.ambient_velocity:
unit_r_vect = target_vector / get_norm(target_vector)
vect -= np.dot(vect, unit_r_vect)*unit_r_vect
vect *= mag/get_norm(vect)
deriv = vect
self.set_to_vector(target_vector + center_point)
self.ambient_change_time += self.frame_duration
def get_random_vector(self, magnitude):
result = 2*np.random.random(len(self.sliders)) - 1
result *= magnitude / get_norm(result)
return result
def update_frame(self, *args, **kwargs):
if self.ambiently_change_sliders:
self.ambient_slider_movement_update()
Scene.update_frame(self, *args, **kwargs)
def wait(self, time = 1):
if self.ambiently_change_sliders:
self.play(Animation(self.sliders, run_time = time))
else:
Scene.wait(self,time)
##########
class MathIsATease(Scene):
def construct(self):
randy = Randolph()
lashes = VGroup()
for eye in randy.eyes:
for angle in np.linspace(-np.pi/3, np.pi/3, 12):
lash = Line(ORIGIN, RIGHT)
lash.set_stroke(DARK_GREY, 2)
lash.set_width(0.27)
lash.next_to(ORIGIN, RIGHT, buff = 0)
lash.rotate(angle + np.pi/2)
lash.shift(eye.get_center())
lashes.add(lash)
lashes.do_in_place(lashes.stretch, 0.8, 1)
lashes.shift(0.04*DOWN)
fan = SVGMobject(
file_name = "fan",
fill_opacity = 1,
fill_color = YELLOW,
stroke_width = 2,
stroke_color = YELLOW,
height = 0.7,
)
VGroup(*fan[-12:]).set_fill(YELLOW_E)
fan.rotate(-np.pi/4)
fan.move_to(randy)
fan.shift(0.85*UP+0.25*LEFT)
self.add(randy)
self.play(
ShowCreation(lashes, lag_ratio = 0),
randy.change, "tease",
randy.look, OUT,
)
self.add_foreground_mobjects(fan)
eye_bottom_y = randy.eyes.get_bottom()[1]
self.play(
ApplyMethod(
lashes.apply_function,
lambda p : [p[0], eye_bottom_y, p[2]],
rate_func = Blink.CONFIG["rate_func"],
),
Blink(randy),
DrawBorderThenFill(fan),
)
self.play(
ApplyMethod(
lashes.apply_function,
lambda p : [p[0], eye_bottom_y, p[2]],
rate_func = Blink.CONFIG["rate_func"],
),
Blink(randy),
)
self.wait()
class TODODeterminants(TODOStub):
CONFIG = {
"message" : "Determinants clip"
}
class CircleToPairsOfPoints(Scene):
def construct(self):
plane = NumberPlane(written_coordinate_height = 0.3)
plane.scale(2)
plane.add_coordinates(y_vals = [-1, 1])
background_plane = plane.copy()
background_plane.set_color(GREY)
background_plane.fade()
circle = Circle(radius = 2, color = YELLOW)
x, y = [np.sqrt(2)/2]*2
dot = Dot(2*x*RIGHT + 2*y*UP, color = LIGHT_GREY)
equation = TexMobject("x", "^2", "+", "y", "^2", "=", "1")
equation.set_color_by_tex("x", GREEN)
equation.set_color_by_tex("y", RED)
equation.to_corner(UP+LEFT)
equation.add_background_rectangle()
coord_pair = TexMobject("(", "-%.02f"%x, ",", "-%.02f"%y, ")")
fixed_numbers = coord_pair.get_parts_by_tex("-")
fixed_numbers.set_fill(opacity = 0)
coord_pair.add_background_rectangle()
coord_pair.next_to(dot, UP+RIGHT, SMALL_BUFF)
numbers = VGroup(*[
DecimalNumber(val).replace(num, dim_to_match = 1)
for val, num in zip([x, y], fixed_numbers)
])
numbers[0].set_color(GREEN)
numbers[1].set_color(RED)
def get_update_func(i):
return lambda t : dot.get_center()[i]/2.0
self.add(background_plane, plane)
self.play(ShowCreation(circle))
self.play(
FadeIn(coord_pair),
Write(numbers, run_time = 1),
ShowCreation(dot),
)
self.play(
Write(equation),
*[
Transform(
number.copy(),
equation.get_parts_by_tex(tex),
remover = True
)
for tex, number in zip("xy", numbers)
]
)
self.play(FocusOn(dot, run_time = 1))
self.play(
Rotating(
dot, run_time = 7, in_place = False,
rate_func = smooth,
),
MaintainPositionRelativeTo(coord_pair, dot),
*[
ChangingDecimal(
num, get_update_func(i),
tracked_mobject = fixed_num
)
for num, i, fixed_num in zip(
numbers, (0, 1), fixed_numbers
)
]
)
self.wait()
######### Rotation equations ##########
rot_equation = TexMobject(
"\\Rightarrow"
"\\big(\\cos(\\theta)x - \\sin(\\theta)y\\big)^2 + ",
"\\big(\\sin(\\theta)x + \\cos(\\theta)y\\big)^2 = 1",
)
rot_equation.scale(0.9)
rot_equation.next_to(equation, RIGHT)
rot_equation.add_background_rectangle()
words = TextMobject("Rotational \\\\ symmetry")
words.next_to(ORIGIN, UP)
words.to_edge(RIGHT)
words.add_background_rectangle()
arrow = Arrow(
words.get_left(), rot_equation.get_bottom(),
path_arc = -np.pi/6
)
randy = Randolph(color = GREY_BROWN)
randy.to_corner(DOWN+LEFT)
self.play(
Write(rot_equation, run_time = 2),
FadeOut(coord_pair),
FadeOut(numbers),
FadeOut(dot),
FadeIn(randy)
)
self.play(randy.change, "confused", rot_equation)
self.play(Blink(randy))
self.play(
Write(words, run_time = 1),
ShowCreation(arrow),
randy.look_at, words
)
plane.remove(*plane.coordinate_labels)
self.play(
Rotate(
plane, np.pi/3,
run_time = 4,
rate_func = there_and_back
),
Animation(equation),
Animation(rot_equation),
Animation(words),
Animation(arrow),
Animation(circle),
randy.change, "hooray"
)
self.wait()
class GreatSourceOfMaterial(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"It's a great source \\\\ of material.",
target_mode = "hooray"
)
self.change_student_modes(*["happy"]*3)
self.wait(3)
class CirclesSpheresSumsSquares(ExternallyAnimatedScene):
pass
class BackAndForth(Scene):
def construct(self):
analytic = TextMobject("Analytic")
analytic.shift(FRAME_X_RADIUS*LEFT/2)
analytic.to_edge(UP, buff = MED_SMALL_BUFF)
geometric = TextMobject("Geometric")
geometric.shift(FRAME_X_RADIUS*RIGHT/2)
geometric.to_edge(UP, buff = MED_SMALL_BUFF)
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
h_line.to_edge(UP, LARGE_BUFF)
v_line = Line(UP, DOWN).scale(FRAME_Y_RADIUS)
self.add(analytic, geometric, h_line, v_line)
pair = TexMobject("(", "x", ",", "y", ")")
pair.shift(FRAME_X_RADIUS*LEFT/2 + FRAME_Y_RADIUS*UP/3)
triplet = TexMobject("(", "x", ",", "y", ",", "z", ")")
triplet.shift(FRAME_X_RADIUS*LEFT/2 + FRAME_Y_RADIUS*DOWN/2)
for mob in pair, triplet:
arrow = DoubleArrow(LEFT, RIGHT)
arrow.move_to(mob)
arrow.shift(2*RIGHT)
mob.arrow = arrow
circle_eq = TexMobject("x", "^2", "+", "y", "^2", "=", "1")
circle_eq.move_to(pair)
sphere_eq = TexMobject("x", "^2", "+", "y", "^2", "+", "z", "^2", "=", "1")
sphere_eq.move_to(triplet)
plane = NumberPlane(x_unit_size = 2, y_unit_size = 2)
circle = Circle(radius = 2, color = YELLOW)
plane_group = VGroup(plane, circle)
plane_group.scale(0.4)
plane_group.next_to(h_line, DOWN, SMALL_BUFF)
plane_group.shift(FRAME_X_RADIUS*RIGHT/2)
self.play(Write(pair))
# self.play(ShowCreation(pair.arrow))
self.play(ShowCreation(plane, run_time = 3))
self.play(Write(triplet))
# self.play(ShowCreation(triplet.arrow))
self.wait(3)
for tup, eq, to_draw in (pair, circle_eq, circle), (triplet, sphere_eq, VMobject()):
for mob in tup, eq:
mob.xyz = VGroup(*[sm for sm in map(mob.get_part_by_tex, "xyz") if sm is not None])
self.play(
ReplacementTransform(tup.xyz, eq.xyz),
FadeOut(VGroup(*[sm for sm in tup if sm not in tup.xyz])),
)
self.play(
Write(VGroup(*[sm for sm in eq if sm not in eq.xyz])),
ShowCreation(to_draw)
)
self.wait(3)
class SphereForming(ExternallyAnimatedScene):
pass
class PreviousVideos(Scene):
def construct(self):
titles = VGroup(*list(map(TextMobject, [
"Pi hiding in prime regularities",
"Visualizing all possible pythagorean triples",
"Borsuk-Ulam theorem",
])))
titles.to_edge(UP, buff = MED_SMALL_BUFF)
screen = ScreenRectangle(height = 6)
screen.next_to(titles, DOWN)
title = titles[0]
self.add(title, screen)
self.wait(2)
for new_title in titles[1:]:
self.play(Transform(title, new_title))
self.wait(2)
class TODOTease(TODOStub):
CONFIG = {
"message" : "Tease"
}
class AskAboutLongerLists(TeacherStudentsScene):
def construct(self):
question = TextMobject(
"What about \\\\",
"$(x_1, x_2, x_3, x_4)?$"
)
tup = question[1]
alt_tups = list(map(TextMobject, [
"$(x_1, x_2, x_3, x_4, x_5)?$",
"$(x_1, x_2, \\dots, x_{99}, x_{100})?$"
]))
self.student_says(question, run_time = 1)
self.wait()
for alt_tup in alt_tups:
alt_tup.move_to(tup)
self.play(Transform(tup, alt_tup))
self.wait()
self.wait()
self.play(
RemovePiCreatureBubble(self.students[1]),
self.teacher.change, "raise_right_hand"
)
self.change_student_modes(
*["confused"]*3,
look_at_arg = self.teacher.get_top() + 2*UP
)
self.play(self.teacher.look, UP)
self.wait(5)
self.student_says(
"I...don't see it.",
target_mode = "maybe",
student_index = 0
)
self.wait(3)
class FourDCubeRotation(ExternallyAnimatedScene):
pass
class HypersphereRotation(ExternallyAnimatedScene):
pass
class FourDSurfaceRotating(ExternallyAnimatedScene):
pass
class Professionals(PiCreatureScene):
def construct(self):
self.introduce_characters()
self.add_equation()
self.analogies()
def introduce_characters(self):
titles = VGroup(*list(map(TextMobject, [
"Mathematician",
"Computer scientist",
"Physicist",
])))
self.remove(*self.pi_creatures)
for title, pi in zip(titles, self.pi_creatures):
title.next_to(pi, DOWN)
self.play(
Animation(VectorizedPoint(pi.eyes.get_center())),
FadeIn(pi),
Write(title, run_time = 1),
)
self.wait()
def add_equation(self):
quaternion = TexMobject(
"\\frac{1}{2}", "+",
"0", "\\textbf{i}", "+",
"\\frac{\\sqrt{6}}{4}", "\\textbf{j}", "+",
"\\frac{\\sqrt{6}}{4}", "\\textbf{k}",
)
quaternion.scale(0.7)
quaternion.next_to(self.mathy, UP)
quaternion.set_color_by_tex_to_color_map({
"i" : RED,
"j" : GREEN,
"k" : BLUE,
})
array = TexMobject("[a_1, a_2, \\dots, a_{100}]")
array.next_to(self.compy, UP)
kets = TexMobject(
"\\alpha",
"|\\!\\uparrow\\rangle + ",
"\\beta",
"|\\!\\downarrow\\rangle"
)
kets.set_color_by_tex_to_color_map({
"\\alpha" : GREEN,
"\\beta" : RED,
})
kets.next_to(self.physy, UP)
terms = VGroup(quaternion, array, kets)
for term, pi in zip(terms, self.pi_creatures):
self.play(
Write(term, run_time = 1),
pi.change, "pondering", term
)
self.wait(2)
self.terms = terms
def analogies(self):
examples = VGroup()
plane = ComplexPlane(
x_radius = 2.5,
y_radius = 1.5,
)
plane.add_coordinates()
plane.add(Circle(color = YELLOW))
plane.scale(0.75)
examples.add(plane)
examples.add(Circle())
examples.arrange(RIGHT, buff = 2)
examples.to_edge(UP, buff = LARGE_BUFF)
labels = VGroup(*list(map(TextMobject, ["2D", "3D"])))
title = TextMobject("Fly by instruments")
title.scale(1.5)
title.to_edge(UP)
for label, example in zip(labels, examples):
label.next_to(example, DOWN)
self.play(
ShowCreation(example),
Write(label, run_time = 1)
)
example.add(label)
self.wait()
self.wait()
self.play(
FadeOut(examples),
self.terms.shift, UP,
Write(title, run_time = 2)
)
self.play(*[
ApplyMethod(
pi.change, mode, self.terms.get_left(),
run_time = 2,
rate_func = squish_rate_func(smooth, a, a+0.5)
)
for pi, mode, a in zip(
self.pi_creatures,
["confused", "sassy", "erm"],
np.linspace(0, 0.5, len(self.pi_creatures))
)
])
self.wait()
self.play(Animation(self.terms[-1]))
self.wait(2)
######
def create_pi_creatures(self):
self.mathy = Mathematician()
self.physy = PiCreature(color = PINK)
self.compy = PiCreature(color = PURPLE)
pi_creatures = VGroup(self.mathy, self.compy, self.physy)
for pi in pi_creatures:
pi.scale(0.7)
pi_creatures.arrange(RIGHT, buff = 3)
pi_creatures.to_edge(DOWN, buff = LARGE_BUFF)
return pi_creatures
class OfferAHybrid(SliderScene):
CONFIG = {
"n_sliders" : 3,
}
def construct(self):
self.remove(self.sliders)
titles = self.get_titles()
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
h_line.next_to(titles, DOWN)
v_lines = VGroup(*[
Line(UP, DOWN).scale(FRAME_Y_RADIUS)
for x in range(2)
])
v_lines.generate_target()
for line, vect in zip(v_lines.target, [LEFT, RIGHT]):
line.shift(vect*FRAME_X_RADIUS/3)
equation = TexMobject("x^2 + y^2 + z^2 = 1")
equation.generate_target()
equation.shift(FRAME_X_RADIUS*LEFT/2)
equation.target.shift(FRAME_WIDTH*LEFT/3)
self.add(titles, h_line, v_lines, equation)
self.wait()
self.play(*list(map(MoveToTarget, [titles, v_lines, equation])))
self.play(Write(self.sliders, run_time = 1))
self.initialize_ambiant_slider_movement()
self.wait(10)
self.wind_down_ambient_movement()
self.wait()
def get_titles(self):
titles = VGroup(*list(map(TextMobject, [
"Analytic", "Hybrid", "Geometric"
])))
titles.to_edge(UP)
titles[1].set_color(BLUE)
titles.generate_target()
titles[1].scale_in_place(0.001)
titles[0].shift(FRAME_X_RADIUS*LEFT/2)
titles.target[0].shift(FRAME_WIDTH*LEFT/3)
titles[2].shift(FRAME_X_RADIUS*RIGHT/2)
titles.target[2].shift(FRAME_WIDTH*RIGHT/3)
return titles
class TODOBoxExample(TODOStub):
CONFIG = {
"message" : "Box Example"
}
class RotatingSphereWithWanderingPoint(ExternallyAnimatedScene):
pass
class DismissProjection(PiCreatureScene):
CONFIG = {
"screen_rect_color" : WHITE,
"example_vect" : np.array([0.52, 0.26, 0.53, 0.60]),
}
def construct(self):
self.remove(self.pi_creature)
self.show_all_spheres()
self.discuss_4d_sphere_definition()
self.talk_through_animation()
self.transition_to_next_scene()
def show_all_spheres(self):
equations = VGroup(*list(map(TexMobject, [
"x^2 + y^2 = 1",
"x^2 + y^2 + z^2 = 1",
"x^2 + y^2 + z^2 + w^2 = 1",
])))
colors = [YELLOW, GREEN, BLUE]
for equation, edge, color in zip(equations, [LEFT, ORIGIN, RIGHT], colors):
equation.set_color(color)
equation.shift(3*UP)
equation.to_edge(edge)
equations[1].shift(LEFT)
spheres = VGroup(
self.get_circle(equations[0]),
self.get_sphere_screen(equations[1], DOWN),
self.get_sphere_screen(equations[2], DOWN),
)
for equation, sphere in zip(equations, spheres):
self.play(
Write(equation),
LaggedStartMap(ShowCreation, sphere),
)
self.wait()
self.equations = equations
self.spheres = spheres
def get_circle(self, equation):
result = VGroup(
NumberPlane(
x_radius = 2.5,
y_radius = 2,
).fade(0.4),
Circle(color = YELLOW, radius = 1),
)
result.scale(0.7)
result.next_to(equation, DOWN)
return result
def get_sphere_screen(self, equation, vect):
square = Rectangle()
square.set_width(equation.get_width())
square.stretch_to_fit_height(3)
square.next_to(equation, vect)
square.set_color(self.screen_rect_color)
return square
def discuss_4d_sphere_definition(self):
sphere = self.spheres[-1]
equation = self.equations[-1]
sphere_words = TextMobject("``4-dimensional sphere''")
sphere_words.next_to(sphere, DOWN+LEFT, buff = LARGE_BUFF)
arrow = Arrow(
sphere_words.get_right(), sphere.get_bottom(),
path_arc = np.pi/3,
color = BLUE
)
descriptor = TexMobject(
"\\text{Just lists of numbers like }",
"(%.02f \\,, %.02f \\,, %.02f \\,, %.02f \\,)"%tuple(self.example_vect)
)
descriptor[1].set_color(BLUE)
descriptor.next_to(sphere_words, DOWN)
dot = Dot(descriptor[1].get_top())
dot.set_fill(WHITE, opacity = 0.75)
self.play(
Write(sphere_words),
ShowCreation(
arrow,
rate_func = squish_rate_func(smooth, 0.5, 1)
),
run_time = 3,
)
self.wait()
self.play(Write(descriptor, run_time = 2))
self.wait()
self.play(
dot.move_to, equation.get_left(),
dot.set_fill, None, 0,
path_arc = -np.pi/12
)
self.wait(2)
self.sphere_words = sphere_words
self.sphere_arrow = arrow
self.descriptor = descriptor
def talk_through_animation(self):
sphere = self.spheres[-1]
morty = self.pi_creature
alt_dims = VGroup(*list(map(TextMobject, ["5D", "6D", "7D"])))
alt_dims.next_to(morty.eyes, UP, SMALL_BUFF)
alt_dim = alt_dims[0]
self.play(FadeIn(morty))
self.play(morty.change, "raise_right_hand", sphere)
self.wait(3)
self.play(morty.change, "confused", sphere)
self.wait(3)
self.play(
morty.change, "erm", alt_dims,
FadeIn(alt_dim)
)
for new_alt_dim in alt_dims[1:]:
self.wait()
self.play(Transform(alt_dim, new_alt_dim))
self.wait()
self.play(morty.change, "concerned_musician")
self.play(FadeOut(alt_dim))
self.wait()
self.play(morty.change, "angry", sphere)
self.wait(2)
def transition_to_next_scene(self):
equation = self.equations[-1]
self.equations.remove(equation)
tup = self.descriptor[1]
self.descriptor.remove(tup)
equation.generate_target()
equation.target.center().to_edge(UP)
tup.generate_target()
tup.target.next_to(equation.target, DOWN)
tup.target.set_color(WHITE)
self.play(LaggedStartMap(FadeOut, VGroup(*[
self.equations, self.spheres,
self.sphere_words, self.sphere_arrow,
self.descriptor,
self.pi_creature
])))
self.play(*list(map(MoveToTarget, [equation, tup])))
self.wait()
###
def create_pi_creature(self):
return Mortimer().scale(0.8).to_corner(DOWN+RIGHT)
class RotatingSphere(ExternallyAnimatedScene):
pass
class Introduce4DSliders(SliderScene):
CONFIG = {
"slider_config" : {
"include_real_estate_ticks" : False,
"numbers_with_elongated_ticks" : [-1, 0, 1],
"tick_frequency" : 0.25,
"tick_size" : 0.05,
"dial_color" : YELLOW,
},
"slider_spacing" : LARGE_BUFF,
}
def construct(self):
self.match_last_scene()
self.introduce_sliders()
self.ask_about_constraint()
def match_last_scene(self):
self.start_vect = DismissProjection.CONFIG["example_vect"]
self.remove(self.sliders)
equation = TexMobject("x^2 + y^2 + z^2 + w^2 = 1")
x, y, z, w = self.start_vect
tup = TexMobject(
"(", "%.02f \\,"%x,
",", "%.02f \\,"%y,
",", "%.02f \\,"%z,
",", "%.02f \\,"%w, ")"
)
equation.center().to_edge(UP)
equation.set_color(BLUE)
tup.next_to(equation, DOWN)
self.sliders.next_to(tup, DOWN)
self.sliders.shift(0.8*LEFT)
self.add(equation, tup)
self.wait()
self.equation = equation
self.tup = tup
def introduce_sliders(self):
self.set_to_vector(self.start_vect)
numbers = self.tup.get_parts_by_tex(".")
self.tup.remove(*numbers)
dials = VGroup(*[slider.dial for slider in self.sliders])
dial_copies = dials.copy()
dials.set_fill(opacity = 0)
self.play(LaggedStartMap(FadeIn, self.sliders))
self.play(*[
Transform(
num, dial,
run_time = 3,
rate_func = squish_rate_func(smooth, a, a+0.5),
remover = True
)
for num, dial, a in zip(
numbers, dial_copies,
np.linspace(0, 0.5, len(numbers))
)
])
dials.set_fill(opacity = 1)
self.initialize_ambiant_slider_movement()
self.play(FadeOut(self.tup))
self.wait(10)
def ask_about_constraint(self):
equation = self.equation
rect = SurroundingRectangle(equation, color = GREEN)
randy = Randolph().scale(0.5)
randy.next_to(rect, DOWN+LEFT, LARGE_BUFF)
self.play(ShowCreation(rect))
self.play(FadeIn(randy))
self.play(randy.change, "pondering", rect)
self.wait()
for mob in self.sliders, rect:
self.play(randy.look_at, mob)
self.play(Blink(randy))
self.wait()
self.wait()
class TwoDimensionalCase(Introduce4DSliders):
CONFIG = {
"n_sliders" : 2,
}
def setup(self):
SliderScene.setup(self)
self.sliders.shift(RIGHT)
for number in self.sliders[0].numbers:
value = int(number.get_tex_string())
number.move_to(center_of_mass([
slider.number_to_point(value)
for slider in self.sliders
]))
plane = NumberPlane(
x_radius = 2.5,
y_radius = 2.5,
)
plane.fade(0.25)
plane.axes.set_color(GREY)
plane.add_coordinates()
plane.to_edge(LEFT)
origin = plane.coords_to_point(0, 0)
circle = Circle(radius = 1, color = WHITE)
circle.move_to(plane.coords_to_point(*self.center_point))
dot = Dot(color = YELLOW)
dot.move_to(plane.coords_to_point(1, 0))
equation = TexMobject("x^2 + y^2 = 1")
equation.to_corner(UP + RIGHT)
self.add(plane, circle, dot, equation)
self.add_foreground_mobjects(dot)
self.plane = plane
self.circle = circle
self.dot = dot
self.equation = equation
def construct(self):
self.let_values_wander()
self.introduce_real_estate()
self.let_values_wander(6)
self.comment_on_cheap_vs_expensive_real_estate()
self.nudge_x_from_one_example()
self.note_circle_steepness()
self.add_tick_marks()
self.write_distance_squared()
def let_values_wander(self, total_time = 5):
self.initialize_ambiant_slider_movement()
self.wait(total_time - 1)
self.wind_down_ambient_movement()
def introduce_real_estate(self):
x_squared_mob = VGroup(*self.equation[:2])
y_squared_mob = VGroup(*self.equation[3:5])
x_rect = SurroundingRectangle(x_squared_mob)
y_rect = SurroundingRectangle(y_squared_mob)
rects = VGroup(x_rect, y_rect)
decimals = VGroup(*[
DecimalNumber(num**2)
for num in self.get_vector()
])
decimals.arrange(RIGHT, buff = LARGE_BUFF)
decimals.next_to(rects, DOWN, LARGE_BUFF)
real_estate_word = TextMobject("``Real estate''")
real_estate_word.next_to(decimals, DOWN, MED_LARGE_BUFF)
self.play(FadeIn(real_estate_word))
colors = GREEN, RED
arrows = VGroup()
for rect, decimal, color in zip(rects, decimals, colors):
rect.set_color(color)
decimal.set_color(color)
arrow = Arrow(
rect.get_bottom()+SMALL_BUFF*UP, decimal.get_top(),
tip_length = 0.2,
)
arrow.set_color(color)
arrows.add(arrow)
self.play(ShowCreation(rect))
self.play(
ShowCreation(arrow),
Write(decimal)
)
self.wait()
sliders = self.sliders
def create_update_func(i):
return lambda alpha : sliders[i].get_real_estate()
self.add_foreground_mobjects(decimals)
self.decimals = decimals
self.decimal_update_anims = [
ChangingDecimal(decimal, create_update_func(i))
for i, decimal in enumerate(decimals)
]
self.real_estate_word = real_estate_word
def comment_on_cheap_vs_expensive_real_estate(self):
blue_rects = VGroup()
red_rects = VGroup()
for slider in self.sliders:
for x1, x2 in (-0.5, 0.5), (0.75, 1.0), (-1.0, -0.75):
p1, p2 = list(map(slider.number_to_point, [x1, x2]))
rect = Rectangle(
stroke_width = 0,
fill_opacity = 0.5,
width = 0.25,
height = (p2-p1)[1]
)
rect.move_to((p1+p2)/2)
if np.mean([x1, x2]) == 0:
rect.set_color(BLUE)
blue_rects.add(rect)
else:
rect.set_color(RED)
red_rects.add(rect)
blue_rects.save_state()
self.play(DrawBorderThenFill(blue_rects))
self.wait()
self.play(ReplacementTransform(blue_rects, red_rects))
self.wait()
self.play(FadeOut(red_rects))
blue_rects.restore()
self.real_estate_rects = VGroup(blue_rects, red_rects)
def nudge_x_from_one_example(self):
x_re = self.decimals[0]
rect = SurroundingRectangle(x_re)
self.reset_dials([1, 0])
self.wait()
self.play(ShowCreation(rect))
self.play(FadeOut(rect))
self.play(FocusOn(self.dot))
self.wait()
self.reset_dials([0.9, -np.sqrt(0.19)])
x_brace, y_brace = [
Brace(
VGroup(slider.dial, Dot(slider.number_to_point(0))),
vect
)
for slider, vect in zip(self.sliders, [LEFT, RIGHT])
]
x_text = x_brace.get_tex("0.9")
y_text = y_brace.get_tex("%.02f"%self.sliders[1].get_value())
self.play(
GrowFromCenter(x_brace),
Write(x_text)
)
self.play(ReplacementTransform(
VGroup(x_text.copy()), x_re
))
self.wait(2)
self.play(
GrowFromCenter(y_brace),
Write(y_text),
)
self.wait(2)
self.play(FadeIn(self.real_estate_rects))
self.reset_dials([1, 0], run_time = 1)
self.reset_dials([0.9, -np.sqrt(0.19)], run_time = 2)
self.play(FadeOut(self.real_estate_rects))
self.play(*list(map(FadeOut, [x_brace, y_brace, x_text, y_text])))
self.wait()
def note_circle_steepness(self):
line = Line(
self.plane.coords_to_point(0.5, 1),
self.plane.coords_to_point(1.5, -1),
)
rect = Rectangle(
stroke_width = 0,
fill_color = BLUE,
fill_opacity = 0.5,
)
rect.replace(line, stretch = True)
self.play(DrawBorderThenFill(rect, stroke_color = YELLOW))
for x, u in (1, 1), (0.8, 1), (1, 1), (0.8, -1), (1, 1):
self.reset_dials([x, u*np.sqrt(1 - x**2)])
self.play(FadeOut(rect))
def add_tick_marks(self):
self.remove_foreground_mobjects(self.sliders)
self.add(self.sliders)
old_ticks = VGroup()
all_ticks = VGroup()
for slider in self.sliders:
slider.tick_size = 0.1
slider.add_real_estate_ticks()
slider.remove(slider.get_tick_marks())
all_ticks.add(*slider.real_estate_ticks)
old_ticks.add(*slider.get_tick_marks()[:-3])
self.play(
FadeOut(old_ticks),
ShowCreation(all_ticks, run_time = 3),
Animation(VGroup(*[slider.dial for slider in self.sliders])),
)
self.add_foreground_mobjects(self.sliders)
self.wait()
for x in np.arange(0.95, 0.05, -0.05):
self.reset_dials(
[np.sqrt(x), np.sqrt(1-x)],
run_time = 0.5
)
self.wait(0.5)
self.initialize_ambiant_slider_movement()
self.wait(10)
def write_distance_squared(self):
d_squared = TexMobject("(\\text{Distance})^2")
d_squared.next_to(self.real_estate_word, DOWN)
d_squared.set_color(YELLOW)
self.play(Write(d_squared))
self.wait(3)
#####
def update_frame(self, *args, **kwargs):
if hasattr(self, "dot"):
x, y = self.get_vector()
self.dot.move_to(self.plane.coords_to_point(x, y))
if hasattr(self, "decimals"):
for anim in self.decimal_update_anims:
anim.update(0)
SliderScene.update_frame(self, *args, **kwargs)
class TwoDimensionalCaseIntro(TwoDimensionalCase):
def construct(self):
self.initialize_ambiant_slider_movement()
self.wait(10)
class ThreeDCase(TwoDimensionalCase):
CONFIG = {
"n_sliders" : 3,
"slider_config" : {
"include_real_estate_ticks" : True,
"numbers_with_elongated_ticks" : [],
"tick_frequency" : 1,
"tick_size" : 0.1,
},
}
def setup(self):
SliderScene.setup(self)
self.equation = TexMobject(
"x^2", "+", "y^2", "+", "z^2", "=", "1"
)
self.equation.to_corner(UP+RIGHT)
self.add(self.equation)
def construct(self):
self.force_skipping()
self.add_real_estate_decimals()
self.initialize_ambiant_slider_movement()
self.point_out_third_slider()
self.wait(3)
self.hold_x_at(0.5, 12)
self.revert_to_original_skipping_status()
self.hold_x_at(0.85, 12)
return
self.hold_x_at(1, 5)
def add_real_estate_decimals(self):
rects = VGroup(*[
SurroundingRectangle(self.equation.get_part_by_tex(char))
for char in "xyz"
])
decimals = VGroup(*[
DecimalNumber(num**2)
for num in self.get_vector()
])
decimals.arrange(RIGHT, buff = LARGE_BUFF)
decimals.next_to(rects, DOWN, LARGE_BUFF)
colors = [GREEN, RED, BLUE]
arrows = VGroup()
for rect, decimal, color in zip(rects, decimals, colors):
rect.set_color(color)
decimal.set_color(color)
arrow = Arrow(
rect.get_bottom()+SMALL_BUFF*UP, decimal.get_top(),
tip_length = 0.2,
color = color
)
arrows.add(arrow)
real_estate_word = TextMobject("``Real estate''")
real_estate_word.next_to(decimals, DOWN, MED_LARGE_BUFF)
sliders = self.sliders
def create_update_func(i):
return lambda alpha : sliders[i].get_real_estate()
self.add_foreground_mobjects(decimals)
self.decimals = decimals
self.decimal_update_anims = [
ChangingDecimal(decimal, create_update_func(i))
for i, decimal in enumerate(decimals)
]
self.add(rects, arrows, real_estate_word)
self.rects = rects
self.arrows = arrows
self.real_estate_word = real_estate_word
def point_out_third_slider(self):
rect = SurroundingRectangle(self.sliders[-1])
self.wait(4)
self.play(ShowCreation(rect))
self.play(FadeOut(rect))
self.wait(8)
def hold_x_at(self, x_val, wait_time):
#Save these
all_sliders = self.sliders
original_total_real_estate = self.total_real_estate
self.reset_dials([x_val], run_time = 3)
self.sliders = VGroup(*self.sliders[1:])
self.total_real_estate = self.total_real_estate-x_val**2
self.initialize_ambiant_slider_movement()
self.wait(wait_time-2)
self.wind_down_ambient_movement()
self.sliders = all_sliders
self.total_real_estate = original_total_real_estate
self.initialize_ambiant_slider_movement()
####
class ThreeDCaseInsert(ThreeDCase):
def construct(self):
self.add_real_estate_decimals()
self.reset_dials([0.85, np.sqrt(1-0.85**2)], run_time = 0)
self.reset_dials([1], run_time = 3)
self.wait()
class SphereAtRest(ExternallyAnimatedScene):
pass
class BugOnASurface(TeacherStudentsScene):
def construct(self):
self.teacher_says("You're a bug \\\\ on a surface")
self.wait(3)
class SphereWithWanderingDotAtX0point5(ExternallyAnimatedScene):
pass
class MoveSphereSliceFromPoint5ToPoint85(ExternallyAnimatedScene):
pass
class SphereWithWanderingDotAtX0point85(ExternallyAnimatedScene):
pass
class MoveSphereSliceFromPoint85To1(ExternallyAnimatedScene):
pass
class BugOnTheSurfaceSlidersPart(ThreeDCase):
CONFIG = {
"run_time" : 30
}
def construct(self):
self.add_real_estate_decimals()
self.reset_dials([0.9], run_time = 0)
time_range = np.arange(0, self.run_time, self.frame_duration)
for time in ProgressDisplay(time_range):
t = 0.3*np.sin(2*np.pi*time/7.0) + 1
u = 0.3*np.sin(4*np.pi*time/7.0) + 1.5
self.set_to_vector([
np.cos(u),
np.sin(u)*np.cos(t),
np.sin(u)*np.sin(t),
])
self.wait(self.frame_duration)
class BugOnTheSurfaceSpherePart(ExternallyAnimatedScene):
pass
class FourDCase(SliderScene, TeacherStudentsScene):
def setup(self):
TeacherStudentsScene.setup(self)
SliderScene.setup(self)
self.sliders.scale(0.9)
self.sliders.to_edge(UP)
self.sliders.shift(2*RIGHT)
self.initialize_ambiant_slider_movement()
def construct(self):
self.show_initial_exchange()
self.fix_one_slider()
self.ask_now_what()
self.set_aside_sliders()
def show_initial_exchange(self):
dot = Dot(fill_opacity = 0)
dot.to_corner(UP+LEFT, buff = 2)
self.play(Animation(dot))
self.wait()
self.play(
Animation(self.sliders),
self.teacher.change, "raise_right_hand",
)
self.change_student_modes(
*["pondering"]*3,
look_at_arg = self.sliders
)
self.wait(4)
def fix_one_slider(self):
x_slider = self.sliders[0]
dial = x_slider.dial
self.wind_down_ambient_movement(wait = False)
self.play(self.teacher.change, "speaking")
self.sliders.remove(x_slider)
self.total_real_estate = get_norm(self.get_vector())**2
self.initialize_ambiant_slider_movement()
arrow = Arrow(LEFT, RIGHT, color = GREEN)
arrow.next_to(dial, LEFT)
self.play(
ShowCreation(arrow),
dial.set_color, arrow.get_color()
)
self.change_student_modes(
"erm", "confused", "hooray",
look_at_arg = self.sliders,
added_anims = [self.teacher.change, "plain"]
)
self.wait(5)
self.x_slider = x_slider
self.x_arrow = arrow
def ask_now_what(self):
self.student_says(
"Okay...now what?",
target_mode = "raise_left_hand",
student_index = 0,
added_anims = [self.teacher.change, "plain"]
)
self.change_student_modes(
None, "pondering", "pondering",
look_at_arg = self.students[0].bubble,
)
self.wait(4)
self.play(RemovePiCreatureBubble(self.students[0]))
def set_aside_sliders(self):
self.sliders.add(self.x_slider)
self.total_real_estate = 1
self.initialize_ambiant_slider_movement()
self.play(
self.sliders.scale, 0.5,
self.sliders.to_corner, UP+RIGHT,
FadeOut(self.x_arrow)
)
self.teacher_says(
"Time for some \\\\ high-dimensional \\\\ strangeness!",
target_mode = "hooray",
)
self.wait(7)
#####
def non_blink_wait(self, time = 1):
SliderScene.wait(self, time)
class TwoDBoxExample(Scene):
def setup(self):
scale_factor = 1.7
self.plane = NumberPlane()
self.plane.scale(scale_factor)
self.plane.add_coordinates()
self.plane.axes.set_color(GREY)
self.add(self.plane)
def construct(self):
self.add_box()
self.label_corner_coordinates()
self.add_corner_circles()
self.add_center_circle()
self.compute_radius()
def add_box(self):
box = Square(color = RED, stroke_width = 6)
line = Line(
self.plane.coords_to_point(-1, -1),
self.plane.coords_to_point(1, 1),
)
box.replace(line, stretch = True)
self.play(ShowCreation(box))
self.wait()
def label_corner_coordinates(self):
corner_dots = VGroup()
coords_group = VGroup()
for x, y in it.product(*[[1, -1]]*2):
point = self.plane.coords_to_point(x, y)
dot = Dot(point, color = WHITE)
coords = TexMobject("(%d, %d)"%(x, y))
coords.add_background_rectangle()
coords.next_to(point, point, SMALL_BUFF)
corner_dots.add(dot)
coords_group.add(coords)
self.play(
ShowCreation(dot),
Write(coords, run_time = 1)
)
self.add_foreground_mobjects(coords_group)
self.corner_dots = corner_dots
self.coords_group = coords_group
def add_corner_circles(self):
line = Line(
self.plane.coords_to_point(-1, 0),
self.plane.coords_to_point(1, 0),
)
circle = Circle(color = YELLOW)
circle.replace(line, dim_to_match = 0)
circles = VGroup(*[
circle.copy().move_to(dot)
for dot in self.corner_dots
])
radius = Line(ORIGIN, self.plane.coords_to_point(1, 0))
radius.set_stroke(GREY, 6)
radius.rotate(-np.pi/4)
c0_center = circles[0].get_center()
radius.shift(c0_center)
r_equals_1 = TexMobject("r = 1")
r_equals_1.add_background_rectangle()
r_equals_1.next_to(
radius.point_from_proportion(0.75),
UP+RIGHT, SMALL_BUFF
)
self.play(LaggedStartMap(ShowCreation, circles))
self.play(
ShowCreation(radius),
Write(r_equals_1)
)
for angle in -np.pi/4, -np.pi/2, 3*np.pi/4:
self.play(Rotating(
radius, about_point = c0_center,
radians = angle,
run_time = 1,
rate_func = smooth,
))
self.wait(0.5)
self.play(*list(map(FadeOut, [radius, r_equals_1])))
self.wait()
self.corner_radius = radius
self.corner_circles = circles
def add_center_circle(self):
r = np.sqrt(2) - 1
radius = Line(ORIGIN, self.plane.coords_to_point(r, 0))
radius.set_stroke(WHITE)
circle = Circle(color = GREEN)
circle.replace(
VGroup(radius, radius.copy().rotate(np.pi)),
dim_to_match = 0
)
radius.rotate(np.pi/4)
r_equals_q = TexMobject("r", "= ???")
r_equals_q[1].add_background_rectangle()
r_equals_q.next_to(radius, RIGHT, buff = -SMALL_BUFF)
self.play(GrowFromCenter(circle, run_time = 2))
self.play(circle.scale, 1.2, rate_func = wiggle)
self.play(ShowCreation(radius))
self.play(Write(r_equals_q))
self.wait(2)
self.play(FadeOut(r_equals_q[1]))
self.inner_radius = radius
self.inner_circle = circle
self.inner_r = r_equals_q[0]
def compute_radius(self):
triangle = Polygon(
ORIGIN,
self.plane.coords_to_point(1, 0),
self.plane.coords_to_point(1, 1),
fill_color = BLUE,
fill_opacity = 0.5,
stroke_width = 6,
stroke_color = WHITE,
)
bottom_one = TexMobject("1")
bottom_one.next_to(triangle.get_bottom(), UP, SMALL_BUFF)
bottom_one.shift(MED_SMALL_BUFF*RIGHT)
side_one = TexMobject("1")
side_one.next_to(triangle, RIGHT)
sqrt_1_plus_1 = TexMobject("\\sqrt", "{1^2 + 1^2}")
sqrt_2 = TexMobject("\\sqrt", "{2}")
for sqrt in sqrt_1_plus_1, sqrt_2:
sqrt.add_background_rectangle()
sqrt.next_to(ORIGIN, UP, SMALL_BUFF)
sqrt.rotate(np.pi/4)
sqrt.shift(triangle.get_center())
root_2_value = TexMobject("\\sqrt{2} \\approx 1.414")
root_2_value.to_corner(UP+RIGHT)
root_2_value.add_background_rectangle()
root_2_minus_1_value = TexMobject(
"\\sqrt{2} - 1 \\approx 0.414"
)
root_2_minus_1_value.next_to(root_2_value, DOWN)
root_2_minus_1_value.to_edge(RIGHT)
root_2_minus_1_value.add_background_rectangle()
corner_radius = self.corner_radius
c0_center = self.corner_circles[0].get_center()
corner_radius.rotate(-np.pi/2, about_point = c0_center)
rhs = TexMobject("=", "\\sqrt", "{2}", "-1")
rhs.next_to(self.inner_r, RIGHT, SMALL_BUFF, DOWN)
rhs.shift(0.5*SMALL_BUFF*DOWN)
sqrt_2_target = VGroup(*rhs[1:3])
rhs.add_background_rectangle()
self.play(
FadeIn(triangle),
Write(VGroup(bottom_one, side_one, sqrt_1_plus_1))
)
self.wait(2)
self.play(ReplacementTransform(sqrt_1_plus_1, sqrt_2))
self.play(
Write(root_2_value, run_time = 1),
*list(map(FadeOut, [bottom_one, side_one]))
)
self.wait()
self.play(ShowCreation(corner_radius))
self.play(Rotating(
corner_radius, about_point = c0_center,
run_time = 2,
rate_func = smooth
))
self.play(FadeOut(triangle), Animation(corner_radius))
self.wait()
self.play(
Write(rhs),
Transform(sqrt_2, sqrt_2_target),
)
self.play(Write(root_2_minus_1_value))
self.wait(2)
class ThreeDBoxExample(ExternallyAnimatedScene):
pass
class ThreeDCubeCorners(Scene):
def construct(self):
coordinates = VGroup(*[
TexMobject("(%d,\\, %d,\\, %d)"%(x, y, z))
for x, y, z in it.product(*3*[[1, -1]])
])
coordinates.arrange(DOWN, aligned_edge = LEFT)
name = TextMobject("Corners: ")
name.next_to(coordinates[0], LEFT)
group = VGroup(name, coordinates)
group.set_height(FRAME_HEIGHT - 1)
group.to_edge(LEFT)
self.play(Write(name, run_time = 2))
self.play(LaggedStartMap(FadeIn, coordinates, run_time = 3))
self.wait()
class ShowDistanceFormula(TeacherStudentsScene):
def construct(self):
rule = TexMobject(
"||(", "x_1", ", ", "x_2", "\\dots, ", "x_n", ")||",
"=",
"\\sqrt", "{x_1^2", " + ", "x_2^2", " +\\cdots", "x_n^2", "}"
)
rule.set_color_by_tex_to_color_map({
"x_1" : GREEN,
"x_2" : RED,
"x_n" : BLUE,
})
for part in rule.get_parts_by_tex("x_"):
if len(part) > 2:
part[1].set_color(WHITE)
rule.next_to(self.teacher, UP, LARGE_BUFF)
rule.to_edge(RIGHT)
rule.shift(UP)
rule.save_state()
rule.shift(2*DOWN)
rule.set_fill(opacity = 0)
self.play(
rule.restore,
self.teacher.change, "raise_right_hand",
)
self.wait(3)
self.student_says("Why?", student_index = 0)
self.play(self.teacher.change, "thinking")
self.wait(3)
class GeneralizePythagoreanTheoremBeyondTwoD(ThreeDScene):
def construct(self):
tex_to_color_map = {
"x" : GREEN,
"y" : RED,
"z" : BLUE,
}
rect = Rectangle(
height = 4, width = 5,
fill_color = WHITE,
fill_opacity = 0.2,
)
diag = Line(
rect.get_corner(DOWN+LEFT),
rect.get_corner(UP+RIGHT),
color = YELLOW
)
bottom = Line(rect.get_left(), rect.get_right())
bottom.move_to(rect.get_bottom())
bottom.set_color(tex_to_color_map["x"])
side = Line(rect.get_bottom(), rect.get_top())
side.move_to(rect.get_right())
side.set_color(tex_to_color_map["y"])
x = TexMobject("x")
x.next_to(rect.get_bottom(), UP, SMALL_BUFF)
y = TexMobject("y")
y.next_to(rect.get_right(), LEFT, SMALL_BUFF)
hyp = TexMobject("\\sqrt", "{x", "^2 + ", "y", "^2}")
hyp.set_color_by_tex_to_color_map(tex_to_color_map)
hyp.next_to(ORIGIN, UP)
hyp.rotate(diag.get_angle())
hyp.shift(diag.get_center())
group = VGroup(rect, bottom, side, diag, x, y, hyp)
self.add(rect)
for line, tex in (bottom, x), (side, y), (diag, hyp):
self.play(
ShowCreation(line),
Write(tex, run_time = 1)
)
self.wait()
self.play(
group.rotate, 0.45*np.pi, LEFT,
group.shift, 2*DOWN
)
corner = diag.get_end()
z_line = Line(corner, corner + 3*UP)
z_line.set_color(tex_to_color_map["z"])
z = TexMobject("z")
z.set_color(tex_to_color_map["z"])
z.next_to(z_line, RIGHT)
dot = Dot(z_line.get_end())
three_d_diag = Line(diag.get_start(), z_line.get_end())
three_d_diag.set_color(MAROON_B)
self.play(
ShowCreation(z_line),
ShowCreation(dot),
Write(z, run_time = 1)
)
self.play(ShowCreation(three_d_diag))
self.wait()
full_group = VGroup(group, z_line, z, three_d_diag, dot)
self.play(Rotating(
full_group, radians = -np.pi/6,
axis = UP,
run_time = 10,
))
self.wait()
class ThreeDBoxFormulas(Scene):
def construct(self):
question = TexMobject(
"||(1, 1, 1)||", "=", "???"
)
answer = TexMobject(
"||(1, 1, 1)||", "&=", "\\sqrt{1^2 + 1^2 + 1^2}\\\\",
"&= \\sqrt{3}\\\\", "&\\approx", "1.73",
)
for mob in question, answer:
mob.to_corner(UP+LEFT)
inner_r = TexMobject(
"\\text{Inner radius}", "&=", "\\sqrt{3} - 1\\\\",
"&\\approx", "0.73"
)
inner_r.next_to(answer, DOWN, LARGE_BUFF, LEFT)
inner_r.set_color(GREEN_C)
VGroup(question, answer).shift(0.55*RIGHT)
self.play(Write(question))
self.wait(2)
self.play(ReplacementTransform(question, answer))
self.wait(2)
self.play(Write(inner_r))
self.wait(2)
class AskAboutHigherDimensions(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"What happens for \\\\ higher dimensions?"
)
self.change_student_modes(*["pondering"]*3)
self.wait(2)
self.student_thinks(
"$\\sqrt{N} - 1$",
target_mode = "happy",
student_index = 1
)
self.wait()
pi = self.students[1]
self.play(pi.change, "confused", pi.bubble)
self.wait(3)
class TenSliders(SliderScene):
CONFIG = {
"n_sliders" : 10,
"run_time": 30,
"slider_spacing" : 0.75,
"ambient_acceleration_magnitude" : 2.0,
}
def construct(self):
self.initialize_ambiant_slider_movement()
self.wait(self.run_time)
self.wind_down_ambient_movement()
class TwoDBoxWithSliders(TwoDimensionalCase):
CONFIG = {
"slider_config" : {
"include_real_estate_ticks" : True,
"tick_frequency" : 1,
"numbers_with_elongated_ticks" : [],
"tick_size" : 0.1,
"dial_color" : YELLOW,
"x_min" : -2,
"x_max" : 2,
"unit_size" : 1.5,
},
"center_point" : [1, -1],
}
def setup(self):
TwoDimensionalCase.setup(self)
##Correct from previous setup
self.remove(self.equation)
self.sliders.shift(RIGHT)
VGroup(*self.get_top_level_mobjects()).shift(RIGHT)
x_slider = self.sliders[0]
for number in x_slider.numbers:
value = int(number.get_tex_string())
number.next_to(
x_slider.number_to_point(value),
LEFT, MED_SMALL_BUFF
)
self.plane.axes.set_color(BLUE)
##Add box material
corner_circles = VGroup(*[
self.circle.copy().move_to(
self.plane.coords_to_point(*coords)
).set_color(GREY)
for coords in ((1, 1), (-1, 1), (-1, -1))
])
line = Line(
self.plane.coords_to_point(-1, -1),
self.plane.coords_to_point(1, 1),
)
box = Square(color = RED)
box.replace(line, stretch = True)
self.add(box, corner_circles)
self.box = box
self.corner_circles = corner_circles
def construct(self):
self.ask_about_off_center_circle()
self.recenter_circle()
self.write_x_and_y_real_estate()
self.swap_with_top_right_circle()
self.show_center_circle()
self.describe_tangent_point()
self.perterb_point()
self.wander_on_inner_circle()
self.ask_about_inner_real_estate()
def ask_about_off_center_circle(self):
question = TextMobject("Off-center circles?")
question.next_to(self.plane, UP)
self.initialize_ambiant_slider_movement()
self.play(Write(question))
self.wait(4)
self.wind_down_ambient_movement()
self.question = question
def recenter_circle(self):
original_center_point = self.center_point
self.play(
self.circle.move_to, self.plane.coords_to_point(0, 0),
Animation(self.sliders),
*[
ApplyMethod(
mob.shift,
slider.number_to_point(0)-slider.number_to_point(slider.center_value)
)
for slider in self.sliders
for mob in [slider.real_estate_ticks, slider.dial]
]
)
self.center_point = [0, 0]
for x, slider in zip(self.center_point, self.sliders):
slider.center_value = x
self.initialize_ambiant_slider_movement()
self.wait(7)
self.wind_down_ambient_movement()
self.play(
self.circle.move_to,
self.plane.coords_to_point(*original_center_point),
Animation(self.sliders),
*[
ApplyMethod(
mob.shift,
slider.number_to_point(x)-slider.number_to_point(0)
)
for x, slider in zip(original_center_point, self.sliders)
for mob in [slider.real_estate_ticks, slider.dial]
]
)
self.center_point = original_center_point
for x, slider in zip(self.center_point, self.sliders):
slider.center_value = x
self.initialize_ambiant_slider_movement()
self.wait(5)
def write_x_and_y_real_estate(self):
phrases = VGroup(
TextMobject("$x$", "real estate:", "$(x-1)^2$"),
TextMobject("$y$", "real estate:", "$(y+1)^2$"),
)
phrases.next_to(self.plane, UP)
phrases[0].set_color_by_tex("x", GREEN)
phrases[1].set_color_by_tex("y", RED)
x_brace, y_brace = [
Brace(slider.real_estate_ticks, RIGHT)
for slider in self.sliders
]
x_brace.set_color(GREEN)
y_brace.set_color(RED)
self.play(FadeOut(self.question))
self.play(
Write(phrases[0]),
GrowFromCenter(x_brace)
)
self.wait(3)
self.play(
Transform(*phrases),
Transform(x_brace, y_brace)
)
self.wait(5)
self.wind_down_ambient_movement(wait = False)
self.play(*list(map(FadeOut, [x_brace, phrases[0]])))
def swap_with_top_right_circle(self):
alt_circle = self.corner_circles[0]
slider = self.sliders[1]
self.play(
self.circle.move_to, alt_circle,
alt_circle.move_to, self.circle,
Animation(slider),
*[
ApplyMethod(
mob.shift,
slider.number_to_point(1) - slider.number_to_point(-1)
)
for mob in (slider.real_estate_ticks, slider.dial)
]
)
slider.center_value = 1
self.center_point[1] = 1
self.initialize_ambiant_slider_movement()
self.wait(3)
def show_center_circle(self):
origin = self.plane.coords_to_point(0, 0)
radius = get_norm(
self.plane.coords_to_point(np.sqrt(2)-1, 0) - origin
)
circle = Circle(radius = radius, color = GREEN)
circle.move_to(origin)
self.play(FocusOn(circle))
self.play(GrowFromCenter(circle, run_time = 2))
self.wait(3)
def describe_tangent_point(self):
target_vector = np.array([
1-np.sqrt(2)/2, 1-np.sqrt(2)/2
])
point = self.plane.coords_to_point(*target_vector)
origin = self.plane.coords_to_point(0, 0)
h_line = Line(point[1]*UP + origin[0]*RIGHT, point)
v_line = Line(point[0]*RIGHT+origin[1]*UP, point)
while get_norm(self.get_vector()-target_vector) > 0.5:
self.wait()
self.wind_down_ambient_movement(0)
self.reset_dials(target_vector)
self.play(*list(map(ShowCreation, [h_line, v_line])))
self.wait()
re_line = DashedLine(
self.sliders[0].dial.get_left() + MED_SMALL_BUFF*LEFT,
self.sliders[1].dial.get_right() + MED_SMALL_BUFF*RIGHT,
)
words = TextMobject("Evenly shared \\\\ real estate")
words.scale(0.8)
words.next_to(re_line, RIGHT)
self.play(ShowCreation(re_line))
self.play(Write(words))
self.wait()
self.evenly_shared_words = words
self.re_line = re_line
def perterb_point(self):
#Perturb dials
target_vector = np.array([
1 - np.sqrt(0.7),
1 - np.sqrt(0.3),
])
ghost_dials = VGroup(*[
slider.dial.copy()
for slider in self.sliders
])
ghost_dials.set_fill(WHITE, opacity = 0.75)
self.add_foreground_mobjects(ghost_dials)
self.reset_dials(target_vector)
self.wait()
#Comment on real estate exchange
x_words = TextMobject("Gain expensive \\\\", "real estate")
y_words = TextMobject("Give up cheap \\\\", "real estate")
VGroup(x_words, y_words).scale(0.8)
x_words.next_to(self.re_line, UP+LEFT)
x_words.shift(SMALL_BUFF*(DOWN+LEFT))
y_words.next_to(self.re_line, UP+RIGHT)
y_words.shift(MED_LARGE_BUFF*UP)
x_arrow, y_arrow = [
Arrow(
words[1].get_edge_center(vect), self.sliders[i].dial,
tip_length = 0.15,
)
for i, words, vect in zip(
(0, 1), [x_words, y_words], [RIGHT, LEFT]
)
]
self.play(
Write(x_words, run_time = 2),
ShowCreation(x_arrow)
)
self.wait()
self.play(FadeOut(self.evenly_shared_words))
self.play(
Write(y_words, run_time = 2),
ShowCreation(y_arrow)
)
self.wait(2)
#Swap perspective
word_starts = VGroup(y_words[0], x_words[0])
crosses = VGroup()
new_words = VGroup()
for w1, w2 in zip(word_starts, reversed(word_starts)):
crosses.add(Cross(w1))
w1_copy = w1.copy()
w1_copy.generate_target()
w1_copy.target.next_to(w2, UP, SMALL_BUFF)
new_words.add(w1_copy)
self.play(*[
ApplyMethod(
slider.real_estate_ticks.shift,
slider.number_to_point(0)-slider.number_to_point(1)
)
for slider in self.sliders
])
self.wait()
self.play(ShowCreation(crosses))
self.play(
LaggedStartMap(MoveToTarget, new_words),
Animation(crosses)
)
self.wait(3)
#Return to original position
target_vector = np.array(2*[1-np.sqrt(0.5)])
self.play(LaggedStartMap(FadeOut, VGroup(*[
ghost_dials,
x_words, y_words,
x_arrow, y_arrow,
crosses, new_words,
])))
self.remove_foreground_mobjects(ghost_dials)
self.reset_dials(target_vector)
self.center_point = np.zeros(2)
for x, slider in zip(self.center_point, self.sliders):
slider.center_value = x
self.set_to_vector(target_vector)
self.total_real_estate = self.get_current_total_real_estate()
self.wait(2)
def wander_on_inner_circle(self):
self.initialize_ambiant_slider_movement()
self.wait(9)
def ask_about_inner_real_estate(self):
question = TextMobject("What is \\\\ $x^2 + y^2$?")
question.next_to(self.re_line, RIGHT)
rhs = TexMobject("<0.5^2 + 0.5^2")
rhs.scale(0.8)
rhs.next_to(question, DOWN)
rhs.to_edge(RIGHT)
half_line = Line(*[
slider.number_to_point(0.5) + MED_LARGE_BUFF*vect
for slider, vect in zip(self.sliders, [LEFT, RIGHT])
])
half = TexMobject("0.5")
half.scale(self.sliders[0].number_scale_val)
half.next_to(half_line, LEFT, SMALL_BUFF)
target_vector = np.array(2*[1-np.sqrt(0.5)])
while get_norm(target_vector - self.get_vector()) > 0.5:
self.wait()
self.wind_down_ambient_movement(0)
self.reset_dials(target_vector)
self.play(Write(question))
self.wait(3)
self.play(
ShowCreation(half_line),
Write(half)
)
self.wait()
self.play(Write(rhs))
self.wait(3)
class AskWhy(TeacherStudentsScene):
def construct(self):
self.student_says(
"Wait, why?",
target_mode = "confused"
)
self.wait(3)
class MentionComparisonToZeroPointFive(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Comparing to $0.5$ will \\\\"+\
"be surprisingly useful!",
target_mode = "hooray"
)
self.change_student_modes(*["happy"]*3)
self.wait(3)
class ThreeDBoxExampleWithSliders(SliderScene):
CONFIG = {
"n_sliders" : 3,
"slider_config" : {
"x_min" : -2,
"x_max" : 2,
"unit_size" : 1.5,
},
"center_point" : np.ones(3),
}
def setup(self):
SliderScene.setup(self)
self.sliders.shift(2*RIGHT)
def construct(self):
self.initialize_ambiant_slider_movement()
self.name_corner_sphere()
self.point_out_closest_point()
self.compare_to_halfway_point()
self.reframe_as_inner_sphere_point()
self.place_bound_on_inner_real_estate()
self.comment_on_inner_sphere_smallness()
def name_corner_sphere(self):
sphere_name = TextMobject(
"""Sphere with radius 1\\\\
centered at (1, 1, 1)"""
)
sphere_name.to_corner(UP+LEFT)
arrow = Arrow(
sphere_name, VGroup(*self.sliders[0].numbers[-2:]),
color = BLUE
)
self.play(
LaggedStartMap(FadeIn, sphere_name,),
ShowCreation(arrow, rate_func = squish_rate_func(smooth, 0.7, 1)),
run_time = 3
)
self.wait(5)
self.sphere_name = sphere_name
self.arrow = arrow
def point_out_closest_point(self):
target_x = 1-np.sqrt(1./3)
target_vector = np.array(3*[target_x])
re_words = TextMobject(
"$x$, $y$ and $z$ each have \\\\",
"$\\frac{1}{3}$", "units of real estate"
)
re_words.to_corner(UP+LEFT)
re_line = DashedLine(*[
self.sliders[i].number_to_point(target_x) + MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (2, RIGHT)]
])
new_arrow = Arrow(
re_words.get_corner(DOWN+RIGHT), re_line.get_left(),
color = BLUE
)
self.wind_down_ambient_movement()
self.play(*[
ApplyMethod(slider.set_value, x)
for x, slider in zip(target_vector, self.sliders)
])
self.play(ShowCreation(re_line))
self.play(
FadeOut(self.sphere_name),
Transform(self.arrow, new_arrow),
)
self.play(LaggedStartMap(FadeIn, re_words))
self.wait(2)
self.re_words = re_words
self.re_line = re_line
def compare_to_halfway_point(self):
half_line = Line(*[
self.sliders[i].number_to_point(0.5)+MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (2, RIGHT)]
])
half_line.set_stroke(MAROON_B, 6)
half_label = TexMobject("0.5")
half_label.scale(self.sliders[0].number_scale_val)
half_label.next_to(half_line, LEFT, MED_SMALL_BUFF)
half_label.set_color(half_line.get_color())
curr_vector = self.get_vector()
target_vector = 0.5*np.ones(3)
ghost_dials = VGroup(*[
slider.dial.copy().set_fill(WHITE, 0.5)
for slider in self.sliders
])
cross = Cross(self.re_words.get_parts_by_tex("frac"))
new_re = TexMobject("(0.5)^2 = 0.25")
new_re.next_to(cross, DOWN, MED_SMALL_BUFF, LEFT)
new_re.set_color(MAROON_B)
self.play(
FadeOut(self.arrow),
Write(half_label, run_time = 1),
ShowCreation(half_line)
)
self.wait()
self.add(ghost_dials)
self.play(*[
ApplyMethod(slider.set_value, 0.5)
for slider in self.sliders
])
self.play(ShowCreation(cross))
self.play(Write(new_re))
self.wait(3)
self.play(
FadeOut(new_re),
FadeOut(cross),
*[
ApplyMethod(slider.set_value, x)
for x, slider in zip(curr_vector, self.sliders)
]
)
def reframe_as_inner_sphere_point(self):
s = self.sliders[0]
shift_vect = s.number_to_point(0)-s.number_to_point(1)
curr_vector = self.get_vector()
self.set_center_point(np.zeros(3))
self.set_to_vector(curr_vector)
self.total_real_estate = self.get_current_total_real_estate()
all_re_ticks = VGroup(*[
slider.real_estate_ticks
for slider in self.sliders
])
inner_sphere_words = TextMobject(
"Also a point on \\\\", "the inner sphere"
)
inner_sphere_words.next_to(self.re_line, RIGHT)
question = TextMobject("How much \\\\", "real estate?")
question.next_to(self.re_line, RIGHT, MED_LARGE_BUFF)
self.play(
Animation(self.sliders),
FadeOut(self.re_words),
LaggedStartMap(
ApplyMethod, all_re_ticks,
lambda m : (m.shift, shift_vect)
)
)
self.initialize_ambiant_slider_movement()
self.play(Write(inner_sphere_words))
self.wait(5)
self.wind_down_ambient_movement(0)
self.play(*[
ApplyMethod(slider.set_value, x)
for slider, x in zip(self.sliders, curr_vector)
])
self.play(ReplacementTransform(
inner_sphere_words, question
))
self.wait(2)
self.re_question = question
def place_bound_on_inner_real_estate(self):
bound = TexMobject(
"&< 3(0.5)^2 ",
"= 0.75"
)
bound.next_to(self.re_question, DOWN)
bound.to_edge(RIGHT)
self.play(Write(bound))
self.wait(2)
def comment_on_inner_sphere_smallness(self):
self.initialize_ambiant_slider_movement()
self.wait(15)
class Rotating3DCornerSphere(ExternallyAnimatedScene):
pass
class FourDBoxExampleWithSliders(ThreeDBoxExampleWithSliders):
CONFIG = {
"n_sliders" : 4,
"center_point" : np.ones(4),
}
def construct(self):
self.list_corner_coordinates()
self.show_16_corner_spheres()
self.show_closest_point()
self.show_real_estate_at_closest_point()
self.reframe_as_inner_sphere_point()
self.compute_inner_radius_numerically()
self.inner_sphere_touches_box()
def list_corner_coordinates(self):
title = TextMobject(
"$2 \\!\\times\\! 2 \\!\\times\\! 2 \\!\\times\\! 2$ box vertices:"
)
title.shift(FRAME_X_RADIUS*LEFT/2)
title.to_edge(UP)
coordinates = list(it.product(*4*[[1, -1]]))
coordinate_mobs = VGroup(*[
TexMobject("(%d, %d, %d, %d)"%tup)
for tup in coordinates
])
coordinate_mobs.arrange(DOWN, aligned_edge = LEFT)
coordinate_mobs.scale(0.8)
left_column = VGroup(*coordinate_mobs[:8])
right_column = VGroup(*coordinate_mobs[8:])
right_column.next_to(left_column, RIGHT)
coordinate_mobs.next_to(title, DOWN)
self.play(Write(title))
self.play(LaggedStartMap(FadeIn, coordinate_mobs))
self.wait()
self.coordinate_mobs = coordinate_mobs
self.coordinates = coordinates
self.box_vertices_title = title
def show_16_corner_spheres(self):
sphere_words = VGroup(TextMobject("Sphere centered at"))
sphere_words.scale(0.8)
sphere_words.next_to(self.sliders, RIGHT)
sphere_words.shift(2*UP)
self.add(sphere_words)
pairs = list(zip(self.coordinate_mobs, self.coordinates))
for coord_mob, coords in pairs[1:] + [pairs[0]]:
coord_mob.set_color(GREEN)
coord_mob_copy = coord_mob.copy()
coord_mob_copy.next_to(sphere_words, DOWN)
for slider, x in zip(self.sliders, coords):
point = slider.number_to_point(x)
slider.real_estate_ticks.move_to(point)
slider.dial.move_to(point)
self.sliders[0].dial.move_to(
self.sliders[0].number_to_point(coords[0]+1)
)
self.add(coord_mob_copy)
self.wait()
self.remove(coord_mob_copy)
coord_mob.set_color(WHITE)
self.add(coord_mob_copy)
sphere_words.add(coord_mob_copy)
self.sphere_words = sphere_words
self.play(
self.sliders.center,
sphere_words.shift, LEFT,
*list(map(FadeOut, [
self.coordinate_mobs, self.box_vertices_title
]))
)
self.initialize_ambiant_slider_movement()
self.wait(4)
def show_closest_point(self):
target_vector = 0.5*np.ones(4)
re_line = DashedLine(*[
self.sliders[i].number_to_point(0.5)+MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (-1, RIGHT)]
])
half_label = TexMobject("0.5")
half_label.scale(self.sliders[0].number_scale_val)
half_label.next_to(re_line, LEFT, MED_SMALL_BUFF)
half_label.set_color(MAROON_B)
self.wind_down_ambient_movement()
self.play(*[
ApplyMethod(slider.set_value, x)
for x, slider in zip(target_vector, self.sliders)
])
self.play(ShowCreation(re_line))
self.play(Write(half_label))
self.wait(2)
self.re_line = re_line
self.half_label = half_label
def show_real_estate_at_closest_point(self):
words = TextMobject("Total real estate:")
value = TexMobject("4(0.5)^2 = 4(0.25) = 1")
value.next_to(words, DOWN)
re_words = VGroup(words, value)
re_words.scale(0.8)
re_words.next_to(self.sphere_words, DOWN, MED_LARGE_BUFF)
re_rects = VGroup()
for slider in self.sliders:
rect = Rectangle(
width = 2*slider.tick_size,
height = 0.5*slider.unit_size,
stroke_width = 0,
fill_color = MAROON_B,
fill_opacity = 0.75,
)
rect.move_to(slider.number_to_point(0.75))
re_rects.add(rect)
self.play(FadeIn(re_words))
self.play(LaggedStartMap(DrawBorderThenFill, re_rects, run_time = 3))
self.wait(2)
self.re_words = re_words
self.re_rects = re_rects
def reframe_as_inner_sphere_point(self):
sphere_words = self.sphere_words
sphere_words.generate_target()
sphere_words.target.shift(2*DOWN)
old_coords = sphere_words.target[1]
new_coords = TexMobject("(0, 0, 0, 0)")
new_coords.replace(old_coords, dim_to_match = 1)
new_coords.set_color(old_coords.get_color())
Transform(old_coords, new_coords).update(1)
self.play(Animation(self.sliders), *[
ApplyMethod(
s.real_estate_ticks.move_to, s.number_to_point(0),
run_time = 2,
rate_func = squish_rate_func(smooth, a, a+0.5)
)
for s, a in zip(self.sliders, np.linspace(0, 0.5, 4))
])
self.play(
MoveToTarget(sphere_words),
self.re_words.next_to, sphere_words.target, UP, MED_LARGE_BUFF,
path_arc = np.pi
)
self.wait(2)
re_shift_vect = 0.5*self.sliders[0].unit_size*DOWN
self.play(LaggedStartMap(
ApplyMethod, self.re_rects,
lambda m : (m.shift, re_shift_vect),
path_arc = np.pi
))
self.wait()
re_words_rect = SurroundingRectangle(self.re_words)
self.play(ShowCreation(re_words_rect))
self.wait()
self.play(FadeOut(re_words_rect))
self.wait()
self.set_center_point(np.zeros(4))
self.initialize_ambiant_slider_movement()
self.wait(4)
def compute_inner_radius_numerically(self):
computation = TexMobject(
"R_\\text{Inner}",
"&= ||(1, 1, 1, 1)|| - 1 \\\\",
# "&= \\sqrt{1^2 + 1^2 + 1^2 + 1^2} - 1 \\\\",
"&= \\sqrt{4} - 1 \\\\",
"&= 1"
)
computation.scale(0.8)
computation.to_corner(UP+LEFT)
computation.shift(DOWN)
brace = Brace(VGroup(*computation[1][1:-2]), UP)
brace_text = brace.get_text("Distance to corner")
brace_text.scale(0.8, about_point = brace_text.get_bottom())
VGroup(brace, brace_text).set_color(RED)
self.play(LaggedStartMap(FadeIn, computation, run_time = 3))
self.play(GrowFromCenter(brace))
self.play(Write(brace_text, run_time = 2))
self.wait(16)
computation.add(brace, brace_text)
self.computation = computation
def inner_sphere_touches_box(self):
touching_words = TextMobject(
"This point touches\\\\",
"the $2 \\!\\times\\! 2 \\!\\times\\! 2 \\!\\times\\! 2$ box!"
)
touching_words.to_corner(UP+LEFT)
arrow = Arrow(MED_SMALL_BUFF*DOWN, 3*RIGHT+DOWN)
arrow.set_color(BLUE)
arrow.shift(touching_words.get_bottom())
self.wind_down_ambient_movement(wait = False)
self.play(FadeOut(self.computation))
self.reset_dials([1])
self.play(Write(touching_words))
self.play(ShowCreation(arrow))
self.wait(2)
class TwoDInnerSphereTouchingBox(TwoDBoxWithSliders, PiCreatureScene):
def setup(self):
TwoDBoxWithSliders.setup(self)
PiCreatureScene.setup(self)
self.remove(self.sliders)
self.remove(self.dot)
self.circle.set_color(GREY)
self.randy.next_to(self.plane, RIGHT, LARGE_BUFF, DOWN)
def construct(self):
little_inner_circle, big_inner_circle = [
Circle(
radius = radius*self.plane.x_unit_size,
color = GREEN
).move_to(self.plane.coords_to_point(0, 0))
for radius in (np.sqrt(2)-1, 1)
]
randy = self.randy
tangency_points = VGroup(*[
Dot(self.plane.coords_to_point(x, y))
for x, y in [(1, 0), (0, 1), (-1, 0), (0, -1)]
])
tangency_points.set_fill(YELLOW, 0.5)
self.play(
ShowCreation(little_inner_circle),
randy.change, "pondering", little_inner_circle
)
self.wait()
self.play(
ReplacementTransform(
little_inner_circle.copy(), big_inner_circle
),
little_inner_circle.fade,
randy.change, "confused"
)
big_inner_circle.save_state()
self.play(big_inner_circle.move_to, self.circle)
self.play(big_inner_circle.restore)
self.wait()
self.play(LaggedStartMap(
DrawBorderThenFill, tangency_points,
rate_func = double_smooth
))
self.play(randy.change, "maybe")
self.play(randy.look_at, self.circle)
self.wait()
self.play(randy.look_at, little_inner_circle)
self.wait()
####
def create_pi_creature(self):
self.randy = Randolph().flip()
return self.randy
class FiveDBoxExampleWithSliders(FourDBoxExampleWithSliders):
CONFIG = {
"n_sliders" : 5,
"center_point" : np.ones(5),
}
def setup(self):
FourDBoxExampleWithSliders.setup(self)
self.sliders.center()
def construct(self):
self.show_32_corner_spheres()
self.show_closest_point()
self.show_halfway_point()
self.reframe_as_inner_sphere_point()
self.compute_radius()
self.poke_out_of_box()
def show_32_corner_spheres(self):
sphere_words = VGroup(TextMobject("Sphere centered at"))
sphere_words.next_to(self.sliders, RIGHT, MED_LARGE_BUFF)
sphere_words.shift(2.5*UP)
self.add(sphere_words)
n_sphere_words = TextMobject("32 corner spheres")
n_sphere_words.to_edge(LEFT)
n_sphere_words.shift(2*UP)
self.add(n_sphere_words)
for coords in it.product(*5*[[-1, 1]]):
s = str(tuple(coords))
s = s.replace("1", "+1")
s = s.replace("-+1", "-1")
coords_mob = TexMobject(s)
coords_mob.set_color(GREEN)
coords_mob.next_to(sphere_words, DOWN)
for slider, x in zip(self.sliders, coords):
for mob in slider.real_estate_ticks, slider.dial:
mob.move_to(slider.number_to_point(x))
self.sliders[0].dial.move_to(
self.sliders[0].number_to_point(coords[0]+1)
)
self.add(coords_mob)
self.wait(0.25)
self.remove(coords_mob)
self.add(coords_mob)
sphere_words.add(coords_mob)
self.sphere_words = sphere_words
self.initialize_ambiant_slider_movement()
self.play(FadeOut(n_sphere_words))
self.wait(3)
def show_closest_point(self):
target_x = 1-np.sqrt(0.2)
re_line = DashedLine(*[
self.sliders[i].number_to_point(target_x)+MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (-1, RIGHT)]
])
re_words = TextMobject(
"$0.2$", "units of real \\\\ estate each"
)
re_words.next_to(self.sphere_words, DOWN, MED_LARGE_BUFF)
re_rects = VGroup()
for slider in self.sliders:
rect = Rectangle(
width = 2*slider.tick_size,
height = (1-target_x)*slider.unit_size,
stroke_width = 0,
fill_color = GREEN,
fill_opacity = 0.75,
)
rect.move_to(slider.number_to_point(1), UP)
re_rects.add(rect)
self.wind_down_ambient_movement()
self.reset_dials(5*[target_x])
self.play(
ShowCreation(re_line),
Write(re_words, run_time = 2)
)
self.play(LaggedStartMap(
DrawBorderThenFill, re_rects,
rate_func = double_smooth
))
self.wait()
self.re_rects = re_rects
self.re_words = re_words
self.re_line = re_line
def show_halfway_point(self):
half_line = Line(*[
self.sliders[i].number_to_point(0.5)+MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (-1, RIGHT)]
])
half_line.set_color(MAROON_B)
half_label = TexMobject("0.5")
half_label.scale(self.sliders[0].number_scale_val)
half_label.next_to(half_line, LEFT, MED_SMALL_BUFF)
half_label.set_color(half_line.get_color())
curr_vector = self.get_vector()
ghost_dials = VGroup(*[
slider.dial.copy().set_fill(WHITE, 0.75)
for slider in self.sliders
])
point_25 = TexMobject("0.25")
point_25.set_color(half_label.get_color())
point_25.move_to(self.re_words[0], RIGHT)
self.re_words.save_state()
self.play(
Write(half_label),
ShowCreation(half_line)
)
self.wait(2)
self.add(ghost_dials)
self.play(*[
ApplyMethod(slider.set_value, 0.5)
for slider in self.sliders
])
self.play(Transform(self.re_words[0], point_25))
self.wait(2)
self.play(*[
ApplyMethod(slider.set_value, x)
for x, slider in zip(curr_vector, self.sliders)
])
self.play(self.re_words.restore)
def reframe_as_inner_sphere_point(self):
s = self.sliders[0]
shift_vect = s.number_to_point(0)-s.number_to_point(1)
re_ticks = VGroup(*[
slider.real_estate_ticks
for slider in self.sliders
])
re_rects = self.re_rects
re_rects.generate_target()
for rect, slider in zip(re_rects.target, self.sliders):
height = slider.unit_size*(1-np.sqrt(0.2))
rect.set_height(height)
rect.move_to(slider.number_to_point(0), DOWN)
self.sphere_words.generate_target()
old_coords = self.sphere_words.target[1]
new_coords = TexMobject(str(tuple(5*[0])))
new_coords.replace(old_coords, dim_to_match = 1)
new_coords.set_color(old_coords.get_color())
Transform(old_coords, new_coords).update(1)
self.re_words.generate_target()
new_re = TexMobject("0.31")
new_re.set_color(GREEN)
old_re = self.re_words.target[0]
new_re.move_to(old_re, RIGHT)
Transform(old_re, new_re).update(1)
self.play(
Animation(self.sliders),
LaggedStartMap(
ApplyMethod, re_ticks,
lambda m : (m.shift, shift_vect),
path_arc = np.pi
),
MoveToTarget(self.sphere_words),
)
self.play(
MoveToTarget(
re_rects,
run_time = 2,
lag_ratio = 0.5,
path_arc = np.pi
),
MoveToTarget(self.re_words),
)
self.wait(2)
self.set_center_point(np.zeros(5))
self.total_real_estate = (np.sqrt(5)-1)**2
self.initialize_ambiant_slider_movement()
self.wait(12)
def compute_radius(self):
computation = TexMobject(
"R_{\\text{inner}} &= \\sqrt{5}-1 \\\\",
"&\\approx 1.24"
)
computation.to_corner(UP+LEFT)
self.play(Write(computation, run_time = 2))
self.wait(12)
def poke_out_of_box(self):
self.wind_down_ambient_movement(0)
self.reset_dials([np.sqrt(5)-1])
words = TextMobject("Poking outside \\\\ the box!")
words.to_edge(LEFT)
words.set_color(RED)
arrow = Arrow(
words.get_top(),
self.sliders[0].dial,
path_arc = -np.pi/3,
color = words.get_color()
)
self.play(
ShowCreation(arrow),
Write(words)
)
self.wait(2)
class SkipAheadTo10(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Let's skip ahead \\\\ to 10 dimensions",
target_mode = "hooray"
)
self.change_student_modes(
"pleading", "confused", "horrified"
)
self.wait(3)
class TenDBoxExampleWithSliders(FiveDBoxExampleWithSliders):
CONFIG = {
"n_sliders" : 10,
"center_point" : np.ones(10),
"ambient_velocity_magnitude" : 2.0,
"ambient_acceleration_magnitude" : 3.0,
}
def setup(self):
FourDBoxExampleWithSliders.setup(self)
self.sliders.to_edge(RIGHT)
def construct(self):
self.initial_wandering()
self.show_closest_point()
self.reframe_as_inner_sphere_point()
self.compute_inner_radius_numerically()
self.wander_on_inner_sphere()
self.poke_outside_outer_box()
def initial_wandering(self):
self.initialize_ambiant_slider_movement()
self.wait(9)
def show_closest_point(self):
target_x = 1-np.sqrt(1./self.n_sliders)
re_line = DashedLine(*[
self.sliders[i].number_to_point(target_x)+MED_SMALL_BUFF*vect
for i, vect in [(0, LEFT), (-1, RIGHT)]
])
re_rects = VGroup()
for slider in self.sliders:
rect = Rectangle(
width = 2*slider.tick_size,
height = (1-target_x)*slider.unit_size,
stroke_width = 0,
fill_color = GREEN,
fill_opacity = 0.75,
)
rect.move_to(slider.number_to_point(1), UP)
re_rects.add(rect)
self.wind_down_ambient_movement()
self.reset_dials(self.n_sliders*[target_x])
self.play(ShowCreation(re_line))
self.play(LaggedStartMap(
DrawBorderThenFill, re_rects,
rate_func = double_smooth
))
self.wait(2)
self.re_line = re_line
self.re_rects = re_rects
def reframe_as_inner_sphere_point(self):
s = self.sliders[0]
shift_vect = s.number_to_point(0)-s.number_to_point(1)
re_ticks = VGroup(*[
slider.real_estate_ticks
for slider in self.sliders
])
re_rects = self.re_rects
re_rects.generate_target()
for rect, slider in zip(re_rects.target, self.sliders):
height = slider.unit_size*(1-np.sqrt(1./self.n_sliders))
rect.stretch_to_fit_height(height)
rect.move_to(slider.number_to_point(0), DOWN)
self.play(
Animation(self.sliders),
LaggedStartMap(
ApplyMethod, re_ticks,
lambda m : (m.shift, shift_vect),
path_arc = np.pi
),
)
self.play(
MoveToTarget(
re_rects,
run_time = 2,
lag_ratio = 0.5,
path_arc = np.pi
),
)
self.wait(2)
self.set_center_point(np.zeros(self.n_sliders))
self.total_real_estate = (np.sqrt(self.n_sliders)-1)**2
self.initialize_ambiant_slider_movement()
self.wait(5)
def compute_inner_radius_numerically(self):
computation = TexMobject(
"R_{\\text{inner}} &= \\sqrt{10}-1 \\\\",
"&\\approx 2.16"
)
computation.to_corner(UP+LEFT)
self.play(Write(computation, run_time = 2))
def wander_on_inner_sphere(self):
self.wait(10)
def poke_outside_outer_box(self):
self.wind_down_ambient_movement()
self.reset_dials([np.sqrt(10)-1])
words = TextMobject(
"Outside the \\emph{outer} \\\\",
"bounding box!"
)
words.to_edge(LEFT)
words.set_color(RED)
arrow = Arrow(
words.get_top(),
self.sliders[0].dial,
path_arc = -np.pi/3,
color = words.get_color()
)
self.play(
Write(words, run_time = 2),
ShowCreation(arrow)
)
self.wait(3)
class TwoDOuterBox(TwoDInnerSphereTouchingBox):
def construct(self):
words = TextMobject("$4 \\!\\times\\! 4$ outer bounding box")
words.next_to(self.plane, UP)
words.set_color(MAROON_B)
line = Line(
self.plane.coords_to_point(-2, -2),
self.plane.coords_to_point(2, 2),
)
box = Square(color = words.get_color())
box.replace(line, stretch = True)
box.set_stroke(width = 8)
self.play(
Write(words),
ShowCreation(box),
self.randy.change, "pondering",
)
self.wait(3)
self.outer_box = box
class ThreeDOuterBoundingBox(ExternallyAnimatedScene):
pass
class ThreeDOuterBoundingBoxWords(Scene):
def construct(self):
words = TextMobject(
"$4 \\!\\times\\! 4\\!\\times\\! 4$ outer\\\\",
"bounding box"
)
words.set_width(FRAME_WIDTH-1)
words.to_edge(DOWN)
words.set_color(MAROON_B)
self.play(Write(words))
self.wait(4)
class FaceDistanceDoesntDependOnDimension(TwoDOuterBox):
def construct(self):
self.force_skipping()
TwoDOuterBox.construct(self)
self.randy.change("confused")
self.revert_to_original_skipping_status()
line = Line(
self.plane.coords_to_point(0, 0),
self.outer_box.get_right(),
buff = 0,
stroke_width = 6,
color = YELLOW
)
length_words = TextMobject("Always 2, in all dimensions")
length_words.next_to(self.plane, RIGHT, MED_LARGE_BUFF, UP)
arrow = Arrow(length_words[4].get_bottom(), line.get_center())
self.play(ShowCreation(line))
self.play(
Write(length_words),
ShowCreation(arrow)
)
self.play(self.randy.change, "thinking")
self.wait(3)
class TenDCornerIsVeryFarAway(TenDBoxExampleWithSliders):
CONFIG = {
"center_point" : np.zeros(10)
}
def construct(self):
self.show_re_rects()
def show_re_rects(self):
re_rects = VGroup()
for slider in self.sliders:
rect = Rectangle(
width = 2*slider.tick_size,
height = slider.unit_size,
stroke_width = 0,
fill_color = GREEN,
fill_opacity = 0.75,
)
rect.move_to(slider.number_to_point(0), DOWN)
re_rects.add(rect)
rect.save_state()
rect.stretch_to_fit_height(0)
rect.move_to(rect.saved_state, DOWN)
self.set_to_vector(np.zeros(10))
self.play(
LaggedStartMap(
ApplyMethod, re_rects,
lambda m : (m.restore,),
lag_ratio = 0.3,
),
LaggedStartMap(
ApplyMethod, self.sliders,
lambda m : (m.set_value, 1),
lag_ratio = 0.3,
),
run_time = 10,
)
self.wait()
class InnerRadiusIsUnbounded(TeacherStudentsScene):
def construct(self):
self.teacher_says("Inner radius \\\\ is unbounded")
self.change_student_modes(*["erm"]*3)
self.wait(3)
class ProportionOfSphereInBox(GraphScene):
CONFIG = {
"x_axis_label" : "Dimension",
"y_axis_label" : "",
"y_max" : 1.5,
"y_min" : 0,
"y_tick_frequency" : 0.25,
"y_labeled_nums" : np.linspace(0.25, 1, 4),
"x_min" : 0,
"x_max" : 50,
"x_tick_frequency" : 5,
"x_labeled_nums" : list(range(10, 50, 10)),
"num_graph_anchor_points" : 100,
}
def construct(self):
self.setup_axes()
title = TextMobject(
"Proportion of inner sphere \\\\ inside box"
)
title.next_to(self.y_axis, RIGHT, MED_SMALL_BUFF, UP)
self.add(title)
graph = self.get_graph(lambda x : np.exp(0.1*(9-x)))
max_y = self.coords_to_point(0, 1)[1]
too_high = graph.points[:,1] > max_y
graph.points[too_high, 1] = max_y
footnote = TextMobject("""
\\begin{flushleft}
*I may or may not have used an easy-to-compute \\\\
but not-totally-accurate curve here, due to \\\\
the surprising difficulty in computing the real \\\\
proportion :)
\\end{flushleft}
""",)
footnote.scale(0.75)
footnote.next_to(
graph.point_from_proportion(0.3),
UP+RIGHT, SMALL_BUFF
)
footnote.set_color(YELLOW)
self.play(ShowCreation(graph, run_time = 5, rate_func=linear))
self.wait()
self.add(footnote)
self.wait(0.25)
class ShowingToFriend(PiCreatureScene, SliderScene):
CONFIG = {
"n_sliders" : 10,
"ambient_acceleration_magnitude" : 3.0,
"seconds_to_blink" : 4,
}
def setup(self):
PiCreatureScene.setup(self)
SliderScene.setup(self)
self.sliders.scale(0.75)
self.sliders.next_to(
self.morty.get_corner(UP+LEFT), UP, MED_LARGE_BUFF
)
self.initialize_ambiant_slider_movement()
def construct(self):
morty, randy = self.morty, self.randy
self.play(morty.change, "raise_right_hand", self.sliders)
self.play(randy.change, "happy", self.sliders)
self.wait(7)
self.play(randy.change, "skeptical", morty.eyes)
self.wait(3)
self.play(randy.change, "thinking", self.sliders)
self.wait(6)
###
def create_pi_creatures(self):
self.morty = Mortimer()
self.morty.to_edge(DOWN).shift(4*RIGHT)
self.randy = Randolph()
self.randy.to_edge(DOWN).shift(4*LEFT)
return VGroup(self.morty, self.randy)
def non_blink_wait(self, time = 1):
SliderScene.wait(self, time)
class QuestionsFromStudents(TeacherStudentsScene):
def construct(self):
self.student_says(
"Is 10-dimensional \\\\ space real?",
target_mode = "sassy",
run_time = 2,
)
self.wait()
self.teacher_says(
"No less real \\\\ than reals",
target_mode = "shruggie",
content_introduction_class = FadeIn,
)
self.wait(2)
self.student_says(
"How do you think \\\\ about volume?",
student_index = 0,
content_introduction_class = FadeIn,
)
self.wait()
self.student_says(
"How do cubes work?",
student_index = 2,
run_time = 2,
)
self.wait(2)
class FunHighDSpherePhenomena(Scene):
def construct(self):
title = TextMobject(
"Fun high-D sphere phenomena"
)
title.to_edge(UP)
title.set_color(BLUE)
h_line = Line(LEFT, RIGHT).scale(5)
h_line.next_to(title, DOWN)
self.add(title, h_line)
items = VGroup(*list(map(TextMobject, [
"$\\cdot$ Most volume is near the equator",
"$\\cdot$ Most volume is near the surface",
"$\\cdot$ Sphere packing in 8 dimensions",
"$\\cdot$ Sphere packing in 24 dimensions",
])))
items.arrange(
DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT
)
items.next_to(h_line, DOWN)
for item in items:
self.play(LaggedStartMap(FadeIn, item, run_time = 2))
self.wait()
class TODOBugOnSurface(TODOStub):
CONFIG = {
"message" : "Bug on surface"
}
class CoordinateFree(PiCreatureScene):
def construct(self):
plane = NumberPlane(x_radius = 2.5, y_radius = 2.5)
plane.add_coordinates()
plane.to_corner(UP+LEFT)
self.add(plane)
circles = VGroup(*[
Circle(color = YELLOW).move_to(
plane.coords_to_point(*coords)
)
for coords in it.product(*2*[[-1, 1]])
])
inner_circle = Circle(
radius = np.sqrt(2)-1,
color = GREEN
).move_to(plane.coords_to_point(0, 0))
self.add_foreground_mobjects(circles, inner_circle)
self.play(PiCreatureSays(
self.pi_creature, "Lose the \\\\ coordinates!",
target_mode = "hooray"
))
self.play(FadeOut(plane, run_time = 2))
self.wait(3)
class Skeptic(TeacherStudentsScene, SliderScene):
def setup(self):
SliderScene.setup(self)
TeacherStudentsScene.setup(self)
self.sliders.scale(0.7)
self.sliders.next_to(self.teacher, UP, aligned_edge = LEFT)
self.sliders.to_edge(UP)
self.initialize_ambiant_slider_movement()
def construct(self):
analytic_thought = VGroup(TextMobject("No different from"))
equation = TexMobject(
"x", "^2 + ", "y", "^2 + ", "z", "^2 + ", "w", "^2 = 1"
)
variables = VGroup(*[
equation.get_part_by_tex(tex)
for tex in "xyzw"
])
slider_labels = VGroup(*[
slider.label for slider in self.sliders
])
equation.next_to(analytic_thought, DOWN)
analytic_thought.add(equation)
all_real_estate_ticks = VGroup(*it.chain(*[
slider.real_estate_ticks
for slider in self.sliders
]))
box = Square(color = RED)
box.next_to(self.sliders, LEFT)
line = Line(box.get_center(), box.get_corner(UP+RIGHT))
line.set_color(YELLOW)
self.student_says(
analytic_thought,
student_index = 0,
target_mode = "sassy",
added_anims = [self.teacher.change, "guilty"]
)
self.wait(2)
equation.remove(*variables)
self.play(ReplacementTransform(variables, slider_labels))
self.play(
self.teacher.change, "pondering", slider_labels,
RemovePiCreatureBubble(
self.students[0], target_mode = "hesitant"
),
)
self.wait(4)
bubble = self.teacher.get_bubble(
"It's much \\\\ more playful!",
bubble_class = SpeechBubble
)
bubble.resize_to_content()
VGroup(bubble, bubble.content).next_to(self.teacher, UP+LEFT)
self.play(
self.teacher.change, "hooray",
ShowCreation(bubble),
Write(bubble.content)
)
self.wait(3)
self.play(
RemovePiCreatureBubble(
self.teacher, target_mode = "raise_right_hand",
look_at_arg = self.sliders
),
*[
ApplyMethod(pi.change, "pondering")
for pi in self.students
]
)
self.play(Animation(self.sliders), LaggedStartMap(
ApplyMethod, all_real_estate_ticks,
lambda m : (m.shift, SMALL_BUFF*LEFT),
rate_func = wiggle,
lag_ratio = 0.3,
run_time = 4,
))
self.play(
ShowCreation(box),
self.teacher.change, "happy"
)
self.play(ShowCreation(line))
self.wait(3)
#####
def non_blink_wait(self, time = 1):
SliderScene.wait(self, time)
class ClipFrom4DBoxExampleTODO(TODOStub):
CONFIG = {
"message" : "Clip from 4d box example"
}
class JustBecauseYouCantVisualize(Scene):
def construct(self):
phrase = "\\raggedright "
phrase += "Just because you can't visualize\\\\ "
phrase += "something doesn't mean you can't\\\\ "
phrase += "still think about it visually."
phrase_mob = TextMobject(*phrase.split(" "))
phrase_mob.set_color_by_tex("visual", YELLOW)
phrase_mob.next_to(ORIGIN, UP)
for part in phrase_mob:
self.play(LaggedStartMap(
FadeIn, part,
run_time = 0.05*len(part)
))
self.wait(2)
class Announcements(TeacherStudentsScene):
def construct(self):
title = TextMobject("Announcements")
title.scale(1.5)
title.to_edge(UP, buff = MED_SMALL_BUFF)
h_line = Line(LEFT, RIGHT).scale(3)
h_line.next_to(title, DOWN)
self.add(title, h_line)
items = VGroup(*list(map(TextMobject, [
"$\\cdot$ Where to learn more",
"$\\cdot$ Q\\&A Followup (podcast!)",
])))
items.arrange(DOWN, aligned_edge = LEFT)
items.next_to(h_line, DOWN)
self.play(
Write(items[0], run_time = 2),
)
self.play(*[
ApplyMethod(pi.change, "hooray", items)
for pi in self.pi_creatures
])
self.play(Write(items[1], run_time = 2))
self.wait(2)
class Promotion(PiCreatureScene):
CONFIG = {
"seconds_to_blink" : 5,
}
def construct(self):
url = TextMobject("https://brilliant.org/3b1b/")
url.to_corner(UP+LEFT)
rect = Rectangle(height = 9, width = 16)
rect.set_height(5.5)
rect.next_to(url, DOWN)
rect.to_edge(LEFT)
self.play(
Write(url),
self.pi_creature.change, "raise_right_hand"
)
self.play(ShowCreation(rect))
self.wait(2)
self.change_mode("thinking")
self.wait()
self.look_at(url)
self.wait(10)
self.change_mode("happy")
self.wait(10)
self.change_mode("raise_right_hand")
self.wait(10)
self.remove(rect)
self.play(
url.next_to, self.pi_creature, UP+LEFT
)
url_rect = SurroundingRectangle(url)
self.play(ShowCreation(url_rect))
self.play(FadeOut(url_rect))
self.wait(3)
class BrilliantGeometryQuiz(ExternallyAnimatedScene):
pass
class BrilliantScrollThroughCourses(ExternallyAnimatedScene):
pass
class Podcast(TeacherStudentsScene):
def construct(self):
title = TextMobject("Podcast!")
title.scale(1.5)
title.to_edge(UP)
title.shift(FRAME_X_RADIUS*LEFT/2)
self.add(title)
q_and_a = TextMobject("Q\\&A Followup")
q_and_a.next_to(self.teacher.get_corner(UP+LEFT), UP, LARGE_BUFF)
self.play(
LaggedStartMap(
ApplyMethod, self.pi_creatures,
lambda pi : (pi.change, "hooray", title)
),
Write(title)
)
self.wait(5)
self.play(
Write(q_and_a),
self.teacher.change, "raise_right_hand",
)
self.wait(4)
class HighDPatreonThanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
"Desmos",
"Burt Humburg",
"CrypticSwarm",
"Juan Benet",
"Ali Yahya",
"William",
"Mayank M. Mehrotra",
"Lukas Biewald",
"Samantha D. Suplee",
"James Park",
"Yana Chernobilsky",
"Kaustuv DeBiswas",
"Kathryn Schmiedicke",
"Yu Jun",
"dave nicponski",
"Damion Kistler",
"Markus Persson",
"Yoni Nazarathy",
"Corey Ogburn",
"Ed Kellett",
"Joseph John Cox",
"Dan Buchoff",
"Luc Ritchie",
"Erik Sundell",
"Xueqi Li",
"David Stork",
"Tianyu Ge",
"Ted Suzman",
"Amir Fayazi",
"Linh Tran",
"Andrew Busey",
"Michael McGuffin",
"John Haley",
"Ankalagon",
"Eric Lavault",
"Tomohiro Furusawa",
"Boris Veselinovich",
"Julian Pulgarin",
"Jeff Linse",
"Cooper Jones",
"Ryan Dahl",
"Mark Govea",
"Robert Teed",
"Jason Hise",
"Meshal Alshammari",
"Bernd Sing",
"Nils Schneider",
"James Thornton",
"Mustafa Mahdi",
"Mathew Bramson",
"Jerry Ling",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Ripta Pasay",
]
}
class Thumbnail(SliderScene):
CONFIG = {
"n_sliders" : 10,
}
def construct(self):
for slider in self.sliders:
self.remove(slider.label)
slider.remove(slider.label)
vect = np.random.random(10) - 0.5
vect /= get_norm(vect)
self.set_to_vector(vect)
title = TextMobject("10D Sphere?")
title.scale(2)
title.to_edge(UP)
self.add(title)