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.scale_to_fit_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_coordinate_labels(self, *numbers): # TODO: Should merge this with the code from NumberPlane.get_coordinate_labels result = VGroup() if len(numbers) == 0: numbers = 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.scale_to_fit_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 __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, **kwargs): digest_config(self, kwargs) videos = [VideoIcon() for x in range(self.num_videos)] VGroup.__init__(self, *videos, **kwargs) self.arrange_submobjects() self.scale_to_fit_width(FRAME_WIDTH - MED_LARGE_BUFF) self.set_color_by_gradient(*self.gradient_colors)
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, 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 __init__(self, **kwargs): possible_values = map(str, 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 ])
class DoubleArrow(Arrow): def init_tip(self): self.tip = VGroup() for b in True, False: t = self.add_tip(add_at_end=b) t.add_at_end = b self.tip.add(t) self.tip.match_style(self.tip[0])
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 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.scale_to_fit_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 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 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 build_the_equation(self): l_part = self.tower.copy() r_part = TexMobject("=", "2") r_part.match_height(l_part.get_base()) equation = VGroup(l_part, r_part) equation.arrange_submobjects(RIGHT, aligned_edge = DOWN) self.play( ReplacementTransform(self.tower, l_part, run_time = 1), Write(r_part, run_time = 2), ) self.equation = equation
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 __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.scale_to_fit_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_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.scale_to_fit_height(self.dot_configuration_height) return dots
def __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.scale_to_fit_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 = 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 generate_points(self): body = Cube(side_length=1) for dim, scale_factor in enumerate(self.body_dimensions): body.stretch(scale_factor, dim=dim) body.scale_to_fit_width(self.width) body.set_fill(self.shaded_body_color, opacity=1) body.sort_submobjects(lambda p: p[2]) body[-1].set_fill(self.body_color) screen_plate = body.copy() keyboard = VGroup(*[ VGroup(*[ Square(**self.key_color_kwargs) for x in range(12 - y % 2) ]).arrange_submobjects(RIGHT, buff=SMALL_BUFF) for y in range(4) ]).arrange_submobjects(DOWN, buff=MED_SMALL_BUFF) keyboard.stretch_to_fit_width( self.keyboard_width_to_body_width * body.get_width(), ) keyboard.stretch_to_fit_height( self.keyboard_height_to_body_height * body.get_height(), ) keyboard.next_to(body, OUT, buff=0.1 * SMALL_BUFF) keyboard.shift(MED_SMALL_BUFF * UP) body.add(keyboard) screen_plate.stretch(self.screen_thickness / self.body_dimensions[2], dim=2) screen = Rectangle( stroke_width=0, fill_color=BLACK, fill_opacity=1, ) screen.replace(screen_plate, stretch=True) screen.scale_in_place(self.screen_width_to_screen_plate_width) screen.next_to(screen_plate, OUT, buff=0.1 * SMALL_BUFF) screen_plate.add(screen) screen_plate.next_to(body, UP, buff=0) screen_plate.rotate( self.open_angle, RIGHT, about_point=screen_plate.get_bottom() ) self.screen_plate = screen_plate self.screen = screen axis = Line( body.get_corner(UP + LEFT + OUT), body.get_corner(UP + RIGHT + OUT), color=BLACK, stroke_width=2 ) self.axis = axis self.add(body, screen_plate, axis) self.rotate(5 * np.pi / 12, LEFT, about_point=ORIGIN) self.rotate(np.pi / 6, DOWN, about_point=ORIGIN)
def create_pi_creatures(self): self.teacher = Mortimer(color=self.default_pi_creature_kwargs["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 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 setup_in_uv_space(self): u_min = self.u_min u_max = self.u_max u_res = self.u_resolution or self.resolution v_min = self.v_min v_max = self.v_max v_res = self.v_resolution or self.resolution u_values = np.linspace(u_min, u_max, u_res + 1) v_values = np.linspace(v_min, v_max, v_res + 1) faces = VGroup() for u1, u2 in zip(u_values[:-1], u_values[1:]): for v1, v2 in zip(v_values[:-1], v_values[1:]): piece = ThreeDVMobject() piece.set_points_as_corners([ [u1, v1, 0], [u2, v1, 0], [u2, v2, 0], [u1, v2, 0], [u1, v1, 0], ]) faces.add(piece) faces.set_fill(color=self.fill_color, opacity=self.fill_opacity) faces.set_stroke( color=self.stroke_color, width=self.stroke_width, opacity=self.stroke_opacity, ) self.add(*faces) if self.checkerboard_colors: self.set_fill_by_checkerboard(*self.checkerboard_colors)
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 construct(self): morty = Mortimer() morty.next_to(ORIGIN, DOWN) patreon_logo = PatreonLogo() patreon_logo.to_edge(UP) n_patrons = len(self.specific_patrons) patrons = map(TextMobject, self.specific_patrons) num_groups = float(len(patrons)) / self.max_patron_group_size proportion_range = np.linspace(0, 1, num_groups + 1) indices = (len(patrons) * proportion_range).astype('int') patron_groups = [ VGroup(*patrons[i:j]) for i, j in zip(indices, indices[1:]) ] for i, group in enumerate(patron_groups): left_group = VGroup(*group[:len(group) / 2]) right_group = VGroup(*group[len(group) / 2:]) for subgroup, vect in (left_group, LEFT), (right_group, RIGHT): subgroup.arrange_submobjects(DOWN, aligned_edge=LEFT) subgroup.scale(self.patron_scale_val) subgroup.to_edge(vect) last_group = None for i, group in enumerate(patron_groups): anims = [] if last_group is not None: self.play( FadeOut(last_group), morty.look, UP + LEFT ) else: anims += [ DrawBorderThenFill(patreon_logo), ] self.play( LaggedStart( FadeIn, group, run_time=2, ), morty.change, "gracious", group.get_corner(UP + LEFT), *anims ) self.play(morty.look_at, group.get_corner(DOWN + LEFT)) self.play(morty.look_at, group.get_corner(UP + RIGHT)) self.play(morty.look_at, group.get_corner(DOWN + RIGHT)) self.play(Blink(morty)) last_group = group
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.scale_to_fit_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.scale_to_fit_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 generate_points(self): self.line_group = VGroup() self.dot_group = VGroup() vertices = self.generate_vertices_from_string(self.walk_string) for k in range(len(vertices) - 1): line = Line(vertices[k], vertices[k + 1], color=self.get_mob_color_by_number(k)) dot = Dot(vertices[k], color=self.dot_color) self.line_group.add(line) self.dot_group.add(dot) self.dot_group.add(Dot(vertices[-1], color=self.dot_color)) self.add(self.line_group, self.dot_group) self.horizontally_center()
def __init__(self, **kwargs): VGroup.__init__(self, **kwargs) self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config) self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config) self.y_axis.rotate(np.pi / 2, about_point=ORIGIN) self.add(self.x_axis, self.y_axis) if self.three_d: self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config) self.z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN) self.z_axis.rotate(angle_of_vector(self.z_normal), OUT, about_point=ORIGIN) self.add(self.z_axis)
def generate_tower_tex_from_texts(self, texts): tower_tex = VGroup(*[ TexMobject(text) for text in self.tower_texts ]) if self.is_infinite: tower_tex.add(ExpDots(**self.expdots_config)) for k, part in enumerate(tower_tex): part.scale(self.scale_factor**k) if k > 0: buff = 0.05 / np.sqrt(k) part.stretch(self.height_stretch_factor, 1) part.next_to(tower_tex[k-1], RIGHT+UP, buff = buff) return tower_tex
def split_by_regex(self, eq, regex): match = re.match(regex, eq.tex_string) if not match: print("{} does not match {}".format(regex, eq.tex_string)) breakpoint(context=7) assert (False) if match.group(0) != eq.tex_string: breakpoint(context=7) assert (False) regex_index = 0 mob_index = 0 group_index = 1 # 0 is the entire string group = VGroup() mobs = [] while True: if mob_index == len(eq.submobjects[0].submobjects): if mobs: group.submobjects.append(VGroup(*mobs)) break # open parentheses, some characters that aren't close parentheses, # then a close parentheses group_match = re.match("\(.*?(?<!\\\\)\)", regex[regex_index:]) if group_match: # handle group if mobs: group.submobjects.append(VGroup(*mobs)) mobs = [] submobs = [] group_regex_index = 0 while group_regex_index < len(match.group(group_index)): num_mobs, num_chars = self.append_mob( eq, submobs, match.group(group_index), group_regex_index, mob_index, subgroup=True) mob_index += num_mobs group_regex_index += num_chars regex_index += len(group_match.group(0)) group_index += 1 group.submobjects.append(VGroup(*submobs)) else: # add mob to list num_mobs, num_chars = self.append_mob(eq, mobs, regex, regex_index, mob_index) mob_index += num_mobs regex_index += num_chars return group
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 __init__(self, **kwargs): VGroup.__init__(self, **kwargs) self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config) self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config) self.y_axis.rotate(np.pi / 2, about_point=ORIGIN) self.add(self.x_axis, self.y_axis) if self.three_d: self.z_axis = self.get_axis( self.z_min, self.z_max, self.z_axis_config) self.z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN) self.z_axis.rotate( angle_of_vector(self.z_normal), OUT, about_point=ORIGIN ) self.add(self.z_axis)
def get_order_n_self(self, order): if order == 0: result = self.get_seed_shape() else: lower_order = self.get_order_n_self(order - 1) subparts = [ lower_order.copy() for x in range(self.num_subparts) ] self.arrange_subparts(*subparts) result = VGroup(*subparts) result.scale_to_fit_height(self.height) result.center() return result
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 get_number_mobjects(self, *numbers, **kwargs): # TODO, handle decimals if len(numbers) == 0: numbers = self.default_numbers_to_display() result = VGroup() for number in numbers: mob = DecimalNumber(number, **self.decimal_number_config) mob.scale(self.number_scale_val) mob.next_to( self.number_to_point(number), self.label_direction, self.line_to_number_buff, ) result.add(mob) return result
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 construct(self): exp_tower = ExpTower(element = "x", order = 10) exp_tower.set_height(6) exp_tower.gradient_highlight(YELLOW, BLUE) two, equal_sign, four = equation = TexMobject("2", "=", "4") two.set_color(GREEN) four.set_color(RED) equation.scale(10) question_mark = TexMobject("?") question_mark.set_height(2) question_mark.next_to(equal_sign, UP, buff = 0.5) notations = VGroup(*[ TexMobject("{}^{\\infty} x"), TexMobject("x \\uparrow \\uparrow \\infty"), ]) for notation, num, direction, angle, color in \ zip(notations, [two, four], [UP+RIGHT, DOWN+LEFT], [-TAU/15, TAU/24], [YELLOW, BLUE]): notation.scale(3) notation.rotate(angle) notation.next_to(num, direction) notation.set_color(color) self.add(exp_tower, notations) self.add(FullScreenFadeRectangle()) self.add(equation, question_mark)
def __init__(self, focal_point, **kwargs): digest_config(self, kwargs) circles = VGroup() for x in range(self.n_circles): circle = Circle( radius=self.big_radius, stroke_color=BLACK, stroke_width=0, ) circle.move_to(focal_point) circle.save_state() circle.set_width(self.small_radius * 2) circle.set_stroke(self.color, self.start_stroke_width) circles.add(circle) LaggedStart.__init__(self, ApplyMethod, circles, lambda c: (c.restore, ), **kwargs)
def get_transformer(self, **kwargs): transform_kwargs = dict(self.default_apply_complex_function_kwargs) transform_kwargs.update(kwargs) plane = self.plane self.prepare_for_transformation(plane) transformer = VGroup(plane, *self.transformable_mobjects) return transformer, transform_kwargs
def add_3d_pieces(self): for axis in self: axis.pieces = VGroup( *axis.main_line.get_pieces(self.num_axis_pieces)) axis.add(axis.pieces) axis.main_line.set_stroke(width=0, family=False) axis.set_shade_in_3d(True)
def get_mobjects_from(self, element): result = [] if not isinstance(element, minidom.Element): return result if element.tagName == 'defs': self.update_ref_to_element(element) elif element.tagName == 'style': pass # TODO, handle style elif element.tagName in ['g', 'svg']: result += it.chain(*[ self.get_mobjects_from(child) for child in element.childNodes ]) elif element.tagName == 'path': result.append( self.path_string_to_mobject(element.getAttribute('d'))) elif element.tagName == 'use': result += self.use_to_mobjects(element) elif element.tagName == 'rect': result.append(self.rect_to_mobject(element)) elif element.tagName == 'circle': result.append(self.circle_to_mobject(element)) elif element.tagName == 'ellipse': result.append(self.ellipse_to_mobject(element)) elif element.tagName in ['polygon', 'polyline']: result.append(self.polygon_to_mobject(element)) else: pass # TODO # warnings.warn("Unknown element type: " + element.tagName) result = [m for m in result if m is not None] self.handle_transforms(element, VMobject(*result)) if len(result) > 1 and not self.unpack_groups: result = [VGroup(*result)] return result
def choose_two_special_numbers(self): two_and_four_text = TextMobject("现在选择两个特殊的数...") two_and_four_text.set_color(YELLOW) two_and_four_text.to_edge(UP) self.play(Transform(self.anything_text, two_and_four_text)) self.wait() two_equation = self.equation four_equation = two_equation.copy() self.play(four_equation.to_edge, RIGHT, self.tower_edge_buff) self.wait() nums = [2, 4] colors = [GREEN, RED] equations = [two_equation, four_equation] targets = [equation[1][1] for equation in equations] two, four = num_texs = [ TexMobject(str(num)).set_color(color).match_height(target).move_to(target) for num, color, equation, target in zip(nums, colors, equations, targets) ] for N_tex, num_tex in zip(targets, num_texs): self.play(Transform(N_tex, num_tex)) self.wait(0.5) self.wait(0.5) self.nums = nums self.colors = colors self.equations = equations self.x_towers = VGroup(*[equation[0] for equation in equations])
def construct(self): # Setup line = NumberLine() house = House() drunk = Drunk(direction=RIGHT) house.place_on(ORIGIN) drunk.step_on(ORIGIN) t_equals = TexMobject("t = ") time = TexMobject("0") time.next_to(t_equals, RIGHT, buff=0.15) VGroup(t_equals, time).next_to(line, DOWN, buff=0.5) old_drunk = drunk.copy() old_time = time.copy() self.add(house, line, drunk, t_equals) # Start wandering for k in range(20): new_time = TexMobject("%s" % str(k + 1)) new_time.next_to(t_equals, RIGHT, buff=0.15) self.play( DrunkWander(drunk, random.choice([-1, 1]), total_time=0.5), Transform(time, new_time, rate_func=snap_head_and_tail(smooth), run_time=0.5), ) self.wait() # Reset self.play(Transform(time, old_time), Transform(drunk, old_drunk)) self.wait()
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( self.dot_template_iterators[place].next() ) 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_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 __init__(self, focal_point, **kwargs): digest_config(self, kwargs) circles = VGroup() for x in range(self.n_circles): circle = Circle( radius=self.big_radius, stroke_color=BLACK, stroke_width=0, ) circle.move_to(focal_point) circle.save_state() circle.scale_to_fit_width(self.small_radius * 2) circle.set_stroke(self.color, self.start_stroke_width) circles.add(circle) LaggedStart.__init__( self, ApplyMethod, circles, lambda c: (c.restore,), **kwargs )
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, x_vals=None, y_vals=None): coordinate_labels = VGroup() if x_vals is None: x_vals = range(-int(self.x_radius), int(self.x_radius) + 1) if y_vals is None: y_vals = range(-int(self.y_radius), int(self.y_radius) + 1) for index, vals in enumerate([x_vals, y_vals]): num_pair = [0, 0] for val in vals: if val == 0: continue num_pair[index] = val point = self.coords_to_point(*num_pair) num = TexMobject(str(val)) num.add_background_rectangle() num.scale_to_fit_height( self.written_coordinate_height ) num.next_to(point, DOWN + LEFT, buff=SMALL_BUFF) coordinate_labels.add(num) self.coordinate_labels = coordinate_labels return coordinate_labels
def get_number_design(self, value, symbol): num = int(value) n_rows = { 2: 2, 3: 3, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, 9: 4, 10: 4, }[num] n_cols = 1 if num in [2, 3] else 2 insertion_indices = { 5: [0], 7: [0], 8: [0, 1], 9: [1], 10: [0, 2], }.get(num, []) top = self.get_top() + symbol.get_height() * DOWN bottom = self.get_bottom() + symbol.get_height() * UP column_points = [ interpolate(top, bottom, alpha) for alpha in np.linspace(0, 1, n_rows) ] design = VGroup(*[ symbol.copy().move_to(point) for point in column_points ]) if n_cols == 2: space = 0.2 * self.get_width() column_copy = design.copy().shift(space * RIGHT) design.shift(space * LEFT) design.add(*column_copy) design.add(*[ symbol.copy().move_to( center_of_mass(column_points[i:i + 2]) ) for i in insertion_indices ]) for symbol in design: if symbol.get_center()[1] < self.get_center()[1]: symbol.rotate_in_place(np.pi) return design
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 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.scale_to_fit_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.scale_to_fit_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 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 add_tip(self, add_at_end=True): tip = VMobject( close_new_points=True, mark_paths_closed=True, fill_color=self.color, fill_opacity=1, stroke_color=self.color, stroke_width=0, ) tip.add_at_end = add_at_end self.set_tip_points(tip, add_at_end, preserve_normal=False) self.add(tip) if not hasattr(self, 'tip'): self.tip = VGroup() self.tip.match_style(tip) self.tip.add(tip) return tip