Example #1
0
 def __init__(self, **kwargs):
     digest_config(self, kwargs)
     videos = [VideoIcon() for x in range(self.num_videos)]
     VGroup.__init__(self, *videos, **kwargs)
     self.arrange()
     self.set_width(FRAME_WIDTH - MED_LARGE_BUFF)
     self.set_color_by_gradient(*self.gradient_colors)
Example #2
0
 def get_tips(self):
     result = VGroup()
     if hasattr(self, "tip"):
         result.add(self.tip)
     if hasattr(self, "start_tip"):
         result.add(self.start_tip)
     return result
Example #3
0
class PartyHat(SVGMobject):
    CONFIG = {
        "file_name": "party_hat",
        "height": 1.5,
        "pi_creature": None,
        "stroke_width": 0,
        "fill_opacity": 1,
        "frills_colors": [MAROON_B, PURPLE],
        "cone_color": GREEN,
        "dots_colors": [YELLOW],
    }
    NUM_FRILLS = 7
    NUM_DOTS = 6

    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.set_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff=0)

        self.frills = VGroup(*self[:self.NUM_FRILLS])
        self.cone = self[self.NUM_FRILLS]
        self.dots = VGroup(*self[self.NUM_FRILLS + 1:])

        self.frills.set_color_by_gradient(*self.frills_colors)
        self.cone.set_color(self.cone_color)
        self.dots.set_color_by_gradient(*self.dots_colors)
Example #4
0
 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)
Example #5
0
 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)
Example #6
0
    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()
Example #7
0
 def __init__(self, **kwargs):
     possible_values = list(map(str, list(range(1, 11)))) + ["J", "Q", "K"]
     possible_suits = ["hearts", "diamonds", "spades", "clubs"]
     VGroup.__init__(self, *[
         PlayingCard(value=value, suit=suit, **kwargs)
         for value in possible_values
         for suit in possible_suits
     ])
 def get_transformer(self, **kwargs):
     transform_kwargs = dict(self.default_apply_complex_function_kwargs)
     transform_kwargs.update(kwargs)
     transformer = VGroup()
     if hasattr(self, "plane"):
         self.prepare_for_transformation(self.plane)
         transformer.add(self.plane)
     transformer.add(*self.transformable_mobjects)
     return transformer, transform_kwargs
Example #9
0
    def __init__(self, stream_lines, **kwargs):
        VGroup.__init__(self, **kwargs)
        self.stream_lines = stream_lines
        for line in stream_lines:
            line.anim = self.line_anim_class(line, **self.line_anim_config)
            line.anim.begin()
            line.time = -self.lag_range * random.random()
            self.add(line.anim.mobject)

        self.add_updater(lambda m, dt: m.update(dt))
Example #10
0
 def pop_tips(self):
     start, end = self.get_start_and_end()
     result = VGroup()
     if self.has_tip():
         result.add(self.tip)
         self.remove(self.tip)
     if self.has_start_tip():
         result.add(self.start_tip)
         self.remove(self.start_tip)
     self.put_start_and_end_on(start, end)
     return result
Example #11
0
 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(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)
Example #12
0
    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,
                            lag_ratio=0,
                        ),
                        *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()
Example #13
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 #14
0
    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.set_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff=0)

        self.frills = VGroup(*self[:self.NUM_FRILLS])
        self.cone = self[self.NUM_FRILLS]
        self.dots = VGroup(*self[self.NUM_FRILLS + 1:])

        self.frills.set_color_by_gradient(*self.frills_colors)
        self.cone.set_color(self.cone_color)
        self.dots.set_color_by_gradient(*self.dots_colors)
Example #15
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
Example #16
0
 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
Example #17
0
    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
Example #18
0
 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
Example #19
0
    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
Example #20
0
    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.set_height(self.height)
        result.center()
        return result
Example #21
0
    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)
Example #22
0
    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)
Example #23
0
 def setup_in_uv_space(self):
     u_values, v_values = self.get_u_values_and_v_values()
     faces = VGroup()
     for i in range(len(u_values) - 1):
         for j in range(len(v_values) - 1):
             u1, u2 = u_values[i:i + 2]
             v1, v2 = v_values[j:j + 2]
             face = ThreeDVMobject()
             face.set_points_as_corners([
                 [u1, v1, 0],
                 [u2, v1, 0],
                 [u2, v2, 0],
                 [u1, v2, 0],
                 [u1, v1, 0],
             ])
             faces.add(face)
             face.u_index = i
             face.v_index = j
             face.u1 = u1
             face.u2 = u2
             face.v1 = v1
             face.v2 = v2
     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)
Example #24
0
    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)
Example #25
0
 def get_axes(self):
     axes = ThreeDAxes(**self.three_d_axes_config)
     for axis in axes:
         if self.cut_axes_at_radius:
             p0 = axis.get_start()
             p1 = axis.number_to_point(-1)
             p2 = axis.number_to_point(1)
             p3 = axis.get_end()
             new_pieces = VGroup(
                 Line(p0, p1), Line(p1, p2), Line(p2, p3),
             )
             for piece in new_pieces:
                 piece.shade_in_3d = True
             new_pieces.match_style(axis.pieces)
             axis.pieces.submobjects = new_pieces.submobjects
         for tick in axis.tick_marks:
             tick.add(VectorizedPoint(
                 1.5 * tick.get_center(),
             ))
     return axes
Example #26
0
def get_det_text(matrix, determinant=None, background_rect=False, initial_scale_factor=2):
    parens = TexMobject("(", ")")
    parens.scale(initial_scale_factor)
    parens.stretch_to_fit_height(matrix.get_height())
    l_paren, r_paren = parens.split()
    l_paren.next_to(matrix, LEFT, buff=0.1)
    r_paren.next_to(matrix, RIGHT, buff=0.1)
    det = TextMobject("det")
    det.scale(initial_scale_factor)
    det.next_to(l_paren, LEFT, buff=0.1)
    if background_rect:
        det.add_background_rectangle()
    det_text = VGroup(det, l_paren, r_paren)
    if determinant is not None:
        eq = TexMobject("=")
        eq.next_to(r_paren, RIGHT, buff=0.1)
        result = TexMobject(str(determinant))
        result.next_to(eq, RIGHT, buff=0.2)
        det_text.add(eq, result)
    return det_text
