Patron-published versions of Bayes videos

This commit is contained in:
Grant Sanderson
2017-06-14 21:54:21 -07:00
parent da1751b7c5
commit 1cd79592e9
5 changed files with 315 additions and 64 deletions

View File

@ -2193,8 +2193,88 @@ class FootnoteWrapper(NextVideoWrapper):
"title" : "Thoughts on the classic Bayes example" "title" : "Thoughts on the classic Bayes example"
} }
class PatreonThanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
"Ali Yahya",
"Burt Humburg",
"CrypticSwarm",
"Juan Benet",
"Mark Zollo",
"James Park",
"Erik Sundell",
"Yana Chernobilsky",
"Kaustuv DeBiswas",
"Kathryn Schmiedicke",
"Karan Bhargava",
"Ankit Agarwal",
"Yu Jun",
"Dave Nicponski",
"Damion Kistler",
"Markus Persson",
"Yoni Nazarathy",
"Ed Kellett",
"Joseph John Cox",
"Dan Buchoff",
"Luc Ritchie",
"Michael McGuffin",
"John Haley",
"Mourits de Beer",
"Ankalagon",
"Eric Lavault",
"Tomohiro Furusawa",
"Boris Veselinovich",
"Julian Pulgarin",
"Jeff Linse",
"Cooper Jones",
"Ryan Dahl",
"Mark Govea",
"Robert Teed",
"Jason Hise",
"Meshal Alshammari",
"Bernd Sing",
"Nils Schneider",
"James Thornton",
"Mustafa Mahdi",
"Mathew Bramson",
"Jerry Ling",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Ripta Pasay",
]
}
class Thumbnail(SampleSpaceScene):
def construct(self):
title = TextMobject("Bayes' rule")
title.scale(2)
title.to_edge(UP)
self.add(title)
prior_label = TexMobject("P(", "H", ")")
post_label = TexMobject("P(", "H", "|", "D", ")")
for label in prior_label, post_label:
label.highlight_by_tex("H", YELLOW)
label.highlight_by_tex("D", GREEN)
label.scale(1.5)
sample_space = self.get_sample_space()
sample_space.scale_to_fit_height(5)
sample_space.divide_horizontally(0.3)
sample_space[0].divide_vertically(0.8, colors = [GREEN, BLUE])
sample_space[1].divide_vertically(0.3, colors = [GREEN_E, BLUE_E])
sample_space.get_side_braces_and_labels([prior_label])
sample_space.add_braces_and_labels()
post_rects = self.get_posterior_rectangles()
group = self.get_posterior_rectangle_braces_and_labels(
post_rects, [post_label]
)
post_rects.add(group)
VGroup(sample_space, post_rects).next_to(title, DOWN, LARGE_BUFF)
self.add(sample_space, post_rects)

View File

