mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 22:47:45 +00:00
Merge branch 'master' of github.com:3b1b/manim into alt-calc
This commit is contained in:
commit
57d594e565
57 changed files with 3899 additions and 2990 deletions
|
|
@ -118,9 +118,6 @@ class StartingCalc101(PiCreatureScene):
|
|||
"{f(x + \\Delta x) - f(x) \\over \\Delta x}",
|
||||
tex_to_color_map={"\\Delta x": BLUE}
|
||||
)
|
||||
self.add(deriv_equation)
|
||||
equations = VGroup(deriv_equation)
|
||||
|
||||
title = TextMobject("Calculus 101")
|
||||
title.to_edge(UP)
|
||||
h_line = Line(LEFT, RIGHT)
|
||||
|
|
@ -134,7 +131,6 @@ class StartingCalc101(PiCreatureScene):
|
|||
|
||||
class StandardDerivativeVisual(GraphScene):
|
||||
CONFIG = {
|
||||
# "y_axis_label": "$f(x)$",
|
||||
"y_max": 8,
|
||||
"y_axis_height": 5,
|
||||
}
|
||||
|
|
|
|||
0
active_projects/eop/chapter0/__init__.py
Normal file
0
active_projects/eop/chapter0/__init__.py
Normal file
82
active_projects/eop/chapter0/intro.py
Normal file
82
active_projects/eop/chapter0/intro.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_series()
|
||||
self.show_examples()
|
||||
|
||||
def show_series(self):
|
||||
series = VideoSeries(num_videos = 11)
|
||||
series.to_edge(UP)
|
||||
this_video = series[0]
|
||||
this_video.set_color(YELLOW)
|
||||
this_video.save_state()
|
||||
this_video.set_fill(opacity = 0)
|
||||
this_video.center()
|
||||
this_video.scale_to_fit_height(FRAME_HEIGHT)
|
||||
self.this_video = this_video
|
||||
|
||||
|
||||
words = TextMobject(
|
||||
"Welcome to \\\\",
|
||||
"Essence of Probability"
|
||||
)
|
||||
words.set_color_by_tex("Essence of Probability", YELLOW)
|
||||
|
||||
self.teacher.change_mode("happy")
|
||||
self.play(
|
||||
FadeIn(
|
||||
series,
|
||||
submobject_mode = "lagged_start",
|
||||
run_time = 2
|
||||
),
|
||||
Blink(self.get_teacher())
|
||||
)
|
||||
self.teacher_says(words, target_mode = "hooray")
|
||||
self.change_student_modes(
|
||||
*["hooray"]*3,
|
||||
look_at_arg = series[1].get_left(),
|
||||
added_anims = [
|
||||
ApplyMethod(this_video.restore, run_time = 3),
|
||||
]
|
||||
)
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
video.shift, 0.5*video.get_height()*DOWN,
|
||||
run_time = 3,
|
||||
rate_func = squish_rate_func(
|
||||
there_and_back, alpha, alpha+0.3
|
||||
)
|
||||
)
|
||||
for video, alpha in zip(series, np.linspace(0, 0.7, len(series)))
|
||||
]+[
|
||||
Animation(self.teacher.bubble),
|
||||
Animation(self.teacher.bubble.content),
|
||||
])
|
||||
|
||||
self.play(
|
||||
FadeOut(self.teacher.bubble),
|
||||
FadeOut(self.teacher.bubble.content),
|
||||
self.get_teacher().change_mode, "raise_right_hand",
|
||||
*[
|
||||
ApplyMethod(pi.change_mode, "pondering")
|
||||
for pi in self.get_students()
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.series = series
|
||||
|
||||
|
||||
def show_examples(self):
|
||||
|
||||
self.wait(10)
|
||||
# put examples here in video editor
|
||||
File diff suppressed because it is too large
Load diff
0
active_projects/eop/chapter1/__init__.py
Normal file
0
active_projects/eop/chapter1/__init__.py
Normal file
62
active_projects/eop/chapter1/all_sequences.py
Normal file
62
active_projects/eop/chapter1/all_sequences.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class ShuffleThroughAllSequences(Scene):
|
||||
CONFIG = {
|
||||
"nb_coins" : 14,
|
||||
"run_time" : 5,
|
||||
"fps" : int(1.0/PRODUCTION_QUALITY_FRAME_DURATION),
|
||||
"coin_size" : 0.5,
|
||||
"coin_spacing" : 0.65
|
||||
}
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
nb_frames = self.run_time * self.fps
|
||||
nb_relevant_coins = int(np.log2(nb_frames)) + 1
|
||||
print "relevant coins:", nb_relevant_coins
|
||||
nb_idle_coins = self.nb_coins - nb_relevant_coins
|
||||
|
||||
idle_heads = CoinSequence(nb_idle_coins * ["H"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
idle_tails = CoinSequence(nb_idle_coins * ["T"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
idle_tails.fade(0.5)
|
||||
|
||||
idle_part = VGroup(idle_heads, idle_tails)
|
||||
left_idle_part = CoinSequence(6 * ["H"],
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
|
||||
self.add(idle_part, left_idle_part)
|
||||
last_coin_seq = VGroup()
|
||||
|
||||
for i in range(2**nb_relevant_coins):
|
||||
binary_seq = binary(i)
|
||||
# pad to the left with 0s
|
||||
nb_leading_zeroes = nb_relevant_coins - len(binary_seq)
|
||||
for j in range(nb_leading_zeroes):
|
||||
binary_seq.insert(0, 0)
|
||||
seq2 = ["H" if x == 0 else "T" for x in binary_seq]
|
||||
coin_seq = CoinSequence(seq2,
|
||||
radius = self.coin_size * 0.5,
|
||||
spacing = self.coin_spacing)
|
||||
coin_seq.next_to(idle_part, LEFT, buff = self.coin_spacing - self.coin_size)
|
||||
left_idle_part.next_to(coin_seq, LEFT, buff = self.coin_spacing - self.coin_size)
|
||||
all_coins = VGroup(left_idle_part, coin_seq, idle_part)
|
||||
all_coins.center()
|
||||
self.remove(last_coin_seq)
|
||||
self.add(coin_seq)
|
||||
#self.wait(1.0/self.fps)
|
||||
self.update_frame()
|
||||
self.add_frames(self.get_frame())
|
||||
last_coin_seq = coin_seq
|
||||
print float(i)/2**nb_relevant_coins
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
228
active_projects/eop/chapter1/area_model_bayes.py
Normal file
228
active_projects/eop/chapter1/area_model_bayes.py
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
|
||||
class IllustrateAreaModelBayes(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
color_A = YELLOW
|
||||
color_not_A = YELLOW_E
|
||||
color_B = MAROON
|
||||
color_not_B = MAROON_E
|
||||
opacity_B = 0.7
|
||||
|
||||
|
||||
# show independent events
|
||||
|
||||
sample_space_width = sample_space_height = 3
|
||||
p_of_A = 0.7
|
||||
p_of_not_A = 1 - p_of_A
|
||||
p_of_B = 0.8
|
||||
p_of_not_B = 1 - p_of_B
|
||||
|
||||
|
||||
rect_A = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = 1 * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_A,
|
||||
fill_opacity = 1.0
|
||||
).move_to(3 * RIGHT + 1.5 * UP)
|
||||
|
||||
rect_not_A = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = 1 * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_A,
|
||||
fill_opacity = 1.0
|
||||
).next_to(rect_A, RIGHT, buff = 0)
|
||||
|
||||
brace_A = Brace(rect_A, DOWN)
|
||||
label_A = TexMobject("P(A)").next_to(brace_A, DOWN).scale(0.7)
|
||||
brace_not_A = Brace(rect_not_A, DOWN)
|
||||
label_not_A = TexMobject("P(\\text{not }A)").next_to(brace_not_A, DOWN).scale(0.7)
|
||||
|
||||
# self.play(
|
||||
# LaggedStart(FadeIn, VGroup(rect_A, rect_not_A), lag_factor = 0.5)
|
||||
# )
|
||||
# self.play(
|
||||
# ShowCreation(brace_A),
|
||||
# Write(label_A),
|
||||
# )
|
||||
|
||||
|
||||
|
||||
rect_B = Rectangle(
|
||||
width = 1 * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
)
|
||||
rect_not_B = Rectangle(
|
||||
width = 1 * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_B, UP, buff = 0)
|
||||
|
||||
VGroup(rect_B, rect_not_B).move_to(VGroup(rect_A, rect_not_A))
|
||||
|
||||
brace_B = Brace(rect_B, LEFT)
|
||||
label_B = TexMobject("P(B)").next_to(brace_B, LEFT).scale(0.7)
|
||||
brace_not_B = Brace(rect_not_B, LEFT)
|
||||
label_not_B = TexMobject("P(\\text{not }B)").next_to(brace_not_B, LEFT).scale(0.7)
|
||||
|
||||
# self.play(
|
||||
# LaggedStart(FadeIn, VGroup(rect_B, rect_not_B), lag_factor = 0.5)
|
||||
# )
|
||||
# self.play(
|
||||
# ShowCreation(brace_B),
|
||||
# Write(label_B),
|
||||
# )
|
||||
|
||||
rect_A_and_B = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 3,
|
||||
fill_opacity = 0.0
|
||||
).align_to(rect_A, DOWN).align_to(rect_A,LEFT)
|
||||
label_A_and_B = TexMobject("P(A\\text{ and }B)").scale(0.7)
|
||||
label_A_and_B.move_to(rect_A_and_B)
|
||||
|
||||
# self.play(
|
||||
# ShowCreation(rect_A_and_B)
|
||||
# )
|
||||
|
||||
indep_formula = TexMobject("P(A\\text{ and }B)", "=", "P(A)", "\cdot", "P(B)")
|
||||
indep_formula = indep_formula.scale(0.7)
|
||||
label_p_of_b = indep_formula.get_part_by_tex("P(B)")
|
||||
|
||||
label_A_and_B_copy = label_A_and_B.copy()
|
||||
label_A_copy = label_A.copy()
|
||||
label_B_copy = label_B.copy()
|
||||
# self.add(label_A_and_B_copy, label_A_copy, label_B_copy)
|
||||
|
||||
# self.play(Transform(label_A_and_B_copy, indep_formula[0]))
|
||||
# self.play(FadeIn(indep_formula[1]))
|
||||
# self.play(Transform(label_A_copy, indep_formula[2]))
|
||||
# self.play(FadeIn(indep_formula[3]))
|
||||
# self.play(Transform(label_B_copy, indep_formula[4]))
|
||||
|
||||
#self.wait()
|
||||
|
||||
label_A_and_B_copy = indep_formula[0]
|
||||
label_A_copy = indep_formula[2]
|
||||
label_B_copy = indep_formula[4]
|
||||
|
||||
# show conditional prob
|
||||
|
||||
rect_A_and_B.set_fill(color = RED, opacity = 0.5)
|
||||
rect_A_and_not_B = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B, UP, buff = 0)
|
||||
|
||||
rect_not_A_and_B = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = p_of_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B, RIGHT, buff = 0)
|
||||
|
||||
rect_not_A_and_not_B = Rectangle(
|
||||
width = p_of_not_A * sample_space_width,
|
||||
height = p_of_not_B * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_not_A_and_B, UP, buff = 0)
|
||||
|
||||
|
||||
indep_formula.next_to(rect_not_A, LEFT, buff = 5)
|
||||
#indep_formula.shift(UP)
|
||||
|
||||
self.play(Write(indep_formula))
|
||||
|
||||
self.play(
|
||||
FadeIn(VGroup(
|
||||
rect_A, rect_not_A, brace_A, label_A, brace_B, label_B,
|
||||
rect_A_and_not_B, rect_not_A_and_B, rect_not_A_and_not_B,
|
||||
rect_A_and_B,
|
||||
label_A_and_B,
|
||||
))
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
p_of_B_knowing_A = 0.6
|
||||
rect_A_and_B.target = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = p_of_B_knowing_A * sample_space_height,
|
||||
stroke_width = 3,
|
||||
fill_color = color_B,
|
||||
fill_opacity = opacity_B
|
||||
).align_to(rect_A_and_B, DOWN).align_to(rect_A_and_B, LEFT)
|
||||
|
||||
rect_A_and_not_B.target = Rectangle(
|
||||
width = p_of_A * sample_space_width,
|
||||
height = (1 - p_of_B_knowing_A) * sample_space_height,
|
||||
stroke_width = 0,
|
||||
fill_color = color_not_B,
|
||||
fill_opacity = opacity_B
|
||||
).next_to(rect_A_and_B.target, UP, buff = 0)
|
||||
|
||||
brace_B.target = Brace(rect_A_and_B.target, LEFT)
|
||||
label_B.target = TexMobject("P(B\mid A)").scale(0.7).next_to(brace_B.target, LEFT)
|
||||
|
||||
|
||||
self.play(
|
||||
MoveToTarget(rect_A_and_B),
|
||||
MoveToTarget(rect_A_and_not_B),
|
||||
MoveToTarget(brace_B),
|
||||
MoveToTarget(label_B),
|
||||
label_A_and_B.move_to,rect_A_and_B.target
|
||||
)
|
||||
label_B_knowing_A = label_B
|
||||
|
||||
#self.play(FadeOut(label_B_copy))
|
||||
self.remove(indep_formula.get_part_by_tex("P(B)"))
|
||||
indep_formula.remove(indep_formula.get_part_by_tex("P(B)"))
|
||||
label_B_knowing_A_copy = label_B_knowing_A.copy()
|
||||
self.add(label_B_knowing_A_copy)
|
||||
|
||||
self.play(
|
||||
label_B_knowing_A_copy.next_to, indep_formula.get_part_by_tex("\cdot"), RIGHT,
|
||||
)
|
||||
|
||||
# solve formula for P(B|A)
|
||||
|
||||
rearranged_formula = TexMobject(["P(B\mid A)", "=", "{P(A\\text{ and }B) \over P(A)}"])
|
||||
rearranged_formula.move_to(indep_formula)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
self.play(
|
||||
# in some places get_part_by_tex does not find the correct part
|
||||
# so I picked out fitting indices
|
||||
label_B_knowing_A_copy.move_to, rearranged_formula.get_part_by_tex("P(B\mid A)"),
|
||||
label_A_copy.move_to, rearranged_formula[-1][10],
|
||||
label_A_and_B_copy.move_to, rearranged_formula[-1][3],
|
||||
indep_formula.get_part_by_tex("=").move_to, rearranged_formula.get_part_by_tex("="),
|
||||
Transform(indep_formula.get_part_by_tex("\cdot"), rearranged_formula[2][8]),
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(rearranged_formula, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
122
active_projects/eop/chapter1/area_model_erf.py
Normal file
122
active_projects/eop/chapter1/area_model_erf.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from old_projects.eoc.chapter8 import *
|
||||
|
||||
import scipy.special
|
||||
|
||||
class IllustrateAreaModelErf(GraphScene):
|
||||
CONFIG = {
|
||||
"x_min" : -3.0,
|
||||
"x_max" : 3.0,
|
||||
"y_min" : 0,
|
||||
"y_max" : 1.0,
|
||||
"num_rects": 400,
|
||||
"y_axis_label" : "",
|
||||
"x_axis_label" : "",
|
||||
"variable_point_label" : "a",
|
||||
"graph_origin": 2.5 * DOWN + 4 * RIGHT,
|
||||
"x_axis_width": 5,
|
||||
"y_axis_height": 5
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
# integral bounds
|
||||
x_min_1 = -0.0001
|
||||
x_max_1 = 0.0001
|
||||
|
||||
x_min_2 = self.x_min
|
||||
x_max_2 = self.x_max
|
||||
|
||||
self.setup_axes()
|
||||
self.remove(self.x_axis, self.y_axis)
|
||||
graph = self.get_graph(lambda x: np.exp(-x**2) * 2.0 / TAU ** 0.5)
|
||||
area = self.area = self.get_area(graph, x_min_1, x_max_1)
|
||||
|
||||
|
||||
pdf_formula = TexMobject("p(x) = {1\over \sigma\sqrt{2\pi}}e^{-{1\over 2}({x\over\sigma})^2}")
|
||||
pdf_formula.set_color(graph.color)
|
||||
|
||||
cdf_formula = TexMobject("P(|X| < ", "a", ") = \int", "_{-a}", "^a", "p(x) dx")
|
||||
cdf_formula.set_color_by_tex("a", YELLOW)
|
||||
cdf_formula.next_to(graph, LEFT, buff = 2)
|
||||
pdf_formula.next_to(cdf_formula, UP)
|
||||
|
||||
formulas = VGroup(pdf_formula, cdf_formula)
|
||||
self.play(Write(pdf_formula))
|
||||
self.play(Write(cdf_formula))
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
self.play(ShowCreation(self.x_axis))
|
||||
self.play(ShowCreation(graph))
|
||||
self.play(FadeIn(area))
|
||||
|
||||
self.v_graph = graph
|
||||
self.add_T_label(
|
||||
x_min_1,
|
||||
label = "-a",
|
||||
side = LEFT,
|
||||
color = YELLOW,
|
||||
animated = False
|
||||
)
|
||||
self.add_T_label(
|
||||
x_max_1,
|
||||
label = "a",
|
||||
side = RIGHT,
|
||||
color = YELLOW,
|
||||
animated = False
|
||||
)
|
||||
# don't show the labels just yet
|
||||
self.remove(
|
||||
self.left_T_label_group[0],
|
||||
self.right_T_label_group[0],
|
||||
)
|
||||
|
||||
def integral_update_func(t):
|
||||
return scipy.special.erf(
|
||||
self.point_to_coords(self.right_v_line.get_center())[0]
|
||||
)
|
||||
|
||||
def integral_update_func_percent(t):
|
||||
return 100 * integral_update_func(t)
|
||||
|
||||
equals_sign = TexMobject("=").next_to(cdf_formula, buff = MED_LARGE_BUFF)
|
||||
|
||||
cdf_value = DecimalNumber(0, color = graph.color, num_decimal_places = 3)
|
||||
cdf_value.next_to(equals_sign)
|
||||
self.play(
|
||||
FadeIn(equals_sign),
|
||||
FadeIn(cdf_value)
|
||||
)
|
||||
self.add_foreground_mobject(cdf_value)
|
||||
|
||||
cdf_percentage = DecimalNumber(0, unit = "\%")
|
||||
cdf_percentage.move_to(self.coords_to_point(0,0.2))
|
||||
self.add_foreground_mobject(cdf_percentage)
|
||||
|
||||
self.add(ContinualChangingDecimal(
|
||||
decimal_number_mobject = cdf_value,
|
||||
number_update_func = integral_update_func,
|
||||
num_decimal_places = 3
|
||||
))
|
||||
|
||||
self.add(ContinualChangingDecimal(
|
||||
decimal_number_mobject = cdf_percentage,
|
||||
number_update_func = integral_update_func_percent,
|
||||
num_decimal_places = 1
|
||||
))
|
||||
|
||||
|
||||
anim = self.get_animation_integral_bounds_change(
|
||||
graph, x_min_2, x_max_2,
|
||||
run_time = 3)
|
||||
|
||||
|
||||
self.play(
|
||||
anim
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(formulas, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
93
active_projects/eop/chapter1/area_model_expectation.py
Normal file
93
active_projects/eop/chapter1/area_model_expectation.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class IllustrateAreaModelExpectation(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
formula = TexMobject("E[X] = \sum_{i=1}^N p_i x_i").move_to(3 * LEFT + UP)
|
||||
self.play(Write(formula))
|
||||
|
||||
|
||||
x_scale = 5.0
|
||||
y_scale = 1.0
|
||||
|
||||
probabilities = np.array([1./8, 3./8, 3./8, 1./8])
|
||||
prob_strings = ["{1\over 8}","{3\over 8}","{3\over 8}","{1\over 8}"]
|
||||
cumulative_probabilities = np.cumsum(probabilities)
|
||||
cumulative_probabilities = np.insert(cumulative_probabilities, 0, 0)
|
||||
y_values = np.array([0, 1, 2, 3])
|
||||
|
||||
hist = Histogram(probabilities, y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none"
|
||||
)
|
||||
|
||||
flat_hist = Histogram(probabilities, 0 * y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none"
|
||||
)
|
||||
|
||||
self.play(FadeIn(flat_hist))
|
||||
self.play(
|
||||
ReplacementTransform(flat_hist, hist)
|
||||
)
|
||||
|
||||
braces = VGroup()
|
||||
p_labels = VGroup()
|
||||
# add x labels (braces)
|
||||
for (p,string,bar) in zip(probabilities, prob_strings,hist.bars):
|
||||
brace = Brace(bar, DOWN, buff = 0.1)
|
||||
p_label = TexMobject(string).next_to(brace, DOWN, buff = SMALL_BUFF).scale(0.7)
|
||||
group = VGroup(brace, p_label)
|
||||
braces.add(brace)
|
||||
p_labels.add(p_label)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn,braces),
|
||||
LaggedStart(FadeIn, p_labels)
|
||||
)
|
||||
|
||||
|
||||
|
||||
y_average = np.mean(y_values)
|
||||
averaged_y_values = y_average * np.ones(np.shape(y_values))
|
||||
|
||||
averaged_hist = flat_hist = Histogram(probabilities, averaged_y_values,
|
||||
mode = "widths",
|
||||
x_scale = x_scale,
|
||||
y_scale = y_scale,
|
||||
x_labels = "none",
|
||||
y_labels = "none"
|
||||
).fade(0.2)
|
||||
|
||||
ghost_hist = hist.copy().fade(0.8)
|
||||
self.bring_to_back(ghost_hist)
|
||||
|
||||
self.play(Transform(hist, averaged_hist, run_time = 3))
|
||||
self.wait()
|
||||
|
||||
average_brace = Brace(averaged_hist, RIGHT, buff = 0.1)
|
||||
average_label = TexMobject(str(y_average)).scale(0.7)
|
||||
average_label.next_to(average_brace, RIGHT, SMALL_BUFF)
|
||||
average_group = VGroup(average_brace, average_label)
|
||||
|
||||
one_brace = Brace(averaged_hist, DOWN, buff = 0.1)
|
||||
one_p_label = TexMobject(str(1)).next_to(one_brace, DOWN, buff = SMALL_BUFF).scale(0.7)
|
||||
one_group = VGroup(one_brace, one_p_label)
|
||||
|
||||
self.play(
|
||||
FadeIn(average_group),
|
||||
Transform(braces, one_brace),
|
||||
Transform(p_labels, one_p_label),
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(formula, buff = 0.5 * MED_LARGE_BUFF)
|
||||
self.play(ShowCreation(rect))
|
||||
|
||||
929
active_projects/eop/chapter1/brick_row_scene.py
Normal file
929
active_projects/eop/chapter1/brick_row_scene.py
Normal file
|
|
@ -0,0 +1,929 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class BrickRowScene(PiCreatureScene):
|
||||
|
||||
|
||||
def split_tallies(self, row, direction = DOWN):
|
||||
# Split all tally symbols at once and move the copies
|
||||
# either horizontally on top of the brick row
|
||||
# or diagonally into the bricks
|
||||
|
||||
self.tallies_copy = self.tallies.copy()
|
||||
self.add_foreground_mobject(self.tallies_copy)
|
||||
|
||||
tally_targets_left = [
|
||||
rect.get_center() + 0.25 * rect.get_width() * LEFT
|
||||
for rect in row.rects
|
||||
]
|
||||
|
||||
tally_targets_right = [
|
||||
rect.get_center() + 0.25 * rect.get_width() * RIGHT
|
||||
for rect in row.rects
|
||||
]
|
||||
|
||||
if np.all(direction == LEFT) or np.all(direction == RIGHT):
|
||||
|
||||
tally_y_pos = self.tallies[0].anchor[1]
|
||||
for target in tally_targets_left:
|
||||
target[1] = tally_y_pos
|
||||
for target in tally_targets_right:
|
||||
target[1] = tally_y_pos
|
||||
|
||||
for (i, tally) in enumerate(self.tallies):
|
||||
|
||||
target_left = tally_targets_left[i]
|
||||
new_tally_left = TallyStack(tally.nb_heads + 1, tally.nb_tails)
|
||||
new_tally_left.move_anchor_to(target_left)
|
||||
v = target_left - tally.anchor
|
||||
|
||||
self.play(
|
||||
tally.move_anchor_to, target_left,
|
||||
)
|
||||
tally.anchor = target_left
|
||||
self.play(Transform(tally, new_tally_left))
|
||||
|
||||
tally_copy = self.tallies_copy[i]
|
||||
|
||||
target_right = tally_targets_right[i]
|
||||
new_tally_right = TallyStack(tally.nb_heads, tally.nb_tails + 1)
|
||||
new_tally_right.move_anchor_to(target_right)
|
||||
v = target_right - tally_copy.anchor
|
||||
|
||||
self.play(tally_copy.move_anchor_to, target_right)
|
||||
tally_copy.anchor = target_right
|
||||
self.play(Transform(tally_copy, new_tally_right))
|
||||
|
||||
tally_copy.nb_heads = new_tally_right.nb_heads
|
||||
tally_copy.nb_tails = new_tally_right.nb_tails
|
||||
tally.nb_heads = new_tally_left.nb_heads
|
||||
tally.nb_tails = new_tally_left.nb_tails
|
||||
|
||||
|
||||
|
||||
|
||||
def tally_split_animations(self, row, direction = DOWN):
|
||||
# Just creates the animations and returns them
|
||||
# Execution can be timed afterwards
|
||||
# Returns two lists: first all those going left, then those to the right
|
||||
|
||||
self.tallies_copy = self.tallies.copy()
|
||||
self.add_foreground_mobject(self.tallies_copy)
|
||||
|
||||
tally_targets_left = [
|
||||
rect.get_center() + 0.25 * rect.get_width() * LEFT
|
||||
for rect in row.rects
|
||||
]
|
||||
|
||||
tally_targets_right = [
|
||||
rect.get_center() + 0.25 * rect.get_width() * RIGHT
|
||||
for rect in row.rects
|
||||
]
|
||||
|
||||
if np.all(direction == LEFT) or np.all(direction == RIGHT):
|
||||
|
||||
tally_y_pos = self.tallies[0].anchor[1]
|
||||
for target in tally_targets_left:
|
||||
target[1] = tally_y_pos
|
||||
for target in tally_targets_right:
|
||||
target[1] = tally_y_pos
|
||||
|
||||
|
||||
anims1 = []
|
||||
|
||||
for (i, tally) in enumerate(self.tallies):
|
||||
|
||||
new_tally_left = TallyStack(tally.nb_heads + 1, tally.nb_tails)
|
||||
target_left = tally_targets_left[i]
|
||||
new_tally_left.move_to(target_left)
|
||||
|
||||
anims1.append(Transform(tally, new_tally_left))
|
||||
|
||||
tally.anchor = target_left
|
||||
tally.nb_heads = new_tally_left.nb_heads
|
||||
tally.nb_tails = new_tally_left.nb_tails
|
||||
|
||||
|
||||
anims2 = []
|
||||
|
||||
for (i, tally) in enumerate(self.tallies_copy):
|
||||
|
||||
new_tally_right = TallyStack(tally.nb_heads, tally.nb_tails + 1)
|
||||
target_right = tally_targets_right[i]
|
||||
new_tally_right.move_to(target_right)
|
||||
|
||||
anims2.append(Transform(tally, new_tally_right))
|
||||
|
||||
tally.anchor = target_right
|
||||
tally.nb_heads = new_tally_right.nb_heads
|
||||
tally.nb_tails = new_tally_right.nb_tails
|
||||
|
||||
return anims1, anims2
|
||||
|
||||
|
||||
|
||||
def split_tallies_at_once(self, row, direction = DOWN):
|
||||
anims1, anims2 = self.tally_split_animations(row, direction = direction)
|
||||
self.play(*(anims1 + anims2))
|
||||
|
||||
def split_tallies_in_two_steps(self, row, direction = DOWN):
|
||||
# First all those to the left, then those to the right
|
||||
anims1, anims2 = self.tally_split_animations(row, direction = direction)
|
||||
self.play(*anims1)
|
||||
self.wait(0.3)
|
||||
self.play(*anims2)
|
||||
|
||||
|
||||
|
||||
|
||||
def merge_rects_by_subdiv(self, row):
|
||||
|
||||
half_merged_row = row.copy()
|
||||
half_merged_row.subdiv_level += 1
|
||||
half_merged_row.generate_points()
|
||||
half_merged_row.move_to(row)
|
||||
|
||||
self.play(FadeIn(half_merged_row))
|
||||
self.remove(row)
|
||||
return half_merged_row
|
||||
|
||||
|
||||
|
||||
|
||||
def merge_tallies(self, row, target_pos = UP):
|
||||
|
||||
r = row.subdiv_level
|
||||
|
||||
if np.all(target_pos == DOWN):
|
||||
tally_targets = [
|
||||
rect.get_center()
|
||||
for rect in row.get_rects_for_level(r)
|
||||
]
|
||||
elif np.all(target_pos == UP):
|
||||
y_pos = row.get_center()[1] + 1.2 * 0.5 * row.get_height()
|
||||
for target in tally_targets:
|
||||
target[1] = y_pos
|
||||
else:
|
||||
raise Exception("Invalid target position (either UP or DOWN)")
|
||||
|
||||
anims = []
|
||||
for (tally, target) in zip(self.tallies[1:], tally_targets[1:-1]):
|
||||
anims.append(tally.move_anchor_to)
|
||||
anims.append(target)
|
||||
|
||||
for (tally, target) in zip(self.tallies_copy[:-1], tally_targets[1:-1]):
|
||||
anims.append(tally.move_anchor_to)
|
||||
anims.append(target)
|
||||
|
||||
self.play(*anims)
|
||||
# update anchors
|
||||
for (tally, target) in zip(self.tallies[1:], tally_targets[1:-1]):
|
||||
tally.anchor = target
|
||||
for (tally, target) in zip(self.tallies_copy[:-1], tally_targets[1:-1]):
|
||||
tally.anchor = target
|
||||
|
||||
self.remove(self.tallies_copy)
|
||||
self.tallies.add(self.tallies_copy[-1])
|
||||
|
||||
|
||||
def merge_rects_by_coloring(self, row):
|
||||
|
||||
merged_row = row.copy()
|
||||
merged_row.coloring_level += 1
|
||||
merged_row.generate_points()
|
||||
merged_row.move_to(row)
|
||||
|
||||
self.play(FadeIn(merged_row))
|
||||
self.remove(row)
|
||||
return merged_row
|
||||
|
||||
|
||||
|
||||
def move_tallies_on_top(self, row):
|
||||
self.play(
|
||||
self.tallies.shift, 1.2 * 0.5 * row.height * UP
|
||||
)
|
||||
for tally in self.tallies:
|
||||
tally.anchor += 1.2 * 0.5 * row.height * UP
|
||||
|
||||
def create_pi_creature(self):
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E)
|
||||
return randy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = self.get_primary_pi_creature()
|
||||
randy = randy.scale(0.5).move_to(3*DOWN + 6*LEFT)
|
||||
#self.add(randy)
|
||||
self.row = BrickRow(0, height = 2, width = 10)
|
||||
self.wait()
|
||||
|
||||
self.play(FadeIn(self.row))
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
# move in all kinds of sequences
|
||||
coin_seqs = VGroup()
|
||||
for i in range(20):
|
||||
n = np.random.randint(1,10)
|
||||
seq = [np.random.choice(["H", "T"]) for j in range(n)]
|
||||
coin_seq = CoinSequence(seq).scale(1.5)
|
||||
loc = np.random.uniform(low = -10, high = 10) * RIGHT
|
||||
loc += np.random.uniform(low = -6, high = 6) * UP
|
||||
coin_seq.move_to(loc)
|
||||
|
||||
coin_seq.target = coin_seq.copy().scale(0.3).move_to(0.4 * loc)
|
||||
coin_seq.target.fade(1)
|
||||
coin_seqs.add(coin_seq)
|
||||
|
||||
self.play(
|
||||
LaggedStart(
|
||||
Succession, coin_seqs, lambda m: (FadeIn(m, run_time = 0.1), MoveToTarget(m)),
|
||||
run_time = 5,
|
||||
lag_ratio = 0.5
|
||||
)
|
||||
)
|
||||
|
||||
# # # # # # # #
|
||||
# FIRST FLIP #
|
||||
# # # # # # # #
|
||||
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
|
||||
self.play(SplitRectsInBrickWall(self.row))
|
||||
self.row = self.merge_rects_by_subdiv(self.row)
|
||||
self.row = self.merge_rects_by_coloring(self.row)
|
||||
#
|
||||
# put tallies on top
|
||||
|
||||
single_flip_labels = VGroup(UprightHeads(), UprightTails())
|
||||
for (label, rect) in zip(single_flip_labels, self.row.rects):
|
||||
label.next_to(rect, UP)
|
||||
self.play(FadeIn(label))
|
||||
self.wait()
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
# # # # # # # #
|
||||
# SECOND FLIP #
|
||||
# # # # # # # #
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
SplitRectsInBrickWall(self.row)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
# split sequences
|
||||
single_flip_labels_copy = single_flip_labels.copy()
|
||||
self.add(single_flip_labels_copy)
|
||||
|
||||
|
||||
v = self.row.get_outcome_centers_for_level(2)[0] - single_flip_labels[0].get_center()
|
||||
self.play(
|
||||
single_flip_labels.shift, v
|
||||
)
|
||||
new_heads = VGroup(UprightHeads(), UprightHeads())
|
||||
for i in range(2):
|
||||
new_heads[i].move_to(single_flip_labels[i])
|
||||
new_heads[i].shift(COIN_SEQUENCE_SPACING * DOWN)
|
||||
self.play(FadeIn(new_heads))
|
||||
|
||||
v = self.row.get_outcome_centers_for_level(2)[-1] - single_flip_labels_copy[-1].get_center()
|
||||
self.play(
|
||||
single_flip_labels_copy.shift, v
|
||||
)
|
||||
new_tails = VGroup(UprightTails(), UprightTails())
|
||||
for i in range(2):
|
||||
new_tails[i].move_to(single_flip_labels_copy[i])
|
||||
new_tails[i].shift(COIN_SEQUENCE_SPACING * DOWN)
|
||||
self.play(FadeIn(new_tails))
|
||||
|
||||
decimal_tallies = VGroup()
|
||||
# introduce notion of tallies
|
||||
for (i, rect) in enumerate(self.row.get_rects_for_level(2)):
|
||||
tally = DecimalTally(2-i, i)
|
||||
tally.next_to(rect, UP)
|
||||
decimal_tallies.add(tally)
|
||||
self.play(FadeIn(tally))
|
||||
self.wait()
|
||||
|
||||
self.add_foreground_mobject(single_flip_labels)
|
||||
self.add_foreground_mobject(new_heads)
|
||||
self.add_foreground_mobject(single_flip_labels_copy)
|
||||
self.add_foreground_mobject(new_tails)
|
||||
|
||||
# show individual outcomes
|
||||
outcomes = self.row.get_outcome_rects_for_level(2, with_labels = False)
|
||||
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, outcomes)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(FadeOut, outcomes),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(single_flip_labels),
|
||||
FadeOut(new_heads),
|
||||
FadeOut(single_flip_labels_copy),
|
||||
FadeOut(new_tails)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
self.tallies = VGroup()
|
||||
for (i, rect) in enumerate(self.row.get_rects_for_level(2)):
|
||||
tally = TallyStack(2-i, i, show_decimals = False)
|
||||
tally.move_to(rect)
|
||||
self.tallies.add(tally)
|
||||
|
||||
|
||||
self.play(FadeIn(self.tallies))
|
||||
self.wait()
|
||||
|
||||
|
||||
anims = []
|
||||
for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies):
|
||||
anims.append(ApplyFunction(
|
||||
tally_stack.position_decimal_tally, decimal_tally
|
||||
))
|
||||
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
|
||||
# replace the original decimal tallies with
|
||||
# the ones that belong to the TallyStacks
|
||||
for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies):
|
||||
self.remove(decimal_tally)
|
||||
tally_stack.position_decimal_tally(tally_stack.decimal_tally)
|
||||
tally_stack.add(tally_stack.decimal_tally)
|
||||
|
||||
self.add_foreground_mobject(self.tallies)
|
||||
self.row = self.merge_rects_by_subdiv(self.row)
|
||||
self.wait()
|
||||
self.row = self.merge_rects_by_coloring(self.row)
|
||||
self.wait()
|
||||
|
||||
|
||||
# # # # # # # # # # # # #
|
||||
# CALLBACK TO SEQUENCES #
|
||||
# # # # # # # # # # # # #
|
||||
|
||||
outcomes = self.row.get_outcome_rects_for_level(2, with_labels = True)
|
||||
subdivs = self.row.get_sequence_subdivs_for_level(2)
|
||||
self.play(
|
||||
FadeIn(outcomes),
|
||||
FadeIn(subdivs),
|
||||
FadeOut(self.tallies)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
rect_to_dice = outcomes[1]
|
||||
N = 10
|
||||
dice_width = rect_to_dice.get_width()/N
|
||||
dice_height = rect_to_dice.get_height()/N
|
||||
prototype_dice = Rectangle(
|
||||
width = dice_width,
|
||||
height = dice_height,
|
||||
stroke_width = 2,
|
||||
stroke_color = WHITE,
|
||||
fill_color = WHITE,
|
||||
fill_opacity = 0
|
||||
)
|
||||
prototype_dice.align_to(rect_to_dice, direction = UP)
|
||||
prototype_dice.align_to(rect_to_dice, direction = LEFT)
|
||||
all_dice = VGroup()
|
||||
for i in range(N):
|
||||
for j in range(N):
|
||||
dice_copy = prototype_dice.copy()
|
||||
dice_copy.shift(j * dice_width * RIGHT + i * dice_height * DOWN)
|
||||
all_dice.add(dice_copy)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, all_dice),
|
||||
FadeOut(rect_to_dice.label)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
table = Ellipse(width = 1.5, height = 1)
|
||||
table.set_fill(color = GREEN_E, opacity = 1)
|
||||
table.next_to(rect_to_dice, UP)
|
||||
self.add(table)
|
||||
coin1 = UprightHeads(radius = 0.1)
|
||||
coin2 = UprightTails(radius = 0.1)
|
||||
|
||||
def get_random_point_in_ellipse(ellipse):
|
||||
width = ellipse.get_width()
|
||||
height = ellipse.get_height()
|
||||
x = y = 1
|
||||
while x**2 + y**2 > 0.9:
|
||||
x = np.random.uniform(-1,1)
|
||||
y = np.random.uniform(-1,1)
|
||||
x *= width/2
|
||||
y *= height/2
|
||||
return ellipse.get_center() + x * RIGHT + y * UP
|
||||
|
||||
|
||||
for dice in all_dice:
|
||||
p1 = get_random_point_in_ellipse(table)
|
||||
p2 = get_random_point_in_ellipse(table)
|
||||
coin1.move_to(p1)
|
||||
coin2.move_to(p2)
|
||||
self.add(coin1, coin2)
|
||||
self.play(
|
||||
ApplyMethod(dice.set_fill, {"opacity" : 0.5},
|
||||
rate_func = there_and_back,
|
||||
run_time = 0.05)
|
||||
)
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeOut(outcomes),
|
||||
FadeOut(subdivs),
|
||||
FadeOut(all_dice),
|
||||
FadeOut(table),
|
||||
FadeOut(coin1),
|
||||
FadeOut(coin2),
|
||||
FadeIn(self.tallies)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
# # # # # # # #
|
||||
# THIRD FLIP #
|
||||
# # # # # # # #
|
||||
|
||||
# move row up, leave a copy without tallies below
|
||||
new_row = self.row.copy()
|
||||
self.clear()
|
||||
self.add(randy, self.row, self.tallies)
|
||||
self.bring_to_back(new_row)
|
||||
self.play(
|
||||
self.row.shift, 2.5 * UP,
|
||||
self.tallies.shift, 2.5 * UP,
|
||||
)
|
||||
|
||||
old_row = self.row
|
||||
self.row = new_row
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
SplitRectsInBrickWall(self.row)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.split_tallies_in_two_steps(self.row)
|
||||
self.wait()
|
||||
|
||||
self.add_foreground_mobject(self.tallies)
|
||||
self.add_foreground_mobject(self.tallies_copy)
|
||||
|
||||
|
||||
|
||||
|
||||
self.remove(new_row)
|
||||
new_row = self.row
|
||||
|
||||
|
||||
|
||||
self.clear()
|
||||
self.add(randy, self.row, old_row)
|
||||
self.add_foreground_mobject(self.tallies)
|
||||
|
||||
|
||||
self.play(
|
||||
self.row.fade, 0.7,
|
||||
old_row.fade, 0.7,
|
||||
FadeOut(self.tallies),
|
||||
)
|
||||
|
||||
# # # # # # # # # # # # # # # # #
|
||||
# SHOW SPLITTING WITH OUTCOMES #
|
||||
# # # # # # # # # # # # # # # # #
|
||||
|
||||
# # show individual outcomes
|
||||
# old_outcomes = old_row.get_outcome_rects_for_level(2, with_labels = True)
|
||||
# old_outcomes_copy = old_outcomes.copy()
|
||||
# new_outcomes = self.row.get_outcome_rects_for_level(3, with_labels = True)
|
||||
|
||||
# self.play(
|
||||
# FadeIn(old_outcomes[0]),
|
||||
# FadeIn(old_outcomes_copy[0]),
|
||||
# )
|
||||
|
||||
# self.wait()
|
||||
|
||||
# self.play(
|
||||
# Transform(old_outcomes_copy[0], new_outcomes[1])
|
||||
# )
|
||||
|
||||
# self.wait()
|
||||
|
||||
# self.play(
|
||||
# FadeIn(old_outcomes[1:3]),
|
||||
# FadeIn(old_outcomes_copy[1:3]),
|
||||
# )
|
||||
|
||||
# self.wait()
|
||||
|
||||
# self.play(
|
||||
# Transform(old_outcomes_copy[1:3], new_outcomes[2:4])
|
||||
# )
|
||||
|
||||
# self.wait()
|
||||
|
||||
# self.row = self.merge_rects_by_subdiv(self.row)
|
||||
# self.wait()
|
||||
|
||||
# self.play(
|
||||
# FadeOut(old_row),
|
||||
# FadeOut(old_outcomes[0:3]),
|
||||
# FadeOut(new_outcomes[1:4]),
|
||||
# self.row.fade,0,
|
||||
# FadeIn(self.tallies[1]),
|
||||
# FadeIn(self.tallies_copy[0]),
|
||||
# )
|
||||
|
||||
# # rest of the new row
|
||||
# self.play(
|
||||
# FadeIn(self.tallies[:1]),
|
||||
# FadeIn(self.tallies[2:]),
|
||||
# FadeIn(self.tallies_copy[1:])
|
||||
# )
|
||||
|
||||
# self.wait()
|
||||
|
||||
# self.merge_tallies(self.row, target_pos = DOWN)
|
||||
# self.add_foreground_mobject(self.tallies)
|
||||
# self.row = self.merge_rects_by_coloring(self.row)
|
||||
# self.wait()
|
||||
|
||||
|
||||
# # # # # # # # # # # # # # # #
|
||||
# SHOW SPLITTING WITH TALLIES #
|
||||
# # # # # # # # # # # # # # # #
|
||||
|
||||
tally_left = TallyStack(2,0)
|
||||
tally_left.move_to(old_row.rects[0])
|
||||
tally_right = TallyStack(1,1)
|
||||
tally_right.move_to(old_row.rects[1])
|
||||
|
||||
rect_left = old_row.rects[0].copy()
|
||||
rect_right = old_row.rects[1].copy()
|
||||
|
||||
self.play(
|
||||
FadeIn(rect_left),
|
||||
FadeIn(rect_right),
|
||||
FadeIn(tally_left),
|
||||
FadeIn(tally_right)
|
||||
)
|
||||
|
||||
rect_left.target = rect_left.copy()
|
||||
rect_left.target.stretch(0.5,0)
|
||||
left_target_pos = self.row.get_outcome_centers_for_level(3)[1]
|
||||
left_v = left_target_pos - rect_left.get_center()
|
||||
rect_left.target.move_to(left_target_pos)
|
||||
|
||||
rect_right.target = rect_right.copy()
|
||||
rect_right.target.stretch(0.5,0)
|
||||
right_target_pos = 0.5 * (self.row.get_outcome_centers_for_level(3)[2] + self.row.get_outcome_centers_for_level(3)[3])
|
||||
right_v = right_target_pos - rect_right.get_center()
|
||||
rect_right.target.move_to(right_target_pos)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(rect_left),
|
||||
tally_left.move_to, left_target_pos
|
||||
)
|
||||
#tally_left.anchor += left_v
|
||||
|
||||
self.wait()
|
||||
|
||||
new_tally_left = TallyStack(2,1)
|
||||
#new_tally_left.move_anchor_to(tally_left.anchor)
|
||||
new_tally_left.move_to(tally_left)
|
||||
|
||||
self.play(
|
||||
Transform(tally_left, new_tally_left)
|
||||
)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(rect_right),
|
||||
tally_right.move_to, right_target_pos
|
||||
)
|
||||
#tally_right.anchor += right_v
|
||||
|
||||
self.wait()
|
||||
new_tally_right = TallyStack(2,1)
|
||||
#new_tally_right.move_anchor_to(tally_right.anchor)
|
||||
new_tally_right.move_to(tally_right)
|
||||
|
||||
self.play(
|
||||
Transform(tally_right, new_tally_right)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
self.row = self.merge_rects_by_subdiv(self.row)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeOut(old_row),
|
||||
self.row.fade,0,
|
||||
FadeOut(new_tally_left),
|
||||
FadeOut(new_tally_right),
|
||||
FadeIn(self.tallies[1]),
|
||||
FadeIn(self.tallies_copy[0]),
|
||||
)
|
||||
|
||||
# rest of the new row
|
||||
self.play(
|
||||
FadeIn(self.tallies[:1]),
|
||||
FadeIn(self.tallies[2:]),
|
||||
FadeIn(self.tallies_copy[1:])
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
self.merge_tallies(self.row, target_pos = DOWN)
|
||||
self.add_foreground_mobject(self.tallies)
|
||||
self.row = self.merge_rects_by_coloring(self.row)
|
||||
self.wait()
|
||||
|
||||
|
||||
# show the 8 individual outcomes
|
||||
outcomes = self.row.get_outcome_rects_for_level(3,
|
||||
with_labels = True,
|
||||
inset = True)
|
||||
self.play(FadeOut(self.tallies))
|
||||
self.wait()
|
||||
self.play(LaggedStart(
|
||||
FadeIn, outcomes,
|
||||
#rate_func = there_and_back_with_pause,
|
||||
run_time = 5))
|
||||
self.wait()
|
||||
self.play(LaggedStart(
|
||||
FadeOut, outcomes,
|
||||
#rate_func = there_and_back_with_pause,
|
||||
run_time = 5))
|
||||
|
||||
self.wait()
|
||||
self.play(FadeIn(self.tallies))
|
||||
|
||||
brace1 = Brace(self.row.rects[2], UP)
|
||||
brace2 = Brace(self.row.rects[3], UP)
|
||||
p1 = TexMobject("{3\over 8}").next_to(brace1, UP)
|
||||
p2 = TexMobject("{1\over 8}").next_to(brace2, UP)
|
||||
|
||||
self.play(
|
||||
ShowCreation(brace1),
|
||||
ShowCreation(brace2),
|
||||
Write(p1),
|
||||
Write(p2),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeOut(brace1),
|
||||
FadeOut(brace2),
|
||||
FadeOut(p1),
|
||||
FadeOut(p2),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
|
||||
# put visuals for other probability distribtuions here
|
||||
|
||||
# back to three coin flips, show all 8 outcomes
|
||||
run_time = 5
|
||||
self.play(
|
||||
LaggedStart(FadeIn, outcomes,
|
||||
#rate_func = there_and_back_with_pause,
|
||||
run_time = run_time),
|
||||
FadeOut(self.tallies,
|
||||
run_time = run_time)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(FadeOut, outcomes,
|
||||
#rate_func = there_and_back_with_pause,
|
||||
run_time = 5),
|
||||
FadeIn(self.tallies,
|
||||
run_time = run_time)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
# # # # # # # #
|
||||
# FOURTH FLIP #
|
||||
# # # # # # # #
|
||||
|
||||
|
||||
|
||||
|
||||
previous_row = self.row.copy()
|
||||
self.add(previous_row)
|
||||
|
||||
v = 1.25 * self.row.height * UP
|
||||
self.play(
|
||||
previous_row.shift, v,
|
||||
self.tallies.shift, v,
|
||||
)
|
||||
self.add_foreground_mobject(self.tallies)
|
||||
|
||||
self.play(
|
||||
SplitRectsInBrickWall(self.row)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.row = self.merge_rects_by_subdiv(self.row)
|
||||
|
||||
self.wait()
|
||||
|
||||
n = 3 # level to split
|
||||
k = 1 # tally to split
|
||||
|
||||
# show individual outcomes
|
||||
outcomes = previous_row.get_outcome_rects_for_level(n,
|
||||
with_labels = False,
|
||||
inset = True
|
||||
)
|
||||
grouped_outcomes = VGroup()
|
||||
index = 0
|
||||
for i in range(n + 1):
|
||||
size = choose(n,i)
|
||||
grouped_outcomes.add(VGroup(outcomes[index:index + size]))
|
||||
index += size
|
||||
|
||||
|
||||
grouped_outcomes_copy = grouped_outcomes.copy()
|
||||
|
||||
original_grouped_outcomes = grouped_outcomes.copy()
|
||||
# for later reference
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, grouped_outcomes),
|
||||
LaggedStart(FadeIn, grouped_outcomes_copy),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# show how the outcomes in one tally split into two copies
|
||||
# going into the neighboring tallies
|
||||
|
||||
#self.revert_to_original_skipping_status()
|
||||
|
||||
target_outcomes = self.row.get_outcome_rects_for_level(n + 1,
|
||||
with_labels = False,
|
||||
inset = True
|
||||
)
|
||||
grouped_target_outcomes = VGroup()
|
||||
index = 0
|
||||
old_tally_sizes = [choose(n,i) for i in range(n + 1)]
|
||||
new_tally_sizes = [choose(n + 1,i) for i in range(n + 2)]
|
||||
for i in range(n + 2):
|
||||
size = new_tally_sizes[i]
|
||||
grouped_target_outcomes.add(VGroup(target_outcomes[index:index + size]))
|
||||
index += size
|
||||
|
||||
self.play(
|
||||
Transform(grouped_outcomes[k][0],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:])
|
||||
)
|
||||
|
||||
self.play(
|
||||
Transform(grouped_outcomes_copy[k][0],grouped_target_outcomes[k + 1][0][:old_tally_sizes[k]])
|
||||
)
|
||||
|
||||
old_tally_sizes.append(0) # makes the edge cases work properly
|
||||
|
||||
# split the other tallies
|
||||
for i in range(k) + range(k + 1, n + 1):
|
||||
self.play(
|
||||
Transform(grouped_outcomes[i][0],
|
||||
grouped_target_outcomes[i][0][old_tally_sizes[i - 1]:]
|
||||
),
|
||||
Transform(grouped_outcomes_copy[i][0],
|
||||
grouped_target_outcomes[i + 1][0][:old_tally_sizes[i]]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
self.wait()
|
||||
|
||||
# fade in new tallies
|
||||
new_rects = self.row.get_rects_for_level(4)
|
||||
new_tallies = VGroup(*[
|
||||
TallyStack(n + 1 - i, i).move_to(rect) for (i, rect) in enumerate(new_rects)
|
||||
])
|
||||
self.play(FadeIn(new_tallies))
|
||||
self.add_foreground_mobject(new_tallies[1])
|
||||
# remove outcomes and sizes except for one tally
|
||||
anims = []
|
||||
for i in range(n + 1):
|
||||
if i != k - 1:
|
||||
anims.append(FadeOut(grouped_outcomes_copy[i]))
|
||||
if i != k:
|
||||
anims.append(FadeOut(grouped_outcomes[i]))
|
||||
anims.append(FadeOut(new_tallies[i]))
|
||||
|
||||
#anims.append(FadeOut(self.tallies[0]))
|
||||
#anims.append(FadeOut(self.tallies[2:]))
|
||||
anims.append(FadeOut(new_tallies[-1]))
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
Transform(grouped_outcomes_copy[k - 1], original_grouped_outcomes[k - 1])
|
||||
)
|
||||
|
||||
self.play(
|
||||
Transform(grouped_outcomes[k], original_grouped_outcomes[k])
|
||||
)
|
||||
|
||||
new_rects = self.row.get_rects_for_level(n + 1)
|
||||
|
||||
self.play(
|
||||
Transform(grouped_outcomes[k][0],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:]),
|
||||
Transform(grouped_outcomes_copy[k - 1][0],grouped_target_outcomes[k][0][:old_tally_sizes[k - 1]]),
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(previous_row),
|
||||
FadeOut(self.tallies),
|
||||
)
|
||||
|
||||
self.row = self.merge_rects_by_coloring(self.row)
|
||||
|
||||
self.play(
|
||||
FadeIn(new_tallies[0]),
|
||||
FadeIn(new_tallies[2:]),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
# # # # # # # # # #
|
||||
# EVEN MORE FLIPS #
|
||||
# # # # # # # # # #
|
||||
|
||||
self.play(FadeOut(new_tallies))
|
||||
self.clear()
|
||||
self.add(randy, self.row)
|
||||
|
||||
|
||||
for i in range(3):
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
|
||||
self.wait()
|
||||
|
||||
previous_row = self.row.copy()
|
||||
|
||||
self.play(previous_row.shift, 1.25 * self.row.height * UP)
|
||||
|
||||
self.play(
|
||||
SplitRectsInBrickWall(self.row)
|
||||
)
|
||||
self.wait()
|
||||
self.row = self.merge_rects_by_subdiv(self.row)
|
||||
self.wait()
|
||||
self.row = self.merge_rects_by_coloring(self.row)
|
||||
self.wait()
|
||||
|
||||
self.play(FadeOut(previous_row))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
143
active_projects/eop/chapter1/entire_brick_wall.py
Normal file
143
active_projects/eop/chapter1/entire_brick_wall.py
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.chapter1.brick_row_scene import BrickRowScene
|
||||
|
||||
class EntireBrickWall(BrickRowScene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.remove(self.get_primary_pi_creature())
|
||||
|
||||
row_height = 0.3
|
||||
nb_rows = 20
|
||||
start_point = 3 * UP + 1 * LEFT
|
||||
|
||||
rows = VMobject()
|
||||
rows.add(BrickRow(0, height = row_height))
|
||||
rows.move_to(start_point)
|
||||
self.add(rows)
|
||||
|
||||
zero_counter = Integer(0).next_to(start_point + 0.5 * rows[0].width * RIGHT)
|
||||
nb_flips_text = TextMobject("\# of flips")
|
||||
nb_flips_text.next_to(zero_counter, RIGHT, buff = LARGE_BUFF)
|
||||
self.add(zero_counter, nb_flips_text)
|
||||
flip_counters = VGroup(zero_counter)
|
||||
|
||||
for i in range(1, nb_rows + 1):
|
||||
rows.add(rows[-1].copy())
|
||||
self.bring_to_back(rows[-1])
|
||||
anims = [
|
||||
rows[-1].shift, row_height * DOWN,
|
||||
Animation(rows[-2])
|
||||
]
|
||||
|
||||
if i % 5 == 0:
|
||||
counter = Integer(i)
|
||||
counter.next_to(rows[-1].get_right() + row_height * DOWN, RIGHT)
|
||||
flip_counters.add(counter)
|
||||
anims.append(FadeIn(counter))
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
self.play(SplitRectsInBrickWall(rows[-1]))
|
||||
rows.submobjects[-1] = self.merge_rects_by_subdiv(rows[-1])
|
||||
rows.submobjects[-1] = self.merge_rects_by_coloring(rows[-1])
|
||||
|
||||
|
||||
|
||||
# draw indices under the last row for the number of tails
|
||||
tails_counters = VGroup()
|
||||
for (i, rect) in enumerate(rows[-1].rects):
|
||||
if i < 6 or i > 14:
|
||||
continue
|
||||
if i == 6:
|
||||
counter = TexMobject("\dots", color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF)
|
||||
elif i == 14:
|
||||
counter = TexMobject("\dots", color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF)
|
||||
counter.shift(0.2 * RIGHT)
|
||||
else:
|
||||
counter = Integer(i, color = COLOR_TAILS)
|
||||
counter.next_to(rect, DOWN)
|
||||
tails_counters.add(counter)
|
||||
|
||||
nb_tails_text = TextMobject("\# of tails", color = COLOR_TAILS)
|
||||
nb_tails_text.next_to(tails_counters[-1], RIGHT, buff = LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, tails_counters),
|
||||
FadeIn(nb_tails_text)
|
||||
)
|
||||
|
||||
# remove any hidden brick rows
|
||||
self.clear()
|
||||
self.add(nb_flips_text)
|
||||
|
||||
mobs_to_shift = VGroup(
|
||||
rows, flip_counters, tails_counters, nb_tails_text,
|
||||
)
|
||||
self.play(mobs_to_shift.shift, 3 * UP)
|
||||
|
||||
last_row_rect = SurroundingRectangle(rows[-1], buff = 0)
|
||||
last_row_rect.set_stroke(color = YELLOW, width = 6)
|
||||
|
||||
self.play(
|
||||
rows.fade, 0.9,
|
||||
ShowCreation(last_row_rect)
|
||||
)
|
||||
|
||||
def highlighted_brick(row = 20, nb_tails = 10):
|
||||
brick_copy = rows[row].rects[nb_tails].copy()
|
||||
brick_copy.set_fill(color = YELLOW, opacity = 0.8)
|
||||
prob_percentage = float(choose(row, nb_tails)) / 2**row * 100
|
||||
brick_label = DecimalNumber(prob_percentage,
|
||||
unit = "\%", num_decimal_places = 1, color = BLACK)
|
||||
brick_label.move_to(brick_copy)
|
||||
brick_label.scale_to_fit_height(0.8 * brick_copy.get_height())
|
||||
return VGroup(brick_copy, brick_label)
|
||||
|
||||
highlighted_bricks = [
|
||||
highlighted_brick(row = 20, nb_tails = i)
|
||||
for i in range(20)
|
||||
]
|
||||
|
||||
self.play(
|
||||
FadeIn(highlighted_bricks[10])
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(highlighted_bricks[10]),
|
||||
FadeIn(highlighted_bricks[9]),
|
||||
FadeIn(highlighted_bricks[11]),
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(highlighted_bricks[9]),
|
||||
FadeOut(highlighted_bricks[11]),
|
||||
FadeIn(highlighted_bricks[8]),
|
||||
FadeIn(highlighted_bricks[12]),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
55
active_projects/eop/chapter1/intro.py
Normal file
55
active_projects/eop/chapter1/intro.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class Chapter1OpeningQuote(OpeningQuote):
|
||||
CONFIG = {
|
||||
"fade_in_kwargs": {
|
||||
"submobject_mode": "lagged_start",
|
||||
"rate_func": None,
|
||||
"lag_factor": 9,
|
||||
"run_time": 10,
|
||||
},
|
||||
"text_size" : "\\normalsize",
|
||||
"use_quotation_marks": False,
|
||||
"quote" : [
|
||||
"To see a world in a grain of sand\\\\",
|
||||
"And a heaven in a wild flower,\\\\",
|
||||
"Hold infinity in the palm of your hand\\\\",
|
||||
"\phantom{r}And eternity in an hour.\\\\"
|
||||
],
|
||||
"quote_arg_separator" : " ",
|
||||
"highlighted_quote_terms" : {},
|
||||
"author" : "William Blake: \\\\ \emph{Auguries of Innocence}",
|
||||
}
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.wait(5)
|
||||
|
||||
self.change_student_modes(
|
||||
"confused", "frustrated", "dejected",
|
||||
look_at_arg = UP + 2 * RIGHT
|
||||
)
|
||||
|
||||
self.wait()
|
||||
|
||||
|
||||
self.get_teacher().change_mode("raise_right_hand")
|
||||
self.wait()
|
||||
|
||||
self.wait(30)
|
||||
# put examples here in video editor
|
||||
|
||||
|
||||
# # # # # # # # # # # # # # # # # #
|
||||
# show examples of the area model #
|
||||
# # # # # # # # # # # # # # # # # #
|
||||
39
active_projects/eop/chapter1/just_randy_flipping_coin.py
Normal file
39
active_projects/eop/chapter1/just_randy_flipping_coin.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class JustFlipping(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E, flip_height = 1).shift(2 * DOWN)
|
||||
self.add(randy)
|
||||
|
||||
self.wait(2)
|
||||
|
||||
for i in range(10):
|
||||
self.wait()
|
||||
self.play(FlipCoin(randy))
|
||||
|
||||
|
||||
|
||||
class JustFlippingWithResults(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E, flip_height = 1).shift(2 * DOWN)
|
||||
self.add(randy)
|
||||
|
||||
self.wait(2)
|
||||
|
||||
for i in range(10):
|
||||
self.wait()
|
||||
self.play(FlipCoin(randy))
|
||||
result = random.choice(["H", "T"])
|
||||
if result == "H":
|
||||
coin = UprightHeads().scale(3)
|
||||
else:
|
||||
coin = UprightTails().scale(3)
|
||||
coin.move_to(2 * UP + 2.5 * LEFT + i * 0.6 * RIGHT)
|
||||
self.play(FadeIn(coin))
|
||||
|
||||
281
active_projects/eop/chapter1/morph_brick_row_into_histogram.py
Normal file
281
active_projects/eop/chapter1/morph_brick_row_into_histogram.py
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class GenericMorphBrickRowIntoHistogram(Scene):
|
||||
|
||||
CONFIG = {
|
||||
"level" : 3,
|
||||
"bar_width" : 2.0,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"show_tallies" : False,
|
||||
"show_nb_flips" : True
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.row = BrickRow(self.level, height = self.bar_width, width = 10)
|
||||
self.bars = OutlineableBars(*[self.row.rects[i] for i in range(self.level + 1)])
|
||||
self.bar_anchors = [self.bar_anchor_height * UP + self.row.height * (i - 0.5 * self.level) * RIGHT for i in range(self.level + 1)]
|
||||
|
||||
self.add(self.row)
|
||||
|
||||
if self.show_tallies:
|
||||
|
||||
tallies = VMobject()
|
||||
|
||||
for (i,brick) in enumerate(self.row.rects):
|
||||
tally = TallyStack(self.level - i, i)
|
||||
tally.move_to(brick)
|
||||
self.add(tally)
|
||||
tallies.add(tally)
|
||||
brick.set_stroke(width = 3)
|
||||
|
||||
if self.show_nb_flips:
|
||||
nb_flips_text = TextMobject("\# of flips: " + str(self.level))
|
||||
nb_flips_text.to_corner(UR)
|
||||
self.add(nb_flips_text)
|
||||
|
||||
self.remove(self.row.subdivs, self.row.border)
|
||||
|
||||
for rect in self.row.rects:
|
||||
rect.set_stroke(color = WHITE, width = 3)
|
||||
|
||||
self.play(self.row.rects.space_out_submobjects, {"factor" : 1.3})
|
||||
|
||||
anims = []
|
||||
for brick in self.row.rects:
|
||||
anims.append(brick.rotate)
|
||||
anims.append(TAU/4)
|
||||
|
||||
if self.show_tallies:
|
||||
anims.append(FadeOut(tallies))
|
||||
self.play(*anims)
|
||||
|
||||
|
||||
anims = []
|
||||
for (i,brick) in enumerate(self.row.rects):
|
||||
anims.append(brick.next_to)
|
||||
anims.append(self.bar_anchors[i])
|
||||
anims.append({"direction" : UP, "buff" : 0})
|
||||
self.play(*anims)
|
||||
|
||||
self.bars.create_outline()
|
||||
anims = [
|
||||
ApplyMethod(rect.set_stroke, {"width" : 0})
|
||||
for rect in self.bars
|
||||
]
|
||||
anims.append(FadeIn(self.bars.outline))
|
||||
self.play(*anims)
|
||||
|
||||
|
||||
|
||||
class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram):
|
||||
|
||||
CONFIG = {
|
||||
"level" : 3,
|
||||
"prob_denominator" : 8,
|
||||
"bar_width" : 2.0,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"show_tallies" : True,
|
||||
"show_nb_flips" : False
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
super(MorphBrickRowIntoHistogram3,self).construct()
|
||||
|
||||
|
||||
# draw x-axis
|
||||
|
||||
x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0)
|
||||
x_axis.next_to(self.bars, DOWN, buff = 0)
|
||||
#x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)])
|
||||
x_labels = VMobject()
|
||||
|
||||
for (i, bar) in enumerate(self.bars):
|
||||
label = Integer(i)
|
||||
label.next_to(self.bar_anchors[i], DOWN)
|
||||
x_labels.add(label)
|
||||
|
||||
nb_tails_label = TextMobject("\# of tails")
|
||||
nb_tails_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF)
|
||||
|
||||
|
||||
|
||||
# draw y-guides
|
||||
|
||||
y_guides = VMobject()
|
||||
for i in range(0,self.prob_denominator + 1):
|
||||
y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY)
|
||||
y_guide.move_to(self.bar_anchor_height * UP + i * float(self.row.width) / self.prob_denominator * UP)
|
||||
y_guide_label = TexMobject("{" + str(i) + "\over " + str(self.prob_denominator) + "}", color = GRAY)
|
||||
y_guide_label.scale(0.7)
|
||||
y_guide_label.next_to(y_guide, LEFT)
|
||||
if i != 0:
|
||||
y_guide.add(y_guide_label)
|
||||
y_guides.add(y_guide)
|
||||
|
||||
self.play(
|
||||
FadeIn(y_guides),
|
||||
Animation(self.bars.outline),
|
||||
Animation(self.bars)
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeIn(x_axis),
|
||||
FadeIn(x_labels),
|
||||
FadeIn(nb_tails_label)
|
||||
)
|
||||
|
||||
self.add_foreground_mobject(nb_tails_label)
|
||||
area_color = YELLOW
|
||||
|
||||
total_area_text = TextMobject("total area =", color = area_color)
|
||||
area_decimal = DecimalNumber(0, color = area_color, num_decimal_places = 3)
|
||||
area_decimal.next_to(total_area_text, RIGHT)
|
||||
|
||||
total_area_group = VGroup(total_area_text, area_decimal)
|
||||
total_area_group.move_to(2.7 * UP)
|
||||
|
||||
self.play(
|
||||
FadeIn(total_area_text),
|
||||
)
|
||||
|
||||
cumulative_areas = [0.125, 0.5, 0.875, 1]
|
||||
covering_rects = self.bars.copy()
|
||||
for (i,rect) in enumerate(covering_rects):
|
||||
rect.set_fill(color = area_color, opacity = 0.5)
|
||||
self.play(
|
||||
FadeIn(rect, rate_func = linear),
|
||||
ChangeDecimalToValue(area_decimal, cumulative_areas[i],
|
||||
rate_func = linear)
|
||||
)
|
||||
self.wait(0.2)
|
||||
|
||||
self.wait()
|
||||
|
||||
total_area_rect = SurroundingRectangle(
|
||||
total_area_group,
|
||||
buff = MED_SMALL_BUFF,
|
||||
stroke_color = area_color
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(covering_rects),
|
||||
ShowCreation(total_area_rect)
|
||||
)
|
||||
|
||||
|
||||
|
||||
class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram):
|
||||
CONFIG = {
|
||||
"level" : 20,
|
||||
"prob_ticks" : 0.05,
|
||||
"bar_width" : 0.5,
|
||||
"bar_anchor_height" : -3.0,
|
||||
"x_ticks": 5
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
super(MorphBrickRowIntoHistogram20, self).construct()
|
||||
|
||||
x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0)
|
||||
x_axis.next_to(self.bars, DOWN, buff = 0)
|
||||
#x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)])
|
||||
x_labels = VMobject()
|
||||
for (i, bar) in enumerate(self.bars):
|
||||
if i % self.x_ticks != 0:
|
||||
continue
|
||||
label = Integer(i)
|
||||
label.next_to(self.bar_anchors[i], DOWN)
|
||||
x_labels.add(label)
|
||||
|
||||
nb_tails_label = TextMobject("\# of tails")
|
||||
nb_tails_label.move_to(5 * RIGHT + 2.5 * DOWN)
|
||||
|
||||
self.play(
|
||||
FadeIn(x_axis),
|
||||
FadeIn(x_labels),
|
||||
FadeIn(nb_tails_label)
|
||||
)
|
||||
|
||||
# draw y-guides
|
||||
|
||||
max_prob = float(choose(self.level, self.level/2)) / 2 ** self.level
|
||||
|
||||
y_guides = VMobject()
|
||||
y_guide_heights = []
|
||||
prob_grid = np.arange(self.prob_ticks, 1.3 * max_prob, self.prob_ticks)
|
||||
for i in prob_grid:
|
||||
y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY)
|
||||
y_guide_height = self.bar_anchor_height + i * float(self.row.width)
|
||||
y_guide_heights.append(y_guide_height)
|
||||
y_guide.move_to(y_guide_height * UP)
|
||||
y_guide_label = DecimalNumber(i, num_decimal_places = 2, color = GRAY)
|
||||
y_guide_label.scale(0.7)
|
||||
y_guide_label.next_to(y_guide, LEFT)
|
||||
y_guide.add(y_guide_label)
|
||||
y_guides.add(y_guide)
|
||||
|
||||
self.bring_to_back(y_guides)
|
||||
self.play(FadeIn(y_guides), Animation(self.bars))
|
||||
|
||||
histogram_width = self.bars.get_width()
|
||||
histogram_height = self.bars.get_height()
|
||||
|
||||
# scale to fit screen
|
||||
self.scale_x = 10.0/((len(self.bars) - 1) * self.bar_width)
|
||||
self.scale_y = 6.0/histogram_height
|
||||
|
||||
|
||||
anims = []
|
||||
for (bar, x_label) in zip(self.bars, x_labels):
|
||||
v = (self.scale_x - 1) * x_label.get_center()[0] * RIGHT
|
||||
anims.append(x_label.shift)
|
||||
anims.append(v)
|
||||
|
||||
|
||||
anims.append(self.bars.stretch_about_point)
|
||||
anims.append(self.scale_x)
|
||||
anims.append(0)
|
||||
anims.append(ORIGIN)
|
||||
anims.append(self.bars.outline.stretch_about_point)
|
||||
anims.append(self.scale_x)
|
||||
anims.append(0)
|
||||
anims.append(ORIGIN)
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
anims = []
|
||||
for (guide, i, h) in zip(y_guides, prob_grid, y_guide_heights):
|
||||
new_y_guide_height = self.bar_anchor_height + i * self.scale_y * float(self.row.width)
|
||||
v = (new_y_guide_height - h) * UP
|
||||
anims.append(guide.shift)
|
||||
anims.append(v)
|
||||
|
||||
anims.append(self.bars.stretch_about_point)
|
||||
anims.append(self.scale_y)
|
||||
anims.append(1)
|
||||
anims.append(self.bars.get_bottom())
|
||||
anims.append(self.bars.outline.stretch_about_point)
|
||||
anims.append(self.scale_y)
|
||||
anims.append(1)
|
||||
anims.append(self.bars.get_bottom())
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
class MorphBrickRowIntoHistogram100(MorphBrickRowIntoHistogram20):
|
||||
CONFIG = {
|
||||
"level" : 100,
|
||||
"x_ticks": 20,
|
||||
"prob_ticks": 0.02
|
||||
}
|
||||
|
||||
class MorphBrickRowIntoHistogram500(MorphBrickRowIntoHistogram20):
|
||||
CONFIG = {
|
||||
"level" : 500,
|
||||
"x_ticks": 100,
|
||||
"prob_ticks": 0.01
|
||||
}
|
||||
268
active_projects/eop/chapter1/prob_dist_visuals.py
Normal file
268
active_projects/eop/chapter1/prob_dist_visuals.py
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class ProbabilityDistributions(PiCreatureScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": False,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
lag_ratio = 0.2
|
||||
run_time = 3
|
||||
|
||||
|
||||
text = TextMobject("Probability distributions", color = YELLOW)
|
||||
text.to_edge(UP)
|
||||
text_rect = SurroundingRectangle(text, buff = MED_SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
FadeIn(text),
|
||||
ShowCreation(text_rect)
|
||||
)
|
||||
|
||||
|
||||
# WEATHER FORECAST
|
||||
|
||||
|
||||
unit_rect = Rectangle(
|
||||
height = 3, width = 3
|
||||
).shift(DOWN)
|
||||
|
||||
p_rain = 0.23
|
||||
p_sun = 1 - p_rain
|
||||
opacity = 0.7
|
||||
|
||||
rain_rect = unit_rect.copy().stretch(p_rain, 0)
|
||||
rain_rect.align_to(unit_rect, LEFT)
|
||||
rain_rect.set_fill(color = BLUE, opacity = opacity)
|
||||
rain_rect.set_stroke(width = 0)
|
||||
|
||||
sun_rect = unit_rect.copy().stretch(p_sun, 0)
|
||||
sun_rect.next_to(rain_rect, RIGHT, buff = 0)
|
||||
sun_rect.set_fill(color = YELLOW, opacity = opacity)
|
||||
sun_rect.set_stroke(width = 0)
|
||||
|
||||
self.play(FadeIn(VGroup(unit_rect, rain_rect, sun_rect)))
|
||||
|
||||
rain = SVGMobject(file_name = "rain").scale(0.35)
|
||||
sun = SVGMobject(file_name = "sun").scale(0.35)
|
||||
|
||||
rain.flip().move_to(rain_rect)
|
||||
sun.move_to(sun_rect)
|
||||
|
||||
self.add(rain, sun)
|
||||
|
||||
text_scale = 0.7
|
||||
|
||||
brace_rain = Brace(rain_rect, UP)
|
||||
p_rain_label = TextMobject("$P($rain$)=$").scale(text_scale)
|
||||
p_rain_decimal = DecimalNumber(p_rain).scale(text_scale)
|
||||
p_rain_decimal.next_to(p_rain_label)
|
||||
p_rain_whole_label = VGroup(p_rain_label, p_rain_decimal)
|
||||
p_rain_whole_label.next_to(brace_rain, UP)
|
||||
|
||||
brace_sun = Brace(sun_rect, DOWN)
|
||||
p_sun_label = TextMobject("$P($sunshine$)=$").scale(text_scale)
|
||||
p_sun_decimal = DecimalNumber(p_sun).scale(text_scale)
|
||||
p_sun_decimal.next_to(p_sun_label)
|
||||
p_sun_whole_label = VGroup(p_sun_label, p_sun_decimal)
|
||||
p_sun_whole_label.next_to(brace_sun, DOWN)
|
||||
|
||||
self.add(brace_rain, p_rain_whole_label, brace_sun, p_sun_whole_label)
|
||||
|
||||
|
||||
|
||||
|
||||
new_p_rain = 0.68
|
||||
new_p_sun = 1 - new_p_rain
|
||||
|
||||
new_rain_rect = unit_rect.copy().stretch(new_p_rain, 0)
|
||||
new_rain_rect.align_to(unit_rect, LEFT)
|
||||
new_rain_rect.set_fill(color = BLUE, opacity = opacity)
|
||||
new_rain_rect.set_stroke(width = 0)
|
||||
|
||||
new_sun_rect = unit_rect.copy().stretch(new_p_sun, 0)
|
||||
new_sun_rect.next_to(new_rain_rect, RIGHT, buff = 0)
|
||||
new_sun_rect.set_fill(color = YELLOW, opacity = opacity)
|
||||
new_sun_rect.set_stroke(width = 0)
|
||||
|
||||
new_rain = SVGMobject(file_name = "rain").scale(0.35)
|
||||
new_sun = SVGMobject(file_name = "sun").scale(0.35)
|
||||
|
||||
new_rain.flip().move_to(new_rain_rect)
|
||||
new_sun.move_to(new_sun_rect)
|
||||
|
||||
new_brace_rain = Brace(new_rain_rect, UP)
|
||||
new_p_rain_label = TextMobject("$P($rain$)=$").scale(text_scale)
|
||||
new_p_rain_decimal = DecimalNumber(new_p_rain).scale(text_scale)
|
||||
new_p_rain_decimal.next_to(new_p_rain_label)
|
||||
new_p_rain_whole_label = VGroup(new_p_rain_label, new_p_rain_decimal)
|
||||
new_p_rain_whole_label.next_to(new_brace_rain, UP)
|
||||
|
||||
|
||||
new_brace_sun = Brace(new_sun_rect, DOWN)
|
||||
new_p_sun_label = TextMobject("$P($sunshine$)=$").scale(text_scale)
|
||||
new_p_sun_decimal = DecimalNumber(new_p_sun).scale(text_scale)
|
||||
new_p_sun_decimal.next_to(new_p_sun_label)
|
||||
new_p_sun_whole_label = VGroup(new_p_sun_label, new_p_sun_decimal)
|
||||
new_p_sun_whole_label.next_to(new_brace_sun, DOWN)
|
||||
|
||||
def rain_update_func(alpha):
|
||||
return alpha * new_p_rain + (1 - alpha) * p_rain
|
||||
|
||||
def sun_update_func(alpha):
|
||||
return 1 - rain_update_func(alpha)
|
||||
|
||||
update_p_rain = ChangingDecimal(
|
||||
p_rain_decimal, rain_update_func,
|
||||
tracked_mobject = p_rain_label,
|
||||
run_time = run_time
|
||||
)
|
||||
update_p_sun = ChangingDecimal(
|
||||
p_sun_decimal, sun_update_func,
|
||||
tracked_mobject = p_sun_label,
|
||||
run_time = run_time
|
||||
)
|
||||
|
||||
self.play(
|
||||
Transform(rain_rect, new_rain_rect, run_time = run_time),
|
||||
Transform(sun_rect, new_sun_rect, run_time = run_time),
|
||||
Transform(rain, new_rain, run_time = run_time),
|
||||
Transform(sun, new_sun, run_time = run_time),
|
||||
Transform(brace_rain, new_brace_rain, run_time = run_time),
|
||||
Transform(brace_sun, new_brace_sun, run_time = run_time),
|
||||
Transform(p_rain_label, new_p_rain_label, run_time = run_time),
|
||||
Transform(p_sun_label, new_p_sun_label, run_time = run_time),
|
||||
update_p_rain,
|
||||
update_p_sun
|
||||
)
|
||||
|
||||
|
||||
|
||||
# move the forecast into a corner
|
||||
|
||||
forecast = VGroup(
|
||||
rain_rect, sun_rect, rain, sun, brace_rain, brace_sun,
|
||||
p_rain_whole_label, p_sun_whole_label, unit_rect
|
||||
)
|
||||
|
||||
forecast.target = forecast.copy().scale(0.5)
|
||||
forecast.target.to_corner(UL)
|
||||
|
||||
self.play(MoveToTarget(forecast))
|
||||
|
||||
self.play(
|
||||
FadeOut(brace_rain),
|
||||
FadeOut(brace_sun),
|
||||
FadeOut(p_rain_whole_label),
|
||||
FadeOut(p_sun_whole_label),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# COIN FLIP
|
||||
|
||||
|
||||
coin_flip_rect = BrickRow(3, height = 2, width = 10)
|
||||
|
||||
for (i, brick) in enumerate(coin_flip_rect.rects):
|
||||
tally = TallyStack(3 - i, i)
|
||||
tally.move_to(brick)
|
||||
coin_flip_rect.add(tally)
|
||||
|
||||
coin_flip_rect.scale(0.8).shift(2*RIGHT)
|
||||
self.play(FadeIn(coin_flip_rect))
|
||||
|
||||
counts = [1, 3, 3, 1]
|
||||
braces = VGroup()
|
||||
labels = VGroup()
|
||||
for (rect, count) in zip(coin_flip_rect.rects, counts):
|
||||
label = TexMobject("{" + str(count) + "\over 8}").scale(0.5)
|
||||
brace = Brace(rect, DOWN)
|
||||
label.next_to(brace, DOWN)
|
||||
braces.add(brace)
|
||||
labels.add(label)
|
||||
|
||||
self.play(
|
||||
LaggedStart(ShowCreation, braces, lag_ratio = lag_ratio, run_time = run_time),
|
||||
LaggedStart(Write, labels, lag_ratio = lag_ratio, run_time = run_time)
|
||||
)
|
||||
|
||||
coin_flip_rect.add(braces, labels)
|
||||
|
||||
coin_flip_rect.target = coin_flip_rect.copy().scale(0.6)
|
||||
coin_flip_rect.target.to_corner(UR, buff = MED_LARGE_BUFF)
|
||||
coin_flip_rect.target.shift(DOWN)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(coin_flip_rect)
|
||||
)
|
||||
self.play(
|
||||
FadeOut(braces),
|
||||
FadeOut(labels)
|
||||
)
|
||||
|
||||
|
||||
# DOUBLE DICE THROW
|
||||
|
||||
cell_size = 0.5
|
||||
dice_table = TwoDiceTable(cell_size = cell_size, label_scale = 0.7)
|
||||
dice_table.shift(0.8 * DOWN)
|
||||
dice_unit_rect = SurroundingRectangle(dice_table.cells, buff = 0,
|
||||
stroke_color = WHITE)
|
||||
|
||||
dice_table_grouped_cells = VGroup()
|
||||
|
||||
for i in range(6):
|
||||
cell = dice_table.cells[6 * i]
|
||||
start = cell.get_center()
|
||||
stop = start + cell_size * LEFT + cell_size * DOWN
|
||||
|
||||
dice_table_grouped_cells.add(VGroup(*[
|
||||
dice_table.cells[6 * i - 5 * k]
|
||||
for k in range(i + 1)
|
||||
]))
|
||||
|
||||
for i in range(5):
|
||||
cell = dice_table.cells[31 + i]
|
||||
start = cell.get_center()
|
||||
stop = start + cell_size * LEFT + cell_size * DOWN
|
||||
|
||||
dice_table_grouped_cells.add(VGroup(*[
|
||||
dice_table.cells[31 + i - 5 * k]
|
||||
for k in range(5 - i)
|
||||
]))
|
||||
|
||||
self.play(
|
||||
FadeIn(dice_unit_rect),
|
||||
FadeIn(dice_table.rows)
|
||||
)
|
||||
|
||||
for (cell, label) in zip(dice_table.cells, dice_table.labels):
|
||||
cell.add(label)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, dice_table_grouped_cells,
|
||||
lag_ratio = lag_ratio, run_time = run_time)
|
||||
)
|
||||
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(dice_table.rows),
|
||||
FadeOut(dice_unit_rect),
|
||||
)
|
||||
|
||||
|
||||
self.play(
|
||||
dice_table_grouped_cells.space_out_submobjects, {"factor" : 1.9},
|
||||
rate_func=there_and_back_with_pause,
|
||||
run_time=run_time
|
||||
)
|
||||
224
active_projects/eop/chapter1/quiz_result.py
Normal file
224
active_projects/eop/chapter1/quiz_result.py
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.independence import *
|
||||
|
||||
from for_3b1b_videos.pi_class import PiCreatureClass
|
||||
|
||||
class QuizResult(PiCreatureScene):
|
||||
CONFIG = {
|
||||
"pi_creatures_start_on_screen" : False,
|
||||
"random_seed" : 6
|
||||
}
|
||||
def construct(self):
|
||||
|
||||
|
||||
def get_example_quiz():
|
||||
quiz = get_quiz(
|
||||
"Define ``Brachistochrone'' ",
|
||||
"Define ``Tautochrone'' ",
|
||||
"Define ``Cycloid'' ",
|
||||
)
|
||||
rect = SurroundingRectangle(quiz, buff = 0)
|
||||
rect.set_fill(color = BLACK, opacity = 1)
|
||||
rect.set_stroke(width = 0)
|
||||
quiz.add_to_back(rect)
|
||||
return quiz
|
||||
|
||||
|
||||
highlight_color = WHITE
|
||||
|
||||
nb_students_x = 5
|
||||
nb_students_y = 3
|
||||
spacing_students_x = 2.0
|
||||
spacing_students_y = 2.2
|
||||
|
||||
all_students = PiCreatureClass(
|
||||
width = nb_students_x, height = nb_students_y)# VGroup()
|
||||
student_points = []
|
||||
grades = []
|
||||
grades_count = []
|
||||
hist_y_values = np.zeros(4)
|
||||
for i in range(nb_students_x):
|
||||
for j in range(nb_students_y):
|
||||
x = i * spacing_students_x
|
||||
y = j * spacing_students_y
|
||||
#pi = PiCreature().scale(0.3)
|
||||
#pi.move_to([x,y,0])
|
||||
#all_students.add(pi)
|
||||
all_students[i*nb_students_y + j].move_to([x,y,0])
|
||||
q1 = np.random.choice([True, False])
|
||||
q2 = np.random.choice([True, False])
|
||||
q3 = np.random.choice([True, False])
|
||||
student_points.append([q1, q2, q3])
|
||||
grade = q1*1+q2*1+q3*1
|
||||
grades.append(grade)
|
||||
hist_y_values[grade] += 1
|
||||
# How many times has this grade already occured?
|
||||
grade_count = grades.count(grade)
|
||||
grades_count.append(grade_count)
|
||||
|
||||
|
||||
all_students.move_to(ORIGIN)
|
||||
self.pi_creatures = all_students
|
||||
self.play(FadeIn(all_students))
|
||||
|
||||
all_quizzes = VGroup()
|
||||
|
||||
quiz = get_example_quiz().scale(0.2)
|
||||
for pi in all_students:
|
||||
quiz_copy = quiz.copy()
|
||||
quiz_copy.next_to(pi, UP)
|
||||
all_quizzes.add(quiz_copy)
|
||||
|
||||
master_quiz = get_example_quiz()
|
||||
self.play(ShowCreation(master_quiz))
|
||||
self.play(Transform(master_quiz, all_quizzes[0]))
|
||||
|
||||
self.play(LaggedStart(FadeIn,all_quizzes))
|
||||
|
||||
grades_mob = VGroup()
|
||||
for (pi, quiz, grade) in zip(all_students, all_quizzes, grades):
|
||||
grade_mob = TexMobject(str(grade) + "/3")
|
||||
grade_mob.move_to(quiz)
|
||||
grades_mob.add(grade_mob)
|
||||
|
||||
self.remove(master_quiz)
|
||||
self.play(
|
||||
FadeOut(all_quizzes),
|
||||
FadeIn(grades_mob)
|
||||
)
|
||||
|
||||
# self.play(
|
||||
# all_students[2:].fade, 0.8,
|
||||
# grades_mob[2:].fade, 0.8
|
||||
# )
|
||||
|
||||
students_points_mob = VGroup()
|
||||
for (pi, quiz, points) in zip(all_students, all_quizzes, student_points):
|
||||
slot = get_slot_group(points, include_qs = False)
|
||||
slot.scale(0.5).move_to(quiz)
|
||||
students_points_mob.add(slot)
|
||||
|
||||
self.play(
|
||||
#all_students.fade, 0,
|
||||
FadeOut(grades_mob),
|
||||
FadeIn(students_points_mob)
|
||||
)
|
||||
|
||||
|
||||
|
||||
anims = []
|
||||
anchor_point = 3 * DOWN + 1 * LEFT
|
||||
for (pi, grade, grades_count) in zip(all_students, grades, grades_count):
|
||||
anims.append(pi.move_to)
|
||||
anims.append(anchor_point + grade * RIGHT + grades_count * UP)
|
||||
anims.append(FadeOut(students_points_mob))
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
grade_labels = VGroup()
|
||||
for i in range(4):
|
||||
grade_label = Integer(i, color = highlight_color)
|
||||
grade_label.move_to(i * RIGHT)
|
||||
grade_labels.add(grade_label)
|
||||
grade_labels.next_to(all_students, DOWN)
|
||||
out_of_label = TextMobject("out of 3", color = highlight_color)
|
||||
out_of_label.next_to(grade_labels, RIGHT, buff = MED_LARGE_BUFF)
|
||||
grade_labels.add(out_of_label)
|
||||
self.play(Write(grade_labels))
|
||||
|
||||
grade_hist = Histogram(
|
||||
np.ones(4),
|
||||
hist_y_values,
|
||||
mode = "widths",
|
||||
x_labels = "none",
|
||||
y_label_position = "center",
|
||||
bar_stroke_width = 0,
|
||||
outline_stroke_width = 5
|
||||
)
|
||||
grade_hist.move_to(all_students)
|
||||
|
||||
self.play(
|
||||
FadeIn(grade_hist),
|
||||
FadeOut(all_students)
|
||||
)
|
||||
|
||||
|
||||
nb_students_label = TextMobject("\# of students", color = highlight_color)
|
||||
nb_students_label.move_to(5 * LEFT + 2 * UP)
|
||||
arrows = VGroup(*[
|
||||
Arrow(nb_students_label.get_right(), grade_hist.bars[i].get_center(),
|
||||
color = highlight_color)
|
||||
for i in range(4)
|
||||
])
|
||||
self.play(Write(nb_students_label), LaggedStart(GrowArrow,arrows))
|
||||
|
||||
percentage_label = TextMobject("\% of students", color = highlight_color)
|
||||
percentage_label.move_to(nb_students_label)
|
||||
percentages = hist_y_values / (nb_students_x * nb_students_y) * 100
|
||||
anims = []
|
||||
for (label, percentage) in zip(grade_hist.y_labels_group, percentages):
|
||||
new_label = DecimalNumber(percentage,
|
||||
num_decimal_places = 1,
|
||||
unit = "\%",
|
||||
color = highlight_color
|
||||
)
|
||||
new_label.scale(0.7)
|
||||
new_label.move_to(label)
|
||||
anims.append(Transform(label, new_label))
|
||||
anims.append(ReplacementTransform(nb_students_label, percentage_label))
|
||||
self.play(*anims)
|
||||
|
||||
self.remove(all_quizzes)
|
||||
# put small copy of class in corner
|
||||
for (i,pi) in enumerate(all_students):
|
||||
x = i % 5
|
||||
y = i / 5
|
||||
pi.move_to(x * RIGHT + y * UP)
|
||||
all_students.scale(0.8)
|
||||
all_students.to_corner(DOWN + LEFT)
|
||||
self.play(FadeIn(all_students))
|
||||
|
||||
prob_label = TextMobject("probability", color = highlight_color)
|
||||
prob_label.move_to(percentage_label)
|
||||
self.play(
|
||||
all_students[8].set_color, MAROON_E,
|
||||
#all_students[:8].fade, 0.6,
|
||||
#all_students[9:].fade, 0.6,
|
||||
ReplacementTransform(percentage_label, prob_label)
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeOut(prob_label),
|
||||
FadeOut(arrows)
|
||||
)
|
||||
|
||||
flash_hist = FlashThroughHistogram(
|
||||
grade_hist,
|
||||
direction = "vertical",
|
||||
mode = "random",
|
||||
cell_opacity = 0.5,
|
||||
run_time = 5,
|
||||
rate_func = linear
|
||||
)
|
||||
|
||||
flash_class = FlashThroughClass(
|
||||
all_students,
|
||||
mode = "random",
|
||||
highlight_color = MAROON_E,
|
||||
run_time = 5,
|
||||
rate_func = linear
|
||||
)
|
||||
|
||||
for i in range(3):
|
||||
self.play(flash_hist, flash_class)
|
||||
self.remove(flash_hist.prototype_cell)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
45
active_projects/eop/chapter1/show_uncertainty_darts.py
Normal file
45
active_projects/eop/chapter1/show_uncertainty_darts.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
class ShowUncertaintyDarts(Scene):
|
||||
|
||||
|
||||
def throw_darts(self, n, run_time = 1):
|
||||
|
||||
points = np.random.normal(
|
||||
loc = self.dartboard.get_center(),
|
||||
scale = 0.6 * np.ones(3),
|
||||
size = (n,3)
|
||||
)
|
||||
points[:,2] = 0
|
||||
dots = VGroup()
|
||||
for point in points:
|
||||
dot = Dot(point, radius = 0.04, fill_opacity = 0.7)
|
||||
dots.add(dot)
|
||||
self.add(dot)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, dots, lag_ratio = 0.01, run_time = run_time)
|
||||
)
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.dartboard = ImageMobject("dartboard").scale(2)
|
||||
dartboard_circle = Circle(
|
||||
radius = self.dartboard.get_width() / 2,
|
||||
fill_color = BLACK,
|
||||
fill_opacity = 0.5,
|
||||
stroke_color = WHITE,
|
||||
stroke_width = 5
|
||||
)
|
||||
self.dartboard.add(dartboard_circle)
|
||||
|
||||
self.add(self.dartboard)
|
||||
|
||||
self.throw_darts(5,5)
|
||||
self.throw_darts(20,5)
|
||||
self.throw_darts(100,5)
|
||||
self.throw_darts(1000,5)
|
||||
|
||||
63
active_projects/eop/chapter1/show_uncertainty_dice.py
Normal file
63
active_projects/eop/chapter1/show_uncertainty_dice.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
class ShowUncertaintyDice(Scene):
|
||||
|
||||
def throw_a_die(self, run_time = 0.3):
|
||||
|
||||
eye = np.random.randint(1,7)
|
||||
face = self.row_of_dice.submobjects[eye - 1]
|
||||
|
||||
self.play(
|
||||
ApplyMethod(face.submobjects[0].set_fill, {"opacity": 1},
|
||||
rate_func = there_and_back,
|
||||
run_time = run_time,
|
||||
),
|
||||
)
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.row_of_dice = RowOfDice(direction = DOWN).scale(0.5)
|
||||
self.add(self.row_of_dice)
|
||||
|
||||
for i in range(5):
|
||||
self.throw_a_die()
|
||||
self.wait(1)
|
||||
|
||||
for i in range(10):
|
||||
self.throw_a_die()
|
||||
self.wait(0.3)
|
||||
|
||||
for i in range(100):
|
||||
self.throw_a_die(0.05)
|
||||
self.wait(0.0)
|
||||
|
||||
|
||||
|
||||
class IdealizedDieHistogram(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
self.probs = 1.0/6 * np.ones(6)
|
||||
x_scale = 1.3
|
||||
|
||||
y_labels = ["${1\over 6}$"] * 6
|
||||
|
||||
hist = Histogram(np.ones(6), self.probs,
|
||||
mode = "widths",
|
||||
x_labels = "none",
|
||||
y_labels = y_labels,
|
||||
y_label_position = "center",
|
||||
y_scale = 20,
|
||||
x_scale = x_scale,
|
||||
)
|
||||
hist.rotate(-TAU/4)
|
||||
|
||||
for label in hist.y_labels_group:
|
||||
label.rotate(TAU/4)
|
||||
hist.remove(hist.y_labels_group)
|
||||
|
||||
|
||||
self.play(FadeIn(hist))
|
||||
self.play(LaggedStart(FadeIn, hist.y_labels_group))
|
||||
|
||||
104
active_projects/eop/chapter1/show_uncertainty_disease.py
Normal file
104
active_projects/eop/chapter1/show_uncertainty_disease.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
|
||||
|
||||
|
||||
class RandyIsSickOrNot(Scene):
|
||||
|
||||
|
||||
def construct(self):
|
||||
title = TextMobject("1 in 200")
|
||||
title.to_edge(UP)
|
||||
|
||||
|
||||
randy = SicklyPiCreature()
|
||||
randy.scale_to_fit_height(3)
|
||||
randy.move_to(2*LEFT)
|
||||
randy.change_mode("plain")
|
||||
randy.set_color(BLUE)
|
||||
randy.save_state()
|
||||
|
||||
self.add(randy)
|
||||
|
||||
p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%").scale(1.7)
|
||||
p_sick.set_color_by_tex("sick", SICKLY_GREEN)
|
||||
p_sick.next_to(randy, UP, buff = LARGE_BUFF)
|
||||
self.add(p_sick)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.wait(2)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_sick)
|
||||
)
|
||||
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
|
||||
self.play(randy.get_better)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.wait(0.5)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.get_sick)
|
||||
)
|
||||
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.get_better)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
|
||||
class OneIn200HasDisease(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("1 in 200")
|
||||
title.to_edge(UP)
|
||||
creature = PiCreature()
|
||||
|
||||
all_creatures = VGroup(*[
|
||||
VGroup(*[
|
||||
creature.copy()
|
||||
for y in range(20)
|
||||
]).arrange_submobjects(DOWN, SMALL_BUFF)
|
||||
for x in range(10)
|
||||
]).arrange_submobjects(RIGHT, SMALL_BUFF)
|
||||
all_creatures.scale_to_fit_height(FRAME_HEIGHT * 0.8)
|
||||
all_creatures.next_to(title, DOWN)
|
||||
randy = all_creatures[0][0]
|
||||
all_creatures[0].remove(randy)
|
||||
randy.change_mode("sick")
|
||||
randy.set_color(SICKLY_GREEN)
|
||||
randy.save_state()
|
||||
randy.scale_to_fit_height(3)
|
||||
randy.center()
|
||||
randy.change_mode("plain")
|
||||
randy.set_color(BLUE)
|
||||
|
||||
self.add(randy)
|
||||
|
||||
#p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%")
|
||||
#p_sick.set_color_by_tex("sick", SICKLY_GREEN)
|
||||
#p_sick.next_to(randy, RIGHT+UP)
|
||||
#self.add(p_sick)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
randy.change_mode, "sick",
|
||||
randy.set_color, SICKLY_GREEN
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.restore)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(title),
|
||||
LaggedStart(FadeIn, all_creatures, run_time = 3)
|
||||
)
|
||||
self.wait()
|
||||
132
active_projects/eop/chapter1/various_intro_visuals.py
Normal file
132
active_projects/eop/chapter1/various_intro_visuals.py
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusable_imports import *
|
||||
from active_projects.eop.combinations import *
|
||||
from active_projects.eop.independence import *
|
||||
|
||||
import itertools as it
|
||||
|
||||
class RandyFlipsAndStacks(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E)
|
||||
randy.scale(0.5).to_edge(LEFT + DOWN)
|
||||
|
||||
heads = tails = 0
|
||||
tally = TallyStack(heads, tails, anchor = ORIGIN)
|
||||
|
||||
nb_flips = 10
|
||||
|
||||
flips = np.random.randint(2, size = nb_flips)
|
||||
|
||||
for i in range(nb_flips):
|
||||
|
||||
self.play(FlipCoin(randy))
|
||||
self.wait(0.5)
|
||||
|
||||
flip = flips[i]
|
||||
if flip == 0:
|
||||
heads += 1
|
||||
elif flip == 1:
|
||||
tails += 1
|
||||
else:
|
||||
raise Exception("That side does not exist on this coin")
|
||||
|
||||
new_tally = TallyStack(heads, tails, anchor = ORIGIN)
|
||||
|
||||
if tally.nb_heads == 0 and new_tally.nb_heads == 1:
|
||||
self.play(FadeIn(new_tally.heads_stack))
|
||||
elif tally.nb_tails == 0 and new_tally.nb_tails == 1:
|
||||
self.play(FadeIn(new_tally.tails_stack))
|
||||
else:
|
||||
self.play(Transform(tally, new_tally))
|
||||
|
||||
tally = new_tally
|
||||
|
||||
|
||||
|
||||
class TwoDiceTableScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
table = TwoDiceTable(cell_size = 1)
|
||||
|
||||
table.center()
|
||||
self.add(table)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class VisualCovariance(Scene):
|
||||
|
||||
|
||||
def construct(self):
|
||||
|
||||
size = 4
|
||||
square = Square(side_length = size)
|
||||
n_points = 30
|
||||
cloud = VGroup(*[
|
||||
Dot((x + 0.8*y) * RIGHT + y * UP).set_fill(WHITE, 1)
|
||||
for x, y in zip(
|
||||
np.random.normal(0, 1, n_points),
|
||||
np.random.normal(0, 1, n_points)
|
||||
)
|
||||
])
|
||||
self.add_foreground_mobject(cloud)
|
||||
|
||||
x_axis = Vector(8*RIGHT, color = WHITE).move_to(2.5*DOWN)
|
||||
y_axis = Vector(5*UP, color = WHITE).move_to(4*LEFT)
|
||||
|
||||
self.add(x_axis, y_axis)
|
||||
|
||||
|
||||
random_pairs = [ (p1, p2) for (p1, p2) in
|
||||
it.combinations(cloud, 2)
|
||||
]
|
||||
np.random.shuffle(random_pairs)
|
||||
|
||||
|
||||
|
||||
for (p1, p2) in random_pairs:
|
||||
c1, c2 = p1.get_center(), p2.get_center()
|
||||
x1, y1, x2, y2 = c1[0], c1[1], c2[0], c2[1]
|
||||
if x1 >= x2:
|
||||
continue
|
||||
if y2 > y1:
|
||||
# make a red rect
|
||||
color = RED
|
||||
opacity = 0.1
|
||||
|
||||
elif y2 < y1:
|
||||
# make a blue rect
|
||||
color = BLUE
|
||||
opacity = 0.2
|
||||
|
||||
rect = Rectangle(width = x2 - x1, height = abs(y2 - y1))
|
||||
rect.set_fill(color = color, opacity = opacity)
|
||||
rect.set_stroke(width = 0)
|
||||
rect.move_to((c1+c2)/2)
|
||||
|
||||
self.play(FadeIn(rect), run_time = 0.05)
|
||||
|
||||
|
||||
|
||||
|
||||
class BinaryChoices(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
example1 = BinaryOption(UprightHeads(), UprightTails())
|
||||
example2 = BinaryOption(Male(), Female())
|
||||
example3 = BinaryOption(Checkmark(), Xmark())
|
||||
|
||||
example2.next_to(example1, DOWN, buff = MED_LARGE_BUFF)
|
||||
example3.next_to(example2, DOWN, buff = MED_LARGE_BUFF)
|
||||
|
||||
all = VGroup(example1, example2, example3)
|
||||
all = all.scale(2)
|
||||
|
||||
self.play(
|
||||
LaggedStart(FadeIn, all)
|
||||
)
|
||||
0
active_projects/eop/chapter2/__init__.py
Normal file
0
active_projects/eop/chapter2/__init__.py
Normal file
11
active_projects/eop/reusable_imports.py
Normal file
11
active_projects/eop/reusable_imports.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
from active_projects.eop.reusables.binary_option import *
|
||||
from active_projects.eop.reusables.brick_row import *
|
||||
from active_projects.eop.reusables.coin_flip_tree import *
|
||||
from active_projects.eop.reusables.coin_flipping_pi_creature import *
|
||||
from active_projects.eop.reusables.coin_stacks import *
|
||||
from active_projects.eop.reusables.dice import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.histograms import *
|
||||
from active_projects.eop.reusables.sick_pi_creature import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
0
active_projects/eop/reusables/__init__.py
Normal file
0
active_projects/eop/reusables/__init__.py
Normal file
12
active_projects/eop/reusables/binary_option.py
Normal file
12
active_projects/eop/reusables/binary_option.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
from mobject.types.vectorized_mobject import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
|
||||
class BinaryOption(VMobject):
|
||||
|
||||
def __init__(self, mob1, mob2, **kwargs):
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
text = TextMobject("or").scale(0.5)
|
||||
mob1.next_to(text, LEFT)
|
||||
mob2.next_to(text, RIGHT)
|
||||
self.add(mob1, text, mob2)
|
||||
207
active_projects/eop/reusables/brick_row.py
Normal file
207
active_projects/eop/reusables/brick_row.py
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
|
||||
class BrickRow(VMobject):
|
||||
|
||||
CONFIG = {
|
||||
"left_color" : RED,
|
||||
"right_color" : BLUE,
|
||||
"height" : 1.0,
|
||||
"width" : 8.0,
|
||||
"outcome_shrinkage_factor_x" : 0.95,
|
||||
"outcome_shrinkage_factor_y" : 0.94
|
||||
}
|
||||
|
||||
def __init__(self, n, **kwargs):
|
||||
self.subdiv_level = n
|
||||
self.coloring_level = n
|
||||
VMobject.__init__(self, **kwargs)
|
||||
|
||||
|
||||
def generate_points(self):
|
||||
|
||||
self.submobjects = []
|
||||
self.rects = self.get_rects_for_level(self.coloring_level)
|
||||
self.add(self.rects)
|
||||
self.subdivs = self.get_subdivs_for_level(self.subdiv_level)
|
||||
self.add(self.subdivs)
|
||||
|
||||
self.border = SurroundingRectangle(self,
|
||||
buff = 0, color = WHITE)
|
||||
self.add(self.border)
|
||||
|
||||
|
||||
|
||||
def get_rects_for_level(self,r):
|
||||
rects = VGroup()
|
||||
for k in range(r + 1):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
new_rect = Rectangle(
|
||||
width = proportion * self.width,
|
||||
height = self.height,
|
||||
fill_color = graded_color(r,k),
|
||||
fill_opacity = 1,
|
||||
stroke_width = 0
|
||||
)
|
||||
if len(rects.submobjects) > 0:
|
||||
new_rect.next_to(rects,RIGHT,buff = 0)
|
||||
else:
|
||||
new_rect.next_to(self.get_center() + 0.5 * self.width * LEFT, RIGHT, buff = 0)
|
||||
rects.add(new_rect)
|
||||
return rects
|
||||
|
||||
|
||||
def get_subdivs_for_level(self,r):
|
||||
subdivs = VGroup()
|
||||
x = - 0.5 * self.width
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
x += proportion * self.width
|
||||
subdiv = Line(
|
||||
x * RIGHT + 0.5 * self.height * UP,
|
||||
x * RIGHT + 0.5 * self.height * DOWN,
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
subdivs.move_to(self.get_center())
|
||||
return subdivs
|
||||
|
||||
|
||||
def get_sequence_subdivs_for_level(self,r):
|
||||
subdivs = VGroup()
|
||||
x = - 0.5 * self.width
|
||||
dx = 1.0 / 2**r
|
||||
for k in range(1, 2 ** r):
|
||||
proportion = dx
|
||||
x += proportion * self.width
|
||||
subdiv = DashedLine(
|
||||
x * RIGHT + 0.5 * self.height * UP,
|
||||
x * RIGHT + 0.5 * self.height * DOWN,
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
subdivs.move_to(self.get_center())
|
||||
return subdivs
|
||||
|
||||
|
||||
def get_outcome_centers_for_level(self,r):
|
||||
|
||||
dpos = float(self.width) / (2 ** r) * RIGHT
|
||||
pos = 0.5 * self.width * LEFT + 0.5 * dpos
|
||||
centers = []
|
||||
for k in range(0, 2 ** r):
|
||||
centers.append(self.get_center() + pos + k * dpos)
|
||||
|
||||
return centers
|
||||
|
||||
def get_outcome_rects_for_level(self, r, inset = False, with_labels = False):
|
||||
|
||||
centers = self.get_outcome_centers_for_level(r)
|
||||
if inset == True:
|
||||
outcome_width = self.outcome_shrinkage_factor_x * float(self.width) / (2 ** r)
|
||||
outcome_height = self.outcome_shrinkage_factor_y * self.height
|
||||
else:
|
||||
outcome_width = float(self.width) / (2 ** r)
|
||||
outcome_height = self.height
|
||||
|
||||
corner_radius = min(0.1, 0.3 * min(outcome_width, outcome_height))
|
||||
# this scales down the corner radius for very narrow rects
|
||||
rect = RoundedRectangle(
|
||||
width = outcome_width,
|
||||
height = outcome_height,
|
||||
corner_radius = corner_radius,
|
||||
fill_color = WHITE,
|
||||
fill_opacity = 0.2,
|
||||
stroke_width = 0
|
||||
)
|
||||
rects = VGroup()
|
||||
for center in centers:
|
||||
rects.add(rect.copy().move_to(center))
|
||||
|
||||
rects.move_to(self.get_center())
|
||||
|
||||
|
||||
if with_labels == False:
|
||||
return rects
|
||||
|
||||
# else
|
||||
sequences = self.get_coin_sequences_for_level(r)
|
||||
labels = VGroup()
|
||||
for (seq, rect) in zip(sequences, rects):
|
||||
coin_seq = CoinSequence(seq, direction = DOWN)
|
||||
coin_seq.shift(rect.get_center() - coin_seq.get_center())
|
||||
# not simply move_to bc coin_seq is not centered
|
||||
rect.add(coin_seq)
|
||||
rect.label = coin_seq
|
||||
|
||||
return rects
|
||||
|
||||
def get_coin_sequences_for_level(self,r):
|
||||
# array of arrays of characters
|
||||
if r < 0 or int(r) != r:
|
||||
raise Exception("Level must be a positive integer")
|
||||
if r == 0:
|
||||
return []
|
||||
if r == 1:
|
||||
return [["H"], ["T"]]
|
||||
|
||||
previous_seq_array = self.get_coin_sequences_for_level(r - 1)
|
||||
subdiv_lengths = [choose(r - 1, k) for k in range(r)]
|
||||
|
||||
seq_array = []
|
||||
index = 0
|
||||
for length in subdiv_lengths:
|
||||
|
||||
for seq in previous_seq_array[index:index + length]:
|
||||
seq_copy = copy.copy(seq)
|
||||
seq_copy.append("H")
|
||||
seq_array.append(seq_copy)
|
||||
|
||||
for seq in previous_seq_array[index:index + length]:
|
||||
seq_copy = copy.copy(seq)
|
||||
seq_copy.append("T")
|
||||
seq_array.append(seq_copy)
|
||||
index += length
|
||||
|
||||
return seq_array
|
||||
|
||||
|
||||
def get_outcome_width_for_level(self,r):
|
||||
return self.width / (2**r)
|
||||
|
||||
def get_rect_widths_for_level(self, r):
|
||||
ret_arr = []
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
ret_arr.append(proportion * self.width)
|
||||
return ret_arr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SplitRectsInBrickWall(AnimationGroup):
|
||||
|
||||
def __init__(self, mobject, **kwargs):
|
||||
|
||||
r = self.subdiv_level = mobject.subdiv_level + 1
|
||||
|
||||
subdivs = VGroup()
|
||||
x = -0.5 * mobject.get_width()
|
||||
|
||||
anims = []
|
||||
for k in range(0, r):
|
||||
proportion = float(choose(r,k)) / 2**r
|
||||
x += proportion * mobject.get_width()
|
||||
subdiv = DashedLine(
|
||||
mobject.get_top() + x * RIGHT,
|
||||
mobject.get_bottom() + x * RIGHT,
|
||||
)
|
||||
subdivs.add(subdiv)
|
||||
anims.append(ShowCreation(subdiv))
|
||||
|
||||
mobject.add(subdivs)
|
||||
AnimationGroup.__init__(self, *anims, **kwargs)
|
||||
|
||||
|
||||
|
||||
76
active_projects/eop/reusables/coin_flip_tree.py
Normal file
76
active_projects/eop/reusables/coin_flip_tree.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from mobject.geometry import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
class CoinFlipTree(VGroup):
|
||||
CONFIG = {
|
||||
"total_width": 12,
|
||||
"level_height": 0.8,
|
||||
"nb_levels": 4,
|
||||
"sort_until_level": 3
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
VGroup.__init__(self, **kwargs)
|
||||
|
||||
self.rows = []
|
||||
for n in range(self.nb_levels + 1):
|
||||
if n <= self.sort_until_level:
|
||||
self.create_row(n, sorted = True)
|
||||
else:
|
||||
self.create_row(n, sorted = False)
|
||||
|
||||
|
||||
for row in self.rows:
|
||||
for leaf in row:
|
||||
dot = Dot()
|
||||
dot.move_to(leaf[0])
|
||||
line = Line(leaf[2], leaf[0])
|
||||
if leaf[2][0] > leaf[0][0]:
|
||||
line_color = COLOR_HEADS
|
||||
else:
|
||||
line_color = COLOR_TAILS
|
||||
line.set_stroke(color = line_color)
|
||||
group = VGroup()
|
||||
group.add(dot)
|
||||
group.add_to_back(line)
|
||||
self.add(group)
|
||||
|
||||
|
||||
|
||||
|
||||
def create_row(self, level, sorted = True):
|
||||
|
||||
if level == 0:
|
||||
new_row = [[ORIGIN,0,ORIGIN]] # is its own parent
|
||||
self.rows.append(new_row)
|
||||
return
|
||||
|
||||
previous_row = self.rows[level - 1]
|
||||
new_row = []
|
||||
dx = float(self.total_width) / (2 ** level)
|
||||
x = - 0.5 * self.total_width + 0.5 * dx
|
||||
y = - self.level_height * level
|
||||
for root in previous_row:
|
||||
root_point = root[0]
|
||||
root_tally = root[1]
|
||||
for i in range(2): # 0 = heads = left, 1 = tails = right
|
||||
leaf = x * RIGHT + y * UP
|
||||
new_row.append([leaf, root_tally + i, root_point]) # leaf and its parent
|
||||
x += dx
|
||||
|
||||
if sorted:
|
||||
# sort the new_row by its tallies
|
||||
sorted_row = []
|
||||
x = - 0.5 * self.total_width + 0.5 * dx
|
||||
for i in range(level + 1):
|
||||
for leaf in new_row:
|
||||
if leaf[1] == i:
|
||||
sorted_leaf = leaf
|
||||
sorted_leaf[0][0] = x
|
||||
x += dx
|
||||
sorted_row.append(leaf)
|
||||
self.rows.append(sorted_row)
|
||||
else:
|
||||
self.rows.append(new_row)
|
||||
112
active_projects/eop/reusables/coin_flipping_pi_creature.py
Normal file
112
active_projects/eop/reusables/coin_flipping_pi_creature.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
from mobject.types.vectorized_mobject import *
|
||||
from animation.animation import *
|
||||
from animation.composition import *
|
||||
from mobject.geometry import Rectangle, Line
|
||||
from utils.rate_functions import *
|
||||
from for_3b1b_videos.pi_creature_scene import *
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
from active_projects.eop.reusables.coin_flipping_pi_creature import *
|
||||
|
||||
|
||||
class PiCreatureCoin(VMobject):
|
||||
CONFIG = {
|
||||
"diameter": 0.8,
|
||||
"thickness": 0.2,
|
||||
"nb_ridges" : 7,
|
||||
"stroke_color": YELLOW,
|
||||
"stroke_width": 3,
|
||||
"fill_color": YELLOW,
|
||||
"fill_opacity": 0.7,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
outer_rect = Rectangle(
|
||||
width = self.diameter,
|
||||
height = self.thickness,
|
||||
fill_color = self.fill_color,
|
||||
fill_opacity = self.fill_opacity,
|
||||
stroke_color = self.stroke_color,
|
||||
stroke_width = 0, #self.stroke_width
|
||||
)
|
||||
self.add(outer_rect)
|
||||
PI = TAU/2
|
||||
ridge_angles = np.arange(PI/self.nb_ridges,PI,PI/self.nb_ridges)
|
||||
ridge_positions = 0.5 * self.diameter * np.array([
|
||||
np.cos(theta) for theta in ridge_angles
|
||||
])
|
||||
ridge_color = interpolate_color(BLACK,self.stroke_color,0.5)
|
||||
for x in ridge_positions:
|
||||
ridge = Line(
|
||||
x * RIGHT + 0.5 * self.thickness * DOWN,
|
||||
x * RIGHT + 0.5 * self.thickness * UP,
|
||||
stroke_color = ridge_color,
|
||||
stroke_width = self.stroke_width
|
||||
)
|
||||
self.add(ridge)
|
||||
|
||||
class CoinFlippingPiCreature(PiCreature):
|
||||
CONFIG = {
|
||||
"flip_height": 3
|
||||
}
|
||||
|
||||
def __init__(self, mode = "coin_flip_1", **kwargs):
|
||||
|
||||
coin = PiCreatureCoin()
|
||||
PiCreature.__init__(self, mode = mode, **kwargs)
|
||||
self.coin = coin
|
||||
self.add(coin)
|
||||
right_arm = self.get_arm_copies()[1]
|
||||
coin.rotate(-TAU/24)
|
||||
coin.next_to(right_arm, RIGHT+UP, buff = 0)
|
||||
coin.shift(0.1 * self.get_width() * LEFT)
|
||||
coin.shift(0.2 * DOWN)
|
||||
|
||||
def flip_coin_up(self):
|
||||
self.change("coin_flip_2")
|
||||
|
||||
|
||||
|
||||
class FlipUpAndDown(Animation):
|
||||
CONFIG = {
|
||||
"vector" : UP,
|
||||
"height" : 3,
|
||||
"nb_turns" : 1
|
||||
}
|
||||
|
||||
def update(self,t):
|
||||
self.mobject.shift(self.height * 4 * t * (1 - t) * self.vector)
|
||||
self.mobject.rotate(t * self.nb_turns * TAU)
|
||||
|
||||
class FlipCoin(AnimationGroup):
|
||||
CONFIG = {
|
||||
"coin_rate_func" : there_and_back,
|
||||
"pi_rate_func" : lambda t : there_and_back_with_pause(t, 1./4)
|
||||
}
|
||||
def __init__(self, pi_creature, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
pi_creature_motion = ApplyMethod(
|
||||
pi_creature.flip_coin_up,
|
||||
rate_func = self.pi_rate_func,
|
||||
**kwargs
|
||||
)
|
||||
coin_motion = Succession(
|
||||
EmptyAnimation(run_time = 1.0),
|
||||
FlipUpAndDown(
|
||||
pi_creature.coin,
|
||||
vector = UP,
|
||||
nb_turns = 5,
|
||||
height = pi_creature.flip_height * pi_creature.get_height(),
|
||||
rate_func = self.coin_rate_func,
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
AnimationGroup.__init__(self,pi_creature_motion, coin_motion)
|
||||
|
||||
class CoinFlippingPiCreatureScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
|
||||
randy = CoinFlippingPiCreature(color = MAROON_E)
|
||||
self.add(randy)
|
||||
self.play(FlipCoin(randy, run_time = 3))
|
||||
111
active_projects/eop/reusables/coin_stacks.py
Normal file
111
active_projects/eop/reusables/coin_stacks.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
from mobject.geometry import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
from active_projects.eop.reusables.upright_coins import *
|
||||
|
||||
|
||||
class CoinStack(VGroup):
|
||||
CONFIG = {
|
||||
"coin_thickness": COIN_THICKNESS,
|
||||
"size": 5,
|
||||
"face": FlatCoin,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
for n in range(self.size):
|
||||
coin = self.face(thickness = self.coin_thickness)
|
||||
coin.shift(n * self.coin_thickness * UP)
|
||||
self.add(coin)
|
||||
if self.size == 0:
|
||||
point = VectorizedPoint()
|
||||
self.add(point)
|
||||
|
||||
class HeadsStack(CoinStack):
|
||||
CONFIG = {
|
||||
"face": FlatHeads
|
||||
}
|
||||
|
||||
class TailsStack(CoinStack):
|
||||
CONFIG = {
|
||||
"face": FlatTails
|
||||
}
|
||||
|
||||
|
||||
|
||||
class DecimalTally(TextMobject):
|
||||
|
||||
def __init__(self, heads, tails, **kwargs):
|
||||
|
||||
TextMobject.__init__(self, str(heads), "\\textemdash\,", str(tails), **kwargs)
|
||||
self[0].set_color(COLOR_HEADS)
|
||||
self[-1].set_color(COLOR_TAILS)
|
||||
# this only works for single-digit tallies
|
||||
|
||||
|
||||
|
||||
|
||||
class TallyStack(VGroup):
|
||||
CONFIG = {
|
||||
"coin_thickness": COIN_THICKNESS,
|
||||
"show_decimals": True
|
||||
}
|
||||
|
||||
def __init__(self, h, t, anchor = ORIGIN, **kwargs):
|
||||
self.nb_heads = h
|
||||
self.nb_tails = t
|
||||
self.anchor = anchor
|
||||
VGroup.__init__(self,**kwargs)
|
||||
|
||||
def generate_points(self):
|
||||
stack1 = HeadsStack(size = self.nb_heads, coin_thickness = self.coin_thickness)
|
||||
stack2 = TailsStack(size = self.nb_tails, coin_thickness = self.coin_thickness)
|
||||
stack1.next_to(self.anchor, LEFT, buff = 0.5 * SMALL_BUFF)
|
||||
stack2.next_to(self.anchor, RIGHT, buff = 0.5 * SMALL_BUFF)
|
||||
stack1.align_to(self.anchor, DOWN)
|
||||
stack2.align_to(self.anchor, DOWN)
|
||||
self.heads_stack = stack1
|
||||
self.tails_stack = stack2
|
||||
self.add(stack1, stack2)
|
||||
self.background_rect = background_rect = RoundedRectangle(
|
||||
width = TALLY_BACKGROUND_WIDTH,
|
||||
height = TALLY_BACKGROUND_WIDTH,
|
||||
corner_radius = 0.1,
|
||||
fill_color = TALLY_BACKGROUND_COLOR,
|
||||
fill_opacity = 1.0,
|
||||
stroke_width = 3
|
||||
).align_to(self.anchor, DOWN).shift(0.1 * DOWN)
|
||||
self.add_to_back(background_rect)
|
||||
|
||||
self.decimal_tally = DecimalTally(self.nb_heads, self.nb_tails)
|
||||
self.position_decimal_tally(self.decimal_tally)
|
||||
if self.show_decimals:
|
||||
self.add(self.decimal_tally)
|
||||
|
||||
def position_decimal_tally(self, decimal_tally):
|
||||
decimal_tally.match_width(self.background_rect)
|
||||
decimal_tally.scale(0.6)
|
||||
decimal_tally.next_to(self.background_rect.get_top(), DOWN, buff = 0.15)
|
||||
return decimal_tally
|
||||
|
||||
|
||||
def move_anchor_to(self, new_anchor):
|
||||
for submob in self.submobjects:
|
||||
submob.shift(new_anchor - self.anchor)
|
||||
|
||||
self.anchor = new_anchor
|
||||
self.position_decimal_tally(self.decimal_tally)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
76
active_projects/eop/reusables/dice.py
Normal file
76
active_projects/eop/reusables/dice.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from mobject.svg.svg_mobject import *
|
||||
from mobject.geometry import *
|
||||
from mobject.numbers import *
|
||||
|
||||
class DieFace(SVGMobject):
|
||||
|
||||
def __init__(self, value, **kwargs):
|
||||
|
||||
self.value = value
|
||||
self.file_name = "Dice-" + str(value)
|
||||
self.ensure_valid_file()
|
||||
SVGMobject.__init__(self, file_name = self.file_name)
|
||||
|
||||
class RowOfDice(VGroup):
|
||||
CONFIG = {
|
||||
"values" : range(1,7),
|
||||
"direction": RIGHT,
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
for value in self.values:
|
||||
new_die = DieFace(value)
|
||||
new_die.submobjects[0].set_fill(opacity = 0)
|
||||
new_die.submobjects[0].set_stroke(width = 7)
|
||||
new_die.next_to(self, self.direction)
|
||||
self.add(new_die)
|
||||
self.move_to(ORIGIN)
|
||||
|
||||
|
||||
class TwoDiceTable(VMobject):
|
||||
CONFIG = {
|
||||
"cell_size" : 1,
|
||||
"label_scale": 0.7
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
VMobject.__init__(self, **kwargs)
|
||||
colors = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], 13)
|
||||
|
||||
self.cells = VGroup()
|
||||
self.labels = VGroup()
|
||||
for i in range(1,7):
|
||||
for j in range(1,7):
|
||||
cell = Square(side_length = self.cell_size)
|
||||
cell.set_fill(color = colors[i+j], opacity = 0.8)
|
||||
cell.move_to(i*self.cell_size*DOWN + j*self.cell_size*RIGHT)
|
||||
self.cells.add(cell)
|
||||
label = Integer(i+j).scale(self.label_scale)
|
||||
label.move_to(cell)
|
||||
self.labels.add(label)
|
||||
|
||||
|
||||
self.add(self.cells, self.labels)
|
||||
row1 = RowOfDice().match_width(self)
|
||||
row2 = row1.copy().rotate(-TAU/4)
|
||||
row1.next_to(self, UP)
|
||||
row2.next_to(self, LEFT)
|
||||
self.rows = VGroup(row1, row2)
|
||||
self.add(self.rows)
|
||||
self.center()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
18
active_projects/eop/reusables/eop_constants.py
Normal file
18
active_projects/eop/reusables/eop_constants.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
from constants import *
|
||||
|
||||
COIN_RADIUS = 0.18
|
||||
COIN_THICKNESS = 0.4 * COIN_RADIUS
|
||||
COIN_FORESHORTENING = 0.5
|
||||
COIN_NB_RIDGES = 20
|
||||
COIN_STROKE_WIDTH = 2
|
||||
|
||||
COIN_SEQUENCE_SPACING = 0.1
|
||||
|
||||
GRADE_COLOR_1 = COLOR_HEADS = RED
|
||||
GRADE_COLOR_2 = COLOR_TAILS = BLUE_E
|
||||
|
||||
TALLY_BACKGROUND_WIDTH = 1.0
|
||||
TALLY_BACKGROUND_COLOR = BLACK
|
||||
|
||||
SICKLY_GREEN = "#9BBD37"
|
||||
36
active_projects/eop/reusables/eop_helpers.py
Normal file
36
active_projects/eop/reusables/eop_helpers.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
from utils.color import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
def binary(i):
|
||||
# returns an array of 0s and 1s
|
||||
if i == 0:
|
||||
return []
|
||||
j = i
|
||||
binary_array = []
|
||||
while j > 0:
|
||||
jj = j/2
|
||||
if jj > 0:
|
||||
binary_array.append(j % 2)
|
||||
else:
|
||||
binary_array.append(1)
|
||||
j = jj
|
||||
return binary_array[::-1]
|
||||
|
||||
def nb_of_ones(i):
|
||||
return binary(i).count(1)
|
||||
|
||||
|
||||
def rainbow_color(alpha):
|
||||
nb_colors = 100
|
||||
rainbow = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], nb_colors)
|
||||
rainbow = np.append(rainbow,PURPLE)
|
||||
index = int(alpha * nb_colors)
|
||||
return rainbow[index]
|
||||
|
||||
def graded_color(n,k):
|
||||
if n != 0:
|
||||
alpha = float(k)/n
|
||||
else:
|
||||
alpha = 0.5
|
||||
color = interpolate_color(GRADE_COLOR_1, GRADE_COLOR_2, alpha)
|
||||
return color
|
||||
|
|
@ -201,7 +201,10 @@ class FlashThroughHistogram(Animation):
|
|||
"hist_opacity" : 0.2
|
||||
}
|
||||
|
||||
def __init__(self, mobject, direction = "horizontal", mode = "random", **kwargs):
|
||||
def __init__(self, mobject,
|
||||
direction = "horizontal",
|
||||
mode = "random",
|
||||
**kwargs):
|
||||
|
||||
digest_config(self, kwargs)
|
||||
|
||||
|
|
@ -277,7 +280,59 @@ class FlashThroughHistogram(Animation):
|
|||
self.mobject.remove(self.prototype_cell)
|
||||
|
||||
|
||||
|
||||
def clean_up(self, surrounding_scene = None):
|
||||
Animation.clean_up(self, surrounding_scene)
|
||||
self.update(1)
|
||||
if surrounding_scene is not None:
|
||||
if self.is_remover():
|
||||
surrounding_scene.remove(self.prototype_cell)
|
||||
else:
|
||||
surrounding_scene.add(self.prototype_cell)
|
||||
return self
|
||||
|
||||
|
||||
|
||||
class OutlineableBars(VGroup):
|
||||
|
||||
# A group of bars (rectangles), together with
|
||||
# a method that draws an outline around them,
|
||||
# assuming the bars are arranged in a histogram
|
||||
# (aligned at the bottom without gaps).
|
||||
|
||||
# We use this to morph a row of bricks into a histogram.
|
||||
|
||||
CONFIG = {
|
||||
"outline_stroke_width" : 3,
|
||||
"stroke_color" : WHITE
|
||||
}
|
||||
def create_outline(self, animated = False, **kwargs):
|
||||
|
||||
outline_points = []
|
||||
|
||||
for (i, bar) in enumerate(self.submobjects):
|
||||
|
||||
if i == 0:
|
||||
# start with the lower left
|
||||
outline_points.append(bar.get_corner(DOWN + LEFT))
|
||||
|
||||
# upper two points of each bar
|
||||
outline_points.append(bar.get_corner(UP + LEFT))
|
||||
outline_points.append(bar.get_corner(UP + RIGHT))
|
||||
|
||||
previous_bar = bar
|
||||
# close the outline
|
||||
# lower right
|
||||
outline_points.append(previous_bar.get_corner(DOWN + RIGHT))
|
||||
# lower left
|
||||
outline_points.append(outline_points[0])
|
||||
|
||||
self.outline = Polygon(*outline_points,
|
||||
stroke_width = self.outline_stroke_width,
|
||||
stroke_color = self.stroke_color)
|
||||
|
||||
if animated:
|
||||
self.play(FadeIn(self.outline, **kwargs))
|
||||
return self.outline
|
||||
|
||||
|
||||
|
||||
22
active_projects/eop/reusables/sick_pi_creature.py
Normal file
22
active_projects/eop/reusables/sick_pi_creature.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
from for_3b1b_videos.pi_creature import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
|
||||
class SicklyPiCreature(PiCreature):
|
||||
CONFIG = {
|
||||
"sick_color": SICKLY_GREEN
|
||||
}
|
||||
|
||||
def get_slightly_sick(self):
|
||||
|
||||
self.save_state()
|
||||
self.set_color(self.sick_color)
|
||||
|
||||
def get_sick(self):
|
||||
|
||||
self.get_slightly_sick()
|
||||
self.change_mode("sick")
|
||||
|
||||
def get_better(self):
|
||||
self.restore()
|
||||
132
active_projects/eop/reusables/upright_coins.py
Normal file
132
active_projects/eop/reusables/upright_coins.py
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
from mobject.geometry import *
|
||||
from mobject.svg.tex_mobject import *
|
||||
from utils.color import *
|
||||
|
||||
from active_projects.eop.reusables.eop_helpers import *
|
||||
from active_projects.eop.reusables.eop_constants import *
|
||||
|
||||
class UprightCoin(Circle):
|
||||
# For use in coin sequences
|
||||
CONFIG = {
|
||||
"radius": COIN_RADIUS,
|
||||
"stroke_width": COIN_STROKE_WIDTH,
|
||||
"stroke_color": WHITE,
|
||||
"fill_opacity": 1,
|
||||
"symbol": "\euro"
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
Circle.__init__(self,**kwargs)
|
||||
self.symbol_mob = TextMobject(self.symbol, stroke_color = self.stroke_color)
|
||||
self.symbol_mob.scale_to_fit_height(0.5*self.get_height()).move_to(self)
|
||||
self.add(self.symbol_mob)
|
||||
|
||||
class UprightHeads(UprightCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_HEADS,
|
||||
"symbol": "H",
|
||||
}
|
||||
|
||||
class UprightTails(UprightCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_TAILS,
|
||||
"symbol": "T",
|
||||
}
|
||||
|
||||
class CoinSequence(VGroup):
|
||||
CONFIG = {
|
||||
"sequence": [],
|
||||
"radius" : COIN_RADIUS,
|
||||
"spacing": COIN_SEQUENCE_SPACING,
|
||||
"direction": RIGHT
|
||||
}
|
||||
|
||||
def __init__(self, sequence, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
self.sequence = sequence
|
||||
offset = 0
|
||||
for symbol in self.sequence:
|
||||
if symbol == "H":
|
||||
new_coin = UprightHeads(radius = self.radius)
|
||||
elif symbol == "T":
|
||||
new_coin = UprightTails(radius = self.radius)
|
||||
else:
|
||||
new_coin = UprightCoin(symbol = symbol, radius = self.radius)
|
||||
new_coin.shift(offset * self.direction)
|
||||
self.add(new_coin)
|
||||
offset += self.spacing
|
||||
|
||||
|
||||
class FlatCoin(UprightCoin):
|
||||
# For use in coin stacks
|
||||
CONFIG = {
|
||||
"thickness": COIN_THICKNESS,
|
||||
"foreshortening": COIN_FORESHORTENING,
|
||||
"nb_ridges": COIN_NB_RIDGES
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
UprightCoin.__init__(self, **kwargs)
|
||||
self.symbol_mob.rotate(TAU/8)
|
||||
self.stretch_in_place(self.foreshortening, 1)
|
||||
|
||||
# draw the edge
|
||||
control_points1 = self.points[12:25].tolist()
|
||||
control_points2 = self.copy().shift(self.thickness * DOWN).points[12:25].tolist()
|
||||
edge_anchors_and_handles = control_points1
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN)
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP)
|
||||
edge_anchors_and_handles += control_points2[::-1] # list concatenation
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP)
|
||||
edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN)
|
||||
edge_anchors_and_handles.append(control_points1[0])
|
||||
#edge_anchors_and_handles = edge_anchors_and_handles[::-1]
|
||||
edge = VMobject()
|
||||
edge.set_points(edge_anchors_and_handles)
|
||||
edge.set_fill(
|
||||
color = self.fill_color,
|
||||
opacity = self.fill_opacity
|
||||
)
|
||||
edge.set_stroke(width = self.stroke_width)
|
||||
self.add(edge)
|
||||
|
||||
# draw the ridges
|
||||
PI = TAU/2
|
||||
dtheta = PI/self.nb_ridges
|
||||
ridge_angles = np.arange(dtheta,PI,dtheta)
|
||||
# add a twist onto each coin
|
||||
ridge_angles += np.random.rand(1) * dtheta
|
||||
# crop the angles that overshoot on either side
|
||||
ridge_angles = ridge_angles[(ridge_angles > 0) * (ridge_angles < PI)]
|
||||
ridge_positions = 0.5 * 2 * self.radius * np.array([
|
||||
np.cos(theta) for theta in ridge_angles
|
||||
])
|
||||
ridge_color = interpolate_color(self.stroke_color, self.fill_color, 0.7)
|
||||
for x in ridge_positions:
|
||||
y = -(1 - (x/self.radius)**2)**0.5 * self.foreshortening * self.radius
|
||||
ridge = Line(
|
||||
x * RIGHT + y * UP,
|
||||
x * RIGHT + y * UP + self.thickness * DOWN,
|
||||
stroke_color = ridge_color,
|
||||
stroke_width = self.stroke_width
|
||||
)
|
||||
self.add(ridge)
|
||||
|
||||
# redraw the unfilled edge to cover the ridge ends
|
||||
empty_edge = edge.copy()
|
||||
empty_edge.set_fill(opacity = 0)
|
||||
self.add(empty_edge)
|
||||
|
||||
class FlatHeads(FlatCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_HEADS,
|
||||
"symbol": "H",
|
||||
}
|
||||
|
||||
class FlatTails(FlatCoin):
|
||||
CONFIG = {
|
||||
"fill_color": COLOR_TAILS,
|
||||
"symbol": "T",
|
||||
}
|
||||
|
||||
21
active_projects/eop/what_does_probability_mean.py
Normal file
21
active_projects/eop/what_does_probability_mean.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
|
||||
class WhatDoesItReallyMean(TeacherStudentsScene):
|
||||
|
||||
CONFIG = {
|
||||
"default_pi_creature_kwargs": {
|
||||
"color": MAROON_E,
|
||||
"flip_at_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
||||
student_q = TextMobject("What does", "``probability''", "\emph{actually}", "mean?")
|
||||
student_q.set_color_by_tex("probability", YELLOW)
|
||||
self.student_says(student_q, target_mode = "sassy")
|
||||
self.wait()
|
||||
self.teacher_says("Don't worry -- philosophy can come later!")
|
||||
self.wait()
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ from utils.config_ops import digest_config
|
|||
|
||||
class ChangingDecimal(Animation):
|
||||
CONFIG = {
|
||||
"num_decimal_points": None,
|
||||
"num_decimal_places": None,
|
||||
"show_ellipsis": None,
|
||||
"position_update_func": None,
|
||||
"tracked_mobject": None,
|
||||
|
|
@ -21,7 +21,7 @@ class ChangingDecimal(Animation):
|
|||
self.decimal_number_config = dict(
|
||||
decimal_number_mobject.initial_config
|
||||
)
|
||||
for attr in "num_decimal_points", "show_ellipsis":
|
||||
for attr in "num_decimal_places", "show_ellipsis":
|
||||
value = getattr(self, attr)
|
||||
if value is not None:
|
||||
self.decimal_number_config[attr] = value
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ or refactoring the library on current or older scene scripts should be entirely
|
|||
addressible by changing this file.
|
||||
|
||||
Note: One should NOT import from this file for main library code, it is meant only
|
||||
as a convenience for scripts createing scenes for videos
|
||||
as a convenience for scripts creating scenes for videos.
|
||||
"""
|
||||
|
||||
from constants import *
|
||||
|
|
|
|||
|
|
@ -151,11 +151,12 @@ def handle_scene(scene, **config):
|
|||
|
||||
if config["show_file_in_finder"]:
|
||||
commands.append("-R")
|
||||
#
|
||||
|
||||
if config["show_last_frame"]:
|
||||
commands.append(scene.get_image_file_path())
|
||||
else:
|
||||
commands.append(scene.get_movie_file_path())
|
||||
#commands.append("-g")
|
||||
FNULL = open(os.devnull, 'w')
|
||||
sp.call(commands, stdout=FNULL, stderr=sp.STDOUT)
|
||||
FNULL.close()
|
||||
|
|
@ -223,8 +224,11 @@ def get_module_posix(file_name):
|
|||
module_name = file_name.replace(".py", "")
|
||||
last_module = imp.load_module(".", *imp.find_module("."))
|
||||
for part in module_name.split(os.sep):
|
||||
load_args = imp.find_module(part, last_module.__path__)
|
||||
last_module = imp.load_module(part, *load_args)
|
||||
try:
|
||||
load_args = imp.find_module(part, last_module.__path__)
|
||||
last_module = imp.load_module(part, *load_args)
|
||||
except ImportError:
|
||||
continue
|
||||
return last_module
|
||||
|
||||
|
||||
|
|
|
|||
23
for_3b1b_videos/pi_class.py
Normal file
23
for_3b1b_videos/pi_class.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import numpy as np
|
||||
import warnings
|
||||
|
||||
from constants import *
|
||||
|
||||
from mobject.types.vectorized_mobject import VGroup
|
||||
from for_3b1b_videos.pi_creature import PiCreature
|
||||
|
||||
class PiCreatureClass(VGroup):
|
||||
CONFIG = {
|
||||
"width" : 3,
|
||||
"height" : 2
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
for i in range(self.width):
|
||||
for j in range(self.height):
|
||||
pi = PiCreature().scale(0.3)
|
||||
pi.move_to(i*DOWN + j* RIGHT)
|
||||
self.add(pi)
|
||||
|
||||
|
||||
|
|
@ -6,6 +6,7 @@ from mobject.mobject import Group
|
|||
|
||||
from mobject.svg.drawings import SpeechBubble
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.creation import ShowCreation
|
||||
from animation.creation import Write
|
||||
from animation.composition import AnimationGroup
|
||||
|
|
@ -16,6 +17,8 @@ from utils.config_ops import digest_config
|
|||
from utils.rate_functions import squish_rate_func
|
||||
from utils.rate_functions import there_and_back
|
||||
|
||||
from for_3b1b_videos.pi_class import PiCreatureClass
|
||||
|
||||
|
||||
class Blink(ApplyMethod):
|
||||
CONFIG = {
|
||||
|
|
@ -101,3 +104,46 @@ class RemovePiCreatureBubble(AnimationGroup):
|
|||
self.pi_creature.bubble = None
|
||||
if surrounding_scene is not None:
|
||||
surrounding_scene.add(self.pi_creature)
|
||||
|
||||
|
||||
|
||||
class FlashThroughClass(Animation):
|
||||
CONFIG = {
|
||||
"highlight_color" : GREEN,
|
||||
}
|
||||
|
||||
def __init__(self, mobject, mode = "linear", **kwargs):
|
||||
|
||||
if not isinstance(mobject, PiCreatureClass):
|
||||
raise Exception("FlashThroughClass mobject must be a PiCreatureClass")
|
||||
digest_config(self, kwargs)
|
||||
self.indices = range(mobject.height * mobject.width)
|
||||
|
||||
if mode == "random":
|
||||
np.random.shuffle(self.indices)
|
||||
|
||||
Animation.__init__(self, mobject, **kwargs)
|
||||
|
||||
|
||||
def update_mobject(self, alpha):
|
||||
index = int(np.floor(alpha * self.mobject.height * self.mobject.width))
|
||||
|
||||
for pi in self.mobject:
|
||||
pi.set_color(BLUE_E)
|
||||
if index < self.mobject.height * self.mobject.width:
|
||||
self.mobject[self.indices[index]].set_color(self.highlight_color)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class Matrix(VMobject):
|
|||
class DecimalMatrix(Matrix):
|
||||
CONFIG = {
|
||||
"element_to_mobject": DecimalNumber,
|
||||
"element_to_mobject_config": {"num_decimal_points": 1}
|
||||
"element_to_mobject_config": {"num_decimal_places": 1}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -623,13 +623,17 @@ class Mobject(Container):
|
|||
values = []
|
||||
values += [
|
||||
mob.reduce_across_dimension(points_func, reduce_func, dim)
|
||||
for mob in self.submobjects
|
||||
for mob in self.nonempty_submobjects()
|
||||
]
|
||||
try:
|
||||
return reduce_func(values)
|
||||
except:
|
||||
return 0
|
||||
|
||||
def nonempty_submobjects(self):
|
||||
return [submob for submob in self.submobjects
|
||||
if len(submob.submobjects) != 0 or len(submob.points) != 0]
|
||||
|
||||
def get_merged_array(self, array_attr):
|
||||
result = None
|
||||
for mob in self.family_members_with_points():
|
||||
|
|
@ -745,6 +749,7 @@ class Mobject(Container):
|
|||
def submobject_family(self):
|
||||
sub_families = map(Mobject.submobject_family, self.submobjects)
|
||||
all_mobjects = [self] + list(it.chain(*sub_families))
|
||||
#all_mobjects = list(it.chain(*sub_families)) + [self]
|
||||
return remove_list_redundancies(all_mobjects)
|
||||
|
||||
def family_members_with_points(self):
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from mobject.types.vectorized_mobject import VMobject
|
|||
|
||||
class DecimalNumber(VMobject):
|
||||
CONFIG = {
|
||||
"num_decimal_points": 2,
|
||||
"num_decimal_places": 2,
|
||||
"digit_to_digit_buff": 0.05,
|
||||
"show_ellipsis": False,
|
||||
"unit": None, # Aligned to bottom unless it starts with "^"
|
||||
|
|
@ -18,7 +18,7 @@ class DecimalNumber(VMobject):
|
|||
def __init__(self, number, **kwargs):
|
||||
VMobject.__init__(self, **kwargs)
|
||||
self.number = number
|
||||
ndp = self.num_decimal_points
|
||||
ndp = self.num_decimal_places
|
||||
|
||||
# Build number string
|
||||
if isinstance(number, complex):
|
||||
|
|
@ -71,5 +71,5 @@ class DecimalNumber(VMobject):
|
|||
|
||||
class Integer(DecimalNumber):
|
||||
CONFIG = {
|
||||
"num_decimal_points": 0,
|
||||
"num_decimal_places": 0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ def walker_animation_with_display(
|
|||
number_update_func = None,
|
||||
show_arrows = True,
|
||||
scale_arrows = False,
|
||||
num_decimal_points = 1,
|
||||
num_decimal_places = 1,
|
||||
include_background_rectangle = True,
|
||||
**kwargs
|
||||
):
|
||||
|
|
@ -581,7 +581,7 @@ def walker_animation_with_display(
|
|||
|
||||
if number_update_func != None:
|
||||
display = DecimalNumber(0,
|
||||
num_decimal_points = num_decimal_points,
|
||||
num_decimal_places = num_decimal_places,
|
||||
fill_color = WHITE if include_background_rectangle else BLACK,
|
||||
include_background_rectangle = include_background_rectangle)
|
||||
if include_background_rectangle:
|
||||
|
|
@ -732,7 +732,7 @@ class PiWalker(ColorMappedByFuncScene):
|
|||
"show_num_plane" : False,
|
||||
"draw_lines" : True,
|
||||
"num_checkpoints" : 10,
|
||||
"num_decimal_points" : 1,
|
||||
"num_decimal_places" : 1,
|
||||
"include_background_rectangle" : False,
|
||||
}
|
||||
|
||||
|
|
@ -788,7 +788,7 @@ class PiWalker(ColorMappedByFuncScene):
|
|||
number_update_func = number_update_func,
|
||||
run_time = self.step_run_time,
|
||||
walker_stroke_color = WALKER_LIGHT_COLOR if self.color_foreground_not_background else BLACK,
|
||||
num_decimal_points = self.num_decimal_points,
|
||||
num_decimal_places = self.num_decimal_places,
|
||||
include_background_rectangle = self.include_background_rectangle,
|
||||
)
|
||||
|
||||
|
|
@ -2751,7 +2751,7 @@ class OneFifthTwoFifthWinder(SpecifiedWinder):
|
|||
"step_size" : 0.01,
|
||||
"show_num_plane" : False,
|
||||
"step_run_time" : 6,
|
||||
"num_decimal_points" : 2,
|
||||
"num_decimal_places" : 2,
|
||||
}
|
||||
|
||||
class OneFifthOneFifthWinderWithReset(OneFifthTwoFifthWinder):
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ class Introduce1DFunctionCase(Scene):
|
|||
)
|
||||
decimal = DecimalNumber(
|
||||
0,
|
||||
num_decimal_points = 3,
|
||||
num_decimal_places = 3,
|
||||
show_ellipsis = True,
|
||||
)
|
||||
decimal.scale(0.7)
|
||||
|
|
@ -484,7 +484,7 @@ class Introduce1DFunctionCase(Scene):
|
|||
if show_decimal:
|
||||
decimal = DecimalNumber(
|
||||
axes.x_axis.point_to_number(arrow.get_start()),
|
||||
num_decimal_points = 3,
|
||||
num_decimal_places = 3,
|
||||
# show_ellipsis = True,
|
||||
)
|
||||
height = self.rect.get_height()
|
||||
|
|
@ -2310,7 +2310,7 @@ class TransitionFromPathsToBoundaries(ColorMappedObjectsScene):
|
|||
)
|
||||
)
|
||||
|
||||
label = DecimalNumber(0, num_decimal_points = 1)
|
||||
label = DecimalNumber(0, num_decimal_places = 1)
|
||||
label_upadte = ContinualChangingDecimal(
|
||||
label, get_total_winding,
|
||||
position_update_func = lambda l : l.next_to(dot, UP+LEFT, SMALL_BUFF)
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class LightIndicator(VMobject):
|
|||
self.foreground.set_stroke(color=INDICATOR_STROKE_COLOR,width=INDICATOR_STROKE_WIDTH)
|
||||
|
||||
self.add(self.background, self.foreground)
|
||||
self.reading = DecimalNumber(self.intensity,num_decimal_points = self.precision)
|
||||
self.reading = DecimalNumber(self.intensity,num_decimal_places = self.precision)
|
||||
self.reading.set_fill(color=INDICATOR_TEXT_COLOR)
|
||||
self.reading.move_to(self.get_center())
|
||||
if self.show_reading:
|
||||
|
|
@ -287,7 +287,7 @@ class IntroScene(PiCreatureScene):
|
|||
equals_sign = self.euler_sum.get_part_by_tex("=")
|
||||
|
||||
self.partial_sum_decimal = DecimalNumber(partial_results_values[1],
|
||||
num_decimal_points = 2)
|
||||
num_decimal_places = 2)
|
||||
self.partial_sum_decimal.next_to(equals_sign, RIGHT)
|
||||
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ class IntroScene(PiCreatureScene):
|
|||
self.partial_sum_decimal,
|
||||
partial_results_values[i+1],
|
||||
run_time = self.duration,
|
||||
num_decimal_points = 6,
|
||||
num_decimal_places = 6,
|
||||
show_ellipsis = True,
|
||||
position_update_func = lambda m: m.next_to(equals_sign, RIGHT)
|
||||
)
|
||||
|
|
@ -863,7 +863,7 @@ class SingleLighthouseScene(PiCreatureScene):
|
|||
# angle msmt (decimal number)
|
||||
|
||||
self.angle_indicator = DecimalNumber(arc_angle / DEGREES,
|
||||
num_decimal_points = 0,
|
||||
num_decimal_places = 0,
|
||||
unit = "^\\circ",
|
||||
fill_opacity = 1.0,
|
||||
fill_color = WHITE)
|
||||
|
|
@ -4262,7 +4262,7 @@ class LabeledArc(Arc):
|
|||
|
||||
Arc.__init__(self,angle,**kwargs)
|
||||
|
||||
label = DecimalNumber(self.length, num_decimal_points = 0)
|
||||
label = DecimalNumber(self.length, num_decimal_places = 0)
|
||||
r = BUFFER * self.radius
|
||||
theta = self.start_angle + self.angle/2
|
||||
label_pos = r * np.array([np.cos(theta), np.sin(theta), 0])
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class LightIndicator(Mobject):
|
|||
self.foreground.set_fill(color = self.fill_color)
|
||||
|
||||
self.add(self.background, self.foreground)
|
||||
self.reading = DecimalNumber(self.intensity,num_decimal_points = self.precision)
|
||||
self.reading = DecimalNumber(self.intensity,num_decimal_places = self.precision)
|
||||
self.reading.set_fill(color=INDICATOR_TEXT_COLOR)
|
||||
self.reading.scale_to_fit_height(self.reading_height)
|
||||
self.reading.move_to(self.get_center())
|
||||
|
|
@ -317,7 +317,7 @@ class IntroScene(PiCreatureScene):
|
|||
|
||||
partial_sum_decimal = self.partial_sum_decimal = DecimalNumber(
|
||||
series_terms[1],
|
||||
num_decimal_points = 2
|
||||
num_decimal_places = 2
|
||||
)
|
||||
partial_sum_decimal.next_to(equals_sign, RIGHT)
|
||||
|
||||
|
|
@ -418,7 +418,7 @@ class IntroScene(PiCreatureScene):
|
|||
partial_sum_decimal,
|
||||
series_terms[i+1],
|
||||
run_time = 1,
|
||||
num_decimal_points = 6,
|
||||
num_decimal_places = 6,
|
||||
position_update_func = lambda m: m.next_to(equals_sign, RIGHT)
|
||||
)
|
||||
]
|
||||
|
|
@ -430,7 +430,7 @@ class IntroScene(PiCreatureScene):
|
|||
ChangeDecimalToValue(
|
||||
partial_sum_decimal,
|
||||
series_terms[i+1],
|
||||
num_decimal_points = 6,
|
||||
num_decimal_places = 6,
|
||||
),
|
||||
]
|
||||
if i == 5:
|
||||
|
|
@ -451,7 +451,7 @@ class IntroScene(PiCreatureScene):
|
|||
ChangeDecimalToValue(
|
||||
partial_sum_decimal,
|
||||
series_terms[-1],
|
||||
num_decimal_points = 6,
|
||||
num_decimal_places = 6,
|
||||
),
|
||||
morty.change, "confused",
|
||||
)
|
||||
|
|
@ -1295,7 +1295,7 @@ class IntroduceScreen(Scene):
|
|||
|
||||
self.angle_indicator = DecimalNumber(
|
||||
arc_angle / DEGREES,
|
||||
num_decimal_points = 0,
|
||||
num_decimal_places = 0,
|
||||
unit = "^\\circ"
|
||||
)
|
||||
self.angle_indicator.next_to(self.angle_arc, RIGHT)
|
||||
|
|
@ -3818,7 +3818,7 @@ class ThinkBackToHowAmazingThisIs(ThreeDScene):
|
|||
dot_pairs = it.starmap(VGroup, zip(positive_dots, negative_dots))
|
||||
|
||||
# Decimal
|
||||
decimal = DecimalNumber(0, num_decimal_points = 6)
|
||||
decimal = DecimalNumber(0, num_decimal_places = 6)
|
||||
decimal.to_edge(UP)
|
||||
terms = [2./(n**2) for n in range(1, 100, 2)]
|
||||
partial_sums = np.cumsum(terms)
|
||||
|
|
@ -4250,7 +4250,7 @@ class LabeledArc(Arc):
|
|||
|
||||
Arc.__init__(self,angle,**kwargs)
|
||||
|
||||
label = DecimalNumber(self.length, num_decimal_points = 0)
|
||||
label = DecimalNumber(self.length, num_decimal_places = 0)
|
||||
r = BUFFER * self.radius
|
||||
theta = self.start_angle + self.angle/2
|
||||
label_pos = r * np.array([np.cos(theta), np.sin(theta), 0])
|
||||
|
|
|
|||
|
|
@ -728,7 +728,7 @@ class UnmixMixedPaint(Scene):
|
|||
class MachineThatTreatsOneFrequencyDifferently(Scene):
|
||||
def construct(self):
|
||||
graph = self.get_cosine_graph(0.5)
|
||||
frequency_mob = DecimalNumber(220, num_decimal_points = 0)
|
||||
frequency_mob = DecimalNumber(220, num_decimal_places = 0)
|
||||
frequency_mob.next_to(graph, UP, buff = MED_LARGE_BUFF)
|
||||
|
||||
self.graph = graph
|
||||
|
|
@ -1273,7 +1273,7 @@ class WrapCosineGraphAroundCircle(FourierMachineScene):
|
|||
def get_winding_frequency_label(self):
|
||||
freq = self.initial_winding_frequency
|
||||
winding_freq_label = VGroup(
|
||||
DecimalNumber(freq, num_decimal_points = 2),
|
||||
DecimalNumber(freq, num_decimal_places = 2),
|
||||
TextMobject("cycles/second")
|
||||
)
|
||||
winding_freq_label.arrange_submobjects(RIGHT)
|
||||
|
|
|
|||
|
|
@ -1805,7 +1805,7 @@ class BoxCountingScene(Scene):
|
|||
return label
|
||||
|
||||
def count_boxes(self, boxes):
|
||||
num = DecimalNumber(len(boxes), num_decimal_points = 0)
|
||||
num = DecimalNumber(len(boxes), num_decimal_places = 0)
|
||||
num.next_to(boxes, RIGHT)
|
||||
num.add_to_back(BackgroundRectangle(num))
|
||||
|
||||
|
|
|
|||
|
|
@ -559,7 +559,7 @@ class WriteAProgram(Scene):
|
|||
rgb = square.fill_rgb
|
||||
num = DecimalNumber(
|
||||
square.fill_rgb[0],
|
||||
num_decimal_points = 1
|
||||
num_decimal_places = 1
|
||||
)
|
||||
num.set_stroke(width = 1)
|
||||
color = rgba_to_color(1 - (rgb + 0.2)/1.2)
|
||||
|
|
@ -1113,7 +1113,7 @@ class IntroduceEachLayer(PreviewMNistNetwork):
|
|||
example_num = None
|
||||
for neuron in neurons:
|
||||
o = neuron.get_fill_opacity()
|
||||
num = DecimalNumber(o, num_decimal_points = 1)
|
||||
num = DecimalNumber(o, num_decimal_places = 1)
|
||||
num.scale_to_fit_width(0.7*neuron.get_width())
|
||||
num.move_to(neuron)
|
||||
if o > 0.8:
|
||||
|
|
|
|||
|
|
@ -962,14 +962,14 @@ class IntroduceCostFunction(PreviewLearning):
|
|||
terms = VGroup()
|
||||
term_updates = []
|
||||
for arrow, d1, d2 in zip(arrows, *self.decimal_groups):
|
||||
term = DecimalNumber(0, num_decimal_points = 4)
|
||||
term = DecimalNumber(0, num_decimal_places = 4)
|
||||
term.scale_to_fit_height(d1.get_height())
|
||||
term.next_to(arrow, LEFT)
|
||||
term.num_update_func = generate_term_update_func(d1, d2)
|
||||
terms.add(term)
|
||||
term_updates.append(ChangingDecimalWithColor(
|
||||
term, term.num_update_func,
|
||||
num_decimal_points = 4
|
||||
num_decimal_places = 4
|
||||
))
|
||||
brace.target.next_to(terms, LEFT)
|
||||
|
||||
|
|
@ -2780,7 +2780,7 @@ class TestPerformance(PreviewLearning):
|
|||
"wrong_wait_time" : 0.5,
|
||||
"stroke_width_exp" : 2,
|
||||
"decimal_kwargs" : {
|
||||
"num_decimal_points" : 3,
|
||||
"num_decimal_places" : 3,
|
||||
}
|
||||
}
|
||||
def construct(self):
|
||||
|
|
|
|||
|
|
@ -671,7 +671,7 @@ class WalkThroughTwoExample(ShowAveragingCost):
|
|||
decimals = VGroup()
|
||||
for neuron in neurons:
|
||||
activation = neuron.get_fill_opacity()
|
||||
decimal = DecimalNumber(activation, num_decimal_points = 1)
|
||||
decimal = DecimalNumber(activation, num_decimal_places = 1)
|
||||
decimal.scale_to_fit_width(0.7*neuron.get_width())
|
||||
decimal.move_to(neuron)
|
||||
if activation > 0.8:
|
||||
|
|
@ -748,7 +748,7 @@ class WalkThroughTwoExample(ShowAveragingCost):
|
|||
anims.append(ChangingDecimal(
|
||||
decimal,
|
||||
get_decimal_update(decimal.number, target),
|
||||
num_decimal_points = 1
|
||||
num_decimal_places = 1
|
||||
))
|
||||
anims.append(UpdateFromFunc(
|
||||
self.decimals[i],
|
||||
|
|
@ -1076,7 +1076,7 @@ class WalkThroughTwoExample(ShowAveragingCost):
|
|||
ChangingDecimal(
|
||||
two_decimal,
|
||||
lambda a : interpolate(two_activation, 1, a),
|
||||
num_decimal_points = 1,
|
||||
num_decimal_places = 1,
|
||||
),
|
||||
UpdateFromFunc(
|
||||
two_decimal,
|
||||
|
|
@ -1110,7 +1110,7 @@ class WalkThroughTwoExample(ShowAveragingCost):
|
|||
ChangingDecimal(
|
||||
two_decimal,
|
||||
lambda a : interpolate(1, two_activation, a),
|
||||
num_decimal_points = 1,
|
||||
num_decimal_places = 1,
|
||||
),
|
||||
UpdateFromFunc(
|
||||
two_decimal,
|
||||
|
|
@ -3613,7 +3613,7 @@ class SimplestNetworkExample(PreviewLearning):
|
|||
|
||||
def get_neuron_activation_decimal(self, neuron):
|
||||
opacity = neuron.get_fill_opacity()
|
||||
decimal = DecimalNumber(opacity, num_decimal_points = 2)
|
||||
decimal = DecimalNumber(opacity, num_decimal_places = 2)
|
||||
decimal.scale_to_fit_width(0.85*neuron.get_width())
|
||||
if decimal.number > 0.8:
|
||||
decimal.set_fill(BLACK)
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ def get_circle_drawing_terms(radius = 1, positioning_func = lambda m : m.center(
|
|||
0.25*rotate_vector(radius.get_vector(), TAU/4)
|
||||
),
|
||||
)
|
||||
decimal = DecimalNumber(0, num_decimal_points = 4, show_ellipsis = True)
|
||||
decimal = DecimalNumber(0, num_decimal_places = 4, show_ellipsis = True)
|
||||
decimal.scale(0.75)
|
||||
def reposition_decimal(decimal):
|
||||
vect = radius.get_vector()
|
||||
|
|
@ -318,7 +318,7 @@ class PiTauDebate(PiCreatureScene):
|
|||
circum_line.next_to(circle, DOWN, buff = MED_LARGE_BUFF)
|
||||
# circum_line.to_edge(LEFT)
|
||||
brace = Brace(circum_line, DOWN, buff = SMALL_BUFF)
|
||||
decimal = DecimalNumber(np.pi, num_decimal_points = 4, show_ellipsis = True)
|
||||
decimal = DecimalNumber(np.pi, num_decimal_places = 4, show_ellipsis = True)
|
||||
decimal.scale(0.75)
|
||||
decimal.next_to(brace, DOWN, SMALL_BUFF)
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class Introduction(Scene):
|
|||
)
|
||||
get_arrow_update().update(1)
|
||||
decimal = DecimalNumber(
|
||||
curr_product, num_decimal_points=5, show_ellipsis=True)
|
||||
curr_product, num_decimal_places=5, show_ellipsis=True)
|
||||
decimal.next_to(arrow, UP, SMALL_BUFF, submobject_to_align=decimal[:5])
|
||||
decimal_anim = ChangingDecimal(
|
||||
decimal,
|
||||
|
|
@ -512,7 +512,7 @@ class ShowProduct(Scene):
|
|||
])
|
||||
|
||||
brace = braces[0].copy()
|
||||
decimal = DecimalNumber(partial_products[0], num_decimal_points=4)
|
||||
decimal = DecimalNumber(partial_products[0], num_decimal_places=4)
|
||||
decimal.next_to(brace, DOWN)
|
||||
|
||||
self.add(brace, decimal, dots[0], parts[0])
|
||||
|
|
@ -677,7 +677,7 @@ class ShowProduct(Scene):
|
|||
])
|
||||
|
||||
brace = braces[0].copy()
|
||||
decimal = DecimalNumber(partial_products_iter.next(), num_decimal_points=4)
|
||||
decimal = DecimalNumber(partial_products_iter.next(), num_decimal_places=4)
|
||||
decimal.next_to(brace, DOWN)
|
||||
|
||||
self.play(*map(FadeIn, [brace, decimal, dots[0]]))
|
||||
|
|
@ -894,7 +894,7 @@ class DistanceProductScene(MovingCameraScene):
|
|||
self.d_labels.add(d_label)
|
||||
return self.d_labels
|
||||
|
||||
def get_numeric_distance_labels(self, lines=None, num_decimal_points=3, show_ellipsis=True):
|
||||
def get_numeric_distance_labels(self, lines=None, num_decimal_places=3, show_ellipsis=True):
|
||||
radius = self.circle.get_width() / 2
|
||||
if lines is None:
|
||||
if not hasattr(self, "distance_lines"):
|
||||
|
|
@ -904,7 +904,7 @@ class DistanceProductScene(MovingCameraScene):
|
|||
for line in lines:
|
||||
label = DecimalNumber(
|
||||
line.get_length() / radius,
|
||||
num_decimal_points=num_decimal_points,
|
||||
num_decimal_places=num_decimal_places,
|
||||
show_ellipsis=show_ellipsis,
|
||||
include_background_rectangle=self.include_distance_labels_background_rectangle,
|
||||
)
|
||||
|
|
@ -943,7 +943,7 @@ class DistanceProductScene(MovingCameraScene):
|
|||
|
||||
product_decimal = DecimalNumber(
|
||||
self.get_distance_product(fraction),
|
||||
num_decimal_points=3,
|
||||
num_decimal_places=3,
|
||||
show_ellipsis=True,
|
||||
include_background_rectangle=self.include_distance_labels_background_rectangle,
|
||||
)
|
||||
|
|
@ -1632,7 +1632,7 @@ class FromGeometryToAlgebra(DistanceProductScene):
|
|||
values = map(plane.point_to_number, self.get_lh_points())
|
||||
complex_decimal = self.complex_decimal = DecimalNumber(
|
||||
values[3],
|
||||
num_decimal_points=3,
|
||||
num_decimal_places=3,
|
||||
include_background_rectangle=True
|
||||
)
|
||||
complex_decimal.next_to(outer_arrow.get_start(), LEFT, SMALL_BUFF)
|
||||
|
|
@ -2190,7 +2190,7 @@ class PlugObserverIntoPolynomial(DistanceProductScene):
|
|||
|
||||
numeric_chord_label = DecimalNumber(
|
||||
np.sqrt(3),
|
||||
num_decimal_points=4,
|
||||
num_decimal_places=4,
|
||||
include_background_rectangle=True,
|
||||
show_ellipsis=True,
|
||||
)
|
||||
|
|
@ -2907,7 +2907,7 @@ class ProveLemma2(PlugObserverIntoPolynomial):
|
|||
|
||||
product = DecimalNumber(
|
||||
self.num_lighthouses,
|
||||
num_decimal_points=3,
|
||||
num_decimal_places=3,
|
||||
show_ellipsis=True
|
||||
)
|
||||
product.move_to(self.q_marks, LEFT)
|
||||
|
|
@ -3235,7 +3235,7 @@ class KeeperAndSailor(DistanceProductScene, PiCreatureScene):
|
|||
|
||||
new_keeper_dp_decimal = DecimalNumber(
|
||||
self.num_lighthouses,
|
||||
num_decimal_points=3,
|
||||
num_decimal_places=3,
|
||||
)
|
||||
new_keeper_dp_decimal.replace(keeper_dp_decimal, dim_to_match=1)
|
||||
new_keeper_dp_decimal.set_color(YELLOW)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ from utils.bezier import bezier
|
|||
from utils.simple_functions import sigmoid
|
||||
|
||||
|
||||
def linear(t):
|
||||
return t
|
||||
|
||||
def smooth(t, inflection=10.0):
|
||||
error = sigmoid(-inflection / 2)
|
||||
return (sigmoid(inflection * (t - 0.5)) - error) / (1 - 2 * error)
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
import os
|
||||
from constants import TEX_DIR
|
||||
from constants import TEX_TEXT_TO_REPLACE
|
||||
|
||||
|
||||
def tex_hash(expression, template_tex_file):
|
||||
return str(hash(expression + template_tex_file))
|
||||
|
||||
|
||||
def tex_to_svg_file(expression, template_tex_file):
|
||||
tex_file = generate_tex_file(expression, template_tex_file)
|
||||
dvi_file = tex_to_dvi(tex_file)
|
||||
return dvi_to_svg(dvi_file)
|
||||
|
||||
|
||||
def generate_tex_file(expression, template_tex_file):
|
||||
result = os.path.join(
|
||||
TEX_DIR,
|
||||
tex_hash(expression, template_tex_file)
|
||||
) + ".tex"
|
||||
if not os.path.exists(result):
|
||||
print("Writing \"%s\" to %s" % (
|
||||
"".join(expression), result
|
||||
))
|
||||
with open(template_tex_file, "r") as infile:
|
||||
body = infile.read()
|
||||
body = body.replace(TEX_TEXT_TO_REPLACE, expression)
|
||||
with open(result, "w") as outfile:
|
||||
outfile.write(body)
|
||||
return result
|
||||
|
||||
|
||||
def get_null():
|
||||
if os.name == "nt":
|
||||
return "NUL"
|
||||
return "/dev/null"
|
||||
|
||||
|
||||
def tex_to_dvi(tex_file):
|
||||
result = tex_file.replace(".tex", ".dvi")
|
||||
if not os.path.exists(result):
|
||||
commands = [
|
||||
"latex",
|
||||
"-interaction=batchmode",
|
||||
"-halt-on-error",
|
||||
"-output-directory=" + TEX_DIR,
|
||||
tex_file,
|
||||
">",
|
||||
get_null()
|
||||
]
|
||||
exit_code = os.system(" ".join(commands))
|
||||
if exit_code != 0:
|
||||
log_file = tex_file.replace(".tex", ".log")
|
||||
raise Exception(
|
||||
"Latex error converting to dvi. "
|
||||
"See log output above or the log file: %s" % log_file)
|
||||
return result
|
||||
|
||||
|
||||
def dvi_to_svg(dvi_file, regen_if_exists=False):
|
||||
"""
|
||||
Converts a dvi, which potentially has multiple slides, into a
|
||||
directory full of enumerated pngs corresponding with these slides.
|
||||
Returns a list of PIL Image objects for these images sorted as they
|
||||
where in the dvi
|
||||
"""
|
||||
result = dvi_file.replace(".dvi", ".svg")
|
||||
if not os.path.exists(result):
|
||||
commands = [
|
||||
"dvisvgm",
|
||||
dvi_file,
|
||||
"-n",
|
||||
"-v",
|
||||
"0",
|
||||
"-o",
|
||||
result,
|
||||
">",
|
||||
get_null()
|
||||
]
|
||||
os.system(" ".join(commands))
|
||||
return result
|
||||
Loading…
Add table
Reference in a new issue