From 69d899a6fefc3d368b3f44b36a7c28809a5dbff2 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Tue, 8 May 2018 13:23:24 +0200 Subject: [PATCH 01/17] trying (and failing) to get the pi creature to flash through the class --- .../eop/chapter1/brick_row_scene.py | 49 +++++++++++++++++-- .../eop/chapter1/prob_dist_visuals.py | 43 ++++++---------- active_projects/eop/chapter1/quiz_result.py | 42 ++++++++++------ active_projects/eop/reusables/histograms.py | 9 ++++ for_3b1b_videos/pi_class.py | 39 +++++++++++++++ mobject/mobject.py | 4 +- 6 files changed, 140 insertions(+), 46 deletions(-) create mode 100644 for_3b1b_videos/pi_class.py diff --git a/active_projects/eop/chapter1/brick_row_scene.py b/active_projects/eop/chapter1/brick_row_scene.py index 6c8b06f6..68e7a8a5 100644 --- a/active_projects/eop/chapter1/brick_row_scene.py +++ b/active_projects/eop/chapter1/brick_row_scene.py @@ -677,11 +677,18 @@ class BrickRowScene(PiCreatureScene): with_labels = True, inset = True) self.play(FadeOut(self.tallies)) - self.play(LaggedStart( - FadeIn, outcomes)) self.wait() self.play(LaggedStart( - FadeOut, outcomes)) + FadeIn, outcomes, + #rate_func = there_and_back_with_pause, + run_time = 5)) + self.wait() + self.play(LaggedStart( + FadeOut, outcomes, + #rate_func = there_and_back_with_pause, + run_time = 5)) + + self.wait() self.play(FadeIn(self.tallies)) brace1 = Brace(self.row.rects[2], UP) @@ -705,6 +712,33 @@ class BrickRowScene(PiCreatureScene): ) self.wait() + + + # put visuals for other probability distribtuions here + + # back to three coin flips, show all 8 outcomes + + self.play( + LaggedStart(FadeIn, outcomes, + #rate_func = there_and_back_with_pause, + run_time = 5), + FadeOut(self.tallies) + ) + self.wait() + self.play( + LaggedStart(FadeOut, outcomes, + #rate_func = there_and_back_with_pause, + run_time = 5), + FadeIn(self.tallies) + ) + + + + + return + + + # # # # # # # # # FOURTH FLIP # # # # # # # # # @@ -889,3 +923,12 @@ class BrickRowScene(PiCreatureScene): #self.merge_decimals() self.wait() + + + + + + + + + diff --git a/active_projects/eop/chapter1/prob_dist_visuals.py b/active_projects/eop/chapter1/prob_dist_visuals.py index 6bd2dbae..1292d7b4 100644 --- a/active_projects/eop/chapter1/prob_dist_visuals.py +++ b/active_projects/eop/chapter1/prob_dist_visuals.py @@ -14,15 +14,25 @@ class ProbabilityDistributions(PiCreatureScene): def construct(self): lag_ratio = 0.2 - run_time = 5 + run_time = 3 + text = TextMobject("Probability distributions", color = YELLOW) + text.to_edge(UP) + text_rect = SurroundingRectangle(text, buff = MED_SMALL_BUFF) + + self.play( + FadeIn(text), + ShowCreation(text_rect) + ) + + # WEATHER FORECAST unit_rect = Rectangle( - height = 4, width = 4 - ) + height = 3, width = 3 + ).shift(DOWN) p_rain = 0.23 p_sun = 1 - p_rain @@ -38,7 +48,7 @@ class ProbabilityDistributions(PiCreatureScene): sun_rect.set_fill(color = YELLOW, opacity = opacity) sun_rect.set_stroke(width = 0) - self.add(unit_rect, rain_rect, sun_rect) + self.play(FadeIn(VGroup(unit_rect, rain_rect, sun_rect))) rain = SVGMobject(file_name = "rain").scale(0.35) sun = SVGMobject(file_name = "sun").scale(0.35) @@ -189,7 +199,8 @@ class ProbabilityDistributions(PiCreatureScene): coin_flip_rect.add(braces, labels) coin_flip_rect.target = coin_flip_rect.copy().scale(0.6) - coin_flip_rect.target.to_corner(UR, buff = LARGE_BUFF) + coin_flip_rect.target.to_corner(UR, buff = MED_LARGE_BUFF) + coin_flip_rect.target.shift(DOWN) self.play( MoveToTarget(coin_flip_rect) @@ -255,25 +266,3 @@ class ProbabilityDistributions(PiCreatureScene): rate_func=there_and_back_with_pause, run_time=run_time ) - - - - - - - - - - - - - - - - - - - - - - diff --git a/active_projects/eop/chapter1/quiz_result.py b/active_projects/eop/chapter1/quiz_result.py index f03700c1..823c7e19 100644 --- a/active_projects/eop/chapter1/quiz_result.py +++ b/active_projects/eop/chapter1/quiz_result.py @@ -1,12 +1,13 @@ - - from big_ol_pile_of_manim_imports import * from active_projects.eop.reusable_imports import * from active_projects.eop.independence import * +from for_3b1b_videos.pi_class import * -class QuizResult(Scene): - +class QuizResult(PiCreatureScene): + CONFIG = { + "pi_creatures_start_on_screen" : False + } def construct(self): @@ -23,14 +24,15 @@ class QuizResult(Scene): return quiz - highlight_color = YELLOW + highlight_color = WHITE nb_students_x = 5 nb_students_y = 3 spacing_students_x = 2.0 spacing_students_y = 2.2 - all_students = VGroup() + all_students = PiCreatureClass( + width = nb_students_x, height = nb_students_y)# VGroup() student_points = [] grades = [] grades_count = [] @@ -39,9 +41,10 @@ class QuizResult(Scene): 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) + #pi = PiCreature().scale(0.3) + #pi.move_to([x,y,0]) + #all_students.add(pi) + all_students[i*nb_students_y + j].move_to([x,y,0]) q1 = np.random.choice([True, False]) q2 = np.random.choice([True, False]) q3 = np.random.choice([True, False]) @@ -55,7 +58,8 @@ class QuizResult(Scene): all_students.move_to(ORIGIN) - self.add(all_students) + self.pi_creatures = all_students + self.play(FadeIn(all_students)) all_quizzes = VGroup() @@ -133,17 +137,20 @@ class QuizResult(Scene): ) grade_hist.move_to(all_students) - self.play(FadeIn(grade_hist)) + self.play( + FadeIn(grade_hist), + FadeOut(all_students) + ) nb_students_label = TextMobject("\# of students", color = highlight_color) - nb_students_label.move_to(3 * LEFT + 2 * UP) + nb_students_label.move_to(5 * LEFT + 2 * UP) arrows = VGroup(*[ - Arrow(nb_students_label, grade_hist.bars[i].get_center(), + Arrow(nb_students_label.get_right(), grade_hist.bars[i].get_center(), color = highlight_color) for i in range(4) ]) - self.play(Write(nb_students_label), LaggedStart(ShowCreation,arrows)) + self.play(Write(nb_students_label), LaggedStart(GrowArrow,arrows)) percentage_label = TextMobject("\% of students", color = highlight_color) percentage_label.move_to(nb_students_label) @@ -155,6 +162,7 @@ class QuizResult(Scene): unit = "\%", color = highlight_color ) + new_label.scale(0.7) new_label.move_to(label) anims.append(Transform(label, new_label)) anims.append(ReplacementTransform(nb_students_label, percentage_label)) @@ -190,6 +198,12 @@ class QuizResult(Scene): grade_hist, direction = "vertical", mode = "random", + cell_opacity = 0.5, + run_time = 1 + ), + FlashThroughClass( + all_students, + mode = "random", run_time = 5 ) ) diff --git a/active_projects/eop/reusables/histograms.py b/active_projects/eop/reusables/histograms.py index dc1e1b2c..61bbe25e 100644 --- a/active_projects/eop/reusables/histograms.py +++ b/active_projects/eop/reusables/histograms.py @@ -277,6 +277,15 @@ class FlashThroughHistogram(Animation): self.mobject.remove(self.prototype_cell) + def clean_up(self): + self.update(1) + self.remove(prototype_cell) + if surrounding_scene is not None: + if self.is_remover(): + surrounding_scene.remove(self.mobject) + else: + surrounding_scene.add(self.mobject) + return self diff --git a/for_3b1b_videos/pi_class.py b/for_3b1b_videos/pi_class.py new file mode 100644 index 00000000..576ac89f --- /dev/null +++ b/for_3b1b_videos/pi_class.py @@ -0,0 +1,39 @@ +from for_3b1b_videos.pi_creature import * + +class PiCreatureClass(VGroup): + CONFIG = { + "width" : 3, + "height" : 2 + } + + def __init__(self, **kwargs): + VGroup.__init__(self, **kwargs) + for i in range(self.width): + for j in range(self.height): + pi = PiCreature().scale(0.3) + pi.move_to(i*DOWN + j* RIGHT) + self.add(pi) + + + +def FlashThroughClass(Animation): + CONFIG = { + "highlight_color" : GREEN, + } + + def __init__(self, mobject, mode = "linear", **kwargs): + + digest_config(self, kwargs) + self.indices = range(self.height * self.width) + + if mode == "random": + np.random.shuffle(self.indices) + + Animation.__init__(self, mobject, **kwargs) + + + def update_mobject(self, alpha): + index = int(np.floor(alpha * self.height * self.width)) + for pi in self.mobject: + pi.set_color(BLUE_E) + self.mobject[index].set_color(self.highlight_color) diff --git a/mobject/mobject.py b/mobject/mobject.py index 72cfd33a..c069caf1 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -742,8 +742,8 @@ class Mobject(Container): def submobject_family(self): sub_families = map(Mobject.submobject_family, self.submobjects) - # all_mobjects = [self] + list(it.chain(*sub_families)) - all_mobjects = list(it.chain(*sub_families)) + [self] + all_mobjects = [self] + list(it.chain(*sub_families)) + #all_mobjects = list(it.chain(*sub_families)) + [self] return remove_list_redundancies(all_mobjects) def family_members_with_points(self): From 10969590a19703731653e0c3cfb6e0d2e84053c7 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Tue, 8 May 2018 16:19:42 +0200 Subject: [PATCH 02/17] finished histogram morphs --- .../eop/chapter1/brick_row_scene.py | 10 -- .../morph_brick_row_into_histogram.py | 113 +++++++++++------- active_projects/eop/reusables/histograms.py | 2 +- utils/rate_functions.py | 3 + 4 files changed, 74 insertions(+), 54 deletions(-) diff --git a/active_projects/eop/chapter1/brick_row_scene.py b/active_projects/eop/chapter1/brick_row_scene.py index 68e7a8a5..ee2fd287 100644 --- a/active_projects/eop/chapter1/brick_row_scene.py +++ b/active_projects/eop/chapter1/brick_row_scene.py @@ -765,16 +765,6 @@ class BrickRowScene(PiCreatureScene): #self.decimal_copies.shift, v ) - self.add(self.row) - self.bring_to_back(self.row) - self.row.shift(v) - - w = 1.5 * self.row.height * DOWN - self.play( - self.row.shift, w, - Animation(previous_row) - ) - self.play( SplitRectsInBrickWall(self.row) ) diff --git a/active_projects/eop/chapter1/morph_brick_row_into_histogram.py b/active_projects/eop/chapter1/morph_brick_row_into_histogram.py index 7294e9e8..213093b2 100644 --- a/active_projects/eop/chapter1/morph_brick_row_into_histogram.py +++ b/active_projects/eop/chapter1/morph_brick_row_into_histogram.py @@ -9,6 +9,7 @@ class GenericMorphBrickRowIntoHistogram(Scene): "bar_width" : 2.0, "bar_anchor_height" : -3.0, "show_tallies" : False, + "show_nb_flips" : True } def construct(self): @@ -25,13 +26,23 @@ class GenericMorphBrickRowIntoHistogram(Scene): for (i,brick) in enumerate(self.row.rects): tally = TallyStack(self.level - i, i) - tally.next_to(brick, UP) + tally.move_to(brick) self.add(tally) tallies.add(tally) brick.set_stroke(width = 3) + if self.show_nb_flips: + nb_flips_text = TextMobject("\# of flips: " + str(self.level)) + nb_flips_text.to_corner(UR) + self.add(nb_flips_text) + self.remove(self.row.subdivs, self.row.border) + for rect in self.row.rects: + rect.set_stroke(color = WHITE, width = 3) + + self.play(self.row.rects.space_out_submobjects, {"factor" : 1.3}) + anims = [] for brick in self.row.rects: anims.append(brick.rotate) @@ -41,7 +52,7 @@ class GenericMorphBrickRowIntoHistogram(Scene): anims.append(FadeOut(tallies)) self.play(*anims) - + anims = [] for (i,brick) in enumerate(self.row.rects): anims.append(brick.next_to) @@ -50,11 +61,10 @@ class GenericMorphBrickRowIntoHistogram(Scene): self.play(*anims) self.bars.create_outline() - - anims = [] - for bar in self.bars.submobjects: - anims.append(bar.set_stroke) - anims.append({"width" : 0}) + anims = [ + ApplyMethod(rect.set_stroke, {"width" : 0}) + for rect in self.bars + ] anims.append(FadeIn(self.bars.outline)) self.play(*anims) @@ -67,7 +77,8 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): "prob_denominator" : 8, "bar_width" : 2.0, "bar_anchor_height" : -3.0, - "show_tallies" : True + "show_tallies" : True, + "show_nb_flips" : False } def construct(self): @@ -89,56 +100,72 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): 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_tails_label) - ) # draw y-guides y_guides = VMobject() - for i in range(1,self.prob_denominator + 1): + for i in range(0,self.prob_denominator + 1): y_guide = Line(5 * LEFT, 5 * RIGHT, stroke_color = GRAY) 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) - y_guide.add(y_guide_label) + if i != 0: + y_guide.add(y_guide_label) y_guides.add(y_guide) - self.bring_to_back(y_guides) - self.play(FadeIn(y_guides), Animation(self.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( + FadeIn(y_guides), + Animation(self.bars.outline), + Animation(self.bars) ) self.play( - Write(total_area_text), + FadeIn(x_axis), + FadeIn(x_labels), + FadeIn(nb_tails_label) + ) + + self.add_foreground_mobject(nb_tails_label) + area_color = YELLOW + + total_area_text = TextMobject("total area =", color = area_color) + area_decimal = DecimalNumber(0, color = area_color, num_decimal_points = 3) + area_decimal.next_to(total_area_text, RIGHT) + + total_area_group = VGroup(total_area_text, area_decimal) + total_area_group.move_to(2.7 * UP) + + self.play( + FadeIn(total_area_text), + ) + + cumulative_areas = [0.125, 0.5, 0.875, 1] + covering_rects = self.bars.copy() + for (i,rect) in enumerate(covering_rects): + rect.set_fill(color = area_color, opacity = 0.5) + self.play( + FadeIn(rect, rate_func = linear), + ChangeDecimalToValue(area_decimal, cumulative_areas[i], + rate_func = linear) + ) + self.wait(0.2) + + self.wait() + + total_area_rect = SurroundingRectangle( + total_area_group, + buff = MED_SMALL_BUFF, + stroke_color = area_color + ) + + self.play( + FadeOut(covering_rects), ShowCreation(total_area_rect) ) - prob_dist_text = TextMobject("probability distribution", color = YELLOW) - prob_dist_text.to_corner(UP, buff = 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 MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): @@ -165,9 +192,9 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): label.next_to(self.bar_anchors[i], DOWN) x_labels.add(label) - nb_tails_label = TextMobject("\# of heads") - nb_tails_label.next_to(x_labels[-1], RIGHT, MED_LARGE_BUFF) - + nb_tails_label = TextMobject("\# of tails") + nb_tails_label.move_to(5 * RIGHT + 2.5 * DOWN) + self.play( FadeIn(x_axis), FadeIn(x_labels), @@ -199,7 +226,7 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): histogram_height = self.bars.get_height() # scale to fit screen - self.scale_x = 10.0/(len(self.bars) * self.bar_width) + self.scale_x = 10.0/((len(self.bars) - 1) * self.bar_width) self.scale_y = 6.0/histogram_height diff --git a/active_projects/eop/reusables/histograms.py b/active_projects/eop/reusables/histograms.py index 61bbe25e..933d94a2 100644 --- a/active_projects/eop/reusables/histograms.py +++ b/active_projects/eop/reusables/histograms.py @@ -299,7 +299,7 @@ class OutlineableBars(VGroup): # We use this to morph a row of bricks into a histogram. CONFIG = { - "outline_stroke_width" : 5, + "outline_stroke_width" : 3, "stroke_color" : WHITE } def create_outline(self, animated = False, **kwargs): diff --git a/utils/rate_functions.py b/utils/rate_functions.py index 5587cb51..f9ebb142 100644 --- a/utils/rate_functions.py +++ b/utils/rate_functions.py @@ -4,6 +4,9 @@ from utils.bezier import bezier from utils.simple_functions import sigmoid +def linear(t): + return t + def smooth(t, inflection=10.0): error = sigmoid(-inflection / 2) return (sigmoid(inflection * (t - 0.5)) - error) / (1 - 2 * error) From 9a4b0dc7734c6f122bf8015476131ff9262a9479 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Tue, 8 May 2018 18:49:37 +0200 Subject: [PATCH 03/17] finalized brick row scene --- .../eop/chapter1/brick_row_scene.py | 105 +++++++++--------- active_projects/eop/reusables/brick_row.py | 18 +-- 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/active_projects/eop/chapter1/brick_row_scene.py b/active_projects/eop/chapter1/brick_row_scene.py index ee2fd287..49365c6e 100644 --- a/active_projects/eop/chapter1/brick_row_scene.py +++ b/active_projects/eop/chapter1/brick_row_scene.py @@ -717,53 +717,42 @@ class BrickRowScene(PiCreatureScene): # put visuals for other probability distribtuions here # back to three coin flips, show all 8 outcomes - + run_time = 5 self.play( LaggedStart(FadeIn, outcomes, #rate_func = there_and_back_with_pause, - run_time = 5), - FadeOut(self.tallies) + run_time = run_time), + FadeOut(self.tallies, + run_time = run_time) ) self.wait() self.play( LaggedStart(FadeOut, outcomes, #rate_func = there_and_back_with_pause, run_time = 5), - FadeIn(self.tallies) + FadeIn(self.tallies, + run_time = run_time) ) - return - - - # # # # # # # # # FOURTH FLIP # # # # # # # # # - # removing the tallies (boy are they sticky) - self.play(FadeOut(self.tallies)) - self.remove(self.tallies, self.tallies_copy) - for tally in self.tallies: - self.remove_foreground_mobject(tally) - self.remove(tally) - for tally in self.tallies_copy: - self.remove_foreground_mobject(tally) - self.remove(tally) - + previous_row = self.row.copy() self.add(previous_row) v = 1.25 * self.row.height * UP self.play( previous_row.shift, v, - #self.decimals.shift, v, - #self.decimal_copies.shift, v + self.tallies.shift, v, ) + self.add_foreground_mobject(self.tallies) self.play( SplitRectsInBrickWall(self.row) @@ -778,7 +767,10 @@ class BrickRowScene(PiCreatureScene): k = 1 # tally to split # show individual outcomes - outcomes = previous_row.get_outcome_rects_for_level(n, with_labels = False) + outcomes = previous_row.get_outcome_rects_for_level(n, + with_labels = False, + inset = True + ) grouped_outcomes = VGroup() index = 0 for i in range(n + 1): @@ -803,7 +795,10 @@ class BrickRowScene(PiCreatureScene): #self.revert_to_original_skipping_status() - target_outcomes = self.row.get_outcome_rects_for_level(n + 1, with_labels = False) + target_outcomes = self.row.get_outcome_rects_for_level(n + 1, + with_labels = False, + inset = True + ) grouped_target_outcomes = VGroup() index = 0 old_tally_sizes = [choose(n,i) for i in range(n + 1)] @@ -837,6 +832,13 @@ class BrickRowScene(PiCreatureScene): self.wait() + # fade in new tallies + new_rects = self.row.get_rects_for_level(4) + new_tallies = VGroup(*[ + TallyStack(n + 1 - i, i).move_to(rect) for (i, rect) in enumerate(new_rects) + ]) + self.play(FadeIn(new_tallies)) + self.add_foreground_mobject(new_tallies[1]) # remove outcomes and sizes except for one tally anims = [] for i in range(n + 1): @@ -844,6 +846,11 @@ class BrickRowScene(PiCreatureScene): anims.append(FadeOut(grouped_outcomes_copy[i])) if i != k: anims.append(FadeOut(grouped_outcomes[i])) + anims.append(FadeOut(new_tallies[i])) + + #anims.append(FadeOut(self.tallies[0])) + #anims.append(FadeOut(self.tallies[2:])) + anims.append(FadeOut(new_tallies[-1])) self.play(*anims) @@ -852,67 +859,63 @@ class BrickRowScene(PiCreatureScene): self.play( Transform(grouped_outcomes_copy[k - 1], original_grouped_outcomes[k - 1]) ) + self.play( Transform(grouped_outcomes[k], original_grouped_outcomes[k]) ) - new_rects = self.row.get_rects_for_level(n + 1) - #decimals_copy = self.decimals.copy() - #decimals_copy2 = self.decimals.copy() - self.play( 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], + Transform(grouped_outcomes_copy[k - 1][0],grouped_target_outcomes[k][0][:old_tally_sizes[k - 1]]), ) + self.play( + FadeOut(previous_row), + FadeOut(self.tallies), + ) + + self.merge_rects_by_coloring() + + self.play( + FadeIn(new_tallies[0]), + FadeIn(new_tallies[2:]), + ) + + + # # # # # # # # # FIFTH FLIP # # # # # # # # # - # self.remove( - # grouped_outcomes, - # grouped_outcomes_copy, - # grouped_target_outcomes, - # target_outcomes, - # outcomes, - # previous_row, - # original_grouped_outcomes) + self.play(FadeOut(new_tallies)) self.clear() - self.add(randy, self.row) - #self.row.shift(0.5 * UP) + self.add(randy, self.row) - #return - self.merge_rects_by_coloring() - - self.revert_to_original_skipping_status() - - for i in range(1): + for i in range(3): self.play(FlipCoin(randy)) self.wait() + previous_row = self.row.copy() + + self.play(previous_row.shift, 1.25 * self.row.height * UP) + 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.play(FadeOut(previous_row)) + diff --git a/active_projects/eop/reusables/brick_row.py b/active_projects/eop/reusables/brick_row.py index e07bcd88..92ca15f7 100644 --- a/active_projects/eop/reusables/brick_row.py +++ b/active_projects/eop/reusables/brick_row.py @@ -11,7 +11,7 @@ class BrickRow(VMobject): "height" : 1.0, "width" : 8.0, "outcome_shrinkage_factor_x" : 0.95, - "outcome_shrinkage_factor_y" : 0.95 + "outcome_shrinkage_factor_y" : 0.94 } def __init__(self, n, **kwargs): @@ -104,12 +104,12 @@ class BrickRow(VMobject): outcome_width = float(self.width) / (2 ** r) outcome_height = self.height - corner_radius = 0 # min(0.1, 0.3 * min(outcome_width, outcome_height)) + corner_radius = min(0.1, 0.3 * min(outcome_width, outcome_height)) # this scales down the corner radius for very narrow rects - rect = Rectangle( # RoundedRectangle( + rect = RoundedRectangle( width = outcome_width, height = outcome_height, - #corner_radius = corner_radius, + corner_radius = corner_radius, fill_color = WHITE, fill_opacity = 0.2, stroke_width = 0 @@ -205,13 +205,3 @@ class SplitRectsInBrickWall(AnimationGroup): - - - # 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) - From 8207687a61bf0011e3d606c0fc807b96372adffb Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Tue, 8 May 2018 23:55:47 +0200 Subject: [PATCH 04/17] flash through pi creature class working --- active_projects/eop/chapter1/quiz_result.py | 39 +++++++++++------ active_projects/eop/reusables/histograms.py | 13 +++--- for_3b1b_videos/pi_class.py | 30 ++++---------- for_3b1b_videos/pi_creature_animations.py | 46 +++++++++++++++++++++ 4 files changed, 88 insertions(+), 40 deletions(-) diff --git a/active_projects/eop/chapter1/quiz_result.py b/active_projects/eop/chapter1/quiz_result.py index 823c7e19..4d7a0f38 100644 --- a/active_projects/eop/chapter1/quiz_result.py +++ b/active_projects/eop/chapter1/quiz_result.py @@ -2,11 +2,12 @@ from big_ol_pile_of_manim_imports import * from active_projects.eop.reusable_imports import * from active_projects.eop.independence import * -from for_3b1b_videos.pi_class import * +from for_3b1b_videos.pi_class import PiCreatureClass class QuizResult(PiCreatureScene): CONFIG = { - "pi_creatures_start_on_screen" : False + "pi_creatures_start_on_screen" : False, + "random_seed" : 6 } def construct(self): @@ -182,8 +183,8 @@ class QuizResult(PiCreatureScene): 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, + #all_students[:8].fade, 0.6, + #all_students[9:].fade, 0.6, ReplacementTransform(percentage_label, prob_label) ) @@ -192,18 +193,32 @@ class QuizResult(PiCreatureScene): FadeOut(arrows) ) - for i in range(1): - self.play( - FlashThroughHistogram( + flash_hist = FlashThroughHistogram( grade_hist, direction = "vertical", mode = "random", cell_opacity = 0.5, - run_time = 1 - ), - FlashThroughClass( + run_time = 5, + rate_func = linear + ) + + flash_class = FlashThroughClass( all_students, mode = "random", - run_time = 5 + highlight_color = MAROON_E, + run_time = 5, + rate_func = linear ) - ) + + for i in range(3): + self.play(flash_hist, flash_class) + self.remove(flash_hist.prototype_cell) + + + + + + + + + diff --git a/active_projects/eop/reusables/histograms.py b/active_projects/eop/reusables/histograms.py index 933d94a2..91c12e86 100644 --- a/active_projects/eop/reusables/histograms.py +++ b/active_projects/eop/reusables/histograms.py @@ -201,7 +201,10 @@ class FlashThroughHistogram(Animation): "hist_opacity" : 0.2 } - def __init__(self, mobject, direction = "horizontal", mode = "random", **kwargs): + def __init__(self, mobject, + direction = "horizontal", + mode = "random", + **kwargs): digest_config(self, kwargs) @@ -277,14 +280,14 @@ class FlashThroughHistogram(Animation): self.mobject.remove(self.prototype_cell) - def clean_up(self): + def clean_up(self, surrounding_scene = None): + Animation.clean_up(self, surrounding_scene) self.update(1) - self.remove(prototype_cell) if surrounding_scene is not None: if self.is_remover(): - surrounding_scene.remove(self.mobject) + surrounding_scene.remove(self.prototype_cell) else: - surrounding_scene.add(self.mobject) + surrounding_scene.add(self.prototype_cell) return self diff --git a/for_3b1b_videos/pi_class.py b/for_3b1b_videos/pi_class.py index 576ac89f..2c0479d7 100644 --- a/for_3b1b_videos/pi_class.py +++ b/for_3b1b_videos/pi_class.py @@ -1,4 +1,10 @@ -from for_3b1b_videos.pi_creature import * +import numpy as np +import warnings + +from constants import * + +from mobject.types.vectorized_mobject import VGroup +from for_3b1b_videos.pi_creature import PiCreature class PiCreatureClass(VGroup): CONFIG = { @@ -15,25 +21,3 @@ class PiCreatureClass(VGroup): self.add(pi) - -def FlashThroughClass(Animation): - CONFIG = { - "highlight_color" : GREEN, - } - - def __init__(self, mobject, mode = "linear", **kwargs): - - digest_config(self, kwargs) - self.indices = range(self.height * self.width) - - if mode == "random": - np.random.shuffle(self.indices) - - Animation.__init__(self, mobject, **kwargs) - - - def update_mobject(self, alpha): - index = int(np.floor(alpha * self.height * self.width)) - for pi in self.mobject: - pi.set_color(BLUE_E) - self.mobject[index].set_color(self.highlight_color) diff --git a/for_3b1b_videos/pi_creature_animations.py b/for_3b1b_videos/pi_creature_animations.py index 352ae5ce..96721b7f 100644 --- a/for_3b1b_videos/pi_creature_animations.py +++ b/for_3b1b_videos/pi_creature_animations.py @@ -6,6 +6,7 @@ from mobject.mobject import Group from mobject.svg.drawings import SpeechBubble +from animation.animation import Animation from animation.creation import ShowCreation from animation.creation import Write from animation.composition import AnimationGroup @@ -16,6 +17,8 @@ from utils.config_ops import digest_config from utils.rate_functions import squish_rate_func from utils.rate_functions import there_and_back +from for_3b1b_videos.pi_class import PiCreatureClass + class Blink(ApplyMethod): CONFIG = { @@ -101,3 +104,46 @@ class RemovePiCreatureBubble(AnimationGroup): self.pi_creature.bubble = None if surrounding_scene is not None: surrounding_scene.add(self.pi_creature) + + + +class FlashThroughClass(Animation): + CONFIG = { + "highlight_color" : GREEN, + } + + def __init__(self, mobject, mode = "linear", **kwargs): + + if not isinstance(mobject, PiCreatureClass): + raise Exception("FlashThroughClass mobject must be a PiCreatureClass") + digest_config(self, kwargs) + self.indices = range(mobject.height * mobject.width) + + if mode == "random": + np.random.shuffle(self.indices) + + Animation.__init__(self, mobject, **kwargs) + + + def update_mobject(self, alpha): + index = int(np.floor(alpha * self.mobject.height * self.mobject.width)) + + for pi in self.mobject: + pi.set_color(BLUE_E) + if index < self.mobject.height * self.mobject.width: + self.mobject[self.indices[index]].set_color(self.highlight_color) + + + + + + + + + + + + + + + From fb9ce5f518a880fc9b7acb0d9a648a4880941f86 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 16:34:09 +0200 Subject: [PATCH 05/17] made extract_scene play nice with Sublime build --- extract_scene.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/extract_scene.py b/extract_scene.py index ae52be31..d609b7ce 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -151,11 +151,12 @@ def handle_scene(scene, **config): if config["show_file_in_finder"]: commands.append("-R") - # + if config["show_last_frame"]: commands.append(scene.get_image_file_path()) else: commands.append(scene.get_movie_file_path()) + #commands.append("-g") FNULL = open(os.devnull, 'w') sp.call(commands, stdout=FNULL, stderr=sp.STDOUT) FNULL.close() @@ -223,14 +224,18 @@ def get_module_posix(file_name): module_name = file_name.replace(".py", "") last_module = imp.load_module(".", *imp.find_module(".")) for part in module_name.split(os.sep): - load_args = imp.find_module(part, last_module.__path__) - last_module = imp.load_module(part, *load_args) + try: + load_args = imp.find_module(part, last_module.__path__) + last_module = imp.load_module(part, *load_args) + except ImportError: + continue return last_module def get_module(file_name): if os.name == 'nt': return get_module_windows(file_name) + print "file_name =", file_name return get_module_posix(file_name) From 90504e24e7df4b525865b0bf3084e0788cf2bfdb Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 16:35:06 +0200 Subject: [PATCH 06/17] fixed bug for reduce_across_dim for mobs with empty submobs --- mobject/mobject.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mobject/mobject.py b/mobject/mobject.py index c9a2affa..56c87c51 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -623,13 +623,17 @@ class Mobject(Container): values = [] values += [ mob.reduce_across_dimension(points_func, reduce_func, dim) - for mob in self.submobjects + for mob in self.nonempty_submobjects() ] try: return reduce_func(values) except: return 0 + def nonempty_submobjects(self): + return [submob for submob in self.submobjects + if len(submob.submobjects) != 0 or len(submob.points) != 0] + def get_merged_array(self, array_attr): result = None for mob in self.family_members_with_points(): @@ -745,10 +749,7 @@ class Mobject(Container): def submobject_family(self): sub_families = map(Mobject.submobject_family, self.submobjects) all_mobjects = [self] + list(it.chain(*sub_families)) -<<<<<<< HEAD #all_mobjects = list(it.chain(*sub_families)) + [self] -======= ->>>>>>> master return remove_list_redundancies(all_mobjects) def family_members_with_points(self): From 7219ff95f752de413d0739235eec58ad09003198 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 16:36:00 +0200 Subject: [PATCH 07/17] made brick row scene reusable for brick wall --- .../eop/chapter1/brick_row_scene.py | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/active_projects/eop/chapter1/brick_row_scene.py b/active_projects/eop/chapter1/brick_row_scene.py index 49365c6e..b11a66ca 100644 --- a/active_projects/eop/chapter1/brick_row_scene.py +++ b/active_projects/eop/chapter1/brick_row_scene.py @@ -5,7 +5,7 @@ from active_projects.eop.reusable_imports import * class BrickRowScene(PiCreatureScene): - def split_tallies(self, direction = DOWN): + def split_tallies(self, row, 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 @@ -15,12 +15,12 @@ class BrickRowScene(PiCreatureScene): tally_targets_left = [ rect.get_center() + 0.25 * rect.get_width() * LEFT - for rect in self.row.rects + for rect in row.rects ] tally_targets_right = [ rect.get_center() + 0.25 * rect.get_width() * RIGHT - for rect in self.row.rects + for rect in row.rects ] if np.all(direction == LEFT) or np.all(direction == RIGHT): @@ -63,7 +63,7 @@ class BrickRowScene(PiCreatureScene): - def tally_split_animations(self, direction = DOWN): + def tally_split_animations(self, row, 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 @@ -73,12 +73,12 @@ class BrickRowScene(PiCreatureScene): tally_targets_left = [ rect.get_center() + 0.25 * rect.get_width() * LEFT - for rect in self.row.rects + for rect in row.rects ] tally_targets_right = [ rect.get_center() + 0.25 * rect.get_width() * RIGHT - for rect in self.row.rects + for rect in row.rects ] if np.all(direction == LEFT) or np.all(direction == RIGHT): @@ -122,13 +122,14 @@ class BrickRowScene(PiCreatureScene): return anims1, anims2 - def split_tallies_at_once(self, direction = DOWN): - anims1, anims2 = self.tally_split_animations(direction = direction) + + def split_tallies_at_once(self, row, direction = DOWN): + anims1, anims2 = self.tally_split_animations(row, direction = direction) self.play(*(anims1 + anims2)) - def split_tallies_in_two_steps(self, direction = DOWN): + def split_tallies_in_two_steps(self, row, direction = DOWN): # First all those to the left, then those to the right - anims1, anims2 = self.tally_split_animations(direction = direction) + anims1, anims2 = self.tally_split_animations(row, direction = direction) self.play(*anims1) self.wait(0.3) self.play(*anims2) @@ -136,31 +137,31 @@ class BrickRowScene(PiCreatureScene): - def merge_rects_by_subdiv(self): + def merge_rects_by_subdiv(self, row): - half_merged_row = self.row.copy() + half_merged_row = row.copy() half_merged_row.subdiv_level += 1 half_merged_row.generate_points() - half_merged_row.move_to(self.row) + half_merged_row.move_to(row) self.play(FadeIn(half_merged_row)) - self.remove(self.row) - self.row = half_merged_row + self.remove(row) + return half_merged_row - def merge_tallies(self, target_pos = UP): + def merge_tallies(self, row, target_pos = UP): - r = self.row.subdiv_level + r = row.subdiv_level if np.all(target_pos == DOWN): tally_targets = [ rect.get_center() - for rect in self.row.get_rects_for_level(r) + for rect in row.get_rects_for_level(r) ] elif np.all(target_pos == UP): - y_pos = self.row.get_center()[1] + 1.2 * 0.5 * self.row.get_height() + y_pos = row.get_center()[1] + 1.2 * 0.5 * row.get_height() for target in tally_targets: target[1] = y_pos else: @@ -186,25 +187,25 @@ class BrickRowScene(PiCreatureScene): self.tallies.add(self.tallies_copy[-1]) - def merge_rects_by_coloring(self): + def merge_rects_by_coloring(self, row): - merged_row = self.row.copy() + merged_row = row.copy() merged_row.coloring_level += 1 merged_row.generate_points() - merged_row.move_to(self.row) + merged_row.move_to(row) self.play(FadeIn(merged_row)) - self.remove(self.row) - self.row = merged_row + self.remove(row) + return merged_row - def move_tallies_on_top(self): + def move_tallies_on_top(self, row): self.play( - self.tallies.shift, 1.2 * 0.5 * self.row.height * UP + self.tallies.shift, 1.2 * 0.5 * row.height * UP ) for tally in self.tallies: - tally.anchor += 1.2 * 0.5 * self.row.height * UP + tally.anchor += 1.2 * 0.5 * row.height * UP def create_pi_creature(self): randy = CoinFlippingPiCreature(color = MAROON_E) @@ -256,12 +257,11 @@ class BrickRowScene(PiCreatureScene): # # # # # # # # - self.play(FlipCoin(randy)) self.play(SplitRectsInBrickWall(self.row)) - self.merge_rects_by_subdiv() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_subdiv(self.row) + self.row = self.merge_rects_by_coloring(self.row) # # put tallies on top @@ -312,7 +312,6 @@ class BrickRowScene(PiCreatureScene): 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)): @@ -347,6 +346,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() + self.tallies = VGroup() for (i, rect) in enumerate(self.row.get_rects_for_level(2)): tally = TallyStack(2-i, i, show_decimals = False) @@ -357,6 +357,7 @@ class BrickRowScene(PiCreatureScene): self.play(FadeIn(self.tallies)) self.wait() + anims = [] for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): anims.append(ApplyFunction( @@ -366,6 +367,7 @@ class BrickRowScene(PiCreatureScene): self.play(*anims) self.wait() + # replace the original decimal tallies with # the ones that belong to the TallyStacks for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): @@ -374,9 +376,9 @@ class BrickRowScene(PiCreatureScene): tally_stack.add(tally_stack.decimal_tally) self.add_foreground_mobject(self.tallies) - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() @@ -494,7 +496,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() - self.split_tallies_in_two_steps() + self.split_tallies_in_two_steps(self.row) self.wait() self.add_foreground_mobject(self.tallies) @@ -554,7 +556,7 @@ class BrickRowScene(PiCreatureScene): # self.wait() - # self.merge_rects_by_subdiv() + # self.row = self.merge_rects_by_subdiv(self.row) # self.wait() # self.play( @@ -575,9 +577,9 @@ class BrickRowScene(PiCreatureScene): # self.wait() - # self.merge_tallies(target_pos = DOWN) + # self.merge_tallies(self.row, target_pos = DOWN) # self.add_foreground_mobject(self.tallies) - # self.merge_rects_by_coloring() + # self.row = self.merge_rects_by_coloring(self.row) # self.wait() @@ -645,7 +647,7 @@ class BrickRowScene(PiCreatureScene): self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() self.play( @@ -666,9 +668,9 @@ class BrickRowScene(PiCreatureScene): self.wait() - self.merge_tallies(target_pos = DOWN) + self.merge_tallies(self.row, target_pos = DOWN) self.add_foreground_mobject(self.tallies) - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() @@ -759,7 +761,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() @@ -876,7 +878,7 @@ class BrickRowScene(PiCreatureScene): FadeOut(self.tallies), ) - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.play( FadeIn(new_tallies[0]), @@ -886,9 +888,9 @@ class BrickRowScene(PiCreatureScene): - # # # # # # # # - # FIFTH FLIP # - # # # # # # # # + # # # # # # # # # # + # EVEN MORE FLIPS # + # # # # # # # # # # self.play(FadeOut(new_tallies)) self.clear() @@ -909,9 +911,9 @@ class BrickRowScene(PiCreatureScene): SplitRectsInBrickWall(self.row) ) self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() self.play(FadeOut(previous_row)) From 84c025aac6179b0acfefcb6df934cef91baa53db Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 16:36:14 +0200 Subject: [PATCH 08/17] added animation steps for brick wall --- .../eop/chapter1/entire_brick_wall.py | 27 ++++++++++++++----- active_projects/eop/reusables/brick_row.py | 2 ++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/active_projects/eop/chapter1/entire_brick_wall.py b/active_projects/eop/chapter1/entire_brick_wall.py index 31d07ec1..f716d760 100644 --- a/active_projects/eop/chapter1/entire_brick_wall.py +++ b/active_projects/eop/chapter1/entire_brick_wall.py @@ -1,29 +1,30 @@ from big_ol_pile_of_manim_imports import * from active_projects.eop.reusable_imports import * +from active_projects.eop.chapter1.brick_row_scene import BrickRowScene - -class EntireBrickWall(Scene): +class EntireBrickWall(BrickRowScene): def construct(self): + self.remove(self.get_primary_pi_creature()) + row_height = 0.3 nb_rows = 20 start_point = 3 * UP + 1 * LEFT rows = VMobject() rows.add(BrickRow(0, height = row_height)) - rows[0].move_to(start_point) + rows.move_to(start_point) self.add(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) + for i in range(1, nb_rows + 1): + rows.add(rows[-1].copy()) self.bring_to_back(rows[-1]) anims = [ rows[-1].shift, row_height * DOWN, @@ -37,6 +38,12 @@ class EntireBrickWall(Scene): self.play(*anims) + self.play(SplitRectsInBrickWall(rows[-1])) + rows.submobjects[-1] = self.merge_rects_by_subdiv(rows[-1]) + rows.submobjects[-1] = self.merge_rects_by_coloring(rows[-1]) + + + # draw indices under the last row for the number of tails tails_counters = VGroup() for (i, rect) in enumerate(rows[-1].rects): @@ -62,6 +69,12 @@ class EntireBrickWall(Scene): FadeIn(nb_tails_text) ) + # remove any hidden brick rows + hidden_brick_rows = VGroup(*[mob for mob in self.mobjects + if isinstance(mob, BrickRow) and not mob in rows + ]) + self.remove(hidden_brick_rows) + special_brick_copy = rows[-1].rects[13].copy() self.play( rows.fade, 0.9, diff --git a/active_projects/eop/reusables/brick_row.py b/active_projects/eop/reusables/brick_row.py index 92ca15f7..875d8920 100644 --- a/active_projects/eop/reusables/brick_row.py +++ b/active_projects/eop/reusables/brick_row.py @@ -184,6 +184,7 @@ class SplitRectsInBrickWall(AnimationGroup): def __init__(self, mobject, **kwargs): + #print mobject.height, mobject.get_height() r = self.subdiv_level = mobject.subdiv_level + 1 subdivs = VGroup() @@ -196,6 +197,7 @@ class SplitRectsInBrickWall(AnimationGroup): subdiv = DashedLine( mobject.get_top() + x * RIGHT, mobject.get_bottom() + x * RIGHT, + dashed_segment_length = 0.02 ) subdivs.add(subdiv) anims.append(ShowCreation(subdiv)) From 1a6771f0cd6bed242f8b87299c400aab4733fad6 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 17:30:39 +0200 Subject: [PATCH 09/17] showing 20th row in detail --- .../eop/chapter1/entire_brick_wall.py | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/active_projects/eop/chapter1/entire_brick_wall.py b/active_projects/eop/chapter1/entire_brick_wall.py index 31d07ec1..83414d38 100644 --- a/active_projects/eop/chapter1/entire_brick_wall.py +++ b/active_projects/eop/chapter1/entire_brick_wall.py @@ -20,6 +20,7 @@ class EntireBrickWall(Scene): nb_flips_text = TextMobject("\# of flips") nb_flips_text.next_to(zero_counter, RIGHT, buff = LARGE_BUFF) self.add(zero_counter, nb_flips_text) + flip_counters = VGroup(zero_counter) for i in range(1,nb_rows + 1): rows.add(BrickRow(i, height = row_height)) @@ -33,6 +34,7 @@ class EntireBrickWall(Scene): if i % 5 == 0: counter = Integer(i) counter.next_to(rows[-1].get_right() + row_height * DOWN, RIGHT) + flip_counters.add(counter) anims.append(FadeIn(counter)) self.play(*anims) @@ -62,10 +64,67 @@ class EntireBrickWall(Scene): FadeIn(nb_tails_text) ) - special_brick_copy = rows[-1].rects[13].copy() + mobs_to_shift = VGroup( + rows, flip_counters, tails_counters, nb_tails_text, + ) + self.play(mobs_to_shift.shift, 3 * UP) + + last_row_rect = SurroundingRectangle(rows[-1], buff = 0) + last_row_rect.set_stroke(color = YELLOW, width = 6) self.play( rows.fade, 0.9, - FadeIn(special_brick_copy) + ShowCreation(last_row_rect) + ) + + def highlighted_brick(row = 20, nb_tails = 10): + brick_copy = rows[row].rects[nb_tails].copy() + brick_copy.set_fill(color = YELLOW, opacity = 0.8) + prob_percentage = float(choose(row, nb_tails)) / 2**row * 100 + brick_label = DecimalNumber(prob_percentage, unit = "\%", num_decimal_places = 1, color = BLACK) + brick_label.move_to(brick_copy) + brick_label.scale_to_fit_height(0.8 * brick_copy.get_height()) + return VGroup(brick_copy, brick_label) + + highlighted_bricks = [ + highlighted_brick(row = 20, nb_tails = i) + for i in range(20) + ] + + self.play( + FadeIn(highlighted_bricks[10]) + ) + + self.play( + FadeOut(highlighted_bricks[10]), + FadeIn(highlighted_bricks[9]), + FadeIn(highlighted_bricks[11]), + ) + + self.play( + FadeOut(highlighted_bricks[9]), + FadeOut(highlighted_bricks[11]), + FadeIn(highlighted_bricks[8]), + FadeIn(highlighted_bricks[12]), ) + + + + + + + + + + + + + + + + + + + + From fd002c13e6c310b0f2e90f6265825131750a7d37 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 18:21:25 +0200 Subject: [PATCH 10/17] renamed num_decimal_points -> num_decimal_places --- .../eop/chapter1/area_model_erf.py | 6 +++--- .../morph_brick_row_into_histogram.py | 4 ++-- active_projects/eop/chapter1/quiz_result.py | 2 +- animation/numbers.py | 4 ++-- mobject/matrix.py | 2 +- mobject/numbers.py | 6 +++--- old_projects/WindingNumber.py | 10 +++++----- old_projects/WindingNumber_G.py | 6 +++--- old_projects/basel/basel.py | 10 +++++----- old_projects/basel/basel2.py | 16 +++++++-------- old_projects/fourier.py | 4 ++-- old_projects/fractal_dimension.py | 2 +- old_projects/nn/part1.py | 4 ++-- old_projects/nn/part2.py | 6 +++--- old_projects/nn/part3.py | 10 +++++----- old_projects/pi_day.py | 4 ++-- old_projects/wallis.py | 20 +++++++++---------- 17 files changed, 58 insertions(+), 58 deletions(-) diff --git a/active_projects/eop/chapter1/area_model_erf.py b/active_projects/eop/chapter1/area_model_erf.py index cb978360..36fd0cce 100644 --- a/active_projects/eop/chapter1/area_model_erf.py +++ b/active_projects/eop/chapter1/area_model_erf.py @@ -84,7 +84,7 @@ class IllustrateAreaModelErf(GraphScene): equals_sign = TexMobject("=").next_to(cdf_formula, buff = MED_LARGE_BUFF) - cdf_value = DecimalNumber(0, color = graph.color, num_decimal_points = 3) + cdf_value = DecimalNumber(0, color = graph.color, num_decimal_places = 3) cdf_value.next_to(equals_sign) self.play( FadeIn(equals_sign), @@ -99,13 +99,13 @@ class IllustrateAreaModelErf(GraphScene): self.add(ContinualChangingDecimal( decimal_number_mobject = cdf_value, number_update_func = integral_update_func, - num_decimal_points = 3 + num_decimal_places = 3 )) self.add(ContinualChangingDecimal( decimal_number_mobject = cdf_percentage, number_update_func = integral_update_func_percent, - num_decimal_points = 1 + num_decimal_places = 1 )) diff --git a/active_projects/eop/chapter1/morph_brick_row_into_histogram.py b/active_projects/eop/chapter1/morph_brick_row_into_histogram.py index 213093b2..be3f744e 100644 --- a/active_projects/eop/chapter1/morph_brick_row_into_histogram.py +++ b/active_projects/eop/chapter1/morph_brick_row_into_histogram.py @@ -132,7 +132,7 @@ class MorphBrickRowIntoHistogram3(GenericMorphBrickRowIntoHistogram): area_color = YELLOW total_area_text = TextMobject("total area =", color = area_color) - area_decimal = DecimalNumber(0, color = area_color, num_decimal_points = 3) + area_decimal = DecimalNumber(0, color = area_color, num_decimal_places = 3) area_decimal.next_to(total_area_text, RIGHT) total_area_group = VGroup(total_area_text, area_decimal) @@ -213,7 +213,7 @@ class MorphBrickRowIntoHistogram20(GenericMorphBrickRowIntoHistogram): 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 = DecimalNumber(i, num_decimal_places = 2, color = GRAY) y_guide_label.scale(0.7) y_guide_label.next_to(y_guide, LEFT) y_guide.add(y_guide_label) diff --git a/active_projects/eop/chapter1/quiz_result.py b/active_projects/eop/chapter1/quiz_result.py index 4d7a0f38..3488efea 100644 --- a/active_projects/eop/chapter1/quiz_result.py +++ b/active_projects/eop/chapter1/quiz_result.py @@ -159,7 +159,7 @@ class QuizResult(PiCreatureScene): anims = [] for (label, percentage) in zip(grade_hist.y_labels_group, percentages): new_label = DecimalNumber(percentage, - num_decimal_points = 1, + num_decimal_places = 1, unit = "\%", color = highlight_color ) diff --git a/animation/numbers.py b/animation/numbers.py index f7b8d250..428203f3 100644 --- a/animation/numbers.py +++ b/animation/numbers.py @@ -10,7 +10,7 @@ from utils.config_ops import digest_config class ChangingDecimal(Animation): CONFIG = { - "num_decimal_points": None, + "num_decimal_places": None, "show_ellipsis": None, "position_update_func": None, "tracked_mobject": None, @@ -21,7 +21,7 @@ class ChangingDecimal(Animation): self.decimal_number_config = dict( decimal_number_mobject.initial_config ) - for attr in "num_decimal_points", "show_ellipsis": + for attr in "num_decimal_places", "show_ellipsis": value = getattr(self, attr) if value is not None: self.decimal_number_config[attr] = value diff --git a/mobject/matrix.py b/mobject/matrix.py index 727f8f4d..cb8e1af2 100644 --- a/mobject/matrix.py +++ b/mobject/matrix.py @@ -139,7 +139,7 @@ class Matrix(VMobject): class DecimalMatrix(Matrix): CONFIG = { "element_to_mobject": DecimalNumber, - "element_to_mobject_config": {"num_decimal_points": 1} + "element_to_mobject_config": {"num_decimal_places": 1} } diff --git a/mobject/numbers.py b/mobject/numbers.py index 5a6ff682..e4986813 100644 --- a/mobject/numbers.py +++ b/mobject/numbers.py @@ -8,7 +8,7 @@ from mobject.types.vectorized_mobject import VMobject class DecimalNumber(VMobject): CONFIG = { - "num_decimal_points": 2, + "num_decimal_places": 2, "digit_to_digit_buff": 0.05, "show_ellipsis": False, "unit": None, # Aligned to bottom unless it starts with "^" @@ -18,7 +18,7 @@ class DecimalNumber(VMobject): def __init__(self, number, **kwargs): VMobject.__init__(self, **kwargs) self.number = number - ndp = self.num_decimal_points + ndp = self.num_decimal_places # Build number string if isinstance(number, complex): @@ -71,5 +71,5 @@ class DecimalNumber(VMobject): class Integer(DecimalNumber): CONFIG = { - "num_decimal_points": 0, + "num_decimal_places": 0, } diff --git a/old_projects/WindingNumber.py b/old_projects/WindingNumber.py index c2d20fef..c12c5cbd 100644 --- a/old_projects/WindingNumber.py +++ b/old_projects/WindingNumber.py @@ -565,7 +565,7 @@ def walker_animation_with_display( number_update_func = None, show_arrows = True, scale_arrows = False, - num_decimal_points = 1, + num_decimal_places = 1, include_background_rectangle = True, **kwargs ): @@ -581,7 +581,7 @@ def walker_animation_with_display( if number_update_func != None: display = DecimalNumber(0, - num_decimal_points = num_decimal_points, + num_decimal_places = num_decimal_places, fill_color = WHITE if include_background_rectangle else BLACK, include_background_rectangle = include_background_rectangle) if include_background_rectangle: @@ -732,7 +732,7 @@ class PiWalker(ColorMappedByFuncScene): "show_num_plane" : False, "draw_lines" : True, "num_checkpoints" : 10, - "num_decimal_points" : 1, + "num_decimal_places" : 1, "include_background_rectangle" : False, } @@ -788,7 +788,7 @@ class PiWalker(ColorMappedByFuncScene): number_update_func = number_update_func, run_time = self.step_run_time, walker_stroke_color = WALKER_LIGHT_COLOR if self.color_foreground_not_background else BLACK, - num_decimal_points = self.num_decimal_points, + num_decimal_places = self.num_decimal_places, include_background_rectangle = self.include_background_rectangle, ) @@ -2751,7 +2751,7 @@ class OneFifthTwoFifthWinder(SpecifiedWinder): "step_size" : 0.01, "show_num_plane" : False, "step_run_time" : 6, - "num_decimal_points" : 2, + "num_decimal_places" : 2, } class OneFifthOneFifthWinderWithReset(OneFifthTwoFifthWinder): diff --git a/old_projects/WindingNumber_G.py b/old_projects/WindingNumber_G.py index 501fc289..4b65bb31 100644 --- a/old_projects/WindingNumber_G.py +++ b/old_projects/WindingNumber_G.py @@ -386,7 +386,7 @@ class Introduce1DFunctionCase(Scene): ) decimal = DecimalNumber( 0, - num_decimal_points = 3, + num_decimal_places = 3, show_ellipsis = True, ) decimal.scale(0.7) @@ -484,7 +484,7 @@ class Introduce1DFunctionCase(Scene): if show_decimal: decimal = DecimalNumber( axes.x_axis.point_to_number(arrow.get_start()), - num_decimal_points = 3, + num_decimal_places = 3, # show_ellipsis = True, ) height = self.rect.get_height() @@ -2310,7 +2310,7 @@ class TransitionFromPathsToBoundaries(ColorMappedObjectsScene): ) ) - label = DecimalNumber(0, num_decimal_points = 1) + label = DecimalNumber(0, num_decimal_places = 1) label_upadte = ContinualChangingDecimal( label, get_total_winding, position_update_func = lambda l : l.next_to(dot, UP+LEFT, SMALL_BUFF) diff --git a/old_projects/basel/basel.py b/old_projects/basel/basel.py index 259c537c..69809107 100644 --- a/old_projects/basel/basel.py +++ b/old_projects/basel/basel.py @@ -119,7 +119,7 @@ class LightIndicator(VMobject): self.foreground.set_stroke(color=INDICATOR_STROKE_COLOR,width=INDICATOR_STROKE_WIDTH) self.add(self.background, self.foreground) - self.reading = DecimalNumber(self.intensity,num_decimal_points = self.precision) + self.reading = DecimalNumber(self.intensity,num_decimal_places = self.precision) self.reading.set_fill(color=INDICATOR_TEXT_COLOR) self.reading.move_to(self.get_center()) if self.show_reading: @@ -287,7 +287,7 @@ class IntroScene(PiCreatureScene): equals_sign = self.euler_sum.get_part_by_tex("=") self.partial_sum_decimal = DecimalNumber(partial_results_values[1], - num_decimal_points = 2) + num_decimal_places = 2) self.partial_sum_decimal.next_to(equals_sign, RIGHT) @@ -313,7 +313,7 @@ class IntroScene(PiCreatureScene): self.partial_sum_decimal, partial_results_values[i+1], run_time = self.duration, - num_decimal_points = 6, + num_decimal_places = 6, show_ellipsis = True, position_update_func = lambda m: m.next_to(equals_sign, RIGHT) ) @@ -863,7 +863,7 @@ class SingleLighthouseScene(PiCreatureScene): # angle msmt (decimal number) self.angle_indicator = DecimalNumber(arc_angle / DEGREES, - num_decimal_points = 0, + num_decimal_places = 0, unit = "^\\circ", fill_opacity = 1.0, fill_color = WHITE) @@ -4262,7 +4262,7 @@ class LabeledArc(Arc): Arc.__init__(self,angle,**kwargs) - label = DecimalNumber(self.length, num_decimal_points = 0) + label = DecimalNumber(self.length, num_decimal_places = 0) r = BUFFER * self.radius theta = self.start_angle + self.angle/2 label_pos = r * np.array([np.cos(theta), np.sin(theta), 0]) diff --git a/old_projects/basel/basel2.py b/old_projects/basel/basel2.py index 1638a26f..bdd41ccc 100644 --- a/old_projects/basel/basel2.py +++ b/old_projects/basel/basel2.py @@ -94,7 +94,7 @@ class LightIndicator(Mobject): self.foreground.set_fill(color = self.fill_color) self.add(self.background, self.foreground) - self.reading = DecimalNumber(self.intensity,num_decimal_points = self.precision) + self.reading = DecimalNumber(self.intensity,num_decimal_places = self.precision) self.reading.set_fill(color=INDICATOR_TEXT_COLOR) self.reading.scale_to_fit_height(self.reading_height) self.reading.move_to(self.get_center()) @@ -317,7 +317,7 @@ class IntroScene(PiCreatureScene): partial_sum_decimal = self.partial_sum_decimal = DecimalNumber( series_terms[1], - num_decimal_points = 2 + num_decimal_places = 2 ) partial_sum_decimal.next_to(equals_sign, RIGHT) @@ -418,7 +418,7 @@ class IntroScene(PiCreatureScene): partial_sum_decimal, series_terms[i+1], run_time = 1, - num_decimal_points = 6, + num_decimal_places = 6, position_update_func = lambda m: m.next_to(equals_sign, RIGHT) ) ] @@ -430,7 +430,7 @@ class IntroScene(PiCreatureScene): ChangeDecimalToValue( partial_sum_decimal, series_terms[i+1], - num_decimal_points = 6, + num_decimal_places = 6, ), ] if i == 5: @@ -451,7 +451,7 @@ class IntroScene(PiCreatureScene): ChangeDecimalToValue( partial_sum_decimal, series_terms[-1], - num_decimal_points = 6, + num_decimal_places = 6, ), morty.change, "confused", ) @@ -1295,7 +1295,7 @@ class IntroduceScreen(Scene): self.angle_indicator = DecimalNumber( arc_angle / DEGREES, - num_decimal_points = 0, + num_decimal_places = 0, unit = "^\\circ" ) self.angle_indicator.next_to(self.angle_arc, RIGHT) @@ -3818,7 +3818,7 @@ class ThinkBackToHowAmazingThisIs(ThreeDScene): dot_pairs = it.starmap(VGroup, zip(positive_dots, negative_dots)) # Decimal - decimal = DecimalNumber(0, num_decimal_points = 6) + decimal = DecimalNumber(0, num_decimal_places = 6) decimal.to_edge(UP) terms = [2./(n**2) for n in range(1, 100, 2)] partial_sums = np.cumsum(terms) @@ -4250,7 +4250,7 @@ class LabeledArc(Arc): Arc.__init__(self,angle,**kwargs) - label = DecimalNumber(self.length, num_decimal_points = 0) + label = DecimalNumber(self.length, num_decimal_places = 0) r = BUFFER * self.radius theta = self.start_angle + self.angle/2 label_pos = r * np.array([np.cos(theta), np.sin(theta), 0]) diff --git a/old_projects/fourier.py b/old_projects/fourier.py index 830f8c78..33d624e5 100644 --- a/old_projects/fourier.py +++ b/old_projects/fourier.py @@ -728,7 +728,7 @@ class UnmixMixedPaint(Scene): class MachineThatTreatsOneFrequencyDifferently(Scene): def construct(self): graph = self.get_cosine_graph(0.5) - frequency_mob = DecimalNumber(220, num_decimal_points = 0) + frequency_mob = DecimalNumber(220, num_decimal_places = 0) frequency_mob.next_to(graph, UP, buff = MED_LARGE_BUFF) self.graph = graph @@ -1273,7 +1273,7 @@ class WrapCosineGraphAroundCircle(FourierMachineScene): def get_winding_frequency_label(self): freq = self.initial_winding_frequency winding_freq_label = VGroup( - DecimalNumber(freq, num_decimal_points = 2), + DecimalNumber(freq, num_decimal_places = 2), TextMobject("cycles/second") ) winding_freq_label.arrange_submobjects(RIGHT) diff --git a/old_projects/fractal_dimension.py b/old_projects/fractal_dimension.py index 27a05397..683f3154 100644 --- a/old_projects/fractal_dimension.py +++ b/old_projects/fractal_dimension.py @@ -1805,7 +1805,7 @@ class BoxCountingScene(Scene): return label def count_boxes(self, boxes): - num = DecimalNumber(len(boxes), num_decimal_points = 0) + num = DecimalNumber(len(boxes), num_decimal_places = 0) num.next_to(boxes, RIGHT) num.add_to_back(BackgroundRectangle(num)) diff --git a/old_projects/nn/part1.py b/old_projects/nn/part1.py index b2d872fc..cdd3618d 100644 --- a/old_projects/nn/part1.py +++ b/old_projects/nn/part1.py @@ -559,7 +559,7 @@ class WriteAProgram(Scene): rgb = square.fill_rgb num = DecimalNumber( square.fill_rgb[0], - num_decimal_points = 1 + num_decimal_places = 1 ) num.set_stroke(width = 1) color = rgba_to_color(1 - (rgb + 0.2)/1.2) @@ -1113,7 +1113,7 @@ class IntroduceEachLayer(PreviewMNistNetwork): example_num = None for neuron in neurons: o = neuron.get_fill_opacity() - num = DecimalNumber(o, num_decimal_points = 1) + num = DecimalNumber(o, num_decimal_places = 1) num.scale_to_fit_width(0.7*neuron.get_width()) num.move_to(neuron) if o > 0.8: diff --git a/old_projects/nn/part2.py b/old_projects/nn/part2.py index 114ddff9..f32e805b 100644 --- a/old_projects/nn/part2.py +++ b/old_projects/nn/part2.py @@ -962,14 +962,14 @@ class IntroduceCostFunction(PreviewLearning): terms = VGroup() term_updates = [] for arrow, d1, d2 in zip(arrows, *self.decimal_groups): - term = DecimalNumber(0, num_decimal_points = 4) + term = DecimalNumber(0, num_decimal_places = 4) term.scale_to_fit_height(d1.get_height()) term.next_to(arrow, LEFT) term.num_update_func = generate_term_update_func(d1, d2) terms.add(term) term_updates.append(ChangingDecimalWithColor( term, term.num_update_func, - num_decimal_points = 4 + num_decimal_places = 4 )) brace.target.next_to(terms, LEFT) @@ -2780,7 +2780,7 @@ class TestPerformance(PreviewLearning): "wrong_wait_time" : 0.5, "stroke_width_exp" : 2, "decimal_kwargs" : { - "num_decimal_points" : 3, + "num_decimal_places" : 3, } } def construct(self): diff --git a/old_projects/nn/part3.py b/old_projects/nn/part3.py index 5b14b69b..ade62581 100644 --- a/old_projects/nn/part3.py +++ b/old_projects/nn/part3.py @@ -671,7 +671,7 @@ class WalkThroughTwoExample(ShowAveragingCost): decimals = VGroup() for neuron in neurons: activation = neuron.get_fill_opacity() - decimal = DecimalNumber(activation, num_decimal_points = 1) + decimal = DecimalNumber(activation, num_decimal_places = 1) decimal.scale_to_fit_width(0.7*neuron.get_width()) decimal.move_to(neuron) if activation > 0.8: @@ -748,7 +748,7 @@ class WalkThroughTwoExample(ShowAveragingCost): anims.append(ChangingDecimal( decimal, get_decimal_update(decimal.number, target), - num_decimal_points = 1 + num_decimal_places = 1 )) anims.append(UpdateFromFunc( self.decimals[i], @@ -1076,7 +1076,7 @@ class WalkThroughTwoExample(ShowAveragingCost): ChangingDecimal( two_decimal, lambda a : interpolate(two_activation, 1, a), - num_decimal_points = 1, + num_decimal_places = 1, ), UpdateFromFunc( two_decimal, @@ -1110,7 +1110,7 @@ class WalkThroughTwoExample(ShowAveragingCost): ChangingDecimal( two_decimal, lambda a : interpolate(1, two_activation, a), - num_decimal_points = 1, + num_decimal_places = 1, ), UpdateFromFunc( two_decimal, @@ -3613,7 +3613,7 @@ class SimplestNetworkExample(PreviewLearning): def get_neuron_activation_decimal(self, neuron): opacity = neuron.get_fill_opacity() - decimal = DecimalNumber(opacity, num_decimal_points = 2) + decimal = DecimalNumber(opacity, num_decimal_places = 2) decimal.scale_to_fit_width(0.85*neuron.get_width()) if decimal.number > 0.8: decimal.set_fill(BLACK) diff --git a/old_projects/pi_day.py b/old_projects/pi_day.py index ce4c2e36..bea9b697 100644 --- a/old_projects/pi_day.py +++ b/old_projects/pi_day.py @@ -226,7 +226,7 @@ def get_circle_drawing_terms(radius = 1, positioning_func = lambda m : m.center( 0.25*rotate_vector(radius.get_vector(), TAU/4) ), ) - decimal = DecimalNumber(0, num_decimal_points = 4, show_ellipsis = True) + decimal = DecimalNumber(0, num_decimal_places = 4, show_ellipsis = True) decimal.scale(0.75) def reposition_decimal(decimal): vect = radius.get_vector() @@ -318,7 +318,7 @@ class PiTauDebate(PiCreatureScene): circum_line.next_to(circle, DOWN, buff = MED_LARGE_BUFF) # circum_line.to_edge(LEFT) brace = Brace(circum_line, DOWN, buff = SMALL_BUFF) - decimal = DecimalNumber(np.pi, num_decimal_points = 4, show_ellipsis = True) + decimal = DecimalNumber(np.pi, num_decimal_places = 4, show_ellipsis = True) decimal.scale(0.75) decimal.next_to(brace, DOWN, SMALL_BUFF) diff --git a/old_projects/wallis.py b/old_projects/wallis.py index b2ffb1ed..707d7d94 100644 --- a/old_projects/wallis.py +++ b/old_projects/wallis.py @@ -112,7 +112,7 @@ class Introduction(Scene): ) get_arrow_update().update(1) decimal = DecimalNumber( - curr_product, num_decimal_points=5, show_ellipsis=True) + curr_product, num_decimal_places=5, show_ellipsis=True) decimal.next_to(arrow, UP, SMALL_BUFF, submobject_to_align=decimal[:5]) decimal_anim = ChangingDecimal( decimal, @@ -512,7 +512,7 @@ class ShowProduct(Scene): ]) brace = braces[0].copy() - decimal = DecimalNumber(partial_products[0], num_decimal_points=4) + decimal = DecimalNumber(partial_products[0], num_decimal_places=4) decimal.next_to(brace, DOWN) self.add(brace, decimal, dots[0], parts[0]) @@ -677,7 +677,7 @@ class ShowProduct(Scene): ]) brace = braces[0].copy() - decimal = DecimalNumber(partial_products_iter.next(), num_decimal_points=4) + decimal = DecimalNumber(partial_products_iter.next(), num_decimal_places=4) decimal.next_to(brace, DOWN) self.play(*map(FadeIn, [brace, decimal, dots[0]])) @@ -894,7 +894,7 @@ class DistanceProductScene(MovingCameraScene): self.d_labels.add(d_label) return self.d_labels - def get_numeric_distance_labels(self, lines=None, num_decimal_points=3, show_ellipsis=True): + def get_numeric_distance_labels(self, lines=None, num_decimal_places=3, show_ellipsis=True): radius = self.circle.get_width() / 2 if lines is None: if not hasattr(self, "distance_lines"): @@ -904,7 +904,7 @@ class DistanceProductScene(MovingCameraScene): for line in lines: label = DecimalNumber( line.get_length() / radius, - num_decimal_points=num_decimal_points, + num_decimal_places=num_decimal_places, show_ellipsis=show_ellipsis, include_background_rectangle=self.include_distance_labels_background_rectangle, ) @@ -943,7 +943,7 @@ class DistanceProductScene(MovingCameraScene): product_decimal = DecimalNumber( self.get_distance_product(fraction), - num_decimal_points=3, + num_decimal_places=3, show_ellipsis=True, include_background_rectangle=self.include_distance_labels_background_rectangle, ) @@ -1632,7 +1632,7 @@ class FromGeometryToAlgebra(DistanceProductScene): values = map(plane.point_to_number, self.get_lh_points()) complex_decimal = self.complex_decimal = DecimalNumber( values[3], - num_decimal_points=3, + num_decimal_places=3, include_background_rectangle=True ) complex_decimal.next_to(outer_arrow.get_start(), LEFT, SMALL_BUFF) @@ -2190,7 +2190,7 @@ class PlugObserverIntoPolynomial(DistanceProductScene): numeric_chord_label = DecimalNumber( np.sqrt(3), - num_decimal_points=4, + num_decimal_places=4, include_background_rectangle=True, show_ellipsis=True, ) @@ -2907,7 +2907,7 @@ class ProveLemma2(PlugObserverIntoPolynomial): product = DecimalNumber( self.num_lighthouses, - num_decimal_points=3, + num_decimal_places=3, show_ellipsis=True ) product.move_to(self.q_marks, LEFT) @@ -3235,7 +3235,7 @@ class KeeperAndSailor(DistanceProductScene, PiCreatureScene): new_keeper_dp_decimal = DecimalNumber( self.num_lighthouses, - num_decimal_points=3, + num_decimal_places=3, ) new_keeper_dp_decimal.replace(keeper_dp_decimal, dim_to_match=1) new_keeper_dp_decimal.set_color(YELLOW) From 7ce5674126e48b72e44e6f38be507b09428eceb1 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 18:22:30 +0200 Subject: [PATCH 11/17] fixed bug for reduce_across_dimension for mobs with empty submobs --- mobject/mobject.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mobject/mobject.py b/mobject/mobject.py index c069caf1..56c87c51 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -467,6 +467,8 @@ class Mobject(Container): # Background rectangle def add_background_rectangle(self, color=BLACK, opacity=0.75, **kwargs): + # TODO, this does not behave well when the mobject has points, + # since it gets displayed on top from mobject.shape_matchers import BackgroundRectangle self.background_rectangle = BackgroundRectangle( self, color=color, @@ -621,13 +623,17 @@ class Mobject(Container): values = [] values += [ mob.reduce_across_dimension(points_func, reduce_func, dim) - for mob in self.submobjects + for mob in self.nonempty_submobjects() ] try: return reduce_func(values) except: return 0 + def nonempty_submobjects(self): + return [submob for submob in self.submobjects + if len(submob.submobjects) != 0 or len(submob.points) != 0] + def get_merged_array(self, array_attr): result = None for mob in self.family_members_with_points(): From d4f3d3c584b09623c16acf786f2901af3b435d2c Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 18:23:01 +0200 Subject: [PATCH 12/17] make extract_scene play nicer with Sublime build system --- extract_scene.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/extract_scene.py b/extract_scene.py index ae52be31..d609b7ce 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -151,11 +151,12 @@ def handle_scene(scene, **config): if config["show_file_in_finder"]: commands.append("-R") - # + if config["show_last_frame"]: commands.append(scene.get_image_file_path()) else: commands.append(scene.get_movie_file_path()) + #commands.append("-g") FNULL = open(os.devnull, 'w') sp.call(commands, stdout=FNULL, stderr=sp.STDOUT) FNULL.close() @@ -223,14 +224,18 @@ def get_module_posix(file_name): module_name = file_name.replace(".py", "") last_module = imp.load_module(".", *imp.find_module(".")) for part in module_name.split(os.sep): - load_args = imp.find_module(part, last_module.__path__) - last_module = imp.load_module(part, *load_args) + try: + load_args = imp.find_module(part, last_module.__path__) + last_module = imp.load_module(part, *load_args) + except ImportError: + continue return last_module def get_module(file_name): if os.name == 'nt': return get_module_windows(file_name) + print "file_name =", file_name return get_module_posix(file_name) From 903e561a87111dc75ec066befc942fa649054b0b Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 18:23:55 +0200 Subject: [PATCH 13/17] made BrickRowScene reusable for EntireBrickWall --- .../eop/chapter1/brick_row_scene.py | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/active_projects/eop/chapter1/brick_row_scene.py b/active_projects/eop/chapter1/brick_row_scene.py index 49365c6e..b11a66ca 100644 --- a/active_projects/eop/chapter1/brick_row_scene.py +++ b/active_projects/eop/chapter1/brick_row_scene.py @@ -5,7 +5,7 @@ from active_projects.eop.reusable_imports import * class BrickRowScene(PiCreatureScene): - def split_tallies(self, direction = DOWN): + def split_tallies(self, row, 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 @@ -15,12 +15,12 @@ class BrickRowScene(PiCreatureScene): tally_targets_left = [ rect.get_center() + 0.25 * rect.get_width() * LEFT - for rect in self.row.rects + for rect in row.rects ] tally_targets_right = [ rect.get_center() + 0.25 * rect.get_width() * RIGHT - for rect in self.row.rects + for rect in row.rects ] if np.all(direction == LEFT) or np.all(direction == RIGHT): @@ -63,7 +63,7 @@ class BrickRowScene(PiCreatureScene): - def tally_split_animations(self, direction = DOWN): + def tally_split_animations(self, row, 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 @@ -73,12 +73,12 @@ class BrickRowScene(PiCreatureScene): tally_targets_left = [ rect.get_center() + 0.25 * rect.get_width() * LEFT - for rect in self.row.rects + for rect in row.rects ] tally_targets_right = [ rect.get_center() + 0.25 * rect.get_width() * RIGHT - for rect in self.row.rects + for rect in row.rects ] if np.all(direction == LEFT) or np.all(direction == RIGHT): @@ -122,13 +122,14 @@ class BrickRowScene(PiCreatureScene): return anims1, anims2 - def split_tallies_at_once(self, direction = DOWN): - anims1, anims2 = self.tally_split_animations(direction = direction) + + def split_tallies_at_once(self, row, direction = DOWN): + anims1, anims2 = self.tally_split_animations(row, direction = direction) self.play(*(anims1 + anims2)) - def split_tallies_in_two_steps(self, direction = DOWN): + def split_tallies_in_two_steps(self, row, direction = DOWN): # First all those to the left, then those to the right - anims1, anims2 = self.tally_split_animations(direction = direction) + anims1, anims2 = self.tally_split_animations(row, direction = direction) self.play(*anims1) self.wait(0.3) self.play(*anims2) @@ -136,31 +137,31 @@ class BrickRowScene(PiCreatureScene): - def merge_rects_by_subdiv(self): + def merge_rects_by_subdiv(self, row): - half_merged_row = self.row.copy() + half_merged_row = row.copy() half_merged_row.subdiv_level += 1 half_merged_row.generate_points() - half_merged_row.move_to(self.row) + half_merged_row.move_to(row) self.play(FadeIn(half_merged_row)) - self.remove(self.row) - self.row = half_merged_row + self.remove(row) + return half_merged_row - def merge_tallies(self, target_pos = UP): + def merge_tallies(self, row, target_pos = UP): - r = self.row.subdiv_level + r = row.subdiv_level if np.all(target_pos == DOWN): tally_targets = [ rect.get_center() - for rect in self.row.get_rects_for_level(r) + for rect in row.get_rects_for_level(r) ] elif np.all(target_pos == UP): - y_pos = self.row.get_center()[1] + 1.2 * 0.5 * self.row.get_height() + y_pos = row.get_center()[1] + 1.2 * 0.5 * row.get_height() for target in tally_targets: target[1] = y_pos else: @@ -186,25 +187,25 @@ class BrickRowScene(PiCreatureScene): self.tallies.add(self.tallies_copy[-1]) - def merge_rects_by_coloring(self): + def merge_rects_by_coloring(self, row): - merged_row = self.row.copy() + merged_row = row.copy() merged_row.coloring_level += 1 merged_row.generate_points() - merged_row.move_to(self.row) + merged_row.move_to(row) self.play(FadeIn(merged_row)) - self.remove(self.row) - self.row = merged_row + self.remove(row) + return merged_row - def move_tallies_on_top(self): + def move_tallies_on_top(self, row): self.play( - self.tallies.shift, 1.2 * 0.5 * self.row.height * UP + self.tallies.shift, 1.2 * 0.5 * row.height * UP ) for tally in self.tallies: - tally.anchor += 1.2 * 0.5 * self.row.height * UP + tally.anchor += 1.2 * 0.5 * row.height * UP def create_pi_creature(self): randy = CoinFlippingPiCreature(color = MAROON_E) @@ -256,12 +257,11 @@ class BrickRowScene(PiCreatureScene): # # # # # # # # - self.play(FlipCoin(randy)) self.play(SplitRectsInBrickWall(self.row)) - self.merge_rects_by_subdiv() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_subdiv(self.row) + self.row = self.merge_rects_by_coloring(self.row) # # put tallies on top @@ -312,7 +312,6 @@ class BrickRowScene(PiCreatureScene): 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)): @@ -347,6 +346,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() + self.tallies = VGroup() for (i, rect) in enumerate(self.row.get_rects_for_level(2)): tally = TallyStack(2-i, i, show_decimals = False) @@ -357,6 +357,7 @@ class BrickRowScene(PiCreatureScene): self.play(FadeIn(self.tallies)) self.wait() + anims = [] for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): anims.append(ApplyFunction( @@ -366,6 +367,7 @@ class BrickRowScene(PiCreatureScene): self.play(*anims) self.wait() + # replace the original decimal tallies with # the ones that belong to the TallyStacks for (decimal_tally, tally_stack) in zip(decimal_tallies, self.tallies): @@ -374,9 +376,9 @@ class BrickRowScene(PiCreatureScene): tally_stack.add(tally_stack.decimal_tally) self.add_foreground_mobject(self.tallies) - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() @@ -494,7 +496,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() - self.split_tallies_in_two_steps() + self.split_tallies_in_two_steps(self.row) self.wait() self.add_foreground_mobject(self.tallies) @@ -554,7 +556,7 @@ class BrickRowScene(PiCreatureScene): # self.wait() - # self.merge_rects_by_subdiv() + # self.row = self.merge_rects_by_subdiv(self.row) # self.wait() # self.play( @@ -575,9 +577,9 @@ class BrickRowScene(PiCreatureScene): # self.wait() - # self.merge_tallies(target_pos = DOWN) + # self.merge_tallies(self.row, target_pos = DOWN) # self.add_foreground_mobject(self.tallies) - # self.merge_rects_by_coloring() + # self.row = self.merge_rects_by_coloring(self.row) # self.wait() @@ -645,7 +647,7 @@ class BrickRowScene(PiCreatureScene): self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() self.play( @@ -666,9 +668,9 @@ class BrickRowScene(PiCreatureScene): self.wait() - self.merge_tallies(target_pos = DOWN) + self.merge_tallies(self.row, target_pos = DOWN) self.add_foreground_mobject(self.tallies) - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() @@ -759,7 +761,7 @@ class BrickRowScene(PiCreatureScene): ) self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() @@ -876,7 +878,7 @@ class BrickRowScene(PiCreatureScene): FadeOut(self.tallies), ) - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.play( FadeIn(new_tallies[0]), @@ -886,9 +888,9 @@ class BrickRowScene(PiCreatureScene): - # # # # # # # # - # FIFTH FLIP # - # # # # # # # # + # # # # # # # # # # + # EVEN MORE FLIPS # + # # # # # # # # # # self.play(FadeOut(new_tallies)) self.clear() @@ -909,9 +911,9 @@ class BrickRowScene(PiCreatureScene): SplitRectsInBrickWall(self.row) ) self.wait() - self.merge_rects_by_subdiv() + self.row = self.merge_rects_by_subdiv(self.row) self.wait() - self.merge_rects_by_coloring() + self.row = self.merge_rects_by_coloring(self.row) self.wait() self.play(FadeOut(previous_row)) From 293771ab1afc59355f0955a7aab886e83d99d2c2 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 18:24:39 +0200 Subject: [PATCH 14/17] working on EntireBrickWall --- active_projects/eop/chapter1/entire_brick_wall.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/active_projects/eop/chapter1/entire_brick_wall.py b/active_projects/eop/chapter1/entire_brick_wall.py index 5302bcc7..90c52e29 100644 --- a/active_projects/eop/chapter1/entire_brick_wall.py +++ b/active_projects/eop/chapter1/entire_brick_wall.py @@ -72,10 +72,8 @@ class EntireBrickWall(BrickRowScene): ) # remove any hidden brick rows - hidden_brick_rows = VGroup(*[mob for mob in self.mobjects - if isinstance(mob, BrickRow) and not mob in rows - ]) - self.remove(hidden_brick_rows) + self.clear() + self.add(nb_flips_text) mobs_to_shift = VGroup( rows, flip_counters, tails_counters, nb_tails_text, @@ -94,7 +92,8 @@ class EntireBrickWall(BrickRowScene): brick_copy = rows[row].rects[nb_tails].copy() brick_copy.set_fill(color = YELLOW, opacity = 0.8) prob_percentage = float(choose(row, nb_tails)) / 2**row * 100 - brick_label = DecimalNumber(prob_percentage, unit = "\%", num_decimal_places = 1, color = BLACK) + brick_label = DecimalNumber(prob_percentage, + unit = "\%", num_decimal_places = 1, color = BLACK) brick_label.move_to(brick_copy) brick_label.scale_to_fit_height(0.8 * brick_copy.get_height()) return VGroup(brick_copy, brick_label) From 10d4fb327a228d677ffc3417bf9fbdf4ba05c1d1 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 20:24:08 +0200 Subject: [PATCH 15/17] shuffling through all sequences of 20 flips --- active_projects/eop/chapter1/all_sequences.py | 62 +++++++++++++++++++ .../eop/reusables/upright_coins.py | 7 ++- 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 active_projects/eop/chapter1/all_sequences.py diff --git a/active_projects/eop/chapter1/all_sequences.py b/active_projects/eop/chapter1/all_sequences.py new file mode 100644 index 00000000..3a9d7e70 --- /dev/null +++ b/active_projects/eop/chapter1/all_sequences.py @@ -0,0 +1,62 @@ +from big_ol_pile_of_manim_imports import * +from active_projects.eop.reusable_imports import * + +class ShuffleThroughAllSequences(Scene): + CONFIG = { + "nb_coins" : 14, + "run_time" : 5, + "fps" : int(1.0/PRODUCTION_QUALITY_FRAME_DURATION), + "coin_size" : 0.5, + "coin_spacing" : 0.65 + } + + + def construct(self): + + nb_frames = self.run_time * self.fps + nb_relevant_coins = int(np.log2(nb_frames)) + 1 + print "relevant coins:", nb_relevant_coins + nb_idle_coins = self.nb_coins - nb_relevant_coins + + idle_heads = CoinSequence(nb_idle_coins * ["H"], + radius = self.coin_size * 0.5, + spacing = self.coin_spacing) + idle_tails = CoinSequence(nb_idle_coins * ["T"], + radius = self.coin_size * 0.5, + spacing = self.coin_spacing) + idle_tails.fade(0.5) + + idle_part = VGroup(idle_heads, idle_tails) + left_idle_part = CoinSequence(6 * ["H"], + radius = self.coin_size * 0.5, + spacing = self.coin_spacing) + + self.add(idle_part, left_idle_part) + last_coin_seq = VGroup() + + for i in range(2**nb_relevant_coins): + binary_seq = binary(i) + # pad to the left with 0s + nb_leading_zeroes = nb_relevant_coins - len(binary_seq) + for j in range(nb_leading_zeroes): + binary_seq.insert(0, 0) + seq2 = ["H" if x == 0 else "T" for x in binary_seq] + coin_seq = CoinSequence(seq2, + radius = self.coin_size * 0.5, + spacing = self.coin_spacing) + coin_seq.next_to(idle_part, LEFT, buff = self.coin_spacing - self.coin_size) + left_idle_part.next_to(coin_seq, LEFT, buff = self.coin_spacing - self.coin_size) + all_coins = VGroup(left_idle_part, coin_seq, idle_part) + all_coins.center() + self.remove(last_coin_seq) + self.add(coin_seq) + #self.wait(1.0/self.fps) + self.update_frame() + self.add_frames(self.get_frame()) + last_coin_seq = coin_seq + print float(i)/2**nb_relevant_coins + + + + + diff --git a/active_projects/eop/reusables/upright_coins.py b/active_projects/eop/reusables/upright_coins.py index 849180b2..1f5456b7 100644 --- a/active_projects/eop/reusables/upright_coins.py +++ b/active_projects/eop/reusables/upright_coins.py @@ -37,6 +37,7 @@ class UprightTails(UprightCoin): class CoinSequence(VGroup): CONFIG = { "sequence": [], + "radius" : COIN_RADIUS, "spacing": COIN_SEQUENCE_SPACING, "direction": RIGHT } @@ -47,11 +48,11 @@ class CoinSequence(VGroup): offset = 0 for symbol in self.sequence: if symbol == "H": - new_coin = UprightHeads() + new_coin = UprightHeads(radius = self.radius) elif symbol == "T": - new_coin = UprightTails() + new_coin = UprightTails(radius = self.radius) else: - new_coin = UprightCoin(symbol = symbol) + new_coin = UprightCoin(symbol = symbol, radius = self.radius) new_coin.shift(offset * self.direction) self.add(new_coin) offset += self.spacing From 6fa024b7739b9d6ef85356107d4ade0c7fd24ce5 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Wed, 9 May 2018 20:24:22 +0200 Subject: [PATCH 16/17] removed print call --- extract_scene.py | 1 - 1 file changed, 1 deletion(-) diff --git a/extract_scene.py b/extract_scene.py index d609b7ce..f7c91f94 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -235,7 +235,6 @@ def get_module_posix(file_name): def get_module(file_name): if os.name == 'nt': return get_module_windows(file_name) - print "file_name =", file_name return get_module_posix(file_name) From d97b9948768444aa3bbb38a53d80f63f78ebcb06 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 9 May 2018 14:01:38 -0700 Subject: [PATCH 17/17] Update tex_mobject.py --- mobject/svg/tex_mobject.py | 143 ++++++++++++------------------------- 1 file changed, 45 insertions(+), 98 deletions(-) diff --git a/mobject/svg/tex_mobject.py b/mobject/svg/tex_mobject.py index 06c6df13..c7bcc78b 100644 --- a/mobject/svg/tex_mobject.py +++ b/mobject/svg/tex_mobject.py @@ -4,14 +4,13 @@ from svg_mobject import SVGMobject from svg_mobject import VMobjectFromSVGPathstring from utils.config_ops import digest_config from utils.strings import split_string_list_to_isolate_substring +from utils.tex_file_writing import tex_to_svg_file +from mobject.geometry import Line from mobject.types.vectorized_mobject import VGroup from mobject.types.vectorized_mobject import VectorizedPoint import operator as op -# TODO list -# - Make sure if "color" is passed into TexMobject, it behaves as expected - TEX_MOB_SCALE_FACTOR = 0.05 @@ -67,11 +66,20 @@ class SingleStringTexMobject(SVGMobject): def modify_special_strings(self, tex): tex = self.remove_stray_braces(tex) - if tex in ["\\over", "\\overline"]: - # fraction line needs something to be over - tex += "\\," - if tex == "\\sqrt": - tex += "{\\quad}" + should_add_filler = reduce(op.or_, [ + # Fraction line needs something to be over + tex == "\\over", + tex == "\\overline", + # Makesure sqrt has overbar + tex == "\\sqrt", + # Need to add blank subscript or superscript + tex.endswith("_"), + tex.endswith("^"), + ]) + if should_add_filler: + filler = "{\\quad}" + tex += filler + if tex == "\\substack": tex = "" for t1, t2 in ("\\left", "\\right"), ("\\right", "\\left"): @@ -95,10 +103,9 @@ class SingleStringTexMobject(SVGMobject): for char in "{}" ] if num_rights > num_lefts: - backwards = tex[::-1].replace("}", "", num_rights - num_lefts) - tex = backwards[::-1] + tex = "{" + tex elif num_lefts > num_rights: - tex = tex.replace("{", "", num_lefts - num_rights) + tex = tex + "}" return tex def get_tex_string(self): @@ -273,98 +280,38 @@ class BulletedList(TextMobject): class TexMobjectFromPresetString(TexMobject): + CONFIG = { + # To be filled by subclasses + "tex": None, + "color": None, + } def __init__(self, **kwargs): digest_config(self, kwargs) TexMobject.__init__(self, self.tex, **kwargs) self.set_color(self.color) -########## +class Title(TextMobject): + CONFIG = { + "scale_factor": 1, + "include_underline": True, + "underline_width": FRAME_WIDTH - 2, + # This will override underline_width + "match_underline_width_to_text": False, + "underline_buff": MED_SMALL_BUFF, + } -def tex_hash(expression, template_tex_file): - return str(hash(expression + template_tex_file)) - - -def tex_to_svg_file(expression, template_tex_file): - image_dir = os.path.join( - TEX_IMAGE_DIR, - tex_hash(expression, template_tex_file) - ) - if os.path.exists(image_dir): - return get_sorted_image_list(image_dir) - tex_file = generate_tex_file(expression, template_tex_file) - dvi_file = tex_to_dvi(tex_file) - return dvi_to_svg(dvi_file) - - -def generate_tex_file(expression, template_tex_file): - result = os.path.join( - TEX_DIR, - tex_hash(expression, template_tex_file) - ) + ".tex" - if not os.path.exists(result): - print("Writing \"%s\" to %s" % ( - "".join(expression), result - )) - with open(template_tex_file, "r") as infile: - body = infile.read() - body = body.replace(TEX_TEXT_TO_REPLACE, expression) - with open(result, "w") as outfile: - outfile.write(body) - return result - - -def get_null(): - if os.name == "nt": - return "NUL" - return "/dev/null" - - -def tex_to_dvi(tex_file): - result = tex_file.replace(".tex", ".dvi") - if not os.path.exists(result): - commands = [ - "latex", - "-interaction=batchmode", - "-halt-on-error", - "-output-directory=" + TEX_DIR, - tex_file, - ">", - get_null() - ] - exit_code = os.system(" ".join(commands)) - if exit_code != 0: - latex_output = '' - log_file = tex_file.replace(".tex", ".log") - if os.path.exists(log_file): - with open(log_file, 'r') as f: - latex_output = f.read() - raise Exception( - "Latex error converting to dvi. " - "See log output above or the log file: %s" % log_file) - return result - - -def dvi_to_svg(dvi_file, regen_if_exists=False): - """ - Converts a dvi, which potentially has multiple slides, into a - directory full of enumerated pngs corresponding with these slides. - Returns a list of PIL Image objects for these images sorted as they - where in the dvi - """ - result = dvi_file.replace(".dvi", ".svg") - if not os.path.exists(result): - commands = [ - "dvisvgm", - dvi_file, - "-n", - "-v", - "0", - "-o", - result, - ">", - get_null() - ] - os.system(" ".join(commands)) - return result + def __init__(self, text, **kwargs): + TextMobject.__init__(self, text, **kwargs) + self.scale(self.scale_factor) + self.to_edge(UP) + if self.include_underline: + underline = Line(LEFT, RIGHT) + underline.next_to(self, DOWN, buff=self.underline_buff) + if self.match_underline_width_to_text: + underline.match_width(self) + else: + underline.scale_to_fit_width(self.underline_width) + self.add(underline) + self.underline = underline