mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
3819 lines
112 KiB
Python
3819 lines
112 KiB
Python
from manimlib.imports import *
|
|
from from_3b1b.active.bayes.beta_helpers import *
|
|
|
|
import scipy.stats
|
|
|
|
OUTPUT_DIRECTORY = "bayes/beta1"
|
|
|
|
|
|
# Scenes
|
|
class BarChartTest(Scene):
|
|
def construct(self):
|
|
bar_chart = BarChart()
|
|
bar_chart.to_edge(DOWN)
|
|
self.add(bar_chart)
|
|
|
|
|
|
class Thumbnail1(Scene):
|
|
def construct(self):
|
|
p1 = "$96\\%$"
|
|
p2 = "$93\\%$"
|
|
n1 = "50"
|
|
n2 = "200"
|
|
t2c = {
|
|
p1: BLUE,
|
|
p2: YELLOW,
|
|
n1: BLUE_C,
|
|
n2: YELLOW,
|
|
}
|
|
kw = {"tex_to_color_map": t2c}
|
|
text = VGroup(
|
|
TextMobject(f"{p1} with {n1} reviews", **kw),
|
|
TextMobject("vs.", **kw),
|
|
TextMobject(f"{p2} with {n2} reviews", **kw),
|
|
)
|
|
fix_percent(text[0].get_part_by_tex(p1)[-1])
|
|
fix_percent(text[2].get_part_by_tex(p2)[-1])
|
|
text.scale(2)
|
|
text.arrange(DOWN, buff=LARGE_BUFF)
|
|
text.set_width(FRAME_WIDTH - 1)
|
|
self.add(text)
|
|
|
|
|
|
class AltThumbnail1(Scene):
|
|
def construct(self):
|
|
N = 20
|
|
n_trials = 10000
|
|
p = 0.7
|
|
outcomes = (np.random.random((N, n_trials)) < p).sum(0)
|
|
counts = []
|
|
for k in range(N + 1):
|
|
counts.append((outcomes == k).sum())
|
|
|
|
hist = Histogram(
|
|
counts,
|
|
y_max=0.3,
|
|
y_tick_freq=0.05,
|
|
y_axis_numbers_to_show=[10, 20, 30],
|
|
x_label_freq=10,
|
|
)
|
|
hist.set_width(FRAME_WIDTH - 1)
|
|
hist.bars.set_submobject_colors_by_gradient(YELLOW, YELLOW, GREEN, BLUE)
|
|
hist.bars.set_stroke(WHITE, 2)
|
|
|
|
title = TextMobject("Binomial distribution")
|
|
title.set_width(12)
|
|
title.to_corner(UR, buff=0.8)
|
|
title.add_background_rectangle()
|
|
|
|
self.add(hist)
|
|
self.add(title)
|
|
|
|
|
|
class Thumbnail2(Scene):
|
|
def construct(self):
|
|
axes = self.get_axes()
|
|
graph = get_beta_graph(axes, 2, 2)
|
|
# sub_graph = axes.get_graph(
|
|
# lambda x: (1 - x) * graph.underlying_function(x)
|
|
# )
|
|
# sub_graph.add_line_to(axes.c2p(1, 0))
|
|
# sub_graph.add_line_to(axes.c2p(0, 0))
|
|
# sub_graph.set_stroke(YELLOW, 4)
|
|
# sub_graph.set_fill(YELLOW_D, 1)
|
|
|
|
new_graph = get_beta_graph(axes, 9, 2)
|
|
new_graph.set_stroke(GREEN, 4)
|
|
new_graph.set_fill(GREEN, 0.5)
|
|
|
|
self.add(axes)
|
|
self.add(graph)
|
|
self.add(new_graph)
|
|
|
|
arrow = Arrow(
|
|
axes.input_to_graph_point(0.5, graph),
|
|
axes.input_to_graph_point(0.8, new_graph),
|
|
path_arc=-90 * DEGREES,
|
|
buff=0.3
|
|
)
|
|
self.add(arrow)
|
|
|
|
formula = TexMobject(
|
|
"P(H|D) = {P(H)P(D|H) \\over P(D)}",
|
|
tex_to_color_map={
|
|
"H": YELLOW,
|
|
"D": GREEN,
|
|
}
|
|
)
|
|
formula.next_to(axes.c2p(0, 3), RIGHT, LARGE_BUFF)
|
|
formula.set_height(1.5)
|
|
formula.to_edge(LEFT)
|
|
formula.to_edge(UP, LARGE_BUFF)
|
|
formula.add_to_back(BackgroundRectangle(formula[:4], buff=0.25))
|
|
|
|
self.add(formula)
|
|
|
|
def get_axes(self, y_max=3, y_height=4.5, y_unit=0.5):
|
|
axes = get_beta_dist_axes(y_max=y_max, y_unit=y_unit)
|
|
axes.y_axis.set_height(y_height, about_point=axes.c2p(0, 0))
|
|
axes.to_edge(DOWN)
|
|
axes.scale(0.9)
|
|
return axes
|
|
|
|
|
|
class Thumbnail3(Thumbnail2):
|
|
def construct(self):
|
|
axes = self.get_axes(y_max=4, y_height=6)
|
|
axes.set_height(7)
|
|
graph = get_beta_graph(axes, 9, 2)
|
|
|
|
self.add(axes)
|
|
self.add(graph)
|
|
|
|
label = TexMobject(
|
|
"\\text{Beta}(10, 3)",
|
|
tex_to_color_map={
|
|
"10": GREEN,
|
|
"3": RED,
|
|
}
|
|
)
|
|
label = get_beta_label(9, 2)
|
|
label.set_height(1.25)
|
|
label.next_to(axes.c2p(0, 3), RIGHT, LARGE_BUFF)
|
|
|
|
self.add(label)
|
|
|
|
|
|
class HighlightReviewParts(Scene):
|
|
CONFIG = {
|
|
"reverse_order": False,
|
|
}
|
|
|
|
def construct(self):
|
|
# Setup up rectangles
|
|
rects = VGroup(*[Rectangle() for x in range(3)])
|
|
rects.set_stroke(width=0)
|
|
rects.set_fill(GREY, 0.5)
|
|
|
|
rects.set_height(1.35, stretch=True)
|
|
rects.set_width(9.75, stretch=True)
|
|
|
|
rects[0].move_to([-0.2, 0.5, 0])
|
|
rects[1].next_to(rects[0], DOWN, buff=0)
|
|
rects[2].next_to(rects[1], DOWN, buff=0)
|
|
|
|
rects[2].set_height(1, stretch=True, about_edge=UP)
|
|
|
|
inv_rects = VGroup()
|
|
for rect in rects:
|
|
fsr = FullScreenFadeRectangle()
|
|
fsr.append_points(rect.points[::-1])
|
|
inv_rects.add(fsr)
|
|
|
|
inv_rects.set_fill(BLACK, 0.85)
|
|
|
|
# Set up labels
|
|
ratings = [100, 96, 93]
|
|
n_reviews = [10, 50, 200]
|
|
colors = [PINK, BLUE, YELLOW]
|
|
|
|
review_labels = VGroup()
|
|
for rect, rating, nr, color in zip(rects, ratings, n_reviews, colors):
|
|
label = TexMobject(
|
|
f"{nr}", "\\text{ reviews }",
|
|
f"{rating}", "\\%",
|
|
)
|
|
label[2:].set_color(color)
|
|
label.set_height(1)
|
|
label.next_to(rect, UP, aligned_edge=RIGHT)
|
|
label.set_stroke(BLACK, 4, background=True)
|
|
fix_percent(label[3][0])
|
|
review_labels.add(label)
|
|
|
|
# Animations
|
|
curr_fsr = inv_rects[0]
|
|
curr_label = None
|
|
|
|
tuples = list(zip(inv_rects, review_labels))
|
|
if self.reverse_order:
|
|
tuples = reversed(tuples)
|
|
curr_fsr = inv_rects[-1]
|
|
|
|
for fsr, label in tuples:
|
|
if curr_fsr is fsr:
|
|
self.play(VFadeIn(fsr))
|
|
else:
|
|
self.play(
|
|
Transform(curr_fsr, fsr),
|
|
MoveToTarget(curr_label),
|
|
)
|
|
|
|
first, second = label[2:], label[:2]
|
|
if self.reverse_order:
|
|
first, second = second, first
|
|
|
|
self.add(first)
|
|
self.wait(2)
|
|
self.add(second)
|
|
self.wait(2)
|
|
|
|
label.generate_target()
|
|
label.target.scale(0.3)
|
|
if curr_label is None:
|
|
label.target.to_corner(UR)
|
|
label.target.shift(MED_LARGE_BUFF * LEFT)
|
|
else:
|
|
label.target.next_to(curr_label, DOWN)
|
|
|
|
curr_label = label
|
|
self.play(MoveToTarget(curr_label))
|
|
self.wait()
|
|
|
|
br = BackgroundRectangle(review_labels, buff=0.25)
|
|
br.set_fill(BLACK, 0.85)
|
|
br.set_width(FRAME_WIDTH)
|
|
br.set_height(FRAME_HEIGHT, stretch=True)
|
|
br.center()
|
|
self.add(br, review_labels)
|
|
self.play(
|
|
FadeOut(curr_fsr),
|
|
FadeIn(br),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ShowThreeCases(Scene):
|
|
def construct(self):
|
|
titles = self.get_titles()
|
|
reviews = self.get_reviews(titles)
|
|
for review in reviews:
|
|
review.match_x(reviews[2])
|
|
|
|
# Introduce everything
|
|
self.play(LaggedStartMap(
|
|
FadeInFrom, titles,
|
|
lambda m: (m, DOWN),
|
|
lag_ratio=0.2
|
|
))
|
|
self.play(LaggedStart(*[
|
|
LaggedStartMap(
|
|
FadeInFromLarge, review,
|
|
lag_ratio=0.1
|
|
)
|
|
for review in reviews
|
|
], lag_ratio=0.1))
|
|
self.add(reviews)
|
|
self.wait()
|
|
|
|
self.play(ShowCreationThenFadeAround(reviews[2]))
|
|
self.wait()
|
|
|
|
# Suspicious of 100%
|
|
randy = Randolph()
|
|
randy.flip()
|
|
randy.set_height(2)
|
|
randy.next_to(
|
|
reviews[0], RIGHT, LARGE_BUFF,
|
|
aligned_edge=UP,
|
|
)
|
|
randy.look_at(reviews[0])
|
|
self.play(FadeIn(randy))
|
|
self.play(randy.change, "sassy")
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
self.play(FadeOut(randy))
|
|
|
|
# Low number means it could be a fluke.
|
|
review = reviews[0]
|
|
|
|
review.generate_target()
|
|
review.target.scale(2)
|
|
review.target.arrange(RIGHT)
|
|
review.target.move_to(review)
|
|
|
|
self.play(MoveToTarget(review))
|
|
|
|
alt_negs = [1, 2, 1, 0]
|
|
alt_reviews = VGroup()
|
|
for k in alt_negs:
|
|
alt_reviews.add(self.get_plusses_and_minuses(titles[0], 1, 10, k))
|
|
for ar in alt_reviews:
|
|
for m1, m2 in zip(ar, review):
|
|
m1.replace(m2)
|
|
|
|
alt_percents = VGroup(*[
|
|
TexMobject(str(10 * (10 - k)) + "\\%")
|
|
for k in alt_negs
|
|
])
|
|
hundo = titles[0][0]
|
|
for ap in alt_percents:
|
|
fix_percent(ap.family_members_with_points()[-1])
|
|
ap.match_style(hundo)
|
|
ap.match_height(hundo)
|
|
ap.move_to(hundo, RIGHT)
|
|
|
|
last_review = review
|
|
last_percent = hundo
|
|
for ar, ap in zip(alt_reviews, alt_percents):
|
|
self.play(
|
|
FadeInFrom(ar, 0.5 * DOWN, lag_ratio=0.2),
|
|
FadeOut(last_review),
|
|
FadeInFrom(ap, 0.5 * DOWN),
|
|
FadeOutAndShift(last_percent, 0.5 * UP),
|
|
run_time=1.5
|
|
)
|
|
last_review = ar
|
|
last_percent = ap
|
|
self.remove(last_review, last_percent)
|
|
self.add(titles, *reviews)
|
|
|
|
# How do you think about the tradeoff?
|
|
p1 = titles[1][0]
|
|
p2 = titles[2][0]
|
|
nums = VGroup(p1, p2)
|
|
lower_reviews = reviews[1:]
|
|
lower_reviews.generate_target()
|
|
lower_reviews.target.arrange(LEFT, buff=1.5)
|
|
lower_reviews.target.center()
|
|
nums.generate_target()
|
|
for nt, review in zip(nums.target, lower_reviews.target):
|
|
nt.next_to(review, UP, MED_LARGE_BUFF)
|
|
|
|
nums.target[0].match_y(nums.target[1])
|
|
|
|
self.clear()
|
|
self.play(
|
|
MoveToTarget(lower_reviews),
|
|
MoveToTarget(nums),
|
|
FadeOut(titles[1][1:]),
|
|
FadeOut(titles[2][1:]),
|
|
FadeOut(titles[0]),
|
|
FadeOut(reviews[0]),
|
|
run_time=2,
|
|
)
|
|
|
|
greater_than = TexMobject(">")
|
|
greater_than.scale(2)
|
|
greater_than.move_to(midpoint(
|
|
reviews[2].get_right(),
|
|
reviews[1].get_left(),
|
|
))
|
|
less_than = greater_than.copy().flip()
|
|
less_than.match_height(nums[0][0])
|
|
less_than.match_y(nums, DOWN)
|
|
|
|
nums.generate_target()
|
|
nums.target[1].next_to(less_than, LEFT, MED_LARGE_BUFF)
|
|
nums.target[0].next_to(less_than, RIGHT, MED_LARGE_BUFF)
|
|
|
|
squares = VGroup(*[
|
|
SurroundingRectangle(
|
|
submob, buff=0.01,
|
|
stroke_color=LIGHT_GREY,
|
|
stroke_width=1,
|
|
)
|
|
for submob in reviews[2]
|
|
])
|
|
squares.shuffle()
|
|
self.play(
|
|
LaggedStartMap(
|
|
ShowCreationThenFadeOut, squares,
|
|
lag_ratio=0.5 / len(squares),
|
|
run_time=3,
|
|
),
|
|
Write(greater_than),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
MoveToTarget(nums),
|
|
TransformFromCopy(
|
|
greater_than, less_than,
|
|
)
|
|
)
|
|
self.wait()
|
|
|
|
def get_titles(self):
|
|
titles = VGroup(
|
|
TextMobject(
|
|
"$100\\%$ \\\\",
|
|
"10 reviews"
|
|
),
|
|
TextMobject(
|
|
"$96\\%$ \\\\",
|
|
"50 reviews"
|
|
),
|
|
TextMobject(
|
|
"$93\\%$ \\\\",
|
|
"200 reviews"
|
|
),
|
|
)
|
|
colors = [PINK, BLUE, YELLOW]
|
|
for title, color in zip(titles, colors):
|
|
fix_percent(title[0][-1])
|
|
title[0].set_color(color)
|
|
|
|
titles.scale(1.25)
|
|
titles.arrange(DOWN, buff=1.5)
|
|
titles.to_corner(UL)
|
|
return titles
|
|
|
|
def get_reviews(self, titles):
|
|
return VGroup(
|
|
self.get_plusses_and_minuses(
|
|
titles[0], 5, 2, 0,
|
|
),
|
|
self.get_plusses_and_minuses(
|
|
titles[1], 5, 10, 2,
|
|
),
|
|
self.get_plusses_and_minuses(
|
|
titles[2], 8, 25, 14,
|
|
),
|
|
)
|
|
|
|
def get_plusses_and_minuses(self, title, n_rows, n_cols, n_minus):
|
|
check = TexMobject(CMARK_TEX, color=GREEN)
|
|
cross = TexMobject(XMARK_TEX, color=RED)
|
|
checks = VGroup(*[
|
|
check.copy() for x in range(n_rows * n_cols)
|
|
])
|
|
checks.arrange_in_grid(n_rows=n_rows, n_cols=n_cols)
|
|
checks.scale(0.5)
|
|
# if checks.get_height() > title.get_height():
|
|
# checks.match_height(title)
|
|
checks.next_to(title, RIGHT, LARGE_BUFF)
|
|
|
|
for check in random.sample(list(checks), n_minus):
|
|
mob = cross.copy()
|
|
mob.replace(check, dim_to_match=0)
|
|
check.become(mob)
|
|
|
|
return checks
|
|
|
|
|
|
class PreviewThreeVideos(Scene):
|
|
def construct(self):
|
|
# Write equations
|
|
equations = VGroup(
|
|
TexMobject("{10", "\\over", "10}", "=", "100\\%"),
|
|
TexMobject("{48", "\\over", "50}", "=", "96\\%"),
|
|
TexMobject("{186", "\\over", "200}", "=", "93\\%"),
|
|
)
|
|
equations.arrange(RIGHT, buff=3)
|
|
equations.to_edge(UP)
|
|
|
|
colors = [PINK, BLUE, YELLOW]
|
|
for eq, color in zip(equations, colors):
|
|
eq[-1].set_color(color)
|
|
fix_percent(eq[-1][-1])
|
|
|
|
vs_labels = VGroup(*[TextMobject("vs.") for x in range(2)])
|
|
for eq1, eq2, vs in zip(equations, equations[1:], vs_labels):
|
|
vs.move_to(midpoint(eq1.get_right(), eq2.get_left()))
|
|
|
|
self.add(equations)
|
|
self.add(vs_labels)
|
|
|
|
# Show topics
|
|
title = TextMobject("To be explained:")
|
|
title.set_height(0.7)
|
|
title.next_to(equations, DOWN, LARGE_BUFF)
|
|
title.to_edge(LEFT)
|
|
title.add(Underline(title))
|
|
|
|
topics = VGroup(
|
|
TextMobject("Binomial distributions"),
|
|
TextMobject("Bayesian updating"),
|
|
TextMobject("Probability density functions"),
|
|
TextMobject("Beta distribution"),
|
|
)
|
|
topics.arrange(DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT)
|
|
topics.next_to(title, DOWN, MED_LARGE_BUFF)
|
|
topics.to_edge(LEFT, buff=LARGE_BUFF)
|
|
|
|
bullets = VGroup()
|
|
for topic in topics:
|
|
bullet = Dot()
|
|
bullet.next_to(topic, LEFT)
|
|
bullets.add(bullet)
|
|
|
|
self.play(
|
|
Write(title),
|
|
Write(bullets),
|
|
run_time=1,
|
|
)
|
|
self.play(LaggedStart(*[
|
|
FadeIn(topic, lag_ratio=0.1)
|
|
for topic in topics
|
|
], run_time=3, lag_ratio=0.3))
|
|
self.wait()
|
|
|
|
# Show videos
|
|
images = [
|
|
ImageMobject(os.path.join(
|
|
consts.VIDEO_DIR,
|
|
OUTPUT_DIRECTORY,
|
|
"images",
|
|
name
|
|
))
|
|
for name in ["Thumbnail1", "Thumbnail2", "Thumbnail3"]
|
|
]
|
|
thumbnails = Group()
|
|
for image in images:
|
|
image.set_width(FRAME_WIDTH / 3 - 1)
|
|
rect = SurroundingRectangle(image, buff=0)
|
|
rect.set_stroke(WHITE, 3)
|
|
rect.set_fill(BLACK, 1)
|
|
thumbnails.add(Group(rect, image))
|
|
|
|
thumbnails.arrange(RIGHT, buff=LARGE_BUFF)
|
|
|
|
for topic, i in zip(topics, [0, 1, 1, 2]):
|
|
thumbnail = thumbnails[i]
|
|
topic.generate_target()
|
|
topic.target.scale(0.6)
|
|
topic.target.next_to(thumbnail, DOWN, aligned_edge=LEFT)
|
|
topics[2].target.next_to(
|
|
topics[1].target, DOWN,
|
|
aligned_edge=LEFT,
|
|
)
|
|
|
|
self.play(
|
|
FadeOutAndShift(title, LEFT),
|
|
FadeOutAndShift(bullets, LEFT),
|
|
LaggedStartMap(MoveToTarget, topics),
|
|
LaggedStartMap(FadeIn, thumbnails),
|
|
)
|
|
self.wait()
|
|
|
|
tn_groups = Group(
|
|
Group(thumbnails[0], topics[0]),
|
|
Group(thumbnails[1], topics[1], topics[2]),
|
|
Group(thumbnails[2], topics[3]),
|
|
)
|
|
|
|
setup_words = TextMobject("Set up the model")
|
|
analysis_words = TextMobject("Analysis")
|
|
for words in [setup_words, analysis_words]:
|
|
words.scale(topics[0][0].get_height() / words[0][0].get_height())
|
|
words.set_color(YELLOW)
|
|
setup_words.move_to(topics[0], UL)
|
|
analysis_words.next_to(topics[3], DOWN, aligned_edge=LEFT)
|
|
|
|
def set_opacity(mob, alpha):
|
|
for sm in mob.family_members_with_points():
|
|
sm.set_opacity(alpha)
|
|
return mob
|
|
|
|
self.play(ApplyFunction(lambda m: set_opacity(m, 0.2), tn_groups[1:]))
|
|
self.play(
|
|
FadeIn(setup_words, lag_ratio=0.1),
|
|
topics[0].next_to, setup_words, DOWN, {"aligned_edge": LEFT},
|
|
)
|
|
tn_groups[0].add(setup_words)
|
|
self.wait(2)
|
|
for i in 0, 1:
|
|
self.play(
|
|
ApplyFunction(lambda m: set_opacity(m, 0.2), tn_groups[i]),
|
|
ApplyFunction(lambda m: set_opacity(m, 1), tn_groups[i + 1]),
|
|
)
|
|
self.wait(2)
|
|
self.play(FadeInFrom(analysis_words, 0.25 * UP))
|
|
tn_groups[2].add(analysis_words)
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
FadeOut(setup_words),
|
|
FadeOut(topics[0]),
|
|
FadeOut(tn_groups[1]),
|
|
FadeOut(tn_groups[2]),
|
|
FadeOutAndShift(vs_labels, UP),
|
|
FadeOutAndShift(equations, UP),
|
|
ApplyFunction(lambda m: set_opacity(m, 1), thumbnails[0]),
|
|
)
|
|
thumbnails[0].generate_target()
|
|
# thumbnails[0].target.set_width(FRAME_WIDTH)
|
|
# thumbnails[0].target.center()
|
|
thumbnails[0].target.to_edge(UP)
|
|
self.play(MoveToTarget(thumbnails[0], run_time=4))
|
|
self.wait()
|
|
|
|
|
|
class LetsLookAtOneAnswer(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.remove(self.background)
|
|
self.teacher_says(
|
|
"Let me show you\\\\one answer.",
|
|
added_anims=[
|
|
self.get_student_changes("pondering", "thinking", "pondering")
|
|
]
|
|
)
|
|
self.look_at(self.screen)
|
|
self.change_all_student_modes("thinking", look_at_arg=self.screen)
|
|
self.wait(4)
|
|
|
|
|
|
class LaplacesRuleOfSuccession(Scene):
|
|
def construct(self):
|
|
# Setup
|
|
title = TextMobject("How to read a rating")
|
|
title.set_height(0.75)
|
|
title.to_edge(UP)
|
|
underline = Underline(title)
|
|
underline.scale(1.2)
|
|
self.add(title, underline)
|
|
|
|
data = get_checks_and_crosses(11 * [True] + [False], width=10)
|
|
data.shift(DOWN)
|
|
underlines = get_underlines(data)
|
|
|
|
real_data = data[:10]
|
|
fake_data = data[10:]
|
|
|
|
def get_review_label(num, denom):
|
|
result = VGroup(
|
|
Integer(num, color=GREEN),
|
|
TextMobject("out of"),
|
|
Integer(denom),
|
|
)
|
|
result.arrange(RIGHT)
|
|
result.set_height(0.6)
|
|
return result
|
|
|
|
review_label = get_review_label(10, 10)
|
|
review_label.next_to(data[:10], UP, MED_LARGE_BUFF)
|
|
|
|
# Show initial review
|
|
self.add(review_label)
|
|
self.add(underlines[:10])
|
|
|
|
self.play(
|
|
ShowIncreasingSubsets(real_data, int_func=np.ceil),
|
|
CountInFrom(review_label[0], 0),
|
|
rate_func=lambda t: smooth(t, 3),
|
|
)
|
|
self.wait()
|
|
|
|
# Fake data
|
|
fd_rect = SurroundingRectangle(VGroup(fake_data, underlines[10:]))
|
|
fd_rect.set_stroke(WHITE, 2)
|
|
fd_rect.set_fill(GREY_E, 1)
|
|
|
|
fd_label = TextMobject("Pretend you see\\\\two more")
|
|
fd_label.next_to(fd_rect, DOWN)
|
|
fd_label.shift_onto_screen()
|
|
|
|
self.play(
|
|
FadeInFrom(fd_label, UP),
|
|
DrawBorderThenFill(fd_rect),
|
|
ShowCreation(underlines[10:])
|
|
)
|
|
self.wait()
|
|
for mark in data[10:]:
|
|
self.play(Write(mark))
|
|
self.wait()
|
|
|
|
# Update rating
|
|
review_center = VectorizedPoint(review_label.get_center())
|
|
pretend_label = TextMobject("Pretend that it's")
|
|
pretend_label.match_width(review_label)
|
|
pretend_label.next_to(review_label, UP, MED_LARGE_BUFF)
|
|
pretend_label.match_x(data)
|
|
pretend_label.set_color(BLUE_D)
|
|
|
|
old_review_label = VGroup(Integer(0), TextMobject("out of"), Integer(0))
|
|
old_review_label.become(review_label)
|
|
|
|
self.add(old_review_label, review_label)
|
|
self.play(
|
|
review_center.set_x, data.get_center()[0],
|
|
MaintainPositionRelativeTo(review_label, review_center),
|
|
UpdateFromAlphaFunc(
|
|
review_label[0],
|
|
lambda m, a: m.set_value(int(interpolate(10, 11, a)))
|
|
),
|
|
UpdateFromAlphaFunc(
|
|
review_label[2],
|
|
lambda m, a: m.set_value(int(interpolate(10, 12, a)))
|
|
),
|
|
FadeInFrom(pretend_label, LEFT),
|
|
old_review_label.scale, 0.5,
|
|
old_review_label.set_opacity, 0.5,
|
|
old_review_label.to_edge, LEFT,
|
|
)
|
|
self.wait()
|
|
|
|
# Show fraction
|
|
eq = TexMobject(
|
|
"{11", "\\over", "12}",
|
|
"\\approx", "91.7\\%"
|
|
)
|
|
fix_percent(eq[-1][-1])
|
|
eq.set_color_by_tex("11", GREEN)
|
|
|
|
eq.next_to(pretend_label, RIGHT)
|
|
eq.to_edge(RIGHT, buff=MED_LARGE_BUFF)
|
|
|
|
self.play(Write(eq))
|
|
self.wait()
|
|
self.play(ShowCreationThenFadeAround(eq))
|
|
self.wait()
|
|
|
|
# Remove clutter
|
|
old_review_label.generate_target()
|
|
old_review_label.target.next_to(title, DOWN, LARGE_BUFF)
|
|
old_review_label.target.to_edge(LEFT)
|
|
old_review_label.target.set_opacity(1)
|
|
arrow = Vector(0.5 * RIGHT)
|
|
arrow.next_to(old_review_label.target, RIGHT)
|
|
|
|
self.play(
|
|
MoveToTarget(old_review_label),
|
|
FadeIn(arrow),
|
|
eq.next_to, arrow, RIGHT,
|
|
FadeOutAndShift(
|
|
VGroup(
|
|
fake_data,
|
|
underlines,
|
|
pretend_label,
|
|
review_label,
|
|
fd_rect, fd_label,
|
|
),
|
|
DOWN,
|
|
lag_ratio=0.01,
|
|
),
|
|
real_data.match_width, old_review_label.target,
|
|
real_data.next_to, old_review_label.target, DOWN,
|
|
)
|
|
self.wait()
|
|
|
|
# Show 48 of 50 case
|
|
# Largely copied from above...not great
|
|
data = get_checks_and_crosses(
|
|
48 * [True] + 2 * [False] + [True, False],
|
|
width=FRAME_WIDTH - 1,
|
|
)
|
|
data.shift(DOWN)
|
|
underlines = get_underlines(data)
|
|
|
|
review_label = get_review_label(48, 50)
|
|
review_label.next_to(data, UP, MED_LARGE_BUFF)
|
|
|
|
true_data = data[:-2]
|
|
fake_data = data[-2:]
|
|
|
|
fd_rect.replace(fake_data, stretch=True)
|
|
fd_rect.stretch(1.2, 0)
|
|
fd_rect.stretch(2.2, 1)
|
|
fd_rect.shift(0.025 * DOWN)
|
|
fd_label.next_to(fd_rect, DOWN, LARGE_BUFF)
|
|
fd_label.shift_onto_screen()
|
|
fd_arrow = Arrow(fd_label.get_top(), fd_rect.get_corner(DL))
|
|
|
|
self.play(
|
|
FadeIn(underlines[:-2]),
|
|
ShowIncreasingSubsets(true_data, int_func=np.ceil),
|
|
CountInFrom(review_label[0], 0),
|
|
UpdateFromAlphaFunc(
|
|
review_label,
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(fd_label),
|
|
GrowArrow(fd_arrow),
|
|
FadeIn(fd_rect),
|
|
Write(fake_data),
|
|
Write(underlines[-2:]),
|
|
)
|
|
self.wait()
|
|
|
|
# Pretend it's 49 / 52
|
|
old_review_label = VGroup(Integer(0), TextMobject("out of"), Integer(0))
|
|
old_review_label.become(review_label)
|
|
review_center = VectorizedPoint(review_label.get_center())
|
|
|
|
self.play(
|
|
review_center.set_x, data.get_center()[0] + 3,
|
|
MaintainPositionRelativeTo(review_label, review_center),
|
|
UpdateFromAlphaFunc(
|
|
review_label[0],
|
|
lambda m, a: m.set_value(int(interpolate(48, 49, a)))
|
|
),
|
|
UpdateFromAlphaFunc(
|
|
review_label[2],
|
|
lambda m, a: m.set_value(int(interpolate(50, 52, a)))
|
|
),
|
|
old_review_label.scale, 0.5,
|
|
old_review_label.to_edge, LEFT,
|
|
)
|
|
self.wait()
|
|
|
|
arrow2 = Vector(0.5 * RIGHT)
|
|
arrow2.next_to(old_review_label, RIGHT)
|
|
|
|
eq2 = TexMobject(
|
|
"{49", "\\over", "52}",
|
|
"\\approx", "94.2\\%"
|
|
)
|
|
fix_percent(eq2[-1][-1])
|
|
eq2[0].set_color(GREEN)
|
|
eq2.next_to(arrow2, RIGHT)
|
|
eq2.save_state()
|
|
eq2[1].set_opacity(0)
|
|
eq2[3:].set_opacity(0)
|
|
eq2[0].replace(review_label[0])
|
|
eq2[2].replace(review_label[2])
|
|
|
|
self.play(
|
|
Restore(eq2, run_time=1.5),
|
|
FadeIn(arrow2),
|
|
)
|
|
self.wait()
|
|
|
|
faders = VGroup(
|
|
fd_rect, fd_arrow, fd_label,
|
|
fake_data, underlines,
|
|
review_label,
|
|
)
|
|
self.play(
|
|
FadeOut(faders),
|
|
true_data.match_width, old_review_label,
|
|
true_data.next_to, old_review_label, DOWN,
|
|
)
|
|
|
|
# 200 review case
|
|
final_review_label = get_review_label(186, 200)
|
|
final_review_label.match_height(old_review_label)
|
|
final_review_label.move_to(old_review_label, LEFT)
|
|
final_review_label.shift(
|
|
arrow2.get_center() -
|
|
arrow.get_center()
|
|
)
|
|
|
|
data = get_checks_and_crosses([True] * 186 + [False] * 14 + [True, False])
|
|
data[:200].arrange_in_grid(10, 20, buff=0)
|
|
data[-2:].next_to(data[:200], DOWN, buff=0)
|
|
data.set_width(FRAME_WIDTH / 2 - 1)
|
|
data.to_edge(RIGHT, buff=MED_SMALL_BUFF)
|
|
data.to_edge(DOWN)
|
|
for mark in data:
|
|
mark.scale(0.5)
|
|
|
|
true_data = data[:-2]
|
|
fake_data = data[-2:]
|
|
|
|
self.play(
|
|
UpdateFromAlphaFunc(
|
|
final_review_label,
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
CountInFrom(final_review_label[0], 0),
|
|
ShowIncreasingSubsets(true_data),
|
|
)
|
|
self.wait()
|
|
|
|
arrow3 = Vector(0.5 * RIGHT)
|
|
arrow3.next_to(final_review_label, RIGHT)
|
|
|
|
eq3 = TexMobject(
|
|
"{187", "\\over", "202}",
|
|
"\\approx", "92.6\\%"
|
|
)
|
|
fix_percent(eq3[-1][-1])
|
|
eq3[0].set_color(GREEN)
|
|
eq3.next_to(arrow3, RIGHT)
|
|
|
|
self.play(
|
|
GrowArrow(arrow3),
|
|
FadeIn(eq3),
|
|
Write(fake_data)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
true_data.match_width, final_review_label,
|
|
true_data.next_to, final_review_label, DOWN,
|
|
FadeOut(fake_data)
|
|
)
|
|
self.wait()
|
|
|
|
# Make a selection
|
|
rect = SurroundingRectangle(VGroup(eq2, old_review_label))
|
|
rect.set_stroke(YELLOW, 2)
|
|
|
|
self.play(
|
|
ShowCreation(rect),
|
|
eq2[-1].set_color, YELLOW,
|
|
)
|
|
self.wait()
|
|
|
|
# Retitle
|
|
name = TextMobject("Laplace's rule of succession")
|
|
name.match_height(title)
|
|
name.move_to(title)
|
|
name.set_color(TEAL)
|
|
|
|
self.play(
|
|
FadeInFromDown(name),
|
|
FadeOutAndShift(title, UP),
|
|
underline.match_width, name,
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class AskWhy(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"Wait...why?",
|
|
look_at_arg=self.screen,
|
|
)
|
|
self.play(
|
|
self.students[0].change, "confused", self.screen,
|
|
self.students[1].change, "confused", self.screen,
|
|
self.teacher.change, "tease", self.students[2].eyes,
|
|
)
|
|
self.wait(3)
|
|
|
|
self.students[2].bubble.content.unlock_triangulation()
|
|
self.student_says(
|
|
"Is that really\\\\the answer?",
|
|
target_mode="raise_right_hand",
|
|
added_anims=[self.teacher.change, "thinking"],
|
|
)
|
|
self.wait(2)
|
|
self.teacher_says("Let's dive in!", target_mode="hooray")
|
|
self.change_all_student_modes("hooray")
|
|
self.wait(3)
|
|
|
|
|
|
class BinomialName(Scene):
|
|
def construct(self):
|
|
text = TextMobject("Probabilities of probabilities\\\\", "Part 1")
|
|
text.set_width(FRAME_WIDTH - 1)
|
|
text[0].set_color(BLUE)
|
|
self.add(text[0])
|
|
self.play(Write(text[1], run_time=2))
|
|
self.wait(2)
|
|
|
|
|
|
class WhatsTheModel(Scene):
|
|
CONFIG = {
|
|
"random_seed": 5,
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_questions()
|
|
self.introduce_buyer_and_seller()
|
|
|
|
for x in range(3):
|
|
self.play(*self.experience_animations(self.seller, self.buyer))
|
|
self.wait()
|
|
|
|
self.add_probability_label()
|
|
self.bring_up_goal()
|
|
|
|
def add_questions(self):
|
|
questions = VGroup(
|
|
TextMobject("What's the model?"),
|
|
TextMobject("What are you optimizing?"),
|
|
)
|
|
for question, vect in zip(questions, [LEFT, RIGHT]):
|
|
question.move_to(vect * FRAME_WIDTH / 4)
|
|
questions.arrange(DOWN, buff=LARGE_BUFF)
|
|
questions.scale(1.5)
|
|
|
|
# Intro questions
|
|
self.play(FadeInFrom(questions[0]))
|
|
self.play(FadeInFrom(questions[1], UP))
|
|
self.wait()
|
|
questions[1].save_state()
|
|
|
|
self.questions = questions
|
|
|
|
def introduce_buyer_and_seller(self):
|
|
if hasattr(self, "questions"):
|
|
questions = self.questions
|
|
added_anims = [
|
|
questions[0].to_edge, UP,
|
|
questions[1].set_opacity, 0.5,
|
|
questions[1].scale, 0.25,
|
|
questions[1].to_corner, UR,
|
|
]
|
|
else:
|
|
added_anims = []
|
|
|
|
seller = Randolph(mode="coin_flip_1")
|
|
seller.to_edge(LEFT)
|
|
seller.label = TextMobject("Seller")
|
|
|
|
buyer = Mortimer()
|
|
buyer.to_edge(RIGHT)
|
|
buyer.label = TextMobject("Buyer")
|
|
|
|
VGroup(buyer, seller).shift(DOWN)
|
|
|
|
labels = VGroup()
|
|
for pi in seller, buyer:
|
|
pi.set_height(2)
|
|
pi.label.scale(1.5)
|
|
pi.label.next_to(pi, DOWN, MED_LARGE_BUFF)
|
|
labels.add(pi.label)
|
|
buyer.make_eye_contact(seller)
|
|
|
|
self.play(
|
|
LaggedStartMap(
|
|
FadeInFromDown, VGroup(seller, buyer, *labels),
|
|
lag_ratio=0.2
|
|
),
|
|
*added_anims
|
|
)
|
|
self.wait()
|
|
|
|
self.buyer = buyer
|
|
self.seller = seller
|
|
|
|
def add_probability_label(self):
|
|
seller = self.seller
|
|
buyer = self.buyer
|
|
|
|
label = get_prob_positive_experience_label()
|
|
label.add(TexMobject("=").next_to(label, RIGHT))
|
|
rhs = DecimalNumber(0.75)
|
|
rhs.next_to(label, RIGHT)
|
|
rhs.align_to(label[0], DOWN)
|
|
label.add(rhs)
|
|
label.scale(1.5)
|
|
label.next_to(seller, UP, MED_LARGE_BUFF, aligned_edge=LEFT)
|
|
|
|
rhs.set_color(YELLOW)
|
|
brace = Brace(rhs, UP)
|
|
success_rate = brace.get_text("Success rate")[0]
|
|
s_sym = brace.get_tex("s").scale(1.5, about_edge=DOWN)
|
|
success_rate.match_color(rhs)
|
|
s_sym.match_color(rhs)
|
|
|
|
self.add(label)
|
|
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
FadeInFrom(success_rate, 0.5 * DOWN)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
TransformFromCopy(success_rate[0], s_sym),
|
|
FadeOutAndShift(success_rate, 0.1 * RIGHT, lag_ratio=0.1),
|
|
)
|
|
for x in range(2):
|
|
self.play(*self.experience_animations(seller, buyer, arc=30 * DEGREES))
|
|
self.wait()
|
|
|
|
grey_box = SurroundingRectangle(rhs, buff=SMALL_BUFF)
|
|
grey_box.set_stroke(GREY_E, 0.5)
|
|
grey_box.set_fill(GREY_D, 1)
|
|
lil_q_marks = TexMobject("???")
|
|
lil_q_marks.scale(0.5)
|
|
lil_q_marks.next_to(buyer, UP)
|
|
|
|
self.play(
|
|
FadeOutAndShift(rhs, 0.5 * DOWN),
|
|
FadeInFrom(grey_box, 0.5 * UP),
|
|
FadeInFrom(lil_q_marks, DOWN),
|
|
buyer.change, "confused", grey_box,
|
|
)
|
|
rhs.set_opacity(0)
|
|
for x in range(2):
|
|
self.play(*self.experience_animations(seller, buyer, arc=30 * DEGREES))
|
|
self.play(buyer.change, "confused", lil_q_marks)
|
|
self.play(Blink(buyer))
|
|
|
|
self.prob_group = VGroup(
|
|
label, grey_box, brace, s_sym,
|
|
)
|
|
self.buyer_q_marks = lil_q_marks
|
|
|
|
def bring_up_goal(self):
|
|
prob_group = self.prob_group
|
|
questions = self.questions
|
|
questions.generate_target()
|
|
questions.target[1].replace(questions[0], dim_to_match=1)
|
|
questions.target[1].match_style(questions[0])
|
|
questions.target[0].replace(questions[1], dim_to_match=1)
|
|
questions.target[0].match_style(questions[1])
|
|
|
|
prob_group.generate_target()
|
|
prob_group.target.scale(0.5)
|
|
prob_group.target.next_to(self.seller, RIGHT)
|
|
|
|
self.play(
|
|
FadeOut(self.buyer_q_marks),
|
|
self.buyer.change, "pondering", questions[0],
|
|
self.seller.change, "pondering", questions[0],
|
|
MoveToTarget(prob_group),
|
|
MoveToTarget(questions),
|
|
)
|
|
self.play(self.seller.change, "coin_flip_1")
|
|
for x in range(3):
|
|
self.play(*self.experience_animations(self.seller, self.buyer))
|
|
self.wait()
|
|
|
|
#
|
|
def experience_animations(self, seller, buyer, arc=-30 * DEGREES, p=0.75):
|
|
positive = (random.random() < p)
|
|
words = TextMobject(
|
|
"Positive\\\\experience"
|
|
if positive else
|
|
"Negative\\\\experience"
|
|
)
|
|
words.set_color(GREEN if positive else RED)
|
|
if positive:
|
|
new_mode = random.choice([
|
|
"hooray",
|
|
"coin_flip_1",
|
|
])
|
|
else:
|
|
new_mode = random.choice([
|
|
"tired",
|
|
"angry",
|
|
"sad",
|
|
])
|
|
|
|
words.move_to(seller.get_corner(UR))
|
|
result = [
|
|
ApplyMethod(
|
|
words.move_to, buyer.get_corner(UL),
|
|
path_arc=arc,
|
|
run_time=2
|
|
),
|
|
VFadeInThenOut(words, run_time=2),
|
|
ApplyMethod(
|
|
buyer.change, new_mode, seller.eyes,
|
|
run_time=2,
|
|
rate_func=squish_rate_func(smooth, 0.5, 1),
|
|
),
|
|
ApplyMethod(
|
|
seller.change, "coin_flip_2", buyer.eyes,
|
|
rate_func=there_and_back,
|
|
),
|
|
]
|
|
return result
|
|
|
|
|
|
class IsSellerOne100(Scene):
|
|
def construct(self):
|
|
self.add_review()
|
|
self.show_probability()
|
|
self.show_simulated_reviews()
|
|
|
|
def add_review(self):
|
|
reviews = VGroup(*[TexMobject(CMARK_TEX) for x in range(10)])
|
|
reviews.arrange(RIGHT)
|
|
reviews.scale(2)
|
|
reviews.set_color(GREEN)
|
|
reviews.next_to(ORIGIN, UP)
|
|
|
|
blanks = VGroup(*[
|
|
Line(LEFT, RIGHT).match_width(rev).next_to(rev, DOWN, SMALL_BUFF)
|
|
for rev in reviews
|
|
])
|
|
blanks.shift(0.25 * reviews[0].get_width() * LEFT)
|
|
|
|
label = TextMobject(
|
|
" out of ",
|
|
)
|
|
tens = VGroup(*[Integer(10) for x in range(2)])
|
|
tens[0].next_to(label, LEFT)
|
|
tens[1].next_to(label, RIGHT)
|
|
tens.set_color(GREEN)
|
|
label.add(tens)
|
|
label.scale(2)
|
|
label.next_to(reviews, DOWN, LARGE_BUFF)
|
|
|
|
self.add(label)
|
|
self.add(blanks)
|
|
tens[0].to_count = reviews
|
|
self.play(
|
|
ShowIncreasingSubsets(reviews, int_func=np.ceil),
|
|
UpdateFromAlphaFunc(
|
|
tens[0],
|
|
lambda m, a: m.set_color(
|
|
interpolate_color(RED, GREEN, a)
|
|
).set_value(len(m.to_count))
|
|
),
|
|
run_time=2,
|
|
rate_func=bezier([0, 0, 1, 1]),
|
|
)
|
|
self.wait()
|
|
|
|
self.review_group = VGroup(reviews, blanks, label)
|
|
|
|
def show_probability(self):
|
|
review_group = self.review_group
|
|
|
|
prob_label = get_prob_positive_experience_label()
|
|
prob_label.add(TexMobject("=").next_to(prob_label, RIGHT))
|
|
rhs = DecimalNumber(1)
|
|
rhs.next_to(prob_label, RIGHT)
|
|
rhs.set_color(YELLOW)
|
|
prob_label.add(rhs)
|
|
prob_label.scale(2)
|
|
prob_label.to_corner(UL)
|
|
|
|
q_mark = TexMobject("?")
|
|
q_mark.set_color(YELLOW)
|
|
q_mark.match_height(rhs)
|
|
q_mark.reference = rhs
|
|
q_mark.add_updater(lambda m: m.next_to(m.reference, RIGHT))
|
|
|
|
rhs_rect = SurroundingRectangle(rhs, buff=0.2)
|
|
rhs_rect.set_color(RED)
|
|
|
|
not_necessarily = TextMobject("Not necessarily!")
|
|
not_necessarily.set_color(RED)
|
|
not_necessarily.scale(1.5)
|
|
not_necessarily.next_to(prob_label, DOWN, 1.5)
|
|
arrow = Arrow(
|
|
not_necessarily.get_top(),
|
|
rhs_rect.get_corner(DL),
|
|
buff=MED_SMALL_BUFF,
|
|
)
|
|
arrow.set_color(RED)
|
|
|
|
rhs.set_value(0)
|
|
self.play(
|
|
ChangeDecimalToValue(rhs, 1),
|
|
UpdateFromAlphaFunc(
|
|
prob_label,
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
FadeIn(q_mark),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(rhs_rect),
|
|
Write(not_necessarily),
|
|
ShowCreation(arrow),
|
|
review_group.to_edge, DOWN,
|
|
run_time=1,
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ChangeDecimalToValue(rhs, 0.95),
|
|
FadeOut(rhs_rect),
|
|
FadeOut(arrow),
|
|
FadeOut(not_necessarily),
|
|
)
|
|
self.wait()
|
|
|
|
self.prob_label_group = VGroup(
|
|
prob_label, rhs, q_mark,
|
|
)
|
|
|
|
def show_simulated_reviews(self):
|
|
prob_label_group = self.prob_label_group
|
|
review_group = self.review_group
|
|
|
|
# Set up decimals
|
|
random.seed(2)
|
|
decimals = VGroup()
|
|
for x in range(10):
|
|
dec = DecimalNumber()
|
|
decimals.add(dec)
|
|
|
|
def randomize_decimals(decimals):
|
|
for dec in decimals:
|
|
value = random.random()
|
|
dec.set_value(value)
|
|
if value > 0.95:
|
|
dec.set_color(RED)
|
|
else:
|
|
dec.set_color(WHITE)
|
|
|
|
randomize_decimals(decimals)
|
|
|
|
decimals.set_height(0.3)
|
|
decimals.arrange(RIGHT, buff=MED_LARGE_BUFF)
|
|
decimals.next_to(ORIGIN, DOWN)
|
|
decimals[0].set_value(0.42)
|
|
decimals[0].set_color(WHITE)
|
|
decimals[1].set_value(0.97)
|
|
decimals[1].set_color(RED)
|
|
|
|
random_label = TextMobject("Random number\\\\in [0, 1]")
|
|
random_label.scale(0.7)
|
|
random_label.next_to(decimals[0], DOWN)
|
|
random_label.set_color(GREY_B)
|
|
|
|
arrows = VGroup()
|
|
for dec in decimals:
|
|
arrow = Vector(0.4 * UP)
|
|
arrow.next_to(dec, UP)
|
|
arrows.add(arrow)
|
|
|
|
# Set up marks
|
|
def get_marks(decs, arrows):
|
|
marks = VGroup()
|
|
for dec, arrow in zip(decs, arrows):
|
|
if dec.get_value() < 0.95:
|
|
mark = TexMobject(CMARK_TEX)
|
|
mark.set_color(GREEN)
|
|
else:
|
|
mark = TexMobject(XMARK_TEX)
|
|
mark.set_color(RED)
|
|
mark.set_height(0.5)
|
|
mark.next_to(arrow, UP)
|
|
marks.add(mark)
|
|
return marks
|
|
|
|
marks = get_marks(decimals, arrows)
|
|
|
|
lt_p95 = TexMobject("< 0.95")
|
|
gte_p95 = TexMobject("\\ge 0.95")
|
|
for label in lt_p95, gte_p95:
|
|
label.match_height(decimals[0])
|
|
|
|
lt_p95.next_to(decimals[0], RIGHT, MED_SMALL_BUFF)
|
|
gte_p95.next_to(decimals[1], RIGHT, MED_SMALL_BUFF)
|
|
lt_p95.set_color(GREEN)
|
|
gte_p95.set_color(RED)
|
|
|
|
# Introduce simulation
|
|
review_group.save_state()
|
|
self.play(
|
|
review_group.scale, 0.25,
|
|
review_group.to_corner, UR,
|
|
Write(random_label),
|
|
CountInFrom(decimals[0], 0),
|
|
)
|
|
self.wait()
|
|
self.play(FadeInFrom(lt_p95, LEFT))
|
|
self.play(
|
|
GrowArrow(arrows[0]),
|
|
FadeInFrom(marks[0], DOWN)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeOutAndShift(lt_p95, 0.5 * RIGHT),
|
|
FadeInFrom(gte_p95, 0.5 * LEFT),
|
|
)
|
|
self.play(
|
|
random_label.match_x, decimals[1],
|
|
CountInFrom(decimals[1], 0),
|
|
UpdateFromAlphaFunc(
|
|
decimals[1],
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
)
|
|
self.play(
|
|
GrowArrow(arrows[1]),
|
|
FadeInFrom(marks[1], DOWN),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
LaggedStartMap(
|
|
CountInFrom, decimals[2:],
|
|
),
|
|
UpdateFromAlphaFunc(
|
|
decimals[2:],
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
FadeOut(gte_p95),
|
|
run_time=1,
|
|
)
|
|
self.add(decimals)
|
|
self.play(
|
|
LaggedStartMap(GrowArrow, arrows[2:]),
|
|
LaggedStartMap(FadeInFromDown, marks[2:]),
|
|
run_time=1
|
|
)
|
|
self.add(arrows, marks)
|
|
self.wait()
|
|
|
|
# Add new rows
|
|
decimals.arrows = arrows
|
|
decimals.add_updater(lambda d: d.next_to(d.arrows, DOWN))
|
|
added_anims = [FadeOut(random_label)]
|
|
rows = VGroup(marks)
|
|
for x in range(3):
|
|
self.play(
|
|
arrows.shift, DOWN,
|
|
UpdateFromFunc(decimals, randomize_decimals),
|
|
*added_anims,
|
|
)
|
|
added_anims = []
|
|
new_marks = get_marks(decimals, arrows)
|
|
self.play(LaggedStartMap(FadeInFromDown, new_marks))
|
|
self.wait()
|
|
rows.add(new_marks)
|
|
|
|
# Create a stockpile of new rows
|
|
added_rows = VGroup()
|
|
decimals.clear_updaters()
|
|
decimals.save_state()
|
|
for x in range(100):
|
|
randomize_decimals(decimals)
|
|
added_rows.add(get_marks(decimals, arrows))
|
|
decimals.restore()
|
|
|
|
# Compress rows
|
|
rows.generate_target()
|
|
for group in rows.target, added_rows:
|
|
group.scale(0.3)
|
|
for row in group:
|
|
row.arrange(RIGHT, buff=SMALL_BUFF)
|
|
group.arrange(DOWN, buff=0.2)
|
|
rows.target.next_to(prob_label_group, DOWN, MED_LARGE_BUFF)
|
|
rows.target.set_x(-3.5)
|
|
|
|
nr = 15
|
|
added_rows[:nr].move_to(rows.target, UP)
|
|
added_rows[nr:2 * nr].move_to(rows.target, UP)
|
|
added_rows[nr:2 * nr].shift(3.5 * RIGHT)
|
|
added_rows[2 * nr:3 * nr].move_to(rows.target, UP)
|
|
added_rows[2 * nr:3 * nr].shift(7 * RIGHT)
|
|
added_rows = added_rows[4:3 * nr]
|
|
|
|
self.play(
|
|
MoveToTarget(rows),
|
|
FadeOut(decimals),
|
|
FadeOut(arrows),
|
|
)
|
|
self.play(ShowIncreasingSubsets(added_rows), run_time=3)
|
|
|
|
# Show scores
|
|
all_rows = VGroup(*rows, *added_rows)
|
|
scores = VGroup()
|
|
ten_rects = VGroup()
|
|
for row in all_rows:
|
|
score = Integer(sum([
|
|
mark.get_color() == Color(GREEN)
|
|
for mark in row
|
|
]))
|
|
score.match_height(row)
|
|
score.next_to(row, RIGHT)
|
|
if score.get_value() == 10:
|
|
score.set_color(TEAL)
|
|
ten_rects.add(SurroundingRectangle(score))
|
|
scores.add(score)
|
|
|
|
ten_rects.set_stroke(YELLOW, 2)
|
|
|
|
self.play(FadeIn(scores))
|
|
self.wait()
|
|
self.play(LaggedStartMap(ShowCreation, ten_rects))
|
|
self.play(LaggedStartMap(FadeOut, ten_rects))
|
|
self.wait(2)
|
|
|
|
# Show alternate possibilities
|
|
prob = DecimalNumber(0.95)
|
|
prob.set_color(YELLOW)
|
|
template = prob_label_group[0][-1]
|
|
prob.match_height(template)
|
|
prob.move_to(template, LEFT)
|
|
rect = BackgroundRectangle(template, buff=SMALL_BUFF)
|
|
rect.set_fill(BLACK, 1)
|
|
self.add(rect)
|
|
self.add(prob)
|
|
self.play(
|
|
LaggedStartMap(FadeOutAndShift, all_rows, lag_ratio=0.01),
|
|
LaggedStartMap(FadeOutAndShift, scores, lag_ratio=0.01),
|
|
Restore(review_group),
|
|
)
|
|
for value in [0.9, 0.99, 0.8, 0.95]:
|
|
self.play(ChangeDecimalToValue(prob, value))
|
|
self.wait()
|
|
|
|
# No longer used
|
|
def show_random_numbers(self):
|
|
prob_label_group = self.prob_label_group
|
|
|
|
random.seed(2)
|
|
rows = VGroup(*[
|
|
VGroup(*[
|
|
Integer(
|
|
random.randint(0, 99)
|
|
).move_to(0.85 * x * RIGHT)
|
|
for x in range(10)
|
|
])
|
|
for y in range(10 * 2)
|
|
])
|
|
rows.arrange_in_grid(n_cols=2, buff=MED_LARGE_BUFF)
|
|
rows[:10].shift(LEFT)
|
|
rows.set_height(5.5)
|
|
rows.center().to_edge(DOWN)
|
|
|
|
lt_95 = VGroup(*[
|
|
mob
|
|
for row in rows
|
|
for mob in row
|
|
if mob.get_value() < 95
|
|
])
|
|
|
|
square = Square()
|
|
square.set_stroke(width=0)
|
|
square.set_fill(YELLOW, 0.5)
|
|
square.set_width(1.5 * rows[0][0].get_height())
|
|
# highlights = VGroup(*[
|
|
# square.copy().move_to(mob)
|
|
# for row in rows
|
|
# for mob in row
|
|
# if mob.get_value() < 95
|
|
# ])
|
|
|
|
row_rects = VGroup(*[
|
|
SurroundingRectangle(row)
|
|
for row in rows
|
|
if all([m.get_value() < 95 for m in row])
|
|
])
|
|
row_rects.set_stroke(GREEN, 2)
|
|
|
|
self.play(
|
|
LaggedStartMap(
|
|
ShowIncreasingSubsets, rows,
|
|
run_time=3,
|
|
lag_ratio=0.25,
|
|
),
|
|
FadeOutAndShift(self.review_group, DOWN),
|
|
prob_label_group.set_height, 0.75,
|
|
prob_label_group.to_corner, UL,
|
|
)
|
|
self.wait()
|
|
# self.add(highlights, rows)
|
|
self.play(
|
|
# FadeIn(highlights)
|
|
lt_95.set_fill, BLUE,
|
|
lt_95.set_stroke, BLUE, 2, {"background": True},
|
|
)
|
|
self.wait()
|
|
self.play(LaggedStartMap(ShowCreation, row_rects))
|
|
self.wait()
|
|
|
|
|
|
class LookAtAllPossibleSuccessRates(Scene):
|
|
def construct(self):
|
|
axes = get_beta_dist_axes(y_max=6, y_unit=1)
|
|
dist = scipy.stats.beta(10, 2)
|
|
graph = axes.get_graph(dist.pdf)
|
|
graph.set_stroke(BLUE, 3)
|
|
flat_graph = graph.copy()
|
|
flat_graph.points[:, 1] = axes.c2p(0, 0)[1]
|
|
flat_graph.set_stroke(YELLOW, 3)
|
|
|
|
x_labels = axes.x_axis.numbers
|
|
x_labels.set_opacity(0)
|
|
|
|
sellers = VGroup(*[
|
|
self.get_example_seller(label.get_value())
|
|
for label in x_labels
|
|
])
|
|
sellers.arrange(RIGHT, buff=LARGE_BUFF)
|
|
sellers.set_width(FRAME_WIDTH - 1)
|
|
sellers.to_edge(UP, buff=LARGE_BUFF)
|
|
|
|
sellers.generate_target()
|
|
for seller, label in zip(sellers.target, x_labels):
|
|
seller.next_to(label, DOWN)
|
|
seller[0].set_opacity(0)
|
|
seller[1].set_opacity(0)
|
|
seller[2].replace(label, dim_to_match=1)
|
|
|
|
x_label = TextMobject("All possible success rates")
|
|
x_label.next_to(axes.c2p(0.5, 0), UP)
|
|
x_label.shift(2 * LEFT)
|
|
|
|
y_axis_label = TextMobject(
|
|
"A kind of probability\\\\",
|
|
"of probabilities"
|
|
)
|
|
y_axis_label.scale(0.75)
|
|
y_axis_label.next_to(axes.y_axis, RIGHT)
|
|
y_axis_label.to_edge(UP)
|
|
y_axis_label[1].set_color(YELLOW)
|
|
|
|
graph_label = TextMobject(
|
|
"Some notion of likelihood\\\\",
|
|
"for each one"
|
|
)
|
|
graph_label[1].align_to(graph_label[0], LEFT)
|
|
graph_label.next_to(graph.get_boundary_point(UP), UP)
|
|
graph_label.shift(0.5 * DOWN)
|
|
graph_label.to_edge(RIGHT)
|
|
|
|
x_axis_line = Line(axes.c2p(0, 0), axes.c2p(1, 0))
|
|
x_axis_line.set_stroke(YELLOW, 3)
|
|
|
|
shuffled_sellers = VGroup(*sellers)
|
|
shuffled_sellers.shuffle()
|
|
self.play(GrowFromCenter(shuffled_sellers[0]))
|
|
self.play(LaggedStartMap(
|
|
FadeInFromPoint, shuffled_sellers[1:],
|
|
lambda m: (m, sellers.get_center())
|
|
))
|
|
self.wait()
|
|
self.play(
|
|
MoveToTarget(sellers),
|
|
FadeIn(axes),
|
|
run_time=2,
|
|
)
|
|
|
|
self.play(
|
|
x_label.shift, 4 * RIGHT,
|
|
UpdateFromAlphaFunc(
|
|
x_label,
|
|
lambda m, a: m.set_opacity(a),
|
|
rate_func=there_and_back,
|
|
),
|
|
ShowCreation(x_axis_line),
|
|
run_time=3,
|
|
)
|
|
self.play(FadeOut(x_axis_line))
|
|
self.wait()
|
|
self.play(
|
|
FadeInFromDown(graph_label),
|
|
ReplacementTransform(flat_graph, graph),
|
|
)
|
|
self.wait()
|
|
self.play(FadeInFromDown(y_axis_label))
|
|
|
|
# Show probabilities
|
|
x_tracker = ValueTracker(0.5)
|
|
|
|
prob_label = get_prob_positive_experience_label(True, True, True)
|
|
prob_label.next_to(axes.c2p(0, 2), RIGHT, MED_LARGE_BUFF)
|
|
prob_label.decimal.tracker = x_tracker
|
|
prob_label.decimal.add_updater(
|
|
lambda m: m.set_value(m.tracker.get_value())
|
|
)
|
|
|
|
v_line = Line(DOWN, UP)
|
|
v_line.set_stroke(YELLOW, 2)
|
|
v_line.tracker = x_tracker
|
|
v_line.graph = graph
|
|
v_line.axes = axes
|
|
v_line.add_updater(
|
|
lambda m: m.put_start_and_end_on(
|
|
m.axes.x_axis.n2p(m.tracker.get_value()),
|
|
m.axes.input_to_graph_point(m.tracker.get_value(), m.graph),
|
|
)
|
|
)
|
|
|
|
self.add(v_line)
|
|
for x in [0.95, 0.8, 0.9]:
|
|
self.play(
|
|
x_tracker.set_value, x,
|
|
run_time=4,
|
|
)
|
|
self.wait()
|
|
|
|
def get_example_seller(self, success_rate):
|
|
randy = Randolph(mode="coin_flip_1", height=1)
|
|
label = TexMobject("s = ")
|
|
decimal = DecimalNumber(success_rate)
|
|
decimal.match_height(label)
|
|
decimal.next_to(label[-1], RIGHT)
|
|
label.set_color(YELLOW)
|
|
decimal.set_color(YELLOW)
|
|
VGroup(label, decimal).next_to(randy, DOWN)
|
|
result = VGroup(randy, label, decimal)
|
|
result.randy = randy
|
|
result.label = label
|
|
result.decimal = decimal
|
|
return result
|
|
|
|
|
|
class AskAboutUnknownProbabilities(Scene):
|
|
def construct(self):
|
|
# Setup
|
|
unknown_title, prob_title = titles = self.get_titles()
|
|
|
|
v_line = Line(UP, DOWN)
|
|
v_line.set_height(FRAME_HEIGHT)
|
|
v_line.set_stroke([WHITE, LIGHT_GREY], 3)
|
|
h_line = Line(LEFT, RIGHT)
|
|
h_line.set_width(FRAME_WIDTH)
|
|
h_line.next_to(titles, DOWN)
|
|
|
|
processes = VGroup(
|
|
get_random_coin(shuffle_time=1),
|
|
get_random_die(shuffle_time=1.5),
|
|
get_random_card(shuffle_time=2),
|
|
)
|
|
processes.arrange(DOWN, buff=0.7)
|
|
processes.next_to(unknown_title, DOWN, LARGE_BUFF)
|
|
processes_rect = BackgroundRectangle(processes)
|
|
processes_rect.set_fill(BLACK, 1)
|
|
|
|
prob_labels = VGroup(
|
|
TexMobject("P(", "00", ")", "=", "1 / 2"),
|
|
TexMobject("P(", "00", ")", "=", "1 / 6}"),
|
|
TexMobject("P(", "00", ")", "=", "1 / 52}"),
|
|
)
|
|
prob_labels.scale(1.5)
|
|
prob_labels.arrange(DOWN, aligned_edge=LEFT)
|
|
prob_labels.match_x(prob_title)
|
|
for pl, pr in zip(prob_labels, processes):
|
|
pl.match_y(pr)
|
|
content = pr[1].copy()
|
|
content.replace(pl[1], dim_to_match=0)
|
|
pl.replace_submobject(1, content)
|
|
|
|
# Putting numbers to the unknown
|
|
number_rects = VGroup(*[
|
|
SurroundingRectangle(pl[-1])
|
|
for pl in prob_labels
|
|
])
|
|
number_rects.set_stroke(YELLOW, 2)
|
|
|
|
for pl in prob_labels:
|
|
pl.save_state()
|
|
pl[:3].match_x(prob_title)
|
|
pl[3:].match_x(prob_title)
|
|
pl.set_opacity(0)
|
|
|
|
self.add(processes)
|
|
self.play(
|
|
LaggedStartMap(FadeInFromDown, titles),
|
|
LaggedStart(
|
|
ShowCreation(v_line),
|
|
ShowCreation(h_line),
|
|
lag_ratio=0.1,
|
|
),
|
|
LaggedStartMap(Restore, prob_labels),
|
|
run_time=1
|
|
)
|
|
self.wait(10)
|
|
# self.play(
|
|
# LaggedStartMap(
|
|
# ShowCreationThenFadeOut,
|
|
# number_rects,
|
|
# run_time=3,
|
|
# )
|
|
# )
|
|
# self.wait(2)
|
|
|
|
# Highlight coin flip
|
|
fade_rects = VGroup(*[
|
|
VGroup(
|
|
BackgroundRectangle(pl, buff=MED_SMALL_BUFF),
|
|
BackgroundRectangle(pr, buff=MED_SMALL_BUFF),
|
|
)
|
|
for pl, pr in zip(prob_labels, processes)
|
|
])
|
|
fade_rects.set_fill(BLACK, 0.8)
|
|
|
|
prob_half = prob_labels[0]
|
|
half = prob_half[-1]
|
|
half_underline = Line(LEFT, RIGHT)
|
|
half_underline.set_width(half.get_width() + MED_SMALL_BUFF)
|
|
half_underline.next_to(half, DOWN, buff=SMALL_BUFF)
|
|
half_underline.set_stroke(YELLOW, 3)
|
|
|
|
self.play(
|
|
FadeIn(fade_rects[1]),
|
|
FadeIn(fade_rects[2]),
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
FadeIn(fade_rects[0]),
|
|
FadeOut(fade_rects[1]),
|
|
)
|
|
self.wait(3)
|
|
self.play(
|
|
FadeOut(fade_rects[0]),
|
|
FadeOut(fade_rects[2]),
|
|
)
|
|
self.wait(4)
|
|
|
|
# Transition to question
|
|
processes.suspend_updating()
|
|
self.play(
|
|
LaggedStart(
|
|
FadeOutAndShift(unknown_title, UP),
|
|
FadeOutAndShift(prob_title, UP),
|
|
lag_ratio=0.2,
|
|
),
|
|
FadeOutAndShift(h_line, UP, lag_ratio=0.1),
|
|
FadeOutAndShift(processes, LEFT, lag_ratio=0.1),
|
|
FadeOut(prob_labels[1]),
|
|
FadeOut(prob_labels[2]),
|
|
v_line.rotate, 90 * DEGREES,
|
|
v_line.shift, 0.6 * FRAME_HEIGHT * UP,
|
|
prob_half.center,
|
|
prob_half.to_edge, UP,
|
|
run_time=2,
|
|
)
|
|
self.clear()
|
|
self.add(prob_half)
|
|
|
|
arrow = Vector(UP)
|
|
arrow.next_to(half, DOWN)
|
|
question = TextMobject("What exactly does\\\\this mean?")
|
|
question.next_to(arrow, DOWN)
|
|
|
|
self.play(
|
|
GrowArrow(arrow),
|
|
FadeInFrom(question, UP),
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
FadeOutAndShift(question, RIGHT),
|
|
Rotate(arrow, 90 * DEGREES),
|
|
VFadeOut(arrow),
|
|
)
|
|
|
|
# Show long run averages
|
|
self.show_many_coins(20, 50)
|
|
self.show_many_coins(40, 100)
|
|
|
|
# Make probability itself unknown
|
|
q_marks = TexMobject("???")
|
|
q_marks.set_color(YELLOW)
|
|
q_marks.replace(half, dim_to_match=0)
|
|
|
|
randy = Randolph(mode="confused")
|
|
randy.center()
|
|
randy.look_at(prob_half)
|
|
|
|
self.play(
|
|
FadeOutAndShift(half, UP),
|
|
FadeInFrom(q_marks, DOWN),
|
|
)
|
|
self.play(FadeIn(randy))
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
|
|
# self.embed()
|
|
|
|
def get_titles(self):
|
|
unknown_label = TextMobject("Random process")
|
|
prob_label = TextMobject("Long-run frequency")
|
|
titles = VGroup(unknown_label, prob_label)
|
|
titles.scale(1.25)
|
|
|
|
unknown_label.move_to(FRAME_WIDTH * LEFT / 4)
|
|
prob_label.move_to(FRAME_WIDTH * RIGHT / 4)
|
|
titles.to_edge(UP, buff=MED_SMALL_BUFF)
|
|
titles.set_color(BLUE)
|
|
return titles
|
|
|
|
def show_many_coins(self, n_rows, n_cols):
|
|
coin_choices = VGroup(
|
|
get_coin("H"),
|
|
get_coin("T"),
|
|
)
|
|
coin_choices.set_stroke(width=0)
|
|
coins = VGroup(*[
|
|
random.choice(coin_choices).copy()
|
|
for x in range(n_rows * n_cols)
|
|
])
|
|
|
|
def organize_coins(coin_group):
|
|
coin_group.scale(1 / coin_group[0].get_height())
|
|
coin_group.arrange_in_grid(n_rows=n_rows)
|
|
coin_group.set_width(FRAME_WIDTH - 1)
|
|
coin_group.to_edge(DOWN, MED_LARGE_BUFF)
|
|
|
|
organize_coins(coins)
|
|
|
|
sorted_coins = VGroup()
|
|
for coin in coins:
|
|
coin.generate_target()
|
|
sorted_coins.add(coin.target)
|
|
sorted_coins.submobjects.sort(key=lambda m: m.symbol)
|
|
organize_coins(sorted_coins)
|
|
|
|
self.play(LaggedStartMap(
|
|
FadeInFrom, coins,
|
|
lambda m: (m, 0.2 * DOWN),
|
|
run_time=3,
|
|
rate_func=linear
|
|
))
|
|
self.wait()
|
|
self.play(LaggedStartMap(
|
|
MoveToTarget, coins,
|
|
path_arc=30 * DEGREES,
|
|
run_time=2,
|
|
lag_ratio=1 / len(coins),
|
|
))
|
|
self.wait()
|
|
self.play(FadeOut(coins))
|
|
|
|
|
|
class AskProbabilityOfCoins(Scene):
|
|
def construct(self):
|
|
condition = VGroup(
|
|
TextMobject("If you've seen"),
|
|
Integer(80, color=BLUE_C),
|
|
get_coin("H").set_height(0.5),
|
|
TextMobject("and"),
|
|
Integer(20, color=RED_C),
|
|
get_coin("T").set_height(0.5),
|
|
)
|
|
condition.arrange(RIGHT)
|
|
condition.to_edge(UP)
|
|
self.add(condition)
|
|
|
|
question = TexMobject(
|
|
"\\text{What is }",
|
|
"P(", "00", ")", "?"
|
|
)
|
|
coin = get_coin("H")
|
|
coin.replace(question.get_part_by_tex("00"))
|
|
question.replace_submobject(
|
|
question.index_of_part_by_tex("00"),
|
|
coin
|
|
)
|
|
question.next_to(condition, DOWN)
|
|
self.add(question)
|
|
|
|
values = ["H"] * 80 + ["T"] * 20
|
|
random.shuffle(values)
|
|
|
|
coins = VGroup(*[
|
|
get_coin(symbol)
|
|
for symbol in values
|
|
])
|
|
coins.arrange_in_grid(10, 10, buff=MED_SMALL_BUFF)
|
|
coins.set_width(5)
|
|
coins.next_to(question, DOWN, MED_LARGE_BUFF)
|
|
|
|
self.play(
|
|
ShowIncreasingSubsets(coins),
|
|
run_time=8,
|
|
rate_func=bezier([0, 0, 1, 1])
|
|
)
|
|
self.wait()
|
|
|
|
self.embed()
|
|
|
|
|
|
class RunCarFactory(Scene):
|
|
def construct(self):
|
|
# Factory
|
|
factory = SVGMobject(file_name="factory")
|
|
factory.set_fill(GREY_D)
|
|
factory.set_stroke(width=0)
|
|
factory.flip()
|
|
factory.set_height(6)
|
|
factory.to_edge(LEFT)
|
|
|
|
self.add(factory)
|
|
|
|
# Dumb hack
|
|
l1 = Line(
|
|
factory[0].points[-200],
|
|
factory[0].points[-216],
|
|
)
|
|
l2 = Line(
|
|
factory[0].points[-300],
|
|
factory[0].points[-318],
|
|
)
|
|
for line in l1, l2:
|
|
square = Square()
|
|
square.set_fill(BLACK, 1)
|
|
square.set_stroke(width=0)
|
|
square.replace(line)
|
|
factory.add(square)
|
|
|
|
rect = Rectangle()
|
|
rect.match_style(factory)
|
|
rect.set_height(1.1)
|
|
rect.set_width(6.75, stretch=True)
|
|
rect.move_to(factory, DL)
|
|
|
|
# Get cars
|
|
car = Car(color=interpolate_color(BLUE_E, GREY_C, 0.5))
|
|
car.set_height(0.9)
|
|
for tire in car.get_tires():
|
|
tire.set_fill(GREY_C)
|
|
tire.set_stroke(BLACK)
|
|
car.randy.set_opacity(0)
|
|
car.move_to(rect.get_corner(DR))
|
|
|
|
cars = VGroup()
|
|
n_cars = 20
|
|
for x in range(n_cars):
|
|
cars.add(car.copy())
|
|
|
|
for car in cars[4], cars[6]:
|
|
scratch = VMobject()
|
|
scratch.start_new_path(UP)
|
|
scratch.add_line_to(0.25 * DL)
|
|
scratch.add_line_to(0.25 * UR)
|
|
scratch.add_line_to(DOWN)
|
|
scratch.set_stroke([RED_A, RED_C], [0.1, 2, 2, 0.1])
|
|
scratch.set_height(0.25)
|
|
scratch.move_to(car)
|
|
scratch.shift(0.1 * DOWN)
|
|
car.add(scratch)
|
|
|
|
self.add(cars, rect)
|
|
self.play(LaggedStartMap(
|
|
MoveCar, cars,
|
|
lambda m: (m, m.get_corner(DR) + 10 * RIGHT),
|
|
lag_ratio=0.3,
|
|
rate_func=linear,
|
|
run_time=1.5 * n_cars,
|
|
))
|
|
self.remove(cars)
|
|
|
|
|
|
class CarFactoryNumbers(Scene):
|
|
def construct(self):
|
|
# Test words
|
|
denom_words = TextMobject(
|
|
"in a test of 100 cars",
|
|
tex_to_color_map={"100": BLUE},
|
|
)
|
|
denom_words.to_corner(UR)
|
|
|
|
numer_words = TextMobject(
|
|
"2 defects found",
|
|
tex_to_color_map={"2": RED}
|
|
)
|
|
numer_words.move_to(denom_words, LEFT)
|
|
|
|
self.play(Write(denom_words, run_time=1))
|
|
self.wait()
|
|
self.play(
|
|
denom_words.next_to, numer_words, DOWN, {"aligned_edge": LEFT},
|
|
FadeIn(numer_words),
|
|
)
|
|
self.wait()
|
|
|
|
# Question words
|
|
question = VGroup(
|
|
TextMobject("How do you plan"),
|
|
TextMobject("for"),
|
|
Integer(int(1e6), color=BLUE),
|
|
TextMobject("cars?")
|
|
)
|
|
question[1:].arrange(RIGHT, aligned_edge=DOWN)
|
|
question[2].shift(
|
|
(question[2][1].get_bottom()[1] - question[2][0].get_bottom()[1]) * UP
|
|
)
|
|
question[1:].next_to(question[0], DOWN, aligned_edge=LEFT)
|
|
question.next_to(denom_words, DOWN, LARGE_BUFF, aligned_edge=LEFT)
|
|
|
|
self.play(
|
|
UpdateFromAlphaFunc(
|
|
question,
|
|
lambda m, a: m.set_opacity(a),
|
|
),
|
|
CountInFrom(question[2], 0, run_time=1.5)
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class ComplainAboutSimplisticModel(TeacherStudentsScene):
|
|
def construct(self):
|
|
axes = self.get_experience_graph()
|
|
|
|
self.add(axes)
|
|
self.play(
|
|
self.teacher.change, "raise_right_hand", axes,
|
|
self.get_student_changes(
|
|
"pondering", "erm", "sassy",
|
|
look_at_arg=axes,
|
|
),
|
|
ShowCreation(
|
|
axes.graph,
|
|
run_time=3,
|
|
rate_func=linear,
|
|
),
|
|
)
|
|
self.wait(2)
|
|
|
|
student = self.students[2]
|
|
bubble = SpeechBubble(
|
|
direction=LEFT,
|
|
height=3,
|
|
width=5,
|
|
)
|
|
bubble.pin_to(student)
|
|
bubble.write("What about something\\\\like this?")
|
|
|
|
self.play(
|
|
axes.next_to, student, UL,
|
|
VFadeOut(axes.graph),
|
|
FadeIn(bubble),
|
|
Write(bubble.content, run_time=1),
|
|
student.change, "raise_left_hand",
|
|
self.students[0].change, "thinking", axes,
|
|
self.students[1].change, "thinking", axes,
|
|
self.teacher.change, "happy",
|
|
)
|
|
|
|
new_graph = VMobject()
|
|
new_graph.set_points_as_corners([
|
|
axes.c2p(0, 0.75),
|
|
axes.c2p(2, 0.9),
|
|
axes.c2p(4, 0.5),
|
|
axes.c2p(6, 0.75),
|
|
axes.c2p(8, 0.55),
|
|
axes.c2p(10, 0.95),
|
|
])
|
|
new_graph.make_smooth()
|
|
new_graph.set_stroke([YELLOW, RED, GREEN], 2)
|
|
|
|
self.play(
|
|
ShowCreation(new_graph),
|
|
*[
|
|
ApplyMethod(pi.look_at, new_graph)
|
|
for pi in self.pi_creatures
|
|
]
|
|
)
|
|
self.wait(3)
|
|
|
|
def get_experience_graph(self):
|
|
axes = Axes(
|
|
x_min=-1,
|
|
x_max=10,
|
|
y_min=0,
|
|
y_max=1.25,
|
|
y_axis_config={
|
|
"unit_size": 5,
|
|
"tick_frequency": 0.25,
|
|
"include_tip": False,
|
|
}
|
|
)
|
|
axes.set_stroke(LIGHT_GREY, 1)
|
|
axes.set_height(3)
|
|
y_label = TextMobject("Experience quality")
|
|
y_label.scale(0.5)
|
|
y_label.next_to(axes.y_axis.get_top(), RIGHT, SMALL_BUFF)
|
|
axes.add(y_label)
|
|
|
|
lines = VGroup()
|
|
for x in range(10):
|
|
lines.add(
|
|
Line(axes.c2p(x, 0), axes.c2p(x + 0.9, 0))
|
|
)
|
|
lines.set_stroke(RED, 3)
|
|
for line in lines:
|
|
if random.random() < 0.5:
|
|
line.set_y(axes.c2p(0, 1)[1])
|
|
line.set_stroke(GREEN)
|
|
|
|
axes.add(lines)
|
|
axes.graph = lines
|
|
|
|
rect = BackgroundRectangle(axes, buff=0.25)
|
|
rect.set_stroke(WHITE, 1)
|
|
rect.set_fill(BLACK, 1)
|
|
|
|
axes.add_to_back(rect)
|
|
axes.to_corner(UR)
|
|
|
|
return axes
|
|
|
|
|
|
class ComingUpWrapper(Scene):
|
|
def construct(self):
|
|
background = FullScreenFadeRectangle()
|
|
background.set_fill(GREY_E, 1)
|
|
|
|
title = TextMobject("What's coming...")
|
|
title.scale(1.5)
|
|
title.to_edge(UP)
|
|
|
|
rect = ScreenRectangle()
|
|
rect.set_height(6)
|
|
rect.set_stroke(WHITE)
|
|
rect.set_fill(BLACK, 1)
|
|
rect.next_to(title, DOWN)
|
|
|
|
self.add(background, rect)
|
|
self.play(FadeInFromDown(title))
|
|
self.wait()
|
|
|
|
|
|
class PreviewBeta(Scene):
|
|
def construct(self):
|
|
axes = get_beta_dist_axes(label_y=True)
|
|
axes.y_axis.remove(axes.y_axis.numbers)
|
|
marks = get_plusses_and_minuses(p=0.75)
|
|
marks.next_to(axes.y_axis.get_top(), DR, buff=0.75)
|
|
|
|
beta_label = get_beta_label(0, 0)
|
|
beta_label.next_to(marks, UR, buff=LARGE_BUFF)
|
|
beta_label.to_edge(UP)
|
|
bl_left = beta_label.get_left()
|
|
|
|
beta_container = VGroup()
|
|
graph_container = VGroup()
|
|
n_graphs = 2
|
|
for x in range(n_graphs):
|
|
graph_container.add(VMobject())
|
|
|
|
def get_counts(marks):
|
|
is_plusses = [m.is_plus for m in marks]
|
|
p = sum(is_plusses)
|
|
n = len(is_plusses) - p
|
|
return p, n
|
|
|
|
def update_beta(container):
|
|
counts = get_counts(marks)
|
|
new_label = get_beta_label(*counts)
|
|
new_label.move_to(bl_left, LEFT)
|
|
container.set_submobjects([new_label])
|
|
return container
|
|
|
|
def update_graph(container):
|
|
counts = get_counts(marks)
|
|
new_graph = get_beta_graph(axes, *counts)
|
|
new_graphs = [*container[1:], new_graph]
|
|
for g, a in zip(new_graphs, np.linspace(0.2, 1, n_graphs)):
|
|
g.set_opacity(a)
|
|
|
|
container.set_submobjects(new_graphs)
|
|
return container
|
|
|
|
self.add(axes)
|
|
self.play(
|
|
ShowIncreasingSubsets(marks),
|
|
UpdateFromFunc(
|
|
beta_container,
|
|
update_beta,
|
|
),
|
|
UpdateFromFunc(
|
|
graph_container,
|
|
update_graph,
|
|
),
|
|
run_time=15,
|
|
rate_func=bezier([0, 0, 1, 1]),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class AskInverseQuestion(WhatsTheModel):
|
|
def construct(self):
|
|
self.force_skipping()
|
|
self.introduce_buyer_and_seller()
|
|
self.bs_group = VGroup(
|
|
self.buyer,
|
|
self.seller,
|
|
self.buyer.label,
|
|
self.seller.label,
|
|
)
|
|
self.bs_group.to_edge(DOWN)
|
|
self.revert_to_original_skipping_status()
|
|
|
|
self.add_probability_label()
|
|
self.show_many_review_animations()
|
|
self.ask_question()
|
|
|
|
def add_probability_label(self):
|
|
label = get_prob_positive_experience_label(True, True, False)
|
|
label.decimal.set_value(0.95)
|
|
label.next_to(self.seller, UP, aligned_edge=LEFT, buff=MED_LARGE_BUFF)
|
|
|
|
self.add(label)
|
|
self.probability_label = label
|
|
|
|
def show_many_review_animations(self):
|
|
for x in range(7):
|
|
self.play(*self.experience_animations(
|
|
self.seller,
|
|
self.buyer,
|
|
arc=30 * DEGREES,
|
|
p=0.95,
|
|
))
|
|
|
|
def ask_question(self):
|
|
pis = [self.buyer, self.seller]
|
|
labels = VGroup(
|
|
self.get_prob_review_label(10, 0),
|
|
self.get_prob_review_label(48, 2),
|
|
self.get_prob_review_label(186, 14),
|
|
)
|
|
labels.arrange(DOWN)
|
|
labels.to_edge(UP)
|
|
|
|
labels[0].save_state()
|
|
labels[0].set_opacity(0)
|
|
words = labels[0][-3:-1]
|
|
words.set_opacity(1)
|
|
words.scale(1.5)
|
|
words.center().to_edge(UP)
|
|
|
|
self.play(
|
|
FadeInFromDown(words),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
Restore(labels[0]),
|
|
*[
|
|
ApplyMethod(pi.change, 'pondering', labels)
|
|
for pi in pis
|
|
]
|
|
)
|
|
self.play(Blink(pis[0]))
|
|
self.play(Blink(pis[1]))
|
|
self.play(LaggedStartMap(FadeInFromDown, labels[1:]))
|
|
self.wait(2)
|
|
|
|
# Succinct
|
|
short_label = TexMobject(
|
|
"P(\\text{data} | s)",
|
|
tex_to_color_map={
|
|
"\\text{data}": LIGHT_GREY,
|
|
"s": YELLOW
|
|
}
|
|
)
|
|
short_label.scale(2)
|
|
short_label.next_to(labels, DOWN, LARGE_BUFF),
|
|
rect = SurroundingRectangle(short_label, buff=MED_SMALL_BUFF)
|
|
bs_group = self.bs_group
|
|
bs_group.add(self.probability_label)
|
|
|
|
self.play(
|
|
FadeInFrom(short_label, UP),
|
|
bs_group.scale, 0.5, {"about_edge": DOWN},
|
|
)
|
|
self.play(ShowCreation(rect))
|
|
self.wait()
|
|
|
|
def get_prob_review_label(self, n_positive, n_negative):
|
|
label = TexMobject(
|
|
"P(",
|
|
f"{n_positive}\\,{CMARK_TEX}", ",\\,",
|
|
f"{n_negative}\\,{XMARK_TEX}",
|
|
"\\,\\text{ Given that }",
|
|
"s = 0.95",
|
|
")",
|
|
)
|
|
label.set_color_by_tex_to_color_map({
|
|
CMARK_TEX: GREEN,
|
|
XMARK_TEX: RED,
|
|
"0.95": YELLOW,
|
|
})
|
|
return label
|
|
|
|
|
|
class SimulationsOf10Reviews(Scene):
|
|
CONFIG = {
|
|
"s": 0.95,
|
|
"histogram_height": 5,
|
|
"histogram_width": 10,
|
|
}
|
|
|
|
def construct(self):
|
|
# Add s label
|
|
s_label = TexMobject("s = 0.95")
|
|
s_label.set_height(0.3)
|
|
s_label.to_corner(UL, buff=MED_SMALL_BUFF)
|
|
s_label.set_color(YELLOW)
|
|
self.add(s_label)
|
|
self.camera.frame.shift(LEFT)
|
|
s_label.shift(LEFT)
|
|
|
|
# Add random row
|
|
np.random.seed(0)
|
|
row = get_random_num_row(self.s)
|
|
count = self.get_count(row)
|
|
count.add_updater(
|
|
lambda m: m.set_value(
|
|
sum([s.positive for s in row.syms])
|
|
)
|
|
)
|
|
|
|
def update_nums(nums):
|
|
for num in nums:
|
|
num.set_value(np.random.random())
|
|
|
|
row.nums.save_state()
|
|
row.nums.set_color(WHITE)
|
|
self.play(
|
|
UpdateFromFunc(row.nums, update_nums),
|
|
run_time=2,
|
|
)
|
|
row.nums.restore()
|
|
self.wait()
|
|
|
|
self.add(count)
|
|
self.play(
|
|
ShowIncreasingSubsets(row.syms),
|
|
run_time=2,
|
|
rate_func=linear,
|
|
)
|
|
count.clear_updaters()
|
|
self.wait()
|
|
|
|
# Histogram
|
|
data = np.zeros(11)
|
|
histogram = self.get_histogram(data)
|
|
|
|
stacks = VGroup()
|
|
for bar in histogram.bars:
|
|
stacks.add(VGroup(bar.copy()))
|
|
|
|
def put_into_histogram(row_count_group):
|
|
row, count = row_count_group
|
|
count.clear_updaters()
|
|
index = int(count.get_value())
|
|
stack = stacks[index]
|
|
|
|
row.set_width(stack.get_width() - SMALL_BUFF)
|
|
row.next_to(stack, UP, SMALL_BUFF)
|
|
count.replace(histogram.axes.x_labels[index])
|
|
stack.add(row)
|
|
return row_count_group
|
|
|
|
# Random samples in histogram
|
|
self.play(
|
|
FadeIn(histogram),
|
|
ApplyFunction(
|
|
put_into_histogram,
|
|
VGroup(row, count),
|
|
)
|
|
)
|
|
self.wait()
|
|
for x in range(2):
|
|
row = get_random_num_row(self.s)
|
|
count = self.get_count(row)
|
|
group = VGroup(row, count)
|
|
self.play(FadeIn(group, lag_ratio=0.2))
|
|
self.wait(0.5)
|
|
self.play(
|
|
ApplyFunction(
|
|
put_into_histogram,
|
|
VGroup(row, count),
|
|
)
|
|
)
|
|
|
|
# More!
|
|
for x in range(40):
|
|
row = get_random_num_row(self.s)
|
|
count = self.get_count(row)
|
|
lower_group = VGroup(row, count).copy()
|
|
put_into_histogram(lower_group)
|
|
self.add(row, count, lower_group)
|
|
self.wait(0.1)
|
|
self.remove(row, count)
|
|
|
|
data = np.array([len(stack) - 1 for stack in stacks])
|
|
self.add(row, count)
|
|
self.play(
|
|
FadeOut(stacks),
|
|
FadeOut(count),
|
|
histogram.bars.become, histogram.get_bars(data),
|
|
histogram.axes.y_labels.set_opacity, 1,
|
|
histogram.axes.h_lines.set_opacity, 1,
|
|
histogram.axes.y_axis.set_opacity, 1,
|
|
)
|
|
self.remove(stacks)
|
|
|
|
arrow = Vector(0.5 * DOWN)
|
|
arrow.set_stroke(width=5)
|
|
arrow.set_color(YELLOW)
|
|
arrow.next_to(histogram.bars[10], UP, SMALL_BUFF)
|
|
|
|
def update(dummy):
|
|
new_row = get_random_num_row(self.s)
|
|
row.become(new_row)
|
|
count = sum([m.positive for m in new_row.nums])
|
|
data[count] += 1
|
|
histogram.bars.become(histogram.get_bars(data))
|
|
arrow.next_to(histogram.bars[count], UP, SMALL_BUFF)
|
|
|
|
self.add(arrow)
|
|
self.play(
|
|
UpdateFromFunc(Group(row, arrow, histogram.bars), update),
|
|
run_time=10,
|
|
)
|
|
|
|
#
|
|
def get_histogram(self, data):
|
|
histogram = Histogram(
|
|
data,
|
|
bar_colors=[RED, RED, BLUE, GREEN],
|
|
height=self.histogram_height,
|
|
width=self.histogram_width,
|
|
)
|
|
histogram.to_edge(DOWN)
|
|
|
|
histogram.axes.y_labels.set_opacity(0)
|
|
histogram.axes.h_lines.set_opacity(0)
|
|
return histogram
|
|
|
|
def get_count(self, row):
|
|
count = Integer()
|
|
count.set_height(0.75)
|
|
count.next_to(row, DOWN, buff=0.65)
|
|
count.set_value(sum([s.positive for s in row.syms]))
|
|
return count
|
|
|
|
|
|
class SimulationsOf10ReviewsSquished(SimulationsOf10Reviews):
|
|
CONFIG = {
|
|
"histogram_height": 2,
|
|
"histogram_width": 11,
|
|
}
|
|
|
|
def get_histogram(self, data):
|
|
hist = super().get_histogram(data)
|
|
hist.to_edge(UP, buff=1.5)
|
|
return hist
|
|
|
|
|
|
class SimulationsOf50Reviews(Scene):
|
|
CONFIG = {
|
|
"s": 0.95,
|
|
"histogram_config": {
|
|
"x_label_freq": 5,
|
|
"y_axis_numbers_to_show": range(10, 70, 10),
|
|
"y_max": 0.6,
|
|
"y_tick_freq": 0.1,
|
|
"height": 5,
|
|
"bar_colors": [BLUE],
|
|
},
|
|
"random_seed": 1,
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_s_label()
|
|
|
|
data = np.zeros(51)
|
|
histogram = self.get_histogram(data)
|
|
|
|
row = self.get_row()
|
|
count = self.get_count(row)
|
|
original_count = count.get_value()
|
|
count.set_value(0)
|
|
|
|
self.add(histogram)
|
|
self.play(
|
|
ShowIncreasingSubsets(row),
|
|
ChangeDecimalToValue(count, original_count)
|
|
)
|
|
|
|
# Run many samples
|
|
arrow = Vector(0.5 * DOWN)
|
|
arrow.set_stroke(width=5)
|
|
arrow.set_color(YELLOW)
|
|
arrow.next_to(histogram.bars[10], UP, SMALL_BUFF)
|
|
|
|
total_data_label = VGroup(
|
|
TextMobject("Total samples: "),
|
|
Integer(1),
|
|
)
|
|
total_data_label.arrange(RIGHT)
|
|
total_data_label.next_to(row, DOWN)
|
|
total_data_label.add_updater(
|
|
lambda m: m[1].set_value(data.sum())
|
|
)
|
|
|
|
def update(dummy, n_added_data_points=0):
|
|
new_row = self.get_row()
|
|
row.become(new_row)
|
|
num_positive = sum([m.positive for m in new_row])
|
|
count.set_value(num_positive)
|
|
data[num_positive] += 1
|
|
if n_added_data_points:
|
|
values = np.random.random((n_added_data_points, 50))
|
|
counts = (values < self.s).sum(1)
|
|
for i in range(len(data)):
|
|
data[i] += (counts == i).sum()
|
|
histogram.bars.become(histogram.get_bars(data))
|
|
histogram.bars.set_fill(GREY_C)
|
|
histogram.bars[48].set_fill(GREEN)
|
|
arrow.next_to(histogram.bars[num_positive], UP, SMALL_BUFF)
|
|
|
|
self.add(arrow, total_data_label)
|
|
group = VGroup(histogram.bars, row, count, arrow)
|
|
self.play(
|
|
UpdateFromFunc(group, update),
|
|
run_time=4
|
|
)
|
|
self.play(
|
|
UpdateFromFunc(
|
|
group,
|
|
lambda m: update(m, 1000)
|
|
),
|
|
run_time=4
|
|
)
|
|
random.seed(0)
|
|
np.random.seed(0)
|
|
update(group)
|
|
self.wait()
|
|
|
|
# Show 48 bar
|
|
axes = histogram.axes
|
|
y = choose(50, 48) * (self.s)**48 * (1 - self.s)**2
|
|
line = DashedLine(
|
|
axes.c2p(0, y),
|
|
axes.c2p(51, y),
|
|
)
|
|
label = TexMobject("{:.1f}\\%".format(100 * y))
|
|
fix_percent(label.family_members_with_points()[-1])
|
|
label.next_to(line, RIGHT)
|
|
|
|
self.play(
|
|
ShowCreation(line),
|
|
FadeInFromPoint(label, line.get_start())
|
|
)
|
|
|
|
def add_s_label(self):
|
|
s_label = TexMobject("s = 0.95")
|
|
s_label.set_height(0.3)
|
|
s_label.to_corner(UL, buff=MED_SMALL_BUFF)
|
|
s_label.shift(0.8 * DOWN)
|
|
s_label.set_color(YELLOW)
|
|
self.add(s_label)
|
|
|
|
def get_histogram(self, data):
|
|
histogram = Histogram(
|
|
data, **self.histogram_config
|
|
)
|
|
histogram.to_edge(DOWN)
|
|
return histogram
|
|
|
|
def get_row(self, n=50):
|
|
row = get_random_checks_and_crosses(n, self.s)
|
|
row.move_to(3.5 * UP)
|
|
return row
|
|
|
|
def get_count(self, row):
|
|
count = Integer(sum([m.positive for m in row]))
|
|
count.set_height(0.3)
|
|
count.next_to(row, RIGHT)
|
|
return count
|
|
|
|
|
|
class ShowBinomialFormula(SimulationsOf50Reviews):
|
|
CONFIG = {
|
|
"histogram_config": {
|
|
"x_label_freq": 5,
|
|
"y_axis_numbers_to_show": range(10, 40, 10),
|
|
"y_max": 0.3,
|
|
"y_tick_freq": 0.1,
|
|
"height": 2.5,
|
|
"bar_colors": [BLUE],
|
|
},
|
|
"random_seed": 0,
|
|
}
|
|
|
|
def construct(self):
|
|
# Add histogram
|
|
dist = scipy.stats.binom(50, self.s)
|
|
data = np.array([
|
|
dist.pmf(x)
|
|
for x in range(0, 51)
|
|
])
|
|
histogram = self.get_histogram(data)
|
|
histogram.bars.set_fill(GREY_C)
|
|
histogram.bars[48].set_fill(GREEN)
|
|
self.add(histogram)
|
|
|
|
row = self.get_row()
|
|
self.add(row)
|
|
|
|
# Formula
|
|
prob_label = get_prob_review_label(48, 2)
|
|
eq = TexMobject("=")
|
|
formula = get_binomial_formula(50, 48, self.s)
|
|
|
|
equation = VGroup(
|
|
prob_label,
|
|
eq,
|
|
formula,
|
|
)
|
|
equation.arrange(RIGHT)
|
|
equation.next_to(histogram, UP, LARGE_BUFF)
|
|
equation.to_edge(RIGHT)
|
|
|
|
prob_label.save_state()
|
|
arrow = Vector(DOWN)
|
|
arrow.next_to(histogram.bars[48], UP, SMALL_BUFF)
|
|
prob_label.next_to(arrow, UP)
|
|
|
|
self.play(
|
|
FadeIn(prob_label),
|
|
GrowArrow(arrow),
|
|
)
|
|
for mob in prob_label[1::2]:
|
|
line = Underline(mob)
|
|
line.match_color(mob)
|
|
self.play(ShowCreationThenDestruction(line))
|
|
self.wait(0.5)
|
|
self.play(
|
|
Restore(prob_label),
|
|
FadeIn(equation[1:], lag_ratio=0.1),
|
|
)
|
|
self.wait()
|
|
|
|
self.explain_n_choose_k(row, formula)
|
|
|
|
# Circle formula parts
|
|
rect1 = SurroundingRectangle(formula[4:8])
|
|
rect2 = SurroundingRectangle(formula[8:])
|
|
rect1.set_stroke(GREEN, 2)
|
|
rect2.set_stroke(RED, 2)
|
|
|
|
for rect in rect1, rect2:
|
|
self.play(ShowCreation(rect))
|
|
self.wait()
|
|
self.play(FadeOut(rect))
|
|
|
|
# Show numerical answer
|
|
eq2 = TexMobject("=")
|
|
value = DecimalNumber(dist.pmf(48), num_decimal_places=5)
|
|
rhs = VGroup(eq2, value)
|
|
rhs.arrange(RIGHT)
|
|
rhs.match_y(eq)
|
|
rhs.to_edge(RIGHT, buff=MED_SMALL_BUFF)
|
|
self.play(
|
|
FadeInFrom(value, LEFT),
|
|
FadeIn(eq2),
|
|
equation.next_to, eq2, LEFT,
|
|
)
|
|
self.wait()
|
|
|
|
# Show alternate values of k
|
|
n = 50
|
|
for k in it.chain(range(47, 42, -1), range(43, 51), [49, 48]):
|
|
new_prob_label = get_prob_review_label(k, n - k)
|
|
new_prob_label.replace(prob_label)
|
|
prob_label.become(new_prob_label)
|
|
new_formula = get_binomial_formula(n, k, self.s)
|
|
new_formula.replace(formula)
|
|
formula.set_submobjects(new_formula)
|
|
|
|
value.set_value(dist.pmf(k))
|
|
histogram.bars.set_fill(LIGHT_GREY)
|
|
histogram.bars[k].set_fill(GREEN)
|
|
arrow.next_to(histogram.bars[k], UP, SMALL_BUFF)
|
|
|
|
new_row = get_checks_and_crosses((n - k) * [False] + k * [True])
|
|
new_row.replace(row)
|
|
row.become(new_row)
|
|
self.wait(0.5)
|
|
|
|
# Name it as the Binomial distribution
|
|
long_equation = VGroup(prob_label, eq, formula, eq2, value)
|
|
bin_name = TextMobject("Binomial", " Distribution")
|
|
bin_name.scale(1.5)
|
|
bin_name.next_to(histogram, UP, MED_LARGE_BUFF)
|
|
|
|
underline = Underline(bin_name[0])
|
|
underline.set_stroke(PINK, 2)
|
|
nck_rect = SurroundingRectangle(formula[:4])
|
|
nck_rect.set_stroke(PINK, 2)
|
|
|
|
self.play(
|
|
long_equation.next_to, self.slots, DOWN, MED_LARGE_BUFF,
|
|
long_equation.to_edge, RIGHT,
|
|
FadeInFrom(bin_name, DOWN),
|
|
)
|
|
self.wait()
|
|
self.play(ShowCreationThenDestruction(underline))
|
|
self.wait()
|
|
bools = [True] * 50
|
|
bools[random.randint(0, 49)] = False
|
|
bools[random.randint(0, 49)] = False
|
|
row.become(get_checks_and_crosses(bools).replace(row))
|
|
self.play(ShowIncreasingSubsets(row, run_time=4))
|
|
self.wait()
|
|
|
|
# Show likelihood and posterior labels
|
|
likelihood_label = TexMobject(
|
|
"P(",
|
|
"\\text{data}", "\\,|\\,",
|
|
"\\text{success rate}",
|
|
")",
|
|
)
|
|
posterior_label = TexMobject(
|
|
"P(",
|
|
"\\text{success rate}",
|
|
"\\,|\\,",
|
|
"\\text{data}",
|
|
")",
|
|
)
|
|
for label in (likelihood_label, posterior_label):
|
|
label.set_color_by_tex_to_color_map({
|
|
"data": GREEN,
|
|
"success": YELLOW,
|
|
})
|
|
|
|
likelihood_label.next_to(
|
|
prob_label, DOWN, LARGE_BUFF, aligned_edge=LEFT
|
|
)
|
|
|
|
right_arrow = Vector(RIGHT)
|
|
right_arrow.next_to(likelihood_label, RIGHT)
|
|
ra_label = TextMobject("But we want")
|
|
ra_label.match_width(right_arrow)
|
|
ra_label.next_to(right_arrow, UP, SMALL_BUFF)
|
|
posterior_label.next_to(right_arrow, RIGHT)
|
|
|
|
self.play(
|
|
FadeInFrom(likelihood_label, UP),
|
|
bin_name.set_height, 0.4,
|
|
bin_name.set_y, histogram.axes.c2p(0, .25)[1]
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
GrowArrow(right_arrow),
|
|
FadeInFrom(ra_label, 0.5 * LEFT),
|
|
)
|
|
anims = []
|
|
for i, j in enumerate([0, 3, 2, 1, 4]):
|
|
anims.append(
|
|
TransformFromCopy(
|
|
likelihood_label[i],
|
|
posterior_label[j],
|
|
path_arc=-45 * DEGREES,
|
|
run_time=2,
|
|
)
|
|
)
|
|
self.play(*anims)
|
|
self.add(posterior_label)
|
|
self.wait()
|
|
|
|
# Prepare for new plot
|
|
histogram.add(bin_name)
|
|
always(arrow.next_to, histogram.bars[48], UP, SMALL_BUFF)
|
|
self.play(
|
|
FadeOut(likelihood_label),
|
|
FadeOut(posterior_label),
|
|
FadeOut(right_arrow),
|
|
FadeOut(ra_label),
|
|
FadeOutAndShift(row, UP),
|
|
FadeOutAndShift(self.slots, UP),
|
|
histogram.scale, 0.7,
|
|
histogram.to_edge, UP,
|
|
arrow.scale, 0.5,
|
|
arrow.set_stroke, None, 4,
|
|
long_equation.center,
|
|
run_time=1.5,
|
|
)
|
|
self.add(arrow)
|
|
|
|
# x_labels = histogram.axes.x_labels
|
|
# underline = Underline(x_labels)
|
|
# underline.set_stroke(GREEN, 3)
|
|
# self.play(
|
|
# LaggedStartMap(
|
|
# ApplyFunction, x_labels,
|
|
# lambda mob: (
|
|
# lambda m: m.scale(1.5).set_color(GREEN),
|
|
# mob,
|
|
# ),
|
|
# rate_func=there_and_back,
|
|
# ),
|
|
# ShowCreationThenDestruction(underline),
|
|
# )
|
|
# num_checks = TexMobject("\\# " + CMARK_TEX)
|
|
# num_checks.set_color(GREEN)
|
|
# num_checks.next_to(
|
|
# x_labels, RIGHT,
|
|
# MED_LARGE_BUFF,
|
|
# aligned_edge=DOWN,
|
|
# )
|
|
# self.play(Write(num_checks))
|
|
# self.wait()
|
|
|
|
low_axes = get_beta_dist_axes(y_max=0.3, y_unit=0.1, label_y=False)
|
|
low_axes.y_axis.set_height(
|
|
2,
|
|
about_point=low_axes.c2p(0, 0),
|
|
stretch=True,
|
|
)
|
|
low_axes.to_edge(DOWN)
|
|
low_axes.x_axis.numbers.set_color(YELLOW)
|
|
y_label_copies = histogram.axes.y_labels.copy()
|
|
y_label_copies.set_height(0.6 * low_axes.get_height())
|
|
y_label_copies.next_to(low_axes, LEFT, 0, aligned_edge=UP)
|
|
y_label_copies.shift(SMALL_BUFF * UP)
|
|
low_axes.y_axis.add(y_label_copies)
|
|
low_axes.y_axis.set_opacity(0)
|
|
|
|
# Show alternate values of s
|
|
s_tracker = ValueTracker(self.s)
|
|
|
|
s_tip = ArrowTip(start_angle=-90 * DEGREES)
|
|
s_tip.set_color(YELLOW)
|
|
s_tip.axis = low_axes.x_axis
|
|
s_tip.st = s_tracker
|
|
s_tip.add_updater(
|
|
lambda m: m.next_to(m.axis.n2p(m.st.get_value()), UP, buff=0)
|
|
)
|
|
|
|
pl_decimal = DecimalNumber(self.s)
|
|
pl_decimal.set_color(YELLOW)
|
|
pl_decimal.replace(prob_label[-2][2:])
|
|
prob_label[-2][2:].set_opacity(0)
|
|
|
|
s_label = VGroup(prob_label[-2][:2], pl_decimal).copy()
|
|
sl_rect = SurroundingRectangle(s_label)
|
|
sl_rect.set_stroke(YELLOW, 2)
|
|
|
|
self.add(pl_decimal)
|
|
self.play(
|
|
ShowCreation(sl_rect),
|
|
Write(low_axes),
|
|
)
|
|
self.play(
|
|
s_label.next_to, s_tip, UP, 0.2, ORIGIN, s_label[1],
|
|
ReplacementTransform(sl_rect, s_tip)
|
|
)
|
|
always(s_label.next_to, s_tip, UP, 0.2, ORIGIN, s_label[1])
|
|
|
|
decimals = VGroup(pl_decimal, s_label[1], formula[5], formula[9])
|
|
decimals.s_tracker = s_tracker
|
|
|
|
histogram.s_tracker = s_tracker
|
|
histogram.n = n
|
|
histogram.rhs_value = value
|
|
|
|
def update_decimals(decs):
|
|
for dec in decs:
|
|
dec.set_value(decs.s_tracker.get_value())
|
|
|
|
def update_histogram(hist):
|
|
new_dist = scipy.stats.binom(hist.n, hist.s_tracker.get_value())
|
|
new_data = np.array([
|
|
new_dist.pmf(x)
|
|
for x in range(0, 51)
|
|
])
|
|
new_bars = hist.get_bars(new_data)
|
|
new_bars.match_style(hist.bars)
|
|
hist.bars.become(new_bars)
|
|
hist.rhs_value.set_value(new_dist.pmf(48))
|
|
|
|
bar_copy = histogram.bars[48].copy()
|
|
value.initial_config["num_decimal_places"] = 3
|
|
value.set_value(value.get_value())
|
|
bar_copy.next_to(value, RIGHT, aligned_edge=DOWN)
|
|
bar_copy.add_updater(
|
|
lambda m: m.set_height(
|
|
max(
|
|
histogram.bars[48].get_height() * 0.75,
|
|
1e-6,
|
|
),
|
|
stretch=True,
|
|
about_edge=DOWN,
|
|
)
|
|
)
|
|
self.add(bar_copy)
|
|
|
|
self.add(histogram)
|
|
self.add(decimals)
|
|
for s in [0.95, 0.5, 0.99, 0.9]:
|
|
self.play(
|
|
s_tracker.set_value, s,
|
|
UpdateFromFunc(decimals, update_decimals),
|
|
UpdateFromFunc(histogram, update_histogram),
|
|
UpdateFromFunc(value, lambda m: m),
|
|
UpdateFromFunc(s_label, lambda m: m.update),
|
|
run_time=5,
|
|
)
|
|
self.wait()
|
|
|
|
# Plot
|
|
def func(x):
|
|
return scipy.stats.binom(50, x).pmf(48) + 1e-5
|
|
graph = low_axes.get_graph(func, step_size=0.05)
|
|
graph.set_stroke(BLUE, 3)
|
|
|
|
v_line = Line(DOWN, UP)
|
|
v_line.axes = low_axes
|
|
v_line.st = s_tracker
|
|
v_line.graph = graph
|
|
v_line.add_updater(
|
|
lambda m: m.put_start_and_end_on(
|
|
m.axes.c2p(m.st.get_value(), 0),
|
|
m.axes.input_to_graph_point(
|
|
m.st.get_value(),
|
|
m.graph,
|
|
),
|
|
)
|
|
)
|
|
v_line.set_stroke(GREEN, 2)
|
|
dot = Dot()
|
|
dot.line = v_line
|
|
dot.set_height(0.05)
|
|
dot.add_updater(lambda m: m.move_to(m.line.get_end()))
|
|
|
|
self.play(
|
|
ApplyMethod(
|
|
histogram.bars[48].stretch, 2, 1, {"about_edge": DOWN},
|
|
rate_func=there_and_back,
|
|
run_time=2,
|
|
),
|
|
)
|
|
self.wait()
|
|
self.play(low_axes.y_axis.set_opacity, 1)
|
|
self.play(
|
|
FadeIn(graph),
|
|
FadeOut(s_label),
|
|
FadeOut(s_tip),
|
|
)
|
|
self.play(
|
|
TransformFromCopy(histogram.bars[48], v_line),
|
|
FadeIn(dot),
|
|
)
|
|
|
|
self.add(histogram)
|
|
decimals.remove(decimals[1])
|
|
for s in [0.9, 0.96, 1, 0.8, 0.96]:
|
|
self.play(
|
|
s_tracker.set_value, s,
|
|
UpdateFromFunc(decimals, update_decimals),
|
|
UpdateFromFunc(histogram, update_histogram),
|
|
UpdateFromFunc(value, lambda m: m),
|
|
run_time=5,
|
|
)
|
|
self.wait()
|
|
|
|
# Write formula
|
|
clean_form = TexMobject(
|
|
"P(", "\\text{data}", "\\,|\\,", "{s}", ")", "=",
|
|
"c", "\\cdot",
|
|
"{s}", "^{\\#" + CMARK_TEX + "}",
|
|
"(1 - ", "{s}", ")", "^{\\#" + XMARK_TEX + "}",
|
|
tex_to_color_map={
|
|
"{s}": YELLOW,
|
|
"\\#" + CMARK_TEX: GREEN,
|
|
"\\#" + XMARK_TEX: RED,
|
|
}
|
|
)
|
|
clean_form.next_to(formula, DOWN, MED_LARGE_BUFF)
|
|
clean_form.save_state()
|
|
clean_form[:6].align_to(equation[1], RIGHT)
|
|
clean_form[6].match_x(formula[2])
|
|
clean_form[7].set_opacity(0)
|
|
clean_form[7].next_to(clean_form[6], RIGHT, SMALL_BUFF)
|
|
clean_form[8:11].match_x(formula[4:8])
|
|
clean_form[11:].match_x(formula[8:])
|
|
clean_form.saved_state.move_to(clean_form, LEFT)
|
|
|
|
fade_rects = VGroup(
|
|
BackgroundRectangle(equation[:2]),
|
|
BackgroundRectangle(formula),
|
|
BackgroundRectangle(VGroup(eq2, bar_copy)),
|
|
)
|
|
fade_rects.set_fill(BLACK, 0.8)
|
|
fade_rects[1].set_fill(opacity=0)
|
|
|
|
pre_c = formula[:4].copy()
|
|
pre_s = formula[4:8].copy()
|
|
pre_1ms = formula[8:].copy()
|
|
|
|
self.play(
|
|
FadeIn(fade_rects),
|
|
FadeIn(clean_form[:6])
|
|
)
|
|
self.play(ShowCreationThenFadeAround(clean_form[3]))
|
|
self.wait()
|
|
for cf, pre in (clean_form[6], pre_c), (clean_form[8:11], pre_s), (clean_form[11:], pre_1ms):
|
|
self.play(
|
|
GrowFromPoint(cf, pre.get_center()),
|
|
pre.move_to, cf,
|
|
pre.scale, 0,
|
|
)
|
|
self.remove(pre)
|
|
self.wait()
|
|
|
|
self.wait()
|
|
self.play(Restore(clean_form))
|
|
|
|
# Show with 480 and 20
|
|
top_fade_rect = BackgroundRectangle(histogram)
|
|
top_fade_rect.shift(SMALL_BUFF * DOWN)
|
|
top_fade_rect.scale(1.5, about_edge=DOWN)
|
|
top_fade_rect.set_fill(BLACK, 0)
|
|
|
|
new_formula = get_binomial_formula(500, 480, 0.96)
|
|
new_formula.move_to(formula)
|
|
|
|
def func500(x):
|
|
return scipy.stats.binom(500, x).pmf(480) + 1e-5
|
|
|
|
graph500 = low_axes.get_graph(func500, step_size=0.05)
|
|
graph500.set_stroke(TEAL, 3)
|
|
|
|
self.play(
|
|
top_fade_rect.set_opacity, 1,
|
|
fade_rects.set_opacity, 1,
|
|
FadeIn(new_formula)
|
|
)
|
|
|
|
self.clear()
|
|
self.add(new_formula, clean_form, low_axes, graph, v_line, dot)
|
|
self.add(low_axes.y_axis)
|
|
|
|
self.play(TransformFromCopy(graph, graph500))
|
|
self.wait()
|
|
|
|
y_axis = low_axes.y_axis
|
|
y_axis.save_state()
|
|
sf = 3
|
|
y_axis.stretch(sf, 1, about_point=low_axes.c2p(0, 0))
|
|
for label in y_label_copies:
|
|
label.stretch(1 / sf, 1)
|
|
|
|
v_line.suspend_updating()
|
|
v_line.graph = graph500
|
|
self.play(
|
|
Restore(y_axis, rate_func=reverse_smooth),
|
|
graph.stretch, sf, 1, {"about_edge": DOWN},
|
|
graph500.stretch, sf, 1, {"about_edge": DOWN},
|
|
)
|
|
v_line.resume_updating()
|
|
self.add(v_line, dot)
|
|
|
|
sub_decimals = VGroup(new_formula[5], new_formula[9])
|
|
sub_decimals.s_tracker = s_tracker
|
|
|
|
for s in [0.94, 0.98, 0.96]:
|
|
self.play(
|
|
s_tracker.set_value, s,
|
|
UpdateFromFunc(sub_decimals, update_decimals),
|
|
run_time=5,
|
|
)
|
|
self.wait()
|
|
|
|
def explain_n_choose_k(self, row, formula):
|
|
row.add_updater(lambda m: m)
|
|
|
|
brace = Brace(formula[:4], UP, buff=SMALL_BUFF)
|
|
words = brace.get_text("``50 choose 48''")
|
|
|
|
slots = self.slots = VGroup()
|
|
for sym in row:
|
|
line = Underline(sym)
|
|
line.scale(0.9)
|
|
slots.add(line)
|
|
for slot in slots:
|
|
slot.match_y(slots[0])
|
|
|
|
formula[1].counted = slots
|
|
k_rect = SurroundingRectangle(formula[2])
|
|
k_rect.set_stroke(GREEN, 2)
|
|
|
|
checks = VGroup()
|
|
for sym in row:
|
|
if sym.positive:
|
|
checks.add(sym)
|
|
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
FadeInFromDown(words),
|
|
)
|
|
self.wait()
|
|
self.play(FadeOut(words))
|
|
formula.save_state()
|
|
self.play(
|
|
ShowIncreasingSubsets(slots),
|
|
UpdateFromFunc(
|
|
formula[1],
|
|
lambda m: m.set_value(len(m.counted))
|
|
),
|
|
run_time=2,
|
|
)
|
|
formula.restore()
|
|
self.add(formula)
|
|
self.wait()
|
|
self.play(
|
|
LaggedStartMap(
|
|
ApplyMethod, checks,
|
|
lambda m: (m.shift, 0.3 * DOWN),
|
|
rate_func=there_and_back,
|
|
lag_ratio=0.05,
|
|
),
|
|
ShowCreationThenFadeOut(k_rect),
|
|
run_time=2,
|
|
)
|
|
self.remove(checks)
|
|
self.add(row)
|
|
self.wait()
|
|
|
|
# Example orderings
|
|
row_target = VGroup()
|
|
for sym in row:
|
|
sym.generate_target()
|
|
row_target.add(sym.target)
|
|
|
|
row_target.sort(submob_func=lambda m: -int(m.positive))
|
|
row_target.arrange(
|
|
RIGHT, buff=get_norm(row[0].get_right() - row[1].get_left())
|
|
)
|
|
row_target.move_to(row)
|
|
self.play(
|
|
LaggedStartMap(
|
|
MoveToTarget, row,
|
|
path_arc=30 * DEGREES,
|
|
lag_ratio=0,
|
|
),
|
|
)
|
|
self.wait()
|
|
row.sort()
|
|
self.play(Swap(*row[-3:-1]))
|
|
self.add(row)
|
|
self.wait()
|
|
|
|
# All orderings
|
|
nck_count = Integer(2)
|
|
nck_count.next_to(brace, UP)
|
|
nck_top = nck_count.get_top()
|
|
always(nck_count.move_to, nck_top, UP)
|
|
|
|
combs = list(it.combinations(range(50), 48))
|
|
bool_lists = [
|
|
[i in comb for i in range(50)]
|
|
for comb in combs
|
|
]
|
|
row.counter = nck_count
|
|
row.bool_lists = bool_lists
|
|
|
|
def update_row(r):
|
|
i = r.counter.get_value() - 1
|
|
new_row = get_checks_and_crosses(r.bool_lists[i])
|
|
new_row.replace(r, dim_to_match=0)
|
|
r.set_submobjects(new_row)
|
|
|
|
row.add_updater(update_row)
|
|
self.add(row)
|
|
self.play(
|
|
ChangeDecimalToValue(nck_count, choose(50, 48)),
|
|
run_time=10,
|
|
)
|
|
row.clear_updaters()
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(nck_count),
|
|
FadeOut(brace),
|
|
)
|
|
|
|
|
|
class StateIndependence(Scene):
|
|
def construct(self):
|
|
row = get_random_checks_and_crosses()
|
|
row.to_edge(UP)
|
|
# self.add(row)
|
|
|
|
arrows = VGroup()
|
|
for m1, m2 in zip(row, row[1:]):
|
|
arrow = Arrow(
|
|
m1.get_bottom() + 0.025 * DOWN,
|
|
m2.get_bottom(),
|
|
path_arc=145 * DEGREES,
|
|
max_stroke_width_to_length_ratio=10,
|
|
max_tip_length_to_length_ratio=0.5,
|
|
)
|
|
arrow.tip.rotate(-10 * DEGREES)
|
|
arrow.shift(SMALL_BUFF * DOWN)
|
|
arrow.set_color(YELLOW)
|
|
arrows.add(arrow)
|
|
|
|
words = TextMobject("No influence")
|
|
words.set_height(0.25)
|
|
words.next_to(arrows[0], DOWN)
|
|
|
|
self.play(
|
|
ShowCreation(arrows[0]),
|
|
FadeIn(words)
|
|
)
|
|
for i in range(10):
|
|
self.play(
|
|
words.next_to, arrows[i + 1], DOWN,
|
|
FadeOut(arrows[i]),
|
|
ShowCreation(arrows[i + 1])
|
|
)
|
|
last_arrow = arrows[i + 1]
|
|
|
|
self.play(
|
|
FadeOut(words),
|
|
FadeOut(last_arrow),
|
|
)
|
|
|
|
|
|
class IllustrateBinomialSetupWithCoins(Scene):
|
|
def construct(self):
|
|
coins = [
|
|
get_coin("H"),
|
|
get_coin("T"),
|
|
]
|
|
|
|
coin_row = VGroup()
|
|
for x in range(12):
|
|
coin_row.add(random.choice(coins).copy())
|
|
|
|
coin_row.arrange(RIGHT)
|
|
coin_row.to_edge(UP)
|
|
|
|
first_coin = get_random_coin(shuffle_time=2, total_time=2)
|
|
first_coin.move_to(coin_row[0])
|
|
|
|
brace = Brace(coin_row, UP)
|
|
brace_label = brace.get_text("$N$ times")
|
|
|
|
prob_label = TexMobject(
|
|
"P(\\# 00 = k)",
|
|
tex_to_color_map={
|
|
"00": WHITE,
|
|
"k": GREEN,
|
|
}
|
|
)
|
|
heads = get_coin("H")
|
|
template = prob_label.get_part_by_tex("00")
|
|
heads.replace(template)
|
|
prob_label.replace_submobject(
|
|
prob_label.index_of_part(template),
|
|
heads,
|
|
)
|
|
prob_label.set_height(1)
|
|
prob_label.next_to(coin_row, DOWN, LARGE_BUFF)
|
|
|
|
self.camera.frame.set_height(1.5 * FRAME_HEIGHT)
|
|
|
|
self.add(first_coin)
|
|
for x in range(4):
|
|
self.wait()
|
|
first_coin.suspend_updating()
|
|
self.wait()
|
|
first_coin.resume_updating()
|
|
|
|
self.remove(first_coin)
|
|
self.play(
|
|
ShowIncreasingSubsets(coin_row, int_func=np.ceil),
|
|
GrowFromPoint(brace, brace.get_left()),
|
|
FadeInFrom(brace_label, 3 * LEFT)
|
|
)
|
|
self.wait()
|
|
self.play(FadeIn(prob_label, lag_ratio=0.1))
|
|
self.wait()
|
|
|
|
|
|
class WriteLikelihoodFunction(Scene):
|
|
def construct(self):
|
|
formula = TexMobject(
|
|
"f({s}) = (\\text{const.})",
|
|
"{s}^{\\#" + CMARK_TEX + "}",
|
|
"(1 - {s})^{\\#" + XMARK_TEX, "}",
|
|
tex_to_color_map={
|
|
"{s}": YELLOW,
|
|
"\\#" + CMARK_TEX: GREEN,
|
|
"\\#" + XMARK_TEX: RED,
|
|
}
|
|
)
|
|
formula.scale(2)
|
|
|
|
rect1 = SurroundingRectangle(formula[3:6])
|
|
rect2 = SurroundingRectangle(formula[6:])
|
|
|
|
self.play(FadeInFromDown(formula))
|
|
self.wait()
|
|
self.play(ShowCreationThenFadeOut(rect1))
|
|
self.wait()
|
|
self.play(ShowCreationThenFadeOut(rect2))
|
|
self.wait()
|
|
|
|
self.add(formula)
|
|
self.embed()
|
|
|
|
|
|
class Guess96Percent(Scene):
|
|
def construct(self):
|
|
randy = Randolph()
|
|
randy.set_height(1)
|
|
|
|
bubble = SpeechBubble(height=2, width=3)
|
|
bubble.pin_to(randy)
|
|
words = TextMobject("96$\\%$, right?")
|
|
fix_percent(words[0][2])
|
|
bubble.add_content(words)
|
|
|
|
arrow = Vector(2 * RIGHT + DOWN)
|
|
arrow.next_to(randy, RIGHT)
|
|
arrow.shift(2 * UP)
|
|
|
|
self.play(
|
|
FadeIn(randy),
|
|
ShowCreation(bubble),
|
|
Write(words),
|
|
)
|
|
self.play(randy.change, "shruggie", randy.get_right() + RIGHT)
|
|
self.play(ShowCreation(arrow))
|
|
for x in range(2):
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
|
|
self.embed()
|
|
|
|
|
|
class LikelihoodGraphFor10of10(ShowBinomialFormula):
|
|
CONFIG = {
|
|
"histogram_config": {
|
|
"x_label_freq": 2,
|
|
"y_axis_numbers_to_show": range(25, 125, 25),
|
|
"y_max": 1,
|
|
"y_tick_freq": 0.25,
|
|
"height": 2,
|
|
"bar_colors": [BLUE],
|
|
},
|
|
}
|
|
|
|
def construct(self):
|
|
# Add histogram
|
|
dist = scipy.stats.binom(10, self.s)
|
|
data = np.array([
|
|
dist.pmf(x)
|
|
for x in range(0, 11)
|
|
])
|
|
histogram = self.get_histogram(data)
|
|
histogram.bars.set_fill(GREY_C)
|
|
histogram.bars[10].set_fill(GREEN)
|
|
histogram.to_edge(UP)
|
|
|
|
x_label = TexMobject("\\#" + CMARK_TEX)
|
|
x_label.set_color(GREEN)
|
|
x_label.next_to(histogram.axes.x_axis.get_end(), RIGHT)
|
|
histogram.add(x_label)
|
|
self.add(histogram)
|
|
|
|
arrow = Vector(DOWN)
|
|
arrow.next_to(histogram.bars[10], UP, SMALL_BUFF)
|
|
self.add(arrow)
|
|
|
|
# Add formula
|
|
prob_label = get_prob_review_label(10, 0)
|
|
eq = TexMobject("=")
|
|
formula = get_binomial_formula(10, 10, self.s)
|
|
eq2 = TexMobject("=")
|
|
value = DecimalNumber(dist.pmf(10), num_decimal_places=2)
|
|
|
|
equation = VGroup(prob_label, eq, formula, eq2, value)
|
|
equation.arrange(RIGHT)
|
|
equation.next_to(histogram, DOWN, MED_LARGE_BUFF)
|
|
|
|
# Add lower axes
|
|
low_axes = get_beta_dist_axes(y_max=1, y_unit=0.25, label_y=False)
|
|
low_axes.y_axis.set_height(
|
|
2,
|
|
about_point=low_axes.c2p(0, 0),
|
|
stretch=True,
|
|
)
|
|
low_axes.to_edge(DOWN)
|
|
low_axes.x_axis.numbers.set_color(YELLOW)
|
|
y_label_copies = histogram.axes.y_labels.copy()
|
|
y_label_copies.set_height(0.7 * low_axes.get_height())
|
|
y_label_copies.next_to(low_axes, LEFT, 0, aligned_edge=UP)
|
|
y_label_copies.shift(SMALL_BUFF * UP)
|
|
low_axes.y_axis.add(y_label_copies)
|
|
|
|
# Add lower plot
|
|
s_tracker = ValueTracker(self.s)
|
|
|
|
def func(x):
|
|
return x**10
|
|
graph = low_axes.get_graph(func, step_size=0.05)
|
|
graph.set_stroke(BLUE, 3)
|
|
|
|
v_line = Line(DOWN, UP)
|
|
v_line.axes = low_axes
|
|
v_line.st = s_tracker
|
|
v_line.graph = graph
|
|
v_line.add_updater(
|
|
lambda m: m.put_start_and_end_on(
|
|
m.axes.c2p(m.st.get_value(), 0),
|
|
m.axes.input_to_graph_point(
|
|
m.st.get_value(),
|
|
m.graph,
|
|
),
|
|
)
|
|
)
|
|
v_line.set_stroke(GREEN, 2)
|
|
dot = Dot()
|
|
dot.line = v_line
|
|
dot.set_height(0.05)
|
|
dot.add_updater(lambda m: m.move_to(m.line.get_end()))
|
|
|
|
# Show simpler formula
|
|
brace = Brace(formula, DOWN, buff=SMALL_BUFF)
|
|
simpler_formula = TexMobject("s", "^{10}")
|
|
simpler_formula.set_color_by_tex("s", YELLOW)
|
|
simpler_formula.set_color_by_tex("10", GREEN)
|
|
simpler_formula.next_to(brace, DOWN)
|
|
|
|
rects = VGroup(
|
|
BackgroundRectangle(formula[:4]),
|
|
BackgroundRectangle(formula[8:]),
|
|
)
|
|
rects.set_opacity(0.75)
|
|
|
|
self.wait()
|
|
self.play(FadeIn(equation))
|
|
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(rects),
|
|
GrowFromCenter(brace),
|
|
FadeInFrom(simpler_formula, UP)
|
|
)
|
|
self.wait()
|
|
|
|
# Show various values of s
|
|
pl_decimal = DecimalNumber(self.s)
|
|
pl_decimal.set_color(YELLOW)
|
|
pl_decimal.replace(prob_label[-2][2:])
|
|
prob_label[-2][2:].set_opacity(0)
|
|
|
|
decimals = VGroup(pl_decimal, formula[5], formula[9])
|
|
decimals.s_tracker = s_tracker
|
|
|
|
histogram.s_tracker = s_tracker
|
|
histogram.n = 10
|
|
histogram.rhs_value = value
|
|
|
|
def update_decimals(decs):
|
|
for dec in decs:
|
|
dec.set_value(decs.s_tracker.get_value())
|
|
|
|
def update_histogram(hist):
|
|
new_dist = scipy.stats.binom(hist.n, hist.s_tracker.get_value())
|
|
new_data = np.array([
|
|
new_dist.pmf(x)
|
|
for x in range(0, 11)
|
|
])
|
|
new_bars = hist.get_bars(new_data)
|
|
new_bars.match_style(hist.bars)
|
|
hist.bars.become(new_bars)
|
|
hist.rhs_value.set_value(new_dist.pmf(10))
|
|
|
|
self.add(histogram)
|
|
self.add(decimals, rects)
|
|
self.play(
|
|
FadeIn(low_axes),
|
|
)
|
|
self.play(
|
|
ShowCreation(v_line),
|
|
FadeIn(dot),
|
|
)
|
|
self.add(graph, v_line, dot)
|
|
self.play(ShowCreation(graph))
|
|
self.wait()
|
|
|
|
always(arrow.next_to, histogram.bars[10], UP, SMALL_BUFF)
|
|
for s in [0.8, 1]:
|
|
self.play(
|
|
s_tracker.set_value, s,
|
|
UpdateFromFunc(decimals, update_decimals),
|
|
UpdateFromFunc(histogram, update_histogram),
|
|
UpdateFromFunc(value, lambda m: m),
|
|
run_time=5,
|
|
)
|
|
self.wait()
|
|
|
|
|
|
class StateNeedForBayesRule(TeacherStudentsScene):
|
|
def construct(self):
|
|
axes = get_beta_dist_axes(y_max=1, y_unit=0.25, label_y=False)
|
|
axes.y_axis.set_height(
|
|
2,
|
|
about_point=axes.c2p(0, 0),
|
|
stretch=True,
|
|
)
|
|
axes.set_width(5)
|
|
graph = axes.get_graph(lambda x: x**10)
|
|
graph.set_stroke(BLUE, 3)
|
|
alt_graph = graph.copy()
|
|
alt_graph.add_line_to(axes.c2p(1, 0))
|
|
alt_graph.add_line_to(axes.c2p(0, 0))
|
|
alt_graph.set_stroke(width=0)
|
|
alt_graph.set_fill(BLUE_E, 1)
|
|
|
|
plot = VGroup(axes, alt_graph, graph)
|
|
|
|
student0, student1, student2 = self.students
|
|
plot.next_to(student2.get_corner(UL), UP, MED_LARGE_BUFF)
|
|
plot.shift(LEFT)
|
|
|
|
v_lines = VGroup(
|
|
DashedLine(axes.c2p(0.8, 0), axes.c2p(0.8, 1)),
|
|
DashedLine(axes.c2p(1, 0), axes.c2p(1, 1)),
|
|
)
|
|
v_lines.set_stroke(YELLOW, 2)
|
|
|
|
self.play(
|
|
LaggedStart(
|
|
ApplyMethod(student0.change, "pondering", plot),
|
|
ApplyMethod(student1.change, "pondering", plot),
|
|
ApplyMethod(student2.change, "raise_left_hand", plot),
|
|
),
|
|
FadeInFrom(plot, DOWN),
|
|
run_time=1.5
|
|
)
|
|
self.play(*map(ShowCreation, v_lines))
|
|
self.play(
|
|
self.teacher.change, "tease",
|
|
*[
|
|
ApplyMethod(
|
|
v_line.move_to,
|
|
axes.c2p(0.9, 0),
|
|
DOWN,
|
|
)
|
|
for v_line in v_lines
|
|
]
|
|
)
|
|
self.change_student_modes(
|
|
"thinking", "thinking", "pondering",
|
|
look_at_arg=v_lines,
|
|
)
|
|
self.wait(2)
|
|
|
|
self.teacher_says(
|
|
"But first...",
|
|
added_anims=[
|
|
FadeOutAndShift(plot, LEFT),
|
|
FadeOutAndShift(v_lines, LEFT),
|
|
self.get_student_changes(
|
|
"erm", "erm", "erm",
|
|
look_at_arg=self.teacher.eyes,
|
|
)
|
|
]
|
|
)
|
|
self.wait(5)
|
|
|
|
|
|
class Part1EndScreen(PatreonEndScreen):
|
|
CONFIG = {
|
|
"specific_patrons": [
|
|
"1stViewMaths",
|
|
"Adam Dřínek",
|
|
"Aidan Shenkman",
|
|
"Alan Stein",
|
|
"Alex Mijalis",
|
|
"Alexis Olson",
|
|
"Ali Yahya",
|
|
"Andrew Busey",
|
|
"Andrew Cary",
|
|
"Andrew R. Whalley",
|
|
"Aravind C V",
|
|
"Arjun Chakroborty",
|
|
"Arthur Zey",
|
|
"Ashwin Siddarth",
|
|
"Austin Goodman",
|
|
"Avi Finkel",
|
|
"Awoo",
|
|
"Axel Ericsson",
|
|
"Ayan Doss",
|
|
"AZsorcerer",
|
|
"Barry Fam",
|
|
"Bernd Sing",
|
|
"Boris Veselinovich",
|
|
"Bradley Pirtle",
|
|
"Brandon Huang",
|
|
"Brian Staroselsky",
|
|
"Britt Selvitelle",
|
|
"Britton Finley",
|
|
"Burt Humburg",
|
|
"Calvin Lin",
|
|
"Charles Southerland",
|
|
"Charlie N",
|
|
"Chenna Kautilya",
|
|
"Chris Connett",
|
|
"Christian Kaiser",
|
|
"cinterloper",
|
|
"Clark Gaebel",
|
|
"Colwyn Fritze-Moor",
|
|
"Cooper Jones",
|
|
"Corey Ogburn",
|
|
"D. Sivakumar",
|
|
"Dan Herbatschek",
|
|
"Daniel Herrera C",
|
|
"Dave B",
|
|
"Dave Kester",
|
|
"dave nicponski",
|
|
"David B. Hill",
|
|
"David Clark",
|
|
"David Gow",
|
|
"Delton Ding",
|
|
"Dominik Wagner",
|
|
"Douglas Cantrell",
|
|
"emptymachine",
|
|
"Eric Younge",
|
|
"Eryq Ouithaqueue",
|
|
"Farzaneh Sarafraz",
|
|
"Federico Lebron",
|
|
"Frank R. Brown, Jr.",
|
|
"Giovanni Filippi",
|
|
"Hal Hildebrand",
|
|
"Hitoshi Yamauchi",
|
|
"Ivan Sorokin",
|
|
"Jacob Baxter",
|
|
"Jacob Harmon",
|
|
"Jacob Hartmann",
|
|
"Jacob Magnuson",
|
|
"Jake Vartuli - Schonberg",
|
|
"Jalex Stark",
|
|
"Jameel Syed",
|
|
"Jason Hise",
|
|
"Jayne Gabriele",
|
|
"Jean-Manuel Izaret",
|
|
"Jeff Linse",
|
|
"Jeff Straathof",
|
|
"Jimmy Yang",
|
|
"John C. Vesey",
|
|
"John Haley",
|
|
"John Le",
|
|
"John V Wertheim",
|
|
"Jonathan Heckerman",
|
|
"Jonathan Wilson",
|
|
"Joseph John Cox",
|
|
"Joseph Kelly",
|
|
"Josh Kinnear",
|
|
"Joshua Claeys",
|
|
"Juan Benet",
|
|
"Kai-Siang Ang",
|
|
"Kanan Gill",
|
|
"Karl Niu",
|
|
"Kartik Cating-Subramanian",
|
|
"Kaustuv DeBiswas",
|
|
"Killian McGuinness",
|
|
"Kros Dai",
|
|
"L0j1k",
|
|
"LAI Oscar",
|
|
"Lambda GPU Workstations",
|
|
"Lee Redden",
|
|
"Linh Tran",
|
|
"Luc Ritchie",
|
|
"Ludwig Schubert",
|
|
"Lukas Biewald",
|
|
"Magister Mugit",
|
|
"Magnus Dahlström",
|
|
"Manoj Rewatkar - RITEK SOLUTIONS",
|
|
"Mark B Bahu",
|
|
"Mark Heising",
|
|
"Mark Mann",
|
|
"Martin Price",
|
|
"Mathias Jansson",
|
|
"Matt Godbolt",
|
|
"Matt Langford",
|
|
"Matt Roveto",
|
|
"Matt Russell",
|
|
"Matteo Delabre",
|
|
"Matthew Bouchard",
|
|
"Matthew Cocke",
|
|
"Mia Parent",
|
|
"Michael Hardel",
|
|
"Michael W White",
|
|
"Mirik Gogri",
|
|
"Mustafa Mahdi",
|
|
"Márton Vaitkus",
|
|
"Nicholas Cahill",
|
|
"Nikita Lesnikov",
|
|
"Oleg Leonov",
|
|
"Oliver Steele",
|
|
"Omar Zrien",
|
|
"Owen Campbell-Moore",
|
|
"Patrick Lucas",
|
|
"Pavel Dubov",
|
|
"Peter Ehrnstrom",
|
|
"Peter Mcinerney",
|
|
"Pierre Lancien",
|
|
"Quantopian",
|
|
"Randy C. Will",
|
|
"rehmi post",
|
|
"Rex Godby",
|
|
"Ripta Pasay",
|
|
"Rish Kundalia",
|
|
"Roman Sergeychik",
|
|
"Roobie",
|
|
"Ryan Atallah",
|
|
"Samuel Judge",
|
|
"SansWord Huang",
|
|
"Scott Gray",
|
|
"Scott Walter, Ph.D.",
|
|
"soekul",
|
|
"Solara570",
|
|
"Steve Huynh",
|
|
"Steve Sperandeo",
|
|
"Steven Braun",
|
|
"Steven Siddals",
|
|
"Stevie Metke",
|
|
"supershabam",
|
|
"Suteerth Vishnu",
|
|
"Suthen Thomas",
|
|
"Tal Einav",
|
|
"Taras Bobrovytsky",
|
|
"Tauba Auerbach",
|
|
"Ted Suzman",
|
|
"Thomas J Sargent",
|
|
"Thomas Tarler",
|
|
"Tianyu Ge",
|
|
"Tihan Seale",
|
|
"Tyler VanValkenburg",
|
|
"Vassili Philippov",
|
|
"Veritasium",
|
|
"Vignesh Ganapathi Subramanian",
|
|
"Vinicius Reis",
|
|
"Xuanji Li",
|
|
"Yana Chernobilsky",
|
|
"Yavor Ivanov",
|
|
"YinYangBalance.Asia",
|
|
"Yu Jun",
|
|
"Yurii Monastyrshyn",
|
|
],
|
|
}
|