def construct(self):
        eq1_text = "4 x + 3 y = 0".split()
        eq2_text = "5 x - 2 y = 3".split()

        eq1_mob = TexMobject(*eq1_text)
        eq2_mob = TexMobject(*eq2_text)

        color_map = {"x": RED_B, "y": GREEN_C}
        eq1_mob.set_color_by_tex_to_color_map(color_map)
        eq2_mob.set_color_by_tex_to_color_map(color_map)

        for eq1_item, eq2_item in zip(eq1_mob, eq2_mob):
            eq2_item.align_to(eq1_item, LEFT)

        eq1 = VGroup(*eq1_mob)
        eq2 = VGroup(*eq2_mob)
        eq2.shift(DOWN)

        eq_group = VGroup(eq1, eq2)
        braces = Brace(eq_group, LEFT)
        eq_text = braces.get_text("A pair of equations")

        self.play(Write(eq_text))
        self.play(GrowFromCenter(braces))
        self.play(Write(eq1), Write(eq2))
        self.wait(2)
Example #2
0
    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]))
Example #3
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        body = Cube(side_length=1)
        for dim, scale_factor in enumerate(self.body_dimensions):
            body.stretch(scale_factor, dim=dim)
        body.set_width(self.width)
        body.set_fill(self.shaded_body_color, opacity=1)
        body.sort(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(RIGHT, buff=SMALL_BUFF)
            for y in range(4)
        ]).arrange(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)
Example #4
0
    def __init__(self, **kwargs):
        if not hasattr(self, "args"):
            self.args = serialize_args([])
        if not hasattr(self, "config"):
            self.config = serialize_config({
                **kwargs,
            })
        super().__init__(**kwargs)
        body = Cube(side_length=1)
        for dim, scale_factor in enumerate(self.body_dimensions):
            body.stretch(scale_factor, dim=dim)
        body.set_width(self.width)
        body.set_fill(self.shaded_body_color, opacity=1)
        body.sort(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(RIGHT, buff=SMALL_BUFF)
            for y in range(4)
        ]).arrange(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)
Example #5
0
    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
Example #6
0
    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
Example #7
0
 def create_label(self):
     for tex, value in zip(self.labels, self.values):
         i = self.labels.index(tex)
         r = self.inner_radius + self.outer_radius_func(self.values[i])
         size = TAU * r / len(self.values) * 0.2
         tex_i = Text(tex, font=self.label_font, color=WHITE, plot_depth=1).set_height(size)
         value_i = Text(str(value), font=self.label_font, color=WHITE, plot_depth=1).set_height(size).next_to(tex_i, DOWN * 0.64 * size)
         if not self.unit == None:
             unit_i = Text(self.unit, font=self.label_font, color=WHITE, plot_depth=1).set_height(size).next_to(value_i, RIGHT * 0.2 * size)
             VGroup(value_i, unit_i).next_to(tex_i, DOWN * 0.64 * size)
             label_i = VGroup(tex_i, value_i, unit_i)
         else:
             label_i = VGroup(tex_i, value_i)
         angle = TAU/len(self.values)
         start_a = np.angle(complex(*self.start_direction[0:2]))
         self.labels_group.add(label_i.shift(self.center + complex_to_R3((r-size * 1.2-r*0.05) * np.exp(1j * (start_a + (i + 0.5) * TAU/len(self.values))))))
     return self.labels_group
Example #8
0
 def move_tip_to(self, point):
     mover = VGroup(self)
     if self.content is not None:
         mover.add(self.content)
     mover.shift(point - self.get_tip())
     return self
