Ejemplo n.º 1
0
class PartyHat(SVGMobject):
    CONFIG = {
        "file_name" : "party_hat",
        "height" : 1.5,
        "pi_creature" : None,
        "stroke_width" : 0,
        "fill_opacity" : 1,
        "propogate_style_to_family" : True,
        "frills_colors" : [MAROON_B, PURPLE],
        "cone_color" : GREEN,
        "dots_colors" : [YELLOW],
    }
    NUM_FRILLS = 7
    NUM_DOTS = 6
    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.scale_to_fit_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff = 0)

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

        self.frills.gradient_highlight(*self.frills_colors)
        self.cone.highlight(self.cone_color)
        self.dots.gradient_highlight(*self.dots_colors)
Ejemplo n.º 2
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)
Ejemplo n.º 3
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)
Ejemplo n.º 4
0
class PartyHat(SVGMobject):
    CONFIG = {
        "file_name" : "party_hat",
        "height" : 1.5,
        "pi_creature" : None,
        "stroke_width" : 0,
        "fill_opacity" : 1,
        "propagate_style_to_family" : True,
        "frills_colors" : [MAROON_B, PURPLE],
        "cone_color" : GREEN,
        "dots_colors" : [YELLOW],
    }
    NUM_FRILLS = 7
    NUM_DOTS = 6
    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.scale_to_fit_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff = 0)

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

        self.frills.set_color_by_gradient(*self.frills_colors)
        self.cone.set_color(self.cone_color)
        self.dots.set_color_by_gradient(*self.dots_colors)
Ejemplo n.º 5
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_submobjects()
     self.scale_to_fit_width(2*SPACE_WIDTH-MED_LARGE_BUFF)
     self.gradient_highlight(*self.gradient_colors)
Ejemplo n.º 6
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_submobjects()
     self.scale_to_fit_width(2 * SPACE_WIDTH - MED_LARGE_BUFF)
     self.gradient_highlight(*self.gradient_colors)
Ejemplo n.º 7
0
 def __init__(self, integer, **kwargs):
     num_str = str(integer)
     VGroup.__init__(self, *map(TexMobject, num_str), **kwargs)
     self.arrange_submobjects(
         RIGHT, buff = self.digit_buff, aligned_edge = DOWN
     )
     if num_str[0] == "-":
         self[0].next_to(self[1], LEFT, buff = SMALL_BUFF)
Ejemplo n.º 8
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()
Ejemplo n.º 9
0
 def __init__(self, integer, **kwargs):
     num_str = str(integer)
     VGroup.__init__(self, *map(TexMobject, num_str), **kwargs)
     self.arrange_submobjects(RIGHT,
                              buff=self.digit_buff,
                              aligned_edge=DOWN)
     if num_str[0] == "-":
         self[0].next_to(self[1], LEFT, buff=SMALL_BUFF)
Ejemplo n.º 10
0
 def __init__(self, **kwargs):
     possible_values = map(str, range(1, 11)) + ["J", "Q", "K"]
     possible_suits = ["hearts", "diamonds", "spades", "clubs"]
     VGroup.__init__(self, *[
         PlayingCard(value = value, suit = suit, **kwargs)
         for value in possible_values
         for suit in possible_suits
     ])
Ejemplo n.º 11
0
 def __init__(self, **kwargs):
     possible_values = map(str, range(1, 11)) + ["J", "Q", "K"]
     possible_suits = ["hearts", "diamonds", "spades", "clubs"]
     VGroup.__init__(self, *[
         PlayingCard(value = value, suit = suit, **kwargs)
         for value in possible_values
         for suit in possible_suits
     ])
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
 def generate_points(self):
     self.main_line = Line(self.x_min * RIGHT, self.x_max * RIGHT)
     self.tick_marks = VGroup()
     self.add(self.main_line, self.tick_marks)
     for x in self.get_tick_numbers():
         self.add_tick(x, self.tick_size)
     for x in self.numbers_with_elongated_ticks:
         self.add_tick(x, self.longer_tick_multiple * self.tick_size)
     self.stretch(self.unit_size, 0)
     self.shift(-self.number_to_point(self.number_at_center))
Ejemplo n.º 14
0
 def change_student_modes(self, *modes, **kwargs):
     added_anims = kwargs.get("added_anims", [])
     pairs = zip(self.get_students(), modes)
     start = VGroup(*[s for s, m in pairs])
     target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
     self.play(
         Transform(start,
                   target,
                   submobject_mode="lagged_start",
                   run_time=2), *added_anims)