Example #27
0
    def __init__(self, func, **kwargs):
        VGroup.__init__(self, **kwargs)
        self.func = func
        dt = self.dt

        start_points = self.get_start_points(
            **self.start_points_generator_config
        )
        for point in start_points:
            points = [point]
            for t in np.arange(0, self.virtual_time, dt):
                last_point = points[-1]
                points.append(last_point + dt * func(last_point))
                if get_norm(last_point) > self.cutoff_norm:
                    break
            line = VMobject()
            step = max(1, int(len(points) / self.n_anchors_per_line))
            line.set_points_smoothly(points[::step])
            self.add(line)

        self.set_stroke(self.stroke_color, self.stroke_width)

        if self.color_by_arc_length:
            len_to_rgb = get_rgb_gradient_function(
                self.min_arc_length,
                self.max_arc_length,
                colors=self.colors,
            )
            for line in self:
                arc_length = line.get_arc_length()
                rgb = len_to_rgb([arc_length])[0]
                color = rgb_to_color(rgb)
                line.set_color(color)
        elif self.color_by_magnitude:
            image_file = get_color_field_image_file(
                lambda p: get_norm(func(p)),
                min_value=self.min_magnitude,
                max_value=self.max_magnitude,
                colors=self.colors,
            )
            self.color_using_background_image(image_file)
Example #28
0
 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.add_updater(
             lambda c: c.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)
     animations = [
         Restore(circle)
         for circle in circles
     ]
     super().__init__(*animations, **kwargs)
Example #29
0
    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()
Example #30
0
    def add_axes(self):
        x_axis = Line(self.tick_width * LEFT / 2, self.width * RIGHT)
        y_axis = Line(MED_LARGE_BUFF * DOWN, self.height * UP)
        ticks = VGroup()
        heights = np.linspace(0, self.height, self.n_ticks + 1)
        values = np.linspace(0, self.max_value, self.n_ticks + 1)
        for y, value in zip(heights, values):
            tick = Line(LEFT, RIGHT)
            tick.set_width(self.tick_width)
            tick.move_to(y * UP)
            ticks.add(tick)
        y_axis.add(ticks)

        self.add(x_axis, y_axis)
        self.x_axis, self.y_axis = x_axis, y_axis

        if self.label_y_axis:
            labels = VGroup()
            for tick, value in zip(ticks, values):
                label = TexMobject(str(np.round(value, 2)))
                label.set_height(self.y_axis_label_height)
                label.next_to(tick, LEFT, SMALL_BUFF)
                labels.add(label)
            self.y_axis_labels = labels
            self.add(labels)
