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.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.preview_tweaks() self.tweak_non_flush_case() self.tweak_flush_case() self.tweak_prior() 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( LaggedStart(FadeIn, 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), FadeIn(label), GrowFromCenter(brace), ) self.play(Write(explanation, run_time = 3)) 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), FadeIn(label) ) self.play( her.change_mode, "shruggie", MaintainPositionRelativeTo(her.glasses, her.eyes) ) self.dither() self.play(*[ ReplacementTransform( VGroup(*label[i1:i2]).copy(), VGroup(explanation[j]), 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.dither() 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(LaggedStart(FadeIn, 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.play(*map(FadeOut, [arrow, fraction] + rects)) self.posterior_tex = posterior_tex def reshape_rectangles(self): post_rects = self.get_posterior_rectangles() prior_rects = self.get_prior_rectangles() braces, labels = self.get_posterior_rectangle_braces_and_labels( post_rects, [self.posterior_tex.copy()] ) height_rect = SurroundingRectangle(braces) self.play( ReplacementTransform( prior_rects.copy(), 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 preview_tweaks(self): post_rects = 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(2) def tweak_non_flush_case(self): her = self.her her.scale_in_place(0.7) her.change_mode("plain") her.shift(DOWN) her.glasses = SunGlasses(her) post_rects = self.post_rects risk_averse_words = TextMobject( "Suppose risk \\\\ averse \\dots" ) risk_averse_words.scale(0.7) risk_averse_words.next_to(her, DOWN) risk_averse_words.shift_onto_screen() arrows = VGroup(*[ Arrow(ORIGIN, LEFT, tip_length = SMALL_BUFF) for x in range(3) ]) arrows.arrange_submobjects(DOWN) arrows.next_to(post_rects[1], RIGHT, SMALL_BUFF) self.dither(2) self.play(*map(FadeIn, [her, her.glasses])) self.play(LaggedStart(FadeIn, risk_averse_words)) self.play(her.change_mode, "sad", Animation(her.glasses)) self.dither() self.play(ShowCreation(arrows)) self.play( *self.get_conditional_change_anims(1, 0.1, post_rects), run_time = 3 ) self.play(FadeOut(arrows)) self.dither(3) self.play( FadeOut(risk_averse_words), *self.get_conditional_change_anims(1, 0.3, post_rects), run_time = 2 ) def tweak_flush_case(self): her = self.her post_rects = self.post_rects self.play( her.change_mode, "erm", Animation(her.glasses) ) self.play( *self.get_conditional_change_anims(0, 0.47, post_rects), run_time = 3 ) self.dither(3) self.play(*self.get_conditional_change_anims( 0, 0.97, post_rects )) self.dither() def tweak_prior(self): her = self.her post_rects = self.post_rects self.play( her.change_mode, "happy", Animation(her.glasses) ) self.play( *self.get_prior_change_anims(0.3, post_rects), run_time = 2 ) self.dither(3) self.play( *self.get_prior_change_anims(1./22, post_rects), run_time = 2 ) self.play(*map(FadeOut, [her, her.glasses])) def compute_posterior(self): prior_rects = self.get_prior_rectangles() post_tex = self.posterior_tex prior_rhs_group = self.get_prior_rhs_group() fraction = TexMobject( "{(0.045)", "(0.97)", "\\over", "(0.995)", "(0.3)", "+", "(0.045)", "(0.97)}" ) products = [ VGroup(*[ fraction.get_parts_by_tex(tex)[i] for tex in tex_list ]) for i, tex_list in [ (0, ["0.045", "0.97"]), (0, ["0.995", "0.3"]), (1, ["0.045", "0.97"]), ] ] for i in 0, 2: products[i].highlight(prior_rects[0].get_color()) products[1].highlight(prior_rects[1].get_color()) fraction.scale(0.65) fraction.to_corner(UP+RIGHT, buff = MED_SMALL_BUFF) arrow_kwargs = { "color" : WHITE, "tip_length" : 0.15, } rhs = TexMobject("\\approx", "0.13") rhs.scale(0.8) rhs.next_to(post_tex, RIGHT) to_rhs_arrow = Arrow( fraction.get_bottom(), rhs.get_top(), **arrow_kwargs ) pre_top_rect_products = VGroup( prior_rhs_group[0], self.top_conditional_rhs ) pre_bottom_rect_products = VGroup( prior_rhs_group[1], self.bottom_conditional_rhs ) self.play(Indicate(prior_rects[0], scale_factor = 1)) self.play(*[ ReplacementTransform( mob.copy(), term, run_time = 2, ) for mob, term in zip( pre_top_rect_products, products[0] ) ]) self.play(Write(fraction.get_part_by_tex("over"))) for pair in zip(pre_top_rect_products, products[0]): self.play(*map(Indicate, pair)) self.dither() self.dither() self.play(Indicate(prior_rects[1], scale_factor = 1)) self.play(*[ ReplacementTransform( mob.copy(), term, run_time = 2, ) for mob, term in zip( pre_bottom_rect_products, products[1] ) ]) self.dither() for pair in zip(pre_bottom_rect_products, products[1]): self.play(*map(Indicate, pair)) self.dither() self.play( Write(fraction.get_part_by_tex("+")), ReplacementTransform(products[0].copy(), products[2]) ) self.dither() self.play(ShowCreation(to_rhs_arrow)) self.play(Write(rhs)) self.dither(3) ###### 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_prior_rhs_group(self): labels = self.sample_space.horizontal_parts.labels return VGroup(*[label[-1] for label in 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 ): given_flush = (sub_sample_space_index == 0) label = self.get_conditional_label(value, given_flush) return SampleSpaceScene.get_conditional_change_anims( self, sub_sample_space_index, value, post_rects, new_label_kwargs = {"labels" : [label]}, ) class BayesRuleInMemory(Scene): def construct(self): randy = Randolph() randy.to_corner(DOWN+LEFT) bubble = ThoughtBubble(height = 4) bubble.pin_to(randy) B = "\\text{Belief}" D = "\\text{Data}" rule = TexMobject( "P(", B, "|", D, ")", "=", "P(", "B", ")", "{P(", D, "|", B, ")", "\\over", "P(", D, ")}" ) rule.highlight_by_tex(B, RED) rule.highlight_by_tex(D, GREEN) rule.next_to(randy, RIGHT, LARGE_BUFF, UP) rule.generate_target() bubble.add_content(rule.target) screen_rect = ScreenRectangle() screen_rect.next_to(randy, UP+RIGHT) self.add(randy) self.play( LaggedStart(FadeIn, rule), randy.change, "erm", rule ) self.play(Blink(randy)) self.play( ShowCreation(bubble), MoveToTarget(rule), randy.change, "pondering", ) self.dither() self.play(rule.fade, 0.7, run_time = 2) self.play(randy.change, "confused", rule) self.play(Blink(randy)) self.dither(2) self.play( FadeOut(VGroup(bubble, rule)), randy.change, "pondering", screen_rect, ) self.play( randy.look_at, screen_rect.get_right(), ShowCreation(screen_rect), ) self.dither(4) class NextVideoWrapper(TeacherStudentsScene): CONFIG = { "title" : "Next chapter: Bayesian networks" } def construct(self): title = TextMobject(self.title) 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, look_at_arg = screen ) self.play(Animation(screen)) self.dither(5) class GeneralizeBayesRule(SampleSpaceScene): def construct(self): self.add_sample_space() self.add_title() self.add_posterior_rectangles() self.add_bayes_rule() self.talk_through_terms() self.name_likelihood() self.dont_memorize() self.show_space_restriction() def add_sample_space(self): sample_space = SampleSpace( full_space_config = { "height" : 3, "width" : 3, "fill_opacity" : 0 } ) sample_space.divide_horizontally(0.4) sample_space.horizontal_parts.set_fill(opacity = 0) labels = [ TexMobject("P(", "B", ")"), TexMobject("P(\\text{not }", "B", ")"), ] for label in labels: label.scale(0.7) self.color_label(label) sample_space.get_side_braces_and_labels(labels) sample_space.add_braces_and_labels() parts = sample_space.horizontal_parts values = [0.8, 0.4] given_strs = ["", "\\text{not }"] color_pairs = [(GREEN, BLUE), (GREEN_E, BLUE_E)] vects = [UP, DOWN] for tup in zip(parts, values, given_strs, color_pairs, vects): part, value, given_str, colors, vect = tup part.divide_vertically(value, colors = colors) part.vertical_parts.set_fill(opacity = 0.8) label = TexMobject( "P(", "I", "|", given_str, "B", ")" ) label.scale(0.7) self.color_label(label) part.get_subdivision_braces_and_labels( part.vertical_parts, [label], vect ) sample_space.add( part.vertical_parts.braces, part.vertical_parts.labels, ) sample_space.to_edge(LEFT) self.add(sample_space) self.sample_space = sample_space def add_title(self): title = TextMobject( "Updating", "Beliefs", "from new", "Information" ) self.color_label(title) title.scale(0.8) title.to_corner(UP+LEFT) self.add(title) def add_posterior_rectangles(self): prior_rects = self.get_prior_rectangles() post_rects = self.get_posterior_rectangles() label = TexMobject("P(", "B", "|", "I", ")") label.scale(0.7) self.color_label(label) braces, labels = self.get_posterior_rectangle_braces_and_labels( post_rects, [label] ) self.play(ReplacementTransform( prior_rects.copy(), post_rects, run_time = 2 )) self.play( GrowFromCenter(braces), Write(label) ) self.post_rects = post_rects self.posterior_tex = label def add_bayes_rule(self): rule = TexMobject( "=", "{P(", "B", ")", "P(", "I", "|", "B", ")", "\\over", "P(", "I", ")}", ) self.color_label(rule) rule.scale(0.7) rule.next_to(self.posterior_tex, RIGHT) bayes_rule_words = TextMobject("Bayes' rule") bayes_rule_words.next_to(VGroup(*rule[1:]), UP, LARGE_BUFF) bayes_rule_words.shift_onto_screen() self.play(FadeIn(rule)) self.play(Write(bayes_rule_words)) self.dither(2) self.bayes_rule_words = bayes_rule_words self.bayes_rule = rule def talk_through_terms(self): prior = self.sample_space.horizontal_parts.labels[0] posterior = self.posterior_tex prior_target = VGroup(*self.bayes_rule[1:4]) likelihood = VGroup(*self.bayes_rule[4:9]) P_I = VGroup(*self.bayes_rule[-3:]) prior_word = TextMobject("Prior") posterior_word = TextMobject("Posterior") words = [prior_word, posterior_word] for word in words: word.highlight(YELLOW) word.scale(0.7) prior_rect = SurroundingRectangle(prior) posterior_rect = SurroundingRectangle(posterior) for rect in prior_rect, posterior_rect: rect.set_stroke(YELLOW, 2) prior_word.next_to(prior, UP, LARGE_BUFF) posterior_word.next_to(posterior, DOWN, LARGE_BUFF) for word in words: word.shift_onto_screen() prior_arrow = Arrow( prior_word.get_bottom(), prior.get_top(), tip_length = 0.15 ) posterior_arrow = Arrow( posterior_word.get_top(), posterior.get_bottom(), tip_length = 0.15 ) self.play( Write(prior_word), ShowCreation(prior_arrow), ShowCreation(prior_rect), ) self.dither() self.play(Transform( prior.copy(), prior_target, run_time = 2, path_arc = -np.pi/3, remover = True, )) self.dither() parts = self.sample_space[0].vertical_parts self.play( Indicate(likelihood), Indicate(parts.labels), Indicate(parts.braces), ) self.dither() self.play(Indicate(P_I)) self.play(FocusOn(self.sample_space[0][0])) for i in range(2): self.play(Indicate( self.sample_space[i][0], scale_factor = 1 )) self.dither() self.play( Write(posterior_word), ShowCreation(posterior_arrow), ShowCreation(posterior_rect), ) self.prior_label = VGroup(prior_word, prior_arrow, prior_rect) self.posterior_label = VGroup(posterior_word, posterior_arrow, posterior_rect) self.likelihood = likelihood def name_likelihood(self): likelihoods = [ self.sample_space[0].vertical_parts.labels[0], self.likelihood ] rects = [ SurroundingRectangle(mob, buff = SMALL_BUFF) for mob in likelihoods ] name = TextMobject("Likelihood") name.scale(0.7) name.next_to(self.posterior_tex, UP, 1.5*LARGE_BUFF) arrows = [ Arrow( name, rect.get_edge_center(vect), tip_length = 0.15 ) for rect, vect in zip(rects, [RIGHT, UP]) ] VGroup(name, *arrows+rects).highlight(YELLOW) morty = Mortimer() morty.scale(0.5) morty.next_to(rects[1], UP, buff = 0) morty.shift(SMALL_BUFF*RIGHT) self.play( self.bayes_rule_words.to_edge, UP, Write(name), *map(ShowCreation, arrows+rects) ) self.dither() self.play(FadeIn(morty)) self.play(morty.change, "confused", name) self.play(Blink(morty)) self.play(morty.look, DOWN) self.dither() self.play(morty.look_at, name) self.play(Blink(morty)) self.play(morty.change, "shruggie") self.play(FadeOut(VGroup(name, *arrows+rects))) self.play(FadeOut(morty)) self.play(FadeOut(self.posterior_label)) self.play(FadeOut(self.prior_label)) def dont_memorize(self): rule = VGroup(*self.bayes_rule[1:]) word = TextMobject("Memorize") word.scale(0.7) word.next_to(rule, DOWN) cross = VGroup( Line(UP+LEFT, DOWN+RIGHT), Line(UP+RIGHT, DOWN+LEFT), ) cross.set_stroke(RED, 6) cross.replace(word, stretch = True) self.play(Write(word)) self.dither() self.play(ShowCreation(cross)) self.dither() self.play(FadeOut(VGroup(cross, word))) self.play(FadeOut(self.bayes_rule)) self.play( FadeOut(self.post_rects), FadeOut(self.post_rects.braces), FadeOut(self.post_rects.labels), ) def show_space_restriction(self): prior_rects = self.get_prior_rectangles() non_I_rects = VGroup(*[ self.sample_space[i][1] for i in range(2) ]) post_rects = self.post_rects self.play(non_I_rects.fade, 0.8) self.play(LaggedStart( ApplyMethod, prior_rects, lambda m : (m.highlight, YELLOW), rate_func = there_and_back, lag_ratio = 0.7 )) self.dither(2) self.play(ReplacementTransform( prior_rects.copy(), post_rects, run_time = 2 )) self.play(*map(FadeIn, [ post_rects.braces, post_rects.labels ])) self.dither() self.play(*self.get_conditional_change_anims(1, 0.2, post_rects)) self.play(*self.get_conditional_change_anims(0, 0.6, post_rects)) self.dither() self.play(*it.chain( self.get_division_change_animations( self.sample_space, self.sample_space.horizontal_parts, 0.1 ), self.get_posterior_rectangle_change_anims(post_rects) )) self.dither(3) #### def color_label(self, label): label.highlight_by_tex("B", RED) label.highlight_by_tex("I", GREEN) class MoreExamples(TeacherStudentsScene): def construct(self): self.teacher_says("More examples!", target_mode = "hooray") self.change_student_modes(*["hooray"]*3) self.dither(2) class MusicExample(SampleSpaceScene, PiCreatureScene): def construct(self): self.introduce_musician() self.add_prior() self.record_track() self.add_bottom_conditionl() self.friend_gives_compliment() self.friends_dont_like() self.false_compliment() self.add_top_conditionl() self.get_positive_review() self.restrict_space() self.show_posterior_rectangles() self.show_prior_rectangle_areas() self.show_posterior_probability() self.intuition_of_positive_feedback() self.make_friends_honest() self.fade_out_post_rect() self.get_negative_feedback() self.compare_prior_to_post_given_negative() self.intuition_of_negative_feedback() def introduce_musician(self): randy = self.pi_creature randy.change_mode("soulful_musician") randy.arms = randy.get_arm_copies() guitar = randy.guitar = Guitar() guitar.move_to(randy) guitar.shift(0.31*RIGHT + 0.6*UP) randy.change_mode("plain") self.play( randy.change_mode, "soulful_musician", path_arc = np.pi/6, ) self.play( Animation(randy), DrawBorderThenFill(guitar), Animation(randy.arms) ) randy.add(guitar, randy.arms) self.dither() self.play_notes(guitar) self.change_pi_creature_with_guitar("concerned_musician") self.dither(2) self.play( randy.scale, 0.7, randy.to_corner, UP+LEFT, ) self.play_notes(guitar) def add_prior(self): sample_space = SampleSpace() sample_space.shift(DOWN) sample_space.divide_horizontally(0.8, colors = [MAROON_D, BLUE_E]) labels = VGroup( TexMobject("P(S) = ", "0.8"), TexMobject("P(\\text{not } S) = ", "0.2"), ) labels.scale(0.7) braces, labels = sample_space.get_side_braces_and_labels(labels) VGroup(sample_space, braces, labels).to_edge(LEFT) words = map(TextMobject, [ "Blunt honesty", "Some confidence" ]) for word, part in zip(words, sample_space.horizontal_parts): word.scale(0.6) word.move_to(part) self.play(LaggedStart(FadeIn, sample_space, run_time = 1)) self.play(*map(GrowFromCenter, braces)) for label in labels: self.play(Write(label, run_time = 2)) self.dither() for word, mode in zip(words, ["maybe", "soulful_musician"]): self.play(LaggedStart(FadeIn, word, run_time = 1)) self.change_pi_creature_with_guitar(mode) self.dither() self.dither() self.play(*map(FadeOut, words)) self.sample_space = sample_space def record_track(self): randy = self.pi_creature friends = VGroup(*[ PiCreature(mode = "happy", color = color).flip() for color in BLUE_B, GREY_BROWN, MAROON_E ]) friends.scale(0.6) friends.arrange_submobjects(RIGHT) friends.next_to(randy, RIGHT, LARGE_BUFF, DOWN) friends.to_edge(RIGHT) for friend in friends: friend.look_at(randy.eyes) headphones = VGroup(*map(Headphones, friends)) self.play(FadeIn(friends)) self.pi_creatures.add(*friends) self.play( FadeIn(headphones), Animation(friends) ) self.play_notes(randy.guitar) self.play(LaggedStart( ApplyMethod, friends, lambda pi : (pi.change, "hooray"), run_time = 2, )) self.friends = friends self.headphones = headphones def add_bottom_conditionl(self): p = 0.99 bottom_part = self.sample_space[1] bottom_part.divide_vertically(p, colors = [GREEN_E, YELLOW]) label = self.get_conditional_label(p, False) braces, labels = bottom_part.get_bottom_braces_and_labels([label]) brace = braces[0] self.play(FadeIn(bottom_part.vertical_parts)) self.play(GrowFromCenter(brace)) self.play(Write(label)) self.dither() def friend_gives_compliment(self): friends = self.friends bubble = SpeechBubble( height = 1.25, width = 3, direction = RIGHT, fill_opacity = 0, ) content = TextMobject("Phenomenal!") content.scale(0.75) bubble.add_content(content) VGroup(bubble, content).next_to(friends, LEFT, SMALL_BUFF) VGroup(bubble, content).to_edge(UP, SMALL_BUFF) self.play(LaggedStart( ApplyMethod, friends, lambda pi : (pi.change_mode, "conniving") )) self.dither() self.play( ShowCreation(bubble), Write(bubble.content, run_time = 1), ApplyMethod(friends[0].change_mode, "hooray"), LaggedStart( ApplyMethod, VGroup(*friends[1:]), lambda pi : (pi.change_mode, "happy") ), ) self.dither(2) self.play(*map(FadeOut, [bubble, content])) def friends_dont_like(self): friends = self.friends pi1, pi2, pi3 = friends for friend in friends: friend.generate_target() pi1.target.change("guilty", pi2.eyes) pi2.target.change("hesitant", pi1.eyes) pi3.target.change("pondering", pi2.eyes) self.play(LaggedStart( MoveToTarget, friends )) self.change_pi_creature_with_guitar("concerned_musician") self.dither() def false_compliment(self): friend = self.friends[0] bubble = SpeechBubble( height = 1.25, width = 4.5, direction = RIGHT, fill_opacity = 0, ) content = TextMobject("The beat was consistent.") content.scale(0.75) bubble.add_content(content) VGroup(bubble, content).next_to(friend, LEFT, SMALL_BUFF) VGroup(bubble, content).to_edge(UP, SMALL_BUFF) self.play( friend.change_mode, "maybe", ShowCreation(bubble), Write(content) ) self.change_pi_creature_with_guitar("happy") self.dither() self.play(*map(FadeOut, [bubble, content])) self.bubble = bubble def add_top_conditionl(self): p = 0.9 top_part = self.sample_space[0] top_part.divide_vertically(p, colors = [TEAL_E, RED_E]) label = self.get_conditional_label(p, True) braces, labels = top_part.get_top_braces_and_labels([label]) brace = braces[0] self.play(FadeIn(top_part.vertical_parts)) self.play(GrowFromCenter(brace)) self.play(Write(label, run_time = 2)) self.dither() def get_positive_review(self): friends = self.friends self.change_pi_creature_with_guitar( "soulful_musician", LaggedStart( ApplyMethod, friends, lambda pi : (pi.change, "happy"), run_time = 1, ) ) self.play_notes(self.pi_creature.guitar) def restrict_space(self): positive_space, negative_space = [ VGroup(*[ self.sample_space[i][j] for i in range(2) ]) for j in range(2) ] negative_space.save_state() self.play(negative_space.fade, 0.8) self.play(LaggedStart( ApplyMethod, positive_space, lambda m : (m.highlight, YELLOW), rate_func = there_and_back, run_time = 2, lag_ratio = 0.7, )) self.dither() self.negative_space = negative_space def show_posterior_rectangles(self): prior_rects = self.get_prior_rectangles() post_rects = self.get_posterior_rectangles() label = TexMobject("P(S | ", "\\checkmark", ")") label.scale(0.7) label.highlight_by_tex("\\checkmark", GREEN) braces, labels = self.get_posterior_rectangle_braces_and_labels( post_rects, [label] ) brace = braces[0] self.play(ReplacementTransform( prior_rects.copy(), post_rects, run_time = 2 )) self.play(GrowFromCenter(brace)) self.play(Write(label)) self.dither() self.post_rects = post_rects self.post_tex = label def show_prior_rectangle_areas(self): prior_rects = self.get_prior_rectangles() products = VGroup( TexMobject("(", "0.8", ")(", "0.9", ")"), TexMobject("(", "0.2", ")(", "0.99", ")"), ) top_product, bottom_product = products for product, rect in zip(products, prior_rects): product.scale(0.7) product.move_to(rect) side_labels = self.sample_space.horizontal_parts.labels top_labels = self.sample_space[0].vertical_parts.labels bottom_labels = self.sample_space[1].vertical_parts.labels self.play( ReplacementTransform( side_labels[0][-1].copy(), top_product[1], ), ReplacementTransform( top_labels[0][-1].copy(), top_product[3], ), Write(VGroup(*top_product[::2])) ) self.dither(2) self.play( ReplacementTransform( side_labels[1][-1].copy(), bottom_product[1], ), ReplacementTransform( bottom_labels[0][-1].copy(), bottom_product[3], ), Write(VGroup(*bottom_product[::2])) ) self.dither(2) self.products = products def show_posterior_probability(self): post_tex = self.post_tex rhs = TexMobject("\\approx", "0.78") rhs.scale(0.7) rhs.next_to(post_tex, RIGHT) ratio = TexMobject( "{(0.8)(0.9)", "\\over", "(0.8)(0.9)", "+", "(0.2)(0.99)}" ) ratio.scale(0.6) ratio.next_to(VGroup(post_tex, rhs), DOWN, LARGE_BUFF) ratio.to_edge(RIGHT) arrow_kwargs = { "tip_length" : 0.15, "color" : WHITE, "buff" : 2*SMALL_BUFF, } to_ratio_arrow = Arrow( post_tex.get_bottom(), ratio.get_top(), **arrow_kwargs ) to_rhs_arrow = Arrow( ratio.get_top(), rhs[1].get_bottom(), **arrow_kwargs ) self.play( ShowCreation(to_ratio_arrow), FadeIn(ratio) ) self.dither() self.play(ShowCreation(to_rhs_arrow)) self.play(Write(rhs, run_time = 1)) self.dither(2) self.post_rhs = rhs self.ratio_group = VGroup(ratio, to_ratio_arrow, to_rhs_arrow) def intuition_of_positive_feedback(self): friends = self.friends prior_num = self.sample_space.horizontal_parts.labels[0][-1] post_num = self.post_rhs[-1] prior_rect = SurroundingRectangle(prior_num) post_rect = SurroundingRectangle(post_num) dot = Dot(prior_rect.get_center()) dot.set_fill(WHITE, 0.5) self.play(ShowCreation(prior_rect)) self.play( dot.move_to, post_rect, dot.set_fill, None, 0, path_arc = -np.pi/6, run_time = 2, ) self.play(ShowCreation(post_rect)) self.dither(2) for mode, time in ("shruggie", 2), ("hesitant", 0): self.play(LaggedStart( ApplyMethod, friends, lambda pi : (pi.change, mode), run_time = 2, )) self.dither(time) self.play(*map(FadeOut, [ prior_rect, post_rect, self.ratio_group, self.post_rhs ])) self.prior_num_rect = prior_rect def make_friends_honest(self): post_rects = self.post_rects self.play(FadeOut(self.products)) for value in 0.5, 0.1, 0.9: label = self.get_conditional_label(value) self.play(*self.get_top_conditional_change_anims( value, post_rects, new_label_kwargs = {"labels" : [label]}, ), run_time = 2) self.dither(2) def fade_out_post_rect(self): self.play(*map(FadeOut, [ self.post_rects, self.post_rects.braces, self.post_rects.labels, ])) self.play(self.negative_space.restore) def get_negative_feedback(self): friends = self.friends old_prior_rects = self.get_prior_rectangles() for part in self.sample_space.horizontal_parts: part.vertical_parts.submobjects.reverse() new_prior_rects = self.get_prior_rectangles() post_rects = self.get_posterior_rectangles() label = TexMobject( "P(S | \\text{not } ", "\\checkmark", ")", "\\approx", "0.98" ) label.scale(0.7) label.highlight_by_tex("\\checkmark", GREEN) braces, labels = self.get_posterior_rectangle_braces_and_labels( post_rects, [label] ) brace = braces[0] self.play(old_prior_rects.fade, 0.8) self.play(LaggedStart( ApplyMethod, friends, lambda pi : (pi.change, "pondering", post_rects), run_time = 1 )) self.dither() self.play(ReplacementTransform( new_prior_rects.copy(), post_rects, run_time = 2 )) self.play(GrowFromCenter(brace)) self.dither(2) self.play(Write(label)) self.dither(3) self.post_rects = post_rects def compare_prior_to_post_given_negative(self): post_num = self.post_rects.labels[0][-1] post_num_rect = SurroundingRectangle(post_num) self.play(ShowCreation(self.prior_num_rect)) self.dither() self.play(ShowCreation(post_num_rect)) self.dither() self.post_num_rect = post_num_rect def intuition_of_negative_feedback(self): friends = self.friends randy = self.pi_creature bubble = self.bubble modes = ["sassy", "pleading", "horrified"] for friend, mode in zip(friends, modes): friend.generate_target() friend.target.change(mode, randy.eyes) content = TextMobject("Horrible. Just horrible.") content.scale(0.6) bubble.add_content(content) self.play(*map(MoveToTarget, friends)) self.play( ShowCreation(bubble), Write(bubble.content) ) self.change_pi_creature_with_guitar("sad") self.dither() self.change_pi_creature_with_guitar("concerned_musician") self.dither(3) ###### def create_pi_creature(self): randy = Randolph() randy.left_arm_range = [.36, .45] self.randy = randy return randy def get_conditional_label(self, value, given_suck = True): positive_str = "\\checkmark" label = TexMobject( "P(", positive_str, "|", "" if given_suck else "\\text{not }", "S", ")", "=", str(value) ) label.highlight_by_tex(positive_str, GREEN) label.scale(0.7) return label def change_pi_creature_with_guitar(self, target_mode, *added_anims): randy = self.pi_creature randy.remove(randy.arms, randy.guitar) target = randy.copy() target.change_mode(target_mode) target.arms = target.get_arm_copies() target.guitar = randy.guitar.copy() for pi in randy, target: pi.add(pi.guitar, pi.arms) self.play(Transform(randy, target), *added_anims) def play_notes(self, guitar): note = SVGMobject(file_name = "8th_note") note.scale_to_fit_height(0.5) note.set_stroke(width = 0) note.set_fill(BLUE, 1) note.move_to(guitar) note.shift(MED_SMALL_BUFF*(DOWN+2*LEFT)) notes = VGroup(*[note.copy() for x in range(10)]) sine_wave = FunctionGraph(np.sin, x_min = -5, x_max = 5) sine_wave.scale(0.75) sine_wave.rotate(np.pi/6) sine_wave.shift( notes.get_center() - \ sine_wave.point_from_proportion(0) ) self.play(LaggedStart( MoveAlongPath, notes, lambda n : (n, sine_wave), path_arc = np.pi/2, run_time = 4, lag_ratio = 0.5, rate_func = lambda t : t, )) class FinalWordsOnRule(SampleSpaceScene): def construct(self): self.add_sample_space() self.add_uses() self.tweak_values() def add_sample_space(self): sample_space = self.sample_space = SampleSpace() prior = 0.2 top_conditional = 0.8 bottom_condional = 0.3 sample_space.divide_horizontally(prior) sample_space[0].divide_vertically( top_conditional, colors = [GREEN, RED] ) sample_space[1].divide_vertically( bottom_condional, colors = [GREEN_E, RED_E] ) B = "\\text{Belief}" D = "\\text{Data}" P_B = TexMobject("P(", B, ")") P_D_given_B = TexMobject("P(", D, "|", B, ")") P_D_given_not_B = TexMobject( "P(", D, "|", "\\text{not }", B, ")" ) P_B_given_D = TexMobject("P(", B, "|", D, ")") labels = VGroup(P_B, P_D_given_B, P_D_given_not_B, P_B_given_D) for label in labels: label.scale(0.7) label.highlight_by_tex(B, BLUE) label.highlight_by_tex(D, GREEN) prior_rects = self.get_prior_rectangles() post_rects = self.get_posterior_rectangles() for i in range(2): sample_space[i][1].fade(0.7) braces = VGroup() bs, ls = sample_space.get_side_braces_and_labels([P_B]) braces.add(*bs) bs, ls = sample_space[0].get_top_braces_and_labels([P_D_given_B]) braces.add(*bs) bs, ls = sample_space[1].get_bottom_braces_and_labels([P_D_given_not_B]) braces.add(*bs) bs, ls = self.get_posterior_rectangle_braces_and_labels( post_rects, [P_B_given_D] ) braces.add(*bs) group = VGroup(sample_space, braces, labels, post_rects) group.to_corner(DOWN + LEFT) self.add(group) self.post_rects = post_rects def add_uses(self): uses = TextMobject( "Machine learning, ", "scientific inference, $\\dots$", ) uses.to_edge(UP) for use in uses: self.play(Write(use, run_time = 2)) self.dither() def tweak_values(self): post_rects = self.post_rects new_value_lists = [ (0.85, 0.1, 0.11), (0.3, 0.9, 0.4), (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.dither() self.play(*it.chain( self.get_horizontal_division_change_animations(new_values[-1]), self.get_posterior_rectangle_change_anims(post_rects) )) self.dither() self.dither(2) class FootnoteWrapper(NextVideoWrapper): CONFIG = { "title" : "Thoughts on the classic Bayes example" }