Ejemplo n.º 15
0
    def setup_axes(self, animate=False):
        x_num_range = float(self.x_max - self.x_min)
        self.space_unit_to_x = self.x_axis_width / x_num_range
        self.x_labeled_nums = self.x_labeled_nums or []
        x_axis = NumberLine(x_min=self.x_min,
                            x_max=self.x_max,
                            space_unit_to_num=self.space_unit_to_x,
                            tick_frequency=self.x_tick_frequency,
                            leftmost_tick=self.x_leftmost_tick or self.x_min,
                            numbers_with_elongated_ticks=self.x_labeled_nums,
                            color=self.axes_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 = filter(lambda x: x != 0,
                                             self.x_labeled_nums)
            x_axis.add_numbers(*self.x_labeled_nums)
        x_label = TextMobject(self.x_axis_label)
        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
        self.y_labeled_nums = self.y_labeled_nums or []
        y_axis = NumberLine(x_min=self.y_min,
                            x_max=self.y_max,
                            space_unit_to_num=self.space_unit_to_y,
                            tick_frequency=self.y_tick_frequency,
                            leftmost_tick=self.y_bottom_tick or self.y_min,
                            numbers_with_elongated_ticks=self.y_labeled_nums,
                            color=self.axes_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 = filter(lambda y: y != 0,
                                             self.y_labeled_nums)
            y_axis.add_numbers(*self.y_labeled_nums)
            for mob in y_axis.numbers:
                mob.next_to(mob.get_center(), LEFT, MED_SMALL_BUFF)
                mob.shift(self.y_axis_numbers_nudge)
        y_label = TextMobject(self.y_axis_label)
        y_label.next_to(y_axis.get_tick_marks(), 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)
Ejemplo n.º 16
0
 def __init__(self, **kwargs):
     VGroup.__init__(self, **kwargs)
     self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config)
     self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config)
     self.y_axis.rotate(np.pi/2)
     self.add(self.x_axis, self.y_axis)
     if self.three_d:
         self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config)
         self.z_axis.rotate(-np.pi/2, UP)
         self.z_axis.rotate(angle_of_vector(self.z_normal), OUT)
         self.add(self.z_axis)
Ejemplo n.º 17
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.parts_named = True
Ejemplo n.º 18
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.parts_named = True
Ejemplo n.º 19
0
 def get_number_mobjects(self, *numbers, **kwargs):
     #TODO, handle decimals
     if len(numbers) == 0:
         numbers = self.default_numbers_to_display()
     result = VGroup()
     for number in numbers:
         mob = TexMobject(str(int(number)))
         mob.scale_to_fit_height(3 * self.tick_size)
         mob.shift(self.number_to_point(number),
                   self.get_vertical_number_offset(**kwargs))
         result.add(mob)
     return result
Ejemplo n.º 20
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_submobjects(RIGHT, buff=0)
     for p in p2, p3, p5, p6:
         p.scale_to_fit_width(p1.get_width())
     p2.move_to(p1.get_top(), DOWN + LEFT)
     p3.move_to(p1.get_bottom(), UP + LEFT)
     p5.move_to(p4.get_top(), DOWN + LEFT)
     p6.move_to(p4.get_bottom(), UP + LEFT)
Ejemplo n.º 21
0
 def arrange_subparts(self, *subparts):
     for i, piece in enumerate(subparts):
         piece.rotate(i*np.pi/12)
     p1, p2, p3, p4, p5, p6, p7 = subparts
     center_row = VGroup(p1, p4, p7)
     center_row.arrange_submobjects(RIGHT, buff = 0)
     for p in p2, p3, p5, p6:
         p.scale_to_fit_width(p1.get_width())
     p2.move_to(p1.get_top(), DOWN+LEFT)
     p3.move_to(p1.get_bottom(), UP+LEFT)
     p5.move_to(p4.get_top(), DOWN+LEFT)
     p6.move_to(p4.get_bottom(), UP+LEFT)
Ejemplo n.º 22
0
 def get_student_changes(self, *modes, **kwargs):
     pairs = zip(self.get_students(), modes)
     pairs = [(s, m) for s, m in pairs if m is not None]
     start = VGroup(*[s for s, m in pairs])
     target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
     if "look_at_arg" in kwargs:
         for pi in target:
             pi.look_at(kwargs["look_at_arg"])
     submobject_mode = kwargs.get("submobject_mode", "lagged_start")
     return Transform(start,
                      target,
                      submobject_mode=submobject_mode,
                      run_time=2)