Example #31
0
class TeacherStudentsScene(PiCreatureScene):
    CONFIG = {
        "student_colors": [BLUE_D, BLUE_E, BLUE_C],
        "teacher_color": GREY_BROWN,
        "background_color": GREY_E,
        "student_scale_factor": 0.8,
        "seconds_to_blink": 2,
        "screen_height": 3,
    }

    def setup(self):
        self.background = FullScreenFadeRectangle(
            fill_color=self.background_color,
            fill_opacity=1,
        )
        self.add(self.background)
        PiCreatureScene.setup(self)
        self.screen = ScreenRectangle(height=self.screen_height)
        self.screen.to_corner(UP + LEFT)
        self.hold_up_spot = self.teacher.get_corner(UP +
                                                    LEFT) + MED_LARGE_BUFF * UP

    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(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_teacher(self):
        return self.teacher

    def get_students(self):
        return self.students

    def teacher_says(self, *content, **kwargs):
        return self.pi_creature_says(self.get_teacher(), *content, **kwargs)

    def student_says(self, *content, **kwargs):
        if "target_mode" not in kwargs:
            target_mode = random.choice([
                "raise_right_hand",
                "raise_left_hand",
            ])
            kwargs["target_mode"] = target_mode
        if "bubble_kwargs" not in kwargs:
            kwargs["bubble_kwargs"] = {"direction": LEFT}
        student = self.get_students()[kwargs.get("student_index", 2)]
        return self.pi_creature_says(student, *content, **kwargs)

    def teacher_thinks(self, *content, **kwargs):
        return self.pi_creature_thinks(self.get_teacher(), *content, **kwargs)

    def student_thinks(self, *content, **kwargs):
        student = self.get_students()[kwargs.get("student_index", 2)]
        return self.pi_creature_thinks(student, *content, **kwargs)

    def change_all_student_modes(self, mode, **kwargs):
        self.change_student_modes(*[mode] * len(self.students), **kwargs)

    def change_student_modes(self, *modes, **kwargs):
        added_anims = kwargs.pop("added_anims", [])
        self.play(self.get_student_changes(*modes, **kwargs), *added_anims)

    def get_student_changes(self, *modes, **kwargs):
        pairs = list(zip(self.get_students(), modes))
        pairs = [(s, m) for s, m in pairs if m is not None]
        start = VGroup(*[s for s, m in pairs])
        target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
        if "look_at_arg" in kwargs:
            for pi in target:
                pi.look_at(kwargs["look_at_arg"])
        anims = [Transform(s, t) for s, t in zip(start, target)]
        return LaggedStart(
            *anims,
            lag_ratio=kwargs.get("lag_ratio", 0.5),
            run_time=1,
        )
        # return Transform(
        #     start, target,
        #     lag_ratio=lag_ratio,
        #     run_time=2
        # )

    def zoom_in_on_thought_bubble(self,
                                  bubble=None,
                                  radius=FRAME_Y_RADIUS + FRAME_X_RADIUS):
        if bubble is None:
            for pi in self.get_pi_creatures():
                if hasattr(pi, "bubble") and isinstance(
                        pi.bubble, ThoughtBubble):
                    bubble = pi.bubble
                    break
            if bubble is None:
                raise Exception("No pi creatures have a thought bubble")
        vect = -bubble.get_bubble_center()

        def func(point):
            centered = point + vect
            return radius * centered / get_norm(centered)

        self.play(
            *
            [ApplyPointwiseFunction(func, mob) for mob in self.get_mobjects()])

    def teacher_holds_up(self,
                         mobject,
                         target_mode="raise_right_hand",
                         added_anims=None,
                         **kwargs):
        mobject.move_to(self.hold_up_spot, DOWN)
        mobject.shift_onto_screen()
        added_anims = added_anims or []
        self.play(FadeIn(mobject, shift=UP), self.teacher.change, target_mode,
                  *added_anims)
    def add_T_label(self,
                    x_val,
                    side=RIGHT,
                    label=None,
                    color=WHITE,
                    animated=False,
                    **kwargs):
        """
        This method adds to the Scene:
            -- a Vertical line from the x-axis to the corresponding point on the graph/curve.
            -- a small vertical Triangle whose top point lies on the base of the vertical line
            -- a TexMobject to be a label for the Line and Triangle, at the bottom of the Triangle.
        The scene needs to have the graph have the identifier/variable name self.v_graph.

        Parameters
        ----------
        x_val (Union[float, int])
            The x value at which the secant enters, and intersects
            the graph for the first time.

        side (np.ndarray())

        label (str)
            The label to give the vertline and triangle

        color (str)
            The hex color of the label.

        animated (bool=False)
            Whether or not to animate the addition of the T_label

        **kwargs
            Any valid keyword argument of a self.play call.
        """
        triangle = RegularPolygon(n=3, start_angle=np.pi / 2)
        triangle.set_height(MED_SMALL_BUFF)
        triangle.move_to(self.coords_to_point(x_val, 0), UP)
        triangle.set_fill(color, 1)
        triangle.set_stroke(width=0)
        if label is None:
            T_label = TexMobject(self.variable_point_label, fill_color=color)
        else:
            T_label = TexMobject(label, fill_color=color)

        T_label.next_to(triangle, DOWN)
        v_line = self.get_vertical_line_to_graph(x_val,
                                                 self.v_graph,
                                                 color=YELLOW)

        if animated:
            self.play(DrawBorderThenFill(triangle), ShowCreation(v_line),
                      Write(T_label, run_time=1), **kwargs)

        if np.all(side == LEFT):
            self.left_T_label_group = VGroup(T_label, triangle)
            self.left_v_line = v_line
            self.add(self.left_T_label_group, self.left_v_line)
        elif np.all(side == RIGHT):
            self.right_T_label_group = VGroup(T_label, triangle)
            self.right_v_line = v_line
            self.add(self.right_T_label_group, self.right_v_line)
    def setup_axes(self, animate=False):
        """
        This method sets up the axes of the graph.

        Parameters
        ----------
        animate (bool=False)
            Whether or not to animate the setting up of the Axes.
        """
        # TODO, once eoc is done, refactor this to be less redundant.
        x_num_range = float(self.x_max - self.x_min)
        self.space_unit_to_x = self.x_axis_width / x_num_range
        if self.x_labeled_nums is None:
            self.x_labeled_nums = []
        if self.x_leftmost_tick is None:
            self.x_leftmost_tick = self.x_min
        x_axis = NumberLine(
            x_min=self.x_min,
            x_max=self.x_max,
            unit_size=self.space_unit_to_x,
            tick_frequency=self.x_tick_frequency,
            leftmost_tick=self.x_leftmost_tick,
            numbers_with_elongated_ticks=self.x_labeled_nums,
            color=self.axes_color,
            # Added this line
            decimal_number_config={"color": self.label_nums_color})
        x_axis.shift(self.graph_origin - x_axis.number_to_point(0))
        if len(self.x_labeled_nums) > 0:
            if self.exclude_zero_label:
                self.x_labeled_nums = [
                    x for x in self.x_labeled_nums if x != 0
                ]
            x_axis.add_numbers(*self.x_labeled_nums)
        if self.x_axis_label:
            x_label = TextMobject(self.x_axis_label)

            # Added this line
            x_label.set_color(self.label_color)
            x_label.next_to(x_axis.get_tick_marks(),
                            UP + RIGHT,
                            buff=SMALL_BUFF)
            x_label.shift_onto_screen()
            x_axis.add(x_label)
            self.x_axis_label_mob = x_label
        y_num_range = float(self.y_max - self.y_min)
        self.space_unit_to_y = self.y_axis_height / y_num_range

        if self.y_labeled_nums is None:
            self.y_labeled_nums = []
        if self.y_bottom_tick is None:
            self.y_bottom_tick = self.y_min
        y_axis = NumberLine(
            x_min=self.y_min,
            x_max=self.y_max,
            unit_size=self.space_unit_to_y,
            tick_frequency=self.y_tick_frequency,
            leftmost_tick=self.y_bottom_tick,
            numbers_with_elongated_ticks=self.y_labeled_nums,
            color=self.axes_color,
            line_to_number_vect=LEFT,
            label_direction=LEFT,
            # yongze added this line
            decimal_number_config={"color": self.label_nums_color},
        )
        y_axis.shift(self.graph_origin - y_axis.number_to_point(0))
        y_axis.rotate(np.pi / 2, about_point=y_axis.number_to_point(0))
        if len(self.y_labeled_nums) > 0:
            if self.exclude_zero_label:
                self.y_labeled_nums = [
                    y for y in self.y_labeled_nums if y != 0
                ]
            y_axis.add_numbers(*self.y_labeled_nums)
        if self.y_axis_label:
            y_label = TextMobject(self.y_axis_label)
            # yongze Added this line
            y_label.set_color(self.label_color)
            y_label.next_to(y_axis.get_corner(UP + RIGHT),
                            UP + RIGHT,
                            buff=SMALL_BUFF)
            y_label.shift_onto_screen()
            y_axis.add(y_label)
            self.y_axis_label_mob = y_label

        if animate:
            self.play(Write(VGroup(x_axis, y_axis)))
        else:
            self.add(x_axis, y_axis)
        self.x_axis, self.y_axis = self.axes = VGroup(x_axis, y_axis)
        self.default_graph_colors = it.cycle(self.default_graph_colors)
Example #34
0
class PiCreature(SVGMobject):
    CONFIG = {
        "color": BLUE_E,
        "file_name_prefix": "PiCreatures",
        "stroke_width": 0,
        "stroke_color": BLACK,
        "fill_opacity": 1.0,
        "height": 3,
        "corner_scale_factor": 0.75,
        "flip_at_start": False,
        "is_looking_direction_purposeful": False,
        "start_corner": None,
        # Range of proportions along body where arms are
        "right_arm_range": [0.55, 0.7],
        "left_arm_range": [.34, .462],
        "pupil_to_eye_width_ratio": 0.4,
        "pupil_dot_to_pupil_width_ratio": 0.3,
    }

    def __init__(self, mode="plain", **kwargs):
        digest_config(self, kwargs)
        self.mode = mode
        self.parts_named = False
        try:
            svg_file = os.path.join(
                PI_CREATURE_DIR, "%s_%s.svg" % (self.file_name_prefix, mode))
            SVGMobject.__init__(self, file_name=svg_file, **kwargs)
        except Exception:
            warnings.warn("No %s design with mode %s" %
                          (self.file_name_prefix, mode))
            # TODO, this needs to change to a different, better directory
            svg_file = os.path.join(
                FILE_DIR,
                "PiCreatures_plain.svg",
            )
            SVGMobject.__init__(self,
                                mode="plain",
                                file_name=svg_file,
                                **kwargs)

        if self.flip_at_start:
            self.flip()
        if self.start_corner is not None:
            self.to_corner(self.start_corner)

    def align_data(self, mobject):
        # This ensures that after a transform into a different mode,
        # the pi creatures mode will be updated appropriately
        SVGMobject.align_data(self, mobject)
        if isinstance(mobject, PiCreature):
            self.mode = mobject.get_mode()

    def name_parts(self):
        self.mouth = self.submobjects[MOUTH_INDEX]
        self.body = self.submobjects[BODY_INDEX]
        self.pupils = VGroup(*[
            self.submobjects[LEFT_PUPIL_INDEX],
            self.submobjects[RIGHT_PUPIL_INDEX]
        ])
        self.eyes = VGroup(*[
            self.submobjects[LEFT_EYE_INDEX], self.submobjects[RIGHT_EYE_INDEX]
        ])
        self.eye_parts = VGroup(self.eyes, self.pupils)
        self.parts_named = True

    def init_colors(self):
        SVGMobject.init_colors(self)
        if not self.parts_named:
            self.name_parts()
        self.mouth.set_fill(BLACK, opacity=1)
        self.body.set_fill(self.color, opacity=1)
        self.eyes.set_fill(WHITE, opacity=1)
        self.init_pupils()
        return self

    def init_pupils(self):
        # Instead of what is drawn, make new circles.
        # This is mostly because the paths associated
        # with the eyes in all the drawings got slightly
        # messed up.
        for eye, pupil in zip(self.eyes, self.pupils):
            pupil_r = eye.get_width() / 2
            pupil_r *= self.pupil_to_eye_width_ratio
            dot_r = pupil_r
            dot_r *= self.pupil_dot_to_pupil_width_ratio

            new_pupil = Circle(
                radius=pupil_r,
                color=BLACK,
                fill_opacity=1,
                stroke_width=0,
            )
            dot = Circle(
                radius=dot_r,
                color=WHITE,
                fill_opacity=1,
                stroke_width=0,
            )
            new_pupil.move_to(pupil)
            pupil.become(new_pupil)
            dot.shift(
                new_pupil.get_boundary_point(UL) - dot.get_boundary_point(UL))
            pupil.add(dot)

    def copy(self):
        copy_mobject = SVGMobject.copy(self)
        copy_mobject.name_parts()
        return copy_mobject

    def set_color(self, color):
        self.body.set_fill(color)
        self.color = color
        return self

    def change_mode(self, mode):
        new_self = self.__class__(mode=mode, )
        new_self.match_style(self)
        new_self.match_height(self)
        if self.is_flipped() != new_self.is_flipped():
            new_self.flip()
        new_self.shift(self.eyes.get_center() - new_self.eyes.get_center())
        if hasattr(self, "purposeful_looking_direction"):
            new_self.look(self.purposeful_looking_direction)
        self.become(new_self)
        self.mode = mode
        return self

    def get_mode(self):
        return self.mode

    def look(self, direction):
        norm = get_norm(direction)
        if norm == 0:
            return
        direction /= norm
        self.purposeful_looking_direction = direction
        for pupil, eye in zip(self.pupils.split(), self.eyes.split()):
            c = eye.get_center()
            right = eye.get_right() - c
            up = eye.get_top() - c
            vect = direction[0] * right + direction[1] * up
            v_norm = get_norm(vect)
            p_radius = 0.5 * pupil.get_width()
            vect *= (v_norm - 0.75 * p_radius) / v_norm
            pupil.move_to(c + vect)
        self.pupils[1].align_to(self.pupils[0], DOWN)
        return self

    def look_at(self, point_or_mobject):
        if isinstance(point_or_mobject, Mobject):
            point = point_or_mobject.get_center()
        else:
            point = point_or_mobject
        self.look(point - self.eyes.get_center())
        return self

    def change(self, new_mode, look_at_arg=None):
        self.change_mode(new_mode)
        if look_at_arg is not None:
            self.look_at(look_at_arg)
        return self

    def get_looking_direction(self):
        vect = self.pupils.get_center() - self.eyes.get_center()
        return normalize(vect)

    def get_look_at_spot(self):
        return self.eyes.get_center() + self.get_looking_direction()

    def is_flipped(self):
        return self.eyes.submobjects[0].get_center()[0] > \
            self.eyes.submobjects[1].get_center()[0]

    def blink(self):
        eye_parts = self.eye_parts
        eye_bottom_y = eye_parts.get_bottom()[1]
        eye_parts.apply_function(lambda p: [p[0], eye_bottom_y, p[2]])
        return self

    def to_corner(self, vect=None, **kwargs):
        if vect is not None:
            SVGMobject.to_corner(self, vect, **kwargs)
        else:
            self.scale(self.corner_scale_factor)
            self.to_corner(DOWN + LEFT, **kwargs)
        return self

    def get_bubble(self, *content, **kwargs):
        bubble_class = kwargs.get("bubble_class", ThoughtBubble)
        bubble = bubble_class(**kwargs)
        if len(content) > 0:
            if isinstance(content[0], str):
                content_mob = TextMobject(*content)
            else:
                content_mob = content[0]
            bubble.add_content(content_mob)
            if "height" not in kwargs and "width" not in kwargs:
                bubble.resize_to_content()
        bubble.pin_to(self)
        self.bubble = bubble
        return bubble

    def make_eye_contact(self, pi_creature):
        self.look_at(pi_creature.eyes)
        pi_creature.look_at(self.eyes)
        return self

    def shrug(self):
        self.change_mode("shruggie")
        top_mouth_point, bottom_mouth_point = [
            self.mouth.points[np.argmax(self.mouth.points[:, 1])],
            self.mouth.points[np.argmin(self.mouth.points[:, 1])]
        ]
        self.look(top_mouth_point - bottom_mouth_point)
        return self

    def get_arm_copies(self):
        body = self.body
        return VGroup(*[
            body.copy().pointwise_become_partial(body, *alpha_range)
            for alpha_range in (self.right_arm_range, self.left_arm_range)
        ])
Example #35
0
 def get_arm_copies(self):
     body = self.body
     return VGroup(*[
         body.copy().pointwise_become_partial(body, *alpha_range)
         for alpha_range in (self.right_arm_range, self.left_arm_range)
     ])
 def get_axis_labels(self, x_label_tex="x", y_label_tex="y"):
     self.axis_labels = VGroup(
         self.get_x_axis_label(x_label_tex),
         self.get_y_axis_label(y_label_tex),
     )
     return self.axis_labels
Example #37
0
class Arrow(Line):
    CONFIG = {
        "tip_length": 0.25,
        "tip_width_to_length_ratio": 1,
        "max_tip_length_to_length_ratio": 0.35,
        "max_stem_width_to_tip_width_ratio": 0.3,
        "buff": MED_SMALL_BUFF,
        "propagate_style_to_family": False,
        "preserve_tip_size_when_scaling": True,
        "normal_vector": OUT,
        "use_rectangular_stem": True,
        "rectangular_stem_width": 0.05,
    }

    def __init__(self, *args, **kwargs):
        points = list(map(self.pointify, args))
        if len(args) == 1:
            args = (points[0] + UP + LEFT, points[0])
        Line.__init__(self, *args, **kwargs)
        self.init_tip()
        if self.use_rectangular_stem and not hasattr(self, "rect"):
            self.add_rectangular_stem()
        self.init_colors()

    def init_tip(self):
        self.add_tip()

    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

    def add_rectangular_stem(self):
        self.rect = Rectangle(
            stroke_width=0,
            fill_color=self.tip.get_fill_color(),
            fill_opacity=self.tip.get_fill_opacity()
        )
        self.add_to_back(self.rect)
        self.set_stroke(width=0)
        self.set_rectangular_stem_points()

    def set_rectangular_stem_points(self):
        start, end = self.get_start_and_end()
        tip_base_points = self.tip[0].get_anchors()[1:3]
        tip_base = center_of_mass(tip_base_points)
        tbp1, tbp2 = tip_base_points
        perp_vect = tbp2 - tbp1
        tip_base_width = get_norm(perp_vect)
        if tip_base_width > 0:
            perp_vect /= tip_base_width
        width = min(
            self.rectangular_stem_width,
            self.max_stem_width_to_tip_width_ratio * tip_base_width,
        )
        if hasattr(self, "second_tip"):
            start = center_of_mass(
                self.second_tip.get_anchors()[1:]
            )
        self.rect.set_points_as_corners([
            tip_base - perp_vect * width / 2,
            start - perp_vect * width / 2,
            start + perp_vect * width / 2,
            tip_base + perp_vect * width / 2,
        ])
        self.stem = self.rect  # Alternate name
        return self

    def set_tip_points(
        self, tip,
        add_at_end=True,
        tip_length=None,
        preserve_normal=True,
    ):
        if tip_length is None:
            tip_length = self.tip_length
        if preserve_normal:
            normal_vector = self.get_normal_vector()
        else:
            normal_vector = self.normal_vector
        line_length = get_norm(self.points[-1] - self.points[0])
        tip_length = min(
            tip_length, self.max_tip_length_to_length_ratio * line_length
        )

        indices = (-2, -1) if add_at_end else (1, 0)
        pre_end_point, end_point = [
            self.get_anchors()[index]
            for index in indices
        ]
        vect = end_point - pre_end_point
        perp_vect = np.cross(vect, normal_vector)
        for v in vect, perp_vect:
            if get_norm(v) == 0:
                v[0] = 1
            v *= tip_length / get_norm(v)
        ratio = self.tip_width_to_length_ratio
        tip.set_points_as_corners([
            end_point,
            end_point - vect + perp_vect * ratio / 2,
            end_point - vect - perp_vect * ratio / 2,
        ])

        return self

    def get_normal_vector(self):
        p0, p1, p2 = self.tip[0].get_anchors()[:3]
        result = np.cross(p2 - p1, p1 - p0)
        norm = get_norm(result)
        if norm == 0:
            return self.normal_vector
        else:
            return result / norm

    def reset_normal_vector(self):
        self.normal_vector = self.get_normal_vector()
        return self

    def get_end(self):
        if hasattr(self, "tip"):
            return self.tip[0].get_anchors()[0]
        else:
            return Line.get_end(self)

    def get_tip(self):
        return self.tip

    def put_start_and_end_on(self, *args, **kwargs):
        Line.put_start_and_end_on(self, *args, **kwargs)
        self.set_tip_points(self.tip[0], preserve_normal=False)
        self.set_rectangular_stem_points()
        return self

    def scale(self, scale_factor, **kwargs):
        Line.scale(self, scale_factor, **kwargs)
        if self.preserve_tip_size_when_scaling:
            for t in self.tip:
                self.set_tip_points(t, add_at_end=t.add_at_end)
        if self.use_rectangular_stem:
            self.set_rectangular_stem_points()
        return self

    def copy(self):
        return self.deepcopy()
Example #38
0
 def get_pis(self):
     return VGroup(Randolph(color=BLUE_E, mode="pondering"),
                   Randolph(color=BLUE_D, mode="hooray"),
                   Randolph(color=BLUE_C, mode="sassy"),
                   Mortimer(color=GREY_BROWN, mode="thinking"))
Example #39
0
 def get_labels(self):
     return VGroup(*(self.numeral_labels.submobjects + self.alphabetical_labels.submobjects))
Example #40
0
    def add_spikes(self):
        layers = VGroup()
        radii = np.linspace(
            self.outer_radius,
            self.pupil_radius,
            self.n_spike_layers,
            endpoint=False,
        )
        radii[:2] = radii[1::-1]  # Swap first two
        if self.n_spike_layers > 2:
            radii[-1] = interpolate(radii[-1], self.pupil_radius, 0.25)

        for radius in radii:
            tip_angle = self.spike_angle
            half_base = radius * np.tan(tip_angle)
            triangle, right_half_triangle = [
                Polygon(
                    radius * UP,
                    half_base * RIGHT,
                    vertex3,
                    fill_opacity=1,
                    stroke_width=0,
                ) for vertex3 in (
                    half_base * LEFT,
                    ORIGIN,
                )
            ]
            left_half_triangle = right_half_triangle.copy()
            left_half_triangle.flip(UP, about_point=ORIGIN)

            n_spikes = self.n_spikes
            full_spikes = [
                triangle.copy().rotate(-angle, about_point=ORIGIN)
                for angle in np.linspace(0, TAU, n_spikes, endpoint=False)
            ]
            index = (3 * n_spikes) // 4
            if radius == radii[0]:
                layer = VGroup(*full_spikes)
                layer.rotate(-TAU / n_spikes / 2, about_point=ORIGIN)
                layer.brown_index = index
            else:
                half_spikes = [
                    right_half_triangle.copy(),
                    left_half_triangle.copy().rotate(
                        90 * DEGREES,
                        about_point=ORIGIN,
                    ),
                    right_half_triangle.copy().rotate(
                        90 * DEGREES,
                        about_point=ORIGIN,
                    ),
                    left_half_triangle.copy()
                ]
                layer = VGroup(*it.chain(
                    half_spikes[:1],
                    full_spikes[1:index],
                    half_spikes[1:3],
                    full_spikes[index + 1:],
                    half_spikes[3:],
                ))
                layer.brown_index = index + 1

            layers.add(layer)

        # Color spikes
        blues = self.blue_spike_colors
        browns = self.brown_spike_colors
        for layer, blue, brown in zip(layers, blues, browns):
            index = layer.brown_index
            layer[:index].set_color(blue)
            layer[index:].set_color(brown)

        self.spike_layers = layers
        self.add(layers)
Example #41
0
 def get_lights(self):
     return VGroup(self.get_front_light(), self.get_rear_light())
Example #42
0
 def create_pi_creatures(self):
     """
     Likely updated for subclasses
     """
     return VGroup(self.create_pi_creature())
Example #43
0
 def get_basis_vectors(self, i_hat_color=X_COLOR, j_hat_color=Y_COLOR):
     return VGroup(*[
         Vector(
             vect, color=color, stroke_width=self.basis_vector_stroke_width)
         for vect, color in [([1, 0], i_hat_color), ([0, 1], j_hat_color)]
     ])
Example #44
0
    def scroll_through_patrons(self):
        logo_box = Square(side_length=2.5)
        logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF)
        total_width = FRAME_X_RADIUS - logo_box.get_right()[0]

        black_rect = Rectangle(
            fill_color=BLACK,
            fill_opacity=1,
            stroke_width=3,
            stroke_color=BLACK,
            width=FRAME_WIDTH,
            height=0.6 * FRAME_HEIGHT,
        )
        black_rect.to_edge(UP, buff=0)
        line = DashedLine(FRAME_X_RADIUS * LEFT, FRAME_X_RADIUS * RIGHT)
        line.move_to(ORIGIN)

        thanks = TextMobject(self.thanks_words)
        thanks.scale(0.9)
        thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF)
        thanks.set_color(YELLOW)
        underline = Line(LEFT, RIGHT)
        underline.match_width(thanks)
        underline.scale(1.1)
        underline.next_to(thanks, DOWN, SMALL_BUFF)
        thanks.add(underline)

        changed_patron_names = map(
            self.modify_patron_name,
            self.specific_patrons,
        )
        patrons = VGroup(*map(
            TextMobject,
            changed_patron_names,
        ))
        patrons.scale(self.patron_scale_val)
        for patron in patrons:
            if patron.get_width() > self.max_patron_width:
                patron.set_width(self.max_patron_width)
        columns = VGroup(*[
            VGroup(*patrons[i::self.n_patron_columns])
            for i in range(self.n_patron_columns)
        ])
        for column in columns:
            for n, name in enumerate(column):
                name.shift(n * self.name_y_spacing * DOWN)
        columns.arrange(
            RIGHT, buff=LARGE_BUFF,
            aligned_edge=UP,
        )
        max_width = FRAME_WIDTH - 1
        if columns.get_width() > max_width:
            columns.set_width(max_width)
        underline.match_width(columns)
        # thanks.to_edge(RIGHT, buff=MED_SMALL_BUFF)
        columns.next_to(underline, DOWN, buff=2)

        columns.generate_target()
        columns.target.to_edge(DOWN, buff=2)
        vect = columns.target.get_center() - columns.get_center()
        distance = get_norm(vect)
        wait_time = 20
        always_shift(
            columns,
            direction=normalize(vect),
            rate=(distance / wait_time)
        )

        self.add(columns, black_rect, line, thanks)
        self.wait(wait_time)