@ -36,9 +36,11 @@ SICKLY_GREEN = "#9BBD37"
class BayesClassicExampleOpeningQuote(OpeningQuote): class BayesClassicExampleOpeningQuote(OpeningQuote):
CONFIG = { CONFIG = {
"quote" : [ "quote" : [
"", "When faced with a difficult question, we often " \
"answer an easier one instead, usually without " \
"noticing the substitution.",
], ],
"author" : "", "author" : "Daniel Kahneman",
} }
class Introduction(TeacherStudentsScene): class Introduction(TeacherStudentsScene):
@ -832,25 +834,81 @@ class DepressingForMedicalTestDesigners(TestScene):
class HowMuchCanYouChangeThisPrior(ShowRestrictedSpace, PiCreatureScene): class HowMuchCanYouChangeThisPrior(ShowRestrictedSpace, PiCreatureScene):
def construct(self): def construct(self):
self.play(LaggedStart( self.single_out_new_sick_one()
FadeIn, self.pi_creatures, self.show_subgroups()
run_time = 4, self.isolate_special_group()
lag_ratio = 0.7,
))
for x in range(2):
self.joint_blink(shuffle = False)
self.dither(2)
def create_pi_creatures(self): def create_pi_creatures(self):
title = TextMobject("Tiny, tiny prior")
title.to_edge(UP)
creatures = self.get_all_creatures() creatures = self.get_all_creatures()
creatures.submobjects = list(it.chain(*creatures))
creatures.scale_to_fit_height(6.5) creatures.scale_to_fit_height(6.5)
creatures.next_to(title, DOWN) creatures.center()
self.add(title) creatures.submobjects = list(it.chain(*creatures))
self.add(creatures)
self.sick_one = creatures.sick_one
return creatures return creatures
def single_out_new_sick_one(self):
creatures = self.pi_creatures
sick_one = self.sick_one
new_sick_one = sick_one.copy()
new_sick_one.shift(1.3*sick_one.get_width()*RIGHT)
sick_one.change_mode("plain")
sick_one.highlight(BLUE_E)
self.add(new_sick_one)
self.sick_one = new_sick_one
def show_subgroups(self):
subgroups = VGroup(*[
VGroup(*it.chain(
self.pi_creatures[i:i+5],
self.pi_creatures[i+25:i+25+5:]
))
for i in range(0, 1000)
if i%5 == 0 and (i/25)%2 == 0
])
special_group = subgroups[-5]
special_group.add(self.sick_one)
subgroups.generate_target()
width_factor = 2*SPACE_WIDTH/subgroups.get_width()
height_factor = 2*SPACE_HEIGHT/subgroups.get_height()
subgroups.target.stretch_in_place(width_factor, 0)
subgroups.target.stretch_in_place(height_factor, 1)
for subgroup in subgroups.target:
subgroup.stretch_in_place(1./width_factor, 0)
subgroup.stretch_in_place(1./height_factor, 1)
self.dither()
self.play(MoveToTarget(subgroups))
subgroups.remove(special_group)
rects = VGroup(*[
SurroundingRectangle(
group, buff = 0, color = GREEN
)
for group in subgroups
])
special_rect = SurroundingRectangle(
special_group, buff = 0, color = RED
)
self.play(FadeIn(rects), FadeIn(special_rect))
self.dither()
self.to_fade = VGroup(subgroups, rects)
self.special_group = special_group
self.special_rect = special_rect
def isolate_special_group(self):
to_fade, special_group = self.to_fade, self.special_group
self.play(FadeOut(to_fade))
self.play(
FadeOut(self.special_rect),
special_group.scale_to_fit_height, 6,
special_group.center,
)
self.dither()
class ShowTheFormula(TeacherStudentsScene): class ShowTheFormula(TeacherStudentsScene):
CONFIG = { CONFIG = {
"seconds_to_blink" : 3, "seconds_to_blink" : 3,
@ -1059,6 +1117,13 @@ class StatisticsVsEmpathy(PiCreatureScene):
sick_group = VGroup( sick_group = VGroup(
sick_one, VectorizedPoint(sick_one.get_bottom()) sick_one, VectorizedPoint(sick_one.get_bottom())
) )
priors = VGroup(*[
TexMobject("%.1f"%p+ "\\%").move_to(ORIGIN, RIGHT)
for p in np.arange(0.1, 2.0, 0.1)
])
priors.next_to(randy, UP+LEFT, LARGE_BUFF)
prior = priors[0]
prior.save_state()
self.play(PiCreatureSays( self.play(PiCreatureSays(
morty, morty,
@ -1067,6 +1132,14 @@ class StatisticsVsEmpathy(PiCreatureScene):
)) ))
self.play(randy.change, "pondering", morty.eyes) self.play(randy.change, "pondering", morty.eyes)
self.dither() self.dither()
self.play(Write(prior))
self.dither()
self.play(
prior.scale, 0.1,
prior.set_fill, None, 0,
prior.move_to, randy.eyes
)
self.dither()
self.play( self.play(
PiCreatureBubbleIntroduction( PiCreatureBubbleIntroduction(
randy, sick_group, randy, sick_group,
@ -1094,7 +1167,12 @@ class StatisticsVsEmpathy(PiCreatureScene):
target_sick_group, target_sick_group,
target_mode = "pleading", target_mode = "pleading",
) )
self.dither(3) self.dither(2)
self.play(prior.restore)
for new_prior in priors[1:]:
self.play(Transform(prior, new_prior, run_time = 0.5))
self.dither()
###### ######
@ -1105,6 +1183,21 @@ class StatisticsVsEmpathy(PiCreatureScene):
morty.to_edge(DOWN).shift(3*RIGHT) morty.to_edge(DOWN).shift(3*RIGHT)
return VGroup(randy, morty) return VGroup(randy, morty)
class LessMedicalExample(Scene):
def construct(self):
disease = TexMobject("P(\\text{Having a disease})")
telepathy = TexMobject("P(\\text{Telepathy})")
cross = Cross(disease)
self.add(disease)
self.dither()
self.play(ShowCreation(cross))
self.play(
FadeIn(telepathy),
VGroup(disease, cross).shift, 2*UP
)
self.dither()
class PlaneCrashProbability(Scene): class PlaneCrashProbability(Scene):
def construct(self): def construct(self):
plane_prob = TexMobject( plane_prob = TexMobject(
@ -1133,10 +1226,14 @@ class PlaneCrashProbability(Scene):
class IntroduceTelepathyExample(StatisticsVsEmpathy): class IntroduceTelepathyExample(StatisticsVsEmpathy):
def construct(self): def construct(self):
self.force_skipping()
self.show_mind_reading_powers() self.show_mind_reading_powers()
self.claim_mind_reading_powers()
self.generate_random_number() self.generate_random_number()
self.guess_number_correctly() self.guess_number_correctly()
self.ask_about_chances() # self.ask_about_chances()
self.revert_to_original_skipping_status()
self.say_you_probably_got_lucky() self.say_you_probably_got_lucky()
def show_mind_reading_powers(self): def show_mind_reading_powers(self):
@ -1146,19 +1243,33 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
self.add(title) self.add(title)
self.read_mind(randy, morty) self.read_mind(randy, morty)
self.play(randy.change, "happy", morty.eyes)
self.title = title self.title = title
def claim_mind_reading_powers(self):
randy, morty = self.randy, self.morty
self.play(PiCreatureSays(
randy, "I have the gift.",
run_time = 1,
look_at_arg = morty.eyes,
))
self.dither()
self.play(RemovePiCreatureBubble(
randy,
target_mode = "happy",
look_at_arg = morty.eyes
))
def generate_random_number(self): def generate_random_number(self):
morty = self.morty morty = self.morty
bubble = morty.get_bubble("", direction = LEFT) bubble = morty.get_bubble("", direction = LEFT)
numbers = [ numbers = [
Integer( Integer(random.choice(range(100)))
random.choice(range(100)),
).next_to(morty, UP, LARGE_BUFF, RIGHT)
for x in range(30) for x in range(30)
] ]
numbers.append(Integer(67))
for number in numbers:
number.next_to(morty, UP, LARGE_BUFF, RIGHT)
for number in numbers: for number in numbers:
@ -1186,8 +1297,6 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
look_at_arg = morty.eyes look_at_arg = morty.eyes
)) ))
self.dither() self.dither()
self.play(morty.change, "confused", randy.eyes)
self.dither()
def ask_about_chances(self): def ask_about_chances(self):
probability = TexMobject( probability = TexMobject(
@ -1198,6 +1307,8 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
probability.highlight_by_tex("Correct", GREEN) probability.highlight_by_tex("Correct", GREEN)
probability.to_edge(UP) probability.to_edge(UP)
self.play(morty.change, "confused", randy.eyes)
self.dither()
self.play(ReplacementTransform( self.play(ReplacementTransform(
self.title, VGroup(*it.chain(*probability)) self.title, VGroup(*it.chain(*probability))
)) ))
@ -1255,6 +1366,53 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
)) ))
self.remove(arcs) self.remove(arcs)
class CompareNumbersInBothExamples(Scene):
def construct(self):
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
v_line.shift(MED_LARGE_BUFF*LEFT)
h_line = Line(LEFT, RIGHT).scale(SPACE_WIDTH)
h_line.to_edge(UP, buff = 1.25*LARGE_BUFF)
titles = VGroup()
for word, vect in ("Disease", LEFT), ("Telepathy", RIGHT):
title = TextMobject("%s example"%word)
title.shift(vect*SPACE_WIDTH/2.0)
title.to_edge(UP)
titles.add(title)
priors = VGroup(*[
TexMobject(
"P(", "\\text{%s}"%s, ")", "= 1/1{,}000}"
)
for s in "Sick", "Powers"
])
likelihoods = VGroup(*[
TexMobject(
"P(", "\\text{%s}"%s1, "|",
"\\text{Not }", "\\text{%s}"%s2, ")",
"=", "1/100"
)
for s1, s2 in ("+", "Sick"), ("Correct", "Powers")
])
priors.next_to(likelihoods, UP, LARGE_BUFF)
for group in priors, likelihoods:
for mob, vect in zip(group, [LEFT, RIGHT]):
mob.highlight_by_tex("Sick", BLUE)
mob.highlight_by_tex("Powers", BLUE)
mob.highlight_by_tex("+", GREEN)
mob.highlight_by_tex("Correct", GREEN)
mob.scale(0.8)
mob.shift(vect*SPACE_WIDTH/2)
self.play(
LaggedStart(FadeIn, titles, lag_ratio = 0.7),
*map(ShowCreation, [h_line, v_line])
)
self.dither()
self.play(FadeIn(priors))
self.dither()
self.play(FadeIn(likelihoods))
self.dither(3)
class NonchalantReactionToPositiveTest(TestScene): class NonchalantReactionToPositiveTest(TestScene):
def construct(self): def construct(self):
randy = self.pi_creature randy = self.pi_creature