Ejemplo n.º 23
0
    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.scale_to_fit_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff=0)

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

        self.frills.gradient_highlight(*self.frills_colors)
        self.cone.highlight(self.cone_color)
        self.dots.gradient_highlight(*self.dots_colors)
Ejemplo n.º 24
0
    def __init__(self, **kwargs):
        SVGMobject.__init__(self, **kwargs)
        self.scale_to_fit_height(self.height)
        if self.pi_creature is not None:
            self.next_to(self.pi_creature.eyes, UP, buff = 0)

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

        self.frills.gradient_highlight(*self.frills_colors)
        self.cone.highlight(self.cone_color)
        self.dots.gradient_highlight(*self.dots_colors)
Ejemplo n.º 25
0
 def get_dot_template(self, place):
     #This should be replaced for non-base-10 counting scenes
     down_right = (0.5) * RIGHT + (np.sqrt(3) / 2) * DOWN
     dots = VGroup(*[
         Dot(
             point,
             radius=0.25,
             fill_opacity=0,
             stroke_width=2,
             stroke_color=WHITE,
         ) for point in self.get_template_configuration(place)
     ])
     dots.scale_to_fit_height(self.dot_configuration_height)
     return dots
Ejemplo n.º 26
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
Ejemplo n.º 27
0
    def construct(self):
        morty = Mortimer()
        morty.next_to(ORIGIN, DOWN)

        patreon_logo = PatreonLogo()
        patreon_logo.to_edge(UP)

        n_patrons = len(self.specific_patrons)
        patrons = map(TextMobject, self.specific_patrons)
        num_groups = float(len(patrons)) / self.max_patron_group_size
        proportion_range = np.linspace(0, 1, num_groups + 1)
        indices = (len(patrons)*proportion_range).astype('int')
        patron_groups = [
            VGroup(*patrons[i:j])
            for i, j in zip(indices, indices[1:])
        ]        

        for i, group in enumerate(patron_groups):
            left_group = VGroup(*group[:len(group)/2])
            right_group = VGroup(*group[len(group)/2:])
            for subgroup, vect in (left_group, LEFT), (right_group, RIGHT):
                subgroup.arrange_submobjects(DOWN, aligned_edge = LEFT)
                subgroup.scale(self.patron_scale_val)
                subgroup.to_edge(vect)

        last_group = None
        for i, group in enumerate(patron_groups):
            anims = []
            if last_group is not None:
                self.play(
                    FadeOut(last_group),
                    morty.look, UP+LEFT
                )
            else:
                anims += [
                    DrawBorderThenFill(patreon_logo),
                ]
            self.play(
                LaggedStart(
                    FadeIn, group, 
                    run_time = 2,
                ),
                morty.change, "gracious", group.get_corner(UP+LEFT),
                *anims
            )
            self.play(morty.look_at, group.get_corner(DOWN+LEFT))
            self.play(morty.look_at, group.get_corner(UP+RIGHT))
            self.play(morty.look_at, group.get_corner(DOWN+RIGHT))
            self.play(Blink(morty))
            last_group = group
Ejemplo n.º 28
0
    def generate_points(self):
        body = Cube(side_length = 1)
        for dim, scale_factor in enumerate(self.body_dimensions):
            body.stretch(scale_factor, dim = dim)
        body.scale_to_fit_width(self.width)
        body.set_fill(self.shaded_body_color, opacity = 1)
        body.sort_submobjects(lambda p : p[2])
        body[-1].set_fill(self.body_color)
        keyboard = VGroup(*[
            VGroup(*[
                Square(**self.key_color_kwargs)
                for x in range(12-y%2)
            ]).arrange_submobjects(RIGHT, buff = SMALL_BUFF)
            for y in range(4)
        ]).arrange_submobjects(DOWN, buff = MED_SMALL_BUFF)
        keyboard.stretch_to_fit_width(
            self.keyboard_width_to_body_width*body.get_width(),
        )
        keyboard.stretch_to_fit_height(
            self.keyboard_height_to_body_height*body.get_height(),
        )
        keyboard.next_to(body, OUT, buff = 0.1*SMALL_BUFF)
        keyboard.shift(MED_SMALL_BUFF*UP)
        body.add(keyboard)

        screen_plate = body.copy()
        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)
        self.rotate(np.pi/6, DOWN)
