From 5ab540a04445c3af17bbbfcd1293a45cf5d53079 Mon Sep 17 00:00:00 2001 From: Ben Hambrecht Date: Thu, 5 Apr 2018 18:50:09 +0200 Subject: [PATCH] first variants of generalized Pascal's Triangle --- active_projects/eop/pascal.py | 422 +++++++++++++++++++++++----------- 1 file changed, 286 insertions(+), 136 deletions(-) diff --git a/active_projects/eop/pascal.py b/active_projects/eop/pascal.py index 0870bef1..2ea554b6 100644 --- a/active_projects/eop/pascal.py +++ b/active_projects/eop/pascal.py @@ -1,201 +1,351 @@ 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 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(RED, BLUE, alpha) + return color -class SampleScene(Scene): +def graded_square(n,k): + return Square( + side_length = 1, + fill_color = graded_color(n,k), + fill_opacity = 1, + stroke_width = 1 + ) - def construct(self): +def graded_binomial(n,k): + return Integer( + choose(n,k), + color = graded_color(n,k) + ) - triangle = Polygon() - self.add(triangle) - self.wait() +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): + def construct(self): - unit_width = 0.25 - top_height = 4.0 - level_height = 2.0 * top_height / nb_levels + unit_width = 0.25 + top_height = 4.0 + level_height = 2.0 * top_height / nb_levels - start_points = np.array([top_height * UP]) + start_points = np.array([top_height * UP]) - 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): - half_width = 0.5 * (n + 0.5) * unit_width + 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_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) + 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) + 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 + 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) + start_points = np.append(stop_points_left,[stop_points_right[-1]], axis = 0) - self.wait() + self.wait() 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()