def __init__(self, file_name=None, **kwargs): Container.__init__(self, **kwargs) self.file_name = file_name or self.file_name self.ensure_valid_file() self.style = self.style.lower() self.gen_html_string() strati = self.html_string.find("background:") self.background_color = self.html_string[strati + 12:strati + 19] self.gen_code_json() self.code = self.gen_colored_lines() if self.insert_line_no: self.line_numbers = self.gen_line_numbers() self.line_numbers.next_to(self.code, direction=LEFT, buff=self.line_no_buff) if self.background == "rectangle": if self.insert_line_no: forground = VGroup(self.code, self.line_numbers) else: forground = self.code self.background_mobject = SurroundingRectangle(forground, buff=self.margin, color=self.background_color, fill_color=self.background_color, stroke_width=0, fill_opacity=1, ) self.background_mobject.round_corners(self.corner_radius) else: if self.insert_line_no: forground = VGroup(self.code, self.line_numbers) else: forground = self.code height = forground.get_height() + 0.1 * 3 + 2 * self.margin width = forground.get_width() + 0.1 * 3 + 2 * self.margin rrect = RoundedRectangle(corner_radius=self.corner_radius, height=height, width=width, stroke_width=0, color=self.background_color, fill_opacity=1) button_radius = 0.09 red_button = Dot(radius=button_radius, stroke_width=0, color='#ff5f56') red_button.shift(LEFT * button_radius * 3) yellow_button = Dot(radius=button_radius, stroke_width=0, color='#ffbd2e') green_button = Dot(radius=button_radius, stroke_width=0, color='#27c93f') green_button.shift(RIGHT * button_radius * 3) buttons = VGroup(red_button, yellow_button, green_button) buttons.shift( UP * (height / 2 - 0.1 * 2 - 0.05) + LEFT * (width / 2 - 0.1 * 5 - self.corner_radius / 2 - 0.05)) self.background_mobject = VGroup(rrect, buttons) x = (height - forground.get_height()) / 2 - 0.1 * 3 self.background_mobject.shift(forground.get_center()) self.background_mobject.shift(UP * x) if self.insert_line_no: VGroup.__init__(self, self.background_mobject, self.line_numbers, *self.code, **kwargs) else: VGroup.__init__(self, self.background_mobject, Dot(fill_opacity=0, stroke_opacity=0), *self.code, **kwargs) self.move_to(np.array([0, 0, 0]))
def apply_space_chars(self): char_index = 0 while char_index < self.text.__len__() - 1: char_index += 1 if self.text[char_index] == " " or self.text[char_index] == "\t" or self.text[char_index] == "\n": space = Dot(fill_opacity=0, stroke_opacity=0) space.move_to(self.submobjects[char_index - 1].get_center()) self.submobjects.insert(char_index, space)
def apply_space_chars(self): submobs = self.submobjects.copy() for char_index in range(len(self.text)): if self.text[char_index] in [" ", "\t", "\n"]: space = Dot(radius=0, fill_opacity=0, stroke_opacity=0) space.move_to(submobs[max(char_index - 1, 0)].get_center()) submobs.insert(char_index, space) self.set_submobjects(submobs)
def __init__(self, init_loc=ORIGIN, **kwargs): VGroup.__init__(self, **kwargs) self.point = Dot(init_loc, color=self.point_color).set_height(self.size) self.value_x = DecimalNumber(0, color=self.coordinates_color, num_decimal_places=self.num_decimal_places).scale(self.coordinates_scale) self.value_y = DecimalNumber(0, color=self.coordinates_color, num_decimal_places=self.num_decimal_places).scale(self.coordinates_scale) text = TexMobject('(', ',', ')').scale(self.coordinates_scale) self.coordinates_text = VGroup(text[0], self.value_x, text[1], self.value_y, text[2]) self.coordinates_text.add_updater(self.update_coordinates_text) self.add(self.point)
def add_bases(self): self.base_top = Dot( point=self.u_max * IN, radius=self.radius, color=self.fill_color, fill_opacity=self.fill_opacity, ) self.base_bottom = Dot( point=self.u_min * IN, radius=self.radius, color=self.fill_color, fill_opacity=self.fill_opacity, ) self.add(self.base_top, self.base_bottom)
def create_starting_mobject(self): return Dot( radius=FRAME_X_RADIUS + FRAME_Y_RADIUS, stroke_width=0, fill_color=self.color, fill_opacity=0, )
class Tracked_Point(VGroup): CONFIG = { 'size': 0.1, 'point_color': BLUE, 'num_decimal_places': 2, 'coordinates_scale': 0.8, 'coordinates_color': GREEN, 'coordinates_direction': DOWN * 0.25, 'bracket_color': WHITE, } def __init__(self, init_loc=ORIGIN, **kwargs): VGroup.__init__(self, **kwargs) self.point = Dot(init_loc, color=self.point_color).set_height(self.size) self.value_x = DecimalNumber(0, color=self.coordinates_color, num_decimal_places=self.num_decimal_places).scale(self.coordinates_scale) self.value_y = DecimalNumber(0, color=self.coordinates_color, num_decimal_places=self.num_decimal_places).scale(self.coordinates_scale) text = TexMobject('(', ',', ')').scale(self.coordinates_scale) self.coordinates_text = VGroup(text[0], self.value_x, text[1], self.value_y, text[2]) self.coordinates_text.add_updater(self.update_coordinates_text) self.add(self.point) def update_coordinates_text(self, coords): for i in range(1, len(coords)): coords[i].next_to(coords[i-1], RIGHT * 0.5) coords[2].align_to(coords[1], DOWN) pos = self.point.get_center() x, y = self.mapping_func(pos[0], pos[1]) coords[1].set_value(x) coords[3].set_value(y) coords.next_to(self.point, self.coordinates_direction) def mapping_func(self, x, y): return x, y
def show_ghost_movement(self, vector): """ This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to convey the idea of mentally moving the entire plane in a direction, without actually moving the plane. Parameters ---------- vector (Union[Arrow, list, tuple, np.ndarray]) The vector which indicates the direction of movement. """ if isinstance(vector, Arrow): vector = vector.get_end() - vector.get_start() elif len(vector) == 2: vector = np.append(np.array(vector), 0.0) x_max = int(FRAME_X_RADIUS + abs(vector[0])) y_max = int(FRAME_Y_RADIUS + abs(vector[1])) dots = VMobject(*[ Dot(x * RIGHT + y * UP) for x in range(-x_max, x_max) for y in range(-y_max, y_max) ]) dots.set_fill(BLACK, opacity=0) dots_halfway = dots.copy().shift(vector / 2).set_fill(WHITE, 1) dots_end = dots.copy().shift(vector) self.play(Transform(dots, dots_halfway, rate_func=rush_into)) self.play(Transform(dots, dots_end, rate_func=rush_from)) self.remove(dots)
def apply_space_chars(self): indexes = self.find_indexes(' ') + self.find_indexes('\n') indexes = sorted(indexes, key=lambda i: i[0]) if len(self.text) == len(indexes): space = Dot(fill_opacity=0, stroke_opacity=0) self.submobjects = [space.copy() for _ in range(len(indexes))] return for start, _ in indexes: space = Dot(fill_opacity=0, stroke_opacity=0) if start == 0: space.move_to(self.submobjects[0].get_center()) else: space.move_to(self.submobjects[start - 1].get_center()) self.submobjects.insert(start, space)
def generate_mobject(self): super().generate_mobject() # Remove empty paths submobjects = list(filter(lambda submob: submob.has_points(), self)) # Apply space characters if self.apply_space_chars: content_str = self.parser.remove_tags(self.text) if self.is_markup: content_str = saxutils.unescape(content_str) for char_index, char in enumerate(content_str): if not re.match(r"\s", char): continue space = Dot(radius=0, fill_opacity=0, stroke_opacity=0) space.move_to(submobjects[max(char_index - 1, 0)].get_center()) submobjects.insert(char_index, space) self.set_submobjects(submobjects)
def construct(self): dot = Dot() text = TextMobject("Label") \ .next_to(dot, RIGHT, buff=SMALL_BUFF) self.add(dot, text) self.play(dot.shift, UP * 2) 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( 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 construct(self): obj = SVGMobject("dvsv").scale(3) points = VGroup(*[ Dot(obj.point_from_proportion(alpha)) for alpha in np.linspace(0, 1, 33) ]) self.add(obj) self.add(points) self.wait()
def __init__(self, *vertices, **kwargs): VGroup.__init__(self, **kwargs) self.lines, self.dots = VGroup(plot_depth=1), VGroup(plot_depth=1) self.poly=Polygon(*vertices, fill_color=self.fill_color, fill_opacity=self.fill_opacity, plot_depth=0).set_stroke(width=0) self.add(self.lines, self.dots, self.poly) n = len(vertices) for i in range(n): self.lines.add(Line(vertices[i], vertices[(i+1) % n], color=self.stroke_color, stroke_width=self.stroke_width, plot_depth=2)) self.dots.add(Dot(vertices[i], color=self.stroke_color, plot_depth=2).set_height(self.stroke_width/100))
def __init__(self, **kwargs): VGroup.__init__(self, **kwargs) self.color_list = color_gradient(self.colors, self.layer_num) self.add(Dot(color=average_color(self.colors[0], WHITE), plot_depth=4).set_height(0.015 * self.radius)) for i in range(self.layer_num): # self.add(Arc(radius= self.radius/self.layer_num * (0.5 + i), angle=TAU, color=self.color_list[i], # stroke_width=100 * self.radius/self.layer_num, # stroke_opacity=self.opacity_func(i/self.layer_num), plot_depth=5)) self.add(Arc(radius= self.radius * self.rate_func((0.5 + i)/self.layer_num), angle=TAU, color=self.color_list[i], stroke_width=101 * (self.rate_func((i + 1)/self.layer_num) - self.rate_func(i/self.layer_num)) * self.radius, stroke_opacity=self.opacity_func(self.rate_func(i/self.layer_num)), plot_depth=5))
def create_target(self): little_dot = Dot(radius=0) little_dot.set_fill(self.color, opacity=self.opacity) little_dot.add_updater( lambda d: d.move_to(self.focus_point) ) return little_dot
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 construct(self): dot = Dot() text = TextMobject("Label") \ .next_to(dot, RIGHT, buff=SMALL_BUFF) self.add(dot, text) def update_text(obj): obj.next_to(dot, RIGHT, buff=SMALL_BUFF) # Only works in play self.play(dot.shift, UP * 2, UpdateFromFunc(text, update_text)) self.wait()
def apply_space_chars(self): for char_index in range(self.text.__len__()): if self.text[char_index] == " " or self.text[char_index] == "\t" or self.text[char_index] == "\n": space = Dot(redius=0, fill_opacity=0, stroke_opacity=0) if char_index == 0: space.move_to(self.submobjects[char_index].get_center()) else: space.move_to(self.submobjects[char_index - 1].get_center()) self.submobjects.insert(char_index, space)
def __init__(self, mobject_or_point, **kwargs): digest_config(self, kwargs) big_dot = Dot( radius=FRAME_X_RADIUS + FRAME_Y_RADIUS, stroke_width=0, fill_color=self.color, fill_opacity=0, ) little_dot = Dot(radius=0) little_dot.set_fill(self.color, opacity=self.opacity) little_dot.move_to(mobject_or_point) Transform.__init__(self, big_dot, little_dot, **kwargs)
def __init__(self, **kwargs): ParametricSurface.__init__(self, self.func, **kwargs) # used for rotations self._current_theta = 0 self._current_phi = 0 if self.show_base: self.base_circle = Dot( point=self.height * IN, radius=self.base_radius, color=self.fill_color, fill_opacity=self.fill_opacity, ) self.add(self.base_circle) self._rotate_to_direction()
def show_ghost_movement(self, vector): if isinstance(vector, Arrow): vector = vector.get_end() - vector.get_start() elif len(vector) == 2: vector = np.append(np.array(vector), 0.0) x_max = int(FRAME_X_RADIUS + abs(vector[0])) y_max = int(FRAME_Y_RADIUS + abs(vector[1])) dots = VMobject(*[ Dot(x * RIGHT + y * UP) for x in range(-x_max, x_max) for y in range(-y_max, y_max) ]) dots.set_fill(BLACK, opacity=0) dots_halfway = dots.copy().shift(vector / 2).set_fill(WHITE, 1) dots_end = dots.copy().shift(vector) self.play(Transform(dots, dots_halfway, rate_func=rush_into)) self.play(Transform(dots, dots_end, rate_func=rush_from)) self.remove(dots)
def construct(self): dot = Dot() text = TextMobject("Label") \ .next_to(dot, RIGHT, buff=SMALL_BUFF) self.add(dot, text) # Add update function to the objects text.add_updater(lambda m: m.next_to(dot, RIGHT, buff=SMALL_BUFF)) # Add the object again self.add(text) self.play(dot.shift, UP * 2) # Remove update function text.clear_updaters() self.wait()
def scatter(self, x, y, size=None, color=None, fill_opacity=None, stroke_width=None, **kwargs): if color is None: color = it.cycle([next(self.default_graph_colors_cycle)]) else: if is_sequence(color): color = it.cycle(color) else: color = it.cycle([color]) if size is None: size = self.default_dot_radius if fill_opacity is None: fill_opacity = self.default_dot_opacity if stroke_width is None: stroke_width = self.default_dot_stroke_width scatter_sequence = VGroup() for i in range(len(y)): point = self.coords_to_point(x[i], y[i]) dot = Dot( color=next(color), radius=size, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs, ).move_to(point) scatter_sequence.add(dot) if hasattr(self, "scatter_sequences") is False: self.scatter_sequences = VGroup() self.scatter_sequences.add(scatter_sequence) self.add(self.scatter_sequences) return scatter_sequence
def construct(self): circle = Circle(color=YELLOW).scale(self.radius) points = [] lines = [] for point in range(self.points): start_angle = (point / self.points) * 2 * np.pi start_point = (RIGHT * np.cos(start_angle) + UP * np.sin(start_angle)) * self.radius points.append(start_point) stop_angle = (point + point * self.step) / self.points * 2 * np.pi stop_point = (RIGHT * np.cos(stop_angle) + UP * np.sin(stop_angle)) * self.radius lines.append(Line(start_point, stop_point, **self.line_config)) self.play(ShowCreation(circle)) self.wait() points_group = VGroup(*[Dot(point, **self.dot_config) for point in points]) lines_group = VGroup(*lines) # self.play(ShowCreation(points_group), run_time=2) self.play(ShowCreation(lines_group), run_time=10, rate_func=linear) self.wait()
def construct(self): dot = Dot() text = TextMobject("Label") \ .next_to(dot, RIGHT, buff=SMALL_BUFF) self.add(dot, text) # Update function def update_text(obj): obj.next_to(dot, RIGHT, buff=SMALL_BUFF) # Add update function to the objects text.add_updater(update_text) # Add the object again self.add(text) self.play(dot.shift, UP * 2) # Remove update function text.remove_updater(update_text) self.wait()
def gen_chars(self): chars = VGroup() submobjects_char_index = 0 for char_index in range(self.text.__len__()): if self.text[char_index] == " " or self.text[ char_index] == "\t" or self.text[char_index] == "\n": space = Dot(redius=0, fill_opacity=0, stroke_opacity=0) if char_index == 0: space.move_to( self.submobjects[submobjects_char_index].get_center()) else: space.move_to(self.submobjects[submobjects_char_index - 1].get_center()) chars.add(space) else: chars.add(self.submobjects[submobjects_char_index]) submobjects_char_index += 1 return chars
def panel_opener_on_mouse_drag(self, mob, event_data): point = event_data["point"] self.panel_opener.match_y(Dot(point)) self.move_panel_and_controls_to_panel_opener() return False
def panel_opener_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool: point = event_data["point"] self.panel_opener.match_y(Dot(point)) self.move_panel_and_controls_to_panel_opener() return False
def panel_opener_on_mouse_drag(self, point, d_point, buttons, modifiers): self.panel_opener.match_y(Dot(point)) self.move_panel_and_controls_to_panel_opener() return False