class Axes(VGroup, CoordinateSystem):
    CONFIG = {
        "axis_config": {
            "include_tip": True,
            "numbers_to_exclude": [0],
        },
        "x_axis_config": {},
        "y_axis_config": {
            "line_to_number_direction": LEFT,
        },
        "height": FRAME_HEIGHT - 2,
        "width": FRAME_WIDTH - 2,
    }

    def __init__(self, x_range=None, y_range=None, **kwargs):
        super().__init__(**kwargs)
        if x_range is not None:
            self.x_range[:len(x_range)] = x_range
        if y_range is not None:
            self.y_range[:len(y_range)] = y_range

        self.x_axis = self.create_axis(
            self.x_range,
            self.x_axis_config,
            self.width,
        )
        self.y_axis = self.create_axis(self.y_range, self.y_axis_config,
                                       self.height)
        self.y_axis.rotate(90 * DEGREES, about_point=ORIGIN)
        # Add as a separate group in case various other
        # mobjects are added to self, as for example in
        # NumberPlane below
        self.axes = VGroup(self.x_axis, self.y_axis)
        self.add(*self.axes)
        self.center()

    def create_axis(self, range_terms, axis_config, length):
        new_config = merge_dicts_recursively(self.axis_config, axis_config)
        new_config["width"] = length
        axis = NumberLine(range_terms, **new_config)
        axis.shift(-axis.n2p(0))
        return axis

    def coords_to_point(self, *coords):
        origin = self.x_axis.number_to_point(0)
        result = origin.copy()
        for axis, coord in zip(self.get_axes(), coords):
            result += (axis.number_to_point(coord) - origin)
        return result

    def point_to_coords(self, point):
        return tuple([axis.point_to_number(point) for axis in self.get_axes()])

    def get_axes(self):
        return self.axes

    def get_all_ranges(self):
        return [self.x_range, self.y_range]

    def add_coordinate_labels(self, x_values=None, y_values=None, **kwargs):
        axes = self.get_axes()
        self.coordinate_labels = VGroup()
        for axis, values in zip(axes, [x_values, y_values]):
            labels = axis.add_numbers(values, **kwargs)
            self.coordinate_labels.add(labels)
        return self.coordinate_labels
