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)
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)
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
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 __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)
def get_student_changes(self, *modes, **kwargs): pairs = zip(self.get_students(), modes) pairs = [(s, m) for s, m in pairs if m is not None] start = VGroup(*[s for s, m in pairs]) target = VGroup(*[s.copy().change_mode(m) for s, m in pairs]) if "look_at_arg" in kwargs: for pi in target: pi.look_at(kwargs["look_at_arg"]) submobject_mode = kwargs.get("submobject_mode", "lagged_start") return Transform(start, target, submobject_mode=submobject_mode, run_time=2)
def construct(self): morty = Mortimer() morty.next_to(ORIGIN, DOWN) patreon_logo = PatreonLogo() patreon_logo.to_edge(UP) n_patrons = len(self.specific_patrons) patrons = map(TextMobject, self.specific_patrons) num_groups = float(len(patrons)) / self.max_patron_group_size proportion_range = np.linspace(0, 1, num_groups + 1) indices = (len(patrons)*proportion_range).astype('int') patron_groups = [ VGroup(*patrons[i:j]) for i, j in zip(indices, indices[1:]) ] for i, group in enumerate(patron_groups): left_group = VGroup(*group[:len(group)/2]) right_group = VGroup(*group[len(group)/2:]) for subgroup, vect in (left_group, LEFT), (right_group, RIGHT): subgroup.arrange_submobjects(DOWN, aligned_edge = LEFT) subgroup.scale(self.patron_scale_val) subgroup.to_edge(vect) last_group = None for i, group in enumerate(patron_groups): anims = [] if last_group is not None: self.play( FadeOut(last_group), morty.look, UP+LEFT ) else: anims += [ DrawBorderThenFill(patreon_logo), ] self.play( LaggedStart( FadeIn, group, run_time = 2, ), morty.change, "gracious", group.get_corner(UP+LEFT), *anims ) self.play(morty.look_at, group.get_corner(DOWN+LEFT)) self.play(morty.look_at, group.get_corner(UP+RIGHT)) self.play(morty.look_at, group.get_corner(DOWN+RIGHT)) self.play(Blink(morty)) last_group = group
def setup(self): self.dots = VGroup() self.number = 0 self.max_place = 0 self.number_mob = VGroup(TexMobject(str(self.number))) self.number_mob.scale(self.num_scale_factor) self.number_mob.shift(self.num_start_location) self.dot_templates = [] self.dot_template_iterators = [] self.curr_configurations = [] self.arrows = VGroup() self.add(self.number_mob)
def get_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
def increment(self, run_time_per_anim = 1): moving_dot = Dot( self.counting_dot_starting_position, radius = self.count_dot_starting_radius, color = self.digit_place_colors[0], ) moving_dot.generate_target() moving_dot.set_fill(opacity = 0) kwargs = { "run_time" : run_time_per_anim } continue_rolling_over = True first_move = True place = 0 while continue_rolling_over: added_anims = [] if first_move: added_anims += self.get_digit_increment_animations() first_move = False moving_dot.target.replace( self.dot_template_iterators[place].next() ) self.play(MoveToTarget(moving_dot), *added_anims, **kwargs) self.curr_configurations[place].add(moving_dot) if len(self.curr_configurations[place].split()) == self.get_place_max(place): full_configuration = self.curr_configurations[place] self.curr_configurations[place] = VGroup() place += 1 center = full_configuration.get_center_of_mass() radius = 0.6*max( full_configuration.get_width(), full_configuration.get_height(), ) circle = Circle( radius = radius, stroke_width = 0, fill_color = self.digit_place_colors[place], fill_opacity = 0.5, ) circle.move_to(center) moving_dot = VGroup(circle, full_configuration) moving_dot.generate_target() moving_dot[0].set_fill(opacity = 0) else: continue_rolling_over = False
def setup(self): self.pi_creatures = VGroup( *self.create_pi_creatures(**self.default_pi_creature_kwargs) ) self.pi_creature = self.get_primary_pi_creature() if self.pi_creatures_start_on_screen: self.add(*self.pi_creatures)
def get_coordinate_labels(self, *numbers): # TODO: Should merge this with the code from NumberPlane.get_coordinate_labels result = VGroup() nudge = 0.1*(DOWN+RIGHT) if len(numbers) == 0: numbers = range(-int(self.x_radius), int(self.x_radius)+1) numbers += [ complex(0, y) for y in range(-int(self.y_radius), int(self.y_radius)+1) ] for number in numbers: if number == complex(0, 0): continue point = self.number_to_point(number) num_str = str(number).replace("j", "i") if num_str.startswith("0"): num_str = "0" elif num_str in ["1i", "-1i"]: num_str = num_str.replace("1", "") num_mob = TexMobject(num_str) num_mob.add_background_rectangle() num_mob.scale_to_fit_height(self.written_coordinate_height) num_mob.next_to(point, DOWN+LEFT, SMALL_BUFF) result.add(num_mob) self.coordinate_labels = result return result
def 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) left_patrons = VGroup( *map(TextMobject, self.specific_patrons[:n_patrons / 2])) right_patrons = VGroup( *map(TextMobject, self.specific_patrons[n_patrons / 2:])) for patrons in left_patrons, right_patrons: patrons.arrange_submobjects(DOWN, aligned_edge=LEFT, buff=1.5 * MED_SMALL_BUFF) all_patrons = VGroup(left_patrons, right_patrons) all_patrons.scale(0.7) for patrons, vect in (left_patrons, LEFT), (right_patrons, RIGHT): patrons.to_corner(UP + vect, buff=MED_SMALL_BUFF) shift_distance = max(0, 1 - SPACE_HEIGHT - all_patrons.get_bottom()[1]) velocity = shift_distance / 9.0 def get_shift_anim(): return ApplyMethod(all_patrons.shift, velocity * UP, rate_func=None) self.play( morty.change_mode, "gracious", DrawBorderThenFill(patreon_logo), ) self.play(Write(special_thanks, run_time=1)) self.play(Write(left_patrons), morty.look_at, left_patrons) self.play(Write(right_patrons), morty.look_at, right_patrons) self.play(Blink(morty), get_shift_anim()) for patrons in left_patrons, right_patrons: for index in 0, -1: self.play(morty.look_at, patrons[index], get_shift_anim()) self.play(get_shift_anim())
def add_configuration(self): new_template = self.get_dot_template(len(self.dot_templates)) new_template.move_to(self.ones_configuration_location) left_vect = (new_template.get_width() + LARGE_BUFF) * LEFT new_template.shift(left_vect * len(self.dot_templates)) self.dot_templates.append(new_template) self.dot_template_iterators.append(it.cycle(new_template)) self.curr_configurations.append(VGroup())
def scroll_through_patrons(self): logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) total_width = SPACE_WIDTH - logo_box.get_right()[0] black_rect = Rectangle(fill_color=BLACK, fill_opacity=1, stroke_width=0, width=2 * SPACE_WIDTH, height=1.1 * SPACE_HEIGHT) black_rect.to_edge(UP, buff=0) line = DashedLine(SPACE_WIDTH * LEFT, SPACE_WIDTH * RIGHT) line.move_to(black_rect, DOWN) line.shift(SMALL_BUFF * SMALL_BUFF * DOWN) self.add(line) patrons = VGroup(*map(TextMobject, self.specific_patrons)) patrons.scale(self.patron_scale_val) for patron in patrons: if patron.get_width() > self.max_patron_width: patron.scale_to_fit_width(self.max_patron_width) columns = VGroup(*[ VGroup(*patrons[i::self.n_patron_columns]).arrange_submobjects( DOWN, buff=MED_SMALL_BUFF) for i in range(self.n_patron_columns) ]) columns.arrange_submobjects( RIGHT, buff=LARGE_BUFF, aligned_edge=UP, ) columns.scale_to_fit_width(total_width - 1) columns.next_to(black_rect, DOWN, 3 * LARGE_BUFF) columns.to_edge(RIGHT) self.play( columns.next_to, SPACE_HEIGHT * DOWN, UP, LARGE_BUFF, columns.to_edge, RIGHT, Animation(black_rect), rate_func=None, run_time=self.run_time, )
def get_transformer(self, **kwargs): transform_kwargs = dict(self.default_apply_complex_function_kwargs) transform_kwargs.update(kwargs) plane = self.plane self.prepare_for_transformation(plane) transformer = VGroup( plane, *self.transformable_mobjects ) return transformer, transform_kwargs
def add_background_rectangle(self): #TODO, is this the best way to handle #background rectangles? self.background_rectangle = BackgroundRectangle(self) self.submobjects = [ self.background_rectangle, VGroup(*self.submobjects) ] return self
def get_corner_numbers(self, value, symbol): value_mob = TextMobject(value) width = self.get_width() / self.card_width_to_corner_num_width height = self.get_height() / self.card_height_to_corner_num_height value_mob.scale_to_fit_width(width) value_mob.stretch_to_fit_height(height) value_mob.next_to(self.get_corner(UP + LEFT), DOWN + RIGHT, buff=MED_LARGE_BUFF * width) value_mob.set_color(symbol.get_color()) corner_symbol = symbol.copy() corner_symbol.scale_to_fit_width(width) corner_symbol.next_to(value_mob, DOWN, buff=MED_SMALL_BUFF * width) corner_group = VGroup(value_mob, corner_symbol) opposite_corner_group = corner_group.copy() opposite_corner_group.rotate(np.pi, about_point=self.get_center()) return VGroup(corner_group, opposite_corner_group)
def get_basis_vector_labels(self, **kwargs): i_hat, j_hat = self.get_basis_vectors() return VGroup(*[ self.get_vector_label( vect, label, color=color, label_scale_factor=1, **kwargs) for vect, label, color in [ (i_hat, "\\hat{\\imath}", X_COLOR), (j_hat, "\\hat{\\jmath}", Y_COLOR), ] ])
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))
def construct(self): logo = MirekOlsakLogo(self.camera) series_title = TextMobject(self.series_str).to_edge(UP) self.add(series_title) chapter_title = TextMobject(self.chapter_str) chapter_title.scale(1.4) self.play(Write(chapter_title)) self.play(ShowCreation(logo)) self.dither(self.dither_time) self.play(FadeOut(VGroup(series_title, chapter_title, logo)))
def generate_points(self): random.seed(self.random_seed) modes = get_all_pi_creature_modes() seed = PiCreature(mode=self.start_mode) seed.scale_to_fit_height(self.height) seed.to_edge(DOWN) creatures = [seed] self.add(VGroup(seed)) for x in range(self.order): new_creatures = [] for creature in creatures: for eye, vect in zip(creature.eyes, [LEFT, RIGHT]): new_creature = PiCreature(mode=random.choice(modes)) new_creature.scale_to_fit_height(self.scale_val * eye.get_height()) new_creature.next_to(eye, vect, buff=0, aligned_edge=DOWN) new_creatures.append(new_creature) creature.look_at(random.choice(new_creatures)) self.add_to_back(VGroup(*new_creatures)) creatures = new_creatures
def add_title(self): title = self.title = TextMobject("Clicky Stuffs") title.scale(1.5) title.to_edge(UP, buff=MED_SMALL_BUFF) randy, morty = self.pi_creatures = VGroup(Randolph(), Mortimer()) for pi, vect in (randy, LEFT), (morty, RIGHT): pi.scale_to_fit_height(title.get_height()) pi.change_mode("thinking") pi.look(DOWN) pi.next_to(title, vect, buff=MED_LARGE_BUFF) self.add_foreground_mobjects(title, randy, morty)
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
def get_order_n_self(self, order): if order == 0: result = self.get_seed_shape() else: lower_order = self.get_order_n_self(order - 1) subparts = [lower_order.copy() for x in range(self.num_subparts)] self.arrange_subparts(*subparts) result = VGroup(*subparts) result.scale_to_fit_height(self.height) result.center() return result
def arrange_subparts(self, *subparts): for i, piece in enumerate(subparts): piece.rotate(i * np.pi / 12, about_point=ORIGIN) p1, p2, p3, p4, p5, p6, p7 = subparts center_row = VGroup(p1, p4, p7) center_row.arrange_submobjects(RIGHT, buff=0) for p in p2, p3, p5, p6: p.scale_to_fit_width(p1.get_width()) p2.move_to(p1.get_top(), DOWN + LEFT) p3.move_to(p1.get_bottom(), UP + LEFT) p5.move_to(p4.get_top(), DOWN + LEFT) p6.move_to(p4.get_bottom(), UP + LEFT)
def get_vertical_lines_to_graph(self, graph, x_min=None, x_max=None, num_lines=20, **kwargs): x_min = x_min or self.x_min x_max = x_max or self.x_max return VGroup(*[ self.get_vertical_line_to_graph(x, graph, **kwargs) for x in np.linspace(x_min, x_max, num_lines) ])
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() labels = 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) 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) y_axis.add(ticks) self.add(x_axis, y_axis, labels) self.x_axis, self.y_axis = x_axis, y_axis self.y_axis_labels = labels
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)
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))