from manimlib.imports import * from from_3b1b.active.bayes.beta_helpers import * from from_3b1b.active.bayes.beta1 import * import scipy.stats OUTPUT_DIRECTORY = "bayes/beta2" class WeightedCoin(Scene): def construct(self): # Coin grid bools = 50 * [True] + 50 * [False] random.shuffle(bools) grid = get_coin_grid(bools) sorted_grid = VGroup(*grid) sorted_grid.submobjects.sort(key=lambda m: m.symbol) # Prob label p_label = get_prob_coin_label() p_label.set_height(0.7) p_label.to_edge(UP) rhs = p_label[-1] rhs_box = SurroundingRectangle(rhs, color=RED) rhs_label = TextMobject("Not necessarily") rhs_label.next_to(rhs_box, DOWN, LARGE_BUFF) rhs_label.to_edge(RIGHT) rhs_label.match_color(rhs_box) rhs_arrow = Arrow( rhs_label.get_top(), rhs_box.get_right(), buff=SMALL_BUFF, path_arc=60 * DEGREES, color=rhs_box.get_color() ) # Introduce coin self.play(FadeIn( grid, run_time=2, rate_func=linear, lag_ratio=3 / len(grid), )) self.wait() self.play( grid.set_height, 5, grid.to_edge, DOWN, FadeInFromDown(p_label) ) for coin in grid: coin.generate_target() sorted_coins = list(grid) sorted_coins.sort(key=lambda m: m.symbol) for c1, c2 in zip(sorted_coins, grid): c1.target.move_to(c2) self.play( FadeIn(rhs_label, lag_ratio=0.1), ShowCreation(rhs_arrow), ShowCreation(rhs_box), LaggedStartMap( MoveToTarget, grid, path_arc=30 * DEGREES, lag_ratio=0.01, ), ) # Alternate weightings old_grid = VGroup(*sorted_coins) rhs_junk_on_screen = True for value in [0.2, 0.9, 0.0, 0.31]: n = int(100 * value) new_grid = get_coin_grid([True] * n + [False] * (100 - n)) new_grid.replace(grid) anims = [] if rhs_junk_on_screen: anims += [ FadeOut(rhs_box), FadeOut(rhs_label), FadeOut(rhs_arrow), ] rhs_junk_on_screen = False self.wait() self.play( FadeOutAndShift( old_grid, 0.1 * DOWN, lag_ratio=0.01, run_time=1.5 ), FadeIn(new_grid, lag_ratio=0.01, run_time=1.5), ChangeDecimalToValue(rhs, value), *anims, ) old_grid = new_grid long_rhs = DecimalNumber( 0.31415926, num_decimal_places=8, show_ellipsis=True, ) long_rhs.match_height(rhs) long_rhs.move_to(rhs, DL) self.play(ShowIncreasingSubsets(long_rhs, rate_func=linear)) self.wait() # You just don't know box = get_q_box(rhs) self.remove(rhs) self.play( FadeOut(old_grid, lag_ratio=0.1), FadeOutAndShift(long_rhs, 0.1 * RIGHT, lag_ratio=0.1), Write(box), ) p_label.add(box) self.wait() # 7/10 heads bools = [True] * 7 + [False] * 3 random.shuffle(bools) coins = VGroup(*[ get_coin("H" if heads else "T") for heads in bools ]) coins.arrange(RIGHT) coins.set_height(0.7) coins.next_to(p_label, DOWN, buff=LARGE_BUFF) heads_arrows = VGroup(*[ Vector( 0.5 * UP, max_stroke_width_to_length_ratio=15, max_tip_length_to_length_ratio=0.4, ).next_to(coin, DOWN) for coin in coins if coin.symbol == "H" ]) numbers = VGroup(*[ Integer(i + 1).next_to(arrow, DOWN, SMALL_BUFF) for i, arrow in enumerate(heads_arrows) ]) for coin in coins: coin.save_state() coin.stretch(0, 0) coin.set_opacity(0) self.play(LaggedStartMap(Restore, coins), run_time=1) self.play( ShowIncreasingSubsets(heads_arrows), ShowIncreasingSubsets(numbers), rate_func=linear, ) self.wait() # Plot axes = scaled_pdf_axes() axes.to_edge(DOWN, buff=MED_SMALL_BUFF) axes.y_axis.numbers.set_opacity(0) axes.y_axis_label.set_opacity(0) x_axis_label = p_label[:4].copy() x_axis_label.set_height(0.4) x_axis_label.next_to(axes.c2p(1, 0), UR, buff=SMALL_BUFF) axes.x_axis.add(x_axis_label) n_heads = 7 n_tails = 3 graph = get_beta_graph(axes, n_heads, n_tails) dist = scipy.stats.beta(n_heads + 1, n_tails + 1) true_graph = axes.get_graph(dist.pdf) v_line = Line( axes.c2p(0.7, 0), axes.input_to_graph_point(0.7, true_graph), ) v_line.set_stroke(YELLOW, 4) region = get_region_under_curve(axes, true_graph, 0.6, 0.8) region.set_fill(GREY, 0.85) region.set_stroke(YELLOW, 1) eq_label = VGroup( p_label[:4].copy(), TexMobject("= 0.7"), ) for mob in eq_label: mob.set_height(0.4) eq_label.arrange(RIGHT, buff=SMALL_BUFF) pp_label = VGroup( TexMobject("P("), eq_label, TexMobject(")"), ) for mob in pp_label[::2]: mob.set_height(0.7) mob.set_color(YELLOW) pp_label.arrange(RIGHT, buff=SMALL_BUFF) pp_label.move_to(axes.c2p(0.3, 3)) self.play( FadeOut(heads_arrows), FadeOut(numbers), Write(axes), DrawBorderThenFill(graph), ) self.play( FadeIn(pp_label[::2]), ShowCreation(v_line), ) self.wait() self.play(TransformFromCopy(p_label[:4], eq_label[0])) self.play( GrowFromPoint(eq_label[1], v_line.get_center()) ) self.wait() # Look confused randy = Randolph() randy.set_height(1.5) randy.next_to(axes.c2p(0, 0), UR, MED_LARGE_BUFF) self.play(FadeIn(randy)) self.play(randy.change, "confused", pp_label.get_top()) self.play(Blink(randy)) self.wait() self.play(FadeOut(randy)) # Remind what the title is title = TextMobject( "Probabilities", "of", "Probabilities" ) title.arrange(DOWN, aligned_edge=LEFT) title.next_to(axes.c2p(0, 0), UR, buff=MED_LARGE_BUFF) title.align_to(pp_label, LEFT) self.play(ShowIncreasingSubsets(title, rate_func=linear)) self.wait() self.play(FadeOut(title)) # Continuous values v_line.tracker = ValueTracker(0.7) v_line.axes = axes v_line.graph = true_graph v_line.add_updater( lambda m: m.put_start_and_end_on( m.axes.c2p(m.tracker.get_value(), 0), m.axes.input_to_graph_point(m.tracker.get_value(), m.graph), ) ) for value in [0.4, 0.9, 0.7]: self.play( v_line.tracker.set_value, value, run_time=3, ) # Label h brace = Brace(rhs_box, DOWN, buff=SMALL_BUFF) h_label = TexMobject("h", buff=SMALL_BUFF) h_label.set_color(YELLOW) h_label.next_to(brace, DOWN) self.play( LaggedStartMap(FadeOutAndShift, coins, lambda m: (m, DOWN)), GrowFromCenter(brace), Write(h_label), ) self.wait() # End self.embed() class Eq70(Scene): def construct(self): label = TexMobject("=", "70", "\\%", "?") fix_percent(label.get_part_by_tex("\\%")[0]) self.play(FadeIn(label)) self.wait() class ShowInfiniteContinuum(Scene): def construct(self): # Axes axes = scaled_pdf_axes() axes.to_edge(DOWN, buff=MED_SMALL_BUFF) axes.y_axis.numbers.set_opacity(0) axes.y_axis_label.set_opacity(0) self.add(axes) # Label p_label = get_prob_coin_label() p_label.set_height(0.7) p_label.to_edge(UP) box = get_q_box(p_label[-1]) p_label.add(box) brace = Brace(box, DOWN, buff=SMALL_BUFF) h_label = TexMobject("h") h_label.next_to(brace, DOWN) h_label.set_color(YELLOW) eq = TexMobject("=") eq.next_to(h_label, RIGHT) value = DecimalNumber(0, num_decimal_places=4) value.match_height(h_label) value.next_to(eq, RIGHT) value.set_color(YELLOW) self.add(p_label) self.add(brace) self.add(h_label) # Moving h h_part = h_label.copy() x_line = Line(axes.c2p(0, 0), axes.c2p(1, 0)) x_line.set_stroke(YELLOW, 3) self.play( h_part.next_to, x_line.get_start(), UR, SMALL_BUFF, Write(eq), FadeInFromPoint(value, h_part.get_center()), ) # Scan continuum h_part.tracked = x_line value.tracked = x_line value.x_axis = axes.x_axis self.play( ShowCreation(x_line), UpdateFromFunc( h_part, lambda m: m.next_to(m.tracked.get_end(), UR, SMALL_BUFF) ), UpdateFromFunc( value, lambda m: m.set_value( m.x_axis.p2n(m.tracked.get_end()) ) ), run_time=3, ) self.wait() self.play( FadeOut(eq), FadeOut(value), ) # Arrows arrows = VGroup() arrow_template = Vector(DOWN) arrow_template.lock_triangulation() def get_arrow(s, denom, arrow_template=arrow_template, axes=axes): arrow = arrow_template.copy() arrow.set_height(4 / denom) arrow.move_to(axes.c2p(s, 0), DOWN) arrow.set_color(interpolate_color( GREY_A, GREY_C, random.random() )) return arrow for k in range(2, 50): for n in range(1, k): if np.gcd(n, k) != 1: continue s = n / k arrows.add(get_arrow(s, k)) for k in range(50, 1000): arrows.add(get_arrow(1 / k, k)) arrows.add(get_arrow(1 - 1 / k, k)) kw = { "lag_ratio": 0.05, "run_time": 5, "rate_func": lambda t: t**5, } arrows.save_state() for arrow in arrows: arrow.stretch(0, 0) arrow.set_stroke(width=0) arrow.set_opacity(0) self.play(Restore(arrows, **kw)) self.play(LaggedStartMap( ApplyMethod, arrows, lambda m: (m.scale, 0, {"about_edge": DOWN}), lag_ratio=10 / len(arrows), rate_func=smooth, run_time=3, )) self.remove(arrows) self.wait() class TitleCard(Scene): def construct(self): text = TextMobject("A beginner's guide to\\\\probability density") text.scale(2) text.to_edge(UP, buff=1.5) subtext = TextMobject("Probabilities of probabilities, ", "part 2") subtext.set_width(FRAME_WIDTH - 3) subtext[0].set_color(BLUE) subtext.next_to(text, DOWN, LARGE_BUFF) self.add(text) self.play(FadeIn(subtext, lag_ratio=0.1, run_time=2)) self.wait(2) class NamePdfs(Scene): def construct(self): label = TextMobject("Probability density\\\\function") self.play(Write(label)) self.wait() class LabelH(Scene): def construct(self): p_label = get_prob_coin_label() p_label.scale(1.5) brace = Brace(p_label, DOWN) h = TexMobject("h") h.scale(2) h.next_to(brace, DOWN) self.add(p_label) self.play(ShowCreationThenFadeAround(p_label)) self.play( GrowFromCenter(brace), FadeInFrom(h, UP), ) self.wait() class Underline(Scene): def construct(self): line = Line(2 * LEFT, 2 * RIGHT) line.set_stroke(PINK, 5) self.play(ShowCreation(line)) self.wait() line.reverse_points() self.play(Uncreate(line)) class TryAssigningProbabilitiesToSpecificValues(Scene): def construct(self): # To get "P(s = .7000001) = ???" type labels def get_p_label(value): result = TexMobject( # "P(", "{s}", "=", value, "\\%", ")", "P(", "{h}", "=", value, ")", ) # fix_percent(result.get_part_by_tex("\\%")[0]) result.set_color_by_tex("{h}", YELLOW) return result labels = VGroup( get_p_label("0.70000000"), get_p_label("0.70000001"), get_p_label("0.70314159"), get_p_label("0.70271828"), get_p_label("0.70466920"), get_p_label("0.70161803"), ) labels.arrange(DOWN, buff=0.35, aligned_edge=LEFT) labels.set_height(4.5) labels.to_edge(DOWN, buff=LARGE_BUFF) q_marks = VGroup() gt_zero = VGroup() eq_zero = VGroup() for label in labels: qm = TexMobject("=", "\\,???") qm.next_to(label, RIGHT) qm[1].set_color(TEAL) q_marks.add(qm) gt = TexMobject("> 0") gt.next_to(label, RIGHT) gt_zero.add(gt) eqz = TexMobject("= 0") eqz.next_to(label, RIGHT) eq_zero.add(eqz) v_dots = TexMobject("\\vdots") v_dots.next_to(q_marks[-1][0], DOWN, MED_LARGE_BUFF) # Animations self.play(FadeInFromDown(labels[0])) self.play(FadeInFrom(q_marks[0], LEFT)) self.wait() self.play(*[ TransformFromCopy(m1, m2) for m1, m2 in [ (q_marks[0], q_marks[1]), (labels[0][:3], labels[1][:3]), (labels[0][-1], labels[1][-1]), ] ]) self.play(ShowIncreasingSubsets( labels[1][3], run_time=3, int_func=np.ceil, rate_func=linear, )) self.add(labels[1]) self.wait() self.play( LaggedStartMap( FadeInFrom, labels[2:], lambda m: (m, UP), ), LaggedStartMap( FadeInFrom, q_marks[2:], lambda m: (m, UP), ), Write(v_dots, rate_func=squish_rate_func(smooth, 0.5, 1)) ) self.add(labels, q_marks) self.wait() q_marks.unlock_triangulation() self.play( ReplacementTransform(q_marks, gt_zero, lag_ratio=0.05), run_time=2, ) self.wait() # Show sum group = VGroup(labels, gt_zero, v_dots) sum_label = TexMobject( "\\sum_{0 \\le {h} \\le 1}", "P(", "{h}", ")", "=", tex_to_color_map={"{h}": YELLOW}, ) # sum_label.set_color_by_tex("{s}", YELLOW) sum_label[0].set_color(WHITE) sum_label.scale(1.75) sum_label.next_to(ORIGIN, RIGHT, buff=1) sum_label.shift(LEFT) morty = Mortimer() morty.set_height(2) morty.to_corner(DR) self.play(group.to_corner, DL) self.play( Write(sum_label), VFadeIn(morty), morty.change, "confused", sum_label, ) infty = TexMobject("\\infty") zero = TexMobject("0") for mob in [infty, zero]: mob.scale(2) mob.next_to(sum_label[-1], RIGHT) zero.set_color(RED) zero.shift(SMALL_BUFF * RIGHT) self.play( Write(infty), morty.change, "horrified", infty, ) self.play(Blink(morty)) self.wait() # If equal to zero eq_zero.move_to(gt_zero) eq_zero.set_color(RED) gt_zero.unlock_triangulation() self.play( ReplacementTransform( gt_zero, eq_zero, lag_ratio=0.05, run_time=2, path_arc=30 * DEGREES, ), morty.change, "pondering", eq_zero, ) self.wait() self.play( FadeInFrom(zero, DOWN), FadeOutAndShift(infty, UP), morty.change, "sad", zero ) self.play(Blink(morty)) self.wait() class WanderingArrow(Scene): def construct(self): arrow = Vector(0.8 * DOWN) arrow.move_to(4 * LEFT, DOWN) for u in [1, -1, 1, -1, 1]: self.play( arrow.shift, u * 8 * RIGHT, run_time=3 ) class ProbabilityToContinuousValuesSupplement(Scene): def construct(self): nl = UnitInterval() nl.set_width(10) nl.add_numbers( *np.arange(0, 1.1, 0.1), buff=0.3, ) nl.to_edge(LEFT) self.add(nl) def f(x): return -100 * (x - 0.6) * (x - 0.8) values = np.linspace(0.65, 0.75, 100) lines = VGroup() for x, color in zip(values, it.cycle([BLUE_E, BLUE_C])): line = Line(ORIGIN, UP) line.set_height(f(x)) line.set_stroke(color, 1) line.move_to(nl.n2p(x), DOWN) lines.add(line) self.play(ShowCreation(lines, lag_ratio=0.9, run_time=5)) lines_row = lines.copy() lines_row.generate_target() for lt in lines_row.target: lt.rotate(90 * DEGREES) lines_row.target.arrange(RIGHT, buff=0) lines_row.target.set_stroke(width=4) lines_row.target.next_to(nl, UP, LARGE_BUFF) lines_row.target.align_to(nl.n2p(0), LEFT) self.play( MoveToTarget( lines_row, lag_ratio=0.1, rate_func=rush_into, run_time=4, ) ) self.wait() self.play( lines.set_height, 0.01, {"about_edge": DOWN, "stretch": True}, ApplyMethod( lines_row.set_width, 0.01, {"about_edge": LEFT}, rate_func=rush_into, ), run_time=6, ) self.wait() 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("What can you say"), TexMobject( "\\text{about } P(\\text{defect})?", tex_to_color_map={"\\text{defect}": RED} ) ) question.arrange(DOWN, aligned_edge=LEFT) question.next_to(denom_words, DOWN, buff=1.5, aligned_edge=LEFT) self.play(FadeIn(question)) self.wait() class TeacherHoldingValue(TeacherStudentsScene): def construct(self): self.play(self.teacher.change, "raise_right_hand", self.screen) self.change_all_student_modes( "pondering", look_at_arg=self.screen, ) self.wait(8) class ShowLimitToPdf(Scene): def construct(self): # Init axes = self.get_axes() alpha = 4 beta = 2 dist = scipy.stats.beta(alpha, beta) bars = self.get_bars(axes, dist, 0.05) axis_prob_label = TextMobject("Probability") axis_prob_label.next_to(axes.y_axis, UP) axis_prob_label.to_edge(LEFT) self.add(axes) self.add(axis_prob_label) # From individual to ranges kw = {"tex_to_color_map": {"h": YELLOW}} eq_label = TexMobject("P(h = 0.8)", **kw) ineq_label = TexMobject("P(0.8 < h < 0.85)", **kw) arrows = VGroup(Vector(DOWN), Vector(DOWN)) for arrow, x in zip(arrows, [0.8, 0.85]): arrow.move_to(axes.c2p(x, 0), DOWN) brace = Brace( Line(arrows[0].get_start(), arrows[1].get_start()), UP, buff=SMALL_BUFF ) eq_label.next_to(arrows[0], UP) ineq_label.next_to(brace, UP) self.play( FadeInFrom(eq_label, 0.2 * DOWN), GrowArrow(arrows[0]), ) self.wait() vect = eq_label.get_center() - ineq_label.get_center() self.play( FadeOutAndShift(eq_label, -vect), FadeInFrom(ineq_label, vect), TransformFromCopy(*arrows), GrowFromPoint(brace, brace.get_left()), ) self.wait() # Bars arrow = arrows[0] arrow.generate_target() arrow.target.next_to(bars[16], UP, SMALL_BUFF) highlighted_bar_color = RED_E bars[16].set_color(highlighted_bar_color) for bar in bars: bar.save_state() bar.stretch(0, 1, about_edge=DOWN) kw = { "run_time": 2, "rate_func": squish_rate_func(smooth, 0.3, 0.9), } self.play( MoveToTarget(arrow, **kw), ApplyMethod(ineq_label.next_to, arrows[0].target, UP, **kw), FadeOut(arrows[1]), FadeOut(brace), LaggedStartMap(Restore, bars, run_time=2, lag_ratio=0.025), ) self.wait() # Focus on area, not height lines = VGroup() new_bars = VGroup() for bar in bars: line = Line( bar.get_corner(DL), bar.get_corner(DR), ) line.set_stroke(YELLOW, 0) line.generate_target() line.target.set_stroke(YELLOW, 3) line.target.move_to(bar.get_top()) lines.add(line) new_bar = bar.copy() new_bar.match_style(line) new_bar.set_fill(YELLOW, 0.5) new_bar.generate_target() new_bar.stretch(0, 1, about_edge=UP) new_bars.add(new_bar) prob_label = TextMobject( "Height", "$\\rightarrow$", "Probability", ) prob_label.space_out_submobjects(1.1) prob_label.next_to(bars[10], UL, LARGE_BUFF) height_word = prob_label[0] height_cross = Cross(height_word) area_word = TextMobject("Area") area_word.move_to(height_word, UR) area_word.set_color(YELLOW) self.play( LaggedStartMap( MoveToTarget, lines, lag_ratio=0.01, ), FadeInFromDown(prob_label), ) self.add(height_word) self.play( ShowCreation(height_cross), FadeOutAndShift(axis_prob_label, LEFT) ) self.wait() self.play( FadeOutAndShift(height_word, UP), FadeOutAndShift(height_cross, UP), FadeInFromDown(area_word), ) self.play( FadeOut(lines), LaggedStartMap( MoveToTarget, new_bars, lag_ratio=0.01, ) ) self.play( FadeOut(new_bars), area_word.set_color, BLUE, ) prob_label = VGroup(area_word, *prob_label[1:]) self.add(prob_label) # Ask about where values come from randy = Randolph(height=1) randy.next_to(prob_label, UP, aligned_edge=LEFT) bubble = SpeechBubble( height=2, width=4, ) bubble.move_to(randy.get_corner(UR), DL) bubble.write("Where do these\\\\probabilities come from?") self.play( FadeIn(randy), ShowCreation(bubble), ) self.play( randy.change, "confused", FadeIn(bubble.content, lag_ratio=0.1) ) self.play(Blink(randy)) bars.generate_target() bars.save_state() bars.target.arrange(RIGHT, buff=SMALL_BUFF, aligned_edge=DOWN) bars.target.next_to(bars.get_bottom(), UP) self.play(MoveToTarget(bars)) self.play(LaggedStartMap(Indicate, bars, scale_factor=1.05), run_time=1) self.play(Restore(bars)) self.play(Blink(randy)) self.play( FadeOut(randy), FadeOut(bubble), FadeOut(bubble.content), ) # Refine last_ineq_label = ineq_label last_bars = bars all_ineq_labels = VGroup(ineq_label) for step_size in [0.025, 0.01, 0.005, 0.001]: new_bars = self.get_bars(axes, dist, step_size) new_ineq_label = TexMobject( "P(0.8 < h < {:.3})".format(0.8 + step_size), tex_to_color_map={"h": YELLOW}, ) if step_size <= 0.005: new_bars.set_stroke(width=0) arrow.generate_target() bar = new_bars[int(0.8 * len(new_bars))] bar.set_color(highlighted_bar_color) arrow.target.next_to(bar, UP, SMALL_BUFF) new_ineq_label.next_to(arrow.target, UP) vect = new_ineq_label.get_center() - last_ineq_label.get_center() self.wait() self.play( ReplacementTransform( last_bars, new_bars, lag_ratio=step_size, ), MoveToTarget(arrow), FadeOutAndShift(last_ineq_label, vect), FadeInFrom(new_ineq_label, -vect), run_time=2, ) last_ineq_label = new_ineq_label last_bars = new_bars all_ineq_labels.add(new_ineq_label) # Show continuous graph graph = get_beta_graph(axes, alpha - 1, beta - 1) graph_curve = axes.get_graph(dist.pdf) graph_curve.set_stroke([YELLOW, GREEN]) limit_words = TextMobject("In the limit...") limit_words.next_to( axes.input_to_graph_point(0.75, graph_curve), UP, MED_LARGE_BUFF, ) self.play( FadeIn(graph), FadeOut(last_ineq_label), FadeOut(arrow), FadeOut(last_bars), ) self.play( ShowCreation(graph_curve), Write(limit_words, run_time=1) ) self.play(FadeOut(graph_curve)) self.wait() # Show individual probabilities goes to zero all_ineq_labels.arrange(DOWN, aligned_edge=LEFT) all_ineq_labels.move_to(prob_label, LEFT) all_ineq_labels.to_edge(UP) prob_label.generate_target() prob_label.target.next_to( all_ineq_labels, DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT ) rhss = VGroup() step_sizes = [0.05, 0.025, 0.01, 0.005, 0.001] for label, step in zip(all_ineq_labels, step_sizes): eq = TexMobject("=") decimal = DecimalNumber( dist.cdf(0.8 + step) - dist.cdf(0.8), num_decimal_places=3, ) eq.next_to(label, RIGHT) decimal.next_to(eq, RIGHT) decimal.set_stroke(BLACK, 3, background=True) rhss.add(VGroup(eq, decimal)) for rhs in rhss: rhs.align_to(rhss[1], LEFT) VGroup(all_ineq_labels, rhss).set_height(3, about_edge=UL) arrow = Arrow(rhss.get_top(), rhss.get_bottom(), buff=0) arrow.next_to(rhss, RIGHT) arrow.set_color(YELLOW) to_zero_words = TextMobject("Individual probabilites\\\\", "go to zero") to_zero_words[1].align_to(to_zero_words[0], LEFT) to_zero_words.next_to(arrow, RIGHT, aligned_edge=UP) self.play( LaggedStartMap( FadeInFrom, all_ineq_labels, lambda m: (m, UP), ), LaggedStartMap( FadeInFrom, rhss, lambda m: (m, UP), ), MoveToTarget(prob_label) ) self.play( GrowArrow(arrow), FadeIn(to_zero_words), ) self.play( LaggedStartMap( Indicate, rhss, scale_factor=1.05, ) ) self.wait(2) # What if it was heights bars.restore() height_word.move_to(area_word, RIGHT) height_word.set_color(PINK) step = 0.05 new_y_numbers = VGroup(*[ DecimalNumber(x) for x in np.arange(step, 5 * step, step) ]) for n1, n2 in zip(axes.y_axis.numbers, new_y_numbers): n2.match_height(n1) n2.add_background_rectangle( opacity=1, buff=SMALL_BUFF, ) n2.move_to(n1, RIGHT) self.play( FadeOut(limit_words), FadeOut(graph), FadeIn(bars), FadeOutAndShift(area_word, UP), FadeInFrom(height_word, DOWN), FadeInFrom(new_y_numbers, 0.5 * RIGHT), ) # Height refine rect = SurroundingRectangle(rhss[0][1]) rect.set_stroke(RED, 3) self.play(FadeIn(rect)) last_bars = bars for step_size, rhs in zip(step_sizes[1:], rhss[1:]): new_bars = self.get_bars(axes, dist, step_size) bar = new_bars[int(0.8 * len(new_bars))] bar.set_color(highlighted_bar_color) new_bars.stretch( step_size / 0.05, 1, about_edge=DOWN, ) if step_size <= 0.05: new_bars.set_stroke(width=0) self.remove(last_bars) self.play( TransformFromCopy(last_bars, new_bars, lag_ratio=step_size), rect.move_to, rhs[1], ) last_bars = new_bars self.play( FadeOut(last_bars), FadeOutAndShiftDown(rect), ) self.wait() # Back to area self.play( FadeIn(graph), FadeInFrom(area_word, 0.5 * DOWN), FadeOutAndShift(height_word, 0.5 * UP), FadeOut(new_y_numbers, lag_ratio=0.2), ) self.play( arrow.scale, 0, {"about_edge": DOWN}, FadeOutAndShift(to_zero_words, DOWN), LaggedStartMap(FadeOutAndShiftDown, all_ineq_labels), LaggedStartMap(FadeOutAndShiftDown, rhss), ) self.wait() # Ask about y_axis units arrow = Arrow( axes.y_axis.get_top() + 3 * RIGHT, axes.y_axis.get_top(), path_arc=90 * DEGREES, ) question = TextMobject("What are the\\\\units here?") question.next_to(arrow.get_start(), DOWN) self.play( FadeIn(question, lag_ratio=0.1), ShowCreation(arrow), ) self.wait() # Bring back bars bars = self.get_bars(axes, dist, 0.05) self.play( FadeOut(graph), FadeIn(bars), ) bars.generate_target() bars.save_state() bars.target.set_opacity(0.2) bar_index = int(0.8 * len(bars)) bars.target[bar_index].set_opacity(0.8) bar = bars[bar_index] prob_word = TextMobject("Probability") prob_word.rotate(90 * DEGREES) prob_word.set_height(0.8 * bar.get_height()) prob_word.move_to(bar) self.play( MoveToTarget(bars), Write(prob_word, run_time=1), ) self.wait() # Show dimensions of bar top_brace = Brace(bar, UP) side_brace = Brace(bar, LEFT) top_label = top_brace.get_tex("\\Delta x") side_label = side_brace.get_tex( "{\\text{Prob.} \\over \\Delta x}" ) self.play( GrowFromCenter(top_brace), FadeIn(top_label), ) self.play(GrowFromCenter(side_brace)) self.wait() self.play(Write(side_label)) self.wait() y_label = TextMobject("Probability density") y_label.next_to(axes.y_axis, UP, aligned_edge=LEFT) self.play( Uncreate(arrow), FadeOutAndShiftDown(question), Write(y_label), ) self.wait(2) self.play( Restore(bars), FadeOut(top_brace), FadeOut(side_brace), FadeOut(top_label), FadeOut(side_label), FadeOut(prob_word), ) # Point out total area is 1 total_label = TextMobject("Total area = 1") total_label.set_height(0.5) total_label.next_to(bars, UP, LARGE_BUFF) self.play(FadeInFrom(total_label, DOWN)) bars.save_state() self.play( bars.arrange, RIGHT, {"aligned_edge": DOWN, "buff": SMALL_BUFF}, bars.move_to, bars.get_bottom() + 0.5 * UP, DOWN, ) self.play(LaggedStartMap(Indicate, bars, scale_factor=1.05)) self.play(Restore(bars)) # Refine again for step_size in step_sizes[1:]: new_bars = self.get_bars(axes, dist, step_size) if step_size <= 0.05: new_bars.set_stroke(width=0) self.play( ReplacementTransform( bars, new_bars, lag_ratio=step_size ), run_time=3, ) self.wait() bars = new_bars self.add(graph, total_label) self.play( FadeIn(graph), FadeOut(bars), total_label.move_to, axes.c2p(0.7, 0.8) ) self.wait() # Name pdf func_name = TextMobject("Probability ", "Density ", "Function") initials = TextMobject("P", "D", "F") for mob in func_name, initials: mob.set_color(YELLOW) mob.next_to(axes.input_to_graph_point(0.75, graph_curve), UP) self.play( ShowCreation(graph_curve), Write(func_name, run_time=1), ) self.wait() func_name_copy = func_name.copy() self.play( func_name.next_to, initials, UP, *[ ReplacementTransform(np[0], ip[0]) for np, ip in zip(func_name_copy, initials) ], *[ FadeOut(np[1:]) for np in func_name_copy ] ) self.add(initials) self.wait() self.play( FadeOut(func_name), FadeOut(total_label), FadeOut(graph_curve), initials.next_to, axes.input_to_graph_point(0.95, graph_curve), UR, ) # Look at bounded area min_x = 0.6 max_x = 0.8 region = get_region_under_curve(axes, graph_curve, min_x, max_x) area_label = DecimalNumber( dist.cdf(max_x) - dist.cdf(min_x), num_decimal_places=3, ) area_label.move_to(region) v_lines = VGroup() for x in [min_x, max_x]: v_lines.add( DashedLine( axes.c2p(x, 0), axes.c2p(x, 2.5), ) ) v_lines.set_stroke(YELLOW, 2) p_label = VGroup( TexMobject("P("), DecimalNumber(min_x), TexMobject("\\le"), TexMobject("h", color=YELLOW), TexMobject("\\le"), DecimalNumber(max_x), TexMobject(")") ) p_label.arrange(RIGHT, buff=0.25) VGroup(p_label[0], p_label[-1]).space_out_submobjects(0.92) p_label.next_to(v_lines, UP) rhs = VGroup( TexMobject("="), area_label.copy() ) rhs.arrange(RIGHT) rhs.next_to(p_label, RIGHT) self.play( FadeInFrom(p_label, 2 * DOWN), *map(ShowCreation, v_lines), ) self.wait() region.func = get_region_under_curve self.play( UpdateFromAlphaFunc( region, lambda m, a: m.become( m.func( m.axes, m.graph, m.min_x, interpolate(m.min_x, m.max_x, a) ) ) ), CountInFrom(area_label), UpdateFromAlphaFunc( area_label, lambda m, a: m.set_opacity(a), ), ) self.wait() self.play( TransformFromCopy(area_label, rhs[1]), Write(rhs[0]), ) self.wait() # Change range new_x = np.mean([min_x, max_x]) area_label.original_width = area_label.get_width() region.new_x = new_x # Squish to area 1 self.play( ChangeDecimalToValue(p_label[1], new_x), ChangeDecimalToValue(p_label[5], new_x), ChangeDecimalToValue(area_label, 0), UpdateFromAlphaFunc( area_label, lambda m, a: m.set_width( interpolate(m.original_width, 1e-6, a) ) ), ChangeDecimalToValue(rhs[1], 0), v_lines[0].move_to, axes.c2p(new_x, 0), DOWN, v_lines[1].move_to, axes.c2p(new_x, 0), DOWN, UpdateFromAlphaFunc( region, lambda m, a: m.become(m.func( m.axes, m.graph, interpolate(m.min_x, m.new_x, a), interpolate(m.max_x, m.new_x, a), )) ), run_time=2, ) self.wait() # Stretch to area 1 self.play( ChangeDecimalToValue(p_label[1], 0), ChangeDecimalToValue(p_label[5], 1), ChangeDecimalToValue(area_label, 1), UpdateFromAlphaFunc( area_label, lambda m, a: m.set_width( interpolate(1e-6, m.original_width, clip(5 * a, 0, 1)) ) ), ChangeDecimalToValue(rhs[1], 1), v_lines[0].move_to, axes.c2p(0, 0), DOWN, v_lines[1].move_to, axes.c2p(1, 0), DOWN, UpdateFromAlphaFunc( region, lambda m, a: m.become(m.func( m.axes, m.graph, interpolate(m.new_x, 0, a), interpolate(m.new_x, 1, a), )) ), run_time=5, ) self.wait() def get_axes(self): axes = Axes( x_min=0, x_max=1, x_axis_config={ "tick_frequency": 0.05, "unit_size": 12, "include_tip": False, }, y_min=0, y_max=4, y_axis_config={ "tick_frequency": 1, "unit_size": 1.25, "include_tip": False, } ) axes.center() h_label = TexMobject("h") h_label.set_color(YELLOW) h_label.next_to(axes.x_axis.n2p(1), UR, buff=0.2) axes.x_axis.add(h_label) axes.x_axis.label = h_label axes.x_axis.add_numbers( *np.arange(0.2, 1.2, 0.2), number_config={"num_decimal_places": 1} ) axes.y_axis.add_numbers(*range(1, 5)) return axes def get_bars(self, axes, dist, step_size): bars = VGroup() for x in np.arange(0, 1, step_size): bar = Rectangle() bar.set_stroke(BLUE, 2) bar.set_fill(BLUE, 0.5) h_line = Line( axes.c2p(x, 0), axes.c2p(x + step_size, 0), ) v_line = Line( axes.c2p(0, 0), axes.c2p(0, dist.pdf(x)), ) bar.match_width(h_line, stretch=True) bar.match_height(v_line, stretch=True) bar.move_to(h_line, DOWN) bars.add(bar) return bars class FiniteVsContinuum(Scene): def construct(self): # Title f_title = TextMobject("Finite context") f_title.set_height(0.5) f_title.to_edge(UP) f_underline = Underline(f_title) f_underline.scale(1.3) f_title.add(f_underline) self.add(f_title) # Equations dice = get_die_faces()[::2] cards = [PlayingCard("A" + sym) for sym in "SHCD"] eqs = VGroup( self.get_union_equation(dice), self.get_union_equation(cards), ) for eq in eqs: eq.set_width(FRAME_WIDTH - 1) eqs.arrange(DOWN, buff=LARGE_BUFF) eqs.next_to(f_underline, DOWN, LARGE_BUFF) anims = [] for eq in eqs: movers = eq.mob_copies1.copy() for m1, m2 in zip(movers, eq.mob_copies2): m1.generate_target() m1.target.replace(m2) eq.mob_copies2.set_opacity(0) eq.add(movers) self.play(FadeIn(eq[0])) anims.append(FadeIn(eq[1:])) anims.append(LaggedStartMap( MoveToTarget, movers, path_arc=30 * DEGREES, lag_ratio=0.1, )) self.wait() for anim in anims: self.play(anim) # Continuum label c_title = TextMobject("Continuous context") c_title.match_height(f_title) c_underline = Underline(c_title) c_underline.scale(1.25) self.play( Write(c_title, run_time=1), ShowCreation(c_underline), eqs[0].shift, 0.5 * UP, eqs[1].shift, UP, ) # Range sum c_eq = TexMobject( "P\\big(", "x \\in [0.65, 0.75]", "\\big)", "=", "\\sum_{x \\in [0.65, 0.75]}", "P(", "x", ")", ) c_eq.set_color_by_tex("P", YELLOW) c_eq.set_color_by_tex(")", YELLOW) c_eq.next_to(c_underline, DOWN, LARGE_BUFF) c_eq.to_edge(LEFT) equals = c_eq.get_part_by_tex("=") equals.shift(SMALL_BUFF * RIGHT) e_cross = Line(DL, UR) e_cross.replace(equals, dim_to_match=0) e_cross.set_stroke(RED, 5) self.play(FadeIn(c_eq)) self.wait(2) self.play(ShowCreation(e_cross)) self.wait() self.embed() def get_union_equation(self, mobs): mob_copies1 = VGroup() mob_copies2 = VGroup() p_color = YELLOW # Create mob_set brackets = TexMobject("\\big\\{\\big\\}")[0] mob_set = VGroup(brackets[0]) commas = VGroup() for mob in mobs: mc = mob.copy() mc.match_height(mob_set[0]) mob_copies1.add(mc) comma = TexMobject(",") commas.add(comma) mob_set.add(mc) mob_set.add(comma) mob_set.remove(commas[-1]) commas.remove(commas[-1]) mob_set.add(brackets[1]) mob_set.arrange(RIGHT, buff=0.15) commas.set_y(mob_set[1].get_bottom()[1]) mob_set.scale(0.8) # Create individual probabilities probs = VGroup() for mob in mobs: prob = TexMobject("P(", "x = ", "00", ")") index = prob.index_of_part_by_tex("00") mc = mob.copy() mc.replace(prob[index]) mc.scale(0.8, about_edge=LEFT) mc.match_y(prob[-1]) mob_copies2.add(mc) prob.replace_submobject(index, mc) prob[0].set_color(p_color) prob[1].match_y(mc) prob[-1].set_color(p_color) probs.add(prob) # Result lhs = VGroup( TexMobject("P\\big(", color=p_color), TexMobject("x \\in"), mob_set, TexMobject("\\big)", color=p_color), ) lhs.arrange(RIGHT, buff=SMALL_BUFF) group = VGroup(lhs, TexMobject("=")) for prob in probs: group.add(prob) group.add(TexMobject("+")) group.remove(group[-1]) group.arrange(RIGHT, buff=0.2) group.mob_copies1 = mob_copies1 group.mob_copies2 = mob_copies2 return group class ComplainAboutRuleChange(TeacherStudentsScene): def construct(self): self.student_says( "Wait, the rules\\\\changed?", target_mode="sassy", added_anims=[self.teacher.change, "tease"] ) self.change_student_modes("erm", "confused") self.wait(4) self.teacher_says("You may enjoy\\\\``Measure theory''") self.change_all_student_modes( "pondering", look_at_arg=self.teacher.bubble ) self.wait(8) class HalfFiniteHalfContinuous(Scene): def construct(self): # Basic symbols box = Rectangle(width=3, height=1.2) box.set_stroke(WHITE, 2) box.set_fill(GREY_E, 1) box.move_to(2.5 * LEFT, RIGHT) arrows = VGroup() arrow_labels = VGroup() for vect in [UP, DOWN]: arrow = Arrow( box.get_corner(vect + RIGHT), box.get_corner(vect + RIGHT) + 3 * RIGHT + 1.5 * vect, buff=MED_SMALL_BUFF, ) label = TexMobject("50\\%") fix_percent(label[0][-1]) label.set_color(YELLOW) label.next_to( arrow.get_center(), vect + LEFT, buff=SMALL_BUFF, ) arrow_labels.add(label) arrows.add(arrow) zero = Integer(0) zero.set_height(0.5) zero.next_to(arrows[0].get_end(), RIGHT) # Half Gaussian axes = Axes( x_min=0, x_max=6.5, y_min=0, y_max=0.25, y_axis_config={ "tick_frequency": 1 / 16, "unit_size": 10, "include_tip": False, } ) axes.next_to(arrows[1].get_end(), RIGHT) dist = scipy.stats.norm(0, 2) graph = axes.get_graph(dist.pdf) graph_fill = graph.copy() close_off_graph(axes, graph_fill) graph.set_stroke(BLUE, 3) graph_fill.set_fill(BLUE_E, 1) graph_fill.set_stroke(BLUE_E, 0) half_gauss = Group( graph, graph_fill, axes, ) # Random Decimal number = DecimalNumber(num_decimal_places=4) number.set_height(0.6) number.move_to(box) number.time = 0 number.last_change = 0 number.change_freq = 0.2 def update_number(number, dt, dist=dist): number.time += dt if (number.time - number.last_change) < number.change_freq: return number.last_change = number.time rand_val = random.random() if rand_val < 0.5: number.set_value(0) else: number.set_value(dist.ppf(rand_val)) number.add_updater(update_number) v_line = SurroundingRectangle(zero) v_line.save_state() v_line.set_stroke(YELLOW, 3) def update_v_line(v_line, number=number, axes=axes, graph=graph): x = number.get_value() if x < 0.5: v_line.restore() else: v_line.set_width(1e-6) p1 = axes.c2p(x, 0) p2 = axes.input_to_graph_point(x, graph) v_line.set_height(get_norm(p2 - p1), stretch=True) v_line.move_to(p1, DOWN) v_line.add_updater(update_v_line) # Add everything self.add(box) self.add(number) self.wait(4) self.play( GrowArrow(arrows[0]), FadeIn(arrow_labels[0]), GrowFromPoint(zero, box.get_corner(UR)) ) self.wait(2) self.play( GrowArrow(arrows[1]), FadeIn(arrow_labels[1]), FadeIn(half_gauss), ) self.add(v_line) self.wait(30) class Thumbnail(Scene): def construct(self): pass class Part2EndScreen(PatreonEndScreen): CONFIG = { "scroll_time": 30, "specific_patrons": [ "1stViewMaths", "Adam Dřínek", "Aidan Shenkman", "Alan Stein", "Albin Egasse", "Alex Mijalis", "Alexander Mai", "Alexis Olson", "Ali Yahya", "Andrew Busey", "Andrew Cary", "Andrew R. Whalley", "Anthony Losego", "Aravind C V", "Arjun Chakroborty", "Arthur Zey", "Ashwin Siddarth", "Augustine Lim", "Austin Goodman", "Avi Finkel", "Awoo", "Axel Ericsson", "Ayan Doss", "AZsorcerer", "Barry Fam", "Ben Delo", "Bernd Sing", "Bill Gatliff", "Bob Sanderson", "Boris Veselinovich", "Bradley Pirtle", "Brandon Huang", "Brian Staroselsky", "Britt Selvitelle", "Britton Finley", "Burt Humburg", "Calvin Lin", "Charles Southerland", "Charlie N", "Chenna Kautilya", "Chris Connett", "Chris Druta", "Christian Kaiser", "cinterloper", "Clark Gaebel", "Colwyn Fritze-Moor", "Cooper Jones", "Corey Ogburn", "D. Sivakumar", "Dan Herbatschek", "Daniel Brown", "Daniel Herrera C", "Darrell Thomas", "Dave B", "Dave Kester", "dave nicponski", "David B. Hill", "David Clark", "David Gow", "Delton Ding", "Dominik Wagner", "Eddie Landesberg", "Eduardo Rodriguez", "emptymachine", "Eric Younge", "Eryq Ouithaqueue", "Federico Lebron", "Fernando Via Canel", "Frank R. Brown, Jr.", "Gavin", "Giovanni Filippi", "Goodwine", "Hal Hildebrand", "Hitoshi Yamauchi", "Ivan Sorokin", "Jacob Baxter", "Jacob Harmon", "Jacob Hartmann", "Jacob Magnuson", "Jalex Stark", "Jameel Syed", "James Beall", "Jason Hise", "Jayne Gabriele", "Jean-Manuel Izaret", "Jeff Dodds", "Jeff Linse", "Jeff Straathof", "Jimmy Yang", "John C. Vesey", "John Camp", "John Haley", "John Le", "John Luttig", "John Rizzo", "John V Wertheim", "Jonathan Heckerman", "Jonathan Wilson", "Joseph John Cox", "Joseph Kelly", "Josh Kinnear", "Joshua Claeys", "Joshua Ouellette", "Juan Benet", "Kai-Siang Ang", "Kanan Gill", "Karl Niu", "Kartik Cating-Subramanian", "Kaustuv DeBiswas", "Killian McGuinness", "Klaas Moerman", "Kros Dai", "L0j1k", "Lael S Costa", "LAI Oscar", "Lambda GPU Workstations", "Laura Gast", "Lee Redden", "Linh Tran", "Luc Ritchie", "Ludwig Schubert", "Lukas Biewald", "Lukas Zenick", "Magister Mugit", "Magnus Dahlström", "Magnus Hiie", "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", "Maxim Nitsche", "Michael Bos", "Michael Day", "Michael Hardel", "Michael W White", "Mihran Vardanyan", "Mirik Gogri", "Molly Mackinlay", "Mustafa Mahdi", "Márton Vaitkus", "Nate Heckmann", "Nicholas Cahill", "Nikita Lesnikov", "Oleg Leonov", "Omar Zrien", "Owen Campbell-Moore", "Patrick Lucas", "Pavel Dubov", "Pesho Ivanov", "Petar Veličković", "Peter Ehrnstrom", "Peter Francis", "Peter Mcinerney", "Pierre Lancien", "Pradeep Gollakota", "Rafael Bove Barrios", "Randy C. Will", "rehmi post", "Rex Godby", "Ripta Pasay", "Rish Kundalia", "Roman Sergeychik", "Roobie", "Ryan Atallah", "Ryan Prayogo", "Samuel Judge", "SansWord Huang", "Scott Gray", "Scott Walter, Ph.D.", "soekul", "Solara570", "Steve Huynh", "Steve Muench", "Steve Sperandeo", "Steven Siddals", "Stevie Metke", "Sunil Nagaraj", "supershabam", "Susanne Fenja Mehr-Koks", "Suteerth Vishnu", "Suthen Thomas", "Tal Einav", "Taras Bobrovytsky", "Tauba Auerbach", "Ted Suzman", "THIS IS THE point OF NO RE tUUurRrhghgGHhhnnn", "Thomas J Sargent", "Thomas Tarler", "Tianyu Ge", "Tihan Seale", "Tyler Herrmann", "Tyler McAtee", "Tyler VanValkenburg", "Tyler Veness", "Vassili Philippov", "Vasu Dubey", "Veritasium", "Vignesh Ganapathi Subramanian", "Vinicius Reis", "Vladimir Solomatin", "Wooyong Ee", "Xuanji Li", "Yana Chernobilsky", "YinYangBalance.Asia", "Yorick Lesecque", "Yu Jun", "Yurii Monastyrshyn", ], }