Example #46
0
 def g_to_mobjects(self, g_element):
     mob = VGroup(*self.get_mobjects_from(g_element))
     self.handle_transforms(g_element, mob)
     return mob.submobjects
Example #47
0
class NumberLine(Line):
    CONFIG = {
        "color": GREY_B,
        "stroke_width": 2,
        # List of 2 or 3 elements, x_min, x_max, step_size
        "x_range": [-8, 8, 1],
        # How big is one one unit of this number line in terms of absolute spacial distance
        "unit_size": 1,
        "width": None,
        "include_ticks": True,
        "tick_size": 0.1,
        "longer_tick_multiple": 1.5,
        "tick_offset": 0,
        # Change name
        "numbers_with_elongated_ticks": [],
        "include_numbers": False,
        "line_to_number_direction": DOWN,
        "line_to_number_buff": MED_SMALL_BUFF,
        "include_tip": False,
        "tip_config": {
            "width": 0.25,
            "length": 0.25,
        },
        "decimal_number_config": {
            "num_decimal_places": 0,
            "font_size": 36,
        },
        "numbers_to_exclude": None
    }

    def __init__(self, x_range=None, **kwargs):
        digest_config(self, kwargs)
        if x_range is None:
            x_range = self.x_range
        if len(x_range) == 2:
            x_range = [*x_range, 1]

        x_min, x_max, x_step = x_range
        # A lot of old scenes pass in x_min or x_max explicitly,
        # so this is just here to keep those workin
        self.x_min = kwargs.get("x_min", x_min)
        self.x_max = kwargs.get("x_max", x_max)
        self.x_step = kwargs.get("x_step", x_step)

        super().__init__(self.x_min * RIGHT, self.x_max * RIGHT, **kwargs)
        if self.width:
            self.set_width(self.width)
        else:
            self.scale(self.unit_size)
        self.center()

        if self.include_tip:
            self.add_tip()
            self.tip.set_stroke(
                self.stroke_color,
                self.stroke_width,
            )
        if self.include_ticks:
            self.add_ticks()
        if self.include_numbers:
            self.add_numbers(excluding=self.numbers_to_exclude)

    def get_tick_range(self):
        if self.include_tip:
            x_max = self.x_max
        else:
            x_max = self.x_max + self.x_step
        return np.arange(self.x_min, x_max, self.x_step)

    def add_ticks(self):
        ticks = VGroup()
        for x in self.get_tick_range():
            size = self.tick_size
            if x in self.numbers_with_elongated_ticks:
                size *= self.longer_tick_multiple
            ticks.add(self.get_tick(x, size))
        self.add(ticks)
        self.ticks = ticks

    def get_tick(self, x, size=None):
        if size is None:
            size = self.tick_size
        result = Line(size * DOWN, size * UP)
        result.rotate(self.get_angle())
        result.move_to(self.number_to_point(x))
        result.match_style(self)
        return result

    def get_tick_marks(self):
        return self.ticks

    def number_to_point(self, number):
        alpha = float(number - self.x_min) / (self.x_max - self.x_min)
        return interpolate(self.get_start(), self.get_end(), alpha)

    def point_to_number(self, point):
        start, end = self.get_start_and_end()
        unit_vect = normalize(end - start)
        proportion = fdiv(
            np.dot(point - start, unit_vect),
            np.dot(end - start, unit_vect),
        )
        return interpolate(self.x_min, self.x_max, proportion)

    def n2p(self, number):
        """Abbreviation for number_to_point"""
        return self.number_to_point(number)

    def p2n(self, point):
        """Abbreviation for point_to_number"""
        return self.point_to_number(point)

    def get_unit_size(self):
        return (self.x_max - self.x_min) / self.get_length()

    def get_number_mobject(self, x,
                           number_config=None,
                           direction=None,
                           buff=None):
        if number_config is None:
            number_config = {}
        number_config = merge_dicts_recursively(
            self.decimal_number_config, number_config
        )
        if direction is None:
            direction = self.line_to_number_direction
        if buff is None:
            buff = self.line_to_number_buff

        num_mob = DecimalNumber(x, **number_config)
        num_mob.next_to(
            self.number_to_point(x),
            direction=direction,
            buff=buff
        )
        if x < 0 and self.line_to_number_direction[0] == 0:
            # Align without the minus sign
            num_mob.shift(num_mob[0].get_width() * LEFT / 2)
        return num_mob

    def add_numbers(self, x_values=None, excluding=None, **kwargs):
        if x_values is None:
            x_values = self.get_tick_range()
        if excluding is not None:
            x_values = list_difference_update(x_values, excluding)

        self.numbers = VGroup()
        for x in x_values:
            self.numbers.add(self.get_number_mobject(x, **kwargs))
        self.add(self.numbers)
        return self.numbers
