diff --git a/active_projects/eop/area_coin_toss.py b/active_projects/eop/area_coin_toss.py new file mode 100644 index 00000000..e1e64fc4 --- /dev/null +++ b/active_projects/eop/area_coin_toss.py @@ -0,0 +1,243 @@ +from big_ol_pile_of_manim_imports import * +from eop.pascal import * + + +WIDTH = 12 +HEIGHT = 1 +GRADE_COLOR_1 = COLOR_HEADS = RED +GRADE_COLOR_2 = COLOR_TAILS = BLUE +NB_ROWS = 6 + + +class Coin(Circle): + CONFIG = { + "radius": 0.2, + "stroke_width": 3, + "stroke_color": WHITE, + "fill_opacity": 1, + "symbol": "\euro", + } + + def __init__(self, **kwargs): + Circle.__init__(self,**kwargs) + self.symbol_mob = TextMobject(self.symbol, stroke_color = self.stroke_color) + self.symbol_mob.scale_to_fit_height(0.5*self.get_height()).move_to(self) + self.add(self.symbol_mob) + + +class Heads(Coin): + CONFIG = { + "fill_color": COLOR_HEADS, + "symbol": "H", + } + + +class Tails(Coin): + CONFIG = { + "fill_color": COLOR_TAILS, + "symbol": "T", + } + +class CoinStack(VGroup): + CONFIG = { + "spacing": 0.1, + "size": 5, + "face": Heads, + } + + def generate_points(self): + for n in range(self.size): + coin = self.face() + coin.shift(n * self.spacing * RIGHT) + self.add(coin) + +class HeadsStack(CoinStack): + CONFIG = { "face": Heads } + +class TailsStack(CoinStack): + CONFIG = { "face": Tails } + +class TallyStack(VGroup): + + def __init__(self,h,t,**kwargs): + self.nb_heads = h + self.nb_tails = t + VGroup.__init__(self,**kwargs) + + def generate_points(self): + stack1 = HeadsStack(size = self.nb_heads) + stack2 = TailsStack(size = self.nb_tails) + stack2.next_to(stack1, RIGHT, buff = SMALL_BUFF) + self.add(stack1, stack2) + + +class AreaSplittingScene(Scene): + + def create_rect_row(self,n): + rects_group = VGroup() + for k in range(n+1): + proportion = float(choose(n,k)) / 2**n + new_rect = Rectangle( + width = proportion * WIDTH, + height = HEIGHT, + fill_color = graded_color(n,k), + fill_opacity = 1 + ) + new_rect.next_to(rects_group,RIGHT,buff = 0) + rects_group.add(new_rect) + return rects_group + + def split_rect_row(self,rect_row): + + split_row = VGroup() + for rect in rect_row.submobjects: + half = rect.copy().stretch_in_place(0.5,0) + left_half = half.next_to(rect.get_center(),LEFT,buff = 0) + right_half = half.copy().next_to(rect.get_center(),RIGHT,buff = 0) + split_row.add(left_half, right_half) + return split_row + + + def rect_center(self,n,i,j): + if n < 0: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + if i < 0 or i > n: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + if j > choose(n,i) or j < 0: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + + rect = self.brick_array[n][i] + width = rect.get_width() + left_x = rect.get_center()[0] - width/2 + spacing = width / choose(n,i) + x = left_x + (j+0.5) * spacing + return np.array([x,rect.get_center()[1], rect.get_center()[2]]) + + def construct(self): + + # Draw the bricks + + brick_wall = VGroup() + rect_row = self.create_rect_row(0) + rect_row.move_to(3.5*UP + 0*HEIGHT*DOWN) + self.add(rect_row) + brick_wall.add(rect_row) + self.brick_array = [[rect_row.submobjects[0]]] + + for n in range(NB_ROWS): + # copy and shift + new_rect_row = rect_row.copy() + self.add(new_rect_row) + self.play(new_rect_row.shift,HEIGHT * DOWN) + self.wait() + + #split + split_row = self.split_rect_row(new_rect_row) + self.play(FadeIn(split_row)) + self.remove(new_rect_row) + self.wait() + + # merge + rect_row = self.create_rect_row(n+1) + rect_row.move_to(3.5*UP + (n+1)*HEIGHT*DOWN) + self.play(FadeIn(rect_row)) + brick_wall.add(rect_row) + self.remove(split_row) + self.wait() + + # add to brick dict + rect_array = [] + for rect in rect_row.submobjects: + rect_array.append(rect) + + self.brick_array.append(rect_array) + + + self.play( + brick_wall.set_fill, {"opacity" : 0.2} + ) + + + # Draw the branches + + for (n, rect_row_array) in enumerate(self.brick_array): + for (i, rect) in enumerate(rect_row_array): + pos = rect.get_center() + tally = TallyStack(n - i, i) + tally.move_to(pos) + + + # from the left + lines = VGroup() + + if i > 0: + for j in range(choose(n-1,i-1)): + start_pos = self.rect_center(n-1,i-1,j) + end_pos = self.rect_center(n,i,j) + lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_2)) + self.play( + LaggedStart(ShowCreation, lines)) + + # from the right + lines = VGroup() + + if i < n: + for j in range(choose(n-1,i)): + start_pos = self.rect_center(n-1,i,j) + if i != 0: + end_pos = self.rect_center(n,i,choose(n-1,i-1) + j) + else: + end_pos = self.rect_center(n,i,j) + + lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_1)) + self.play( + LaggedStart(ShowCreation, lines)) + + + + #self.play(FadeIn(tally)) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + self.wait() + + + diff --git a/active_projects/eop/chapter1.py b/active_projects/eop/chapter1.py new file mode 100644 index 00000000..7cb6c469 --- /dev/null +++ b/active_projects/eop/chapter1.py @@ -0,0 +1,954 @@ +from big_ol_pile_of_manim_imports import * +from old_projects.eoc.chapter8 import * + +COIN_RADIUS = 0.3 +COIN_THICKNESS = 0.4 * COIN_RADIUS +COIN_FORESHORTENING = 0.3 +COIN_NB_RIDGES = 20 +COIN_STROKE_WIDTH = 2 + +COIN_SEQUENCE_SPACING = 0.1 + +GRADE_COLOR_1 = COLOR_HEADS = RED +GRADE_COLOR_2 = COLOR_TAILS = BLUE + + +def binary(i): + # returns an array of 0s and 1s + if i == 0: + return [] + j = i + binary_array = [] + while j > 0: + jj = j/2 + if jj > 0: + binary_array.append(j % 2) + else: + binary_array.append(1) + j = jj + return binary_array[::-1] + +def nb_of_ones(i): + return binary(i).count(1) + +class PiCreatureCoin(VMobject): + CONFIG = { + "diameter": 0.8, + "thickness": 0.2, + "nb_ridges" : 7, + "stroke_color": YELLOW, + "stroke_width": 3, + "fill_color": YELLOW, + "fill_opacity": 0.7, + } + + def generate_points(self): + outer_rect = Rectangle( + width = self.diameter, + height = self.thickness, + fill_color = self.fill_color, + fill_opacity = self.fill_opacity, + stroke_color = self.stroke_color, + stroke_width = 0, #self.stroke_width + ) + self.add(outer_rect) + PI = TAU/2 + ridge_angles = np.arange(PI/self.nb_ridges,PI,PI/self.nb_ridges) + ridge_positions = 0.5 * self.diameter * np.array([ + np.cos(theta) for theta in ridge_angles + ]) + ridge_color = interpolate_color(BLACK,self.stroke_color,0.5) + for x in ridge_positions: + ridge = Line( + x * RIGHT + 0.5 * self.thickness * DOWN, + x * RIGHT + 0.5 * self.thickness * UP, + stroke_color = ridge_color, + stroke_width = self.stroke_width + ) + self.add(ridge) + +class CoinFlippingPiCreature(PiCreature): + + def __init__(self, **kwargs): + + coin = PiCreatureCoin() # Line(ORIGIN, 0.4 * RIGHT, stroke_width = 15, color = YELLOW) + PiCreature.__init__(self,**kwargs) + self.coin = coin + self.add(coin) + right_arm = self.get_arm_copies()[1] + coin.next_to(right_arm, RIGHT+UP, buff = 0) + coin.shift(0.15 * self.get_width() * LEFT) + + def flip_coin_up(self): + self.change("raise_right_hand") + +class FlipUpAndDown(Animation): + CONFIG = { + "vector" : UP, + "nb_turns" : 1 + } + + def update(self,t): + self.mobject.shift(4 * t * (1 - t) * self.vector) + self.mobject.rotate(t * self.nb_turns * TAU) + +class FlipCoin(AnimationGroup): + CONFIG = { + "rate_func" : there_and_back + } + def __init__(self, pi_creature, **kwargs): + digest_config(self, kwargs) + pi_creature_motion = ApplyMethod( + pi_creature.flip_coin_up, + rate_func = self.rate_func, + **kwargs + ) + coin_motion = FlipUpAndDown( + pi_creature.coin, + vector = UP, + nb_turns = 5, + rate_func = self.rate_func, + **kwargs + ) + AnimationGroup.__init__(self,pi_creature_motion, coin_motion) + +class CoinFlippingPiCreatureScene(Scene): + + def construct(self): + + randy = CoinFlippingPiCreature() + self.add(randy) + self.play(FlipCoin(randy, run_time = 3)) + + +class UprightCoin(Circle): +# For use in coin sequences + CONFIG = { + "radius": COIN_RADIUS, + "stroke_width": COIN_STROKE_WIDTH, + "stroke_color": WHITE, + "fill_opacity": 1, + "symbol": "\euro" + } + + def __init__(self, **kwargs): + Circle.__init__(self,**kwargs) + self.symbol_mob = TextMobject(self.symbol, stroke_color = self.stroke_color) + self.symbol_mob.scale_to_fit_height(0.5*self.get_height()).move_to(self) + self.add(self.symbol_mob) + +class UprightHeads(UprightCoin): + CONFIG = { + "fill_color": COLOR_HEADS, + "symbol": "H", + } + +class UprightTails(UprightCoin): + CONFIG = { + "fill_color": COLOR_TAILS, + "symbol": "T", + } + +class CoinSequence(VGroup): + CONFIG = { + "sequence": [], + "spacing": COIN_SEQUENCE_SPACING + } + + def __init__(self, sequence, **kwargs): + VGroup.__init__(self, **kwargs) + self.sequence = sequence + offset = 0 + for symbol in self.sequence: + if symbol == "H": + new_coin = UprightHeads() + elif symbol == "T": + new_coin = UprightTails() + else: + new_coin = UprightCoin(symbol = symbol) + new_coin.shift(offset * RIGHT) + self.add(new_coin) + offset += self.spacing + +class FlatCoin(UprightCoin): +# For use in coin stacks + CONFIG = { + "thickness": COIN_THICKNESS, + "foreshortening": COIN_FORESHORTENING, + "nb_ridges": COIN_NB_RIDGES + } + + def __init__(self, **kwargs): + UprightCoin.__init__(self, **kwargs) + self.symbol_mob.rotate(TAU/8) + self.stretch_in_place(self.foreshortening, 1) + + # draw the edge + control_points1 = self.points[12:25].tolist() + control_points2 = self.copy().shift(self.thickness * DOWN).points[12:25].tolist() + edge_anchors_and_handles = control_points1 + edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN) + edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP) + edge_anchors_and_handles += control_points2[::-1] # list concatenation + edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * UP) + edge_anchors_and_handles.append(edge_anchors_and_handles[-1] + self.thickness * DOWN) + edge_anchors_and_handles.append(control_points1[0]) + #edge_anchors_and_handles = edge_anchors_and_handles[::-1] + edge = VMobject() + edge.set_points(edge_anchors_and_handles) + edge.set_fill( + color = self.fill_color, + opacity = self.fill_opacity + ) + edge.set_stroke(width = self.stroke_width) + self.add(edge) + + # draw the ridges + PI = TAU/2 + dtheta = PI/self.nb_ridges + ridge_angles = np.arange(dtheta,PI,dtheta) + # add a twist onto each coin + ridge_angles += np.random.rand(1) * dtheta + # crop the angles that overshoot on either side + ridge_angles = ridge_angles[(ridge_angles > 0) * (ridge_angles < PI)] + ridge_positions = 0.5 * 2 * self.radius * np.array([ + np.cos(theta) for theta in ridge_angles + ]) + ridge_color = interpolate_color(self.stroke_color, self.fill_color, 0.7) + for x in ridge_positions: + y = -(1 - (x/self.radius)**2)**0.5 * self.foreshortening * self.radius + ridge = Line( + x * RIGHT + y * UP, + x * RIGHT + y * UP + self.thickness * DOWN, + stroke_color = ridge_color, + stroke_width = self.stroke_width + ) + self.add(ridge) + + # redraw the unfilled edge to cover the ridge ends + empty_edge = edge.copy() + empty_edge.set_fill(opacity = 0) + self.add(empty_edge) + +class FlatHeads(FlatCoin): + CONFIG = { + "fill_color": COLOR_HEADS, + "symbol": "H", + } + +class FlatTails(FlatCoin): + CONFIG = { + "fill_color": COLOR_TAILS, + "symbol": "T", + } + +class CoinStack(VGroup): + CONFIG = { + "coin_thickness": COIN_THICKNESS, + "size": 5, + "face": FlatCoin, + } + + def generate_points(self): + for n in range(self.size): + coin = self.face(thickness = self.coin_thickness) + coin.shift(n * self.coin_thickness * UP) + self.add(coin) + +class HeadsStack(CoinStack): + CONFIG = { + "face": FlatHeads + } + +class TailsStack(CoinStack): + CONFIG = { + "face": FlatTails + } + +class TallyStack(VGroup): + + def __init__(self,h,t,**kwargs): + self.nb_heads = h + self.nb_tails = t + VGroup.__init__(self,**kwargs) + + def generate_points(self): + stack1 = HeadsStack(size = self.nb_heads, coin_thickness = self.coin_thickness) + stack2 = TailsStack(size = self.nb_tails, coin_thickness = self.coin_thickness) + stack2.next_to(stack1, RIGHT, buff = SMALL_BUFF) + stack2.align_to(stack1, DOWN) + self.add(stack1, stack2) + +class CoinFlipTree(VGroup): + CONFIG = { + "total_width": 12, + "level_height": 0.8, + "nb_levels": 4, + "sort_until_level": 3 + } + + def __init__(self, **kwargs): + + VGroup.__init__(self, **kwargs) + + self.rows = [] + for n in range(self.nb_levels + 1): + if n <= self.sort_until_level: + self.create_row(n, sorted = True) + else: + self.create_row(n, sorted = False) + + + for row in self.rows: + for leaf in row: + dot = Dot() + dot.move_to(leaf[0]) + line = Line(leaf[2], leaf[0]) + if leaf[2][0] > leaf[0][0]: + line_color = COLOR_HEADS + else: + line_color = COLOR_TAILS + line.set_stroke(color = line_color) + group = VGroup() + group.add(dot) + group.add_to_back(line) + self.add(group) + + + + + def create_row(self, level, sorted = True): + + if level == 0: + new_row = [[ORIGIN,0,ORIGIN]] # is its own parent + self.rows.append(new_row) + return + + previous_row = self.rows[level - 1] + new_row = [] + dx = float(self.total_width) / (2 ** level) + x = - 0.5 * self.total_width + 0.5 * dx + y = - self.level_height * level + for root in previous_row: + root_point = root[0] + root_tally = root[1] + for i in range(2): # 0 = heads = left, 1 = tails = right + leaf = x * RIGHT + y * UP + new_row.append([leaf, root_tally + i, root_point]) # leaf and its parent + x += dx + + #print "tallies for row", level, ":", [new_row[i][1] for i in range(2**level)] + + if sorted: + # sort the new_row by its tallies + sorted_row = [] + x = - 0.5 * self.total_width + 0.5 * dx + for i in range(level + 1): + for leaf in new_row: + if leaf[1] == i: + sorted_leaf = leaf + sorted_leaf[0][0] = x + x += dx + sorted_row.append(leaf) + print "sorted roots:", [sorted_row[i][2][0] for i in range(2**level)] + self.rows.append(sorted_row) + else: + self.rows.append(new_row) + + + + +class TestScene(Scene): + + def construct(self): + + #seq = CoinSequence(["H", "T", "T", "H"]).move_to(2 * LEFT) + #self.add(seq) + + #stack = TallyStack(4,7, coin_thickness = COIN_THICKNESS) + #self.add(stack) + + tree = CoinFlipTree(nb_levels = 7, sort_until_level = 0) + tree.move_to(ORIGIN) + self.add(tree) + + for i in range(1, 8): + new_tree = CoinFlipTree(nb_levels = 7, sort_until_level = i) + new_tree.move_to(ORIGIN) + self.play(Transform(tree, new_tree)) + self.wait() + + self.wait() + + +class CoinFlipBranchToAreaScene(Scene): + + def construct(self): + + pass + + + +class Chapter1OpeningQuote(OpeningQuote): + CONFIG = { + "fade_in_kwargs": { + "submobject_mode": "lagged_start", + "rate_func": None, + "lag_factor": 9, + "run_time": 10, + }, + "text_size" : "\\normalsize", + "use_quotation_marks": False, + "quote" : [ + "To see a world in a grain of sand\\\\", + "And a heaven in a wild flower,\\\\", + "Hold infinity in the palm of your hand\\\\", + "\phantom{r}And eternity in an hour.\\\\" + ], + "quote_arg_separator" : " ", + "highlighted_quote_terms" : {}, + "author" : "William Blake: \\\\ \emph{Auguries of Innocence}", + } + +class Introduction(TeacherStudentsScene): + + CONFIG = { + "default_pi_creature_kwargs": { + "color": MAROON_E, + "flip_at_start": True, + }, + } + + def construct(self): + self.show_series() + + def show_series(self): + series = VideoSeries() + 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), + ]) + + essence_words = words.get_part_by_tex("Essence").copy() + self.play( + FadeOut(self.teacher.bubble), + FadeOut(self.teacher.bubble.content), + essence_words.next_to, series, DOWN, + *[ + ApplyMethod(pi.change_mode, "pondering") + for pi in self.get_pi_creatures() + ] + ) + self.wait(3) + + self.series = series + self.essence_words = essence_words + +class IllustrateAreaModel1(Scene): + + def construct(self): + + # show independent events + + sample_space_width = sample_space_height = 3.0 + p_of_A = 0.7 + p_of_not_A = 1 - p_of_A + p_of_B = 0.8 + p_of_not_B = 1 - p_of_B + + + rect_A = Rectangle( + width = p_of_A * sample_space_width, + height = 1 * sample_space_height, + stroke_width = 0, + fill_color = BLUE, + fill_opacity = 1.0 + ) + rect_not_A = Rectangle( + width = p_of_not_A * sample_space_width, + height = 1 * sample_space_height, + stroke_width = 0, + fill_color = BLUE_E, + fill_opacity = 1.0 + ).next_to(rect_A, RIGHT, buff = 0) + + brace_A = Brace(rect_A, DOWN) + label_A = TexMobject("P(A)").next_to(brace_A, DOWN).scale(0.7) + brace_not_A = Brace(rect_not_A, DOWN) + label_not_A = TexMobject("P(\\text{not }A)").next_to(brace_not_A, DOWN).scale(0.7) + + self.play( + LaggedStart(FadeIn, VGroup(rect_A, rect_not_A), lag_factor = 0.5) + ) + self.play( + ShowCreation(brace_A), + Write(label_A), + ) + # self.play( + # ShowCreation(brace_not_A), + # Write(label_not_A), + # ) + + + + + rect_B = Rectangle( + width = 1 * sample_space_width, + height = p_of_B * sample_space_height, + stroke_width = 0, + fill_color = GREEN, + fill_opacity = 0.5 + ) + rect_not_B = Rectangle( + width = 1 * sample_space_width, + height = p_of_not_B * sample_space_height, + stroke_width = 0, + fill_color = GREEN_E, + fill_opacity = 0.5 + ).next_to(rect_B, UP, buff = 0) + + VGroup(rect_B, rect_not_B).move_to(VGroup(rect_A, rect_not_A)) + + brace_B = Brace(rect_B, LEFT) + label_B = TexMobject("P(B)").next_to(brace_B, LEFT).scale(0.7) + brace_not_B = Brace(rect_not_B, LEFT) + label_not_B = TexMobject("P(\\text{not }B)").next_to(brace_not_B, LEFT).scale(0.7) + + self.play( + LaggedStart(FadeIn, VGroup(rect_B, rect_not_B), lag_factor = 0.5) + ) + self.play( + ShowCreation(brace_B), + Write(label_B), + ) + # self.play( + # ShowCreation(brace_not_B), + # Write(label_not_B), + # ) + + rect_A_and_B = Rectangle( + width = p_of_A * sample_space_width, + height = p_of_B * sample_space_height, + stroke_width = 3, + fill_opacity = 0.0 + ).align_to(rect_A, DOWN).align_to(rect_A,LEFT) + label_A_and_B = TexMobject("P(A\\text{ and }B)").scale(0.7) + label_A_and_B.move_to(rect_A_and_B) + + self.play( + ShowCreation(rect_A_and_B) + ) + self.play(FadeIn(label_A_and_B)) + self.add_foreground_mobject(label_A_and_B) + + indep_formula = TexMobject("P(A\\text{ and }B)", "=", "P(A)", "\cdot", "P(B)") + indep_formula = indep_formula.scale(0.7).next_to(rect_not_B, UP, buff = MED_LARGE_BUFF) + + label_A_and_B_copy = label_A_and_B.copy() + label_A_copy = label_A.copy() + label_B_copy = label_B.copy() + self.add(label_A_and_B_copy, label_A_copy, label_B_copy) + + self.play(Transform(label_A_and_B_copy, indep_formula[0])) + self.play(FadeIn(indep_formula[1])) + self.play(Transform(label_A_copy, indep_formula[2])) + self.play(FadeIn(indep_formula[3])) + self.play(Transform(label_B_copy, indep_formula[4])) + + self.wait() + + + # show conditional prob + + rect_A_and_B.set_fill(color = GREEN, opacity = 0.5) + rect_A_and_not_B = Rectangle( + width = p_of_A * sample_space_width, + height = p_of_not_B * sample_space_height, + stroke_width = 0, + fill_color = GREEN_E, + fill_opacity = 0.5 + ).next_to(rect_A_and_B, UP, buff = 0) + + rect_not_A_and_B = Rectangle( + width = p_of_not_A * sample_space_width, + height = p_of_B * sample_space_height, + stroke_width = 0, + fill_color = GREEN, + fill_opacity = 0.5 + ).next_to(rect_A_and_B, RIGHT, buff = 0) + + rect_not_A_and_not_B = Rectangle( + width = p_of_not_A * sample_space_width, + height = p_of_not_B * sample_space_height, + stroke_width = 0, + fill_color = GREEN_E, + fill_opacity = 0.5 + ).next_to(rect_not_A_and_B, UP, buff = 0) + + self.remove(rect_B, rect_not_B) + self.add(rect_A_and_not_B, rect_not_A_and_B, rect_not_A_and_not_B) + + + + + + p_of_B_knowing_A = 0.6 + rect_A_and_B.target = Rectangle( + width = p_of_A * sample_space_width, + height = p_of_B_knowing_A * sample_space_height, + stroke_width = 3, + fill_color = GREEN, + fill_opacity = 0.5 + ).align_to(rect_A_and_B, DOWN).align_to(rect_A_and_B, LEFT) + + rect_A_and_not_B.target = Rectangle( + width = p_of_A * sample_space_width, + height = (1 - p_of_B_knowing_A) * sample_space_height, + stroke_width = 0, + fill_color = GREEN_E, + fill_opacity = 0.5 + ).next_to(rect_A_and_B.target, UP, buff = 0) + + brace_B.target = Brace(rect_A_and_B.target, LEFT) + label_B.target = TexMobject("P(B\mid A)").scale(0.7).next_to(brace_B.target, LEFT) + + + self.play( + MoveToTarget(rect_A_and_B), + MoveToTarget(rect_A_and_not_B), + MoveToTarget(brace_B), + MoveToTarget(label_B), + label_A_and_B.move_to,rect_A_and_B.target + ) + label_B_knowing_A = label_B + + self.play(FadeOut(label_B_copy)) + label_B_knowing_A_copy = label_B_knowing_A.copy() + self.add(label_B_knowing_A_copy) + + self.play( + label_B_knowing_A_copy.next_to, indep_formula[-2], RIGHT + ) + + + + + + self.wait() + + + # def show_independent_events(self): + # sample_space = SampleSpace( + # full_space_config = { + # "height" : 3, + # "width" : 3, + # "fill_opacity" : 0 + # } + # ) + # sample_space.divide_horizontally(0.4) + # sample_space.horizontal_parts.set_fill(opacity = 0) + # h_labels = [ + # TexMobject("P(", "A", ")"), + # TexMobject("P(\\text{not }", "A", ")"), + # ] + # for label in h_labels: + # label.scale(0.7) + # #self.color_label(label) + # sample_space.get_side_braces_and_labels(h_labels) + # sample_space.add_braces_and_labels() + # h_parts = sample_space.horizontal_parts + # for (label, part) in zip(h_labels, h_parts): + # label.next_to(part, 2 * LEFT) + # sample_space.add(label) + + # values = [0.2, 0.2] + # color_pairs = [(GREEN, BLUE), (GREEN_E, BLUE_E)] + # v_parts = VGroup() + # for tup in zip(h_parts, values, color_pairs): + # part, value, colors = tup + # part.divide_vertically(value, colors = colors) + # part.vertical_parts.set_fill(opacity = 0.8) + # #label = TexMobject( + # # "P(", "B", "|", given_str, "A", ")" + # #) + # #label.scale(0.7) + # #self.color_label(label) + # if part == h_parts[0]: + # part.get_subdivision_braces_and_labels( + # part.vertical_parts, [label], DOWN + # ) + # sample_space.add( + # part.vertical_parts.braces, + # # part.vertical_parts.labels, + # ) + # v_parts.add(part.vertical_parts.submobjects) + + + # v_labels = [ + # TexMobject("P(", "B", ")"), + # TexMobject("P(\\text{not }", "B", ")"), + # ] + # for (label, part) in zip(v_labels, v_parts[1::2]): + # label.scale(0.7) + # label.next_to(part, DOWN) + # sample_space.add(label) + + + # sample_space.to_edge(LEFT) + + # self.add(sample_space) + # self.sample_space = sample_space + + # self.wait() + + + + + + def color_label(self, label): + label.set_color_by_tex("B", RED) + label.set_color_by_tex("I", GREEN) + + + + + +class IllustrateAreaModel2(AreaIsDerivative): + + CONFIG = { + "y_max" : 4, + "y_min" : -4, + "num_iterations" : 7, + "y_axis_label" : "", + "num_rects" : 400, + "dT" : 0.25, + "variable_point_label" : "T", + "area_opacity" : 0.8, + } + def construct(self): + + self.setup_axes() + self.introduce_variable_area() + + graph, label = self.get_v_graph_and_label() + + rect_list = self.get_riemann_rectangles_list( + graph, self.num_iterations + ) + VGroup(*rect_list).set_fill(opacity = 0.8) + rects = rect_list[0] + + self.play(ShowCreation(graph)) + self.play(Write(rects)) + for new_rects in rect_list[1:]: + rects.align_submobjects(new_rects) + for every_other_rect in rects[::2]: + every_other_rect.set_fill(opacity = 0) + self.play(Transform( + rects, new_rects, + run_time = 2, + submobject_mode = "lagged_start" + )) + self.wait() + +# self.play(FadeOut(self.x_axis.numbers)) + self.add_T_label(6) + self.change_area_bounds( + new_t_max = 4, + rate_func = there_and_back, + run_time = 2 + ) + + def func(self, x): + return np.exp(-x**2/2) + + +class AreaSplitting(Scene): + + def create_rect_row(self,n): + rects_group = VGroup() + for k in range(n+1): + proportion = float(choose(n,k)) / 2**n + new_rect = Rectangle( + width = proportion * WIDTH, + height = HEIGHT, + fill_color = graded_color(n,k), + fill_opacity = 1 + ) + new_rect.next_to(rects_group,RIGHT,buff = 0) + rects_group.add(new_rect) + return rects_group + + def split_rect_row(self,rect_row): + + split_row = VGroup() + for rect in rect_row.submobjects: + half = rect.copy().stretch_in_place(0.5,0) + left_half = half.next_to(rect.get_center(),LEFT,buff = 0) + right_half = half.copy().next_to(rect.get_center(),RIGHT,buff = 0) + split_row.add(left_half, right_half) + return split_row + + + def rect_center(self,n,i,j): + if n < 0: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + if i < 0 or i > n: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + if j > choose(n,i) or j < 0: + raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j)) + + rect = self.brick_array[n][i] + width = rect.get_width() + left_x = rect.get_center()[0] - width/2 + spacing = width / choose(n,i) + x = left_x + (j+0.5) * spacing + return np.array([x,rect.get_center()[1], rect.get_center()[2]]) + + def construct(self): + + # Draw the bricks + + brick_wall = VGroup() + rect_row = self.create_rect_row(0) + rect_row.move_to(3.5*UP + 0*HEIGHT*DOWN) + self.add(rect_row) + brick_wall.add(rect_row) + self.brick_array = [[rect_row.submobjects[0]]] + + for n in range(NB_ROWS): + # copy and shift + new_rect_row = rect_row.copy() + self.add(new_rect_row) + self.play(new_rect_row.shift,HEIGHT * DOWN) + self.wait() + + #split + split_row = self.split_rect_row(new_rect_row) + self.play(FadeIn(split_row)) + self.remove(new_rect_row) + self.wait() + + # merge + rect_row = self.create_rect_row(n+1) + rect_row.move_to(3.5*UP + (n+1)*HEIGHT*DOWN) + self.play(FadeIn(rect_row)) + brick_wall.add(rect_row) + self.remove(split_row) + self.wait() + + # add to brick dict + rect_array = [] + for rect in rect_row.submobjects: + rect_array.append(rect) + + self.brick_array.append(rect_array) + + + self.play( + brick_wall.set_fill, {"opacity" : 0.2} + ) + + + # Draw the branches + + for (n, rect_row_array) in enumerate(self.brick_array): + for (i, rect) in enumerate(rect_row_array): + pos = rect.get_center() + tally = TallyStack(n - i, i) + tally.move_to(pos) + + + # from the left + lines = VGroup() + + if i > 0: + for j in range(choose(n-1,i-1)): + start_pos = self.rect_center(n-1,i-1,j) + end_pos = self.rect_center(n,i,j) + lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_2)) + self.play( + LaggedStart(ShowCreation, lines)) + + # from the right + lines = VGroup() + + if i < n: + for j in range(choose(n-1,i)): + start_pos = self.rect_center(n-1,i,j) + if i != 0: + end_pos = self.rect_center(n,i,choose(n-1,i-1) + j) + else: + end_pos = self.rect_center(n,i,j) + + lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_1)) + self.play( + LaggedStart(ShowCreation, lines)) + + + + #self.play(FadeIn(tally)) + + + + + + + + + + + + + + + + + + + + + + diff --git a/active_projects/eop/histograms.py b/active_projects/eop/histograms.py index 7303155d..2de66ea4 100644 --- a/active_projects/eop/histograms.py +++ b/active_projects/eop/histograms.py @@ -1,7 +1,7 @@ from big_ol_pile_of_manim_imports import * from random import * -def text_range(start,stop,step): +def text_range(start,stop,step): # a range as a list of strings numbers = np.arange(start,stop,step) labels = [] for x in numbers: diff --git a/active_projects/eop/pascal.py b/active_projects/eop/pascal.py index 087caf6b..688d3a5e 100644 --- a/active_projects/eop/pascal.py +++ b/active_projects/eop/pascal.py @@ -1,193 +1,355 @@ from big_ol_pile_of_manim_imports import * +from once_useful_constructs.combinatorics import * -nb_levels = 50 +nb_levels = 5 dev_x_step = 2 dev_y_step = 5 +GRADE_COLOR_1 = RED +GRADE_COLOR_2 = BLUE + + def rainbow_color(alpha): - nb_colors = 100 - rainbow = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], nb_colors) - rainbow = np.append(rainbow,PURPLE) - index = int(alpha * nb_colors) - return rainbow[index] + nb_colors = 100 + rainbow = color_gradient([RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE], nb_colors) + rainbow = np.append(rainbow,PURPLE) + index = int(alpha * nb_colors) + return rainbow[index] + +def graded_color(n,k): + if n != 0: + alpha = float(k)/n + else: + alpha = 0.5 + color = interpolate_color(GRADE_COLOR_1, GRADE_COLOR_2, alpha) + return color + + +def graded_square(n,k): + return Square( + side_length = 1, + fill_color = graded_color(n,k), + fill_opacity = 1, + stroke_width = 1 + ) + +def graded_binomial(n,k): + return Integer( + choose(n,k), + color = graded_color(n,k) + ) + +def split_square(n,k): + width = 1 + height = 1 + + proportion = float(choose(n,k)) / 2**n + + lower_height = proportion * height + upper_height = (1 - proportion) * height + lower_rect = Rectangle( + width = width, + height = lower_height, + fill_color = RED, + fill_opacity = 1.0, + stroke_color = WHITE, + stroke_width = 3 + ) + upper_rect = Rectangle( + width = width, + height = upper_height, + fill_color = BLUE, + fill_opacity = 1.0, + stroke_color = WHITE, + stroke_width = 3 + ) + upper_rect.next_to(lower_rect,UP,buff = 0) + square = VGroup(lower_rect, upper_rect).move_to(ORIGIN) + return square + + +class BuildNewPascalRow(Transform): + + def __init__(self,mobject, duplicate_row = None, **kwargs): + if mobject.__class__ != GeneralizedPascalsTriangle and mobject.__class__ != PascalsTriangle: + raise("Transform BuildNewPascalRow only works on members of (Generalized)PascalsTriangle!") + + n = mobject.nrows - 1 + lowest_row_copy1 = mobject.get_lowest_row() + lowest_row_copy2 = duplicate_row + + start_mob = VGroup(lowest_row_copy1, lowest_row_copy2) + + new_pt = mobject.copy() + new_pt.nrows += 1 + new_pt.generate_points() + # align with original (copy got centered on screen) + c1 = new_pt.coords_to_mobs[0][0].get_center() + c2 = mobject.coords_to_mobs[0][0].get_center() + print c1, c2 + v = c2 - c1 + new_pt.shift(v) + + new_row_left_copy = VGroup(*[ + new_pt.coords_to_mobs[n+1][k] + for k in range(0,n+1) + ]) + + new_row_right_copy = VGroup(*[ + new_pt.coords_to_mobs[n+1][k] + for k in range(1,n+2) + ]).copy() + + target_mob = VGroup(new_row_left_copy, new_row_right_copy) + + Transform.__init__(self, start_mob, target_mob, **kwargs) + + + + + +class SimplePascal(Scene): + + def build_new_pascal_row(self,old_pt): + + lowest_row_copy = old_pt.get_lowest_row().copy() + self.add(lowest_row_copy) + + n = old_pt.nrows - 1 + lowest_row_copy1 = old_pt.get_lowest_row() + lowest_row_copy2 = lowest_row_copy1.copy() + + + start_mob = VGroup(lowest_row_copy1, lowest_row_copy2) + self.add(start_mob) + + new_pt = old_pt.copy() + cell_height = old_pt.height / old_pt.nrows + cell_width = old_pt.width / old_pt.nrows + new_pt.nrows += 1 + new_pt.height = new_pt.nrows * cell_height + new_pt.width = new_pt.nrows * cell_width + + new_pt.generate_points() + # align with original (copy got centered on screen) + c1 = new_pt.coords_to_mobs[0][0].get_center() + c2 = old_pt.coords_to_mobs[0][0].get_center() + v = c2 - c1 + new_pt.shift(v) + + new_row_left_copy = VGroup(*[ + new_pt.coords_to_mobs[n+1][k] + for k in range(0,n+1) + ]) + + new_row_right_copy = VGroup(*[ + new_pt.coords_to_mobs[n+1][k] + for k in range(1,n+2) + ]).copy() + + target_mob = VGroup(new_row_left_copy, new_row_right_copy) + self.play(Transform(start_mob, target_mob)) + + return new_pt + + + + def construct(self): + + cell_height = 1 + cell_width = 1 + nrows = 1 + pt = GeneralizedPascalsTriangle( + nrows = nrows, + height = nrows * cell_height, + width = nrows * cell_width, + submob_class = graded_square, + portion_to_fill = 0.9 + ) + pt.shift(3 * UP) + self.add(pt) + lowest_row_copy = pt.get_lowest_row().copy() + self.add(lowest_row_copy) + #self.play(BuildNewPascalRow(pt, duplicate_row = lowest_row_copy)) + for i in range(7): + pt = self.build_new_pascal_row(pt) + +class PascalNetScene(Scene): + + def construct(self): + + unit_width = 0.25 + top_height = 4.0 + level_height = 2.0 * top_height / nb_levels + + start_points = np.array([top_height * UP]) + + dev_start = start_points[0] + + j = 0 + + for n in range(nb_levels): + + half_width = 0.5 * (n + 0.5) * unit_width + + stop_points_left = start_points.copy() + stop_points_left[:,0] -= 0.5 * unit_width + stop_points_left[:,1] -= level_height + + stop_points_right = start_points.copy() + stop_points_right[:,0] += 0.5 * unit_width + stop_points_right[:,1] -= level_height + + for (p,q) in zip(start_points,stop_points_left): + alpha = np.abs((p[0]+q[0])/2) / half_width + color = rainbow_color(alpha) + line = Line(p,q, stroke_color = color) + self.add(line) + + for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)): + alpha = np.abs((p[0]+q[0])/2) / half_width + color = rainbow_color(alpha) + line = Line(p,q, stroke_color = color) + self.add(line) + + if (n + 1) % dev_y_step == 0 and n != 1: + j += dev_x_step + dev_stop = stop_points_left[j] + line = Line(dev_start,dev_stop,stroke_color = WHITE) + self.add(line) + dot = Dot(dev_stop, fill_color = WHITE) + self.add_foreground_mobject(dot) + dev_start = dev_stop + + start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0) -class PascalScene(Scene): - - def construct(self): - - unit_width = 0.25 - top_height = 4.0 - level_height = 2.0 * top_height / nb_levels - - start_points = np.array([top_height * UP]) - - dev_start = start_points[0] - - j = 0 - - for n in range(nb_levels): - - half_width = 0.5 * (n + 0.5) * unit_width - - stop_points_left = start_points.copy() - stop_points_left[:,0] -= 0.5 * unit_width - stop_points_left[:,1] -= level_height - - stop_points_right = start_points.copy() - stop_points_right[:,0] += 0.5 * unit_width - stop_points_right[:,1] -= level_height - - for (p,q) in zip(start_points,stop_points_left): - alpha = np.abs((p[0]+q[0])/2) / half_width - color = rainbow_color(alpha) - line = Line(p,q, stroke_color = color) - self.add(line) - - for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)): - alpha = np.abs((p[0]+q[0])/2) / half_width - color = rainbow_color(alpha) - line = Line(p,q, stroke_color = color) - self.add(line) - - if (n + 1) % dev_y_step == 0 and n != 1: - j += dev_x_step - dev_stop = stop_points_left[j] - line = Line(dev_start,dev_stop,stroke_color = WHITE) - self.add(line) - dot = Dot(dev_stop, fill_color = WHITE) - self.add_foreground_mobject(dot) - dev_start = dev_stop - - start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0) - - - self.wait() + self.wait() -class RescaledPascalScene(Scene): +class RescaledPascalNetScene(Scene): - def construct(self): + def construct(self): - half_width = 3.0 - top_height = 4.0 - level_height = 2.0 * top_height / nb_levels + half_width = 3.0 + top_height = 4.0 + level_height = 2.0 * top_height / nb_levels - start_points = np.array([top_height * UP]) - left_edge = top_height * UP + half_width * LEFT - right_edge = top_height * UP + half_width * RIGHT + start_points = np.array([top_height * UP]) + left_edge = top_height * UP + half_width * LEFT + right_edge = top_height * UP + half_width * RIGHT - dev_start = start_points[0] + dev_start = start_points[0] - j = 0 + j = 0 - for n in range(nb_levels): + for n in range(nb_levels): - if n == 0: - start_points_left_shift = np.array([left_edge]) - else: - start_points_left_shift = start_points[:-1] - start_points_left_shift = np.insert(start_points_left_shift,0,left_edge, axis = 0) - stop_points_left = 0.5 * (start_points + start_points_left_shift) - stop_points_left += level_height * DOWN + if n == 0: + start_points_left_shift = np.array([left_edge]) + else: + start_points_left_shift = start_points[:-1] + start_points_left_shift = np.insert(start_points_left_shift,0,left_edge, axis = 0) + stop_points_left = 0.5 * (start_points + start_points_left_shift) + stop_points_left += level_height * DOWN - - if n == 0: - start_points_right_shift = np.array([right_edge]) - else: - start_points_right_shift = start_points[1:] - start_points_right_shift = np.append(start_points_right_shift,np.array([right_edge]), axis = 0) - stop_points_right = 0.5 * (start_points + start_points_right_shift) - stop_points_right += level_height * DOWN + + if n == 0: + start_points_right_shift = np.array([right_edge]) + else: + start_points_right_shift = start_points[1:] + start_points_right_shift = np.append(start_points_right_shift,np.array([right_edge]), axis = 0) + stop_points_right = 0.5 * (start_points + start_points_right_shift) + stop_points_right += level_height * DOWN - - for (i,(p,q)) in enumerate(zip(start_points,stop_points_left)): - - color = LIGHT_GRAY + + for (i,(p,q)) in enumerate(zip(start_points,stop_points_left)): + + color = LIGHT_GRAY - if n % 2 == 0 and i <= n/2: - m = n/2 + 0.25 - jj = i - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + if n % 2 == 0 and i <= n/2: + m = n/2 + 0.25 + jj = i + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 0 and i > n/2: - m = n/2 + 0.25 - jj = n - i + 0.5 - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 0 and i > n/2: + m = n/2 + 0.25 + jj = n - i + 0.5 + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 1 and i <= n/2: - m = n/2 + 0.75 - jj = i - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 1 and i <= n/2: + m = n/2 + 0.75 + jj = i + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 1 and i > n/2: - m = n/2 + 0.75 - jj = n - i + 0.5 - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 1 and i > n/2: + m = n/2 + 0.75 + jj = n - i + 0.5 + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - line = Line(p,q, stroke_color = color) - self.add(line) + line = Line(p,q, stroke_color = color) + self.add(line) - for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)): - - color = LIGHT_GRAY + for (i,(p,q)) in enumerate(zip(start_points,stop_points_right)): + + color = LIGHT_GRAY - if n % 2 == 0 and i < n/2: - m = n/2 + 0.25 - jj = i + 0.5 - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + if n % 2 == 0 and i < n/2: + m = n/2 + 0.25 + jj = i + 0.5 + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 0 and i >= n/2: - m = n/2 + 0.25 - jj = n - i - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 0 and i >= n/2: + m = n/2 + 0.25 + jj = n - i + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 1 and i <= n/2: - m = n/2 + 0.75 - jj = i + 0.5 - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 1 and i <= n/2: + m = n/2 + 0.75 + jj = i + 0.5 + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - elif n % 2 == 1 and i > n/2: - m = n/2 + 0.75 - jj = n - i - alpha = 1 - float(jj)/m - color = rainbow_color(alpha) + elif n % 2 == 1 and i > n/2: + m = n/2 + 0.75 + jj = n - i + alpha = 1 - float(jj)/m + color = rainbow_color(alpha) - line = Line(p,q, stroke_color = color) - self.add(line) + line = Line(p,q, stroke_color = color) + self.add(line) - if (n + 1) % dev_y_step == 0 and n != 1: - j += dev_x_step - dev_stop = stop_points_left[j] - line = Line(dev_start,dev_stop,stroke_color = WHITE) - self.add(line) - dot = Dot(dev_stop, fill_color = WHITE) - self.add_foreground_mobject(dot) - dev_start = dev_stop + if (n + 1) % dev_y_step == 0 and n != 1: + j += dev_x_step + dev_stop = stop_points_left[j] + line = Line(dev_start,dev_stop,stroke_color = WHITE) + self.add(line) + dot = Dot(dev_stop, fill_color = WHITE) + self.add_foreground_mobject(dot) + dev_start = dev_stop - start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0) - - left_edge += level_height * DOWN - right_edge += level_height * DOWN + start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0) + + left_edge += level_height * DOWN + right_edge += level_height * DOWN - self.wait() + self.wait() diff --git a/big_ol_pile_of_manim_imports.py b/big_ol_pile_of_manim_imports.py index 9e941ec7..628367c3 100644 --- a/big_ol_pile_of_manim_imports.py +++ b/big_ol_pile_of_manim_imports.py @@ -46,6 +46,7 @@ from mobject.numbers import * from mobject.probability import * from mobject.shape_matchers import * from mobject.svg.brace import * +from mobject.svg.drawings import * from mobject.svg.svg_mobject import * from mobject.svg.tex_mobject import * from mobject.three_dimensions import * @@ -59,15 +60,6 @@ from for_3b1b_videos.pi_creature import * from for_3b1b_videos.pi_creature_animations import * from for_3b1b_videos.pi_creature_scene import * -from scene.graph_scene import * -from scene.moving_camera_scene import * -from scene.reconfigurable_scene import * -from scene.scene import * -from scene.scene_from_video import * -from scene.three_d_scene import * -from scene.vector_space_scene import * -from scene.zoomed_scene import * - from once_useful_constructs.arithmetic import * from once_useful_constructs.combinatorics import * from once_useful_constructs.complex_transformation_scene import * @@ -76,6 +68,16 @@ from once_useful_constructs.fractals import * from once_useful_constructs.graph_theory import * from once_useful_constructs.light import * +from scene.graph_scene import * +from scene.moving_camera_scene import * +from scene.reconfigurable_scene import * +from scene.scene import * +from scene.sample_space_scene import * +from scene.graph_scene import * +from scene.scene_from_video import * +from scene.three_d_scene import * +from scene.vector_space_scene import * +from scene.zoomed_scene import * from utils.bezier import * from utils.color import * diff --git a/for_3b1b_videos/common_scenes.py b/for_3b1b_videos/common_scenes.py index e25cd68b..f1731d8c 100644 --- a/for_3b1b_videos/common_scenes.py +++ b/for_3b1b_videos/common_scenes.py @@ -34,6 +34,10 @@ class OpeningQuote(Scene): "lag_factor": 4, "run_time": 5, }, + "text_size" : "\\Large", + "use_quotation_marks": True, + "top_buff" : 1.0, + "author_buff": 1.0, } def construct(self): @@ -42,7 +46,7 @@ class OpeningQuote(Scene): self.play(FadeIn(self.quote, **self.fade_in_kwargs)) self.wait(2) - self.play(Write(self.author, run_time=3)) + self.play(Write(self.author, run_time = 3)) self.wait() def get_quote(self, max_width=FRAME_WIDTH - 1): @@ -51,25 +55,32 @@ class OpeningQuote(Scene): "arg_separator": self.quote_arg_separator, } if isinstance(self.quote, str): - quote = TextMobject("``%s''" % + if self.use_quotation_marks: + quote = TextMobject("``%s''" % + self.quote.strip(), **text_mobject_kwargs) + else: + quote = TextMobject("%s" % self.quote.strip(), **text_mobject_kwargs) else: - words = ["\\Large ``"] + list(self.quote) + ["''"] + if self.use_quotation_marks: + words = [self.text_size + " ``"] + list(self.quote) + ["''"] + else: + words = [self.text_size] + list(self.quote) quote = TextMobject(*words, **text_mobject_kwargs) # TODO, make less hacky if self.quote_arg_separator == " ": quote[0].shift(0.2 * RIGHT) quote[-1].shift(0.2 * LEFT) - for term, color in self.set_colored_quote_terms.items(): + for term, color in self.highlighted_quote_terms: quote.set_color_by_tex(term, color) - quote.to_edge(UP) + quote.to_edge(UP, buff = self.top_buff) if quote.get_width() > max_width: quote.scale_to_fit_width(max_width) return quote def get_author(self, quote): - author = TextMobject("\\Large -" + self.author) - author.next_to(quote, DOWN) + author = TextMobject(self.text_size + " --" + self.author) + author.next_to(quote, DOWN, buff = self.author_buff) author.set_color(YELLOW) return author diff --git a/for_3b1b_videos/pi_creature.py b/for_3b1b_videos/pi_creature.py index 95f82973..46064cf6 100644 --- a/for_3b1b_videos/pi_creature.py +++ b/for_3b1b_videos/pi_creature.py @@ -1,4 +1,5 @@ import numpy as np +import warnings from constants import * diff --git a/for_3b1b_videos/pi_creature_scene.py b/for_3b1b_videos/pi_creature_scene.py index 220e58a7..3f9da5db 100644 --- a/for_3b1b_videos/pi_creature_scene.py +++ b/for_3b1b_videos/pi_creature_scene.py @@ -266,7 +266,7 @@ class TeacherStudentsScene(PiCreatureScene): UP + LEFT) + MED_LARGE_BUFF * UP def create_pi_creatures(self): - self.teacher = Mortimer() + self.teacher = Mortimer(color = self.default_pi_creature_kwargs["color"]) self.teacher.to_corner(DOWN + RIGHT) self.teacher.look(DOWN + LEFT) self.students = VGroup(*[ diff --git a/mobject/mobject.py b/mobject/mobject.py index bfe13e09..00bc8502 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -115,7 +115,7 @@ class Mobject(Container): def copy(self): # TODO, either justify reason for shallow copy, or # remove this redundancy everywhere - return self.deepcopy() + #return self.deepcopy() copy_mobject = copy.copy(self) copy_mobject.points = np.array(self.points) @@ -554,7 +554,7 @@ class Mobject(Container): return self def fade_to(self, color, alpha): - for mob in self.subobject_family(): + for mob in self.submobject_family(): mob.fade_to_no_recurse(self, color, alpha) return self diff --git a/once_useful_constructs/combinatorics.py b/once_useful_constructs/combinatorics.py index 42340dfd..88a300b3 100644 --- a/once_useful_constructs/combinatorics.py +++ b/once_useful_constructs/combinatorics.py @@ -1,7 +1,8 @@ from constants import * from mobject.svg.tex_mobject import TexMobject -from mobject.types.vectorized_mobject import VMobject +from mobject.types.vectorized_mobject import VMobject, VGroup +from mobject.numbers import Integer from scene.scene import Scene from utils.simple_functions import choose @@ -85,12 +86,17 @@ class CountingScene(Scene): self.number = num_mob return self -class PascalsTriangle(VMobject): +def combinationMobject(n,k): + return Integer(choose(n,k)) + + +class GeneralizedPascalsTriangle(VMobject): CONFIG = { "nrows" : 7, "height" : FRAME_HEIGHT - 1, "width" : 1.5*FRAME_X_RADIUS, - "portion_to_fill" : 0.7 + "portion_to_fill" : 0.7, + "submob_class" : combinationMobject, } def generate_points(self): self.cell_height = float(self.height) / self.nrows @@ -98,16 +104,16 @@ class PascalsTriangle(VMobject): self.bottom_left = (self.cell_width * self.nrows / 2.0)*LEFT + \ (self.cell_height * self.nrows / 2.0)*DOWN num_to_num_mob = {} - self.coords_to_mobs = {} + self.coords_to_mobs = {} self.coords = [ (n, k) for n in range(self.nrows) for k in range(n+1) ] for n, k in self.coords: - num = choose(n, k) + num = choose(n, k) center = self.coords_to_center(n, k) - num_mob = TexMobject(str(num)) + num_mob = self.submob_class(n,k) #TexMobject(str(num)) scale_factor = min( 1, self.portion_to_fill * self.cell_height / num_mob.get_height(), @@ -167,7 +173,19 @@ class PascalsTriangle(VMobject): self.add(mob) return self - + def get_lowest_row(self): + n = self.nrows - 1 + lowest_row = VGroup(*[ + self.coords_to_mobs[n][k] + for k in range(n+1) + ]) + return lowest_row + + +class PascalsTriangle(GeneralizedPascalsTriangle): + CONFIG = { + "submob_class" : combinationMobject, + } diff --git a/scene/graph_scene.py b/scene/graph_scene.py index 3d014d62..5caec9e6 100644 --- a/scene/graph_scene.py +++ b/scene/graph_scene.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from constants import * +import itertools as it from scene.scene import Scene from animation.creation import Write diff --git a/scene/sample_space_scene.py b/scene/sample_space_scene.py index b1fa129f..a03e4195 100644 --- a/scene/sample_space_scene.py +++ b/scene/sample_space_scene.py @@ -1,6 +1,6 @@ from constants import * -from scene.scene import Scene +from scene import Scene from animation.animation import Animation from animation.transform import MoveToTarget