class PartyHat(SVGMobject): CONFIG = { "file_name": "party_hat", "height": 1.5, "pi_creature": None, "stroke_width": 0, "fill_opacity": 1, "propagate_style_to_family": True, "frills_colors": [MAROON_B, PURPLE], "cone_color": GREEN, "dots_colors": [YELLOW], } NUM_FRILLS = 7 NUM_DOTS = 6 def __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.set_height(self.height) if self.pi_creature is not None: self.next_to(self.pi_creature.eyes, UP, buff=0) self.frills = VGroup(*self[:self.NUM_FRILLS]) self.cone = self[self.NUM_FRILLS] self.dots = VGroup(*self[self.NUM_FRILLS + 1:]) self.frills.set_color_by_gradient(*self.frills_colors) self.cone.set_color(self.cone_color) self.dots.set_color_by_gradient(*self.dots_colors)
def get_subdivision_braces_and_labels(self, parts, labels, direction, buff=SMALL_BUFF, min_num_quads=1): label_mobs = VGroup() braces = VGroup() for label, part in zip(labels, parts): brace = Brace(part, direction, min_num_quads=min_num_quads, buff=buff) if isinstance(label, Mobject): label_mob = label else: label_mob = TexMobject(label) label_mob.scale(self.default_label_scale_val) label_mob.next_to(brace, direction, buff) braces.add(brace) label_mobs.add(label_mob) parts.braces = braces parts.labels = label_mobs parts.label_kwargs = { "labels": label_mobs.copy(), "direction": direction, "buff": buff, } return VGroup(parts.braces, parts.labels)
def add_lines(self, left, right): line_kwargs = { "color": BLUE, "stroke_width": 2, } left_rows = [VGroup(*row) for row in left.get_mob_matrix()] h_lines = VGroup() for row in left_rows[:-1]: h_line = Line(row.get_left(), row.get_right(), **line_kwargs) h_line.next_to(row, DOWN, buff=left.v_buff / 2.) h_lines.add(h_line) right_cols = [ VGroup(*col) for col in np.transpose(right.get_mob_matrix()) ] v_lines = VGroup() for col in right_cols[:-1]: v_line = Line(col.get_top(), col.get_bottom(), **line_kwargs) v_line.next_to(col, RIGHT, buff=right.h_buff / 2.) v_lines.add(v_line) self.play(ShowCreation(h_lines)) self.play(ShowCreation(v_lines)) self.wait() self.show_frame()
def get_coordinate_labels(self, *numbers): # TODO: Should merge this with the code from NumberPlane.get_coordinate_labels result = VGroup() if len(numbers) == 0: numbers = list(range(-int(self.x_radius), int(self.x_radius) + 1)) numbers += [ complex(0, y) for y in range(-int(self.y_radius), int(self.y_radius) + 1) ] for number in numbers: if number == complex(0, 0): continue point = self.number_to_point(number) num_str = str(number).replace("j", "i") if num_str.startswith("0"): num_str = "0" elif num_str in ["1i", "-1i"]: num_str = num_str.replace("1", "") num_mob = TexMobject(num_str) num_mob.add_background_rectangle() num_mob.set_height(self.written_coordinate_height) num_mob.next_to(point, DOWN + LEFT, SMALL_BUFF) result.add(num_mob) self.coordinate_labels = result return result
def add_T_label(self, x_val, side=RIGHT, label=None, color=WHITE, animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.set_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(color, 1) triangle.set_stroke(width=0) if label == None: T_label = TexMobject(self.variable_point_label, fill_color=color) else: T_label = TexMobject(label, fill_color=color) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph(x_val, self.v_graph, color=YELLOW) if animated: self.play(DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs) if np.all(side == LEFT): self.left_T_label_group = VGroup(T_label, triangle) self.left_v_line = v_line self.add(self.left_T_label_group, self.left_v_line) elif np.all(side == RIGHT): self.right_T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line self.add(self.right_T_label_group, self.right_v_line)
def __init__(self, **kwargs): digest_config(self, kwargs) videos = [VideoIcon() for x in range(self.num_videos)] VGroup.__init__(self, *videos, **kwargs) self.arrange_submobjects() self.set_width(FRAME_WIDTH - MED_LARGE_BUFF) self.set_color_by_gradient(*self.gradient_colors)
def setup(self): self.default_graph_colors_cycle = it.cycle(self.default_graph_colors) self.left_T_label = VGroup() self.left_v_line = VGroup() self.right_T_label = VGroup() self.right_v_line = VGroup()
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 __init__(self, mobject, **kwargs): VGroup.__init__( self, Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT), ) self.replace(mobject, stretch=True) self.set_stroke(self.stroke_color, self.stroke_width)
def __init__(self, **kwargs): possible_values = list(map(str, list(range(1, 11)))) + ["J", "Q", "K"] possible_suits = ["hearts", "diamonds", "spades", "clubs"] VGroup.__init__( self, *[ PlayingCard(value=value, suit=suit, **kwargs) for value in possible_values for suit in possible_suits ])
def __init__(self, values, **kwargs): VGroup.__init__(self, **kwargs) if self.max_value is None: self.max_value = max(values) self.add_axes() self.add_bars(values) self.center()
def arrange_subparts(self, *subparts): for i, piece in enumerate(subparts): piece.rotate(i * np.pi / 12, about_point=ORIGIN) p1, p2, p3, p4, p5, p6, p7 = subparts center_row = VGroup(p1, p4, p7) center_row.arrange_submobjects(RIGHT, buff=0) for p in p2, p3, p5, p6: p.set_width(p1.get_width()) p2.move_to(p1.get_top(), DOWN + LEFT) p3.move_to(p1.get_bottom(), UP + LEFT) p5.move_to(p4.get_top(), DOWN + LEFT) p6.move_to(p4.get_bottom(), UP + LEFT)
def name_parts(self): self.mouth = self.submobjects[MOUTH_INDEX] self.body = self.submobjects[BODY_INDEX] self.pupils = VGroup(*[ self.submobjects[LEFT_PUPIL_INDEX], self.submobjects[RIGHT_PUPIL_INDEX] ]) self.eyes = VGroup(*[ self.submobjects[LEFT_EYE_INDEX], self.submobjects[RIGHT_EYE_INDEX] ]) self.eye_parts = VGroup(self.eyes, self.pupils) self.parts_named = True
def __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.set_height(self.height) if self.pi_creature is not None: self.next_to(self.pi_creature.eyes, UP, buff=0) self.frills = VGroup(*self[:self.NUM_FRILLS]) self.cone = self[self.NUM_FRILLS] self.dots = VGroup(*self[self.NUM_FRILLS + 1:]) self.frills.set_color_by_gradient(*self.frills_colors) self.cone.set_color(self.cone_color) self.dots.set_color_by_gradient(*self.dots_colors)
def get_student_changes(self, *modes, **kwargs): pairs = list(zip(self.get_students(), modes)) pairs = [(s, m) for s, m in pairs if m is not None] start = VGroup(*[s for s, m in pairs]) target = VGroup(*[s.copy().change_mode(m) for s, m in pairs]) if "look_at_arg" in kwargs: for pi in target: pi.look_at(kwargs["look_at_arg"]) submobject_mode = kwargs.get("submobject_mode", "lagged_start") return Transform( start, target, submobject_mode=submobject_mode, run_time=2 )
def add_axes(self): x_axis = Line(self.tick_width * LEFT / 2, self.width * RIGHT) y_axis = Line(MED_LARGE_BUFF * DOWN, self.height * UP) ticks = VGroup() heights = np.linspace(0, self.height, self.n_ticks + 1) values = np.linspace(0, self.max_value, self.n_ticks + 1) for y, value in zip(heights, values): tick = Line(LEFT, RIGHT) tick.set_width(self.tick_width) tick.move_to(y * UP) ticks.add(tick) y_axis.add(ticks) self.add(x_axis, y_axis) self.x_axis, self.y_axis = x_axis, y_axis if self.label_y_axis: labels = VGroup() for tick, value in zip(ticks, values): label = TexMobject(str(np.round(value, 2))) label.set_height(self.y_axis_label_height) label.next_to(tick, LEFT, SMALL_BUFF) labels.add(label) self.y_axis_labels = labels self.add(labels)
def get_dot_template(self, place): # This should be replaced for non-base-10 counting scenes dots = VGroup(*[ Dot( point, radius=0.25, fill_opacity=0, stroke_width=2, stroke_color=WHITE, ) for point in self.get_template_configuration(place) ]) dots.set_height(self.dot_configuration_height) return dots
def get_number_mob(self, num): result = VGroup() place = 0 max_place = self.max_place while place < max_place: digit = TexMobject(str(self.get_place_num(num, place))) if place >= len(self.digit_place_colors): self.digit_place_colors += self.digit_place_colors digit.set_color(self.digit_place_colors[place]) digit.scale(self.num_scale_factor) digit.next_to(result, LEFT, buff=SMALL_BUFF, aligned_edge=DOWN) result.add(digit) place += 1 return result
def get_riemann_rectangles(self, graph, x_min=None, x_max=None, dx=0.1, input_sample_type="left", stroke_width=1, stroke_color=BLACK, fill_opacity=1, start_color=None, end_color=None, show_signed_area=True, width_scale_factor=1.001): x_min = x_min if x_min is not None else self.x_min x_max = x_max if x_max is not None else self.x_max if start_color is None: start_color = self.default_riemann_start_color if end_color is None: end_color = self.default_riemann_end_color rectangles = VGroup() x_range = np.arange(x_min, x_max, dx) colors = color_gradient([start_color, end_color], len(x_range)) for x, color in zip(x_range, colors): if input_sample_type == "left": sample_input = x elif input_sample_type == "right": sample_input = x + dx elif input_sample_type == "center": sample_input = x + 0.5 * dx else: raise Exception("Invalid input sample type") graph_point = self.input_to_graph_point(sample_input, graph) points = VGroup(*list( map(VectorizedPoint, [ self.coords_to_point(x, 0), self.coords_to_point(x + width_scale_factor * dx, 0), graph_point ]))) rect = Rectangle() rect.replace(points, stretch=True) if graph_point[1] < self.graph_origin[1] and show_signed_area: fill_color = invert_color(color) else: fill_color = color rect.set_fill(fill_color, opacity=fill_opacity) rect.set_stroke(stroke_color, width=stroke_width) rectangles.add(rect) return rectangles
def get_division_along_dimension(self, p_list, dim, colors, vect): p_list = self.complete_p_list(p_list) colors = color_gradient(colors, len(p_list)) last_point = self.get_edge_center(-vect) parts = VGroup() for factor, color in zip(p_list, colors): part = SampleSpace() part.set_fill(color, 1) part.replace(self, stretch=True) part.stretch(factor, dim) part.move_to(last_point, -vect) last_point = part.get_edge_center(vect) parts.add(part) return parts
def __init__(self, **kwargs): circle = Circle() ticks = [] for x in range(12): alpha = x / 12. point = complex_to_R3(np.exp(2 * np.pi * alpha * complex(0, 1))) length = 0.2 if x % 3 == 0 else 0.1 ticks.append(Line(point, (1 - length) * point)) self.hour_hand = Line(ORIGIN, 0.3 * UP) self.minute_hand = Line(ORIGIN, 0.6 * UP) # for hand in self.hour_hand, self.minute_hand: # #Balance out where the center is # hand.add(VectorizedPoint(-hand.get_end())) VGroup.__init__(self, circle, self.hour_hand, self.minute_hand, *ticks)
def setup(self): self.dots = VGroup() self.number = 0 self.max_place = 0 self.number_mob = VGroup(TexMobject(str(self.number))) self.number_mob.scale(self.num_scale_factor) self.number_mob.shift(self.num_start_location) self.dot_templates = [] self.dot_template_iterators = [] self.curr_configurations = [] self.arrows = VGroup() self.add(self.number_mob)
def get_axis_labels(self, x_label="x", y_label="y"): x_axis, y_axis = self.get_axes().split() quads = [ (x_axis, x_label, UP, RIGHT), (y_axis, y_label, RIGHT, UP), ] labels = VGroup() for axis, tex, vect, edge in quads: label = TexMobject(tex) label.add_background_rectangle() label.next_to(axis, vect) label.to_edge(edge) labels.add(label) self.axis_labels = labels return labels
def create_pi_creatures(self): self.teacher = Mortimer(color=self.teacher_color) self.teacher.to_corner(DOWN + RIGHT) self.teacher.look(DOWN + LEFT) self.students = VGroup(*[ Randolph(color=c) for c in self.student_colors ]) self.students.arrange_submobjects(RIGHT) self.students.scale(self.student_scale_factor) self.students.to_corner(DOWN + LEFT) self.teacher.look_at(self.students[-1].eyes) for student in self.students: student.look_at(self.teacher.eyes) return [self.teacher] + list(self.students)
def increment(self, run_time_per_anim=1): moving_dot = Dot( self.counting_dot_starting_position, radius=self.count_dot_starting_radius, color=self.digit_place_colors[0], ) moving_dot.generate_target() moving_dot.set_fill(opacity=0) kwargs = { "run_time": run_time_per_anim } continue_rolling_over = True first_move = True place = 0 while continue_rolling_over: added_anims = [] if first_move: added_anims += self.get_digit_increment_animations() first_move = False moving_dot.target.replace( next(self.dot_template_iterators[place]) ) self.play(MoveToTarget(moving_dot), *added_anims, **kwargs) self.curr_configurations[place].add(moving_dot) if len(self.curr_configurations[place].split()) == self.get_place_max(place): full_configuration = self.curr_configurations[place] self.curr_configurations[place] = VGroup() place += 1 center = full_configuration.get_center_of_mass() radius = 0.6 * max( full_configuration.get_width(), full_configuration.get_height(), ) circle = Circle( radius=radius, stroke_width=0, fill_color=self.digit_place_colors[place], fill_opacity=0.5, ) circle.move_to(center) moving_dot = VGroup(circle, full_configuration) moving_dot.generate_target() moving_dot[0].set_fill(opacity=0) else: continue_rolling_over = False
def get_animation_integral_bounds_change(self, graph, new_t_min, new_t_max, fade_close_to_origin=True, run_time=1.0): curr_t_min = self.x_axis.point_to_number(self.area.get_left()) curr_t_max = self.x_axis.point_to_number(self.area.get_right()) if new_t_min is None: new_t_min = curr_t_min if new_t_max is None: new_t_max = curr_t_max group = VGroup(self.area) group.add(self.left_v_line) group.add(self.left_T_label_group) group.add(self.right_v_line) group.add(self.right_T_label_group) def update_group(group, alpha): area, left_v_line, left_T_label, right_v_line, right_T_label = group t_min = interpolate(curr_t_min, new_t_min, alpha) t_max = interpolate(curr_t_max, new_t_max, alpha) new_area = self.get_area(graph, t_min, t_max) new_left_v_line = self.get_vertical_line_to_graph(t_min, graph) new_left_v_line.set_color(left_v_line.get_color()) left_T_label.move_to(new_left_v_line.get_bottom(), UP) new_right_v_line = self.get_vertical_line_to_graph(t_max, graph) new_right_v_line.set_color(right_v_line.get_color()) right_T_label.move_to(new_right_v_line.get_bottom(), UP) # Fade close to 0 if fade_close_to_origin: if len(left_T_label) > 0: left_T_label[0].set_fill(opacity=min(1, np.abs(t_min))) if len(right_T_label) > 0: right_T_label[0].set_fill(opacity=min(1, np.abs(t_max))) Transform(area, new_area).update(1) Transform(left_v_line, new_left_v_line).update(1) Transform(right_v_line, new_right_v_line).update(1) return group return UpdateFromAlphaFunc(group, update_group, run_time=run_time)
def animate_product(self, left, right, result): l_matrix = left.get_mob_matrix() r_matrix = right.get_mob_matrix() result_matrix = result.get_mob_matrix() circle = Circle(radius=l_matrix[0][0].get_height(), color=GREEN) circles = VGroup(*[ entry.get_point_mobject() for entry in (l_matrix[0][0], r_matrix[0][0]) ]) (m, k), n = l_matrix.shape, r_matrix.shape[1] for mob in result_matrix.flatten(): mob.set_color(BLACK) lagging_anims = [] for a in range(m): for b in range(n): for c in range(k): l_matrix[a][c].set_color(YELLOW) r_matrix[c][b].set_color(YELLOW) for c in range(k): start_parts = VGroup(l_matrix[a][c].copy(), r_matrix[c][b].copy()) result_entry = result_matrix[a][b].split()[c] new_circles = VGroup(*[ circle.copy().shift(part.get_center()) for part in start_parts.split() ]) self.play(Transform(circles, new_circles)) self.play( Transform( start_parts, result_entry.copy().set_color(YELLOW), path_arc=-np.pi / 2, submobject_mode="all_at_once", ), *lagging_anims) result_entry.set_color(YELLOW) self.remove(start_parts) lagging_anims = [ ApplyMethod(result_entry.set_color, WHITE) ] for c in range(k): l_matrix[a][c].set_color(WHITE) r_matrix[c][b].set_color(WHITE) self.play(FadeOut(circles), *lagging_anims) self.wait()
def get_corner_numbers(self, value, symbol): value_mob = TextMobject(value) width = self.get_width() / self.card_width_to_corner_num_width height = self.get_height() / self.card_height_to_corner_num_height value_mob.set_width(width) value_mob.stretch_to_fit_height(height) value_mob.next_to(self.get_corner(UP + LEFT), DOWN + RIGHT, buff=MED_LARGE_BUFF * width) value_mob.set_color(symbol.get_color()) corner_symbol = symbol.copy() corner_symbol.set_width(width) corner_symbol.next_to(value_mob, DOWN, buff=MED_SMALL_BUFF * width) corner_group = VGroup(value_mob, corner_symbol) opposite_corner_group = corner_group.copy() opposite_corner_group.rotate(np.pi, about_point=self.get_center()) return VGroup(corner_group, opposite_corner_group)
def add_3d_pieces(self): for attr in "x_axis", "y_axis", "z_axis": axis = getattr(self, attr) axis.add(VGroup(*axis.main_line.get_pieces(self.num_axis_pieces))) axis.main_line.set_stroke(width=0, family=False) axis_3d = ThreeDVMobject(axis) self.remove(axis) self.add(axis_3d) setattr(self, attr, axis_3d)
def get_basis_vector_labels(self, **kwargs): i_hat, j_hat = self.get_basis_vectors() return VGroup(*[ self.get_vector_label( vect, label, color=color, label_scale_factor=1, **kwargs) for vect, label, color in [ (i_hat, "\\hat{\\imath}", X_COLOR), (j_hat, "\\hat{\\jmath}", Y_COLOR), ] ])