Ejemplo n.º 29
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.highlight(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
Ejemplo n.º 30
0
    def create_pi_creatures(self):
        self.teacher = Mortimer()
        self.teacher.to_corner(DOWN + RIGHT)
        self.teacher.look(DOWN + LEFT)
        self.students = VGroup(
            *[Randolph(color=c) for c in self.student_colors])
        self.students.arrange_submobjects(RIGHT)
        self.students.scale(self.student_scale_factor)
        self.students.to_corner(DOWN + LEFT)
        self.teacher.look_at(self.students[-1].eyes)
        for student in self.students:
            student.look_at(self.teacher.eyes)

        return [self.teacher] + list(self.students)
Ejemplo n.º 31
0
 def get_number_mobjects(self, *numbers, **kwargs):
     #TODO, handle decimals
     if len(numbers) == 0:
         numbers = self.default_numbers_to_display()
     result = VGroup()
     for number in numbers:
         mob = TexMobject(str(int(number)))
         mob.scale_to_fit_height(3*self.tick_size)
         mob.shift(
             self.number_to_point(number),
             self.get_vertical_number_offset(**kwargs)
         )
         result.add(mob)
     return result
Ejemplo n.º 32
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.scale_to_fit_width(self.tick_width)
            tick.move_to(y*UP)
            ticks.add(tick)
        y_axis.add(ticks)

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

        if self.label_y_axis:
            labels = VGroup()
            for tick, value in zip(ticks, values):
                label = TexMobject(str(np.round(value, 2)))
                label.scale_to_fit_height(self.y_axis_label_height)
                label.next_to(tick, LEFT, SMALL_BUFF)
                labels.add(label)
            self.y_axis_labels = labels
            self.add(labels)
Ejemplo n.º 33
0
    def construct(self):
        morty = Mortimer()
        morty.next_to(ORIGIN, DOWN)

        n_patrons = len(self.specific_patrons)
        special_thanks = TextMobject("Special thanks")
        special_thanks.highlight(YELLOW)
        special_thanks.to_edge(UP)

        patreon_logo = PatreonLogo()
        patreon_logo.next_to(morty, UP, buff=MED_LARGE_BUFF)

        patrons = map(TextMobject, self.specific_patrons)
        patron_groups = []
        index = 0
        counter = 0
        while index < len(patrons):
            next_index = index + self.patron_group_size
            group = VGroup(*patrons[index:next_index])
            group.arrange_submobjects(DOWN, aligned_edge=LEFT)
            if counter % 2 == 0:
                group.to_edge(LEFT)
            else:
                group.to_edge(RIGHT)
            patron_groups.append(group)
            index = next_index
            counter += 1

        self.play(
            morty.change_mode,
            "gracious",
            DrawBorderThenFill(patreon_logo),
        )
        self.play(Write(special_thanks, run_time=1))
        for i, group in enumerate(patron_groups):
            anims = [
                FadeIn(
                    group,
                    run_time=2,
                    submobject_mode="lagged_start",
                    lag_factor=4,
                ),
                morty.look_at,
                group.get_top(),
            ]
            if i >= 2:
                anims.append(FadeOut(patron_groups[i - 2]))
            self.play(*anims)
            self.play(morty.look_at, group.get_bottom())
            self.play(Blink(morty))
Ejemplo n.º 34
0
 def change_student_modes(self, *modes, **kwargs):
     added_anims = kwargs.get("added_anims", [])
     pairs = zip(self.get_students(), modes)
     pairs = [(s, m) for s, m in pairs if m is not None]
     start = VGroup(*[s for s, m in pairs])
     target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
     if "look_at_arg" in kwargs:
         for pi in target:
             pi.look_at(kwargs["look_at_arg"])
     self.play(
         Transform(start,
                   target,
                   submobject_mode="lagged_start",
                   run_time=2), *added_anims)
Ejemplo n.º 35
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.scale_to_fit_height(self.height)
        result.center()
        return result
Ejemplo n.º 36
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)
Ejemplo n.º 37
0
 def get_axis_labels(self, x_label = "x", y_label = "y"):
     x_axis, y_axis = self.get_axes().split()
     quads = [
         (x_axis, x_label, UP, RIGHT),
         (y_axis, y_label, RIGHT, UP),
     ]
     labels = VGroup()
     for axis, tex, vect, edge in quads:
         label = TexMobject(tex)
         label.add_background_rectangle()
         label.next_to(axis, vect)
         label.to_edge(edge)
         labels.add(label)
     self.axis_labels = labels
     return labels