Example #48
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 #49
0
    def create_eyes(self, mode=None, thing_to_look_at=None):
        if mode is None:
            mode = self.mode
        if thing_to_look_at is None:
            thing_to_look_at = self.thing_to_look_at
        self.thing_to_look_at = thing_to_look_at
        self.mode = mode
        looking_direction = None

        pi = PiCreature(mode=mode)
        eyes = VGroup(pi.eyes, pi.pupils)
        if self.submobjects:
            eyes.match_height(self)
            eyes.move_to(self, DOWN)
            looking_direction = self[1].get_center() - self[0].get_center()
        else:
            eyes.set_height(self.height)
            eyes.move_to(self.body.get_top(), DOWN)

        height = eyes.get_height()
        if thing_to_look_at is not None:
            pi.look_at(thing_to_look_at)
        elif looking_direction is not None:
            pi.look(looking_direction)
        eyes.set_height(height)

        return eyes
Example #50
0
    def get_secant_slope_group(
        self,
        x,
        graph,
        dx=None,
        dx_line_color=None,
        df_line_color=None,
        dx_label=None,
        df_label=None,
        include_secant_line=True,
        secant_line_color=None,
        secant_line_length=10,
    ):
        """
        Resulting group is of the form VGroup(
            dx_line,
            df_line,
            dx_label, (if applicable)
            df_label, (if applicable)
            secant_line, (if applicable)
        )
        with attributes of those names.
        """
        kwargs = locals()
        kwargs.pop("self")
        group = VGroup()
        group.kwargs = kwargs

        dx = dx or float(self.x_max - self.x_min) / 10
        dx_line_color = dx_line_color or self.default_input_color
        df_line_color = df_line_color or graph.get_color()

        p1 = self.input_to_graph_point(x, graph)
        p2 = self.input_to_graph_point(x + dx, graph)
        interim_point = p2[0] * RIGHT + p1[1] * UP

        group.dx_line = Line(p1, interim_point, color=dx_line_color)
        group.df_line = Line(interim_point, p2, color=df_line_color)
        group.add(group.dx_line, group.df_line)

        labels = VGroup()
        if dx_label is not None:
            group.dx_label = TexMobject(dx_label)
            labels.add(group.dx_label)
            group.add(group.dx_label)
        if df_label is not None:
            group.df_label = TexMobject(df_label)
            labels.add(group.df_label)
            group.add(group.df_label)

        if len(labels) > 0:
            max_width = 0.8 * group.dx_line.get_width()
            max_height = 0.8 * group.df_line.get_height()
            if labels.get_width() > max_width:
                labels.set_width(max_width)
            if labels.get_height() > max_height:
                labels.set_height(max_height)

        if dx_label is not None:
            group.dx_label.next_to(group.dx_line,
                                   np.sign(dx) * DOWN,
                                   buff=group.dx_label.get_height() / 2)
            group.dx_label.set_color(group.dx_line.get_color())

        if df_label is not None:
            group.df_label.next_to(group.df_line,
                                   np.sign(dx) * RIGHT,
                                   buff=group.df_label.get_height() / 2)
            group.df_label.set_color(group.df_line.get_color())

        if include_secant_line:
            secant_line_color = secant_line_color or self.default_derivative_color
            group.secant_line = Line(p1, p2, color=secant_line_color)
            group.secant_line.scale_in_place(secant_line_length /
                                             group.secant_line.get_length())
            group.add(group.secant_line)

        return group
    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):
        """
        This method returns the VGroup() of the Riemann Rectangles for
        a particular curve.

        Parameters
        ----------
        graph (ParametricFunction)
            The graph whose area needs to be approximated
            by the Riemann Rectangles.

        x_min Union[int,float]
            The lower bound from which to start adding rectangles

        x_max Union[int,float]
            The upper bound where the rectangles stop.

        dx Union[int,float]
            The smallest change in x-values that is 
            considered significant.

        input_sample_type str
            Can be any of "left", "right" or "center

        stroke_width : Union[int, float]
            The stroke_width of the border of the rectangles.

        stroke_color : str
            The string of hex colour of the rectangle's border.

        fill_opacity Union[int, float]
            The opacity of the rectangles.

        start_color : str,
            The hex starting colour for the rectangles,
            this will, if end_color is a different colour,
            make a nice gradient.

        end_color : str,
            The hex ending colour for the rectangles,
            this will, if start_color is a different colour,
            make a nice gradient.

        show_signed_area : bool (True)
            Whether or not to indicate -ve area if curve dips below
            x-axis.

        width_scale_factor : Union[int, float]
            How much the width of the rectangles are scaled by when transforming.

        Returns
        -------
        VGroup
            A VGroup containing the Riemann Rectangles.

        """
        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
