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"
}
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):
CONFIG = {
"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):
@ -832,25 +834,81 @@ class DepressingForMedicalTestDesigners(TestScene):
class HowMuchCanYouChangeThisPrior(ShowRestrictedSpace, PiCreatureScene):
def construct(self):
self.play(LaggedStart(
FadeIn, self.pi_creatures,
run_time = 4,
lag_ratio = 0.7,
))
for x in range(2):
self.joint_blink(shuffle = False)
self.dither(2)
self.single_out_new_sick_one()
self.show_subgroups()
self.isolate_special_group()
def create_pi_creatures(self):
title = TextMobject("Tiny, tiny prior")
title.to_edge(UP)
creatures = self.get_all_creatures()
creatures.submobjects = list(it.chain(*creatures))
creatures.scale_to_fit_height(6.5)
creatures.next_to(title, DOWN)
self.add(title)
creatures.center()
creatures.submobjects = list(it.chain(*creatures))
self.add(creatures)
self.sick_one = creatures.sick_one
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):
CONFIG = {
"seconds_to_blink" : 3,
@ -1059,6 +1117,13 @@ class StatisticsVsEmpathy(PiCreatureScene):
sick_group = VGroup(
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(
morty,
@ -1067,6 +1132,14 @@ class StatisticsVsEmpathy(PiCreatureScene):
))
self.play(randy.change, "pondering", morty.eyes)
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(
PiCreatureBubbleIntroduction(
randy, sick_group,
@ -1094,7 +1167,12 @@ class StatisticsVsEmpathy(PiCreatureScene):
target_sick_group,
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)
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):
def construct(self):
plane_prob = TexMobject(
@ -1133,10 +1226,14 @@ class PlaneCrashProbability(Scene):
class IntroduceTelepathyExample(StatisticsVsEmpathy):
def construct(self):
self.force_skipping()
self.show_mind_reading_powers()
self.claim_mind_reading_powers()
self.generate_random_number()
self.guess_number_correctly()
self.ask_about_chances()
# self.ask_about_chances()
self.revert_to_original_skipping_status()
self.say_you_probably_got_lucky()
def show_mind_reading_powers(self):
@ -1146,19 +1243,33 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
self.add(title)
self.read_mind(randy, morty)
self.play(randy.change, "happy", morty.eyes)
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):
morty = self.morty
bubble = morty.get_bubble("", direction = LEFT)
numbers = [
Integer(
random.choice(range(100)),
).next_to(morty, UP, LARGE_BUFF, RIGHT)
Integer(random.choice(range(100)))
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:
@ -1186,8 +1297,6 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
look_at_arg = morty.eyes
))
self.dither()
self.play(morty.change, "confused", randy.eyes)
self.dither()
def ask_about_chances(self):
probability = TexMobject(
@ -1198,6 +1307,8 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
probability.highlight_by_tex("Correct", GREEN)
probability.to_edge(UP)
self.play(morty.change, "confused", randy.eyes)
self.dither()
self.play(ReplacementTransform(
self.title, VGroup(*it.chain(*probability))
))
@ -1255,6 +1366,53 @@ class IntroduceTelepathyExample(StatisticsVsEmpathy):
))
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):
def construct(self):
randy = self.pi_creature

View File

@ -2,7 +2,7 @@
from helpers import *
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 mobject.vectorized_mobject import VGroup
from mobject.tex_mobject import TexMobject, TextMobject
@ -91,7 +91,7 @@ class PatreonThanks(Scene):
"Ripta Pasay",
"Felipe Diniz",
],
"patron_group_size" : 10,
"max_patron_group_size" : 20,
"patron_scale_val" : 0.7,
}
@ -99,16 +99,12 @@ class PatreonThanks(Scene):
morty = Mortimer()
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.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)
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)
indices = (len(patrons)*proportion_range).astype('int')
patron_groups = [
@ -117,30 +113,38 @@ class PatreonThanks(Scene):
]
for i, group in enumerate(patron_groups):
group.arrange_submobjects(DOWN, aligned_edge = LEFT)
group.scale(self.patron_scale_val)
group.to_edge(LEFT if i%2 == 0 else RIGHT)
left_group = VGroup(*group[:len(group)/2])
right_group = VGroup(*group[len(group)/2:])
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(
morty.change_mode, "gracious",
DrawBorderThenFill(patreon_logo),
)
self.play(Write(special_thanks, run_time = 1))
print len(patron_groups)
last_group = None
for i, group in enumerate(patron_groups):
anims = [
FadeIn(
group, run_time = 2,
submobject_mode = "lagged_start",
lag_factor = 4,
anims = []
if last_group is not None:
self.play(
FadeOut(last_group),
morty.look, UP+LEFT
)
else:
anims += [
DrawBorderThenFill(patreon_logo),
]
self.play(
LaggedStart(
FadeIn, group,
run_time = 2,
),
morty.look_at, group.get_top(),
]
if i >= 2:
anims.append(FadeOut(patron_groups[i-2]))
self.play(*anims)
self.play(morty.look_at, group.get_bottom())
morty.change, "gracious", group.get_corner(UP+LEFT),
*anims
)
self.play(morty.look_at, group.get_corner(DOWN+LEFT))
self.play(morty.look_at, group.get_corner(UP+RIGHT))
self.play(morty.look_at, group.get_corner(DOWN+RIGHT))
self.play(Blink(morty))
last_group = group

View File

@ -1,7 +1,7 @@
from helpers import *
from mobject import Mobject
from mobject.vectorized_mobject import VMobject
from mobject.vectorized_mobject import VMobject, VGroup
class Arc(VMobject):
CONFIG = {
@ -413,6 +413,18 @@ class PictureInPictureFrame(Rectangle):
)
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):
CONFIG = {

View File

@ -8,7 +8,8 @@ from mobject.tex_mobject import TextMobject, TexMobject
from animation import Animation
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
class Guitar(SVGMobject):
@ -228,20 +229,16 @@ class Laptop(VGroup):
class PatreonLogo(SVGMobject):
CONFIG = {
"file_name" : "patreon_logo",
"fill_color" : "#ff5900",
"fill_color" : "#F96854",
# "fill_color" : WHITE,
"fill_opacity" : 1,
"stroke_width" : 0,
"height" : 2,
"width" : 4,
"propogate_style_to_family" : True
}
def __init__(self, **kwargs):
SVGMobject.__init__(self, **kwargs)
outer, inner = self.split()
# 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.scale_to_fit_width(self.width)
self.center()
class VideoIcon(SVGMobject):