Ejemplo n.º 38
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)
Ejemplo n.º 39
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
Ejemplo n.º 40
0
    def __init__(self, **kwargs):
        circle = Circle()
        ticks = []
        for x in range(12):
            alpha = x / 12.
            point = complex_to_R3(np.exp(2 * np.pi * alpha * complex(0, 1)))
            length = 0.2 if x % 3 == 0 else 0.1
            ticks.append(Line(point, (1 - length) * point))
        self.hour_hand = Line(ORIGIN, 0.3 * UP)
        self.minute_hand = Line(ORIGIN, 0.6 * UP)
        # for hand in self.hour_hand, self.minute_hand:
        #     #Balance out where the center is
        #     hand.add(VectorizedPoint(-hand.get_end()))

        VGroup.__init__(self, circle, self.hour_hand, self.minute_hand, *ticks)
Ejemplo n.º 41
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.full_space.get_edge_center(-vect)
        parts = VGroup()
        for factor, color in zip(p_list, colors):
            part = SampleSpace()
            part.set_fill(color, 1)
            part.replace(self.full_space, stretch = True)
            part.stretch(factor, dim)
            part.move_to(last_point, -vect)
            last_point = part.get_edge_center(vect)
            parts.add(part)
        return parts
Ejemplo n.º 42
0
 def get_dot_template(self, place):
     #This should be replaced for non-base-10 counting scenes
     down_right = (0.5)*RIGHT + (np.sqrt(3)/2)*DOWN
     dots = VGroup(*[
         Dot(
             point, 
             radius = 0.25,
             fill_opacity = 0,
             stroke_width = 2,
             stroke_color = WHITE,
         )
         for point in self.get_template_configuration(place)
     ])
     dots.scale_to_fit_height(self.dot_configuration_height)
     return dots
Ejemplo n.º 43
0
 def get_axis_labels(self, x_label = "x", y_label = "y"):
     x_axis, y_axis = self.get_axes().split()
     quads = [
         (x_axis, x_label, UP, RIGHT),
         (y_axis, y_label, RIGHT, UP),
     ]
     labels = VGroup()
     for axis, tex, vect, edge in quads:
         label = TexMobject(tex)
         label.add_background_rectangle()
         label.next_to(axis, vect)
         label.to_edge(edge)
         labels.add(label)
     self.axis_labels = labels
     return labels
