3b1b-manim/from_3b1b/active/bayes/beta2.py
2020-04-12 09:54:20 -07:00

2338 lines
68 KiB
Python

from manimlib.imports import *
from from_3b1b.active.bayes.beta_helpers import *
from from_3b1b.active.bayes.beta1 import *
from from_3b1b.old.hyperdarts import Dartboard
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 DrawUnderline(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("Discrete 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(letter + "H") for letter in "A35"]
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()
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 SumToIntegral(Scene):
def construct(self):
# Titles
titles = VGroup(
TextMobject("Discrete context"),
TextMobject("Continuous context"),
)
titles.set_height(0.5)
for title, vect in zip(titles, [LEFT, RIGHT]):
title.move_to(vect * FRAME_WIDTH / 4)
title.to_edge(UP, buff=MED_SMALL_BUFF)
v_line = Line(UP, DOWN).set_height(FRAME_HEIGHT)
h_line = Line(LEFT, RIGHT).set_width(FRAME_WIDTH)
h_line.next_to(titles, DOWN)
h_line.set_x(0)
v_line.center()
self.play(
ShowCreation(VGroup(h_line, v_line)),
LaggedStartMap(
FadeInFrom, titles,
lambda m: (m, -0.2 * m.get_center()[0] * RIGHT),
run_time=1,
lag_ratio=0.1,
),
)
self.wait()
# Sum and int
kw = {"tex_to_color_map": {"S": BLUE}}
s_sym = TexMobject("\\sum", "_{x \\in S} P(x)", **kw)
i_sym = TexMobject("\\int_{S} p(x)", "\\text{d}x", **kw)
syms = VGroup(s_sym, i_sym)
syms.scale(2)
for sym, title in zip(syms, titles):
sym.shift(-sym[-1].get_center())
sym.match_x(title)
arrow = Arrow(
s_sym[0].get_corner(UP),
i_sym[0].get_corner(UP),
path_arc=-90 * DEGREES,
)
arrow.set_color(YELLOW)
self.play(Write(s_sym, run_time=1))
anims = [ShowCreation(arrow)]
for i, j in [(0, 0), (2, 1), (3, 2)]:
source = s_sym[i].deepcopy()
target = i_sym[j]
target.save_state()
source.generate_target()
target.replace(source, stretch=True)
source.target.replace(target, stretch=True)
target.set_opacity(0)
source.target.set_opacity(0)
anims += [
Restore(target, path_arc=-60 * DEGREES),
MoveToTarget(source, path_arc=-60 * DEGREES),
]
self.play(LaggedStart(*anims))
self.play(FadeInFromDown(i_sym[3]))
self.add(i_sym)
self.wait()
self.play(
FadeOutAndShift(arrow, UP),
syms.next_to, h_line, DOWN, {"buff": MED_LARGE_BUFF},
syms.match_x, syms,
)
# Add curve area in editing
# Add bar chart
axes = Axes(
x_min=0,
x_max=10,
y_min=0,
y_max=7,
y_axis_config={
"unit_size": 0.75,
}
)
axes.set_width(0.5 * FRAME_WIDTH - 1)
axes.next_to(s_sym, DOWN)
axes.y_axis.add_numbers(2, 4, 6)
bars = VGroup()
for x, y in [(1, 1), (4, 3), (7, 2)]:
bar = Rectangle()
bar.set_stroke(WHITE, 1)
bar.set_fill(BLUE_D, 1)
line = Line(axes.c2p(x, 0), axes.c2p(x + 2, y))
bar.replace(line, stretch=True)
bars.add(bar)
addition_formula = TexMobject(*"1+3+2")
addition_formula.space_out_submobjects(2.1)
addition_formula.next_to(bars, UP)
for bar in bars:
bar.save_state()
bar.stretch(0, 1, about_edge=DOWN)
self.play(
Write(axes),
LaggedStartMap(Restore, bars),
LaggedStartMap(FadeInFromDown, addition_formula),
)
self.wait()
# Confusion
morty = Mortimer()
morty.to_corner(DR)
morty.look_at(i_sym)
self.play(
*map(FadeOut, [axes, bars, addition_formula]),
FadeIn(morty)
)
self.play(morty.change, "maybe")
self.play(Blink(morty))
self.play(morty.change, "confused", i_sym.get_right())
self.play(Blink(morty))
self.wait()
# Focus on integral
self.play(
Uncreate(VGroup(v_line, h_line)),
FadeOutAndShift(titles, UP),
FadeOutAndShift(morty, RIGHT),
FadeOutAndShift(s_sym, LEFT),
i_sym.center,
i_sym.to_edge, LEFT
)
arrows = VGroup()
for vect in [UP, DOWN]:
corner = i_sym[-1].get_corner(RIGHT + vect)
arrows.add(Arrow(
corner,
corner + 2 * RIGHT + 2 * vect,
path_arc=-np.sign(vect[1]) * 60 * DEGREES,
))
self.play(*map(ShowCreation, arrows))
# Types of integration
dist = scipy.stats.beta(7 + 1, 3 + 1)
axes_pair = VGroup()
graph_pair = VGroup()
for arrow in arrows:
axes = get_beta_dist_axes(y_max=5, y_unit=1)
axes.set_width(4)
axes.next_to(arrow.get_end(), RIGHT)
graph = axes.get_graph(dist.pdf)
graph.set_stroke(BLUE, 2)
graph.set_fill(BLUE_E, 0)
graph.make_smooth()
axes_pair.add(axes)
graph_pair.add(graph)
r_axes, l_axes = axes_pair
r_graph, l_graph = graph_pair
r_name = TextMobject("Riemann\\\\Integration")
r_name.next_to(r_axes, RIGHT)
l_name = TextMobject("Lebesgue\\\\Integration$^*$")
l_name.next_to(l_axes, RIGHT)
footnote = TextMobject("*a bit more complicated than\\\\these bars make it look")
footnote.match_width(l_name)
footnote.next_to(l_name, DOWN)
self.play(LaggedStart(
FadeIn(r_axes),
FadeIn(r_graph),
FadeIn(r_name),
FadeIn(l_axes),
FadeIn(l_graph),
FadeIn(l_name),
run_time=1,
))
# Approximation bars
def get_riemann_rects(dx, axes=r_axes, func=dist.pdf):
bars = VGroup()
for x in np.arange(0, 1, dx):
bar = Rectangle()
line = Line(
axes.c2p(x, 0),
axes.c2p(x + dx, func(x)),
)
bar.replace(line, stretch=True)
bar.set_stroke(BLUE_E, width=10 * dx, opacity=1)
bar.set_fill(BLUE, 0.5)
bars.add(bar)
return bars
def get_lebesgue_bars(dy, axes=l_axes, func=dist.pdf, mx=0.7, y_max=dist.pdf(0.7)):
bars = VGroup()
for y in np.arange(dy, y_max + dy, dy):
x0 = binary_search(func, y, 0, mx) or mx
x1 = binary_search(func, y, mx, 1) or mx
line = Line(axes.c2p(x0, y - dy), axes.c2p(x1, y))
bar = Rectangle()
bar.set_stroke(RED_E, 0)
bar.set_fill(RED_E, 0.5)
bar.replace(line, stretch=True)
bars.add(bar)
return bars
r_bar_groups = []
l_bar_groups = []
Ns = [10, 20, 40, 80, 160]
Ms = [2, 4, 8, 16, 32]
for N, M in zip(Ns, Ms):
r_bar_groups.append(get_riemann_rects(dx=1 / N))
l_bar_groups.append(get_lebesgue_bars(dy=1 / M))
self.play(
FadeIn(r_bar_groups[0], lag_ratio=0.1),
FadeIn(l_bar_groups[0], lag_ratio=0.1),
FadeIn(footnote),
)
self.wait()
for rbg0, rbg1, lbg0, lbg1 in zip(r_bar_groups, r_bar_groups[1:], l_bar_groups, l_bar_groups[1:]):
self.play(
ReplacementTransform(
rbg0, rbg1,
lag_ratio=1 / len(rbg0),
run_time=2,
),
ReplacementTransform(
lbg0, lbg1,
lag_ratio=1 / len(lbg0),
run_time=2,
),
)
self.wait()
self.play(
FadeOut(r_bar_groups[-1]),
FadeOut(l_bar_groups[-1]),
r_graph.set_fill, BLUE_E, 1,
l_graph.set_fill, RED_E, 1,
)
class MeasureTheoryLeadsTo(Scene):
def construct(self):
words = TextMobject("Measure Theory")
words.set_color(RED)
arrow = Vector(DOWN)
arrow.next_to(words, DOWN, buff=SMALL_BUFF)
arrow.set_stroke(width=7)
arrow.rotate(45 * DEGREES, about_point=arrow.get_start())
self.play(
FadeInFrom(words, DOWN),
GrowArrow(arrow),
UpdateFromAlphaFunc(arrow, lambda m, a: m.set_opacity(a)),
)
self.wait()
class WhenIWasFirstLearning(TeacherStudentsScene):
def construct(self):
self.teacher.change_mode("raise_right_hand")
self.play(
self.get_student_changes("pondering", "thinking", "tease"),
self.teacher.change, "thinking",
)
younger = BabyPiCreature(color=GREY_BROWN)
younger.set_height(2)
younger.move_to(self.students, DL)
self.look_at(self.screen)
self.wait()
self.play(
ReplacementTransform(self.teacher, younger),
LaggedStartMap(
FadeOutAndShift, self.students,
lambda m: (m, DOWN),
)
)
# Bubble
bubble = ThoughtBubble()
bubble[-1].set_fill(GREEN_SCREEN, 1)
bubble.move_to(younger.get_corner(UR), DL)
self.play(
Write(bubble),
younger.change, "maybe", bubble.get_bubble_center(),
)
self.play(Blink(younger))
for mode in ["confused", "angry", "pondering", "maybe"]:
self.play(younger.change, mode)
for x in range(2):
self.wait()
if random.random() < 0.5:
self.play(Blink(younger))
class PossibleYetProbabilityZero(Scene):
def construct(self):
poss = TextMobject("Possible")
prob = TextMobject("Probability = 0")
total = TextMobject("P(dart hits somewhere) = 1")
# total[1].next_to(total[0][0], RIGHT)
words = VGroup(poss, prob, total)
words.scale(1.5)
words.arrange(DOWN, aligned_edge=LEFT, buff=MED_LARGE_BUFF)
self.play(Write(poss, run_time=0.5))
self.wait()
self.play(FadeInFrom(prob, UP))
self.wait()
self.play(FadeInFrom(total, UP))
self.wait()
class TiePossibleToDensity(Scene):
def construct(self):
poss = TextMobject("Possibility")
prob = TextMobject("Probability", " $>$ 0")
dens = TextMobject("Probability \\emph{density}", " $>$ 0")
dens[0].set_color(BLUE)
implies = TexMobject("\\Rightarrow")
implies2 = implies.copy()
poss.next_to(implies, LEFT)
prob.next_to(implies, RIGHT)
dens.next_to(implies, RIGHT)
cross = Cross(implies)
self.camera.frame.scale(0.7, about_point=dens.get_center())
self.add(poss)
self.play(
FadeInFrom(prob, LEFT),
Write(implies, run_time=1)
)
self.wait()
self.play(ShowCreation(cross))
self.wait()
self.play(
VGroup(implies, cross, prob).shift, UP,
FadeIn(implies2),
FadeIn(dens),
)
self.wait()
self.embed()
class DrawBigRect(Scene):
def construct(self):
rect = Rectangle(width=7, height=2.5)
rect.set_stroke(RED, 5)
rect.to_edge(RIGHT)
words = TextMobject("Not how to\\\\think about it")
words.set_color(RED)
words.align_to(rect, LEFT)
words.to_edge(UP)
arrow = Arrow(
words.get_bottom(),
rect.get_top(),
buff=0.25,
color=RED,
)
self.play(ShowCreation(rect))
self.play(
FadeInFromDown(words),
GrowArrow(arrow),
)
self.wait()
class Thumbnail(Scene):
def construct(self):
dartboard = Dartboard()
axes = NumberPlane(
x_min=-1.25,
x_max=1.25,
y_min=-1.25,
y_max=1.25,
axis_config={
"unit_size": 0.5 * dartboard.get_width(),
"tick_frequency": 0.25,
},
x_line_frequency=1.0,
y_line_frequency=1.0,
)
group = VGroup(dartboard, axes)
group.to_edge(LEFT, buff=0)
# Arrow
arrow = Vector(DR, max_stroke_width_to_length_ratio=np.inf)
arrow.move_to(axes.c2p(PI / 10, np.exp(1) / 10), DR)
arrow.scale(1.5, about_edge=DR)
arrow.set_stroke(WHITE, 10)
black_arrow = arrow.copy()
black_arrow.set_color(BLACK)
black_arrow.set_stroke(width=20)
arrow.points[0] += 0.025 * DR
# Coords
coords = TexMobject("(x, y) = (0.31415\\dots, 0.27182\\dots)")
coords.set_width(5.5)
coords.set_stroke(BLACK, 10, background=True)
coords.next_to(axes.get_bottom(), UP, buff=0)
# Words
words = VGroup(
TextMobject("Probability = 0"),
TextMobject("$\\dots$but still possible"),
)
for word in words:
word.set_width(6)
words.arrange(DOWN, buff=MED_LARGE_BUFF)
words.next_to(axes, RIGHT)
words.to_edge(UP, buff=LARGE_BUFF)
# Pi
morty = Mortimer()
morty.to_corner(DR)
morty.change("confused", words)
self.add(group)
self.add(black_arrow)
self.add(arrow)
self.add(coords)
self.add(words)
self.add(morty)
self.embed()
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",
],
}