Example #52
0
 def get_columns(self):
     return VGroup(*[
         VGroup(*[row[i] for row in self.mob_matrix])
         for i in range(len(self.mob_matrix[0]))
     ])
    def get_secant_slope_group(
        self,
        x,
        graph,
        dx=None,
        dx_line_color=None,
        df_line_color=None,
        dx_label=None,
        df_label=None,
        include_secant_line=True,
        secant_line_color=None,
        secant_line_length=10,
    ):
        """
        This method returns a VGroup of (two lines 
        representing dx and df, the labels for dx and 
        df, and the Secant to the Graph/curve at a 
        particular x value.

        Parameters
        ----------
        x (Union[float, int])
            The x value at which the secant enters, and intersects
            the graph for the first time.

        graph (ParametricFunction)
            The curve/graph for which the secant must
            be found.

        dx (Union[float, int])
            The change in x after which the secant exits.

        dx_line_color (str)
            The line color for the line that indicates the change in x.

        df_line_color (str)
            The line color for the line that indicates the change in y.

        dx_label (str)
            The label to be provided for the change in x.

        df_label (str)
            The label to be provided for the change in y.

        include_secant_line (bool=True)
            Whether or not to include the secant line in the graph,
            or just have the df and dx lines and labels.

        secant_line_color (str)
            The color of the secant line.

        secant_line_length (Union[float,int=10])
            How long the secant line should be.

        Returns:
        --------
        VGroup
            Resulting group is of the form VGroup(
                dx_line,
                df_line,
                dx_label, (if applicable)
                df_label, (if applicable)
                secant_line, (if applicable)
            )
            with attributes of those names.
        """
        kwargs = locals()
        kwargs.pop("self")
        group = VGroup()
        group.kwargs = kwargs

        dx = dx or float(self.x_max - self.x_min) / 10
        dx_line_color = dx_line_color or self.default_input_color
        df_line_color = df_line_color or graph.get_color()

        p1 = self.input_to_graph_point(x, graph)
        p2 = self.input_to_graph_point(x + dx, graph)
        interim_point = p2[0] * RIGHT + p1[1] * UP

        group.dx_line = Line(p1, interim_point, color=dx_line_color)
        group.df_line = Line(interim_point, p2, color=df_line_color)
        group.add(group.dx_line, group.df_line)

        labels = VGroup()
        if dx_label is not None:
            group.dx_label = TexMobject(dx_label)
            labels.add(group.dx_label)
            group.add(group.dx_label)
        if df_label is not None:
            group.df_label = TexMobject(df_label)
            labels.add(group.df_label)
            group.add(group.df_label)

        if len(labels) > 0:
            max_width = 0.8 * group.dx_line.get_width()
            max_height = 0.8 * group.df_line.get_height()
            if labels.get_width() > max_width:
                labels.set_width(max_width)
            if labels.get_height() > max_height:
                labels.set_height(max_height)

        if dx_label is not None:
            group.dx_label.next_to(group.dx_line,
                                   np.sign(dx) * DOWN,
                                   buff=group.dx_label.get_height() / 2)
            group.dx_label.set_color(group.dx_line.get_color())

        if df_label is not None:
            group.df_label.next_to(group.df_line,
                                   np.sign(dx) * RIGHT,
                                   buff=group.df_label.get_height() / 2)
            group.df_label.set_color(group.df_line.get_color())

        if include_secant_line:
            secant_line_color = secant_line_color or self.default_derivative_color
            group.secant_line = Line(p1, p2, color=secant_line_color)
            group.secant_line.scale_in_place(secant_line_length /
                                             group.secant_line.get_length())
            group.add(group.secant_line)

        return group