View File

@ -2,7 +2,7 @@
from helpers import * from helpers import *
from scene.scene import Scene from scene.scene import Scene
from animation.simple_animations import Write, DrawBorderThenFill from animation.simple_animations import Write, DrawBorderThenFill, LaggedStart
from animation.transform import FadeIn, FadeOut, ApplyMethod from animation.transform import FadeIn, FadeOut, ApplyMethod
from mobject.vectorized_mobject import VGroup from mobject.vectorized_mobject import VGroup
from mobject.tex_mobject import TexMobject, TextMobject from mobject.tex_mobject import TexMobject, TextMobject
@ -91,7 +91,7 @@ class PatreonThanks(Scene):
"Ripta Pasay", "Ripta Pasay",
"Felipe Diniz", "Felipe Diniz",
], ],
"patron_group_size" : 10, "max_patron_group_size" : 20,
"patron_scale_val" : 0.7, "patron_scale_val" : 0.7,
} }
@ -99,16 +99,12 @@ class PatreonThanks(Scene):
morty = Mortimer() morty = Mortimer()
morty.next_to(ORIGIN, DOWN) morty.next_to(ORIGIN, DOWN)
n_patrons = len(self.specific_patrons)
special_thanks = TextMobject("Special thanks")
special_thanks.highlight(YELLOW)
special_thanks.to_edge(UP)
patreon_logo = PatreonLogo() patreon_logo = PatreonLogo()
patreon_logo.next_to(morty, UP, buff = MED_LARGE_BUFF) patreon_logo.to_edge(UP)
n_patrons = len(self.specific_patrons)
patrons = map(TextMobject, self.specific_patrons) patrons = map(TextMobject, self.specific_patrons)
num_groups = float(len(patrons)) / self.patron_group_size num_groups = float(len(patrons)) / self.max_patron_group_size
proportion_range = np.linspace(0, 1, num_groups + 1) proportion_range = np.linspace(0, 1, num_groups + 1)
indices = (len(patrons)*proportion_range).astype('int') indices = (len(patrons)*proportion_range).astype('int')
patron_groups = [ patron_groups = [
@ -117,30 +113,38 @@ class PatreonThanks(Scene):
] ]
for i, group in enumerate(patron_groups): for i, group in enumerate(patron_groups):
group.arrange_submobjects(DOWN, aligned_edge = LEFT) left_group = VGroup(*group[:len(group)/2])
group.scale(self.patron_scale_val) right_group = VGroup(*group[len(group)/2:])
group.to_edge(LEFT if i%2 == 0 else RIGHT) for subgroup, vect in (left_group, LEFT), (right_group, RIGHT):
subgroup.arrange_submobjects(DOWN, aligned_edge = LEFT)
subgroup.scale(self.patron_scale_val)
subgroup.to_edge(vect)
self.play( last_group = None
morty.change_mode, "gracious",
DrawBorderThenFill(patreon_logo),
)
self.play(Write(special_thanks, run_time = 1))
print len(patron_groups)
for i, group in enumerate(patron_groups): for i, group in enumerate(patron_groups):
anims = [ anims = []
FadeIn( if last_group is not None:
group, run_time = 2, self.play(
submobject_mode = "lagged_start", FadeOut(last_group),
lag_factor = 4, morty.look, UP+LEFT
)
else:
anims += [
DrawBorderThenFill(patreon_logo),
]
self.play(
LaggedStart(
FadeIn, group,
run_time = 2,
), ),
morty.look_at, group.get_top(), morty.change, "gracious", group.get_corner(UP+LEFT),
] *anims
if i >= 2: )
anims.append(FadeOut(patron_groups[i-2])) self.play(morty.look_at, group.get_corner(DOWN+LEFT))
self.play(*anims) self.play(morty.look_at, group.get_corner(UP+RIGHT))
self.play(morty.look_at, group.get_bottom()) self.play(morty.look_at, group.get_corner(DOWN+RIGHT))
self.play(Blink(morty)) self.play(Blink(morty))
last_group = group

