From 04a495b37795fc4cd8b710b27351592192e55aac Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Tue, 24 Apr 2018 12:11:35 +0200 Subject: [PATCH 01/17] started teacher student scene --- active_projects/eop/chapter1.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 5f28ee60..55058e84 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -2030,7 +2030,14 @@ class PascalBrickWallScene(Scene): - +class IRecognizeThis(TeacherStudentsScene): + + def construct(self): + + self.student_says("I have seen this before!") + self.change_student_modes("pondering", "raise_right_hand", "pondering") + self.teacher_says("This is Pascal's Triangle") + From ade2e0c87eeadb864ae82c0596422f2b83c65110 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 25 Apr 2018 07:30:21 +0200 Subject: [PATCH 02/17] typos --- active_projects/eop/combinations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/active_projects/eop/combinations.py b/active_projects/eop/combinations.py index 31e88ce9..cb456823 100644 --- a/active_projects/eop/combinations.py +++ b/active_projects/eop/combinations.py @@ -53,7 +53,7 @@ class Female(Male): "color" : MAROON_B, } -class PascalsTraingle(VGroup): +class PascalsTriangle(VGroup): CONFIG = { "n_rows" : 9, "distance" : 0.8, @@ -143,7 +143,7 @@ class ExperienceProblemSolver(PiCreatureScene): def think_about_patterns(self): randy, jenny = self.randy, self.jenny - rows = PascalsTraingle( + rows = PascalsTriangle( n_rows = 6, distance = 0.6, ) @@ -1768,7 +1768,7 @@ class IntroducePascalsTriangle(Scene): self.cap_off_triangle() def show_triangle(self): - rows = PascalsTraingle(n_rows = self.max_n+1) + rows = PascalsTriangle(n_rows = self.max_n+1) self.play(FadeIn(rows[1])) for last_row, curr_row in zip(rows[1:], rows[2:]): self.play(*[ @@ -3477,7 +3477,7 @@ class AskWhyTheyAreCalledBinomial(TeacherStudentsScene): self.teacher.get_corner(UP+LEFT), UP ) - pascals = PascalsTraingle(n_rows = 6) + pascals = PascalsTriangle(n_rows = 6) pascals.scale_to_fit_height(3) pascals.to_corner(UP+LEFT, buff = MED_SMALL_BUFF) pascals.set_color_by_gradient(BLUE, YELLOW) From 88cc7cedff500552d1c3bc9b5edb81d9a112cf3a Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 25 Apr 2018 07:30:36 +0200 Subject: [PATCH 03/17] finished TS Scene --- active_projects/eop/chapter1.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 55058e84..d3814f43 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -2036,7 +2036,20 @@ class IRecognizeThis(TeacherStudentsScene): self.student_says("I have seen this before!") self.change_student_modes("pondering", "raise_right_hand", "pondering") - self.teacher_says("This is Pascal's Triangle") + self.wait() + self.play(FadeOut(self.get_students[1].bubble)) + + self.wait() + # insert https://www.youtube.com/watch?v=K8P8uFahAgc&t=6m47s here + + self.teacher_says("It's Pascal's Triangle") + + + +class EntirePascalBrickWall(Scene): + + def construct(self): + @@ -2054,9 +2067,6 @@ class IRecognizeThis(TeacherStudentsScene): - - - From e947e1d115ee3919341967f21e4a51b694fcd48d Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 25 Apr 2018 17:26:34 +0200 Subject: [PATCH 04/17] brick row morphing into histogram --- active_projects/eop/chapter1.py | 142 +++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 13 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index d3814f43..b7bff5eb 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -1181,7 +1181,7 @@ class OneIn200HasDisease(Scene): -class PascalBrickWall(VMobject): +class BrickRow(VMobject): CONFIG = { "left_color" : YELLOW, @@ -1374,7 +1374,7 @@ class SplitRectsInBrickWall(Animation): -class PascalBrickWallScene(Scene): +class BrickRowScene(Scene): def split_tallies(self, direction = DOWN): @@ -1671,7 +1671,7 @@ class PascalBrickWallScene(Scene): randy = CoinFlippingPiCreature() randy = randy.scale(0.5).move_to(3*DOWN + 6*LEFT) self.add(randy) - self.row = PascalBrickWall(1, height = 2, width = 10) + self.row = BrickRow(1, height = 2, width = 10) self.decimals = VGroup() @@ -1883,7 +1883,8 @@ class PascalBrickWallScene(Scene): w = 1.5 * self.row.height * DOWN self.play( - self.row.shift, w + self.row.shift, w, + Animation(previous_row) ) self.play( @@ -2030,27 +2031,142 @@ class PascalBrickWallScene(Scene): -class IRecognizeThis(TeacherStudentsScene): +class MorphBrickRowIntoHistogram(Scene): def construct(self): - self.student_says("I have seen this before!") - self.change_student_modes("pondering", "raise_right_hand", "pondering") - self.wait() - self.play(FadeOut(self.get_students[1].bubble)) + row = BrickRow(3, height = 2, width = 10) + self.add(row) + tallies = VMobject() - self.wait() - # insert https://www.youtube.com/watch?v=K8P8uFahAgc&t=6m47s here + for (i,brick) in enumerate(row.rects): + tally = TallyStack(3 - i, i) + tally.next_to(brick, UP) + self.add(tally) + tallies.add(tally) + brick.set_stroke(width = 3) - self.teacher_says("It's Pascal's Triangle") + self.remove(row.subdivs, row.border) + + anims = [] + for brick in row.rects: + anims.append(brick.rotate) + anims.append(TAU/4) + anims.append(FadeOut(tallies)) + self.play(*anims) + + bar_anchors = [2.5 * DOWN + row.height * (i - 1.5) * RIGHT for i in range(4)] + + anims = [] + for (i,brick) in enumerate(row.rects): + anims.append(brick.next_to) + anims.append(bar_anchors[i]) + anims.append({"direction" : UP, "buff" : 0}) + self.play(*anims) + + bars = VMobject(*[row.rects[i] for i in range(4)]) + + # draw x-axis + + x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) + x_axis.next_to(bars, DOWN, buff = -0.1) + #x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)]) + x_labels = VMobject() + for (i, bar) in enumerate(bars): + label = Integer(i) + label.next_to(bar_anchors[i], DOWN) + x_labels.add(label) + + nb_heads_label = TextMobject("\# of heads") + nb_heads_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) + + self.play( + FadeIn(x_axis), + FadeIn(x_labels), + FadeIn(nb_heads_label) + ) + + + + # draw y-guides + + y_guides = VMobject() + for i in range(1,5): + y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) + y_guide.move_to(2.5 * DOWN + i * float(row.width) / 8 * UP) + y_guide_label = TexMobject("{" + str(i) + "\over 8}", color = GRAY).scale(0.7) + y_guide_label.next_to(y_guide, LEFT) + y_guide.add(y_guide_label) + y_guides.add(y_guide) + + self.bring_to_back(y_guides) + self.play(FadeIn(y_guides), Animation(bars)) + + + total_area_text = TextMobject("total area = 1", color = YELLOW) + total_area_rect = SurroundingRectangle(total_area_text, + buff = MED_SMALL_BUFF, + fill_opacity = 0.5, + fill_color = BLACK, + stroke_color = YELLOW + ) + + self.play( + Write(total_area_text), + ShowCreation(total_area_rect) + ) + + prob_dist_text = TextMobject("probability distribution", color = YELLOW) + prob_dist_text.to_corner(UP, buff = MED_LARGE_BUFF) + prob_dist_rect = SurroundingRectangle(prob_dist_text, + buff = MED_SMALL_BUFF, + stroke_color = YELLOW + ) + + self.play( + Write(prob_dist_text), + ShowCreation(prob_dist_rect) + ) + + + +# class IRecognizeThis(TeacherStudentsScene): + +# def construct(self): + +# self.student_says("I have seen this before!") +# self.change_student_modes("pondering", "raise_right_hand", "pondering") +# self.wait() +# self.play(FadeOut(self.get_students[1].bubble)) + +# self.wait() +# # insert https://www.youtube.com/watch?v=K8P8uFahAgc&t=6m47s here + +# self.teacher_says("It's Pascal's Triangle") -class EntirePascalBrickWall(Scene): +class EntireBrickWall(Scene): def construct(self): + row_height = 0.3 + nb_rows = 20 + start_point = 3 * UP + rows = VMobject() + rows.add(BrickRow(0, height = row_height)) + rows[0].move_to(start_point) + self.add(rows) + + for i in range(1,nb_rows): + rows.add(BrickRow(i, height = row_height)) + rows[-1].move_to(start_point + (i - 1) * row_height * DOWN) + self.bring_to_back(rows[-1]) + self.play( + rows[-1].shift, row_height * DOWN, + Animation(rows[-2]) + ) From 8af8a22df0711ee864157127bf7fc314bc3f2b7c Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 25 Apr 2018 20:13:37 +0200 Subject: [PATCH 05/17] simplified brick row scene, made more generic; work on morphing into histogram for N = 20 --- active_projects/eop/chapter1.py | 235 ++++++++++++++++++++++---------- 1 file changed, 160 insertions(+), 75 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index b7bff5eb..80a28558 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -1625,14 +1625,14 @@ class BrickRowScene(Scene): def merge_decimals(self): - anims = [] + anims = [] + self.new_decimals = VGroup() + self.decimal_copies = VGroup() + if self.decimals in self.mobjects: anims.append(FadeOut(self.decimals)) if self.decimal_copies in self.mobjects: anims.append(FadeOut(self.decimal_copies)) - - self.new_decimals = VGroup() - self.decimal_copies = VGroup() r = self.row.coloring_level for (i, rect) in enumerate(self.row.rects): @@ -1710,15 +1710,6 @@ class BrickRowScene(Scene): ) self.wait() - self.split_tallies_in_two_steps() - self.wait() - self.merge_rects_by_subdiv() - self.wait() - self.merge_tallies() - self.merge_rects_by_coloring() - self.wait() - self.move_tallies_on_top() - # show individual outcomes outcomes = self.row.get_outcome_rects_for_level(2, with_labels = True) self.play( @@ -1729,21 +1720,32 @@ class BrickRowScene(Scene): LaggedStart(FadeOut, outcomes) ) - # show their numbers - nb_outcomes = [1,2,1] - self.decimals = VGroup() - for (n,rect) in zip(nb_outcomes, self.row.rects): - decimal = Integer(n).move_to(rect) - self.decimals.add(decimal) - self.play( - LaggedStart(FadeIn, self.decimals) - ) + self.split_tallies_in_two_steps() self.wait() - self.play( - LaggedStart(FadeOut, self.decimals) - ) + self.merge_rects_by_subdiv() + self.wait() + self.merge_tallies() + self.merge_rects_by_coloring() + self.wait() + self.move_tallies_on_top() + - self.decimals = VGroup() + + # # show their numbers + # nb_outcomes = [1,2,1] + # self.decimals = VGroup() + # for (n,rect) in zip(nb_outcomes, self.row.rects): + # decimal = Integer(n).move_to(rect) + # self.decimals.add(decimal) + # self.play( + # LaggedStart(FadeIn, self.decimals) + # ) + # self.wait() + # self.play( + # LaggedStart(FadeOut, self.decimals) + # ) + + # self.decimals = VGroup() @@ -1783,17 +1785,17 @@ class BrickRowScene(Scene): LaggedStart(FadeOut, outcomes) ) - # show their numbers - nb_outcomes = [1,3,3,1] - self.decimals = VGroup() - for (n,rect) in zip(nb_outcomes, self.row.rects): - decimal = Integer(n).move_to(rect) - self.decimals.add(decimal) - self.play( - LaggedStart(FadeIn, self.decimals) - ) - self.wait() - self.add_foreground_mobject(self.decimals) + # # show their numbers + # nb_outcomes = [1,3,3,1] + # self.decimals = VGroup() + # for (n,rect) in zip(nb_outcomes, self.row.rects): + # decimal = Integer(n).move_to(rect) + # self.decimals.add(decimal) + # self.play( + # LaggedStart(FadeIn, self.decimals) + # ) + # self.wait() + # self.add_foreground_mobject(self.decimals) # # # # # # # # @@ -1825,28 +1827,28 @@ class BrickRowScene(Scene): # FIFTH FLIP # # # # # # # # # - self.play(FlipCoin(randy)) + # self.play(FlipCoin(randy)) - self.wait() + # self.wait() - self.play( - SplitRectsInBrickWall(self.row) - ) - self.wait() + # self.play( + # SplitRectsInBrickWall(self.row) + # ) + # self.wait() - self.split_tallies_at_once(direction = LEFT) - self.wait() - self.merge_rects_by_subdiv() - self.wait() - self.merge_tallies(direction = LEFT) - self.merge_rects_by_coloring() - self.merge_decimals() - self.wait() + # self.split_tallies_at_once(direction = LEFT) + # self.wait() + # self.merge_rects_by_subdiv() + # self.wait() + # self.merge_tallies(direction = LEFT) + # self.merge_rects_by_coloring() + # self.merge_decimals() + # self.wait() - # # # # # # # # - # SIXTH FLIP # - # # # # # # # # + # # # # # # # # # + # # SIXTH FLIP # + # # # # # # # # # self.revert_to_original_skipping_status() @@ -1896,13 +1898,15 @@ class BrickRowScene(Scene): self.wait() + n = 4 # level to split + k = 2 # tally to split # show individual outcomes - outcomes = previous_row.get_outcome_rects_for_level(5, with_labels = False) + outcomes = previous_row.get_outcome_rects_for_level(n, with_labels = False) grouped_outcomes = VGroup() index = 0 - for i in range(6): - size = choose(5,i) + for i in range(n + 1): + size = choose(n,i) grouped_outcomes.add(VGroup(outcomes[index:index + size])) index += size @@ -1921,8 +1925,6 @@ class BrickRowScene(Scene): # show how the outcomes in one tally split into two copies # going into the neighboring tallies - n = 5 # level to split - k = 2 # tally to split target_outcomes = self.row.get_outcome_rects_for_level(n + 1, with_labels = False) grouped_target_outcomes = VGroup() @@ -2031,16 +2033,28 @@ class BrickRowScene(Scene): -class MorphBrickRowIntoHistogram(Scene): +class GenericMorphBrickRowIntoHistogram(Scene): + + CONFIG = { + "level" : 3 + } + + def __init__(self, **kwargs): + + self.row = BrickRow(self.level, height = 6.0 / self.level, width = 10) + self.bars = VMobject(*[self.row.rects[i] for i in range(self.level + 1)]) + self.bar_anchors = [3 * DOWN + row.height * (i - 1.5) * RIGHT for i in range(self.level + 1)] + + Scene.__init__(self, **kwargs) + def construct(self): - row = BrickRow(3, height = 2, width = 10) self.add(row) tallies = VMobject() for (i,brick) in enumerate(row.rects): - tally = TallyStack(3 - i, i) + tally = TallyStack(self.level - i, i) tally.next_to(brick, UP) self.add(tally) tallies.add(tally) @@ -2055,26 +2069,43 @@ class MorphBrickRowIntoHistogram(Scene): anims.append(FadeOut(tallies)) self.play(*anims) - bar_anchors = [2.5 * DOWN + row.height * (i - 1.5) * RIGHT for i in range(4)] - + anims = [] for (i,brick) in enumerate(row.rects): anims.append(brick.next_to) - anims.append(bar_anchors[i]) + anims.append(self.bar_anchors[i]) anims.append({"direction" : UP, "buff" : 0}) self.play(*anims) - bars = VMobject(*[row.rects[i] for i in range(4)]) - + self.additional_animations() + + def additional_animations(self): + pass + + + + +class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): + CONFIG = { + "level" : 3, + "prob_denominator" : 8 + } + + def __init__(self, **kwargs): + GenericMorphBrickRowIntoHistogram.__init__(self, **kwargs) + + + def additional_animations(self): + # draw x-axis x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) - x_axis.next_to(bars, DOWN, buff = -0.1) + x_axis.next_to(self.bars, DOWN, buff = -0.1) #x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)]) x_labels = VMobject() - for (i, bar) in enumerate(bars): + for (i, bar) in enumerate(self.bars): label = Integer(i) - label.next_to(bar_anchors[i], DOWN) + label.next_to(self.bar_anchors[i], DOWN) x_labels.add(label) nb_heads_label = TextMobject("\# of heads") @@ -2091,16 +2122,17 @@ class MorphBrickRowIntoHistogram(Scene): # draw y-guides y_guides = VMobject() - for i in range(1,5): + for i in range(1,self.prob_denominator + 1): y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) - y_guide.move_to(2.5 * DOWN + i * float(row.width) / 8 * UP) - y_guide_label = TexMobject("{" + str(i) + "\over 8}", color = GRAY).scale(0.7) + y_guide.move_to(3 * DOWN + i * float(row.width) / self.prob_denominator * UP) + y_guide_label = TexMobject("{" + str(i) + "\over " + str(self.prob_denominator) + "}", color = GRAY) + y_guide_label.scale(0.7) y_guide_label.next_to(y_guide, LEFT) y_guide.add(y_guide_label) y_guides.add(y_guide) self.bring_to_back(y_guides) - self.play(FadeIn(y_guides), Animation(bars)) + self.play(FadeIn(y_guides), Animation(self.bars)) total_area_text = TextMobject("total area = 1", color = YELLOW) @@ -2117,7 +2149,7 @@ class MorphBrickRowIntoHistogram(Scene): ) prob_dist_text = TextMobject("probability distribution", color = YELLOW) - prob_dist_text.to_corner(UP, buff = MED_LARGE_BUFF) + prob_dist_text.to_corner(UP, buff = LARGE_BUFF) prob_dist_rect = SurroundingRectangle(prob_dist_text, buff = MED_SMALL_BUFF, stroke_color = YELLOW @@ -2130,6 +2162,59 @@ class MorphBrickRowIntoHistogram(Scene): +class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): + CONFIG = { + "level" : 20, + "prob_ticks" : 0.02 + } + + def __init__(self, **kwargs): + GenericMorphBrickRowIntoHistogram.__init__(self, **kwargs) + + def construct(self): + + super(GenericMorphBrickRowIntoHistogram, self).construct() + + x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) + x_axis.next_to(self.bars, DOWN, buff = -0.1) + #x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)]) + x_labels = VMobject() + for (i, bar) in enumerate(self.bars): + if i % 5 != 0: + continue + label = Integer(i) + label.next_to(self.bar_anchors[i], DOWN) + x_labels.add(label) + + nb_heads_label = TextMobject("\# of heads") + nb_heads_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) + + self.play( + FadeIn(x_axis), + FadeIn(x_labels), + FadeIn(nb_heads_label) + ) + + + + max_prob = self.row.width * float(choose(self.level, self.level/2)) / 2 ** self.level + # draw y-guides + + y_guides = VMobject() + for i in np.arange(self.prob_ticks, 1.3 * max_prob): + y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) + y_guide.move_to(3 * DOWN + i * float(row.width) / self.prob_denominator * UP) + y_guide_label = DecimalNumber(i, num_decimal_points = 2, color = GRAY) + y_guide_label.scale(0.7) + y_guide_label.next_to(y_guide, LEFT) + y_guide.add(y_guide_label) + y_guides.add(y_guide) + + self.bring_to_back(y_guides) + self.play(FadeIn(y_guides), Animation(bars)) + + + # class IRecognizeThis(TeacherStudentsScene): # def construct(self): From cfc79253bc9488d8f6bf5123cf113b79aa7573db Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 25 Apr 2018 23:01:02 +0200 Subject: [PATCH 06/17] scaling of morphed histograms working --- active_projects/eop/chapter1.py | 76 +++++++++++++++++---------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 80a28558..c62ef426 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -2036,34 +2036,32 @@ class BrickRowScene(Scene): class GenericMorphBrickRowIntoHistogram(Scene): CONFIG = { - "level" : 3 + "level" : 3, + "bar_width" : 2.0, + "bar_anchor_height" : -3.0 } - def __init__(self, **kwargs): - - self.row = BrickRow(self.level, height = 6.0 / self.level, width = 10) - self.bars = VMobject(*[self.row.rects[i] for i in range(self.level + 1)]) - self.bar_anchors = [3 * DOWN + row.height * (i - 1.5) * RIGHT for i in range(self.level + 1)] - - Scene.__init__(self, **kwargs) - - def construct(self): - self.add(row) + self.row = BrickRow(self.level, height = self.bar_width, width = 10) + self.bars = VMobject(*[self.row.rects[i] for i in range(self.level + 1)]) + self.bar_anchors = [self.bar_anchor_height * UP + self.row.height * (i - 0.5 * self.level) * RIGHT for i in range(self.level + 1)] + + + self.add(self.row) tallies = VMobject() - for (i,brick) in enumerate(row.rects): + for (i,brick) in enumerate(self.row.rects): tally = TallyStack(self.level - i, i) tally.next_to(brick, UP) self.add(tally) tallies.add(tally) brick.set_stroke(width = 3) - self.remove(row.subdivs, row.border) + self.remove(self.row.subdivs, self.row.border) anims = [] - for brick in row.rects: + for brick in self.row.rects: anims.append(brick.rotate) anims.append(TAU/4) anims.append(FadeOut(tallies)) @@ -2071,31 +2069,29 @@ class GenericMorphBrickRowIntoHistogram(Scene): anims = [] - for (i,brick) in enumerate(row.rects): + for (i,brick) in enumerate(self.row.rects): anims.append(brick.next_to) anims.append(self.bar_anchors[i]) anims.append({"direction" : UP, "buff" : 0}) self.play(*anims) - self.additional_animations() - - def additional_animations(self): - pass class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): + CONFIG = { "level" : 3, - "prob_denominator" : 8 + "prob_denominator" : 8, + "bar_width" : 2.0, + "bar_anchor_height" : -3.0 } - def __init__(self, **kwargs): - GenericMorphBrickRowIntoHistogram.__init__(self, **kwargs) + def construct(self): - - def additional_animations(self): + super(MorphBrickRowIntoHistogram3,self).construct() + # draw x-axis @@ -2124,7 +2120,7 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): y_guides = VMobject() for i in range(1,self.prob_denominator + 1): y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) - y_guide.move_to(3 * DOWN + i * float(row.width) / self.prob_denominator * UP) + y_guide.move_to(self.bar_anchor_height * UP + i * float(self.row.width) / self.prob_denominator * UP) y_guide_label = TexMobject("{" + str(i) + "\over " + str(self.prob_denominator) + "}", color = GRAY) y_guide_label.scale(0.7) y_guide_label.next_to(y_guide, LEFT) @@ -2165,15 +2161,14 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): CONFIG = { "level" : 20, - "prob_ticks" : 0.02 + "prob_ticks" : 0.05, + "bar_width" : 0.5, + "bar_anchor_height" : -1.0 } - - def __init__(self, **kwargs): - GenericMorphBrickRowIntoHistogram.__init__(self, **kwargs) def construct(self): - super(GenericMorphBrickRowIntoHistogram, self).construct() + super(MorphBrickRowIntoHistogram20, self).construct() x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) x_axis.next_to(self.bars, DOWN, buff = -0.1) @@ -2195,15 +2190,14 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): FadeIn(nb_heads_label) ) - - - max_prob = self.row.width * float(choose(self.level, self.level/2)) / 2 ** self.level # draw y-guides + max_prob = float(choose(self.level, self.level/2)) / 2 ** self.level + y_guides = VMobject() - for i in np.arange(self.prob_ticks, 1.3 * max_prob): + for i in np.arange(self.prob_ticks, 1.3 * max_prob, self.prob_ticks): y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) - y_guide.move_to(3 * DOWN + i * float(row.width) / self.prob_denominator * UP) + y_guide.move_to(self.bar_anchor_height * UP + i * float(self.row.width) * UP) y_guide_label = DecimalNumber(i, num_decimal_points = 2, color = GRAY) y_guide_label.scale(0.7) y_guide_label.next_to(y_guide, LEFT) @@ -2211,7 +2205,7 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): y_guides.add(y_guide) self.bring_to_back(y_guides) - self.play(FadeIn(y_guides), Animation(bars)) + self.play(FadeIn(y_guides), Animation(self.bars)) @@ -2255,7 +2249,15 @@ class EntireBrickWall(Scene): - +class SceneType1(Scene): + def construct(self): + self.randy = Randolph() + + +class SceneType2(SceneType1): + def construct(self): + super(SceneType2, self).construct() + self.add(self.randy) From 9c6bcd6653391418735af0394026f71fa8d4d895 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Thu, 26 Apr 2018 22:47:51 +0200 Subject: [PATCH 07/17] Histograms form brick rows can now automatically scale, expanded and tweaked brick wall scene --- active_projects/eop/chapter1.py | 511 +++++++++++++++++++------------- 1 file changed, 310 insertions(+), 201 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index c62ef426..5474948f 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -1189,7 +1189,7 @@ class BrickRow(VMobject): "height" : 1.0, "width" : 8.0, "outcome_shrinkage_factor_x" : 0.85, - "outcome_shrinkage_factor_y" : 0.95 + "outcome_shrinkage_factor_y" : 0.9 } def __init__(self, n, **kwargs): @@ -1267,8 +1267,8 @@ class BrickRow(VMobject): width = outcome_width, height = outcome_height, corner_radius = corner_radius, - fill_color = BLACK, - fill_opacity = 0.2, + fill_color = DARK_GREY, + fill_opacity = 0.8, stroke_width = 0 ) rects = VGroup() @@ -1401,10 +1401,10 @@ class BrickRowScene(Scene): for (i, tally) in enumerate(self.tallies): - if len(self.decimals) > 0: - decimal = self.decimals[i] - else: - decimal = VMobject() + # if len(self.decimals) > 0: + # decimal = self.decimals[i] + # else: + # decimal = VMobject() target_left = tally_targets_left[i] new_tally_left = TallyStack(tally.nb_heads + 1, tally.nb_tails) @@ -1413,13 +1413,13 @@ class BrickRowScene(Scene): self.play( tally.move_anchor_to, target_left, - decimal.shift,v + #decimal.shift,v ) tally.anchor = target_left self.play(Transform(tally, new_tally_left)) tally_copy = self.tallies_copy[i] - decimal_copy = decimal.copy() + #decimal_copy = decimal.copy() target_right = tally_targets_right[i] new_tally_right = TallyStack(tally.nb_heads, tally.nb_tails + 1) @@ -1462,38 +1462,38 @@ class BrickRowScene(Scene): anims1 = [] - if len(self.decimals) > 0: - self.decimal_copies = VGroup() + # if len(self.decimals) > 0: + # self.decimal_copies = VGroup() for (i, tally) in enumerate(self.tallies): - if len(self.decimals) > 0: - decimal = self.decimals[i] - else: - decimal = VMobject() + # if len(self.decimals) > 0: + # decimal = self.decimals[i] + # else: + # decimal = VMobject() target_left = tally_targets_left[i] v = target_left - tally.anchor anims1.append(tally.move_anchor_to) anims1.append(target_left) - anims1.append(decimal.shift) - anims1.append(v) + #anims1.append(decimal.shift) + #anims1.append(v) tally.anchor = target_left tally_copy = self.tallies_copy[i] - decimal_copy = decimal.copy() + #decimal_copy = decimal.copy() target_right = tally_targets_right[i] v = target_right - tally_copy.anchor anims1.append(tally_copy.move_anchor_to) anims1.append(target_right) - anims1.append(decimal_copy.shift) - anims1.append(v) - if len(self.decimals) > 0: - self.decimal_copies.add(decimal_copy) + #anims1.append(decimal_copy.shift) + #anims1.append(v) + # if len(self.decimals) > 0: + # self.decimal_copies.add(decimal_copy) tally_copy.anchor = target_right @@ -1518,8 +1518,8 @@ class BrickRowScene(Scene): - if len(self.decimals) > 0: - self.add_foreground_mobject(self.decimal_copies) + # if len(self.decimals) > 0: + # self.add_foreground_mobject(self.decimal_copies) return anims1, anims2 @@ -1536,36 +1536,36 @@ class BrickRowScene(Scene): - def split_decimals_alone(self): + # def split_decimals_alone(self): - r = self.row.coloring_level - targets_left = [] - targets_right = [] + # r = self.row.coloring_level + # targets_left = [] + # targets_right = [] - for rect in self.row.get_rects_for_level(r): - target = rect.get_center() + 0.25 * rect.get_width() * LEFT - targets_left.append(target) - target = rect.get_center() + 0.25 * rect.get_width() * RIGHT - targets_right.append(target) + # for rect in self.row.get_rects_for_level(r): + # target = rect.get_center() + 0.25 * rect.get_width() * LEFT + # targets_left.append(target) + # target = rect.get_center() + 0.25 * rect.get_width() * RIGHT + # targets_right.append(target) - anims = [] - self.decimal_copies = VGroup() + # anims = [] + # self.decimal_copies = VGroup() - for (i, decimal) in enumerate(self.decimals): + # for (i, decimal) in enumerate(self.decimals): - anims.append(decimal.move_to) - anims.append(targets_left[i]) + # anims.append(decimal.move_to) + # anims.append(targets_left[i]) - decimal_copy = decimal.copy() + # decimal_copy = decimal.copy() - anims.append(decimal_copy.move_to) - anims.append(targets_right[i]) - self.decimal_copies.add(decimal_copy) + # anims.append(decimal_copy.move_to) + # anims.append(targets_right[i]) + # self.decimal_copies.add(decimal_copy) - self.play(*anims) + # self.play(*anims) - self.add_foreground_mobject(self.decimal_copies) + # self.add_foreground_mobject(self.decimal_copies) @@ -1623,36 +1623,36 @@ class BrickRowScene(Scene): self.row = merged_row - def merge_decimals(self): + # def merge_decimals(self): - anims = [] - self.new_decimals = VGroup() - self.decimal_copies = VGroup() + # anims = [] + # self.new_decimals = VGroup() + # self.decimal_copies = VGroup() - if self.decimals in self.mobjects: - anims.append(FadeOut(self.decimals)) - if self.decimal_copies in self.mobjects: - anims.append(FadeOut(self.decimal_copies)) + # if self.decimals in self.mobjects: + # anims.append(FadeOut(self.decimals)) + # if self.decimal_copies in self.mobjects: + # anims.append(FadeOut(self.decimal_copies)) - r = self.row.coloring_level - for (i, rect) in enumerate(self.row.rects): - k = choose(r,i) - decimal = Integer(k) - decimal.move_to(rect) - if rect.get_width() < 0.2: - # then the rect is too narrow, - # let the decimal go in dignity - decimal.set_stroke(width = 0) - decimal.set_fill(opacity = 0) - self.new_decimals.add(decimal) + # r = self.row.coloring_level + # for (i, rect) in enumerate(self.row.rects): + # k = choose(r,i) + # decimal = Integer(k) + # decimal.move_to(rect) + # if rect.get_width() < 0.2: + # # then the rect is too narrow, + # # let the decimal go in dignity + # decimal.set_stroke(width = 0) + # decimal.set_fill(opacity = 0) + # self.new_decimals.add(decimal) - anims.append(FadeIn(self.new_decimals)) - self.play(*anims) + # anims.append(FadeIn(self.new_decimals)) + # self.play(*anims) - self.remove(self.decimal_copies) - self.decimals = self.new_decimals.copy() - #self.remove(self.new_decimals) - self.add_foreground_mobject(self.decimals) + # self.remove(self.decimal_copies) + # self.decimals = self.new_decimals.copy() + # #self.remove(self.new_decimals) + # self.add_foreground_mobject(self.decimals) @@ -1673,7 +1673,7 @@ class BrickRowScene(Scene): self.add(randy) self.row = BrickRow(1, height = 2, width = 10) - self.decimals = VGroup() + #self.decimals = VGroup() self.play(FlipCoin(randy), FadeIn(self.row)) @@ -1731,22 +1731,6 @@ class BrickRowScene(Scene): - # # show their numbers - # nb_outcomes = [1,2,1] - # self.decimals = VGroup() - # for (n,rect) in zip(nb_outcomes, self.row.rects): - # decimal = Integer(n).move_to(rect) - # self.decimals.add(decimal) - # self.play( - # LaggedStart(FadeIn, self.decimals) - # ) - # self.wait() - # self.play( - # LaggedStart(FadeOut, self.decimals) - # ) - - # self.decimals = VGroup() - # # # # # # # # @@ -1802,25 +1786,25 @@ class BrickRowScene(Scene): # FOURTH FLIP # # # # # # # # # - self.play(FlipCoin(randy)) + # self.play(FlipCoin(randy)) - self.wait() + # self.wait() - self.play( - SplitRectsInBrickWall(self.row) - ) - self.wait() + # self.play( + # SplitRectsInBrickWall(self.row) + # ) + # self.wait() - self.add_foreground_mobject(self.tallies[-1]) - # this tweaks an undesirable overlap in the next animation - self.split_tallies_at_once(direction = LEFT) - self.wait() - self.merge_rects_by_subdiv() - self.wait() - self.merge_tallies(direction = LEFT) - self.merge_rects_by_coloring() - self.merge_decimals() - self.wait() + # self.add_foreground_mobject(self.tallies[-1]) + # # this tweaks an undesirable overlap in the next animation + # self.split_tallies_at_once(direction = LEFT) + # self.wait() + # self.merge_rects_by_subdiv() + # self.wait() + # self.merge_tallies(direction = LEFT) + # self.merge_rects_by_coloring() + # self.merge_decimals() + # self.wait() # # # # # # # # @@ -1846,12 +1830,11 @@ class BrickRowScene(Scene): # self.wait() - # # # # # # # # # - # # SIXTH FLIP # - # # # # # # # # # + # # # # # # # # # # # # # # + # # FOURTH FLIP IN DETAIL # + # # # # # # # # # # # # # # - self.revert_to_original_skipping_status() # removing the tallies (boy are they sticky) self.play(FadeOut(self.tallies)) @@ -1866,7 +1849,7 @@ class BrickRowScene(Scene): # delete all the old crap hidden behind the row # before we can move it self.remove(*self.mobjects) - self.add(randy,self.decimals,self.decimal_copies) + self.add(randy) #,self.decimals,self.decimal_copies) previous_row = self.row.copy() @@ -1875,8 +1858,8 @@ class BrickRowScene(Scene): v = 1.25 * self.row.height * UP self.play( previous_row.shift, v, - self.decimals.shift, v, - self.decimal_copies.shift, v + #self.decimals.shift, v, + #self.decimal_copies.shift, v ) self.add(self.row) @@ -1898,8 +1881,8 @@ class BrickRowScene(Scene): self.wait() - n = 4 # level to split - k = 2 # tally to split + n = 3 # level to split + k = 1 # tally to split # show individual outcomes outcomes = previous_row.get_outcome_rects_for_level(n, with_labels = False) @@ -1925,6 +1908,7 @@ class BrickRowScene(Scene): # show how the outcomes in one tally split into two copies # going into the neighboring tallies + self.revert_to_original_skipping_status() target_outcomes = self.row.get_outcome_rects_for_level(n + 1, with_labels = False) grouped_target_outcomes = VGroup() @@ -1937,17 +1921,16 @@ class BrickRowScene(Scene): index += size self.play( - Transform(grouped_outcomes[k],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:]) + Transform(grouped_outcomes[k][0],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:]) ) self.play( - Transform(grouped_outcomes_copy[k],grouped_target_outcomes[k + 1][0][:old_tally_sizes[k]]) + Transform(grouped_outcomes_copy[k][0],grouped_target_outcomes[k + 1][0][:old_tally_sizes[k]]) ) + old_tally_sizes.append(0) # makes the edge cases work properly - old_tally_sizes.append(0) # makes the ege cases work properly - - # split the other + # split the other tallies for i in range(k) + range(k + 1, n + 1): self.play( Transform(grouped_outcomes[i][0], @@ -1983,52 +1966,88 @@ class BrickRowScene(Scene): new_rects = self.row.get_rects_for_level(n + 1) - decimals_copy = self.decimals.copy() - decimals_copy2 = self.decimals.copy() + #decimals_copy = self.decimals.copy() + #decimals_copy2 = self.decimals.copy() self.play( - Transform(grouped_outcomes[k],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:]), - Transform(grouped_outcomes_copy[k - 1],grouped_target_outcomes[k][0][:old_tally_sizes[k]]), - decimals_copy[k - 1].move_to, new_rects[k], - decimals_copy2[k].move_to, new_rects[k], - ) - - # show new outcome sizes - new_decimals = VGroup() - for (i,rect) in zip(new_tally_sizes, new_rects): - decimal = Integer(i).move_to(rect) - new_decimals.add(decimal) - - self.play( - FadeOut(decimals_copy[k - 1]), - FadeOut(decimals_copy2[k]), - FadeIn(new_decimals[k]) + Transform(grouped_outcomes[k][0],grouped_target_outcomes[k][0][old_tally_sizes[k - 1]:]), + Transform(grouped_outcomes_copy[k - 1][0],grouped_target_outcomes[k][0][:old_tally_sizes[k]]), + #decimals_copy[k - 1].move_to, new_rects[k], + #decimals_copy2[k].move_to, new_rects[k], ) - # move the old decimals into the new row - anims = [] - anims.append(decimals_copy2[0].move_to) - anims.append(new_rects[0]) - for i in range(1,k) + range(k + 1, n): - anims.append(decimals_copy[i - 1].move_to) - anims.append(new_rects[i]) - anims.append(decimals_copy2[i].move_to) - anims.append(new_rects[i]) - anims.append(decimals_copy[n].move_to) - anims.append(new_rects[n + 1]) + # show new outcome sizes + # new_decimals = VGroup() + # for (i,rect) in zip(new_tally_sizes, new_rects): + # decimal = Integer(i).move_to(rect) + # new_decimals.add(decimal) - self.play(*anims) + # self.play( + # FadeOut(decimals_copy[k - 1]), + # FadeOut(decimals_copy2[k]), + # FadeIn(new_decimals[k]) + # ) - # fade them out and fade in their sums - anims = [] - for i in range(1,k) + range(k + 1, n): - anims.append(FadeOut(decimals_copy[i - 1])) - anims.append(FadeOut(decimals_copy2[i])) - anims.append(FadeIn(new_decimals[i])) + # # move the old decimals into the new row + # anims = [] + # anims.append(decimals_copy2[0].move_to) + # anims.append(new_rects[0]) + # for i in range(1,k) + range(k + 1, n): + # anims.append(decimals_copy[i - 1].move_to) + # anims.append(new_rects[i]) + # anims.append(decimals_copy2[i].move_to) + # anims.append(new_rects[i]) + # anims.append(decimals_copy[n].move_to) + # anims.append(new_rects[n + 1]) - self.play(*anims) + # # self.play(*anims) + + # # fade them out and fade in their sums + # anims = [] + # for i in range(1,k) + range(k + 1, n): + # anims.append(FadeOut(decimals_copy[i - 1])) + # anims.append(FadeOut(decimals_copy2[i])) + # anims.append(FadeIn(new_decimals[i])) + + # self.play(*anims) + + # self.add_foreground_mobject(new_decimals) + + +class OutlineableBars(VGroup): + CONFIG = { + "outline_stroke_width" : 5, + "stroke_color" : WHITE + } + def create_outline(self, animated = False, **kwargs): + + outline_points = [] + + for (i, bar) in enumerate(self.submobjects): + + if i == 0: + # start with the lower left + outline_points.append(bar.get_corner(DOWN + LEFT)) + + # upper two points of each bar + outline_points.append(bar.get_corner(UP + LEFT)) + outline_points.append(bar.get_corner(UP + RIGHT)) + + previous_bar = bar + # close the outline + # lower right + outline_points.append(previous_bar.get_corner(DOWN + RIGHT)) + # lower left + outline_points.append(outline_points[0]) + + self.outline = Polygon(*outline_points, + stroke_width = self.outline_stroke_width, + stroke_color = self.stroke_color) + + if animated: + self.play(FadeIn(self.outline, **kwargs)) + return self.outline - self.add_foreground_mobject(new_decimals) @@ -2038,25 +2057,28 @@ class GenericMorphBrickRowIntoHistogram(Scene): CONFIG = { "level" : 3, "bar_width" : 2.0, - "bar_anchor_height" : -3.0 + "bar_anchor_height" : -3.0, + "show_tallies" : False, } def construct(self): self.row = BrickRow(self.level, height = self.bar_width, width = 10) - self.bars = VMobject(*[self.row.rects[i] for i in range(self.level + 1)]) + self.bars = OutlineableBars(*[self.row.rects[i] for i in range(self.level + 1)]) self.bar_anchors = [self.bar_anchor_height * UP + self.row.height * (i - 0.5 * self.level) * RIGHT for i in range(self.level + 1)] - self.add(self.row) - tallies = VMobject() - for (i,brick) in enumerate(self.row.rects): - tally = TallyStack(self.level - i, i) - tally.next_to(brick, UP) - self.add(tally) - tallies.add(tally) - brick.set_stroke(width = 3) + if self.show_tallies: + + tallies = VMobject() + + for (i,brick) in enumerate(self.row.rects): + tally = TallyStack(self.level - i, i) + tally.next_to(brick, UP) + self.add(tally) + tallies.add(tally) + brick.set_stroke(width = 3) self.remove(self.row.subdivs, self.row.border) @@ -2064,7 +2086,9 @@ class GenericMorphBrickRowIntoHistogram(Scene): for brick in self.row.rects: anims.append(brick.rotate) anims.append(TAU/4) - anims.append(FadeOut(tallies)) + + if self.show_tallies: + anims.append(FadeOut(tallies)) self.play(*anims) @@ -2075,6 +2099,17 @@ class GenericMorphBrickRowIntoHistogram(Scene): anims.append({"direction" : UP, "buff" : 0}) self.play(*anims) + self.bars.create_outline() + + anims = [] + for bar in self.bars.submobjects: + anims.append(bar.set_stroke) + anims.append({"width" : 0}) + anims.append(FadeIn(self.bars.outline)) + self.play(*anims) + + + @@ -2085,7 +2120,8 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): "level" : 3, "prob_denominator" : 8, "bar_width" : 2.0, - "bar_anchor_height" : -3.0 + "bar_anchor_height" : -3.0, + "show_tallies" : True } def construct(self): @@ -2095,10 +2131,11 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): # draw x-axis - x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) - x_axis.next_to(self.bars, DOWN, buff = -0.1) + x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) + x_axis.next_to(self.bars, DOWN, buff = 0) #x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)]) x_labels = VMobject() + for (i, bar) in enumerate(self.bars): label = Integer(i) label.next_to(self.bar_anchors[i], DOWN) @@ -2163,19 +2200,20 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): "level" : 20, "prob_ticks" : 0.05, "bar_width" : 0.5, - "bar_anchor_height" : -1.0 + "bar_anchor_height" : -3.0, + "x_ticks": 5 } def construct(self): super(MorphBrickRowIntoHistogram20, self).construct() - x_axis = Arrow(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) - x_axis.next_to(self.bars, DOWN, buff = -0.1) + x_axis = Line(ORIGIN, 10 * RIGHT, color = WHITE, buff = 0) + x_axis.next_to(self.bars, DOWN, buff = 0) #x_labels = VMobject(*[TexMobject(str(i)) for i in range(4)]) x_labels = VMobject() for (i, bar) in enumerate(self.bars): - if i % 5 != 0: + if i % self.x_ticks != 0: continue label = Integer(i) label.next_to(self.bar_anchors[i], DOWN) @@ -2195,9 +2233,13 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): max_prob = float(choose(self.level, self.level/2)) / 2 ** self.level y_guides = VMobject() - for i in np.arange(self.prob_ticks, 1.3 * max_prob, self.prob_ticks): + y_guide_heights = [] + prob_grid = np.arange(self.prob_ticks, 1.3 * max_prob, self.prob_ticks) + for i in prob_grid: y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) - y_guide.move_to(self.bar_anchor_height * UP + i * float(self.row.width) * UP) + y_guide_height = self.bar_anchor_height + i * float(self.row.width) + y_guide_heights.append(y_guide_height) + y_guide.move_to(y_guide_height * UP) y_guide_label = DecimalNumber(i, num_decimal_points = 2, color = GRAY) y_guide_label.scale(0.7) y_guide_label.next_to(y_guide, LEFT) @@ -2207,21 +2249,64 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): self.bring_to_back(y_guides) self.play(FadeIn(y_guides), Animation(self.bars)) + histogram_width = self.bars.get_width() + histogram_height = self.bars.get_height() + + # scale to fit screen + self.scale_x = 10.0/(len(self.bars) * self.bar_width) + self.scale_y = 6.0/histogram_height -# class IRecognizeThis(TeacherStudentsScene): + anims = [] + for (bar, x_label) in zip(self.bars, x_labels): + v = (self.scale_x - 1) * x_label.get_center()[0] * RIGHT + anims.append(x_label.shift) + anims.append(v) -# def construct(self): -# self.student_says("I have seen this before!") -# self.change_student_modes("pondering", "raise_right_hand", "pondering") -# self.wait() -# self.play(FadeOut(self.get_students[1].bubble)) + anims.append(self.bars.stretch_about_point) + anims.append(self.scale_x) + anims.append(0) + anims.append(ORIGIN) + anims.append(self.bars.outline.stretch_about_point) + anims.append(self.scale_x) + anims.append(0) + anims.append(ORIGIN) -# self.wait() -# # insert https://www.youtube.com/watch?v=K8P8uFahAgc&t=6m47s here + self.play(*anims) + + anims = [] + for (guide, i, h) in zip(y_guides, prob_grid, y_guide_heights): + new_y_guide_height = self.bar_anchor_height + i * self.scale_y * float(self.row.width) + v = (new_y_guide_height - h) * UP + anims.append(guide.shift) + anims.append(v) + + anims.append(self.bars.stretch_about_point) + anims.append(self.scale_y) + anims.append(1) + anims.append(self.bars.get_bottom()) + anims.append(self.bars.outline.stretch_about_point) + anims.append(self.scale_y) + anims.append(1) + anims.append(self.bars.get_bottom()) + + self.play(*anims) + +class MorphBrickRowIntoHistogram100(MorphBrickRowIntoHistogram20): + CONFIG = { + "level" : 100, + "x_ticks": 20, + "prob_ticks": 0.02 + } + +class MorphBrickRowIntoHistogram500(MorphBrickRowIntoHistogram20): + CONFIG = { + "level" : 500, + "x_ticks": 100, + "prob_ticks": 0.01 + } -# self.teacher_says("It's Pascal's Triangle") @@ -2231,40 +2316,64 @@ class EntireBrickWall(Scene): row_height = 0.3 nb_rows = 20 - start_point = 3 * UP + start_point = 3 * UP + 1 * LEFT rows = VMobject() rows.add(BrickRow(0, height = row_height)) rows[0].move_to(start_point) self.add(rows) - for i in range(1,nb_rows): + zero_counter = Integer(0).next_to(start_point + 0.5 * rows[0].width * RIGHT) + nb_flips_text = TextMobject("\# of flips") + nb_flips_text.next_to(zero_counter, RIGHT, buff = LARGE_BUFF) + self.add(zero_counter, nb_flips_text) + + for i in range(1,nb_rows + 1): rows.add(BrickRow(i, height = row_height)) rows[-1].move_to(start_point + (i - 1) * row_height * DOWN) self.bring_to_back(rows[-1]) - self.play( + anims = [ rows[-1].shift, row_height * DOWN, Animation(rows[-2]) - ) - - - -class SceneType1(Scene): - def construct(self): - self.randy = Randolph() - - -class SceneType2(SceneType1): - def construct(self): - super(SceneType2, self).construct() - self.add(self.randy) - - + ] + if i % 5 == 0: + counter = Integer(i) + counter.next_to(rows[-1].get_right() + row_height * DOWN, RIGHT) + anims.append(FadeIn(counter)) + self.play(*anims) + # draw indices under the last row for the number of tails + tails_counters = VGroup() + for (i, rect) in enumerate(rows[-1].rects): + if i < 6 or i > 14: + continue + if i == 6: + counter = TexMobject("\dots", color = COLOR_TAILS) + counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF) + elif i == 14: + counter = TexMobject("\dots", color = COLOR_TAILS) + counter.next_to(rect, DOWN, buff = 1.5 * MED_SMALL_BUFF) + counter.shift(0.2 * RIGHT) + else: + counter = Integer(i, color = COLOR_TAILS) + counter.next_to(rect, DOWN) + tails_counters.add(counter) + nb_tails_text = TextMobject("\# of tails", color = COLOR_TAILS) + nb_tails_text.next_to(tails_counters[-1], RIGHT, buff = LARGE_BUFF) + self.play( + LaggedStart(FadeIn, tails_counters), + FadeIn(nb_tails_text) + ) + + special_brick_copy = rows[-1].rects[13].copy() + self.play( + rows.fade, 0.9, + FadeIn(special_brick_copy) + ) From 5f7810db832a2663c63ab8715a54e7dc6e483990 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Fri, 27 Apr 2018 18:28:49 +0200 Subject: [PATCH 08/17] fixed unit color bug --- mobject/numbers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobject/numbers.py b/mobject/numbers.py index 1e8d84f2..118289f7 100644 --- a/mobject/numbers.py +++ b/mobject/numbers.py @@ -51,7 +51,7 @@ class DecimalNumber(VMobject): ) if self.unit is not None: - self.unit_sign = TexMobject(self.unit) + self.unit_sign = TexMobject(self.unit, color = self.color) self.add(self.unit_sign) self.arrange_submobjects( From c3c6e72d386d80a9082d69094d031aec72a7f87b Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Fri, 27 Apr 2018 18:29:09 +0200 Subject: [PATCH 09/17] bug fixes in Histogram --- active_projects/eop/histograms.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/active_projects/eop/histograms.py b/active_projects/eop/histograms.py index 0974569d..5c4060a2 100644 --- a/active_projects/eop/histograms.py +++ b/active_projects/eop/histograms.py @@ -107,6 +107,8 @@ class Histogram(VMobject): self.x_labels = num_arr_to_string_arr(self.widths) elif self.x_labels == "mids": self.x_labels = num_arr_to_string_arr(self.x_mids) + elif self.x_labels == "auto": + self.x_labels = num_arr_to_string_arr(self.x_mids) elif self.x_labels == "none": self.x_labels = empty_string_array(len(self.widths)) @@ -228,7 +230,7 @@ class FlashThroughHistogram(Animation): self.cell_indices = [] for (i,x) in enumerate(x_values): - nb_cells = y_values[i] + nb_cells = int(np.floor(y_values[i])) for j in range(nb_cells): self.cell_indices.append((i, j)) @@ -271,8 +273,8 @@ class FlashThroughHistogram(Animation): self.prototype_cell.generate_points() self.prototype_cell.move_to(cell.get_center()) - #if t == 1: - # self.mobject.remove(self.prototype_cell) + if t == 1: + self.mobject.remove(self.prototype_cell) From 026e6390d64e5d1aaa7388378f320ba9afdb503d Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Fri, 27 Apr 2018 18:29:28 +0200 Subject: [PATCH 10/17] wrote quiz scene --- active_projects/eop/chapter1.py | 203 +++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 2 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 5474948f..caee3fb8 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -1,9 +1,11 @@ from big_ol_pile_of_manim_imports import * from old_projects.eoc.chapter8 import * from active_projects.eop.histograms import * +from active_projects.eop.independence import * import scipy.special + COIN_RADIUS = 0.18 COIN_THICKNESS = 0.4 * COIN_RADIUS COIN_FORESHORTENING = 0.5 @@ -17,6 +19,18 @@ GRADE_COLOR_2 = COLOR_TAILS = BLUE TALLY_BACKGROUND_WIDTH = 1.0 +def get_example_quiz(): + quiz = get_quiz( + "Define ``Brachistochrone'' ", + "Define ``Tautochrone'' ", + "Define ``Cycloid'' ", + ) + rect = SurroundingRectangle(quiz, buff = 0) + rect.set_fill(color = BLACK, opacity = 1) + rect.set_stroke(width = 0) + quiz.add_to_back(rect) + return quiz + def binary(i): # returns an array of 0s and 1s if i == 0: @@ -140,7 +154,7 @@ class CoinFlippingPiCreatureScene(Scene): def construct(self): - randy = CoinFlippingPiCreature() + randy = CoinFlippingPiCreature(color = MAROON_E) self.add(randy) self.play(FlipCoin(randy, run_time = 3)) @@ -2336,7 +2350,7 @@ class EntireBrickWall(Scene): rows[-1].shift, row_height * DOWN, Animation(rows[-2]) ] - + if i % 5 == 0: counter = Integer(i) counter.next_to(rows[-1].get_right() + row_height * DOWN, RIGHT) @@ -2380,5 +2394,190 @@ class EntireBrickWall(Scene): +class QuizResult(Scene): + + def construct(self): + + highlight_color = YELLOW + + nb_students_x = 5 + nb_students_y = 3 + spacing_students_x = 2.0 + spacing_students_y = 2.2 + + all_students = VGroup() + student_points = [] + grades = [] + grades_count = [] + hist_y_values = np.zeros(4) + for i in range(nb_students_x): + for j in range(nb_students_y): + x = i * spacing_students_x + y = j * spacing_students_y + pi = PiCreature().scale(0.3) + pi.move_to([x,y,0]) + all_students.add(pi) + q1 = np.random.choice([True, False]) + q2 = np.random.choice([True, False]) + q3 = np.random.choice([True, False]) + student_points.append([q1, q2, q3]) + grade = q1*1+q2*1+q3*1 + grades.append(grade) + hist_y_values[grade] += 1 + # How many times has this grade already occured? + grade_count = grades.count(grade) + grades_count.append(grade_count) + + + all_students.move_to(ORIGIN) + self.add(all_students) + + all_quizzes = VGroup() + + quiz = get_example_quiz().scale(0.2) + for pi in all_students: + quiz_copy = quiz.copy() + quiz_copy.next_to(pi, UP) + all_quizzes.add(quiz_copy) + + master_quiz = get_example_quiz() + self.play(ShowCreation(master_quiz)) + self.play(Transform(master_quiz, all_quizzes[0])) + + self.play(LaggedStart(FadeIn,all_quizzes)) + + grades_mob = VGroup() + for (pi, quiz, grade) in zip(all_students, all_quizzes, grades): + grade_mob = TexMobject(str(grade) + "/3") + grade_mob.move_to(quiz) + grades_mob.add(grade_mob) + + self.remove(master_quiz) + self.play( + FadeOut(all_quizzes), + FadeIn(grades_mob) + ) + + # self.play( + # all_students[2:].fade, 0.8, + # grades_mob[2:].fade, 0.8 + # ) + + students_points_mob = VGroup() + for (pi, quiz, points) in zip(all_students, all_quizzes, student_points): + slot = get_slot_group(points, include_qs = False) + slot.scale(0.5).move_to(quiz) + students_points_mob.add(slot) + + self.play( + #all_students.fade, 0, + FadeOut(grades_mob), + FadeIn(students_points_mob) + ) + + + + anims = [] + anchor_point = 3 * DOWN + 1 * LEFT + for (pi, grade, grades_count) in zip(all_students, grades, grades_count): + anims.append(pi.move_to) + anims.append(anchor_point + grade * RIGHT + grades_count * UP) + anims.append(FadeOut(students_points_mob)) + + self.play(*anims) + + grade_labels = VGroup() + for i in range(4): + grade_label = Integer(i, color = highlight_color) + grade_label.move_to(i * RIGHT) + grade_labels.add(grade_label) + grade_labels.next_to(all_students, DOWN) + out_of_label = TextMobject("out of 3", color = highlight_color) + out_of_label.next_to(grade_labels, RIGHT, buff = MED_LARGE_BUFF) + grade_labels.add(out_of_label) + self.play(Write(grade_labels)) + + grade_hist = Histogram( + np.ones(4), + hist_y_values, + mode = "widths", + x_labels = "none", + y_label_position = "center", + bar_stroke_width = 0, + outline_stroke_width = 5 + ) + grade_hist.move_to(all_students) + + self.play(FadeIn(grade_hist)) + + + nb_students_label = TextMobject("\# of students", color = highlight_color) + nb_students_label.move_to(3 * LEFT + 2 * UP) + arrows = VGroup(*[ + Arrow(nb_students_label, grade_hist.bars[i].get_center(), + color = highlight_color) + for i in range(4) + ]) + self.play(Write(nb_students_label), LaggedStart(ShowCreation,arrows)) + + percentage_label = TextMobject("\% of students", color = highlight_color) + percentage_label.move_to(nb_students_label) + percentages = hist_y_values / (nb_students_x * nb_students_y) * 100 + anims = [] + for (label, percentage) in zip(grade_hist.y_labels_group, percentages): + new_label = DecimalNumber(percentage, + num_decimal_points = 1, + unit = "\%", + color = highlight_color + ) + new_label.move_to(label) + anims.append(Transform(label, new_label)) + anims.append(ReplacementTransform(nb_students_label, percentage_label)) + self.play(*anims) + + self.remove(all_quizzes) + # put small copy of class in corner + for (i,pi) in enumerate(all_students): + x = i % 5 + y = i / 5 + pi.move_to(x * RIGHT + y * UP) + all_students.scale(0.8) + all_students.to_corner(DOWN + LEFT) + self.play(FadeIn(all_students)) + + prob_label = TextMobject("probability", color = highlight_color) + prob_label.move_to(percentage_label) + self.play( + all_students[8].set_color, MAROON_E, + all_students[:8].fade, 0.6, + all_students[9:].fade, 0.6, + ReplacementTransform(percentage_label, prob_label) + ) + + self.play( + FadeOut(prob_label), + FadeOut(arrows) + ) + + for i in range(1): + self.play( + FlashThroughHistogram( + grade_hist, + direction = "vertical", + mode = "random", + run_time = 5 + ) + ) + + + + + + + + + + + From 6fdcf59c84dc330d916f5a2c74e45955f1a26f73 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Mon, 30 Apr 2018 15:47:57 +0200 Subject: [PATCH 11/17] created chapter 0 --- active_projects/eop/chapter0.py | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 active_projects/eop/chapter0.py diff --git a/active_projects/eop/chapter0.py b/active_projects/eop/chapter0.py new file mode 100644 index 00000000..94a9d9df --- /dev/null +++ b/active_projects/eop/chapter0.py @@ -0,0 +1,82 @@ +from big_ol_pile_of_manim_imports import * + +class Introduction(TeacherStudentsScene): + + CONFIG = { + "default_pi_creature_kwargs": { + "color": MAROON_E, + "flip_at_start": True, + }, + } + + def construct(self): + self.show_series() + self.show_examples() + + def show_series(self): + series = VideoSeries(num_videos = 11) + series.to_edge(UP) + this_video = series[0] + this_video.set_color(YELLOW) + this_video.save_state() + this_video.set_fill(opacity = 0) + this_video.center() + this_video.scale_to_fit_height(FRAME_HEIGHT) + self.this_video = this_video + + + words = TextMobject( + "Welcome to \\\\", + "Essence of Probability" + ) + words.set_color_by_tex("Essence of Probability", YELLOW) + + self.teacher.change_mode("happy") + self.play( + FadeIn( + series, + submobject_mode = "lagged_start", + run_time = 2 + ), + Blink(self.get_teacher()) + ) + self.teacher_says(words, target_mode = "hooray") + self.change_student_modes( + *["hooray"]*3, + look_at_arg = series[1].get_left(), + added_anims = [ + ApplyMethod(this_video.restore, run_time = 3), + ] + ) + self.play(*[ + ApplyMethod( + video.shift, 0.5*video.get_height()*DOWN, + run_time = 3, + rate_func = squish_rate_func( + there_and_back, alpha, alpha+0.3 + ) + ) + for video, alpha in zip(series, np.linspace(0, 0.7, len(series))) + ]+[ + Animation(self.teacher.bubble), + Animation(self.teacher.bubble.content), + ]) + + self.play( + FadeOut(self.teacher.bubble), + FadeOut(self.teacher.bubble.content), + self.get_teacher().change_mode, "raise_right_hand", + *[ + ApplyMethod(pi.change_mode, "pondering") + for pi in self.get_students() + ] + ) + self.wait() + + self.series = series + + + def show_examples(self): + + self.wait(10) + # put examples here in video editor From 9ef8dc257637847b904a2fb2b1175eeda1b85386 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Mon, 30 Apr 2018 15:48:15 +0200 Subject: [PATCH 12/17] created chapter 0, tweaks --- active_projects/eop/chapter1.py | 96 +++++++++++---------------------- 1 file changed, 32 insertions(+), 64 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index caee3fb8..78fe4c7c 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -451,75 +451,29 @@ class Introduction(TeacherStudentsScene): } def construct(self): - self.show_series() - self.show_examples() - - def show_series(self): - series = VideoSeries(num_videos = 11) - series.to_edge(UP) - this_video = series[0] - this_video.set_color(YELLOW) - this_video.save_state() - this_video.set_fill(opacity = 0) - this_video.center() - this_video.scale_to_fit_height(FRAME_HEIGHT) - self.this_video = this_video - - - words = TextMobject( - "Welcome to \\\\", - "Essence of Probability" - ) - words.set_color_by_tex("Essence of Probability", YELLOW) - - self.teacher.change_mode("happy") - self.play( - FadeIn( - series, - submobject_mode = "lagged_start", - run_time = 2 - ), - Blink(self.get_teacher()) - ) - self.teacher_says(words, target_mode = "hooray") + + self.wait() + self.change_student_modes( - *["hooray"]*3, - look_at_arg = series[1].get_left(), - added_anims = [ - ApplyMethod(this_video.restore, run_time = 3), - ] + "confused", "frustrated", "dejected", + look_at_arg = UP + 2 * RIGHT ) - self.play(*[ - ApplyMethod( - video.shift, 0.5*video.get_height()*DOWN, - run_time = 3, - rate_func = squish_rate_func( - there_and_back, alpha, alpha+0.3 - ) - ) - for video, alpha in zip(series, np.linspace(0, 0.7, len(series))) - ]+[ - Animation(self.teacher.bubble), - Animation(self.teacher.bubble.content), - ]) + + self.wait() + + + self.get_teacher().change_mode("hooray") + self.wait() self.play( - FadeOut(self.teacher.bubble), - FadeOut(self.teacher.bubble.content), self.get_teacher().change_mode, "raise_right_hand", *[ - ApplyMethod(pi.change_mode, "pondering") + ApplyMethod(pi.change, "pondering", {"look_at_arg" : UP + 2 * LEFT}) for pi in self.get_students() ] ) - self.wait() - self.series = series - - - def show_examples(self): - - self.wait(10) + self.wait(30) # put examples here in video editor @@ -1001,7 +955,7 @@ class RowOfDice(VGroup): class ShowUncertainty1(Scene): - def throw_a_die(self): + def throw_a_die(self, run_time = 0.3): eye = np.random.randint(1,7) face = self.row_of_dice.submobjects[eye - 1] @@ -1009,7 +963,7 @@ class ShowUncertainty1(Scene): self.play( ApplyMethod(face.submobjects[0].set_fill, {"opacity": 1}, rate_func = there_and_back, - run_time = 0.3, + run_time = run_time, ), ) @@ -1026,9 +980,9 @@ class ShowUncertainty1(Scene): self.throw_a_die() self.wait(0.3) - for i in range(10): - self.throw_a_die() - self.wait(0.1) + for i in range(100): + self.throw_a_die(0.05) + self.wait(0.0) @@ -1386,6 +1340,20 @@ class SplitRectsInBrickWall(Animation): +class JustFlipping(Scene): + + def construct(self): + + randy = CoinFlippingPiCreature() + self.add(randy) + + self.wait(2) + + for i in range(10): + self.wait() + self.play(FlipCoin(randy)) + + class BrickRowScene(Scene): From 85808eb905c8e27151f06f81b72da6ae0242234d Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 2 May 2018 11:09:53 +0200 Subject: [PATCH 13/17] bug in debugging method --- active_projects/eop/chapter1.py | 420 +++++++++++++++++++++++--------- mobject/mobject.py | 2 +- 2 files changed, 312 insertions(+), 110 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 78fe4c7c..047262ac 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -452,7 +452,7 @@ class Introduction(TeacherStudentsScene): def construct(self): - self.wait() + self.wait(5) self.change_student_modes( "confused", "frustrated", "dejected", @@ -462,17 +462,9 @@ class Introduction(TeacherStudentsScene): self.wait() - self.get_teacher().change_mode("hooray") + self.get_teacher().change_mode("raise_right_hand") self.wait() - self.play( - self.get_teacher().change_mode, "raise_right_hand", - *[ - ApplyMethod(pi.change, "pondering", {"look_at_arg" : UP + 2 * LEFT}) - for pi in self.get_students() - ] - ) - self.wait(30) # put examples here in video editor @@ -1057,10 +1049,130 @@ class ShowUncertainty2(Scene): self.throw_darts(1000,5) +SICKLY_GREEN = "#9BBD37" + + +class SicklyPiCreature(PiCreature): + CONFIG = { + "sick_color": SICKLY_GREEN + } + + def get_slightly_sick(self): + + self.save_state() + self.set_color(self.sick_color) + + def get_sick(self): + + self.get_slightly_sick() + self.change_mode("sick") + + def get_better(self): + self.restore() + + +class RandyIsSickOrNot(Scene): + + + def construct(self): + title = TextMobject("1 in 200") + title.to_edge(UP) + + + randy = SicklyPiCreature() + randy.scale_to_fit_height(3) + randy.move_to(2*LEFT) + randy.change_mode("plain") + randy.set_color(BLUE) + randy.save_state() + + self.add(randy) + + p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%").scale(1.7) + p_sick.set_color_by_tex("sick", SICKLY_GREEN) + p_sick.next_to(randy, UP, buff = LARGE_BUFF) + self.add(p_sick) + self.wait() + + self.play( + ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back) + ) + self.play(Blink(randy)) + self.wait(2) + + self.play( + ApplyMethod(randy.get_sick) + ) + + self.play(Blink(randy)) + self.wait() + + self.play(randy.get_better) + + self.play( + ApplyMethod(randy.get_slightly_sick, rate_func = there_and_back) + ) + self.play(Blink(randy)) + self.wait(0.5) + + self.play( + ApplyMethod(randy.get_sick) + ) + + self.play(Blink(randy)) + self.play(randy.get_better) + self.wait(3) -class ShowUncertainty3(Scene): +class OneIn200HasDisease(Scene): + def construct(self): + title = TextMobject("1 in 200") + title.to_edge(UP) + creature = PiCreature() + + all_creatures = VGroup(*[ + VGroup(*[ + creature.copy() + for y in range(20) + ]).arrange_submobjects(DOWN, SMALL_BUFF) + for x in range(10) + ]).arrange_submobjects(RIGHT, SMALL_BUFF) + all_creatures.scale_to_fit_height(FRAME_HEIGHT * 0.8) + all_creatures.next_to(title, DOWN) + randy = all_creatures[0][0] + all_creatures[0].remove(randy) + randy.change_mode("sick") + randy.set_color(SICKLY_GREEN) + randy.save_state() + randy.scale_to_fit_height(3) + randy.center() + randy.change_mode("plain") + randy.set_color(BLUE) + + self.add(randy) + + #p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%") + #p_sick.set_color_by_tex("sick", SICKLY_GREEN) + #p_sick.next_to(randy, RIGHT+UP) + #self.add(p_sick) + self.wait() + + self.play( + randy.change_mode, "sick", + randy.set_color, SICKLY_GREEN + ) + self.play(Blink(randy)) + self.play(randy.restore) + self.wait() + self.play( + Write(title), + LaggedStart(FadeIn, all_creatures, run_time = 3) + ) + self.wait() + + +class RandyFlipsAndStacks(Scene): def construct(self): @@ -1100,52 +1212,39 @@ class ShowUncertainty3(Scene): -SICKLY_GREEN = "#9BBD37" +class TwoDiceTable(Scene): -class OneIn200HasDisease(Scene): def construct(self): - title = TextMobject("1 in 200") - title.to_edge(UP) - creature = PiCreature() - all_creatures = VGroup(*[ - VGroup(*[ - creature.copy() - for y in range(20) - ]).arrange_submobjects(DOWN, SMALL_BUFF) - for x in range(10) - ]).arrange_submobjects(RIGHT, SMALL_BUFF) - all_creatures.scale_to_fit_height(FRAME_HEIGHT * 0.8) - all_creatures.next_to(title, DOWN) - randy = all_creatures[0][0] - all_creatures[0].remove(randy) - randy.change_mode("sick") - randy.set_color(SICKLY_GREEN) - randy.save_state() - randy.scale_to_fit_height(3) - randy.center() - randy.change_mode("plain") - randy.set_color(BLUE) + table = VGroup() + cell_size = 1 + colors = np.random.permutation(color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], 13)) + + for i in range(1,7): + for j in range(1,7): + cell = Square(side_length = cell_size) + cell.set_fill(color = colors[i+j], opacity = 0.8) + label = Integer(i+j) + label.move_to(cell) + cell.add(label) + cell.move_to(i*cell_size*RIGHT + j*cell_size*DOWN) + table.add(cell) + + table.center() + self.add(table) + + row1 = RowOfDice().match_width(table) + print row1.is_subpath + row2 = row1.copy().rotate(-TAU/4) + print row2.is_subpath + row1.next_to(table, UP) + row2.next_to(table, LEFT) + self.add(row1, row2) + + + - self.add(randy) - p_sick = TexMobject("p(","\\text{sick}",") = 0.5\%") - p_sick.set_color_by_tex("sick", SICKLY_GREEN) - p_sick.next_to(randy, RIGHT+UP) - self.add(p_sick) - self.wait() - self.play( - randy.change_mode, "sick", - randy.set_color, SICKLY_GREEN - ) - self.play(Blink(randy)) - self.play(randy.restore) - self.play( - FadeOut(p_sick), - Write(title), - LaggedStart(FadeIn, all_creatures, run_time = 3) - ) - self.wait() @@ -1344,7 +1443,7 @@ class JustFlipping(Scene): def construct(self): - randy = CoinFlippingPiCreature() + randy = CoinFlippingPiCreature().shift(2 * DOWN) self.add(randy) self.wait(2) @@ -1355,6 +1454,46 @@ class JustFlipping(Scene): +class JustFlippingWithResults(Scene): + + def construct(self): + + randy = CoinFlippingPiCreature().shift(2 * DOWN) + self.add(randy) + + self.wait(2) + + for i in range(10): + self.wait() + self.play(FlipCoin(randy)) + result = random.choice(["H", "T"]) + if result == "H": + coin = UprightHeads().scale(3) + else: + coin = UprightTails().scale(3) + coin.move_to(2 * UP + 2.5 * LEFT + i * 0.6 * RIGHT) + self.play(FadeIn(coin)) + + + +class WhatDoesItReallyMean(TeacherStudentsScene): + + CONFIG = { + "default_pi_creature_kwargs": { + "color": MAROON_E, + "flip_at_start": True, + }, + } + + def construct(self): + + student_q = TextMobject("What does", "``probability''", "\emph{actually}", "mean?") + student_q.set_color_by_tex("probability", YELLOW) + self.student_says(student_q, target_mode = "sassy") + self.wait() + self.teacher_says("Don't worry -- philosophy can come later!") + self.wait() + class BrickRowScene(Scene): @@ -1648,7 +1787,7 @@ class BrickRowScene(Scene): def construct(self): - #self.force_skipping() + self.force_skipping() randy = CoinFlippingPiCreature() randy = randy.scale(0.5).move_to(3*DOWN + 6*LEFT) @@ -1764,54 +1903,6 @@ class BrickRowScene(Scene): # self.add_foreground_mobject(self.decimals) - # # # # # # # # - # FOURTH FLIP # - # # # # # # # # - - # self.play(FlipCoin(randy)) - - # self.wait() - - # self.play( - # SplitRectsInBrickWall(self.row) - # ) - # self.wait() - - # self.add_foreground_mobject(self.tallies[-1]) - # # this tweaks an undesirable overlap in the next animation - # self.split_tallies_at_once(direction = LEFT) - # self.wait() - # self.merge_rects_by_subdiv() - # self.wait() - # self.merge_tallies(direction = LEFT) - # self.merge_rects_by_coloring() - # self.merge_decimals() - # self.wait() - - - # # # # # # # # - # FIFTH FLIP # - # # # # # # # # - - # self.play(FlipCoin(randy)) - - # self.wait() - - # self.play( - # SplitRectsInBrickWall(self.row) - # ) - # self.wait() - - # self.split_tallies_at_once(direction = LEFT) - # self.wait() - # self.merge_rects_by_subdiv() - # self.wait() - # self.merge_tallies(direction = LEFT) - # self.merge_rects_by_coloring() - # self.merge_decimals() - # self.wait() - - # # # # # # # # # # # # # # # # FOURTH FLIP IN DETAIL # # # # # # # # # # # # # # # @@ -1890,7 +1981,7 @@ class BrickRowScene(Scene): # show how the outcomes in one tally split into two copies # going into the neighboring tallies - self.revert_to_original_skipping_status() + #self.revert_to_original_skipping_status() target_outcomes = self.row.get_outcome_rects_for_level(n + 1, with_labels = False) grouped_target_outcomes = VGroup() @@ -1995,6 +2086,117 @@ class BrickRowScene(Scene): # self.add_foreground_mobject(new_decimals) + # # # # # # # # + # FIFTH FLIP # + # # # # # # # # + + # self.remove( + # grouped_outcomes, + # grouped_outcomes_copy, + # grouped_target_outcomes, + # target_outcomes, + # outcomes, + # previous_row, + # original_grouped_outcomes) + self.clear() + self.add(randy, self.row) + self.row.shift(0.5 * UP) + + + self.merge_rects_by_coloring() + + self.revert_to_original_skipping_status() + + for i in range(3): + + self.play(FlipCoin(randy)) + + self.wait() + + self.play( + SplitRectsInBrickWall(self.row) + ) + self.wait() + + #self.split_tallies_at_once(direction = LEFT) + self.wait() + self.merge_rects_by_subdiv() + self.wait() + #self.merge_tallies(direction = LEFT) + self.merge_rects_by_coloring() + #self.merge_decimals() + self.wait() + +class LevelsOfDetailInBrickRow(BrickRowScene): + + def construct(self): + + self.force_skipping() + + randy = CoinFlippingPiCreature() + randy = randy.scale(0.5).move_to(3*DOWN + 6*LEFT) + self.add(randy) + self.row = BrickRow(1, height = 2, width = 10) + + #self.decimals = VGroup() + + self.play(FlipCoin(randy), + FadeIn(self.row)) + + + self.wait() + + # put tallies on top + + self.tallies = VGroup(*[ + TallyStack(1 - i, i) for i in range(2) + ]) + for (tally, rect) in zip(self.tallies, self.row.rects): + new_anchor = rect.get_center() + 1.2 * 0.5 * rect.get_height() * UP + tally.move_anchor_to(new_anchor) + self.play(FadeIn(tally)) + + self.add_foreground_mobject(self.tallies) + self.wait() + + + # # # # # # # # + # SECOND FLIP # + # # # # # # # # + + + + self.play(FlipCoin(randy)) + self.wait() + + + self.play( + SplitRectsInBrickWall(self.row) + ) + self.wait() + + # show individual outcomes + outcomes = self.row.get_outcome_rects_for_level(2, with_labels = True) + self.play( + LaggedStart(FadeIn, outcomes) + ) + self.wait() + self.play( + LaggedStart(FadeOut, outcomes) + ) + + self.split_tallies_in_two_steps() + self.wait() + self.merge_rects_by_subdiv() + self.wait() + self.merge_tallies() + self.merge_rects_by_coloring() + self.wait() + self.move_tallies_on_top() + + + + class OutlineableBars(VGroup): CONFIG = { @@ -2123,13 +2325,13 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): label.next_to(self.bar_anchors[i], DOWN) x_labels.add(label) - nb_heads_label = TextMobject("\# of heads") - nb_heads_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) + nb_tails_label = TextMobject("\# of tails") + nb_tails_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) self.play( FadeIn(x_axis), FadeIn(x_labels), - FadeIn(nb_heads_label) + FadeIn(nb_tails_label) ) @@ -2201,13 +2403,13 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): label.next_to(self.bar_anchors[i], DOWN) x_labels.add(label) - nb_heads_label = TextMobject("\# of heads") - nb_heads_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) + nb_tails_label = TextMobject("\# of heads") + nb_tails_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) self.play( FadeIn(x_axis), FadeIn(x_labels), - FadeIn(nb_heads_label) + FadeIn(nb_tails_label) ) # draw y-guides diff --git a/mobject/mobject.py b/mobject/mobject.py index 123b5206..235ed515 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -767,7 +767,7 @@ class Mobject(Container): """For debugging purposes""" print "\t" * n_tabs, self, id(self) for submob in self.submobjects: - submob.print_mobject_family(n_tabs + 1) + submob.print_submobject_family(n_tabs + 1) # Alignment def align_data(self, mobject): From 51129b51ba844ba87c96fb7cf9c531e8c6222c87 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 2 May 2018 17:17:34 +0200 Subject: [PATCH 14/17] TeXMobject convenience subclass --- mobject/svg/tex_mobject.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mobject/svg/tex_mobject.py b/mobject/svg/tex_mobject.py index 2fbe11f3..cbb57a72 100644 --- a/mobject/svg/tex_mobject.py +++ b/mobject/svg/tex_mobject.py @@ -275,6 +275,14 @@ class BulletedList(TextMobject): else: other_part.set_fill(opacity=opacity) + +class TexMobjectFromPresetString(TexMobject): + + def __init__(self, **kwargs): + digest_config(self, kwargs) + TexMobject.__init__(self, self.tex, **kwargs) + self.set_color(self.color) + ########## From 337ee743a6ed0390bf1164ca89ae24ae58d8aa5d Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 2 May 2018 17:18:23 +0200 Subject: [PATCH 15/17] tweaking intro scene --- active_projects/eop/chapter1.py | 363 ++++++++++++++-------------- active_projects/eop/independence.py | 14 ++ 2 files changed, 191 insertions(+), 186 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 047262ac..88cfa8e4 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -2,8 +2,10 @@ from big_ol_pile_of_manim_imports import * from old_projects.eoc.chapter8 import * from active_projects.eop.histograms import * from active_projects.eop.independence import * +from active_projects.eop.combinations import * import scipy.special +import itertools as it COIN_RADIUS = 0.18 @@ -15,7 +17,7 @@ COIN_STROKE_WIDTH = 2 COIN_SEQUENCE_SPACING = 0.1 GRADE_COLOR_1 = COLOR_HEADS = RED -GRADE_COLOR_2 = COLOR_TAILS = BLUE +GRADE_COLOR_2 = COLOR_TAILS = BLUE_E TALLY_BACKGROUND_WIDTH = 1.0 @@ -104,10 +106,10 @@ class PiCreatureCoin(VMobject): class CoinFlippingPiCreature(PiCreature): - def __init__(self, **kwargs): + def __init__(self, mode = "coin_flip_1", **kwargs): coin = PiCreatureCoin() - PiCreature.__init__(self,**kwargs) + PiCreature.__init__(self, mode = mode, **kwargs) self.coin = coin self.add(coin) right_arm = self.get_arm_copies()[1] @@ -115,7 +117,9 @@ class CoinFlippingPiCreature(PiCreature): coin.shift(0.15 * self.get_width() * LEFT) def flip_coin_up(self): - self.change("raise_right_hand") + self.change("coin_flip_2") + + class FlipUpAndDown(Animation): CONFIG = { @@ -129,13 +133,14 @@ class FlipUpAndDown(Animation): class FlipCoin(AnimationGroup): CONFIG = { - "rate_func" : there_and_back + "coin_rate_func" : there_and_back, + "pi_rate_func" : there_and_back_with_pause } def __init__(self, pi_creature, **kwargs): digest_config(self, kwargs) pi_creature_motion = ApplyMethod( pi_creature.flip_coin_up, - rate_func = self.rate_func, + rate_func = self.pi_rate_func, **kwargs ) coin_motion = Succession( @@ -144,7 +149,7 @@ class FlipCoin(AnimationGroup): pi_creature.coin, vector = UP, nb_turns = 5, - rate_func = self.rate_func, + rate_func = self.coin_rate_func, **kwargs ) ) @@ -1218,7 +1223,7 @@ class TwoDiceTable(Scene): table = VGroup() cell_size = 1 - colors = np.random.permutation(color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], 13)) + colors = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], 13) for i in range(1,7): for j in range(1,7): @@ -1239,13 +1244,94 @@ class TwoDiceTable(Scene): print row2.is_subpath row1.next_to(table, UP) row2.next_to(table, LEFT) - self.add(row1, row2) + table.add(row1, row2) + table.center() +class VisualCovariance(Scene): + + + def construct(self): + + size = 4 + square = Square(side_length = size) + n_points = 30 + cloud = VGroup(*[ + Dot((x + 0.8*y) * RIGHT + y * UP).set_fill(WHITE, 1) + for x, y in zip( + np.random.normal(0, 1, n_points), + np.random.normal(0, 1, n_points) + ) + ]) + self.add_foreground_mobject(cloud) + + x_axis = Vector(8*RIGHT, color = WHITE).move_to(2.5*DOWN) + y_axis = Vector(5*UP, color = WHITE).move_to(4*LEFT) + + self.add(x_axis, y_axis) + + + random_pairs = [ (p1, p2) for (p1, p2) in + it.combinations(cloud, 2) + ] + np.random.shuffle(random_pairs) + for (p1, p2) in random_pairs: + c1, c2 = p1.get_center(), p2.get_center() + x1, y1, x2, y2 = c1[0], c1[1], c2[0], c2[1] + if x1 >= x2: + continue + if y2 > y1: + # make a red rect + color = RED + opacity = 0.1 + + elif y2 < y1: + # make a blue rect + color = BLUE + opacity = 0.2 + + rect = Rectangle(width = x2 - x1, height = abs(y2 - y1)) + rect.set_fill(color = color, opacity = opacity) + rect.set_stroke(width = 0) + rect.move_to((c1+c2)/2) + + self.play(FadeIn(rect), run_time = 0.05) + + + +class BinaryOption(VMobject): + + def __init__(self, mob1, mob2, **kwargs): + + VMobject.__init__(self, **kwargs) + text = TextMobject("or").scale(0.5) + mob1.next_to(text, LEFT) + mob2.next_to(text, RIGHT) + self.add(mob1, text, mob2) + + + +class BinaryChoices(Scene): + + def construct(self): + + example1 = BinaryOption(UprightHeads(), UprightTails()) + example2 = BinaryOption(Male(), Female()) + example3 = BinaryOption(Checkmark(), Xmark()) + + example2.next_to(example1, DOWN, buff = MED_LARGE_BUFF) + example3.next_to(example2, DOWN, buff = MED_LARGE_BUFF) + + all = VGroup(example1, example2, example3) + all = all.scale(2) + + self.play( + LaggedStart(FadeIn, all) + ) class BrickRow(VMobject): @@ -1403,39 +1489,40 @@ class BrickRow(VMobject): -class SplitRectsInBrickWall(Animation): +class SplitRectsInBrickWall(AnimationGroup): def __init__(self, mobject, **kwargs): r = self.subdiv_level = mobject.subdiv_level + 1 - self.subdivs = VGroup() - x = - 0.5 * mobject.width + subdivs = VGroup() + x = -0.5 * mobject.get_width() + anims = [] for k in range(0, r): proportion = float(choose(r,k)) / 2**r - x += proportion * mobject.width + x += proportion * mobject.get_width() subdiv = DashedLine( - mobject.get_center() + x * RIGHT + 0.5 * mobject.height * UP, - mobject.get_center() + x * RIGHT + 0.5 * mobject.height * UP, + mobject.get_top() + x * RIGHT, + mobject.get_bottom() + x * RIGHT, ) - self.subdivs.add(subdiv) + subdivs.add(subdiv) + anims.append(ShowCreation(subdiv)) - mobject.add(self.subdivs) - - Animation.__init__(self, mobject, **kwargs) + mobject.add(subdivs) + AnimationGroup.__init__(self, *anims, **kwargs) - def update_mobject(self, alpha): - for subdiv in self.subdivs: - x = subdiv.get_start()[0] - start = self.mobject.get_center() - start += x * RIGHT + 0.5 * self.mobject.height * UP - end = start + alpha * self.mobject.height * DOWN - subdiv.put_start_and_end_on(start,end) + # def update_mobject(self, alpha): + # for subdiv in self.subdivs: + # x = subdiv.get_start()[0] + # start = self.mobject.get_center() + # start += x * RIGHT + 0.5 * self.mobject.get_height() * UP + # end = start + alpha * self.mobject.get_height() * DOWN + # subdiv.put_start_and_end_on(start,end) @@ -1497,7 +1584,11 @@ class WhatDoesItReallyMean(TeacherStudentsScene): class BrickRowScene(Scene): + def split_tallies(self, direction = DOWN): + # Split all tally symbols at once and move the copies + # either horizontally on top of the brick row + # or diagonally into the bricks self.tallies_copy = self.tallies.copy() self.add_foreground_mobject(self.tallies_copy) @@ -1522,11 +1613,6 @@ class BrickRowScene(Scene): for (i, tally) in enumerate(self.tallies): - # if len(self.decimals) > 0: - # decimal = self.decimals[i] - # else: - # decimal = VMobject() - target_left = tally_targets_left[i] new_tally_left = TallyStack(tally.nb_heads + 1, tally.nb_tails) new_tally_left.move_anchor_to(target_left) @@ -1534,13 +1620,11 @@ class BrickRowScene(Scene): self.play( tally.move_anchor_to, target_left, - #decimal.shift,v ) tally.anchor = target_left self.play(Transform(tally, new_tally_left)) tally_copy = self.tallies_copy[i] - #decimal_copy = decimal.copy() target_right = tally_targets_right[i] new_tally_right = TallyStack(tally.nb_heads, tally.nb_tails + 1) @@ -1551,14 +1635,18 @@ class BrickRowScene(Scene): tally_copy.anchor = target_right self.play(Transform(tally_copy, new_tally_right)) - tally_copy.nb_heads = new_tally_right.nb_heads tally_copy.nb_tails = new_tally_right.nb_tails tally.nb_heads = new_tally_left.nb_heads tally.nb_tails = new_tally_left.nb_tails + + def tally_split_animations(self, direction = DOWN): + # Just creates the animations and returns them + # Execution can be timed afterwards + # Returns two lists: first all those going left, then those to the right self.tallies_copy = self.tallies.copy() self.add_foreground_mobject(self.tallies_copy) @@ -1583,38 +1671,24 @@ class BrickRowScene(Scene): anims1 = [] - # if len(self.decimals) > 0: - # self.decimal_copies = VGroup() for (i, tally) in enumerate(self.tallies): - # if len(self.decimals) > 0: - # decimal = self.decimals[i] - # else: - # decimal = VMobject() - target_left = tally_targets_left[i] v = target_left - tally.anchor anims1.append(tally.move_anchor_to) anims1.append(target_left) - #anims1.append(decimal.shift) - #anims1.append(v) tally.anchor = target_left tally_copy = self.tallies_copy[i] - #decimal_copy = decimal.copy() target_right = tally_targets_right[i] v = target_right - tally_copy.anchor anims1.append(tally_copy.move_anchor_to) anims1.append(target_right) - #anims1.append(decimal_copy.shift) - #anims1.append(v) - # if len(self.decimals) > 0: - # self.decimal_copies.add(decimal_copy) tally_copy.anchor = target_right @@ -1637,18 +1711,15 @@ class BrickRowScene(Scene): tally.nb_heads = new_tally_left.nb_heads tally.nb_tails = new_tally_left.nb_tails - - - # if len(self.decimals) > 0: - # self.add_foreground_mobject(self.decimal_copies) - return anims1, anims2 + def split_tallies_at_once(self, direction = DOWN): anims1, anims2 = self.tally_split_animations(direction = direction) self.play(*(anims1 + anims2)) def split_tallies_in_two_steps(self, direction = DOWN): + # First all thiode to the left, then those to the right anims1, anims2 = self.tally_split_animations(direction = direction) self.play(*anims1) self.wait(0.3) @@ -1657,41 +1728,6 @@ class BrickRowScene(Scene): - # def split_decimals_alone(self): - - # r = self.row.coloring_level - # targets_left = [] - # targets_right = [] - - # for rect in self.row.get_rects_for_level(r): - # target = rect.get_center() + 0.25 * rect.get_width() * LEFT - # targets_left.append(target) - # target = rect.get_center() + 0.25 * rect.get_width() * RIGHT - # targets_right.append(target) - - # anims = [] - # self.decimal_copies = VGroup() - - # for (i, decimal) in enumerate(self.decimals): - - # anims.append(decimal.move_to) - # anims.append(targets_left[i]) - - # decimal_copy = decimal.copy() - - # anims.append(decimal_copy.move_to) - # anims.append(targets_right[i]) - # self.decimal_copies.add(decimal_copy) - - - # self.play(*anims) - - # self.add_foreground_mobject(self.decimal_copies) - - - - - def merge_rects_by_subdiv(self): half_merged_row = self.row.copy() @@ -1739,44 +1775,12 @@ class BrickRowScene(Scene): merged_row = self.row.copy() merged_row.coloring_level += 1 merged_row.generate_points() + merged_row.move_to(self.row) self.play(FadeIn(merged_row)) self.row = merged_row - # def merge_decimals(self): - - # anims = [] - # self.new_decimals = VGroup() - # self.decimal_copies = VGroup() - - # if self.decimals in self.mobjects: - # anims.append(FadeOut(self.decimals)) - # if self.decimal_copies in self.mobjects: - # anims.append(FadeOut(self.decimal_copies)) - - # r = self.row.coloring_level - # for (i, rect) in enumerate(self.row.rects): - # k = choose(r,i) - # decimal = Integer(k) - # decimal.move_to(rect) - # if rect.get_width() < 0.2: - # # then the rect is too narrow, - # # let the decimal go in dignity - # decimal.set_stroke(width = 0) - # decimal.set_fill(opacity = 0) - # self.new_decimals.add(decimal) - - # anims.append(FadeIn(self.new_decimals)) - # self.play(*anims) - - # self.remove(self.decimal_copies) - # self.decimals = self.new_decimals.copy() - # #self.remove(self.new_decimals) - # self.add_foreground_mobject(self.decimals) - - - def move_tallies_on_top(self): self.play( @@ -1787,34 +1791,67 @@ class BrickRowScene(Scene): def construct(self): - self.force_skipping() randy = CoinFlippingPiCreature() randy = randy.scale(0.5).move_to(3*DOWN + 6*LEFT) self.add(randy) - self.row = BrickRow(1, height = 2, width = 10) - - #self.decimals = VGroup() + self.row = BrickRow(0, height = 2, width = 10) + self.wait() - self.play(FlipCoin(randy), - FadeIn(self.row)) + self.play(FadeIn(self.row)) self.wait() + + + # move in all kinds of sequences + coin_seqs = VGroup() + for i in range(20): + n = np.random.randint(1,10) + seq = [np.random.choice(["H", "T"]) for j in range(n)] + coin_seq = CoinSequence(seq).scale(1.5) + loc = np.random.uniform(low = -1, high = 1) * FRAME_X_RADIUS * RIGHT + loc += np.random.uniform(low = -1, high = 1) * FRAME_Y_RADIUS * UP + coin_seq.move_to(loc) + + coin_seq.target = coin_seq.copy().scale(0.3).move_to(0.4 * loc) + coin_seq.target.fade(1) + coin_seqs.add(coin_seq) + + self.play( + LaggedStart( + Succession, coin_seqs, lambda m: (FadeIn(m, run_time = 0.1), MoveToTarget(m)), + run_time = 5, + lag_ratio = 0.5 + ) + ) + + + self.play(SplitRectsInBrickWall(self.row)) + self.merge_rects_by_subdiv() + self.merge_rects_by_coloring() + # # put tallies on top - self.tallies = VGroup(*[ - TallyStack(1 - i, i) for i in range(2) - ]) - for (tally, rect) in zip(self.tallies, self.row.rects): - new_anchor = rect.get_center() + 1.2 * 0.5 * rect.get_height() * UP - tally.move_anchor_to(new_anchor) - self.play(FadeIn(tally)) + self.single_flip_labels = VGroup(UprightHeads(), UprightTails()) + for (label, rect) in zip(self.single_flip_labels, self.row.rects): + label.next_to(rect, UP) + self.play(FadeIn(label)) + self.wait() - self.add_foreground_mobject(self.tallies) + #self.tallies = VGroup(*[ + # TallyStack(1 - i, i) for i in range(2) + #]) + # for (label, rect) in zip(self.single_flip_labels, self.row.rects): + # new_anchor = rect.get_center() + 1.2 * 0.5 * rect.get_height() * UP + # label.move_anchor_to(new_anchor) + # self.play(FadeIn(label)) + # self.wait() + + self.add_foreground_mobject(self.single_flip_labels) self.wait() - + return # # # # # # # # # SECOND FLIP # @@ -1890,18 +1927,6 @@ class BrickRowScene(Scene): LaggedStart(FadeOut, outcomes) ) - # # show their numbers - # nb_outcomes = [1,3,3,1] - # self.decimals = VGroup() - # for (n,rect) in zip(nb_outcomes, self.row.rects): - # decimal = Integer(n).move_to(rect) - # self.decimals.add(decimal) - # self.play( - # LaggedStart(FadeIn, self.decimals) - # ) - # self.wait() - # self.add_foreground_mobject(self.decimals) - # # # # # # # # # # # # # # # # FOURTH FLIP IN DETAIL # @@ -2049,42 +2074,6 @@ class BrickRowScene(Scene): #decimals_copy2[k].move_to, new_rects[k], ) - # show new outcome sizes - # new_decimals = VGroup() - # for (i,rect) in zip(new_tally_sizes, new_rects): - # decimal = Integer(i).move_to(rect) - # new_decimals.add(decimal) - - # self.play( - # FadeOut(decimals_copy[k - 1]), - # FadeOut(decimals_copy2[k]), - # FadeIn(new_decimals[k]) - # ) - - # # move the old decimals into the new row - # anims = [] - # anims.append(decimals_copy2[0].move_to) - # anims.append(new_rects[0]) - # for i in range(1,k) + range(k + 1, n): - # anims.append(decimals_copy[i - 1].move_to) - # anims.append(new_rects[i]) - # anims.append(decimals_copy2[i].move_to) - # anims.append(new_rects[i]) - # anims.append(decimals_copy[n].move_to) - # anims.append(new_rects[n + 1]) - - # # self.play(*anims) - - # # fade them out and fade in their sums - # anims = [] - # for i in range(1,k) + range(k + 1, n): - # anims.append(FadeOut(decimals_copy[i - 1])) - # anims.append(FadeOut(decimals_copy2[i])) - # anims.append(FadeIn(new_decimals[i])) - - # self.play(*anims) - - # self.add_foreground_mobject(new_decimals) # # # # # # # # # FIFTH FLIP # @@ -2100,14 +2089,15 @@ class BrickRowScene(Scene): # original_grouped_outcomes) self.clear() self.add(randy, self.row) - self.row.shift(0.5 * UP) + #self.row.shift(0.5 * UP) + #return self.merge_rects_by_coloring() self.revert_to_original_skipping_status() - for i in range(3): + for i in range(1): self.play(FlipCoin(randy)) @@ -2118,6 +2108,7 @@ class BrickRowScene(Scene): ) self.wait() + #self.split_tallies_at_once(direction = LEFT) self.wait() self.merge_rects_by_subdiv() diff --git a/active_projects/eop/independence.py b/active_projects/eop/independence.py index 48fd868b..1d050fc2 100644 --- a/active_projects/eop/independence.py +++ b/active_projects/eop/independence.py @@ -32,6 +32,20 @@ def get_quiz(*questions): quiz.scale(0.7) return quiz +class Checkmark(TexMobjectFromPresetString): + CONFIG = { + "tex" : "\\checkmark", + "color" : GREEN + } + +class Xmark(TexMobjectFromPresetString): + CONFIG = { + "tex" : "\\times", + "color" : RED + } + + + def get_slot_group( bool_list, buff = MED_LARGE_BUFF, From a222181d77e99944da61e16168016486d2deff59 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Thu, 3 May 2018 12:15:36 +0200 Subject: [PATCH 16/17] added decimal tallies --- active_projects/eop/chapter1.py | 129 ++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 15 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index 88cfa8e4..bb1073dc 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -20,6 +20,7 @@ GRADE_COLOR_1 = COLOR_HEADS = RED GRADE_COLOR_2 = COLOR_TAILS = BLUE_E TALLY_BACKGROUND_WIDTH = 1.0 +TALLY_BACKGROUND_COLOR = BLACK def get_example_quiz(): quiz = get_quiz( @@ -312,10 +313,11 @@ class TailsStack(CoinStack): class TallyStack(VGroup): CONFIG = { - "coin_thickness": COIN_THICKNESS + "coin_thickness": COIN_THICKNESS, + "show_decimals": True } - def __init__(self,h,t,anchor = ORIGIN, **kwargs): + def __init__(self, h, t, anchor = ORIGIN, **kwargs): self.nb_heads = h self.nb_tails = t self.anchor = anchor @@ -331,21 +333,36 @@ class TallyStack(VGroup): self.heads_stack = stack1 self.tails_stack = stack2 self.add(stack1, stack2) - background_rect = RoundedRectangle( + self.background_rect = background_rect = RoundedRectangle( width = TALLY_BACKGROUND_WIDTH, height = TALLY_BACKGROUND_WIDTH, corner_radius = 0.1, - fill_color = DARK_GREY, + fill_color = TALLY_BACKGROUND_COLOR, fill_opacity = 1.0, stroke_width = 3 ).align_to(self.anchor, DOWN).shift(0.1 * DOWN) self.add_to_back(background_rect) + self.decimal_tally = DecimalTally(self.nb_heads, self.nb_tails) + self.position_decimal_tally(self.decimal_tally) + if self.show_decimals: + self.add(self.decimal_tally) + + def position_decimal_tally(self, decimal_tally): + decimal_tally.match_width(self.background_rect) + print self.background_rect.get_center() + decimal_tally.scale(0.6) + decimal_tally.next_to(self.background_rect.get_top(), DOWN, buff = 0.15) + return decimal_tally + + def move_anchor_to(self, new_anchor): for submob in self.submobjects: submob.shift(new_anchor - self.anchor) self.anchor = new_anchor + self.position_decimal_tally(self.decimal_tally) + return self class CoinFlipTree(VGroup): @@ -1582,6 +1599,17 @@ class WhatDoesItReallyMean(TeacherStudentsScene): self.wait() +class DecimalTally(TextMobject): + + def __init__(self, heads, tails, **kwargs): + + TextMobject.__init__(self, str(heads), "\\textemdash\,", str(tails), **kwargs) + self[0].set_color(COLOR_HEADS) + self[-1].set_color(COLOR_TAILS) + # this only works for single-digit tallies + + + class BrickRowScene(Scene): @@ -1809,8 +1837,8 @@ class BrickRowScene(Scene): n = np.random.randint(1,10) seq = [np.random.choice(["H", "T"]) for j in range(n)] coin_seq = CoinSequence(seq).scale(1.5) - loc = np.random.uniform(low = -1, high = 1) * FRAME_X_RADIUS * RIGHT - loc += np.random.uniform(low = -1, high = 1) * FRAME_Y_RADIUS * UP + loc = np.random.uniform(low = -10, high = 10) * RIGHT + loc += np.random.uniform(low = -6, high = 6) * UP coin_seq.move_to(loc) coin_seq.target = coin_seq.copy().scale(0.3).move_to(0.4 * loc) @@ -1833,8 +1861,8 @@ class BrickRowScene(Scene): # # put tallies on top - self.single_flip_labels = VGroup(UprightHeads(), UprightTails()) - for (label, rect) in zip(self.single_flip_labels, self.row.rects): + single_flip_labels = VGroup(UprightHeads(), UprightTails()) + for (label, rect) in zip(single_flip_labels, self.row.rects): label.next_to(rect, UP) self.play(FadeIn(label)) self.wait() @@ -1848,36 +1876,107 @@ class BrickRowScene(Scene): # self.play(FadeIn(label)) # self.wait() - self.add_foreground_mobject(self.single_flip_labels) + #self.add_foreground_mobject(single_flip_labels) self.wait() - return # # # # # # # # # SECOND FLIP # # # # # # # # # - - self.play(FlipCoin(randy)) self.wait() - self.play( SplitRectsInBrickWall(self.row) ) self.wait() + + # split sequences + single_flip_labels_copy = single_flip_labels.copy() + self.add(single_flip_labels_copy) + + + v = self.row.get_outcome_centers_for_level(2)[0] - single_flip_labels[0].get_center() + self.play( + single_flip_labels.shift, v + ) + new_heads = VGroup(UprightHeads(), UprightHeads()) + for i in range(2): + new_heads[i].move_to(single_flip_labels[i]) + new_heads[i].shift(COIN_SEQUENCE_SPACING * DOWN) + self.play(FadeIn(new_heads)) + + v = self.row.get_outcome_centers_for_level(2)[-1] - single_flip_labels_copy[-1].get_center() + self.play( + single_flip_labels_copy.shift, v + ) + new_tails = VGroup(UprightTails(), UprightTails()) + for i in range(2): + new_tails[i].move_to(single_flip_labels_copy[i]) + new_tails[i].shift(COIN_SEQUENCE_SPACING * DOWN) + self.play(FadeIn(new_tails)) + + + decimal_tallies = VGroup() + # introduce notion of tallies + for (i, rect) in enumerate(self.row.get_rects_for_level(2)): + tally = DecimalTally(2-i, i) + tally.next_to(rect, UP) + decimal_tallies.add(tally) + self.play(FadeIn(tally)) + self.wait() + + self.add_foreground_mobject(single_flip_labels) + self.add_foreground_mobject(new_heads) + self.add_foreground_mobject(single_flip_labels_copy) + self.add_foreground_mobject(new_tails) + # show individual outcomes - outcomes = self.row.get_outcome_rects_for_level(2, with_labels = True) + outcomes = self.row.get_outcome_rects_for_level(2, with_labels = False) + + self.play( LaggedStart(FadeIn, outcomes) ) self.wait() self.play( - LaggedStart(FadeOut, outcomes) + LaggedStart(FadeOut, outcomes), ) + self.play( + FadeOut(single_flip_labels), + FadeOut(new_heads), + FadeOut(single_flip_labels_copy), + FadeOut(new_tails) + ) + + self.tallies = VGroup() + for (i, rect) in enumerate(self.row.get_rects_for_level(2)): + tally = TallyStack(2-i, i, show_decimals = False) + tally.move_to(rect) + self.tallies.add(tally) + + + self.play(FadeIn(self.tallies)) + + anims = [] + for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): + anims.append(ApplyFunction( + tally_stack.position_decimal_tally, decimal_tally + )) + + self.play(*anims) + + # replace the original decimal tallies with + # the ones that belong to the TallyStacks + for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): + self.remove(decimal_tally) + tally_stack.position_decimal_tally(tally_stack.decimal_tally) + tally_stack.add(tally_stack.decimal_tally) + return + self.split_tallies_in_two_steps() self.wait() self.merge_rects_by_subdiv() From fa00363313d7d5cbd18134301858b6e872e22a08 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Thu, 3 May 2018 12:16:21 +0200 Subject: [PATCH 17/17] tweaked coin flipping motion --- active_projects/eop/chapter1.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py index bb1073dc..89d62e2b 100644 --- a/active_projects/eop/chapter1.py +++ b/active_projects/eop/chapter1.py @@ -114,8 +114,10 @@ class CoinFlippingPiCreature(PiCreature): self.coin = coin self.add(coin) right_arm = self.get_arm_copies()[1] + coin.rotate(-TAU/24) coin.next_to(right_arm, RIGHT+UP, buff = 0) - coin.shift(0.15 * self.get_width() * LEFT) + coin.shift(0.1 * self.get_width() * LEFT) + coin.shift(0.2 * DOWN) def flip_coin_up(self): self.change("coin_flip_2") @@ -125,17 +127,18 @@ class CoinFlippingPiCreature(PiCreature): class FlipUpAndDown(Animation): CONFIG = { "vector" : UP, + "height" : 3, "nb_turns" : 1 } def update(self,t): - self.mobject.shift(4 * t * (1 - t) * self.vector) + self.mobject.shift(self.height * 4 * t * (1 - t) * self.vector) self.mobject.rotate(t * self.nb_turns * TAU) class FlipCoin(AnimationGroup): CONFIG = { "coin_rate_func" : there_and_back, - "pi_rate_func" : there_and_back_with_pause + "pi_rate_func" : lambda t : there_and_back_with_pause(t, 1./4) } def __init__(self, pi_creature, **kwargs): digest_config(self, kwargs)