Example #9
0
class CountingScene(Scene):
    CONFIG = {
        "digit_place_colors": [YELLOW, MAROON_B, RED, GREEN, BLUE, PURPLE_D],
        "counting_dot_starting_position":
        (FRAME_X_RADIUS - 1) * RIGHT + (FRAME_Y_RADIUS - 1) * UP,
        "count_dot_starting_radius":
        0.5,
        "dot_configuration_height":
        2,
        "ones_configuration_location":
        UP + 2 * RIGHT,
        "num_scale_factor":
        2,
        "num_start_location":
        2 * DOWN,
    }

    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_template_configuration(self, place):
        # This should probably be replaced for non-base-10 counting scenes
        down_right = (0.5) * RIGHT + (np.sqrt(3) / 2) * DOWN
        result = []
        for down_right_steps in range(5):
            for left_steps in range(down_right_steps):
                result.append(down_right_steps * down_right +
                              left_steps * LEFT)
        return reversed(result[:self.get_place_max(place)])

    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 add_configuration(self):
        new_template = self.get_dot_template(len(self.dot_templates))
        new_template.move_to(self.ones_configuration_location)
        left_vect = (new_template.get_width() + LARGE_BUFF) * LEFT
        new_template.shift(left_vect * len(self.dot_templates))
        self.dot_templates.append(new_template)
        self.dot_template_iterators.append(it.cycle(new_template))
        self.curr_configurations.append(VGroup())

    def count(self, max_val, run_time_per_anim=1):
        for x in range(max_val):
            self.increment(run_time_per_anim)

    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_digit_increment_animations(self):
        result = []
        self.number += 1
        is_next_digit = self.is_next_digit()
        if is_next_digit:
            self.max_place += 1
        new_number_mob = self.get_number_mob(self.number)
        new_number_mob.move_to(self.number_mob, RIGHT)
        if is_next_digit:
            self.add_configuration()
            place = len(new_number_mob.split()) - 1
            result.append(FadeIn(self.dot_templates[place]))
            arrow = Arrow(new_number_mob[place].get_top(),
                          self.dot_templates[place].get_bottom(),
                          color=self.digit_place_colors[place])
            self.arrows.add(arrow)
            result.append(ShowCreation(arrow))
        result.append(Transform(self.number_mob, new_number_mob,
                                lag_ratio=0.5))
        return result

    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 is_next_digit(self):
        return False

    def get_place_num(self, num, place):
        return 0

    def get_place_max(self, place):
        return 0
Example #10
0
class CountingScene(Scene):
    CONFIG = {
        "digit_place_colors": [YELLOW, MAROON_B, RED, GREEN, BLUE, PURPLE_D],
        "counting_dot_starting_position": (FRAME_X_RADIUS - 1) * RIGHT + (FRAME_Y_RADIUS - 1) * UP,
        "count_dot_starting_radius": 0.5,
        "dot_configuration_height": 2,
        "ones_configuration_location": UP + 2 * RIGHT,
        "num_scale_factor": 2,
        "num_start_location": 2 * DOWN,
    }

    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_template_configuration(self, place):
        # This should probably be replaced for non-base-10 counting scenes
        down_right = (0.5) * RIGHT + (np.sqrt(3) / 2) * DOWN
        result = []
        for down_right_steps in range(5):
            for left_steps in range(down_right_steps):
                result.append(
                    down_right_steps * down_right + left_steps * LEFT
                )
        return reversed(result[:self.get_place_max(place)])

    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 add_configuration(self):
        new_template = self.get_dot_template(len(self.dot_templates))
        new_template.move_to(self.ones_configuration_location)
        left_vect = (new_template.get_width() + LARGE_BUFF) * LEFT
        new_template.shift(
            left_vect * len(self.dot_templates)
        )
        self.dot_templates.append(new_template)
        self.dot_template_iterators.append(
            it.cycle(new_template)
        )
        self.curr_configurations.append(VGroup())

    def count(self, max_val, run_time_per_anim=1):
        for x in range(max_val):
            self.increment(run_time_per_anim)

    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_digit_increment_animations(self):
        result = []
        self.number += 1
        is_next_digit = self.is_next_digit()
        if is_next_digit:
            self.max_place += 1
        new_number_mob = self.get_number_mob(self.number)
        new_number_mob.move_to(self.number_mob, RIGHT)
        if is_next_digit:
            self.add_configuration()
            place = len(new_number_mob.split()) - 1
            result.append(FadeIn(self.dot_templates[place]))
            arrow = Arrow(
                new_number_mob[place].get_top(),
                self.dot_templates[place].get_bottom(),
                color=self.digit_place_colors[place]
            )
            self.arrows.add(arrow)
            result.append(ShowCreation(arrow))
        result.append(Transform(
            self.number_mob, new_number_mob,
            lag_ratio=0.5
        ))
        return result

    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 is_next_digit(self):
        return False

    def get_place_num(self, num, place):
        return 0

    def get_place_max(self, place):
        return 0
