mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
Patron-published versions of Bayes videos
This commit is contained in:
84
eop/bayes.py
84
eop/bayes.py
@ -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)
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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):
|
||||
|
Reference in New Issue
Block a user