3b1b-manim/eop/bayes.py
2017-06-07 14:34:39 -07:00

1067 lines
33 KiB
Python

from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import *
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from animation.playground import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from topics.complex_numbers import *
from topics.common_scenes import *
from topics.probability import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
#revert_to_original_skipping_status
#########
class BayesOpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"Inside every non-Bayesian there \\\\ is a Bayesian struggling to get out."
],
"author" : "Dennis V. Lindley",
}
class IntroducePokerHand(PiCreatureScene, SampleSpaceScene):
CONFIG = {
"community_cards_center" : 1.5*DOWN,
"community_card_values" : ["10S", "QH", "AH", "2C", "5H"],
"your_hand_values" : ["JS", "KC"],
}
def construct(self):
self.add_cards()
self.indicate_straight()
self.show_flush_potential()
self.compute_flush_probability()
self.show_flush_sample_space()
self.talk_through_sample_space()
self.place_high_bet()
self.change_belief()
self.move_community_cards_out_of_the_way()
self.name_bayes_rule()
def add_cards(self):
you, her = self.you, self.her
community_cards = VGroup(*map(
PlayingCard, self.community_card_values
))
community_cards.arrange_submobjects(RIGHT)
community_cards.move_to(self.community_cards_center)
deck = VGroup(*[
PlayingCard(turned_over = True)
for x in range(5)
])
for i, card in enumerate(deck):
card.shift(i*(0.03*RIGHT + 0.015*DOWN))
deck.next_to(community_cards, LEFT)
you.hand = self.get_hand(you, self.your_hand_values)
her.hand = self.get_hand(her, None)
hand_cards = VGroup(*it.chain(*zip(you.hand, her.hand)))
self.add(deck)
for group in hand_cards, community_cards:
for card in group:
card.generate_target()
card.scale(0.01)
card.move_to(deck[-1], UP+RIGHT)
self.play(LaggedStart(MoveToTarget, group, lag_ratio = 0.8))
self.dither()
self.dither()
self.community_cards = community_cards
self.deck = deck
def indicate_straight(self):
you = self.you
community_cards = self.community_cards
you.hand.save_state()
you.hand.generate_target()
for card in you.hand.target:
card.scale_to_fit_height(community_cards.get_height())
selected_community_cards = VGroup(*filter(
lambda card : card.numerical_value >= 10,
community_cards
))
card_cmp = lambda c1, c2 : cmp(
c1.numerical_value, c2.numerical_value
)
selected_community_cards.submobjects.sort(card_cmp)
selected_community_cards.save_state()
for card in selected_community_cards:
card.generate_target()
straight_cards = VGroup(*it.chain(
you.hand.target,
[c.target for c in selected_community_cards]
))
straight_cards.submobjects.sort(card_cmp)
straight_cards.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
straight_cards.next_to(community_cards, UP, aligned_edge = LEFT)
you.hand.target.shift(MED_SMALL_BUFF*UP)
self.play(LaggedStart(
MoveToTarget,
selected_community_cards,
run_time = 1.5
))
self.play(MoveToTarget(you.hand))
self.play(LaggedStart(
ApplyMethod,
straight_cards,
lambda m : (m.highlight, YELLOW),
rate_func = there_and_back,
run_time = 1.5,
lag_ratio = 0.5,
remover = True,
))
self.play(you.change, "hooray", straight_cards)
self.dither(2)
self.play(
selected_community_cards.restore,
you.hand.restore,
you.change_mode, "happy"
)
self.dither()
def show_flush_potential(self):
you, her = self.you, self.her
heart_cards = VGroup(*filter(
lambda c : c.suit == "hearts",
self.community_cards
))
heart_cards.save_state()
her.hand.save_state()
her.hand.generate_target()
her.hand.target.arrange_submobjects(RIGHT)
her.hand.target.next_to(heart_cards, UP)
her.hand.target.to_edge(UP)
her.glasses.save_state()
her.glasses.move_to(her.hand.target)
her.glasses.set_fill(opacity = 0)
heart_qs = VGroup()
hearts = VGroup()
q_marks = VGroup()
for target in her.hand.target:
heart = SuitSymbol("hearts")
q_mark = TexMobject("?")
heart_q = VGroup(heart, q_mark)
for mob in heart_q:
mob.scale_to_fit_height(0.5)
heart_q.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
heart_q.move_to(target)
heart_qs.add(heart, q_mark)
hearts.add(heart)
q_marks.add(q_mark)
self.play(heart_cards.shift, heart_cards.get_height()*UP)
self.play(you.change_mode, "hesitant")
self.play(MoveToTarget(her.hand))
self.play(LaggedStart(DrawBorderThenFill, heart_qs))
self.play(
her.change, "happy",
her.glasses.restore,
)
self.pi_creatures.remove(her)
new_suit_pairs = [
("clubs", "diamonds"),
("diamonds", "spades"),
("spades", "clubs"),
("hearts", "hearts"),
]
for new_suit_pair in new_suit_pairs:
new_symbols = VGroup(*map(SuitSymbol, new_suit_pair))
for new_symbol, heart in zip(new_symbols, hearts):
new_symbol.replace(heart, dim_to_match = 1)
self.play(Transform(
hearts, new_symbols,
submobject_mode = "lagged_start"
))
self.dither()
self.play(FadeOut(heart_qs))
self.play(
heart_cards.restore,
her.hand.restore,
you.change_mode, "pondering",
)
self.q_marks = q_marks
def compute_flush_probability(self):
you, her = self.you, self.her
equation = TexMobject(
"{ {10 \\choose 2}", "\\over", "{45 \\choose 2} }",
"=", "{1 \\over 22}", "\\approx", "4.5\\%"
)
equation.next_to(self.community_cards, UP, buff = LARGE_BUFF)
percentage = equation.get_part_by_tex("4.5")
ten = VGroup(*equation[0][1:3])
num_hearts = TextMobject("\\# Remaining hearts")
num_hearts.scale(0.75)
num_hearts.next_to(
ten, UP, aligned_edge = LEFT
)
num_hearts.to_edge(UP)
num_hearts.highlight(RED)
num_hearts_arrow = Arrow(
num_hearts.get_bottom(), ten.get_right(),
color = RED, buff = SMALL_BUFF
)
fourty_five = VGroup(*equation[2][1:3])
num_cards = TextMobject("\\# Remaining cards")
num_cards.scale(0.75)
num_cards.next_to(fourty_five, LEFT)
num_cards.to_edge(LEFT)
num_cards.highlight(BLUE)
num_cards_arrow = Arrow(
num_cards, fourty_five,
color = BLUE, buff = SMALL_BUFF
)
self.play(LaggedStart(FadeIn, equation))
self.dither(2)
self.play(
FadeIn(num_hearts),
ShowCreation(num_hearts_arrow),
ten.highlight, RED,
)
self.play(
FadeIn(num_cards),
ShowCreation(num_cards_arrow),
fourty_five.highlight, BLUE
)
self.dither(3)
equation.remove(percentage)
self.play(*map(FadeOut, [
equation,
num_hearts, num_hearts_arrow,
num_cards, num_cards_arrow,
]))
self.percentage = percentage
def show_flush_sample_space(self):
you, her = self.you, self.her
percentage = self.percentage
sample_space = self.get_sample_space()
sample_space.add_title("Your belief")
sample_space.move_to(VGroup(you.hand, her.hand))
sample_space.to_edge(UP, buff = MED_SMALL_BUFF)
p = 1./22
sample_space.divide_horizontally(
p, colors = [SuitSymbol.CONFIG["red"], BLUE_E]
)
braces, labels = sample_space.get_side_braces_and_labels([
percentage.get_tex_string(), "95.5\\%"
])
top_label, bottom_label = labels
self.play(
FadeIn(sample_space),
ReplacementTransform(percentage, top_label)
)
self.play(*map(GrowFromCenter, [
brace for brace in braces
]))
self.dither(2)
self.play(Write(bottom_label))
self.dither(2)
self.sample_space = sample_space
def talk_through_sample_space(self):
her = self.her
sample_space = self.sample_space
top_part, bottom_part = self.sample_space.horizontal_parts
flush_hands, non_flush_hands = hand_lists = [
[self.get_hand(her, keys) for keys in key_list]
for key_list in [
[("3H", "8H"), ("4H", "5H"), ("JH", "KH")],
[("AC", "6D"), ("3D", "6S"), ("JH", "4C")],
]
]
for hand_list, part in zip(hand_lists, [top_part, bottom_part]):
self.play(Indicate(part, scale_factor = 1))
for hand in hand_list:
hand.save_state()
hand.scale(0.01)
hand.move_to(part.get_right())
self.play(hand.restore)
self.dither()
self.dither()
self.play(*map(FadeOut, it.chain(*hand_lists)))
def place_high_bet(self):
you, her = self.you, self.her
pre_money = VGroup(*[
VGroup(*[
TexMobject("\\$")
for x in range(10)
]).arrange_submobjects(RIGHT, buff = SMALL_BUFF)
for y in range(4)
]).arrange_submobjects(UP, buff = SMALL_BUFF)
money = VGroup(*it.chain(*pre_money))
money.highlight(GREEN)
money.scale(0.8)
money.next_to(her.hand, DOWN)
for dollar in money:
dollar.save_state()
dollar.scale(0.01)
dollar.move_to(her.get_boundary_point(RIGHT))
dollar.set_fill(opacity = 0)
self.play(LaggedStart(
ApplyMethod,
money,
lambda m : (m.restore,),
run_time = 5,
))
self.play(you.change_mode, "confused")
self.dither()
self.money = money
def change_belief(self):
numbers = self.sample_space.horizontal_parts.labels
rect = Rectangle(stroke_width = 0)
rect.set_fill(BLACK, 1)
rect.stretch_to_fit_width(numbers.get_width())
rect.stretch_to_fit_height(self.sample_space.get_height())
rect.move_to(numbers, UP)
self.play(FadeIn(rect))
anims = self.get_horizontal_division_change_animations(0.2)
anims.append(Animation(rect))
self.play(
*anims,
run_time = 3,
rate_func = there_and_back
)
self.play(FadeOut(rect))
def move_community_cards_out_of_the_way(self):
cards = self.community_cards
cards.generate_target()
cards.target.arrange_submobjects(
RIGHT, buff = -cards[0].get_width() + MED_SMALL_BUFF,
)
cards.target.move_to(self.deck)
cards.target.to_edge(LEFT)
self.sample_space.add_braces_and_labels()
self.play(
self.deck.scale, 0.7,
self.deck.next_to, cards.target, UP,
self.deck.to_edge, LEFT,
self.sample_space.shift, 3*DOWN,
MoveToTarget(cards)
)
def name_bayes_rule(self):
title = TextMobject("Bayes' rule")
title.highlight(BLUE)
title.to_edge(UP)
subtitle = TextMobject("Update ", "prior ", "beliefs")
subtitle.scale(0.8)
subtitle.next_to(title, DOWN)
prior_word = subtitle.get_part_by_tex("prior")
numbers = self.sample_space.horizontal_parts.labels
rect = SurroundingRectangle(numbers, color = GREEN)
arrow = Arrow(prior_word.get_bottom(), rect.get_top())
arrow.highlight(GREEN)
words = TextMobject(
"Maybe she really \\\\ does have a flush $\\dots$",
alignment = ""
)
words.scale(0.7)
words.next_to(self.money, DOWN, aligned_edge = LEFT)
self.play(
Write(title, run_time = 2),
self.you.change_mode, "pondering"
)
self.dither()
self.play(FadeIn(subtitle))
self.play(prior_word.highlight, GREEN)
self.play(
ShowCreation(rect),
ShowCreation(arrow)
)
self.dither(3)
self.play(Write(words))
self.dither(3)
######
def create_pi_creatures(self):
shift_val = 3
you = PiCreature(color = BLUE_D)
her = PiCreature(color = BLUE_B).flip()
for pi in you, her:
pi.scale(0.5)
you.to_corner(UP+LEFT)
her.to_corner(UP+RIGHT)
you.make_eye_contact(her)
glasses = SunGlasses(her)
her.glasses = glasses
self.you = you
self.her = her
return VGroup(you, her)
def get_hand(self, pi_creature, keys = None):
if keys is not None:
hand = VGroup(*map(PlayingCard, keys))
else:
hand = VGroup(*[
PlayingCard(turned_over = True)
for x in range(2)
])
hand.scale(0.7)
card1, card2 = hand
vect = np.sign(pi_creature.get_center()[0])*LEFT
card2.move_to(card1)
card2.shift(MED_SMALL_BUFF*RIGHT + SMALL_BUFF*DOWN)
hand.next_to(
pi_creature, vect,
buff = MED_LARGE_BUFF,
aligned_edge = UP
)
return hand
class HowDoesPokerWork(TeacherStudentsScene):
def construct(self):
self.student_says(
"Wait, how does \\\\ poker work again?",
target_mode = "confused",
run_time = 1
)
self.change_student_modes(*["confused"]*3)
self.dither(2)
class YourGutKnowsBayesRule(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Your gut knows \\\\ Bayes' rule.",
run_time = 1
)
self.change_student_modes("confused", "gracious", "guilty")
self.dither(3)
class UpdatePokerPrior(SampleSpaceScene):
CONFIG = {
"double_heart_template" : "HH",
"cash_string" : "\\$\\$\\$",
}
def construct(self):
self.force_skipping()
self.add_sample_space()
self.add_top_conditionals()
self.react_to_top_conditionals()
self.add_bottom_conditionals()
# self.ask_where_conditionals_come_from()
# self.vary_conditionals()
self.show_restricted_space()
self.write_P_flush_given_bet()
self.reshape_rectangles()
self.compare_prior_to_posterior()
self.tweak_estimates()
self.compute_posterior()
def add_sample_space(self):
p = 1./22
sample_space = SampleSpace(fill_opacity = 0)
sample_space.shift(LEFT)
sample_space.divide_horizontally(p, colors = [
SuitSymbol.CONFIG["red"], BLUE_E
])
labels = self.get_prior_labels(p)
braces_and_labels = sample_space.get_side_braces_and_labels(labels)
self.play(
DrawBorderThenFill(sample_space),
Write(braces_and_labels)
)
self.dither()
sample_space.add(braces_and_labels)
self.sample_space = sample_space
def add_top_conditionals(self):
top_part = self.sample_space.horizontal_parts[0]
color = average_color(YELLOW, GREEN, GREEN)
p = 0.97
top_part.divide_vertically(p, colors = [color, BLUE])
label = self.get_conditional_label(p, True)
brace, _ignore = top_part.get_top_braces_and_labels([label])
explanation = TextMobject(
"Probability of", "high bet", "given", "flush"
)
explanation.highlight_by_tex("high bet", GREEN)
explanation.highlight_by_tex("flush", RED)
explanation.scale(0.6)
explanation.next_to(label, UP)
self.play(
FadeIn(top_part.vertical_parts),
Write(explanation, run_time = 3),
GrowFromCenter(brace),
)
self.play(LaggedStart(FadeIn, label, run_time = 2, lag_ratio = 0.7))
self.dither(2)
self.sample_space.add(brace, label)
self.top_explanation = explanation
self.top_conditional_rhs = label[-1]
def react_to_top_conditionals(self):
her = PiCreature(color = BLUE_B).flip()
her.next_to(self.sample_space, RIGHT)
her.to_edge(RIGHT)
glasses = SunGlasses(her)
glasses.save_state()
glasses.shift(UP)
glasses.set_fill(opacity = 0)
her.glasses = glasses
self.play(FadeIn(her))
self.play(glasses.restore)
self.play(
her.change_mode, "happy",
Animation(glasses)
)
self.dither(2)
self.her = her
def add_bottom_conditionals(self):
her = self.her
bottom_part = self.sample_space.horizontal_parts[1]
p = 0.3
bottom_part.divide_vertically(p, colors = [GREEN_E, BLUE_E])
label = self.get_conditional_label(p, False)
brace, _ignore = bottom_part.get_bottom_braces_and_labels([label])
explanation = TextMobject(
"Probability of", "high bet", "given", "no flush"
)
explanation.highlight_by_tex("high bet", GREEN)
explanation.highlight_by_tex("no flush", RED)
explanation.scale(0.6)
explanation.next_to(label, DOWN)
self.play(DrawBorderThenFill(bottom_part.vertical_parts))
self.play(GrowFromCenter(brace))
self.play(
her.change_mode, "shruggie",
MaintainPositionRelativeTo(her.glasses, her.eyes)
)
self.play(Write(explanation))
self.dither()
self.play(*[
ReplacementTransform(
VGroup(explanation[j].copy()),
VGroup(*label[i1:i2]),
run_time = 2,
rate_func = squish_rate_func(smooth, a, a+0.5)
)
for a, (i1, i2, j) in zip(np.linspace(0, 0.5, 4), [
(0, 1, 0),
(1, 2, 1),
(2, 3, 2),
(3, 6, 3),
])
])
self.play(Write(VGroup(*label[-2:])))
self.dither(2)
self.play(*map(FadeOut, [her, her.glasses]))
self.sample_space.add(brace, label)
self.bottom_explanation = explanation
self.bottom_conditional_rhs = label[-1]
def ask_where_conditionals_come_from(self):
randy = Randolph().flip()
randy.scale(0.75)
randy.to_edge(RIGHT)
randy.shift(2*DOWN)
words = TextMobject("Where do these \\\\", "numbers", "come from?")
numbers_word = words.get_part_by_tex("numbers")
numbers_word.highlight(YELLOW)
words.scale(0.7)
bubble = ThoughtBubble(height = 3, width = 4)
bubble.pin_to(randy)
bubble.shift(MED_LARGE_BUFF*RIGHT)
bubble.add_content(words)
numbers = VGroup(
self.top_conditional_rhs,
self.bottom_conditional_rhs
)
numbers.save_state()
arrows = VGroup(*[
Arrow(
numbers_word.get_left(),
num.get_right(),
buff = 2*SMALL_BUFF
)
for num in numbers
])
questions = VGroup(*map(TextMobject, [
"Does she bluff?",
"How much does she have?",
"Does she take risks?",
"What's her model of me?",
"\\vdots"
]))
questions.arrange_submobjects(DOWN, aligned_edge = LEFT)
questions[-1].next_to(questions[-2], DOWN)
questions.scale(0.7)
questions.next_to(randy, UP)
questions.shift_onto_screen()
self.play(
randy.change_mode, "confused",
ShowCreation(bubble),
Write(words, run_time = 2)
)
self.play(*map(ShowCreation, arrows))
self.play(numbers.highlight, YELLOW)
self.play(Blink(randy))
self.play(randy.change_mode, "maybe")
self.play(*map(FadeOut, [
bubble, words, arrows
]))
for question in questions:
self.play(
FadeIn(question),
randy.look_at, question
)
self.dither()
self.play(Blink(randy))
self.dither()
self.play(
randy.change_mode, "pondering",
FadeOut(questions)
)
self.randy = randy
def vary_conditionals(self):
randy = self.randy
rects = VGroup(*[
SurroundingRectangle(
VGroup(explanation),
buff = SMALL_BUFF,
)
for explanation, rhs in zip(
[self.top_explanation, self.bottom_explanation],
[self.top_conditional_rhs, self.bottom_conditional_rhs],
)
])
new_conditionals = [
(0.91, 0.4),
(0.83, 0.1),
(0.99, 0.2),
(0.97, 0.3),
]
self.play(*map(ShowCreation, rects))
self.play(FadeOut(rects))
for i, value in enumerate(it.chain(*new_conditionals)):
self.play(
randy.look_at, rects[i%2],
*self.get_conditional_change_anims(i%2, value)
)
if i%2 == 1:
self.dither()
self.play(FadeOut(randy))
def show_restricted_space(self):
high_bet_space, low_bet_space = [
VGroup(*[
self.sample_space.horizontal_parts[i].vertical_parts[j]
for i in range(2)
])
for j in range(2)
]
words = TexMobject("P(", self.cash_string, ")")
words.highlight_by_tex(self.cash_string, GREEN)
words.next_to(self.sample_space, RIGHT)
low_bet_space.generate_target()
for submob in low_bet_space.target:
submob.highlight(average_color(
submob.get_color(), *[BLACK]*4
))
arrows = VGroup(*[
Arrow(
words.get_left(),
submob.get_edge_center(vect),
color = submob.get_color()
)
for submob, vect in zip(high_bet_space, [DOWN, RIGHT])
])
self.play(MoveToTarget(low_bet_space))
self.play(
Write(words),
*map(ShowCreation, arrows)
)
self.dither()
for rect in high_bet_space:
self.play(Indicate(rect, scale_factor = 1))
self.play(*map(FadeOut, [words, arrows]))
self.high_bet_space = high_bet_space
def write_P_flush_given_bet(self):
posterior_tex = TexMobject(
"P(", self.double_heart_template,
"|", self.cash_string, ")"
)
posterior_tex.scale(0.7)
posterior_tex.highlight_by_tex(self.cash_string, GREEN)
self.insert_double_heart(posterior_tex)
rects = self.high_bet_space.copy()
rects = [rects[0].copy()] + list(rects)
for rect in rects:
rect.generate_target()
numerator = rects[0].target
plus = TexMobject("+")
denominator = VGroup(rects[1].target, plus, rects[2].target)
denominator.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
frac_line = TexMobject("\\over")
frac_line.stretch_to_fit_width(denominator.get_width())
fraction = VGroup(numerator, frac_line, denominator)
fraction.arrange_submobjects(DOWN)
arrow = TexMobject("\\downarrow")
group = VGroup(posterior_tex, arrow, fraction)
group.arrange_submobjects(DOWN)
group.to_corner(UP+RIGHT)
self.play(Write(posterior_tex))
self.play(Write(arrow))
self.play(MoveToTarget(rects[0]))
self.dither()
self.play(*it.chain(
map(Write, [frac_line, plus]),
map(MoveToTarget, rects[1:])
))
self.dither(3)
self.posterior_tex = posterior_tex
self.to_fade = VGroup(arrow, frac_line, plus)
self.to_post_rects = VGroup(VGroup(*rects[:2]),rects[2])
def reshape_rectangles(self):
post_rects = self.get_posterior_rectangles()
braces, labels = self.get_posterior_rectangle_braces_and_labels(
post_rects, [self.posterior_tex.copy()]
)
height_rect = SurroundingRectangle(braces)
self.play(
FadeOut(self.to_fade),
ReplacementTransform(
self.to_post_rects, post_rects,
run_time = 2,
),
)
self.dither(2)
self.play(ReplacementTransform(self.posterior_tex, labels[0]))
self.posterior_tex = labels[0]
self.play(GrowFromCenter(braces))
self.dither()
self.play(ShowCreation(height_rect))
self.play(FadeOut(height_rect))
self.dither()
self.post_rects = post_rects
def compare_prior_to_posterior(self):
prior_tex = self.sample_space.horizontal_parts.labels[0]
post_tex = self.posterior_tex
prior_rect, post_rect = [
SurroundingRectangle(tex, stroke_width = 2)
for tex in [prior_tex, post_tex]
]
post_words = TextMobject("Posterior", "probability")
post_words.scale(0.8)
post_words.to_corner(UP+RIGHT)
post_arrow = Arrow(
post_words[0].get_bottom(), post_tex.get_top(),
color = WHITE
)
self.play(ShowCreation(prior_rect))
self.dither()
self.play(ReplacementTransform(prior_rect, post_rect))
self.dither()
self.play(FadeOut(post_rect))
self.play(Indicate(post_tex.get_part_by_tex(self.cash_string)))
self.dither()
self.play(
Write(post_words),
ShowCreation(post_arrow)
)
self.dither()
self.play(post_words[1].fade, 0.8)
self.dither(2)
self.play(*map(FadeOut, [post_words, post_arrow]))
def tweak_estimates(self):
post_rects = self.post_rects
self.revert_to_original_skipping_status()
self.preview_tweaks(post_rects)
def preview_tweaks(self, post_rects):
new_value_lists = [
(0.85, 0.1, 0.11),
(0.97, 0.3, 1./22),
]
for new_values in new_value_lists:
for i, value in zip(range(2), new_values):
self.play(*self.get_conditional_change_anims(
i, value, post_rects
))
self.play(*self.get_prior_change_anims(
new_values[-1], post_rects
))
self.dither()
def compute_posterior(self):
pass
######
def get_prior_labels(self, value):
p_str = "%0.3f"%value
q_str = "%0.3f"%(1-value)
labels = [
TexMobject(
"P(", s, self.double_heart_template, ")",
"= ", num
)
for s, num in ("", p_str), ("\\text{not }", q_str)
]
for label in labels:
label.scale(0.7)
self.insert_double_heart(label)
return labels
def get_conditional_label(self, value, given_flush = True):
label = TexMobject(
"P(", self.cash_string, "|",
"" if given_flush else "\\text{not }",
self.double_heart_template, ")",
"=", str(value)
)
self.insert_double_heart(label)
label.highlight_by_tex(self.cash_string, GREEN)
label.scale(0.7)
return label
def insert_double_heart(self, tex_mob):
double_heart = SuitSymbol("hearts")
double_heart.add(SuitSymbol("hearts"))
double_heart.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
double_heart.get_tex_string = lambda : self.double_heart_template
template = tex_mob.get_part_by_tex(self.double_heart_template)
double_heart.replace(template)
tex_mob.submobjects[tex_mob.index_of_part(template)] = double_heart
return tex_mob
def get_prior_change_anims(self, value, post_rects = None):
space = self.sample_space
parts = space.horizontal_parts
anims = self.get_horizontal_division_change_animations(
value, new_label_kwargs = {
"labels" : self.get_prior_labels(value)
}
)
if post_rects is not None:
anims += self.get_posterior_rectangle_change_anims(post_rects)
return anims
def get_conditional_change_anims(
self, sub_sample_space_index, value,
post_rects = None
):
parts = self.sample_space.horizontal_parts
sub_sample_space = parts[sub_sample_space_index]
given_flush = (sub_sample_space_index == 0)
label = self.get_conditional_label(value, given_flush)
anims = self.get_division_change_animations(
sub_sample_space, sub_sample_space.vertical_parts, value,
dimension = 0,
new_label_kwargs = {"labels" : [label]},
)
if post_rects is not None:
anims += self.get_posterior_rectangle_change_anims(post_rects)
return anims
def get_top_conditional_change_anims(self, *args, **kwargs):
return self.get_conditional_change_anims(0, *args, **kwargs)
def get_bottom_conditional_change_anims(self, *args, **kwargs):
return self.get_conditional_change_anims(1, *args, **kwargs)
def get_prior_rectangles(self):
return VGroup(*[
self.sample_space.horizontal_parts[i].vertical_parts[0]
for i in range(2)
])
def get_posterior_rectangles(self):
prior_rects = self.get_prior_rectangles()
areas = [
rect.get_width()*rect.get_height()
for rect in prior_rects
]
total_area = sum(areas)
total_height = prior_rects.get_height()
post_rects = prior_rects.copy()
for rect, area in zip(post_rects, areas):
rect.stretch_to_fit_height(total_height * area/total_area)
rect.stretch_to_fit_width(
area/rect.get_height()
)
post_rects.arrange_submobjects(DOWN, buff = 0)
post_rects.next_to(
self.sample_space.full_space, RIGHT, MED_LARGE_BUFF
)
return post_rects
def get_posterior_rectangle_braces_and_labels(self, post_rects, labels):
braces = VGroup()
label_mobs = VGroup()
for label, rect in zip(labels, post_rects):
if not isinstance(label, Mobject):
label_mob = TexMobject(label)
label_mob.scale(0.7)
else:
label_mob = label
brace = Brace(
rect, RIGHT,
buff = SMALL_BUFF,
min_num_quads = 2
)
label_mob.next_to(brace, RIGHT, SMALL_BUFF)
label_mobs.add(label_mob)
braces.add(brace)
post_rects.braces = braces
post_rects.labels = label_mobs
return VGroup(braces, label_mobs)
def update_posterior_braces(self, post_rects):
braces = post_rects.braces
labels = post_rects.labels
for rect, brace, label in zip(post_rects, braces, labels):
brace.stretch_to_fit_height(rect.get_height())
brace.next_to(rect, RIGHT, SMALL_BUFF)
label.next_to(brace, RIGHT, SMALL_BUFF)
def get_posterior_rectangle_change_anims(self, post_rects):
def update_rects(rects):
new_rects = self.get_posterior_rectangles()
Transform(rects, new_rects).update(1)
if hasattr(rects, "braces"):
self.update_posterior_braces(rects)
return rects
anims = [UpdateFromFunc(post_rects, update_rects)]
if hasattr(post_rects, "braces"):
anims += map(Animation, [
post_rects.labels, post_rects.braces
])
return anims
class NextVideoWrapper(TeacherStudentsScene):
def construct(self):
title = TextMobject("Next video: Bayesian networks")
title.scale(0.8)
title.to_edge(UP, buff = SMALL_BUFF)
screen = ScreenRectangle(height = 4)
screen.next_to(title, DOWN)
title.save_state()
title.shift(DOWN)
title.set_fill(opacity = 0)
self.play(
title.restore,
self.teacher.change, "raise_right_hand"
)
self.play(ShowCreation(screen))
self.change_student_modes(*["pondering"]*3)
self.play(Animation(screen))
self.dither(5)