Example #11
0
class Code(VGroup):
    CONFIG = {
        "tab_width": 3,
        "line_spacing": 0.1,
        "scale_factor": 0.5,
        "run_time": 1,
        "font": 'Monospac821 BT',
        'stroke_width': 0,
        'margin': 0.3,
        'indentation_char': "  ",
        "background": "rectangle",  # or window
        "corner_radius": 0.2,
        'insert_line_no': True,
        'line_no_from': 1,
        "line_no_buff": 0.4,
        'style': 'vim',
        'language': 'cpp',
        'generate_html_file': False
    }

    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)
            red_button = Dot(radius=0.1, stroke_width=0, color='#ff5f56')
            red_button.shift(LEFT * 0.1 * 3)
            yellow_button = Dot(radius=0.1, stroke_width=0, color='#ffbd2e')
            green_button = Dot(radius=0.1, stroke_width=0, color='#27c93f')
            green_button.shift(RIGHT * 0.1 * 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_points_function_about_point(self,
                                          func,
                                          about_point=None,
                                          about_edge=None):
        if about_point is None:
            if about_edge is None:
                about_edge = self.get_corner(UP + LEFT)
            about_point = self.get_critical_point(about_edge)
        for mob in self.family_members_with_points():
            mob.points -= about_point
            mob.points = func(mob.points)
            mob.points += about_point
        return self

    def ensure_valid_file(self):
        if self.file_name is None:
            raise Exception("Must specify file for Code")
        possible_paths = [
            os.path.join(os.path.join("assets", "codes"), self.file_name),
            self.file_name,
        ]
        for path in possible_paths:
            if os.path.exists(path):
                self.file_path = path
                return
        raise IOError("No file matching %s in codes directory" %
                      self.file_name)

    def gen_line_numbers(self):
        line_numbers_array = []
        for line_no in range(0, self.code_json.__len__()):
            number = str(self.line_no_from + line_no)
            line_numbers_array.append(number)
        line_numbers = Paragraph(*[i for i in line_numbers_array],
                                 line_spacing=self.line_spacing,
                                 alignment="right",
                                 font=self.font,
                                 stroke_width=self.stroke_width).scale(
                                     self.scale_factor)
        return line_numbers

    def gen_colored_lines(self):
        lines_text = []
        for line_no in range(0, self.code_json.__len__()):
            line_str = ""
            for word_index in range(self.code_json[line_no].__len__()):
                line_str = line_str + self.code_json[line_no][word_index][0]
            lines_text.append(self.tab_spaces[line_no] * "\t" + line_str)
        code = Paragraph(*[i for i in lines_text],
                         line_spacing=self.line_spacing,
                         tab_width=self.tab_width,
                         alignment="left",
                         font=self.font,
                         stroke_width=self.stroke_width).scale(
                             self.scale_factor)
        for line_no in range(code.__len__()):
            line = code[line_no]
            line_char_index = self.tab_spaces[line_no]
            for word_index in range(self.code_json[line_no].__len__()):
                line[line_char_index:line_char_index + self.
                     code_json[line_no][word_index][0].__len__()].set_color(
                         self.code_json[line_no][word_index][1])
                line_char_index += self.code_json[line_no][word_index][
                    0].__len__()
        return code

    def gen_html_string(self):
        file = open(self.file_path, "r")
        code_str = file.read()
        file.close()
        self.html_string = hilite_me(
            code_str, self.language, {}, self.style, self.insert_line_no,
            "border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"
        )
        if self.generate_html_file:
            os.makedirs(os.path.join("assets", "codes",
                                     "generated_html_files"),
                        exist_ok=True)
            file = open(
                os.path.join("assets", "codes", "generated_html_files",
                             self.file_name + ".html"), "w")
            file.write(self.html_string)
            file.close()

    def gen_code_json(self):
        if self.background_color == "#111111" or \
                self.background_color == "#272822" or \
                self.background_color == "#202020" or \
                self.background_color == "#000000":
            self.default_color = "#ffffff"
        else:
            self.default_color = "#000000"
        for i in range(3, -1, -1):
            self.html_string = self.html_string.replace("</" + " " * i, "</")
        for i in range(10, -1, -1):
            self.html_string = self.html_string.replace(
                "</span>" + " " * i, " " * i + "</span>")
        self.html_string = self.html_string.replace("background-color:",
                                                    "background:")

        if self.insert_line_no:
            start_point = self.html_string.find("</td><td><pre")
            start_point = start_point + 9
        else:
            start_point = self.html_string.find("<pre")
        self.html_string = self.html_string[start_point:]
        # print(self.html_string)
        lines = self.html_string.split("\n")
        lines = lines[0:lines.__len__() - 2]
        start_point = lines[0].find(">")
        lines[0] = lines[0][start_point + 1:]
        # print(lines)
        self.code_json = []
        self.tab_spaces = []
        code_json_line_index = -1
        for line_index in range(0, lines.__len__()):
            if lines[line_index].__len__() == 0:
                continue
            # print(lines[line_index])
            self.code_json.append([])
            code_json_line_index = code_json_line_index + 1
            if lines[line_index].startswith(self.indentation_char):
                start_point = lines[line_index].find("<")
                starting_string = lines[line_index][:start_point]
                indentation_char_count = lines[line_index][:start_point].count(
                    self.indentation_char)
                if starting_string.__len__(
                ) != indentation_char_count * self.indentation_char.__len__():
                    lines[line_index] = "\t" * indentation_char_count + starting_string[starting_string.rfind(
                        self.indentation_char) + self.indentation_char.__len__():] + \
                                        lines[line_index][start_point:]
                else:
                    lines[line_index] = "\t" * indentation_char_count + lines[
                        line_index][start_point:]

            indentation_char_count = 0
            while lines[line_index][indentation_char_count] == '\t':
                indentation_char_count = indentation_char_count + 1
            self.tab_spaces.append(indentation_char_count)
            # print(lines[line_index])
            lines[line_index] = self.correct_non_span(lines[line_index])
            # print(lines[line_index])
            words = lines[line_index].split("<span")
            for word_index in range(1, words.__len__()):
                color_index = words[word_index].find("color:")
                if color_index == -1:
                    color = self.default_color
                else:
                    starti = words[word_index][color_index:].find("#")
                    color = words[word_index][color_index +
                                              starti:color_index + starti + 7]

                start_point = words[word_index].find(">")
                end_point = words[word_index].find("</span>")
                text = words[word_index][start_point + 1:end_point]
                text = html.unescape(text)
                if text != "":
                    # print(text, "'" + color + "'")
                    self.code_json[code_json_line_index].append([text, color])
        # print(self.code_json)

    def correct_non_span(self, line_str):
        words = line_str.split("</span>")
        line_str = ""
        for i in range(0, words.__len__()):
            if i != words.__len__() - 1:
                j = words[i].find("<span")
            else:
                j = words[i].__len__()
            temp = ""
            starti = -1
            for k in range(0, j):
                if words[i][k] == "\t" and starti == -1:
                    continue
                else:
                    if starti == -1: starti = k
                    temp = temp + words[i][k]
            if temp != "":
                if i != words.__len__() - 1:
                    temp = '<span style="color:' + self.default_color + '">' + words[
                        i][starti:j] + "</span>"
                else:
                    temp = '<span style="color:' + self.default_color + '">' + words[
                        i][starti:j]
                temp = temp + words[i][j:]
                words[i] = temp
            if words[i] != "":
                line_str = line_str + words[i] + "</span>"
        return line_str
Example #12
0
 def move_tip_to(self, point):
     mover = VGroup(self)
     if self.content is not None:
         mover.add(self.content)
     mover.shift(point - self.get_tip())
     return self
Example #13
0
class Code(VGroup):
    CONFIG = {
        "tab_width": 1,
        "line_spacing": 0.3,  # space between the lines
        "scale_factor": 0.4,
        "run_time": 1,
        #"font": 'Monospac821 BT',
        #"font": 'Arial',
        #"font": "DejaVu Sans Mono",
        "font": "Courier New",
        #"font": 'Courier New',
        "font_size": 48,
        'stroke_width': 0,
        'margin': 0.3,
        'indentation_char': " ",
        "background": "window",  #rectangle or window
        "corner_radius": 0.2,
        'insert_line_no': True,
        'line_no_from': 1,
        "line_no_buff": 0.4,
        'style':
        'railscasts',  #white based:railscasts, vim , material, native; black based: tango, xcode ;
        #pink-based: paraiso-light; styles not highlithing print() and list(): monokai, fruity, paraiso-dark
        #grey-based: arduino, solarized-dark, solarized-light
        #beige-based: inkpot, zenburn
        'language': 'python',
        'generate_html_file': False,
        'adapting_x': False,
        'adapting_y': False,
        'center_y': True,
    }

    def __init__(self, file_name=None, code_str=None, **kwargs):
        Container.__init__(self, **kwargs)
        self.file_name = file_name
        self.code_str = code_str
        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=GREY_E,
                                     fill_opacity=1)
            red_button = Dot(radius=0.1, stroke_width=0, color='#ff5f56')
            red_button.shift(LEFT * 0.1 * 3)
            yellow_button = Dot(radius=0.1, stroke_width=0, color='#ffbd2e')
            green_button = Dot(radius=0.1, stroke_width=0, color='#27c93f')
            green_button.shift(RIGHT * 0.1 * 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)

        window = RIGHT_SIDE[0] - LEFT_SIDE[0]
        width = self.background_mobject.get_width()
        print(width)
        scale_x = window / width * 0.96

        window = TOP[1] - BOTTOM[1]
        print(window)
        width = self.background_mobject.get_height()
        scale_y = window / width * 0.96

        if self.adapting_x and scale_x < scale_y:
            self.scale(scale_x)
        if self.adapting_y and scale_y <= scale_x:
            self.scale(scale_y)
        self.align_to(LEFT_SIDE + self.margin, LEFT)
        self.align_to(
            TOP - self.margin + 0.42 *
            (self.code.char_height + self.code.line_spacing) *
            self.scale_factor, UP)

    def FadeInWindow(self):
        return FadeIn(self.background_mobject),

    '''
    def Write(self):
        write_code = [Write(line) for line in self.code.lines[0]]
        write_line_numbers = [Write(number) for number in self.line_numbers.lines[0]]
        write_all = [item for sublist in zip(write_line_numbers, write_code) for item in sublist]
        return write_all
    def ShowCreation(self):
        write_code = [ShowCreation(line, duration= 1) for line in self.code.lines[0]]
        write_line_numbers = [ShowCreation(number) for number in self.line_numbers.lines[0]]
        write_all = [item for sublist in zip(write_line_numbers, write_code) for item in sublist]

        return write_all
    '''

    def center_to_code(self):
        if self.center_y:
            print(self.get_y() - self.code.lines[0][0].get_height() +
                  self.code.line_spacing)
            self.set_y(self.get_y() +
                       (self.code.char_height + self.code.line_spacing) *
                       self.scale_factor)

    def apply_points_function_about_point(self,
                                          func,
                                          about_point=None,
                                          about_edge=None):
        if about_point is None:
            if about_edge is None:
                about_edge = self.get_corner(UP + LEFT)
            about_point = self.get_critical_point(about_edge)
        for mob in self.family_members_with_points():
            mob.points -= about_point
            mob.points = func(mob.points)
            mob.points += about_point
        return self

    def ensure_valid_file(self):
        if not self.file_name is None:
            possible_paths = [
                os.path.join(os.path.join("assets", "codes"), self.file_name),
                self.file_name,
            ]
            for path in possible_paths:
                if os.path.exists(path):
                    self.file_path = path
                    return
            raise IOError("No file matching %s in codes directory" %
                          self.file_name)

    def gen_line_numbers(self):
        line_numbers_array = []
        for line_no in range(0, self.code_json.__len__()):
            number = str(self.line_no_from + line_no)
            line_numbers_array.append(number)
        #color  ="#E6E8E8"
        line_numbers = Paragraph(
            *[i for i in line_numbers_array],
            line_spacing=self.line_spacing,
            alignment="left",
            font=self.font,
            stroke_width=self.stroke_width,
        ).scale(self.scale_factor)
        return line_numbers

    def gen_colored_lines(self):

        lines_text = []
        for line_no in range(0, self.code_json.__len__()):
            line_str = ""
            for word_index in range(self.code_json[line_no].__len__()):
                line_str = line_str + self.code_json[line_no][word_index][0]
            lines_text.append(self.tab_spaces[line_no] * "\t" + line_str)
        #print(lines_text)
        code = Paragraph(*[text for text in lines_text],
                         line_spacing=self.line_spacing,
                         tab_width=self.tab_width,
                         alignment="left",
                         font=self.font,
                         stroke_width=self.stroke_width,
                         unpack_groups=True).scale(self.scale_factor)
        for line_no in range(code.__len__()):
            line = code[line_no]
            line_char_index = self.tab_spaces[line_no]
            for word_index in range(self.code_json[line_no].__len__()):
                line[line_char_index:line_char_index + self.
                     code_json[line_no][word_index][0].__len__()].set_color(
                         self.code_json[line_no][word_index][1])
                line_char_index += self.code_json[line_no][word_index][
                    0].__len__()
        #print(self.code_json)
        return code

    def gen_html_string(self):
        if self.file_name:
            file = open(self.file_path, "r")
            code_str = file.read()
            file.close()
        if self.code_str:
            code_str = self.code_str
        self.html_string = hilite_me(
            code_str, self.language, {}, self.style, self.insert_line_no,
            "border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"
        )

        if self.generate_html_file:
            os.makedirs(os.path.join("assets", "codes",
                                     "generated_html_files"),
                        exist_ok=True)
            file = open(
                os.path.join("assets", "codes", "generated_html_files",
                             self.file_name + ".html"), "w")
            file.write(self.html_string)
            file.close()

    def gen_code_json(self):
        #print(self.html_string)
        if self.background_color == "#111111" or \
                self.background_color == "#272822" or \
                self.background_color == "#202020" or \
                self.background_color == "#000000":
            self.default_color = "#ffffff"
        else:
            self.default_color = "#000000"

        for i in range(3, -1, -1):
            self.html_string = self.html_string.replace("</" + " " * i, "</")
        for i in range(10, -1, -1):
            self.html_string = self.html_string.replace(
                "</span>" + " " * i, " " * i + "</span>")

        self.html_string = self.html_string.replace("background-color:",
                                                    "background:")

        if self.insert_line_no:
            start_point = self.html_string.find("</td><td><pre")
            start_point = start_point + 9
        else:
            start_point = self.html_string.find("<pre")
        self.html_string = self.html_string[start_point:]
        # print(self.html_string)
        lines = self.html_string.split("\n")
        lines = lines[0:lines.__len__() - 2]
        start_point = lines[0].find(">")
        lines[0] = lines[0][start_point + 1:]
        # print(lines)
        self.code_json = []
        self.tab_spaces = []
        code_json_line_index = -1
        #print(self.html_string)
        starting_string = ""
        for line_index in range(0, lines.__len__()):
            if lines[line_index].__len__() == 0:
                continue
            #print(lines[line_index])
            self.code_json.append([])
            code_json_line_index = code_json_line_index + 1
            if lines[line_index].startswith(self.indentation_char):
                start_point = lines[line_index].find("<")
                starting_string = lines[line_index][:start_point]
                indentation_char_count = lines[line_index][:start_point].count(
                    self.indentation_char)
                if starting_string.__len__(
                ) != indentation_char_count * self.indentation_char.__len__():
                    lines[line_index] = "\t" * indentation_char_count + starting_string[starting_string.rfind(
                        self.indentation_char) + self.indentation_char.__len__():] + \
                                        lines[line_index][start_point:]
                else:
                    lines[line_index] = "\t" * indentation_char_count + lines[
                        line_index][start_point:]

            indentation_char_count = 0
            while lines[line_index][indentation_char_count] == '\t':
                indentation_char_count = indentation_char_count + 1
            self.tab_spaces.append(indentation_char_count)
            # print(lines[line_index])
            lines[line_index] = self.correct_non_span(lines[line_index])
            # print(lines[line_index])
            words = lines[line_index].split("<span")
            for word_index in range(1, words.__len__()):
                color_index = words[word_index].find("color:")
                if color_index == -1:
                    color = self.default_color
                else:
                    starti = words[word_index][color_index:].find("#")
                    color = words[word_index][color_index +
                                              starti:color_index + starti + 7]

                start_point = words[word_index].find(">")
                end_point = words[word_index].find("</span>")
                text = words[word_index][start_point + 1:end_point]
                text = html.unescape(text)
                if text != "":
                    #print(text, "'" + color + "'")
                    self.code_json[code_json_line_index].append([text, color])
        #print(self.code_json)

    def correct_non_span(self, line_str):
        words = line_str.split("</span>")
        line_str = ""
        for i in range(0, words.__len__()):
            if i != words.__len__() - 1:
                j = words[i].find("<span")
            else:
                j = words[i].__len__()
            temp = ""
            starti = -1
            for k in range(0, j):
                if words[i][k] == "\t" and starti == -1:
                    continue
                else:
                    if starti == -1: starti = k
                    temp = temp + words[i][k]
            if temp != "":
                if i != words.__len__() - 1:
                    temp = '<span style="color:' + self.default_color + '">' + words[
                        i][starti:j] + "</span>"
                else:
                    temp = '<span style="color:' + self.default_color + '">' + words[
                        i][starti:j]
                temp = temp + words[i][j:]
                words[i] = temp
            if words[i] != "":
                line_str = line_str + words[i] + "</span>"
        return line_str