View File

@ -1,7 +1,7 @@
from helpers import * from helpers import *
from mobject import Mobject from mobject import Mobject
from mobject.vectorized_mobject import VMobject from mobject.vectorized_mobject import VMobject, VGroup
class Arc(VMobject): class Arc(VMobject):
CONFIG = { CONFIG = {
@ -413,6 +413,18 @@ class PictureInPictureFrame(Rectangle):
) )
self.scale_to_fit_height(height) self.scale_to_fit_height(height)
class Cross(VGroup):
CONFIG = {
"stroke_color" : RED,
"stroke_width" : 6,
}
def __init__(self, mobject, **kwargs):
VGroup.__init__(self,
Line(UP+LEFT, DOWN+RIGHT),
Line(UP+RIGHT, DOWN+LEFT),
)
self.replace(mobject, stretch = True)
self.set_stroke(self.stroke_color, self.stroke_width)
class Grid(VMobject): class Grid(VMobject):
CONFIG = { CONFIG = {

View File

@ -8,7 +8,8 @@ from mobject.tex_mobject import TextMobject, TexMobject
from animation import Animation from animation import Animation
from animation.simple_animations import Rotating from animation.simple_animations import Rotating
from topics.geometry import Circle, Line, Rectangle, Square, Arc, Polygon from topics.geometry import Circle, Line, Rectangle, Square, \
Arc, Polygon, SurroundingRectangle
from topics.three_dimensions import Cube from topics.three_dimensions import Cube
class Guitar(SVGMobject): class Guitar(SVGMobject):
@ -228,20 +229,16 @@ class Laptop(VGroup):
class PatreonLogo(SVGMobject): class PatreonLogo(SVGMobject):
CONFIG = { CONFIG = {
"file_name" : "patreon_logo", "file_name" : "patreon_logo",
"fill_color" : "#ff5900", "fill_color" : "#F96854",
# "fill_color" : WHITE,
"fill_opacity" : 1, "fill_opacity" : 1,
"stroke_width" : 0, "stroke_width" : 0,
"height" : 2, "width" : 4,
"propogate_style_to_family" : True "propogate_style_to_family" : True
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
SVGMobject.__init__(self, **kwargs) SVGMobject.__init__(self, **kwargs)
outer, inner = self.split() self.scale_to_fit_width(self.width)
# outer.add_subpath(inner.points)
# self.remove(inner)
inner.set_fill(BLACK, opacity = 1)
inner.set_stroke(self.fill_color, width = 0.5)
self.scale_to_fit_height(self.height)
self.center() self.center()
class VideoIcon(SVGMobject): class VideoIcon(SVGMobject):