Example #54
0
 def get_number_mobjects(self, *numbers, **kwargs):
     if len(numbers) == 0:
         numbers = self.default_numbers_to_display()
     return VGroup(
         *[self.get_number_mobject(number, **kwargs) for number in numbers])
    def get_animation_integral_bounds_change(self,
                                             graph,
                                             new_t_min,
                                             new_t_max,
                                             fade_close_to_origin=True,
                                             run_time=1.0):
        """
        This method requires a lot of prerequisites:
        self.area must be defined from self.get_area()
        self.left_v_line and self.right_v_line must be defined from self.get_v_line
        self.left_T_label_group and self.right_T_label_group must be defined from self.add_T_label

        This method will returna VGroup of new mobjects for each of those, when provided the graph/curve,
        the new t_min and t_max, the run_time and a bool stating whether or not to fade when close to
        the origin.

        Parameters
        ----------
        graph (ParametricFunction)
            The graph for which this must be done.

        new_t_min (Union[int,float])
            The new lower bound.

        new_t_max (Union[int,float])
            The new upper bound.

        fade_close_to_origin (bool=True)
            Whether or not to fade when close to the origin.

        run_time (Union[int,float=1.0])
            The run_time of the animation of this change.
        """
        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)
Example #56
0
 def get_tick_marks(self):
     return VGroup(
         *self.tick_marks,
         *self.big_tick_marks,
     )
Example #57
0
 def setup(self):
     self.pi_creatures = VGroup(*self.create_pi_creatures())
     self.pi_creature = self.get_primary_pi_creature()
     if self.pi_creatures_start_on_screen:
         self.add(*self.pi_creatures)
Example #58
0
 def get_piece_movement(self, pieces):
     start = VGroup(*pieces)
     target = VGroup(*[mob.target for mob in pieces])
     if self.leave_ghost_vectors:
         self.add(start.copy().fade(0.7))
     return Transform(start, target, lag_ratio=0)
Example #59
0
 def get_on_screen_pi_creatures(self):
     mobjects = self.get_mobject_family_members()
     return VGroup(
         *[pi for pi in self.get_pi_creatures() if pi in mobjects])
Example #60
0
 def get_tires(self):
     return VGroup(self[1][0], self[1][1])