Example #14
0
    def __init__(self, file_name=None, code_str=None, **kwargs):
        Container.__init__(self, **kwargs)
        self.file_name = file_name
        self.code_str = code_str
        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=GREY_E,
                                     fill_opacity=1)
            red_button = Dot(radius=0.1, stroke_width=0, color='#ff5f56')
            red_button.shift(LEFT * 0.1 * 3)
            yellow_button = Dot(radius=0.1, stroke_width=0, color='#ffbd2e')
            green_button = Dot(radius=0.1, stroke_width=0, color='#27c93f')
            green_button.shift(RIGHT * 0.1 * 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)

        window = RIGHT_SIDE[0] - LEFT_SIDE[0]
        width = self.background_mobject.get_width()
        print(width)
        scale_x = window / width * 0.96

        window = TOP[1] - BOTTOM[1]
        print(window)
        width = self.background_mobject.get_height()
        scale_y = window / width * 0.96

        if self.adapting_x and scale_x < scale_y:
            self.scale(scale_x)
        if self.adapting_y and scale_y <= scale_x:
            self.scale(scale_y)
        self.align_to(LEFT_SIDE + self.margin, LEFT)
        self.align_to(
            TOP - self.margin + 0.42 *
            (self.code.char_height + self.code.line_spacing) *
            self.scale_factor, UP)