mirror of
https://github.com/3b1b/manim.git
synced 2025-07-29 21:12:35 +08:00
Added slider objects for highD.py
This commit is contained in:
556
highD.py
556
highD.py
@ -29,8 +29,240 @@ from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject 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,
|
||||
"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(0))
|
||||
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_real_estate_ticks(
|
||||
self,
|
||||
re_per_tick = 0.05,
|
||||
colors = [BLUE, RED],
|
||||
):
|
||||
self.real_estate_ticks = VGroup(*[
|
||||
self.get_tick(u*np.sqrt(x))
|
||||
for x in np.arange(re_per_tick, 1, re_per_tick)
|
||||
for u in [-1, 1]
|
||||
])
|
||||
self.real_estate_ticks.set_stroke(width = 3)
|
||||
self.real_estate_ticks.gradient_highlight(*colors)
|
||||
self.add(self.real_estate_ticks)
|
||||
self.add(self.dial)
|
||||
return self.real_estate_ticks
|
||||
|
||||
def set_value(self, x):
|
||||
for dial, val in (self.dial, x), (self.re_dial, x**2):
|
||||
dial.move_to(self.number_to_point(val))
|
||||
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(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_submobjects(RIGHT, buff = self.slider_spacing)
|
||||
sliders[0].add_numbers()
|
||||
sliders[0].set_value(np.sqrt(self.total_real_estate))
|
||||
|
||||
self.add(sliders)
|
||||
self.sliders = sliders
|
||||
|
||||
def reset_dials(self, values, fixed_sliders = None):
|
||||
if fixed_sliders is None: fixed_sliders = []
|
||||
unspecified_sliders = [
|
||||
self.sliders[i]
|
||||
for i in range(len(self.sliders))
|
||||
if i >= len(values) or values[i] is None
|
||||
if self.sliders[i] not in fixed_sliders
|
||||
]
|
||||
for value, slider in zip(values, self.sliders):
|
||||
if value is not None:
|
||||
slider.set_value(value)
|
||||
#Readjust sliers with unspecified values that are not fixed
|
||||
real_estate_diff = self.total_real_estate - self.get_current_total_real_estate()
|
||||
for i, slider in enumerate(unspecified_sliders):
|
||||
n_remaining = len(unspecified_sliders[i:])
|
||||
d_re = real_estate_diff / n_remaining
|
||||
left_over = slider.change_real_estate(d_re)
|
||||
real_estate_diff -= (d_re - left_over)
|
||||
if real_estate_diff > 0.001:
|
||||
raise Exception("Overspecified reset")
|
||||
|
||||
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 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,
|
||||
]
|
||||
]
|
||||
self.add_foreground_mobjects(self.sliders)
|
||||
|
||||
def wind_down_ambient_movement(self, time = 1):
|
||||
self.ambient_change_end_time = 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
|
||||
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 / np.linalg.norm(target_vector)
|
||||
vect -= np.dot(vect, unit_r_vect)*unit_r_vect
|
||||
vect *= mag/np.linalg.norm(vect)
|
||||
deriv = vect
|
||||
|
||||
self.reset_dials(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 / np.linalg.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 dither(self, time = 1):
|
||||
if self.ambiently_change_sliders:
|
||||
self.play(Animation(self.sliders, run_time = time))
|
||||
else:
|
||||
self.dither(time)
|
||||
|
||||
##########
|
||||
|
||||
class MathIsATease(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph()
|
||||
@ -102,7 +334,9 @@ class CircleToPairsOfPoints(Scene):
|
||||
background_plane.highlight(GREY)
|
||||
background_plane.fade()
|
||||
circle = Circle(radius = 2, color = YELLOW)
|
||||
dot = Dot(circle.get_right(), color = LIGHT_GREY)
|
||||
|
||||
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.highlight_by_tex("x", GREEN)
|
||||
@ -110,9 +344,8 @@ class CircleToPairsOfPoints(Scene):
|
||||
equation.to_corner(UP+LEFT)
|
||||
equation.add_background_rectangle()
|
||||
|
||||
x, y = 1, 0
|
||||
coord_pair = TexMobject("(", "-%.02f"%x, ",", "-%.02f"%y, ")")
|
||||
fixed_numbers = coord_pair.get_parts_by_tex(".00")
|
||||
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)
|
||||
@ -129,18 +362,23 @@ class CircleToPairsOfPoints(Scene):
|
||||
|
||||
self.add(background_plane, plane)
|
||||
self.play(ShowCreation(circle))
|
||||
self.play(Write(equation))
|
||||
self.play(
|
||||
LaggedStart(FadeIn, coord_pair),
|
||||
FadeIn(coord_pair),
|
||||
Write(numbers, run_time = 1),
|
||||
ShowCreation(dot),
|
||||
)
|
||||
self.play(
|
||||
Write(equation),
|
||||
*[
|
||||
ReplacementTransform(
|
||||
equation.get_parts_by_tex(tex).copy(),
|
||||
number
|
||||
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,
|
||||
@ -179,7 +417,8 @@ class CircleToPairsOfPoints(Scene):
|
||||
words.get_left(), rot_equation.get_bottom(),
|
||||
path_arc = -np.pi/6
|
||||
)
|
||||
randy = Randolph().to_corner(DOWN+LEFT)
|
||||
randy = Randolph(color = GREY_BROWN)
|
||||
randy.to_corner(DOWN+LEFT)
|
||||
|
||||
self.play(
|
||||
Write(rot_equation, run_time = 2),
|
||||
@ -211,6 +450,305 @@ class CircleToPairsOfPoints(Scene):
|
||||
)
|
||||
self.dither()
|
||||
|
||||
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.dither(3)
|
||||
|
||||
class CirclesSpheresSumsSquares(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class BackAndForth(Scene):
|
||||
def construct(self):
|
||||
analytic = TextMobject("Analytic")
|
||||
analytic.shift(SPACE_WIDTH*LEFT/2)
|
||||
analytic.to_edge(UP, buff = MED_SMALL_BUFF)
|
||||
geometric = TextMobject("Geometric")
|
||||
geometric.shift(SPACE_WIDTH*RIGHT/2)
|
||||
geometric.to_edge(UP, buff = MED_SMALL_BUFF)
|
||||
h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH)
|
||||
h_line.to_edge(UP, LARGE_BUFF)
|
||||
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
||||
self.add(analytic, geometric, h_line, v_line)
|
||||
|
||||
pair = TexMobject("(", "x", ",", "y", ")")
|
||||
pair.shift(SPACE_WIDTH*LEFT/2 + SPACE_HEIGHT*UP/3)
|
||||
triplet = TexMobject("(", "x", ",", "y", ",", "z", ")")
|
||||
triplet.shift(SPACE_WIDTH*LEFT/2 + SPACE_HEIGHT*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(SPACE_WIDTH*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.dither(3)
|
||||
for tup, eq, to_draw in (pair, circle_eq, circle), (triplet, sphere_eq, VMobject()):
|
||||
for mob in tup, eq:
|
||||
mob.xyz = VGroup(*filter(
|
||||
lambda sm : sm is not None,
|
||||
map(mob.get_part_by_tex, "xyz")
|
||||
))
|
||||
self.play(
|
||||
ReplacementTransform(tup.xyz, eq.xyz),
|
||||
FadeOut(VGroup(*filter(
|
||||
lambda sm : sm not in tup.xyz, tup
|
||||
))),
|
||||
)
|
||||
self.play(
|
||||
Write(VGroup(*filter(
|
||||
lambda sm : sm not in eq.xyz, eq
|
||||
))),
|
||||
ShowCreation(to_draw)
|
||||
)
|
||||
self.dither(3)
|
||||
|
||||
class SphereForming(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
class PreviousVideos(Scene):
|
||||
def construct(self):
|
||||
titles = VGroup(*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.dither(2)
|
||||
for new_title in titles[1:]:
|
||||
self.play(Transform(title, new_title))
|
||||
self.dither(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 = 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.dither()
|
||||
for alt_tup in alt_tups:
|
||||
alt_tup.move_to(tup)
|
||||
self.play(Transform(tup, alt_tup))
|
||||
self.dither()
|
||||
self.dither()
|
||||
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.dither(5)
|
||||
self.student_says(
|
||||
"I...don't see it.",
|
||||
target_mode = "maybe",
|
||||
student_index = 0
|
||||
)
|
||||
self.dither(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 add_equation(self):
|
||||
quaternion = TexMobject(
|
||||
"\\frac{1}{2}", "+",
|
||||
"0", "\\textbf{i}", "+",
|
||||
"\\frac{\\sqrt{6}}{4}", "\\textbf{j}", "+",
|
||||
"\\frac{\\sqrt{6}}{4}", "\\textbf{k}",
|
||||
)
|
||||
quaternion.shift(SPACE_WIDTH*LEFT/2)
|
||||
equation = TexMobject(
|
||||
"\\textbf{i}", "^2", "=",
|
||||
"\\textbf{j}", "^2", "=",
|
||||
"\\textbf{k}", "^2", "=",
|
||||
"\\textbf{i}", "\\textbf{j}", "\\textbf{k}", "=",
|
||||
"-1"
|
||||
)
|
||||
equation.shift(SPACE_WIDTH*RIGHT/2)
|
||||
VGroup(quaternion, equation).to_edge(UP)
|
||||
for mob in quaternion, equation:
|
||||
mob.highlight_by_tex_to_color_map({
|
||||
"i" : RED,
|
||||
"j" : GREEN,
|
||||
"k" : BLUE,
|
||||
})
|
||||
|
||||
brace = Brace(quaternion, DOWN)
|
||||
words = brace.get_text("4 numbers")
|
||||
|
||||
self.play(
|
||||
Write(quaternion),
|
||||
Write(equation),
|
||||
GrowFromCenter(brace),
|
||||
FadeIn(words),
|
||||
run_time = 2
|
||||
)
|
||||
self.play(*[
|
||||
ApplyMethod(pi.change, "pondering", quaternion)
|
||||
for pi in self.pi_creatures
|
||||
])
|
||||
self.dither()
|
||||
self.play(FadeOut(VGroup(brace, words)))
|
||||
|
||||
|
||||
self.quaternion = quaternion
|
||||
self.equation = equation
|
||||
|
||||
def introduce_characters(self):
|
||||
titles = VGroup(*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.dither()
|
||||
|
||||
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_submobjects(RIGHT, buff = 2)
|
||||
examples.next_to(self.pi_creatures, UP, MED_LARGE_BUFF)
|
||||
labels = VGroup(*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.dither()
|
||||
self.dither()
|
||||
self.play(
|
||||
FadeOut(examples),
|
||||
VGroup(self.quaternion, self.equation).shift, 2*DOWN,
|
||||
Write(title, run_time = 2)
|
||||
)
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
pi.change, mode, self.equation,
|
||||
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.dither()
|
||||
self.play(Animation(self.quaternion))
|
||||
self.dither(2)
|
||||
|
||||
|
||||
|
||||
######
|
||||
|
||||
def create_pi_creatures(self):
|
||||
mathy = Mathematician()
|
||||
physy = PiCreature(color = PINK)
|
||||
compy = PiCreature(color = PURPLE)
|
||||
pi_creatures = VGroup(mathy, compy, physy)
|
||||
for pi in pi_creatures:
|
||||
pi.scale(0.7)
|
||||
pi_creatures.arrange_submobjects(RIGHT, buff = 3)
|
||||
pi_creatures.to_edge(DOWN, buff = LARGE_BUFF)
|
||||
return pi_creatures
|
||||
|
||||
class OfferAHybrid(SliderScene):
|
||||
def construct(self):
|
||||
slider = self.sliders[0]
|
||||
|
||||
self.initialize_ambiant_slider_movement()
|
||||
self.dither(3)
|
||||
self.play(slider.shift, 3*LEFT)
|
||||
self.dither(2)
|
||||
self.wind_down_ambient_movement()
|
||||
self.dither(2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
50
stage_animations.py
Normal file
50
stage_animations.py
Normal file
@ -0,0 +1,50 @@
|
||||
import sys
|
||||
import inspect
|
||||
import os
|
||||
import shutil
|
||||
import itertools as it
|
||||
from extract_scene import is_scene, get_module
|
||||
from constants import MOVIE_DIR, STAGED_SCENES_DIR
|
||||
|
||||
|
||||
def get_sorted_scene_names(module_name):
|
||||
module = get_module(module_name)
|
||||
line_to_scene = {}
|
||||
for name, scene_class in inspect.getmembers(module, is_scene):
|
||||
lines, line_no = inspect.getsourcelines(scene_class)
|
||||
line_to_scene[line_no] = name
|
||||
return [
|
||||
line_to_scene[line_no]
|
||||
for line_no in sorted(line_to_scene.keys())
|
||||
]
|
||||
|
||||
|
||||
|
||||
def stage_animaions(module_name):
|
||||
scene_names = get_sorted_scene_names(module_name)
|
||||
movie_dir = os.path.join(
|
||||
MOVIE_DIR, module_name.replace(".py", "")
|
||||
)
|
||||
files = os.listdir(movie_dir)
|
||||
sorted_files = []
|
||||
for scene in scene_names:
|
||||
for clip in filter(lambda f : f.startswith(scene), files):
|
||||
sorted_files.append(
|
||||
os.path.join(movie_dir, clip)
|
||||
)
|
||||
for f in os.listdir(STAGED_SCENES_DIR):
|
||||
os.remove(os.path.join(STAGED_SCENES_DIR, f))
|
||||
for f, count in zip(sorted_files, it.count()):
|
||||
symlink_name = os.path.join(
|
||||
STAGED_SCENES_DIR,
|
||||
"Scene_%03d"%count + f.split(os.sep)[-1]
|
||||
)
|
||||
os.symlink(f, symlink_name)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
raise Exception("No module given.")
|
||||
module_name = sys.argv[1]
|
||||
stage_animaions(module_name)
|
@ -196,10 +196,10 @@ class ComplexPlane(NumberPlane):
|
||||
result = VGroup()
|
||||
nudge = 0.1*(DOWN+RIGHT)
|
||||
if len(numbers) == 0:
|
||||
numbers = range(-int(self.x_radius), int(self.x_radius))
|
||||
numbers = range(-int(self.x_radius), int(self.x_radius)+1)
|
||||
numbers += [
|
||||
complex(0, y)
|
||||
for y in range(-int(self.y_radius), int(self.y_radius))
|
||||
for y in range(-int(self.y_radius), int(self.y_radius)+1)
|
||||
]
|
||||
for number in numbers:
|
||||
point = self.number_to_point(number)
|
||||
|
@ -391,7 +391,7 @@ class PictureInPictureFrame(Rectangle):
|
||||
**kwargs
|
||||
)
|
||||
self.scale_to_fit_height(height)
|
||||
|
||||
|
||||
class Cross(VGroup):
|
||||
CONFIG = {
|
||||
"stroke_color" : RED,
|
||||
|
@ -19,7 +19,10 @@ class NumberLine(VMobject):
|
||||
"numbers_to_show" : None,
|
||||
"longer_tick_multiple" : 2,
|
||||
"number_at_center" : 0,
|
||||
"propogate_style_to_family" : True
|
||||
"number_scale_val" : 0.5,
|
||||
"line_to_number_vect" : DOWN,
|
||||
"line_to_number_buff" : MED_SMALL_BUFF,
|
||||
"propogate_style_to_family" : True,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
@ -38,13 +41,17 @@ class NumberLine(VMobject):
|
||||
self.stretch(self.unit_size, 0)
|
||||
self.shift(-self.number_to_point(self.number_at_center))
|
||||
|
||||
def add_tick(self, x, size):
|
||||
self.tick_marks.add(Line(
|
||||
x*RIGHT+size*DOWN,
|
||||
x*RIGHT+size*UP,
|
||||
))
|
||||
def add_tick(self, x, size = None):
|
||||
self.tick_marks.add(self.get_tick(x, size))
|
||||
return self
|
||||
|
||||
def get_tick(self, x, size = None):
|
||||
if size is None: size = self.tick_size
|
||||
result = Line(size*DOWN, size*UP)
|
||||
result.rotate(self.main_line.get_angle())
|
||||
result.move_to(self.number_to_point(x))
|
||||
return result
|
||||
|
||||
def get_tick_marks(self):
|
||||
return self.tick_marks
|
||||
|
||||
@ -77,10 +84,7 @@ class NumberLine(VMobject):
|
||||
def default_numbers_to_display(self):
|
||||
if self.numbers_to_show is not None:
|
||||
return self.numbers_to_show
|
||||
return np.arange(self.leftmost_tick, self.x_max, 1)
|
||||
|
||||
def get_vertical_number_offset(self, direction = DOWN):
|
||||
return 4*direction*self.tick_size
|
||||
return np.arange(int(self.leftmost_tick), int(self.x_max)+1)
|
||||
|
||||
def get_number_mobjects(self, *numbers, **kwargs):
|
||||
#TODO, handle decimals
|
||||
@ -91,10 +95,11 @@ class NumberLine(VMobject):
|
||||
result = VGroup()
|
||||
for number in numbers:
|
||||
mob = TexMobject(str(number))
|
||||
mob.scale_to_fit_height(3*self.tick_size)
|
||||
mob.shift(
|
||||
mob.scale(self.number_scale_val)
|
||||
mob.next_to(
|
||||
self.number_to_point(number),
|
||||
self.get_vertical_number_offset(**kwargs)
|
||||
self.line_to_number_vect,
|
||||
self.line_to_number_buff,
|
||||
)
|
||||
result.add(mob)
|
||||
return result
|
||||
|
@ -367,8 +367,6 @@ class BarChart(VGroup):
|
||||
return self.deepcopy()
|
||||
|
||||
|
||||
|
||||
|
||||
### Cards ###
|
||||
|
||||
class DeckOfCards(VGroup):
|
||||
|
Reference in New Issue
Block a user