3b1b-manim/eop/independence.py

2850 lines
87 KiB
Python
Raw Normal View History

2017-07-18 10:04:24 -07:00
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 *
from scene.scene import ProgressDisplay
2017-07-18 10:04:24 -07:00
#revert_to_original_skipping_status
def get_binomial_distribution(n, p):
return lambda k : choose(n, k)*(p**(k))*((1-p)**(n-k))
def get_quiz(*questions):
q_mobs = VGroup(*map(TextMobject, [
"%d. %s"%(i+1, question)
for i, question in enumerate(questions)
]))
q_mobs.arrange_submobjects(
DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT,
)
content = VGroup(
TextMobject("Quiz").scale(1.5),
Line(q_mobs.get_left(), q_mobs.get_right()),
q_mobs
)
content.arrange_submobjects(DOWN, buff = MED_SMALL_BUFF)
rect = SurroundingRectangle(content, buff = MED_LARGE_BUFF)
rect.shift(MED_SMALL_BUFF*DOWN)
rect.highlight(WHITE)
quiz = VGroup(rect, content)
quiz.scale(0.7)
return quiz
def get_slot_group(bool_list, buff = MED_LARGE_BUFF, include_qs = True):
lines = VGroup(*[
Line(ORIGIN, MED_LARGE_BUFF*RIGHT)
for x in range(3)
])
lines.arrange_submobjects(RIGHT, buff = buff)
if include_qs:
labels = VGroup(*[
TextMobject("Q%d"%d) for d in range(1, 4)
])
else:
labels = VGroup(*[VectorizedPoint() for d in range(3)])
for label, line in zip(labels, lines):
label.scale(0.7)
label.next_to(line, DOWN, SMALL_BUFF)
slot_group = VGroup()
slot_group.lines = lines
slot_group.labels = labels
slot_group.content = VGroup()
slot_group.digest_mobject_attrs()
slot_group.to_edge(RIGHT)
slot_group.bool_list = bool_list
total_height = SPACE_HEIGHT
base = 2.3
for i, line in enumerate(lines):
if i >= len(bool_list) or bool_list[i] is None:
mob = VectorizedPoint()
elif bool_list[i]:
mob = TexMobject("\\checkmark")
mob.highlight(GREEN)
slot_group.shift(total_height*DOWN / (base**(i+1)))
else:
mob = TexMobject("\\times")
mob.highlight(RED)
slot_group.shift(total_height*UP / (base**(i+1)))
mob.next_to(line, UP, SMALL_BUFF)
slot_group.content.add(mob)
return slot_group
def get_probability_of_slot_group(bool_list, conditioned_list = None):
filler_tex = "Filler"
if conditioned_list is None:
result = TexMobject("P(", filler_tex, ")")
else:
result = TexMobject("P(", filler_tex, "|", filler_tex, ")")
fillers = result.get_parts_by_tex(filler_tex)
for filler, bl in zip(fillers, [bool_list, conditioned_list]):
slot_group = get_slot_group(
bl, buff = SMALL_BUFF, include_qs = False,
)
slot_group.replace(filler, dim_to_match = 0)
slot_group.shift(0.5*SMALL_BUFF*DOWN)
index = result.index_of_part(filler)
result.submobjects[index] = slot_group
return result
2017-07-18 10:04:24 -07:00
#########
class IndependenceOpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"Far better an ", "approximate",
" answer to the ", " right question",
", which is often vague, than an ", "exact",
" answer to the ", "wrong question", "."
],
"highlighted_quote_terms" : {
"approximate" : GREEN,
"right" : GREEN,
"exact" : RED,
"wrong" : RED,
},
"author" : "John Tukey",
"quote_arg_separator" : "",
}
class DangerInProbability(Scene):
def construct(self):
warning = self.get_warning_sign()
probability = TextMobject("Probability")
probability.scale(2)
self.play(Write(warning, run_time = 1))
self.play(
warning.next_to, probability, UP, LARGE_BUFF,
LaggedStart(FadeIn, probability)
)
self.dither()
#####
def get_warning_sign(self):
triangle = RegularPolygon(n = 3, start_angle = np.pi/2)
triangle.set_stroke(RED, 12)
triangle.scale_to_fit_height(2)
bang = TextMobject("!")
bang.scale_to_fit_height(0.6*triangle.get_height())
bang.move_to(interpolate(
triangle.get_bottom(),
triangle.get_top(),
0.4,
))
triangle.add(bang)
return triangle
class MeaningOfIndependence(SampleSpaceScene):
CONFIG = {
"sample_space_config" : {
"height" : 4,
"width" : 4,
}
}
def construct(self):
self.add_labeled_space()
self.align_conditionals()
self.relabel()
self.assume_independence()
self.no_independence()
def add_labeled_space(self):
self.add_sample_space(**self.sample_space_config)
self.sample_space.shift(2*LEFT)
self.sample_space.divide_horizontally(0.3)
self.sample_space[0].divide_vertically(
0.9, colors = [BLUE_D, GREEN_C]
)
self.sample_space[1].divide_vertically(
0.5, colors = [BLUE_E, GREEN_E]
)
side_braces_and_labels = self.sample_space.get_side_braces_and_labels(
["P(A)", "P(\\overline A)"]
)
top_braces_and_labels, bottom_braces_and_labels = [
part.get_subdivision_braces_and_labels(
part.vertical_parts,
labels = ["P(B | %s)"%s, "P(\\overline B | %s)"%s],
direction = vect
)
for part, s, vect in zip(
self.sample_space.horizontal_parts,
["A", "\\overline A"],
[UP, DOWN],
)
]
braces_and_labels_groups = VGroup(
side_braces_and_labels,
top_braces_and_labels,
bottom_braces_and_labels,
)
self.add(self.sample_space)
self.play(Write(braces_and_labels_groups, run_time = 4))
def align_conditionals(self):
line = Line(*[
interpolate(
self.sample_space.get_corner(vect+LEFT),
self.sample_space.get_corner(vect+RIGHT),
0.7
)
for vect in UP, DOWN
])
line.set_stroke(RED, 8)
word = TextMobject("Independence")
word.scale(1.5)
word.next_to(self.sample_space, RIGHT, buff = LARGE_BUFF)
word.highlight(RED)
self.play(*it.chain(
self.get_top_conditional_change_anims(0.7),
self.get_bottom_conditional_change_anims(0.7)
))
self.play(
ShowCreation(line),
Write(word, run_time = 1)
)
self.dither()
self.independence_word = word
self.independence_line = line
def relabel(self):
old_labels = self.sample_space[0].vertical_parts.labels
ignored_braces, new_top_labels = self.sample_space[0].get_top_braces_and_labels(
["P(B)", "P(\\overline B)"]
)
equation = TexMobject(
"P(B | A) = P(B)"
)
equation.scale(1.5)
equation.move_to(self.independence_word)
self.play(
Transform(old_labels, new_top_labels),
FadeOut(self.sample_space[1].vertical_parts.labels),
FadeOut(self.sample_space[1].vertical_parts.braces),
)
self.play(
self.independence_word.next_to, equation, UP, MED_LARGE_BUFF,
Write(equation)
)
self.dither()
self.equation = equation
def assume_independence(self):
everything = VGroup(*self.get_top_level_mobjects())
morty = Mortimer()
morty.scale(0.7)
morty.to_corner(DOWN+RIGHT)
bubble = ThoughtBubble(direction = RIGHT)
bubble.pin_to(morty)
bubble.set_fill(opacity = 0)
self.play(
FadeIn(morty),
everything.scale, 0.5,
everything.move_to, bubble.get_bubble_center(),
)
self.play(
morty.change, "hooray", everything,
ShowCreation(bubble)
)
self.dither()
self.play(Blink(morty))
self.dither()
self.morty = morty
def no_independence(self):
for part in self.sample_space.horizontal_parts:
part.vertical_parts.labels = None
self.play(*it.chain(
self.get_top_conditional_change_anims(0.9),
self.get_bottom_conditional_change_anims(0.5),
[
self.independence_word.fade, 0.7,
self.equation.fade, 0.7,
self.morty.change, "confused", self.sample_space,
FadeOut(self.independence_line)
]
))
self.dither()
class IntroduceBinomial(Scene):
CONFIG = {
"n" : 8,
"p" : 0.7,
}
def construct(self):
self.add_title()
self.add_bar_chart()
self.add_p_slider()
self.write_independence_assumption()
self.play_with_p_value(0.2, 0.5)
self.cross_out_assumption()
self.play_with_p_value(0.8, 0.4)
self.shift_weight_to_tails()
def add_title(self):
title = TextMobject("Binomial distribution")
title.scale(1.3)
title.to_edge(RIGHT)
title.shift(2*UP)
formula = TexMobject(
"P(X=", "k", ")=",
"{n \\choose k}",
"p", "^k",
"(1-", "p", ")", "^{n-", "k}",
arg_separator = ""
)
formula.highlight_by_tex("k", BLUE)
formula.highlight_by_tex("p", YELLOW)
choose_part = formula.get_part_by_tex("choose")
choose_part.highlight(WHITE)
choose_part[-2].highlight(BLUE)
formula.next_to(title, DOWN, MED_LARGE_BUFF)
self.formula = formula
self.title = title
self.add(title, formula)
def add_bar_chart(self):
n, p = self.n, self.p
dist = get_binomial_distribution(n, p)
chart = BarChart(
[dist(k) for k in range(n+1)],
bar_names = range(n+1),
)
chart.to_edge(LEFT)
self.bar_chart = chart
self.play(LaggedStart(
FadeIn, VGroup(*it.chain(*chart)),
run_time = 2
))
def add_p_slider(self):
interval = UnitInterval(color = LIGHT_GREY)
interval.scale_to_fit_width(4)
interval.next_to(
VGroup(self.bar_chart.x_axis, self.bar_chart.y_axis),
UP, MED_LARGE_BUFF
)
interval.add_numbers(0, 1)
triangle = RegularPolygon(
n=3, start_angle = -np.pi/2,
stroke_width = 0,
fill_color = YELLOW,
fill_opacity = 1,
)
triangle.scale_to_fit_height(0.25)
triangle.move_to(interval.number_to_point(self.p), DOWN)
label = TexMobject("p")
label.next_to(triangle, UP, SMALL_BUFF)
label.highlight(triangle.get_color())
self.p_slider = VGroup(interval, triangle, label)
self.play(Write(self.p_slider, run_time = 1))
def play_with_p_value(self, *values):
for value in values:
self.change_p(value)
self.dither()
def write_independence_assumption(self):
assumption = TextMobject("Independence assumption")
assumption.scale(1.2)
assumption.next_to(self.formula, DOWN, MED_LARGE_BUFF, LEFT)
assumption.highlight(GREEN_C)
self.play(Write(assumption, run_time = 2))
self.dither()
self.assumption = assumption
def cross_out_assumption(self):
cross = Cross(self.assumption)
cross.highlight(GREY)
self.bar_chart.save_state()
self.play(ShowCreation(cross))
self.play(self.bar_chart.fade, 0.7)
self.dither(2)
self.play(self.bar_chart.restore)
def shift_weight_to_tails(self):
chart = self.bar_chart
chart_copy = chart.copy()
dist = get_binomial_distribution(self.n, self.p)
values = np.array(map(dist, range(self.n+1)))
values += 0.1
values /= sum(values)
old_bars = chart.bars
old_bars.generate_target()
new_bars = chart_copy.bars
for bars, vect in (old_bars.target, LEFT), (new_bars, RIGHT):
for bar in bars:
corner = bar.get_corner(DOWN+vect)
bar.stretch(0.5, 0)
bar.move_to(corner, DOWN+vect)
old_bars.target.highlight(RED)
old_bars.target.fade()
self.play(
MoveToTarget(old_bars),
ReplacementTransform(
old_bars.copy().set_fill(opacity = 0),
new_bars
)
)
self.play(
chart_copy.change_bar_values, values
)
self.dither(2)
#####
def change_p(self, p):
interval, triangle, p_label = self.p_slider
alt_dist = get_binomial_distribution(self.n, p)
self.play(
ApplyMethod(
self.bar_chart.change_bar_values,
[alt_dist(k) for k in range(self.n+1)],
),
triangle.move_to, interval.number_to_point(p), DOWN,
MaintainPositionRelativeTo(p_label, triangle)
)
self.p = p
class IntroduceQuiz(PiCreatureScene):
def construct(self):
self.add_quiz()
self.ask_about_probabilities()
self.show_distribution()
self.show_single_question_probability()
def add_quiz(self):
quiz = self.get_example_quiz()
quiz.next_to(self.randy, UP+RIGHT)
self.play(
Write(quiz),
self.randy.change, "pondering", quiz
)
self.dither()
self.quiz = quiz
def ask_about_probabilities(self):
probabilities, abbreviated_probabilities = [
VGroup(*[
TexMobject(
"P(", s_tex, "=", str(score), ")", rhs
).highlight_by_tex_to_color_map({
str(score) : YELLOW,
"text" : GREEN,
})
for score in range(4)
])
for s_tex, rhs in [
("\\text{Score}", "= \\, ???"),
("\\text{S}", "")
]
]
for group in probabilities, abbreviated_probabilities:
group.arrange_submobjects(
DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
group.to_corner(UP+LEFT)
self.play(
LaggedStart(FadeIn, probabilities, run_time = 3),
self.quiz.scale_to_fit_height, 0.7*self.randy.get_height(),
self.quiz.next_to, self.randy, RIGHT,
self.randy.change, "confused", probabilities
)
self.dither()
self.probabilities = probabilities
self.abbreviated_probabilities = abbreviated_probabilities
def show_distribution(self):
dist = get_binomial_distribution(3, 0.7)
values = map(dist, range(4))
chart = BarChart(
values,
width = 7,
bar_names = range(4)
)
chart.to_edge(RIGHT)
for short_p, bar in zip(self.abbreviated_probabilities, chart.bars):
short_p.scale_to_fit_width(1.75*bar.get_width())
short_p.next_to(bar, UP)
self.play(
LaggedStart(Write, VGroup(
*filter(lambda m : m is not chart.bars, chart)
)),
)
self.play(*[
ReplacementTransform(
bar.copy().stretch_to_fit_height(0).move_to(bar.get_bottom()),
bar
)
for bar in chart.bars
])
self.play(*[
ReplacementTransform(p.copy(), short_p)
for p, short_p in zip(
self.probabilities,
self.abbreviated_probabilities,
)
])
self.dither()
self.bar_chart = chart
def show_single_question_probability(self):
prob = TexMobject(
"P(", "\\text{Can answer a given question}", ")",
"= 0.8"
)
prob.to_corner(UP+RIGHT)
prob.highlight_by_tex("text", GREEN)
rect = SurroundingRectangle(prob, buff = MED_SMALL_BUFF)
self.play(
Write(prob),
self.randy.change, "happy", prob
)
self.play(ShowCreation(rect))
self.dither()
self.single_question_probability = VGroup(
prob, rect
)
######
def create_pi_creature(self):
randy = Randolph()
randy.scale(0.7)
randy.to_corner(DOWN+LEFT)
self.randy = randy
return randy
def get_example_quiz(self):
return get_quiz(
"Define ``Brachistochrone'' ",
"Define ``Tautochrone'' ",
"Define ``Cycloid'' ",
)
class BreakDownQuestionPatterns(IntroduceQuiz):
def construct(self):
self.add_parts_from_last_scene()
self.break_down_possibilities()
self.count_patterns()
def add_parts_from_last_scene(self):
self.force_skipping()
IntroduceQuiz.construct(self)
self.revert_to_original_skipping_status()
chart_group = VGroup(
self.bar_chart,
self.abbreviated_probabilities
)
self.play(
self.single_question_probability.scale, 0.8,
self.single_question_probability.to_corner, UP+LEFT,
chart_group.scale, 0.7, chart_group.get_top(),
chart_group.to_edge, LEFT,
FadeOut(self.probabilities)
)
def break_down_possibilities(self):
slot_group_groups = VGroup(*[VGroup() for x in range(4)])
bool_lists = [[]]
while bool_lists:
bool_list = bool_lists.pop()
slot_group = self.get_slot_group(bool_list)
slot_group_groups[len(bool_list)].add(slot_group)
if len(bool_list) < 3:
bool_lists += [
list(bool_list) + [True],
list(bool_list) + [False],
]
group_group = slot_group_groups[0]
self.revert_to_original_skipping_status()
self.play(Write(group_group, run_time = 1))
self.dither()
for new_group_group in slot_group_groups[1:]:
self.play(Transform(group_group, new_group_group))
self.dither(2)
self.slot_groups = slot_group_groups[-1]
def count_patterns(self):
brace = Brace(self.slot_groups, LEFT)
count = TexMobject("2^3 = 8")
count.next_to(brace, LEFT)
self.play(
GrowFromCenter(brace),
Write(count)
)
self.dither()
#######
def get_slot_group(self, bool_list):
return get_slot_group(bool_list, include_qs = len(bool_list) < 3)
class AssociatePatternsWithScores(BreakDownQuestionPatterns):
CONFIG = {
"score_group_scale_val" : 0.8,
}
def construct(self):
self.add_slot_groups()
self.show_score_groups()
self.think_about_binomial_patterns()
def add_slot_groups(self):
self.slot_groups = VGroup(*map(
self.get_slot_group,
it.product(*[[True, False]]*3)
))
self.add(self.slot_groups)
self.remove(self.randy)
def show_score_groups(self):
score_groups = [VGroup() for x in range(4)]
scores = VGroup()
full_score_groups = VGroup()
for slot_group in self.slot_groups:
score_groups[sum(slot_group.bool_list)].add(slot_group)
for i, score_group in enumerate(score_groups):
score = TextMobject("Score", "=", str(i))
score.highlight_by_tex("Score", GREEN)
scores.add(score)
score_group.organized = score_group.deepcopy()
score_group.organized.arrange_submobjects(UP, buff = SMALL_BUFF)
score_group.organized.scale(self.score_group_scale_val)
brace = Brace(score_group.organized, LEFT)
score.next_to(brace, LEFT)
score.add(brace)
full_score_groups.add(VGroup(score, score_group.organized))
full_score_groups.arrange_submobjects(
DOWN, buff = MED_LARGE_BUFF,
aligned_edge = RIGHT
)
full_score_groups.to_edge(LEFT)
for score, score_group in zip(scores, score_groups):
score_group.save_state()
self.play(score_group.next_to, score_group, LEFT, MED_LARGE_BUFF)
self.dither()
self.play(
ReplacementTransform(
score_group.copy(), score_group.organized
),
LaggedStart(FadeIn, score, run_time = 1)
)
self.play(score_group.restore)
self.dither()
def think_about_binomial_patterns(self):
triangle = PascalsTriangle(
nrows = 5,
height = 3,
width = 3,
)
triangle.to_edge(UP+RIGHT)
row = VGroup(*[
triangle.coords_to_mobs[3][k]
for k in range(4)
])
self.randy.center().to_edge(DOWN)
bubble = ThoughtBubble()
bubble.add_content(triangle)
bubble.resize_to_content()
triangle.shift(SMALL_BUFF*(3*UP + RIGHT))
bubble.add(triangle)
bubble.next_to(self.randy, UP+RIGHT, SMALL_BUFF)
bubble.remove(triangle)
self.play(
FadeOut(self.slot_groups),
FadeIn(self.randy),
FadeIn(bubble)
)
self.play(
self.randy.change, "pondering",
LaggedStart(FadeIn, triangle, run_time = 4),
)
self.play(row.highlight, YELLOW)
self.dither(4)
class TemptingButWrongCalculation(BreakDownQuestionPatterns):
def construct(self):
self.add_title()
self.write_simple_product()
def add_title(self):
title = TextMobject("Tempting$\\dots$")
title.scale(1.5)
title.to_edge(UP)
self.add(title)
def write_simple_product(self):
lhs = TexMobject("P\\big(", "Filler Blah", "\\big)", "= ")
lhs.next_to(ORIGIN, UP+LEFT)
p_of = lhs.get_part_by_tex("P\\big(")
filler = lhs.get_part_by_tex("Filler")
rp = lhs.get_part_by_tex("\\big)")
slot_group = self.get_slot_group([True, True, False])
slot_group.replace(filler, dim_to_match = 0)
lhs.submobjects.remove(filler)
rhs = VGroup(*[
TexMobject("P(", "\\checkmark" if b else "\\times", ")")
for b in slot_group.bool_list
])
rhs.arrange_submobjects(RIGHT, SMALL_BUFF)
rhs.next_to(lhs, RIGHT, SMALL_BUFF)
for part, b in zip(rhs, slot_group.bool_list):
part.highlight_by_tex_to_color_map({
"checkmark" : GREEN,
"times" : RED,
})
brace = Brace(part, UP)
if b:
value = TexMobject("(0.8)")
else:
value = TexMobject("(0.2)")
value.highlight(part[1].get_color())
value.next_to(brace, UP)
part.brace = brace
part.value = value
question = TextMobject("What about correlations?")
question.next_to(rhs, DOWN, LARGE_BUFF)
self.play(
Write(lhs),
ShowCreation(slot_group.lines),
LaggedStart(FadeIn, slot_group.content, run_time = 3),
self.randy.change, "pondering"
)
self.dither(2)
for part, mob in zip(rhs, slot_group.content):
self.play(*[
ReplacementTransform(
mob.copy(), subpart,
path_arc = np.pi/6
)
for subpart, mob in zip(part, [
p_of, mob, rp
])
])
self.play(GrowFromCenter(part.brace))
self.play(FadeIn(part.value))
self.dither()
self.dither()
self.play(
Write(question),
self.randy.change, "confused"
)
self.dither(3)
class ThousandPossibleQuizzes(Scene):
CONFIG = {
"n_quiz_rows" : 25,
"n_quiz_cols" : 40,
"n_movers" : 100,
# "n_quiz_rows" : 5,
# "n_quiz_cols" : 8,
# "n_movers" : 4,
"quizzes_height" : 4,
}
def construct(self):
self.draw_all_quizzes()
self.show_division_by_first_question()
self.show_uncorrelated_division_by_second()
self.increase_second_correct_slice()
self.second_division_among_first_wrong()
self.show_that_second_is_still_80()
self.emphasize_disproportionate_divide()
self.show_third_question_results()
def draw_all_quizzes(self):
quizzes = self.get_thousand_quizzes()
title = TextMobject("$1{,}000$ possible quizzes")
title.scale(1.5)
title.next_to(quizzes, UP)
full_quizzes = VGroup(
get_quiz(
"Define ``Brachistochrone''",
"Define ``Tautochrone''",
"Define ``Cycloid''",
),
get_quiz(
"Define $\\dfrac{df}{dx}$",
"Define $\\displaystyle \\lim_{h \\to 0} f(h)$",
"Prove $\\dfrac{d(x^2)}{dx} = 2x$ ",
),
get_quiz(
"Find all primes $p$ \\\\ where $p+2$ is prime.",
"Find all primes $p$ \\\\ where $2^{p}-1$ is prime.",
"Solve $\\zeta(s) = 0$",
),
)
full_quizzes.arrange_submobjects(RIGHT)
target_quizzes = VGroup(*quizzes[:len(full_quizzes)])
self.add(full_quizzes)
self.dither()
self.play(
Transform(full_quizzes, target_quizzes),
FadeIn(title)
)
self.play(
LaggedStart(
FadeIn, quizzes,
run_time = 3,
lag_ratio = 0.2,
),
Animation(full_quizzes, remover = True)
)
self.dither()
self.quizzes = quizzes
self.title = title
def show_division_by_first_question(self):
n = int(0.8*len(self.quizzes))
top_split = VGroup(*self.quizzes[:n])
bottom_split = VGroup(*self.quizzes[n:])
for split, color, vect in (top_split, GREEN, UP), (bottom_split, RED, DOWN):
split.sort_submobjects(lambda p : p[0])
split.generate_target()
split.target.shift(MED_LARGE_BUFF*vect)
for quiz in split.target:
quiz[0].highlight(color)
labels = VGroup()
for num, b, split in (800, True, top_split), (200, False, bottom_split):
label = VGroup(
TexMobject(str(num)),
get_slot_group([b], buff = SMALL_BUFF, include_qs = False)
)
label.arrange_submobjects(DOWN)
label.next_to(split.target, LEFT, buff = LARGE_BUFF)
labels.add(label)
self.play(
FadeOut(self.title),
MoveToTarget(top_split),
MoveToTarget(bottom_split),
)
for label in labels:
self.play(FadeIn(label))
self.dither()
self.splits = VGroup(top_split, bottom_split)
self.q1_split_labels = labels
def show_uncorrelated_division_by_second(self):
top_split = self.splits[0]
top_label = self.q1_split_labels[0]
n = int(0.8*len(top_split))
left_split = VGroup(*top_split[:n])
right_split = VGroup(*top_split[n:])
for split, color in (left_split, GREEN_E), (right_split, RED_E):
split.generate_target()
for quiz in split.target:
quiz[1].highlight(color)
left_split.target.shift(LEFT)
left_label = VGroup(
TexMobject("(0.8)", "800 =", "640"),
get_slot_group([True, True], buff = SMALL_BUFF, include_qs = False)
)
left_label.arrange_submobjects(RIGHT, buff = MED_LARGE_BUFF)
left_label.next_to(left_split.target, UP)
self.play(
MoveToTarget(left_split),
MaintainPositionRelativeTo(top_label, left_split),
MoveToTarget(right_split),
)
self.play(FadeIn(left_label))
self.play(LaggedStart(
ApplyMethod, left_split,
lambda m : (m.highlight, YELLOW),
rate_func = there_and_back,
lag_ratio = 0.2,
))
self.dither()
self.top_left_label = left_label
self.top_splits = VGroup(left_split, right_split)
def increase_second_correct_slice(self):
left_split, right_split = self.top_splits
left_label = self.top_left_label
left_label_equation = left_label[0]
movers = VGroup(*right_split[:self.n_movers])
movers.generate_target()
for quiz in movers.target:
quiz[1].highlight(left_split[0][1].get_color())
movers.target.shift(LEFT)
new_equation = TexMobject("(0.925)", "800 =", "740")
for i in 0, 2:
new_equation[i].highlight(YELLOW)
new_equation.move_to(left_label_equation)
self.play(
MoveToTarget(
movers,
submobject_mode = "lagged_start",
lag_factor = 4,
run_time = 3,
),
Transform(left_label_equation, new_equation)
)
self.dither(2)
self.play(Indicate(left_label_equation[0]))
self.dither()
left_split.add(*movers)
right_split.remove(*movers)
self.top_left_split = left_split
self.top_right_split = right_split
self.top_movers = movers
self.top_equation = left_label_equation
def second_division_among_first_wrong(self):
top_label, bottom_label = self.q1_split_labels
top_split, bottom_split = self.splits
top_left_label = self.top_left_label
top_group = VGroup(top_split, top_left_label, top_label)
n = int(0.8*len(bottom_split))
left_split = VGroup(*bottom_split[:n])
right_split = VGroup(*bottom_split[n:])
for split, color in (left_split, GREEN_E), (right_split, RED_E):
split.generate_target()
for quiz in split.target:
quiz[1].highlight(color)
left_split.target.shift(LEFT)
movers = VGroup(*left_split[-self.n_movers:])
movers.generate_target()
for quiz in movers.target:
quiz[1].highlight(right_split.target[0][1].get_color())
equation = TexMobject("(0.8)", "200 = ", "160")
slot_group = get_slot_group([False, True], buff = SMALL_BUFF, include_qs = False)
label = VGroup(equation, slot_group)
label.arrange_submobjects(DOWN, buff = SMALL_BUFF)
label.next_to(left_split.target, UP, SMALL_BUFF, LEFT)
alt_equation = TexMobject("(0.3)", "200 = ", "60")
for i in 0, 2:
alt_equation[i].highlight(YELLOW)
alt_equation.move_to(equation)
self.play(top_group.to_edge, UP, SMALL_BUFF)
self.play(
bottom_label.shift, LEFT,
*map(MoveToTarget, [left_split, right_split])
)
self.play(FadeIn(label))
self.dither()
self.play(
MoveToTarget(
movers,
submobject_mode = "lagged_start",
run_time = 3,
),
Transform(equation, alt_equation)
)
self.dither()
left_split.remove(*movers)
right_split.add(*movers)
self.bottom_left_split = left_split
self.bottom_right_split = right_split
self.bottom_movers = movers
self.bottom_equation = equation
self.bottom_left_label = label
def show_that_second_is_still_80(self):
second_right = VGroup(
self.bottom_left_split, self.top_left_split
)
second_wrong = VGroup(
self.bottom_right_split, self.top_right_split
)
rects = VGroup(*[
SurroundingRectangle(mob, buff = SMALL_BUFF)
for mob in second_right
])
num1 = self.top_equation[-1].copy()
num2 = self.bottom_equation[-1].copy()
equation = TexMobject("740", "+", "60", "=", "800")
for tex in "740", "60":
equation.highlight_by_tex(tex, YELLOW)
slot_group = get_slot_group([True, True])
slot_group.content[0].set_fill(BLACK, 0)
label = VGroup(equation, slot_group)
label.arrange_submobjects(DOWN)
label.next_to(self.quizzes, LEFT, LARGE_BUFF)
self.play(
FadeOut(self.q1_split_labels),
ShowCreation(rects)
)
self.play(
FadeIn(slot_group),
Transform(
num1, equation[0],
rate_func = squish_rate_func(smooth, 0, 0.7),
),
Transform(
num2, equation[2],
rate_func = squish_rate_func(smooth, 0.3, 1),
),
run_time = 2
)
self.play(
Write(equation),
*map(Animation, [num1, num2])
)
self.remove(num1, num2)
self.dither()
self.play(FadeOut(rects))
def emphasize_disproportionate_divide(self):
top_movers = self.top_movers
bottom_movers = self.bottom_movers
both_movers = VGroup(top_movers, bottom_movers)
both_movers.save_state()
top_movers.target = bottom_movers.copy().shift(LEFT)
bottom_movers.target = top_movers.copy().shift(RIGHT)
for quiz in top_movers.target:
quiz[0].highlight(RED)
for quiz in bottom_movers.target:
quiz[0].highlight(GREEN)
line = Line(UP, DOWN, color = YELLOW)
line.scale_to_fit_height(self.quizzes.get_height())
line.next_to(bottom_movers.target, LEFT, MED_LARGE_BUFF, UP)
self.revert_to_original_skipping_status()
self.play(*map(MoveToTarget, both_movers))
self.play(ShowCreation(line))
self.play(FadeOut(line))
self.dither()
self.play(both_movers.restore)
self.dither()
def show_third_question_results(self):
all_splits = VGroup(
self.top_left_split, self.top_right_split,
self.bottom_left_split, self.bottom_right_split
)
proportions = [0.9, 0.8, 0.8, 0.4]
for split, prop in zip(all_splits, proportions):
n = int(prop*len(split))
split.sort_submobjects(lambda p : -p[1])
split.generate_target()
top_part = VGroup(*split.target[:n])
top_part.shift(MED_SMALL_BUFF*UP)
bottom_part = VGroup(*split.target[n:])
bottom_part.shift(MED_SMALL_BUFF*DOWN)
for quiz in top_part:
quiz[-1].highlight(GREEN)
for quiz in bottom_part:
quiz[-1].highlight(RED)
split = self.top_left_split
n_all_right = int(proportions[0]*len(split))
all_right = VGroup(*split[:n_all_right])
self.play(
FadeOut(self.top_left_label),
FadeOut(self.bottom_left_label),
)
for split in all_splits:
self.play(MoveToTarget(split))
self.dither()
self.play(LaggedStart(
ApplyMethod, all_right,
lambda m : (m.highlight, YELLOW),
rate_func = there_and_back,
lag_ratio = 0.2,
run_time = 2
))
self.dither(2)
#####
def get_thousand_quizzes(self):
rows = VGroup()
for x in xrange(self.n_quiz_rows):
quiz = VGroup(*[
Rectangle(
height = SMALL_BUFF,
width = 0.5*SMALL_BUFF
)
for x in range(3)
])
quiz.arrange_submobjects(RIGHT, buff = 0)
quiz.set_stroke(width = 0)
quiz.set_fill(LIGHT_GREY, 1)
row = VGroup(*[quiz.copy() for y in range(self.n_quiz_cols)])
row.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
rows.add(row)
rows.arrange_submobjects(DOWN, buff = SMALL_BUFF)
quizzes = VGroup(*it.chain(*rows))
quizzes.scale_to_fit_height(self.quizzes_height)
quizzes.to_edge(RIGHT)
quizzes.shift(MED_LARGE_BUFF*DOWN)
return quizzes
class AccurateProductRule(SampleSpaceScene, ThreeDScene):
def construct(self):
self.setup_terms()
self.add_sample_space()
self.dither()
self.show_first_division()
self.show_second_division()
self.move_to_third_dimension()
self.show_final_probability()
self.show_confusion()
def setup_terms(self):
filler_tex = "Filler"
lhs = TexMobject("P(", filler_tex, ")", "=")
p1 = TexMobject("P(", filler_tex, ")")
p2 = TexMobject("P(", filler_tex, "|", filler_tex, ")")
p3 = TexMobject("P(", filler_tex, "|", filler_tex, ")")
terms = VGroup(lhs, p1, p2, p3)
terms.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
terms.to_edge(UP, buff = LARGE_BUFF)
kwargs = {"buff" : SMALL_BUFF, "include_qs" : False}
slot_group_lists = [
[get_slot_group([True, True, False], **kwargs)],
[get_slot_group([True], **kwargs)],
[
get_slot_group([True, True], **kwargs),
get_slot_group([True], **kwargs),
],
[
get_slot_group([True, True, False], **kwargs),
get_slot_group([True, True], **kwargs),
],
]
for term, slot_group_list in zip(terms, slot_group_lists):
parts = term.get_parts_by_tex(filler_tex)
for part, slot_group in zip(parts, slot_group_list):
slot_group.replace(part, dim_to_match = 0)
term.submobjects[term.index_of_part(part)] = slot_group
# terms[2][1].content[0].set_fill(BLACK, 0)
# VGroup(*terms[3][1].content[:2]).set_fill(BLACK, 0)
value_texs = ["0.8", ">0.8", "<0.2"]
for term, tex in zip(terms[1:], value_texs):
term.value = TexMobject(tex)
term.value.next_to(term, UP)
self.terms = terms
self.add(terms[0])
def add_sample_space(self):
SampleSpaceScene.add_sample_space(self, height = 4, width = 5)
self.sample_space.to_edge(DOWN)
def show_first_division(self):
space = self.sample_space
space.divide_horizontally(
[0.8], colors = [GREEN_E, RED_E]
)
space.horizontal_parts.fade(0.1)
top_label = self.terms[1].copy()
bottom_label = top_label.copy()
slot_group = get_slot_group([False], buff = SMALL_BUFF, include_qs = False)
slot_group.replace(bottom_label[1])
Transform(bottom_label[1], slot_group).update(1)
braces_and_labels = space.get_side_braces_and_labels(
[top_label, bottom_label]
)
self.play(
FadeIn(space.horizontal_parts),
FadeIn(braces_and_labels)
)
self.play(ReplacementTransform(
top_label.copy(), self.terms[1]
))
self.dither()
self.play(Write(self.terms[1].value))
self.dither()
space.add(braces_and_labels)
self.top_part = space.horizontal_parts[0]
def show_second_division(self):
space = self.sample_space
top_part = self.top_part
green_red_mix = average_color(GREEN_E, RED_E)
top_part.divide_vertically(
[0.9], colors = [GREEN_E, green_red_mix]
)
label = self.terms[2].deepcopy()
braces_and_labels = top_part.get_top_braces_and_labels(
labels = [label]
)
self.play(
FadeIn(top_part.vertical_parts),
FadeIn(braces_and_labels)
)
self.play(ReplacementTransform(
label.copy(), self.terms[2]
))
self.dither()
self.play(Write(self.terms[2].value))
self.dither()
space.add(braces_and_labels)
self.top_left_part = top_part.vertical_parts[0]
def move_to_third_dimension(self):
space = self.sample_space
part = self.top_left_part
cubes = VGroup(
Cube(fill_color = RED_E),
Cube(fill_color = GREEN_E),
)
cubes.set_fill(opacity = 0)
cubes.stretch_to_fit_width(part.get_width())
cubes.stretch_to_fit_height(part.get_height())
cubes[1].move_to(part, IN)
cubes[0].stretch(0.2, 2)
cubes[0].move_to(cubes[1].get_edge_center(OUT), IN)
space.add(cubes)
self.play(
space.rotate, 0.9*np.pi/2, LEFT,
space.rotate, np.pi/12, UP,
space.to_corner, DOWN+RIGHT, LARGE_BUFF
)
space.remove(cubes)
self.play(
cubes[0].set_fill, None, 1,
cubes[0].set_stroke, WHITE, 1,
cubes[1].set_fill, None, 0.5,
cubes[1].set_stroke, WHITE, 1,
)
self.dither()
self.cubes = cubes
def show_final_probability(self):
cube = self.cubes[0]
face = cube[2]
points = face.get_anchors()
line = Line(points[2], points[3])
line.set_stroke(YELLOW, 8)
brace = Brace(line, LEFT)
label = self.terms[3].copy()
label.next_to(brace, LEFT)
self.play(
GrowFromCenter(brace),
FadeIn(label),
)
self.dither()
self.play(ReplacementTransform(
label.copy(), self.terms[3]
))
self.dither()
def show_confusion(self):
randy = Randolph()
randy.to_corner(DOWN+LEFT)
self.play(FadeIn(randy))
self.play(randy.change, "confused", self.terms)
self.play(randy.look_at, self.cubes)
self.play(Blink(randy))
self.play(randy.look_at, self.terms)
self.dither()
class ShowAllEightConditionals(Scene):
def construct(self):
self.show_all_conditionals()
self.suggest_independence()
def show_all_conditionals(self):
equations = VGroup()
filler_tex = "Filler"
for bool_list in it.product(*[[True, False]]*3):
equation = TexMobject(
"P(", filler_tex, ")", "=",
"P(", filler_tex, ")",
"P(", filler_tex, "|", filler_tex, ")",
"P(", filler_tex, "|", filler_tex, ")",
)
sub_bool_lists = [
bool_list[:n] for n in 3, 1, 2, 1, 3, 2
]
parts = equation.get_parts_by_tex(filler_tex)
for part, sub_list in zip(parts, sub_bool_lists):
slot_group = get_slot_group(
sub_list,
buff = SMALL_BUFF,
include_qs = False
)
slot_group.replace(part, dim_to_match = 0)
index = equation.index_of_part(part)
equation.submobjects[index] = slot_group
equations.add(equation)
equations.arrange_submobjects(DOWN)
rect = SurroundingRectangle(
VGroup(*equations[0][7:]+equations[-1][7:]),
buff = SMALL_BUFF
)
rect.shift(0.5*SMALL_BUFF*RIGHT)
self.play(LaggedStart(
FadeIn, equations,
run_time = 5,
lag_ratio = 0.3
))
self.dither()
self.play(ShowCreation(rect, run_time = 2))
self.play(FadeOut(rect))
self.dither()
def suggest_independence(self):
full_screen_rect = FullScreenFadeRectangle()
randy = Randolph()
randy.to_corner(DOWN+LEFT)
self.play(
FadeIn(full_screen_rect),
FadeIn(randy)
)
self.play(PiCreatureSays(
randy, "Let's just assume \\\\ independence.",
target_mode = "shruggie"
))
self.play(Blink(randy))
self.dither()
class ShowIndependenceSymbolically(Scene):
def construct(self):
filler_tex = "Filler"
rhs = TexMobject("=", "0.8")
rhs.highlight_by_tex("0.8", YELLOW)
rhs.next_to(ORIGIN, RIGHT, LARGE_BUFF)
lhs = TexMobject("P(", filler_tex, "|", filler_tex, ")")
lhs.next_to(rhs, LEFT)
VGroup(lhs, rhs).scale(1.5)
for part in lhs.get_parts_by_tex(filler_tex):
slot_group = get_slot_group(
[True, True, True],
buff = SMALL_BUFF,
include_qs = False,
)
slot_group.replace(part, dim_to_match = 0)
lhs.submobjects[lhs.index_of_part(part)] = slot_group
VGroup(*lhs[1].content[:2]).set_fill(BLACK, 0)
condition = lhs[3]
condition.content[2].set_fill(BLACK, 0)
bool_lists = [
[False], [True, False], [False, True], [True],
]
arrow = Arrow(UP, DOWN)
arrow.next_to(condition, UP)
arrow.highlight(RED)
words = TextMobject("Doesn't matter")
words.highlight(RED)
words.next_to(arrow, UP)
self.add(rhs, lhs, arrow, words)
self.dither()
for bool_list in bool_lists:
slot_group = get_slot_group(bool_list, SMALL_BUFF, False)
slot_group.replace(condition)
slot_group.move_to(condition, DOWN)
self.play(Transform(condition, slot_group))
self.dither()
class ComputeProbabilityOfOneWrong(Scene):
CONFIG = {
"score" : 2,
"final_result_rhs_tex" : [
"3", "(0.8)", "^2", "(0.2)", "=", "0.384",
],
"default_bool" : True,
"default_p" : "0.8",
"default_q" : "0.2",
}
def construct(self):
self.show_all_three_patterns()
self.show_final_result()
def show_all_three_patterns(self):
probabilities = VGroup()
point_8s = VGroup()
point_2s = VGroup()
for i in reversed(range(3)):
bool_list = [self.default_bool]*3
bool_list[i] = not self.default_bool
probs = ["(%s)"%self.default_p]*3
probs[i] = "(%s)"%self.default_q
lhs = get_probability_of_slot_group(bool_list)
rhs = TexMobject("=", *probs)
rhs.highlight_by_tex("0.8", GREEN)
rhs.highlight_by_tex("0.2", RED)
point_8s.add(*rhs.get_parts_by_tex("0.8"))
point_2s.add(*rhs.get_parts_by_tex("0.2"))
rhs.next_to(lhs, RIGHT)
probabilities.add(VGroup(lhs, rhs))
probabilities.arrange_submobjects(DOWN, buff = LARGE_BUFF)
probabilities.center()
self.play(Write(probabilities[0]))
self.dither(2)
for i in range(2):
self.play(ReplacementTransform(
probabilities[i].copy(),
probabilities[i+1]
))
self.dither()
for group in point_8s, point_2s:
self.play(LaggedStart(
Indicate, group,
rate_func = there_and_back,
lag_ratio = 0.7
))
self.dither()
def show_final_result(self):
result = TexMobject(
"P(", "\\text{Score} = %s"%self.score, ")", "=",
*self.final_result_rhs_tex
)
result.highlight_by_tex_to_color_map({
"0.8" : GREEN,
"0.2" : RED,
"Score" : YELLOW,
})
result[-1].highlight(YELLOW)
result.highlight_by_tex("0.8", GREEN)
result.highlight_by_tex("0.2", RED)
result.to_edge(UP)
self.play(Write(result))
self.dither()
class ComputeProbabilityOfOneRight(ComputeProbabilityOfOneWrong):
CONFIG = {
"score" : 1,
"final_result_rhs_tex" : [
"3", "(0.8)", "(0.2)", "^2", "=", "0.096",
],
"default_bool" : False,
"default_p" : "0.2",
"default_q" : "0.8",
}
class ShowFullDistribution(Scene):
def construct(self):
self.add_scores_one_and_two()
self.add_scores_zero_and_three()
self.show_bar_chart()
self.compare_to_binomial_pattern()
self.show_alternate_values_of_p()
def add_scores_one_and_two(self):
scores = VGroup(
TexMobject(
"P(", "\\text{Score} = 0", ")",
"=", "(0.2)", "^3",
"=", "0.008",
),
TexMobject(
"P(", "\\text{Score} = 1", ")",
"=", "3", "(0.8)", "(0.2)", "^2",
"=", "0.096",
),
TexMobject(
"P(", "\\text{Score} = 2", ")",
"=", "3", "(0.8)", "^2", "(0.2)",
"=", "0.384",
),
TexMobject(
"P(", "\\text{Score} = 3", ")",
"=", "(0.8)", "^3",
"=", "0.512",
),
)
scores.arrange_submobjects(
DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
scores.shift(MED_LARGE_BUFF*UP)
scores.to_edge(LEFT)
for score in scores:
score.highlight_by_tex_to_color_map({
"0.8" : GREEN,
"0.2" : RED,
})
score[-1].highlight(YELLOW)
self.add(*scores[1:3])
self.scores = scores
def add_scores_zero_and_three(self):
self.p_slot_groups = VGroup()
self.dither()
self.add_edge_score(0, UP, False)
self.add_edge_score(3, DOWN, True)
def add_edge_score(self, index, vect, q_bool):
score = self.scores[index]
prob = VGroup(*score[:3])
brace = Brace(prob, vect)
p_slot_group = get_probability_of_slot_group([q_bool]*3)
p_slot_group.next_to(brace, vect)
group = VGroup(*it.chain(p_slot_group, brace, score))
self.play(LaggedStart(
FadeIn, group,
run_time = 2,
lag_ratio = 0.7,
))
self.dither(2)
self.p_slot_groups.add(brace, p_slot_group)
def show_bar_chart(self):
p_terms = VGroup()
to_fade = VGroup(self.p_slot_groups)
value_mobs = VGroup()
for score in self.scores:
p_terms.add(VGroup(*score[:3]))
to_fade.add(VGroup(*score[3:-1]))
value_mobs.add(score[-1])
dist = get_binomial_distribution(3, 0.8)
values = map(dist, range(4))
chart = BarChart(
values, bar_names = range(4),
)
chart.shift(DOWN)
new_p_terms = VGroup(*[
TexMobject("P(", "S=%d"%k, ")")
for k in range(4)
])
for term, bar in zip(new_p_terms, chart.bars):
term[1].highlight(YELLOW)
term.scale_to_fit_width(1.5*bar.get_width())
term.next_to(bar, UP)
self.play(
ReplacementTransform(
value_mobs, chart.bars,
submobject_mode = "lagged_start",
run_time = 2
)
)
self.play(
LaggedStart(FadeIn, VGroup(*it.chain(*[
submob
for submob in chart
if submob is not chart.bars
]))),
Transform(p_terms, new_p_terms),
FadeOut(to_fade),
)
self.dither(2)
chart.bar_top_labels = p_terms
chart.add(p_terms)
self.bar_chart = chart
def compare_to_binomial_pattern(self):
dist = get_binomial_distribution(3, 0.5)
values = map(dist, range(4))
alt_chart = BarChart(values)
alt_chart.move_to(self.bar_chart)
bars = alt_chart.bars
bars.set_fill(GREY, opacity = 0.5)
vect = 4*UP
bars.shift(vect)
nums = VGroup(*map(TexMobject, map(str, [1, 3, 3, 1])))
for num, bar in zip(nums, bars):
num.next_to(bar, UP)
bars_copy = bars.copy()
self.play(
LaggedStart(FadeIn, bars),
LaggedStart(FadeIn, nums),
)
self.dither(2)
self.play(bars_copy.shift, -vect)
self.play(ReplacementTransform(
bars_copy, self.bar_chart.bars
))
self.dither(2)
self.play(
VGroup(self.bar_chart, bars, nums).to_edge, LEFT
)
self.alt_bars = bars
self.alt_bars_labels = nums
def show_alternate_values_of_p(self):
new_prob = TexMobject(
"P(", "\\text{Correct}", ")", "=", "0.8"
)
new_prob.highlight_by_tex("Correct", GREEN)
new_prob.shift(SPACE_WIDTH*RIGHT/2)
new_prob.to_edge(UP)
alt_ps = 0.5, 0.65, 0.25
alt_rhss = VGroup()
alt_charts = VGroup()
for p in alt_ps:
rhs = TexMobject(str(p))
rhs.highlight(YELLOW)
rhs.move_to(new_prob[-1])
alt_rhss.add(rhs)
dist = get_binomial_distribution(3, p)
values = map(dist, range(4))
chart = self.bar_chart.copy()
chart.change_bar_values(values)
for label, bar in zip(chart.bar_top_labels, chart.bars):
label.next_to(bar, UP)
alt_charts.add(chart)
self.play(FadeIn(new_prob))
self.play(Transform(new_prob[-1], alt_rhss[0]))
point_5_probs = self.show_point_5_probs(new_prob)
self.dither()
self.play(Transform(self.bar_chart, alt_charts[0]))
self.dither()
self.play(FadeOut(point_5_probs))
for rhs, chart in zip(alt_rhss, alt_charts)[1:]:
self.play(Transform(new_prob[-1], rhs))
self.play(Transform(self.bar_chart, chart))
self.dither(2)
def show_point_5_probs(self, mob):
probs = VGroup()
last = mob
for k in range(4):
buff = MED_LARGE_BUFF
for indices in it.combinations(range(3), k):
bool_list = np.array([False]*3)
bool_list[list(indices)] = True
prob = get_probability_of_slot_group(bool_list)
rhs = TexMobject("= (0.5)^3")
rhs.next_to(prob, RIGHT)
prob.add(rhs)
prob.scale(0.9)
prob.next_to(last, DOWN, buff)
probs.add(prob)
last = prob
buff = SMALL_BUFF
self.play(LaggedStart(FadeIn, probs))
self.dither()
return probs
class ProbablyWrong(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Probably wrong!",
run_time = 1,
)
self.change_student_modes(
*["angry"]*3,
run_time = 1
)
self.dither()
class ShowTrueDistribution(PiCreatureScene):
def construct(self):
self.remove(self.randy)
self.add_title()
self.show_distributions()
self.show_emotion()
self.imagine_score_0()
def add_title(self):
title = TexMobject("P(", "\\text{Correct}", ")", "=", "0.65")
title.to_edge(UP)
title.highlight_by_tex("Correct", GREEN)
self.add(title)
self.title = title
def show_distributions(self):
dist = get_binomial_distribution(3, 0.65)
values = np.array(map(dist, range(4)))
alt_values = values + [0.2, 0, 0, 0.2]
alt_values /= sum(alt_values)
chart = BarChart(values, bar_names = range(4))
bars = chart.bars
old_bars = bars.copy()
arrows = VGroup()
for bar, old_bar in zip(bars, old_bars):
for mob, vect in (bar, RIGHT), (old_bar, LEFT):
mob.generate_target()
mob.target.do_about_point(
mob.get_corner(DOWN+vect),
mob.target.stretch, 0.5, 0
)
old_bar.target.highlight(average_color(RED_E, BLACK))
old_bar.target.set_stroke(width = 0)
arrow = Arrow(ORIGIN, UP, buff = 0, color = GREEN)
arrow.move_to(bar.get_bottom())
arrow.shift(3*UP)
arrows.add(arrow)
for arrow in arrows[1:3]:
arrow.rotate_in_place(np.pi)
arrow.highlight(RED)
arrows.gradient_highlight(BLUE, YELLOW)
self.add(chart)
self.play(*map(MoveToTarget, it.chain(bars, old_bars)))
self.play(
chart.change_bar_values, alt_values,
*map(ShowCreation, arrows)
)
self.dither(2)
self.bar_chart = chart
self.old_bars = old_bars
def show_emotion(self):
randy = self.randy
self.play(FadeIn(randy))
self.play(randy.change, "sad")
self.play(Blink(randy))
def imagine_score_0(self):
prob_rect = SurroundingRectangle(self.title[-1])
bar_rect = SurroundingRectangle(VGroup(
self.bar_chart.bars[0], self.old_bars[0],
self.bar_chart.bar_labels[0],
))
self.play(ShowCreation(prob_rect))
self.dither()
self.play(ReplacementTransform(
prob_rect, bar_rect
))
self.dither()
self.play(FadeOut(bar_rect))
#####
def create_pi_creature(self):
self.randy = Randolph()
self.randy.to_corner(DOWN+LEFT)
return self.randy
class TeacherAssessingLiklihoodOfZero(TeacherStudentsScene):
def construct(self):
self.add_title()
self.fade_other_students()
self.show_independence_probability()
self.teacher_reacts()
def add_title(self):
title = TexMobject("P(", "\\text{Correct}", ")", "=", "0.65")
title.to_edge(UP)
title.highlight_by_tex("Correct", GREEN)
q_mark = TexMobject("?")
q_mark.next_to(title[-2], UP, SMALL_BUFF)
title.add(q_mark)
self.add(title)
self.title = title
def fade_other_students(self):
for student in self.students[0::2]:
student.fade(0.7)
self.pi_creatures.remove(student)
def show_independence_probability(self):
prob = get_probability_of_slot_group(3*[False])
rhs = TexMobject("=", "(0.35)", "^3", "\\approx 4.3\\%")
rhs.highlight_by_tex("0.35", RED)
rhs.next_to(prob, RIGHT)
prob.add(rhs)
prob.next_to(self.teacher, UP+LEFT)
words = TextMobject("Assuming independence")
words.next_to(prob, UP)
self.play(
self.teacher.change, "raise_right_hand",
FadeIn(words),
Write(prob)
)
self.dither()
self.ind_group = VGroup(prob, words)
def teacher_reacts(self):
ind_group = self.ind_group
box = SurroundingRectangle(ind_group)
box.set_stroke(WHITE, 0)
ind_group.add(box)
ind_group.generate_target()
ind_group.target.scale(0.7)
ind_group.target.to_corner(UP+RIGHT, MED_SMALL_BUFF)
ind_group.target[-1].set_stroke(WHITE, 2)
randy = self.students[1]
self.teacher_says(
"Highly unlikely",
target_mode = "sassy",
added_anims = [MoveToTarget(ind_group)],
run_time = 2,
)
self.play(randy.change, "sad")
self.dither(2)
self.play(
RemovePiCreatureBubble(
self.teacher, target_mode = "guilty",
),
PiCreatureSays(randy, "Wait!", target_mode = "surprised"),
run_time = 1
)
self.dither(1)
class CorrelationsWith35Percent(ThousandPossibleQuizzes):
def construct(self):
self.add_top_calculation()
self.show_first_split()
self.show_second_split()
self.show_third_split()
self.comment_on_final_size()
def add_top_calculation(self):
equation = VGroup(
get_probability_of_slot_group(3*[False]),
TexMobject("="),
get_probability_of_slot_group([False]),
get_probability_of_slot_group(2*[False], [False]),
get_probability_of_slot_group(3*[False], 2*[False]),
)
equation.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
equation.to_edge(UP)
self.add(equation)
self.equation = equation
def show_first_split(self):
quizzes = self.get_thousand_quizzes()
n = int(0.65*len(quizzes))
top_part = VGroup(*quizzes[:n])
bottom_part = VGroup(*quizzes[n:])
parts = [top_part, bottom_part]
for part, color in zip(parts, [GREEN, RED]):
part.generate_target()
for quiz in part.target:
quiz[0].highlight(color)
top_part.target.shift(UP)
brace = Brace(bottom_part, LEFT)
prop = TexMobject("0.35")
prop.next_to(brace, LEFT)
term = self.equation[2]
term_brace = Brace(term, DOWN)
self.add(quizzes)
self.dither()
self.play(
GrowFromCenter(brace),
FadeIn(prop),
*map(MoveToTarget, parts)
)
self.dither()
self.play(
top_part.fade, 0.8,
Transform(brace, term_brace),
prop.next_to, term_brace, DOWN,
)
self.dither()
self.quizzes = bottom_part
self.quizzes.sort_submobjects(lambda p : p[0])
def show_second_split(self):
n = int(0.45*len(self.quizzes))
left_part = VGroup(*self.quizzes[:n])
right_part = VGroup(*self.quizzes[n:])
parts = [left_part, right_part]
for part, color in zip(parts, [GREEN, RED_E]):
part.generate_target()
for quiz in part.target:
quiz[1].highlight(color)
left_part.target.shift(LEFT)
brace = Brace(right_part, UP)
prop = TexMobject(">0.35")
prop.next_to(brace, UP)
term = self.equation[3]
term_brace = Brace(term, DOWN)
self.play(
GrowFromCenter(brace),
FadeIn(prop),
*map(MoveToTarget, parts)
)
self.dither()
self.play(
Transform(brace, term_brace),
prop.next_to, term_brace, DOWN
)
self.play(left_part.fade, 0.8)
self.quizzes = right_part
self.quizzes.sort_submobjects(lambda p : -p[1])
def show_third_split(self):
quizzes = self.quizzes
n = int(0.22*len(quizzes))
top_part = VGroup(*quizzes[:n])
bottom_part = VGroup(*quizzes[n:])
parts = [top_part, bottom_part]
for part, color in zip(parts, [GREEN, RED_B]):
part.generate_target()
for quiz in part.target:
quiz[2].highlight(color)
top_part.target.shift(0.5*UP)
brace = Brace(bottom_part, LEFT)
prop = TexMobject("\\gg 0.35")
prop.next_to(brace, LEFT)
term = self.equation[4]
term_brace = Brace(term, DOWN)
self.play(
GrowFromCenter(brace),
FadeIn(prop),
*map(MoveToTarget, parts)
)
self.dither()
self.play(
Transform(brace, term_brace),
prop.next_to, term_brace, DOWN,
)
self.play(top_part.fade, 0.8)
self.dither()
self.quizzes = bottom_part
def comment_on_final_size(self):
rect = SurroundingRectangle(self.quizzes)
words = TextMobject(
"Much more than ", "$(0.35)^3 \\approx 4.3\\%$"
)
words.next_to(rect, LEFT)
self.play(
ShowCreation(rect),
FadeIn(words)
)
self.dither()
class NameBinomial(Scene):
CONFIG = {
"flip_indices" : [1, 2, 4, 5, 7, 9],
}
def construct(self):
self.name_distribution()
self.add_quiz_questions()
self.change_to_gender()
self.change_bar_chart_for_gender_example()
self.point_out_example_input()
self.write_probability_of_girl()
self.think_through_probabilities()
def name_distribution(self):
ns = [3, 10]
p = 0.65
charts = VGroup()
for n in ns:
dist = get_binomial_distribution(n, p)
values = map(dist, range(n+1))
chart = BarChart(values, bar_names = range(n+1))
chart.to_edge(LEFT)
charts.add(chart)
probability = TexMobject(
"P(", "\\checkmark", ")", "=", str(p)
)
probability.highlight_by_tex("checkmark", GREEN)
probability.move_to(charts, UP)
title = TextMobject("``Binomial distribution''")
title.next_to(charts, UP)
title.to_edge(UP)
formula = TexMobject(
"P(X=", "k", ")=",
"{n \\choose k}",
"p", "^k",
"(1-", "p", ")", "^{n-", "k}",
arg_separator = ""
)
formula.highlight_by_tex("p", YELLOW)
formula.highlight_by_tex("k", GREEN)
choose_part = formula.get_part_by_tex("choose")
choose_part.highlight(WHITE)
choose_part[-2].highlight(GREEN)
formula.to_corner(UP+RIGHT)
self.add(charts[0], probability)
self.dither()
self.play(Write(title))
self.dither()
self.play(ReplacementTransform(*charts))
self.play(Write(formula))
self.dither()
self.play(
formula.scale, 0.7,
formula.next_to, charts, DOWN,
)
self.chart = charts[1]
self.probability = probability
self.title = title
self.formula = formula
def add_quiz_questions(self):
n = 10
checkmarks = VGroup(*[
TexMobject("\\checkmark").highlight(GREEN)
for x in range(n)
])
checkmarks.arrange_submobjects(DOWN, buff = 0.3)
crosses = VGroup()
arrows = VGroup()
for checkmark in checkmarks:
cross = TexMobject("\\times")
cross.highlight(RED)
cross.next_to(checkmark, RIGHT, LARGE_BUFF)
crosses.add(cross)
arrow = Arrow(
checkmark, cross,
tip_length = 0.15,
color = WHITE
)
arrows.add(arrow)
full_group = VGroup(checkmarks, crosses, arrows)
full_group.center().to_corner(UP + RIGHT, buff = MED_LARGE_BUFF)
flip_indices = self.flip_indices
flipped_arrows, faded_crosses, full_checks = [
VGroup(*[group[i] for i in flip_indices])
for group in arrows, crosses, checkmarks
]
faded_checkmarks = VGroup(*filter(
lambda m : m not in full_checks,
checkmarks
))
self.play(*[
LaggedStart(
Write, mob,
run_time = 3,
lag_ratio = 0.3
)
for mob in full_group
])
self.dither()
self.play(
LaggedStart(
Rotate, flipped_arrows,
angle = np.pi,
in_place = True,
run_time = 2,
lag_ratio = 0.5
),
faded_crosses.set_fill, None, 0.5,
faded_checkmarks.set_fill, None, 0.5,
)
self.dither()
self.checkmarks = checkmarks
self.crosses = crosses
self.arrows = arrows
def change_to_gender(self):
flip_indices = self.flip_indices
male = self.get_male()
female = self.get_female()
girls, boys = [
VGroup(*[
template.copy().move_to(mob)
for mob in group
])
for template, group in [
(female, self.checkmarks), (male, self.crosses)
]
]
for i in range(len(boys)):
mob = boys[i] if i in flip_indices else girls[i]
mob.set_fill(opacity = 0.5)
brace = Brace(girls, LEFT)
words = brace.get_text("$n$ children")
self.play(
GrowFromCenter(brace),
FadeIn(words)
)
for m1, m2 in (self.checkmarks, girls), (self.crosses, boys):
self.play(ReplacementTransform(
m1, m2,
submobject_mode = "lagged_start"
))
self.dither()
self.boys = boys
self.girls = girls
self.children_brace = brace
self.n_children_words = words
def change_bar_chart_for_gender_example(self):
checkmark = self.probability.get_part_by_tex("checkmark")
p_mob = self.probability[-1]
female = self.get_female()
female.move_to(checkmark)
new_p_mob = TexMobject("0.49")
new_p_mob.move_to(p_mob, LEFT)
dist = get_binomial_distribution(10, 0.49)
values = map(dist, range(11))
self.play(
Transform(checkmark, female),
Transform(p_mob, new_p_mob),
)
self.play(self.chart.change_bar_values, values)
self.dither()
def point_out_example_input(self):
boy_girl_groups = VGroup(*[
VGroup(boy, girl)
for boy, girl in zip(self.boys, self.girls)
])
girl_rects = VGroup(*[
SurroundingRectangle(
boy_girl_groups[i],
color = MAROON_B,
buff = SMALL_BUFF,
)
for i in sorted(self.flip_indices)
])
chart = self.chart
n_girls = len(girl_rects)
chart_rect = SurroundingRectangle(
VGroup(chart.bars[n_girls], chart.bar_labels[n_girls]),
buff = SMALL_BUFF
)
self.play(ShowCreation(chart_rect))
self.play(LaggedStart(
ShowCreation, girl_rects,
run_time = 2,
lag_ratio = 0.5,
))
self.dither()
self.chart_rect = chart_rect
self.girl_rects = girl_rects
def write_probability_of_girl(self):
probability = self.probability
probability_copies = VGroup(*[
probability.copy().scale(0.7).next_to(
girl, LEFT, MED_LARGE_BUFF
)
for girl in self.girls
])
self.play(FocusOn(probability))
self.play(Indicate(probability[-1]))
self.dither()
self.play(
ReplacementTransform(
VGroup(probability.copy()), probability_copies
),
FadeOut(self.children_brace),
FadeOut(self.n_children_words),
)
self.dither()
self.probability_copies = probability_copies
def think_through_probabilities(self):
randy = Randolph().scale(0.5)
randy.next_to(self.probability_copies, LEFT, LARGE_BUFF)
self.play(FadeIn(randy))
self.play(randy.change, "pondering")
self.play(Blink(randy))
self.dither()
##
def get_male(self):
return TexMobject("\\male").scale(1.3).highlight(BLUE)
def get_female(self):
return TexMobject("\\female").scale(1.3).highlight(MAROON_B)
class CycleThroughPatterns(NameBinomial):
CONFIG = {
"n_patterns_shown" : 100,
"pattern_scale_value" : 2.7,
"n" : 10,
"k" : 6,
}
def construct(self):
n = self.n
k = self.k
question = TextMobject(
"How many patterns have \\\\ %d "%k,
"$\\female$",
" and %d "%(n-k),
"$\\male$",
"?",
arg_separator = ""
)
question.highlight_by_tex("male", BLUE)
question.highlight_by_tex("female", MAROON_B)
question.scale_to_fit_width(2*SPACE_WIDTH - 1)
question.to_edge(UP, buff = LARGE_BUFF)
self.add(question)
all_combinations = list(it.combinations(range(n), k))
shown_combinations = all_combinations[:self.n_patterns_shown]
patterns = VGroup(*[
self.get_pattern(indicies)
for indicies in shown_combinations
])
patterns.to_edge(DOWN, buff = LARGE_BUFF)
pattern = patterns[0]
self.add(pattern)
for new_pattern in ProgressDisplay(patterns[1:]):
self.play(*[
Transform(
getattr(pattern, attr),
getattr(new_pattern, attr),
path_arc = np.pi
)
for attr in "boys", "girls"
])
####
def get_pattern(self, indices):
pattern = VGroup()
pattern.boys = VGroup()
pattern.girls = VGroup()
for i in range(self.n):
if i in indices:
mob = self.get_female()
pattern.girls.add(mob)
else:
mob = self.get_male()
pattern.boys.add(mob)
mob.shift(i*MED_LARGE_BUFF*RIGHT)
pattern.add(mob)
pattern.scale(self.pattern_scale_value)
pattern.to_edge(LEFT)
return pattern
class Compute6of10GirlsProbability(CycleThroughPatterns):
def construct(self):
self.show_combinations()
self.write_n_choose_k()
def show_combinations(self):
pattern_rect = ScreenRectangle(height = 4)
pattern_rect.center()
pattern_rect.to_edge(UP, buff = MED_SMALL_BUFF)
self.add(pattern_rect)
self.dither(5)
self.pattern_rect = pattern_rect
def write_n_choose_k(self):
brace = Brace(self.pattern_rect, DOWN)
ten_choose_six = brace.get_tex("{10 \\choose 6}")
see_chapter_one = TextMobject("(See chapter 1)")
see_chapter_one.next_to(ten_choose_six, DOWN)
see_chapter_one.highlight(GREEN)
computation = TexMobject(
"=\\frac{%s}{%s}"%(
"\\cdot ".join(map(str, range(10, 4, -1))),
"\\cdot ".join(map(str, range(1, 7))),
)
)
computation.move_to(ten_choose_six, UP)
rhs = TexMobject("=", "210")
rhs.next_to(computation, RIGHT)
self.play(
FadeIn(see_chapter_one),
GrowFromCenter(brace)
)
self.play(Write(ten_choose_six))
self.dither(2)
self.play(
ten_choose_six.next_to, computation.copy(), LEFT,
Write(VGroup(computation, rhs))
)
self.dither()
self.ten_choose_six = ten_choose_six
self.rhs = rhs
class ProbabilityOfAGivenBoyGirlPattern(CycleThroughPatterns):
def construct(self):
self.write_total_count()
self.write_example_probability()
self.write_total_probability()
def write_total_count(self):
count = TextMobject(
"${10 \\choose 6}$", " $= 210$",
"total patterns."
)
count.to_edge(UP)
self.add(count)
self.count = count
def write_example_probability(self):
prob = TexMobject("P\\big(", "O "*15, "\\big)", "=")
indices = [1, 2, 4, 6, 8, 9]
pattern = self.get_pattern(indices)
pattern.replace(prob[1], dim_to_match = 0)
prob.submobjects[1] = pattern
prob.next_to(self.count, DOWN, LARGE_BUFF)
gp = TexMobject("(0.49)").highlight(MAROON_B)
bp = TexMobject("(0.51)").highlight(BLUE)
factored = VGroup()
gps = VGroup()
bps = VGroup()
for i in range(10):
if i in indices:
mob = gp.copy()
gps.add(mob)
else:
mob = bp.copy()
bps.add(mob)
factored.add(mob)
factored.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
factored.next_to(prob, DOWN, MED_LARGE_BUFF)
gps.save_state()
bps.save_state()
final_probability = TexMobject(
"(0.49)^6", "(0.51)^4"
)
final_probability.highlight_by_tex("0.49", MAROON_B)
final_probability.highlight_by_tex("0.51", BLUE)
final_probability.next_to(factored, DOWN, LARGE_BUFF)
self.play(FadeIn(prob))
self.dither()
self.play(ReplacementTransform(
pattern.copy(), factored,
run_time = 1.5,
))
self.dither(2)
for group, tex in (gps, "0.49"), (bps, "0.51"):
part = final_probability.get_part_by_tex(tex)
self.play(group.shift, MED_LARGE_BUFF*DOWN)
self.play(
ReplacementTransform(
group.copy(), VGroup(VGroup(*part[:-1]))
),
Write(part[-1])
)
self.dither()
self.play(group.restore)
self.dither()
self.final_probability = final_probability
def write_total_probability(self):
ten_choose_six = self.count[0].copy()
ten_choose_six.generate_target()
ten_choose_six.target.move_to(self.final_probability)
p_tex = TexMobject("P(", "\\text{6 Girls}", ")", "=")
p_tex.highlight_by_tex("Girls", MAROON_B)
p_tex.next_to(ten_choose_six.target, LEFT)
self.play(
Write(p_tex, run_time = 2),
self.final_probability.next_to,
ten_choose_six.target, RIGHT
)
self.play(MoveToTarget(ten_choose_six))
self.dither()
class CycleThroughPatternsForThree(CycleThroughPatterns):
CONFIG = {
"k" : 3,
"n_patterns_shown" : 20,
}
class GeneralBinomialDistributionValues(Scene):
CONFIG = {
"n" : 10,
"alt_n" : 8,
"p" : 0.49,
}
def construct(self):
self.add_chart()
self.show_a_few_values()
self.compare_to_pascal_row()
self.mention_center_concentration()
self.generalize()
self.play_with_p_value()
def add_chart(self):
dist = get_binomial_distribution(self.n, self.p)
values = map(dist, range(self.n+1))
chart = BarChart(
values,
bar_names = range(self.n+1)
)
chart.to_edge(LEFT)
full_probability = self.get_probability_expression(
"10", "k", "(0.49)", "(0.51)"
)
full_probability.next_to(chart, UP, aligned_edge = LEFT)
self.add(chart, full_probability)
self.chart = chart
self.full_probability = full_probability
def show_a_few_values(self):
chart = self.chart
probabilities = VGroup()
for i, bar in enumerate(chart.bars):
prob = self.get_probability_expression(
"10", str(i), "(0.49)", "(0.51)",
full = False
)
arrow = Arrow(
UP, DOWN,
color = WHITE,
tip_length = 0.15
)
arrow.next_to(bar, UP, SMALL_BUFF)
prob.next_to(arrow, UP, SMALL_BUFF)
##
prob.shift(LEFT)
prob.shift_onto_screen()
prob.shift(RIGHT)
##
prob.add(arrow)
probabilities.add(prob)
shown_prob = probabilities[6].copy()
self.play(FadeIn(shown_prob))
self.dither()
last_k = 6
for k in 3, 8, 5, 9, 6:
self.play(Transform(
shown_prob, probabilities[k],
path_arc = -np.pi/6 if k > last_k else np.pi/6
))
self.dither(2)
last_k = k
self.shown_prob = shown_prob
def compare_to_pascal_row(self):
triangle = PascalsTriangle(nrows = 11)
triangle.scale_to_fit_width(6)
triangle.to_corner(UP+RIGHT)
last_row = VGroup(*[
triangle.coords_to_mobs[10][k]
for k in range(11)
])
ten_choose_ks = VGroup()
for k, mob in enumerate(last_row):
ten_choose_k = TexMobject("10 \\choose %s"%k)
ten_choose_k.scale(0.5)
ten_choose_k.stretch(0.8, 0)
ten_choose_k.next_to(mob, DOWN)
ten_choose_ks.add(ten_choose_k)
ten_choose_ks.gradient_highlight(BLUE, YELLOW)
self.play(
LaggedStart(FadeIn, triangle),
FadeOut(self.shown_prob)
)
self.play(
last_row.gradient_highlight, BLUE, YELLOW,
Write(ten_choose_ks, run_time = 2)
)
self.dither()
self.play(ApplyWave(self.chart.bars, direction = UP))
self.play(FocusOn(last_row))
self.play(LaggedStart(
ApplyMethod, last_row,
lambda m : (m.scale_in_place, 1.2),
rate_func = there_and_back,
))
self.dither()
self.pascals_triangle = triangle
self.ten_choose_ks = ten_choose_ks
def mention_center_concentration(self):
bars = self.chart.bars
bars.generate_target()
bars.save_state()
bars.target.arrange_submobjects(UP, buff = 0)
bars.target.stretch_to_fit_height(self.chart.height)
bars.target.move_to(
self.chart.x_axis.point_from_proportion(0.05),
DOWN
)
brace = Brace(VGroup(*bars.target[4:7]), RIGHT)
words = brace.get_text("Most probability \\\\ in middle values")
self.play(MoveToTarget(bars))
self.play(
GrowFromCenter(brace),
FadeIn(words)
)
self.dither(2)
self.play(
bars.restore,
*map(FadeOut, [
brace, words,
self.pascals_triangle,
self.ten_choose_ks
])
)
def generalize(self):
alt_n = self.alt_n
dist = get_binomial_distribution(alt_n, self.p)
values = map(dist, range(alt_n + 1))
alt_chart = BarChart(
values, bar_names = range(alt_n + 1)
)
alt_chart.move_to(self.chart)
alt_probs = [
self.get_probability_expression("n", "k", "(0.49)", "(0.51)"),
self.get_probability_expression("n", "k", "p", "(1-p)"),
]
for prob in alt_probs:
prob.move_to(self.full_probability)
self.play(FocusOn(
self.full_probability.get_part_by_tex("choose")
))
self.play(
ReplacementTransform(self.chart, alt_chart),
Transform(self.full_probability, alt_probs[0])
)
self.chart = alt_chart
self.dither(2)
self.play(Transform(self.full_probability, alt_probs[1]))
self.dither()
def play_with_p_value(self):
p = self.p
interval = UnitInterval(color = WHITE)
interval.scale_to_fit_width(5)
interval.next_to(self.full_probability, DOWN, LARGE_BUFF)
interval.add_numbers(0, 0.5, 1)
triangle = RegularPolygon(
n=3, start_angle = -np.pi/2,
fill_color = MAROON_B,
fill_opacity = 1,
stroke_width = 0,
)
triangle.scale_to_fit_height(0.25)
triangle.move_to(interval.number_to_point(p), DOWN)
p_mob = TexMobject("p")
p_mob.highlight(MAROON_B)
p_mob.next_to(triangle, UP, SMALL_BUFF)
triangle.add(p_mob)
new_p_values = [0.8, 0.4, 0.2, 0.9, 0.97, 0.6]
self.play(
ShowCreation(interval),
Write(triangle, run_time = 1)
)
self.dither()
for new_p in new_p_values:
p = new_p
dist = get_binomial_distribution(self.alt_n, p)
values = map(dist, range(self.alt_n + 1))
self.play(
self.chart.change_bar_values, values,
triangle.move_to, interval.number_to_point(p), DOWN
)
self.dither()
#######
def get_probability_expression(
self, n = "n", k = "k", p = "p", q = "(1-p)",
full = True
):
args = []
if full:
args += ["P(", "\\# \\text{Girls}", "=", k, ")", "="]
args += [
"{%s \\choose %s}"%(n, k),
p, "^%s"%k,
q, "^{%s"%n, "-", "%s}"%k,
]
result = TexMobject(*args, arg_separator = "")
color_map = {
"Girls" : MAROON_B,
n : WHITE,
k : YELLOW,
p : MAROON_B,
q : BLUE,
}
result.highlight_by_tex_to_color_map(color_map)
choose_part = result.get_part_by_tex("choose")
choose_part.highlight(WHITE)
VGroup(*choose_part[1:1+len(n)]).highlight(color_map[n])
VGroup(*choose_part[-1-len(k):-1]).highlight(color_map[k])
return result
class PointOutSimplicityOfFormula(TeacherStudentsScene, GeneralBinomialDistributionValues):
def construct(self):
prob = self.get_probability_expression(full = False)
corner = self.teacher.get_corner(UP+LEFT)
prob.next_to(corner, UP, MED_LARGE_BUFF)
prob.save_state()
prob.move_to(corner)
prob.set_fill(opacity = 0)
self.play(
prob.restore,
self.teacher.change_mode, "raise_right_hand"
)
self.change_student_modes(
*["pondering"]*3,
look_at_arg = prob
)
self.dither()
self.student_says(
"Simpler than I feared",
target_mode = "hooray",
student_index = 0,
added_anims = [prob.to_corner, UP+RIGHT]
)
self.dither()
self.teacher_says("Due to \\\\ independence")
self.dither(2)
class CorrectForDependence(NameBinomial):
CONFIG = {
"flip_indices" : [3, 6, 8],
}
def setup(self):
self.force_skipping()
self.name_distribution()
self.add_quiz_questions()
self.revert_to_original_skipping_status()
def construct(self):
self.force_skipping()
self.mention_dependence()
self.show_tendency_to_align()
self.adjust_chart()
def mention_dependence(self):
brace = Brace(self.checkmarks, LEFT)
words = brace.get_text("What if there's \\\\ correlation?")
self.play(
GrowFromCenter(brace),
Write(words)
)
self.dither(2)
def show_tendency_to_align(self):
checkmarks = self.checkmarks
arrows = self.arrows
crosses = self.crosses
groups = [
VGroup(*trip)
for trip in zip(checkmarks, arrows, crosses)
]
top_rect = SurroundingRectangle(groups[0])
top_rect.highlight(GREEN)
indices_to_follow = [1, 4, 5, 7]
self.revert_to_original_skipping_status()
self.play(ShowCreation(top_rect))
self.play(*self.get_arrow_flip_anims([0]))
self.dither()
self.play(*self.get_arrow_flip_anims(indices_to_follow))
self.dither()
def adjust_chart(self):
pass
######
def get_arrow_flip_anims(self, indices):
checkmarks, arrows, crosses = movers = [
VGroup(*[
group[i]
for i in range(len(group))
if i in indices
])
for group in self.checkmarks, self.arrows, self.crosses
]
for arrow in arrows:
arrow.target = arrow.deepcopy()
arrow.target.rotate_in_place(np.pi)
for group in checkmarks, crosses:
for mob, arrow in zip(group, arrows):
mob.generate_target()
c = mob.get_center()
start, end = arrow.target.get_start_and_end()
to_end = np.linalg.norm(c - end)
to_start = np.linalg.norm(c - start)
if to_end < to_start:
mob.target.set_fill(opacity = 1)
else:
mob.target.set_fill(opacity = 0.5)
for checkmark in checkmarks:
checkmark.target.scale_in_place(1.2)
kwargs = {"path_arc" : np.pi}
if len(indices) > 1:
kwargs.update({"run_time" : 2})
return [
LaggedStart(
MoveToTarget, mover,
**kwargs
)
for mover in movers
]
2017-07-18 10:04:24 -07:00