Ejemplo n.º 44
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
            else:
                raise Exception("Invalid input sample type")
            graph_point = self.input_to_graph_point(sample_input, graph)
            points = VGroup(*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
Ejemplo n.º 45
0
    def increment(self, run_time_per_anim = 1):
        moving_dot = Dot(
            self.counting_dot_starting_position,
            radius = self.count_dot_starting_radius,
            color = self.digit_place_colors[0],
        )
        moving_dot.generate_target()
        moving_dot.set_fill(opacity = 0)
        kwargs = {
            "run_time" : run_time_per_anim
        }

        continue_rolling_over = True
        first_move = True
        place = 0
        while continue_rolling_over:
            added_anims = []                
            if first_move:
                added_anims += self.get_digit_increment_animations()
                first_move = False
            moving_dot.target.replace(
                self.dot_template_iterators[place].next()
            )
            self.play(MoveToTarget(moving_dot), *added_anims, **kwargs)
            self.curr_configurations[place].add(moving_dot)


            if len(self.curr_configurations[place].split()) == self.get_place_max(place):
                full_configuration = self.curr_configurations[place]
                self.curr_configurations[place] = VGroup()
                place += 1
                center = full_configuration.get_center_of_mass()
                radius = 0.6*max(
                    full_configuration.get_width(),
                    full_configuration.get_height(),
                )
                circle = Circle(
                    radius = radius,
                    stroke_width = 0,
                    fill_color = self.digit_place_colors[place],
                    fill_opacity = 0.5,
                )
                circle.move_to(center)
                moving_dot = VGroup(circle, full_configuration)
                moving_dot.generate_target()
                moving_dot[0].set_fill(opacity = 0)
            else:
                continue_rolling_over = False
Ejemplo n.º 46
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
            else:
                raise Exception("Invalid input sample type")
            graph_point = self.input_to_graph_point(sample_input, graph)
            points = VGroup(*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
Ejemplo n.º 47
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.move_to(focal_point)
         circle.save_state()
         circle.scale_to_fit_width(self.small_radius * 2)
         circle.set_stroke(WHITE, 8)
         circles.add(circle)
     LaggedStart.__init__(self, ApplyMethod, circles, lambda c:
                          (c.restore, ), **kwargs)
Ejemplo n.º 48
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)
Ejemplo n.º 49
0
    def get_riemann_rectangles(
        self, 
        graph,
        x_min = None, 
        x_max = None, 
        dx = 0.1, 
        input_sample_type = "left",
        stroke_width = 1,
        start_color = BLUE,
        end_color = GREEN):
        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
        rectangles = VGroup()
        for x in np.arange(x_min, x_max, dx):
            if input_sample_type == "left":
                sample_input = x
            elif input_sample_type == "right":
                sample_input = x+dx
            else:
                raise Exception("Invalid input sample type")
            graph_point = self.input_to_graph_point(sample_input, graph)
            points = VGroup(*map(VectorizedPoint, [
                self.coords_to_point(x, 0),
                self.coords_to_point(x+dx, 0),
                graph_point
            ]))

            rect = Rectangle()
            rect.replace(points, stretch = True)
            rect.set_fill(opacity = 1)
            rectangles.add(rect)
        rectangles.gradient_highlight(start_color, end_color)
        rectangles.set_stroke(BLACK, width = stroke_width)
        return rectangles
Ejemplo n.º 50
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
Ejemplo n.º 51
0
    def __init__(self, **kwargs):
        circle = Circle()
        ticks = []
        for x in range(12):
            alpha = x/12.
            point = complex_to_R3(
                np.exp(2*np.pi*alpha*complex(0, 1))
            )
            length = 0.2 if x%3 == 0 else 0.1
            ticks.append(
                Line(point, (1-length)*point)
            )
        self.hour_hand = Line(ORIGIN, 0.3*UP)
        self.minute_hand = Line(ORIGIN, 0.6*UP)
        # for hand in self.hour_hand, self.minute_hand:
        #     #Balance out where the center is
        #     hand.add(VectorizedPoint(-hand.get_end()))

        VGroup.__init__(
            self, circle, 
            self.hour_hand, self.minute_hand,
            *ticks
        )
Ejemplo n.º 52
0
    def get_corner_numbers(self, value, symbol):
        value_mob = TextMobject(value)
        width = self.get_width()/self.card_width_to_corner_num_width
        height = self.get_height()/self.card_height_to_corner_num_height
        value_mob.scale_to_fit_width(width)
        value_mob.stretch_to_fit_height(height)
        value_mob.next_to(
            self.get_corner(UP+LEFT), DOWN+RIGHT,
            buff = MED_LARGE_BUFF*width
        )
        value_mob.highlight(symbol.get_color())
        corner_symbol = symbol.copy()
        corner_symbol.scale_to_fit_width(width)
        corner_symbol.next_to(
            value_mob, DOWN, 
            buff = MED_SMALL_BUFF*width
        )
        corner_group = VGroup(value_mob, corner_symbol)
        opposite_corner_group = corner_group.copy()
        opposite_corner_group.rotate(
            np.pi, about_point = self.get_center()
        )

        return VGroup(corner_group, opposite_corner_group)
Ejemplo n.º 53
0
    def create_pi_creatures(self):
        self.teacher = Mortimer()
        self.teacher.to_corner(DOWN + RIGHT)
        self.teacher.look(DOWN+LEFT)
        self.students = VGroup(*[
            Randolph(color = c)
            for c in self.student_colors
        ])
        self.students.arrange_submobjects(RIGHT)
        self.students.scale(self.student_scale_factor)
        self.students.to_corner(DOWN+LEFT)
        self.teacher.look_at(self.students[-1].eyes)
        for student in self.students:
            student.look_at(self.teacher.eyes)

        return [self.teacher] + list(self.students)
Ejemplo n.º 54
0
    def get_eyes(self, mode = None, thing_to_look_at = None):
        mode = mode or self.mode
        if thing_to_look_at is None:
            thing_to_look_at = self.thing_looked_at

        pi = Randolph(mode = mode)
        eyes = VGroup(pi.eyes, pi.pupils)
        eyes.scale_to_fit_height(self.height)
        if self.submobjects:
            eyes.move_to(self, DOWN)
        else:
            eyes.move_to(self.mobject.get_top(), DOWN)
        if thing_to_look_at is not None:
            pi.look_at(thing_to_look_at)
        return eyes
Ejemplo n.º 55
0
    def setup(self):
        self.teacher = Mortimer()
        self.teacher.to_corner(DOWN + RIGHT)
        self.teacher.look(DOWN+LEFT)
        self.students = VGroup(*[
            Randolph(color = c)
            for c in BLUE_D, BLUE_C, BLUE_E
        ])
        self.students.arrange_submobjects(RIGHT)
        self.students.scale(0.8)
        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)

        for pi_creature in self.get_everyone():
            pi_creature.bubble = None
        self.add(*self.get_everyone())
Ejemplo n.º 56
0
 def __init__(self, *args, **kwargs):
     PiCreature.__init__(self, *args, **kwargs)
     self.scale(self.scale_factor)
     self.shift(LEFT)
     self.to_edge(DOWN, buff = LARGE_BUFF)
     eyes = VGroup(self.eyes, self.pupils)
     eyes_bottom = eyes.get_bottom()
     eyes.scale(self.eye_scale_factor)
     eyes.move_to(eyes_bottom, aligned_edge = DOWN)
     looking_direction = self.get_looking_direction()
     for pupil in self.pupils:
         pupil.scale_in_place(self.pupil_scale_factor)
     self.look(looking_direction)
Ejemplo n.º 57
0
 def get_riemann_rectangles(self, 
                            x_min = None, 
                            x_max = None, 
                            dx = 0.1, 
                            stroke_width = 1,
                            start_color = BLUE,
                            end_color = GREEN):
     assert(hasattr(self, "func"))
     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
     rectangles = VGroup()
     for x in np.arange(x_min, x_max, dx):
         points = VGroup(*map(VectorizedPoint, [
             self.coords_to_point(x, 0),
             self.coords_to_point(x+dx, self.func(x+dx)),
         ]))
         rect = Rectangle()
         rect.replace(points, stretch = True)
         rect.set_fill(opacity = 1)
         rectangles.add(rect)
     rectangles.gradient_highlight(start_color, end_color)
     rectangles.set_stroke(BLACK, width = stroke_width)
     return rectangles
Ejemplo n.º 58
0
class TeacherStudentsScene(Scene):
    def setup(self):
        self.teacher = Mortimer()
        self.teacher.to_corner(DOWN + RIGHT)
        self.teacher.look(DOWN+LEFT)
        self.students = VGroup(*[
            Randolph(color = c)
            for c in BLUE_D, BLUE_C, BLUE_E
        ])
        self.students.arrange_submobjects(RIGHT)
        self.students.scale(0.8)
        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)

        for pi_creature in self.get_everyone():
            pi_creature.bubble = None
        self.add(*self.get_everyone())

    def get_teacher(self):
        return self.teacher

    def get_students(self):
        return self.students

    def get_everyone(self):
        return [self.get_teacher()] + list(self.get_students())

    def get_bubble_intro_animation(self, content, bubble_type,
                                   pi_creature,
                                   **bubble_kwargs):
        bubble = pi_creature.get_bubble(bubble_type, **bubble_kwargs)
        bubble.add_content(content)
        bubble.resize_to_content()
        if pi_creature.bubble:
            content_intro_anims = [
                Transform(pi_creature.bubble, bubble),
                Transform(pi_creature.bubble.content, bubble.content)
            ]
        else:
            content_intro_anims = [
                FadeIn(bubble),
                Write(content),
            ]
            pi_creature.bubble = bubble 
        return content_intro_anims

    def introduce_bubble(self, content, bubble_type, pi_creature,
                         target_mode = None,
                         added_anims = [],
                         **bubble_kwargs):
        if all(map(lambda s : isinstance(s, str), content)):
            content = TextMobject(*content)
        elif len(content) == 1 and isinstance(content[0], Mobject):
            content = content[0]
        else:
            raise Exception("Invalid content type")

        anims = []
        #Remove other bubbles
        for p in self.get_everyone():
            if (p.bubble is not None) and (p is not pi_creature):
                anims += [
                    FadeOut(p.bubble),
                    FadeOut(p.bubble.content)
                ]
                p.bubble = None
                anims.append(ApplyMethod(p.change_mode, "plain"))
        #Bring in new bubble
        anims += self.get_bubble_intro_animation(
            content, bubble_type, pi_creature, **bubble_kwargs
        )
        #Add changing mode
        if not target_mode:
            if bubble_type is "speech":
                target_mode = "speaking"
            else:
                target_mode = "pondering"
        anims.append(
            ApplyMethod(
                pi_creature.change_mode, 
                target_mode,
            )
        )
        self.play(*anims + added_anims)
        return pi_creature.bubble

    def teacher_says(self, *content, **kwargs):
        return self.introduce_bubble(
            content, "speech", self.get_teacher(), **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
        student = self.get_students()[kwargs.get("student_index", 1)]
        return self.introduce_bubble(content, "speech", student, **kwargs)

    def teacher_thinks(self, *content, **kwargs):
        return self.introduce_bubble(
            content, "thought", self.get_teacher(), **kwargs
        )

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

    def random_blink(self, num_times = 1):
        for x in range(num_times):
            pi_creature = random.choice(self.get_everyone())
            self.play(Blink(pi_creature))
            Scene.dither(self)

    def dither(self, time = 1):
        self.random_blink(num_times = max(time/2, 1))

    def change_student_modes(self, *modes, **kwargs):
        added_anims = kwargs.get("added_anims", [])
        pairs = zip(self.get_students(), modes)
        pairs = [(s, m) for s, m in pairs if m is not None]
        start = VGroup(*[s for s, m in pairs])
        target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
        self.play(
            Transform(
                start, target, 
                submobject_mode = "lagged_start",
                run_time = 2
            ),
            *added_anims
        )


    def zoom_in_on_thought_bubble(self, bubble = None, radius = SPACE_HEIGHT+SPACE_WIDTH):
        if bubble is None:
            for pi in self.get_everyone():
                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/np.linalg.norm(centered)
        self.play(*[
            ApplyPointwiseFunction(func, mob)
            for mob in self.get_mobjects()
        ])
Ejemplo n.º 59
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.scale_to_fit_width(max_width)
            if labels.get_height() > max_height:
                labels.scale_to_fit_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.highlight(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.highlight(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
Ejemplo n.º 60
0
class PiCreature(SVGMobject):
    CONFIG = {
        "color" : BLUE_E,
        "stroke_width" : 0,
        "fill_opacity" : 1.0,
        "initial_scale_factor" : 0.01,
        "corner_scale_factor" : 0.75,
        "flip_at_start" : False,
        "is_looking_direction_purposeful" : False,
        "start_corner" : None,
    }
    def __init__(self, mode = "plain", **kwargs):
        self.parts_named = False
        svg_file = os.path.join(
            PI_CREATURE_DIR, 
            "PiCreatures_%s.svg"%mode
        )
        digest_config(self, kwargs, locals())
        SVGMobject.__init__(self, file_name = svg_file, **kwargs)
        self.init_colors()
        if self.flip_at_start:
            self.flip()
        if self.start_corner is not None:
            self.to_corner(self.start_corner)

    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.submobjects = []
        self.add(self.body, self.mouth, self.eyes, self.pupils)
        self.parts_named = True

    def init_colors(self):
        self.set_stroke(color = BLACK, width = self.stroke_width)
        if not self.parts_named:
            self.name_parts()
        self.mouth.set_fill(BLACK, opacity = 1)
        self.body.set_fill(self.color, opacity = 1)
        self.pupils.set_fill(BLACK, opacity = 1)
        self.eyes.set_fill(WHITE, opacity = 1)
        return self


    def highlight(self, color):
        self.body.set_fill(color)
        return self

    def change_mode(self, mode):
        curr_eye_center = self.eyes.get_center()
        curr_height = self.get_height()
        should_be_flipped = self.is_flipped()
        should_look = hasattr(self, "purposeful_looking_direction")
        if should_look:
            looking_direction = self.purposeful_looking_direction
        self.__init__(mode)
        self.scale_to_fit_height(curr_height)
        self.shift(curr_eye_center - self.eyes.get_center())
        if should_be_flipped ^ self.is_flipped():
            self.flip()
        if should_look:
            self.look(looking_direction)
        return self

    def look(self, direction):
        direction = direction/np.linalg.norm(direction)
        self.purposeful_looking_direction = direction
        for pupil, eye in zip(self.pupils.split(), self.eyes.split()):
            pupil_radius = pupil.get_width()/2.
            eye_radius = eye.get_width()/2.
            pupil.move_to(eye)
            if direction[1] < 0:
                pupil.shift(pupil_radius*DOWN/3)
            pupil.shift(direction*(eye_radius-pupil_radius))
            bottom_diff = eye.get_bottom()[1] - pupil.get_bottom()[1]
            if bottom_diff > 0:
                pupil.shift(bottom_diff*UP)
            #TODO, how to handle looking up...
            # top_diff = eye.get_top()[1]-pupil.get_top()[1]
            # if top_diff < 0:
            #     pupil.shift(top_diff*UP)
        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 get_looking_direction(self):
        return np.sign(np.round(
            self.pupils.get_center() - self.eyes.get_center(),
            decimals = 2
        ))

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

    def blink(self):
        eye_bottom_y = self.eyes.get_bottom()[1]
        for mob in self.eyes, self.pupils:
            mob.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, bubble_type = "thought", **kwargs):
        #TODO, change bubble_type arg to have type Bubble
        if bubble_type == "thought":
            bubble = ThoughtBubble(**kwargs)
        elif bubble_type == "speech":
            bubble = SpeechBubble(**kwargs)
        else:
            raise Exception("%s is an invalid bubble type"%bubble_type)
        bubble.pin_to(self)
        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