def __init__(self, **kwargs): digest_config(self, kwargs) Rectangle.__init__( self, width=self.aspect_ratio * self.height, height=self.height, **kwargs )
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)
def add_bars(self, values): buff = float(self.width) / (2 * len(values) + 1) bars = VGroup() for i, value in enumerate(values): bar = Rectangle( height=(value / self.max_value) * self.height, width=buff, stroke_width=self.bar_stroke_width, fill_opacity=self.bar_fill_opacity, ) bar.move_to((2 * i + 1) * buff * RIGHT, DOWN + LEFT) bars.add(bar) bars.set_color_by_gradient(*self.bar_colors) bar_labels = VGroup() for bar, name in zip(bars, self.bar_names): label = TexMobject(str(name)) label.scale(self.bar_label_scale_val) label.next_to(bar, DOWN, SMALL_BUFF) bar_labels.add(label) self.add(bars, bar_labels) self.bars = bars self.bar_labels = bar_labels
def get_face_card_design(self, value, symbol): from for_3b1b_videos.pi_creature import PiCreature sub_rect = Rectangle( stroke_color=BLACK, fill_opacity=0, height=0.9 * self.get_height(), width=0.6 * self.get_width(), ) sub_rect.move_to(self) # pi_color = average_color(symbol.get_color(), GREY) pi_color = symbol.get_color() pi_mode = { "J": "plain", "Q": "thinking", "K": "hooray" }[value] pi_creature = PiCreature( mode=pi_mode, color=pi_color, ) pi_creature.set_width(0.8 * sub_rect.get_width()) if value in ["Q", "K"]: prefix = "king" if value == "K" else "queen" crown = SVGMobject(file_name=prefix + "_crown") crown.set_stroke(width=0) crown.set_fill(YELLOW, 1) crown.stretch_to_fit_width(0.5 * sub_rect.get_width()) crown.stretch_to_fit_height(0.17 * sub_rect.get_height()) crown.move_to(pi_creature.eyes.get_center(), DOWN) pi_creature.add_to_back(crown) to_top_buff = 0 else: to_top_buff = SMALL_BUFF * sub_rect.get_height() pi_creature.next_to(sub_rect.get_top(), DOWN, to_top_buff) # pi_creature.shift(0.05*sub_rect.get_width()*RIGHT) pi_copy = pi_creature.copy() pi_copy.rotate(np.pi, about_point=sub_rect.get_center()) return VGroup(sub_rect, pi_creature, pi_copy)
def rect_to_mobject(self, rect_element): fill_color = rect_element.getAttribute("fill") stroke_color = rect_element.getAttribute("stroke") stroke_width = rect_element.getAttribute("stroke-width") corner_radius = rect_element.getAttribute("rx") # input preprocessing if fill_color in ["", "none", "#FFF", "#FFFFFF"] or Color(fill_color) == Color(WHITE): opacity = 0 fill_color = BLACK # shdn't be necessary but avoids error msgs if fill_color in ["#000", "#000000"]: fill_color = WHITE if stroke_color in ["", "none", "#FFF", "#FFFFFF"] or Color(stroke_color) == Color(WHITE): stroke_width = 0 stroke_color = BLACK if stroke_color in ["#000", "#000000"]: stroke_color = WHITE if stroke_width in ["", "none", "0"]: stroke_width = 0 if corner_radius in ["", "0", "none"]: corner_radius = 0 corner_radius = float(corner_radius) if corner_radius == 0: mob = Rectangle( width=self.attribute_to_float( rect_element.getAttribute("width") ), height=self.attribute_to_float( rect_element.getAttribute("height") ), stroke_width=stroke_width, stroke_color=stroke_color, fill_color=fill_color, fill_opacity=opacity ) else: mob = RoundedRectangle( width=self.attribute_to_float( rect_element.getAttribute("width") ), height=self.attribute_to_float( rect_element.getAttribute("height") ), stroke_width=stroke_width, stroke_color=stroke_color, fill_color=fill_color, fill_opacity=opacity, corner_radius=corner_radius ) mob.shift(mob.get_center() - mob.get_corner(UP + LEFT)) return 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 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
def __init__(self, value: bool = True, **kwargs): digest_config(self, kwargs) self.box = Rectangle(**self.rect_kwargs) self.box_content = self.get_checkmark() if value else self.get_cross() super().__init__(value, self.box, self.box_content, **kwargs) self.add_mouse_press_listner(self.on_mouse_press)
def __init__(self, **kwargs): digest_config(self, kwargs) Rectangle.__init__(self, width=self.aspect_ratio * self.height, height=self.height, **kwargs)
def __init__(self, **kwargs): Rectangle.__init__(self, **kwargs) self.set_width(self.aspect_ratio * self.get_height(), stretch=True)
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 ): """ Riemman rectangles. Parameters ---------- graph : VMobject Graph from ``get_graph`` x_min : float TODO x_max : float TODO dx : float TODO input_sample_type : str Can be ``"left"``, ``"center"``, ``"right"`` """ 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
def construct(self): # Add title title = self.title = TextMobject("Clicky Stuffs") title.scale(1.5) title.to_edge(UP, buff=MED_SMALL_BUFF) pi_creatures = VGroup(Randolph(), Mortimer()) for pi, vect in zip(pi_creatures, [LEFT, RIGHT]): pi.set_height(title.get_height()) pi.change_mode("thinking") pi.look(DOWN) pi.next_to(title, vect, buff=MED_LARGE_BUFF) self.add(title, pi_creatures) # Set the top of the screen logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) 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) # Add thanks 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) # Build name list with open("manimlib/files/patrons.txt", 'r') as fp: names = [ self.modify_patron_name(name.strip()) for name in fp.readlines() ] if self.randomize_order: random.shuffle(names) else: names.sort() name_labels = VGroup(*map(TextMobject, names)) name_labels.scale(self.patron_scale_val) for label in name_labels: if label.get_width() > self.max_patron_width: label.set_width(self.max_patron_width) columns = VGroup(*[ VGroup(*name_labels[i::self.n_patron_columns]) for i in range(self.n_patron_columns) ]) column_x_spacing = 0.5 + max([c.get_width() for c in columns]) for i, column in enumerate(columns): for n, name in enumerate(column): name.shift(n * self.name_y_spacing * DOWN) name.align_to(ORIGIN, LEFT) column.move_to(i * column_x_spacing * RIGHT, UL) columns.center() max_width = FRAME_WIDTH - 1 if columns.get_width() > max_width: columns.set_width(max_width) underline.match_width(columns) columns.next_to(underline, DOWN, buff=3) # Set movement columns.generate_target() distance = columns.get_height() + 2 wait_time = self.scroll_time frame = self.camera.frame frame_shift = ApplyMethod( frame.shift, distance * DOWN, run_time=wait_time, rate_func=linear, ) blink_anims = [] blank_mob = Mobject() for x in range(wait_time): if random.random() < 0.25: blink_anims.append(Blink(random.choice(pi_creatures))) else: blink_anims.append(Animation(blank_mob)) blinks = Succession(*blink_anims) static_group = VGroup(black_rect, line, thanks, pi_creatures, title) static_group.fix_in_frame() self.add(columns, static_group) self.play(frame_shift, blinks)
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) patrons = VGroup(*list(map(TextMobject, self.specific_patrons))) 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, ) if columns.get_width() > self.max_patron_width: columns.set_width(total_width - 1) thanks.to_edge(RIGHT) columns.next_to(thanks, DOWN, 3 * LARGE_BUFF) columns.generate_target() columns.target.move_to(2 * DOWN, DOWN) columns.target.align_to(thanks, alignment_vect=RIGHT) 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)
def hist(self, x, bins=None, bin_range=None, density=None, weights=None, cumulative=False, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, normed=None, fill_opacity=None, stroke_width=None, **kwargs): if bins is None: bins = self.default_hist_bins if bin_range is None: bin_range = (min(x), max(x)) if density is None: density = self.default_hist_density if align == 'mid': align = ORIGIN elif align == 'right': align = RIGHT elif align == 'left': align = LEFT if rwidth is None: rwidth = self.default_hist_rwidth if color is None: color = it.cycle([next(self.default_graph_colors_cycle)]) else: if is_sequence(color): color = it.cycle(color) else: color = it.cycle([color]) if fill_opacity is None: fill_opacity = self.default_bar_opacity if stroke_width is None: stroke_width = self.default_bar_stroke_width data, bin_edges = np.histogram( x, bins=bins, range=bin_range, weights=weights, density=density, ) histogram = VGroup() for i in range(len(bin_edges) - 1): x0, y0, z0 = self.coords_to_point(bin_edges[i], 0) x1, y1, z1 = self.coords_to_point(bin_edges[i + 1], data[i]) bin_width = x1 - x0 bin_center = (x0, y0, z0) + bin_width / 2 * (RIGHT + align) bar_height = y1 - y0 bar_width = rwidth * bin_width bar = Rectangle( height=bar_height, width=bar_width, color=next(color), fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs, ).next_to(bin_center, UP, buff=0) histogram.add(bar) if hasattr(self, "hist_sequences") is False: self.hist_sequences = VGroup() self.hist_sequences.add(histogram) self.add(self.hist_sequences) return data, bin_edges, histogram
class ControlPanel(Group): CONFIG = { "panel_kwargs": { "width": FRAME_WIDTH / 4, "height": MED_SMALL_BUFF + FRAME_HEIGHT, "fill_color": GREY_C, "fill_opacity": 1.0, "stroke_width": 0.0 }, "opener_kwargs": { "width": FRAME_WIDTH / 8, "height": 0.5, "fill_color": GREY_C, "fill_opacity": 1.0 }, "opener_text_kwargs": { "text": "Control Panel", "font_size": 20 } } def __init__(self, *controls: ControlMobject, **kwargs): digest_config(self, kwargs) self.panel = Rectangle(**self.panel_kwargs) self.panel.to_corner(UP + LEFT, buff=0) self.panel.shift(self.panel.get_height() * UP) self.panel.add_mouse_scroll_listner(self.panel_on_mouse_scroll) self.panel_opener_rect = Rectangle(**self.opener_kwargs) self.panel_info_text = Text(**self.opener_text_kwargs) self.panel_info_text.move_to(self.panel_opener_rect) self.panel_opener = Group(self.panel_opener_rect, self.panel_info_text) self.panel_opener.next_to(self.panel, DOWN, aligned_edge=DOWN) self.panel_opener.add_mouse_drag_listner(self.panel_opener_on_mouse_drag) self.controls = Group(*controls) self.controls.arrange(DOWN, center=False, aligned_edge=ORIGIN) self.controls.move_to(self.panel) super().__init__( self.panel, self.panel_opener, self.controls, **kwargs ) self.move_panel_and_controls_to_panel_opener() self.fix_in_frame() def move_panel_and_controls_to_panel_opener(self) -> None: self.panel.next_to( self.panel_opener_rect, direction=UP, buff=0 ) controls_old_x = self.controls.get_x() self.controls.next_to( self.panel_opener_rect, direction=UP, buff=MED_SMALL_BUFF ) self.controls.set_x(controls_old_x) def add_controls(self, *new_controls: ControlMobject) -> None: self.controls.add(*new_controls) self.move_panel_and_controls_to_panel_opener() def remove_controls(self, *controls_to_remove: ControlMobject) -> None: self.controls.remove(*controls_to_remove) self.move_panel_and_controls_to_panel_opener() def open_panel(self): panel_opener_x = self.panel_opener.get_x() self.panel_opener.to_corner(DOWN + LEFT, buff=0.0) self.panel_opener.set_x(panel_opener_x) self.move_panel_and_controls_to_panel_opener() return self def close_panel(self): panel_opener_x = self.panel_opener.get_x() self.panel_opener.to_corner(UP + LEFT, buff=0.0) self.panel_opener.set_x(panel_opener_x) self.move_panel_and_controls_to_panel_opener() return self def panel_opener_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool: point = event_data["point"] self.panel_opener.match_y(Dot(point)) self.move_panel_and_controls_to_panel_opener() return False def panel_on_mouse_scroll(self, mob, event_data: dict[str, np.ndarray]) -> bool: offset = event_data["offset"] factor = 10 * offset[1] self.controls.set_y(self.controls.get_y() + factor) return False
class ColorSliders(Group): CONFIG = { "sliders_kwargs": {}, "rect_kwargs": { "width": 2.0, "height": 0.5, "stroke_opacity": 1.0 }, "background_grid_kwargs": { "colors": [GREY_A, GREY_C], "single_square_len": 0.1 }, "sliders_buff": MED_LARGE_BUFF, "default_rgb_value": 255, "default_a_value": 1, } def __init__(self, **kwargs): digest_config(self, kwargs) rgb_kwargs = {"value": self.default_rgb_value, "min_value": 0, "max_value": 255, "step": 1} a_kwargs = {"value": self.default_a_value, "min_value": 0, "max_value": 1, "step": 0.04} self.r_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.g_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.b_slider = LinearNumberSlider(**self.sliders_kwargs, **rgb_kwargs) self.a_slider = LinearNumberSlider(**self.sliders_kwargs, **a_kwargs) self.sliders = Group( self.r_slider, self.g_slider, self.b_slider, self.a_slider ) self.sliders.arrange(DOWN, buff=self.sliders_buff) self.r_slider.slider.set_color(RED) self.g_slider.slider.set_color(GREEN) self.b_slider.slider.set_color(BLUE) self.a_slider.slider.set_color_by_gradient([BLACK, WHITE]) self.selected_color_box = Rectangle(**self.rect_kwargs) self.selected_color_box.add_updater( lambda mob: mob.set_fill( self.get_picked_color(), self.get_picked_opacity() ) ) self.background = self.get_background() super().__init__( Group(self.background, self.selected_color_box).fix_in_frame(), self.sliders, **kwargs ) self.arrange(DOWN) def get_background(self) -> VGroup: single_square_len = self.background_grid_kwargs["single_square_len"] colors = self.background_grid_kwargs["colors"] width = self.rect_kwargs["width"] height = self.rect_kwargs["height"] rows = int(height / single_square_len) cols = int(width / single_square_len) cols = (cols + 1) if (cols % 2 == 0) else cols single_square = Square(single_square_len) grid = single_square.get_grid(n_rows=rows, n_cols=cols, buff=0.0) grid.stretch_to_fit_width(width) grid.stretch_to_fit_height(height) grid.move_to(self.selected_color_box) for idx, square in enumerate(grid): assert(isinstance(square, Square)) square.set_stroke(width=0.0, opacity=0.0) square.set_fill(colors[idx % len(colors)], 1.0) return grid def set_value(self, r: float, g: float, b: float, a: float): self.r_slider.set_value(r) self.g_slider.set_value(g) self.b_slider.set_value(b) self.a_slider.set_value(a) def get_value(self) -> np.ndarary: r = self.r_slider.get_value() / 255 g = self.g_slider.get_value() / 255 b = self.b_slider.get_value() / 255 alpha = self.a_slider.get_value() return color_to_rgba(rgb_to_color((r, g, b)), alpha=alpha) def get_picked_color(self) -> str: rgba = self.get_value() return rgb_to_hex(rgba[:3]) def get_picked_opacity(self) -> float: rgba = self.get_value() return rgba[3]
def construct(self): self._main_title() text_one = TextMobject("Given a list of items sold") text_two: TextMobject = TextMobject( "Randomly choose items matching this distribution") text_two.next_to(text_one, DOWN) number_line = NumberLine( numbers_with_elongated_ticks=[0, 1], include_numbers=True, x_min=0, x_max=1, unit_size=10, tick_frequency=0.1, # decimal_number_config={"num_decimal_places": 1}, numbers_to_show=[0, 1]) number_line.next_to(text_two, UP) self.play(ShowCreation(text_one)) self.wait() self.play(ShowCreation(text_two)) self.wait(4) apples_text = TextMobject("Apples:") apples_text.set_color(self._apple_colour) apples_text.to_edge(UP) apples_text.align_to(text_two, LEFT) apple_count_text = TextMobject(f"{self._apple_count}") apple_count_text.set_color(self._apple_colour) apple_count_text.next_to(apples_text, RIGHT) banana_text = TextMobject("Bananas:") banana_text.set_color(self._banana_colour) banana_text.next_to(apples_text, DOWN) banana_text.align_to(apples_text, LEFT) banana_count_text = TextMobject(f"{self._banana_count}") banana_count_text.set_color(self._banana_colour) banana_count_text.next_to(banana_text, RIGHT) self.play(Transform(text_one, apples_text)) self.play(ShowCreation(apple_count_text)) self.play(ShowCreation(banana_text), ShowCreation(banana_count_text)) banana_bar = Rectangle( height=0.4, width=number_line.point_to_number(self._banana_fraction * 10) * (number_line.number_to_point(1)[0]), color=self._banana_colour, fill_color=self._banana_colour, fill_opacity=0.75) banana_bar.next_to(banana_count_text, RIGHT + RIGHT) apple_bar = Rectangle( height=0.4, width=number_line.point_to_number(self._apple_fraction * 10) * (number_line.number_to_point(1)[0]), color=self._apple_colour, fill_color=self._apple_colour, fill_opacity=0.75) apple_bar.next_to(banana_bar, UP) apple_bar.align_to(banana_bar, LEFT) self.play(FadeIn(apple_bar), FadeIn(banana_bar)) self.wait(1.5) apple_fraction_text = TextMobject("$\\frac{" + str(self._apple_count) + "}{" + str(self._apple_count + self._banana_count) + "} = " + str(self._apple_fraction) + "$") apple_fraction_text.next_to(apple_bar, RIGHT) banana_fraction_text = TextMobject("$\\frac{" + str(self._banana_count) + "}{" + str(self._apple_count + self._banana_count) + "} = " + str(self._banana_fraction) + "$") banana_fraction_text.next_to(banana_bar, RIGHT) self.play(ShowCreation(apple_fraction_text)) self.play(ShowCreation(banana_fraction_text)) self.wait(2) number_line_map_text = TextMobject( "Map these counts to values between 0 and 1") number_line_map_text.next_to(text_two, UP) self.play(ShowCreation(number_line_map_text)) self.wait(3) self.play(Transform(number_line_map_text, number_line)) apple_num_ln_bar = Rectangle( height=0.4, # width=1 - self._apple_fraction * (number_line.number_to_point(1)[0]), width=number_line.point_to_number(self._apple_fraction * 10) * (number_line.number_to_point(1)[0]), color=self._apple_colour, fill_color=self._apple_colour, fill_opacity=0.25) apple_num_ln_bar.move_to(apple_bar, LEFT) self.add(apple_num_ln_bar) self.wait(2) self.play( ApplyMethod(apple_num_ln_bar.move_to, number_line.number_to_point(0), LEFT)) banana_num_ln_bar = Rectangle( height=0.4, width=number_line.point_to_number(self._banana_fraction * 10) * (number_line.number_to_point(1)[0]), color=self._banana_colour, fill_color=self._banana_colour, fill_opacity=0.25) banana_num_ln_bar.move_to(banana_bar, LEFT) self.add(banana_num_ln_bar) self.wait(2) self.play( ApplyMethod(banana_num_ln_bar.move_to, number_line.number_to_point(1), RIGHT)) text_scale: float = 0.75 get_rnd_full = TextMobject( "Get a random number $n$ between 0 and 1 (uniform distribution)") get_apple_text = TextMobject( f"Apple\\quad if $n <= {self._apple_fraction}$", tex_to_color_map={"Apple": self._apple_colour}) get_banana_text = TextMobject( f"Banana\\quad if $n > {self._apple_fraction}$", tex_to_color_map={"Banana": self._banana_colour}) get_rnd_full.scale(text_scale) get_rnd_full.next_to(text_two, DOWN) get_banana_text.next_to(get_apple_text, DOWN) step_group = VGroup(get_apple_text, get_banana_text) brace = Brace(step_group, LEFT) step_text_d = brace.get_text("$n \\sim U(0, 1)$") step_text_d.scale(text_scale) step_text_d.next_to(get_rnd_full, DOWN + DOWN) step_text_d.shift(LEFT) brace.next_to(step_text_d, RIGHT) step_group.scale(text_scale) step_group.next_to(step_text_d, RIGHT + RIGHT + RIGHT) self.wait(2) self.play(ShowCreation(get_rnd_full)) self.wait(2) self.play(ShowCreation(step_text_d)) self.wait(2) self.play(GrowFromCenter(brace)) self.wait() self.play(ShowCreation(get_apple_text)) self.wait(2) self.play(ShowCreation(get_banana_text)) # random_nos_to_draw = 10 # main_arrow = Arrow(ORIGIN, DOWN * 1.3) # helper_arrow = Arrow(ORIGIN, LEFT * 1.3) # # for i in range(random_nos_to_draw): # num: float = np.random.random_sample(1) # point = number_line.number_to_point(num) # arrow_colour = self._apple_colour if num <= self._apple_fraction else self._banana_colour # arrow_recipient = get_apple_text if num <= self._apple_fraction else get_banana_text # # main_arrow.set_color(arrow_colour) # # if i == 0: # main_arrow.next_to(point, UP) # helper_arrow.next_to(arrow_recipient, RIGHT) # self.play(GrowArrow(main_arrow), GrowArrow(helper_arrow)) # else: # self.play(ApplyMethod(helper_arrow.next_to, arrow_recipient, RIGHT), # ApplyMethod(main_arrow.next_to, point, UP)) # self.wait() # # self.play(FadeOut(main_arrow), FadeOut(helper_arrow)) self.wait()
def generate_points(self): self.width = self.width_to_height_ratio * self.height Rectangle.generate_points(self)
def __init__(self, **kwargs): Rectangle.__init__(self, **kwargs) self.set_width( self.aspect_ratio * self.get_height(), stretch=True )
class Textbox(ControlMobject): CONFIG = { "value_type": np.dtype(object), "box_kwargs": { "width": 2.0, "height": 1.0, "fill_color": WHITE, "fill_opacity": 1.0, }, "text_kwargs": { "color": BLUE }, "text_buff": MED_SMALL_BUFF, "isInitiallyActive": False, "active_color": BLUE, "deactive_color": RED, } def __init__(self, value: str = "", **kwargs): digest_config(self, kwargs) self.isActive = self.isInitiallyActive self.box = Rectangle(**self.box_kwargs) self.box.add_mouse_press_listner(self.box_on_mouse_press) self.text = Text(value, **self.text_kwargs) super().__init__(value, self.box, self.text, **kwargs) self.update_text(value) self.active_anim(self.isActive) self.add_key_press_listner(self.on_key_press) def set_value_anim(self, value: str) -> None: self.update_text(value) def update_text(self, value: str) -> None: text = self.text self.remove(text) text.__init__(value, **self.text_kwargs) height = text.get_height() text.set_width(self.box.get_width() - 2 * self.text_buff) if text.get_height() > height: text.set_height(height) text.add_updater(lambda mob: mob.move_to(self.box)) text.fix_in_frame() self.add(text) def active_anim(self, isActive: bool) -> None: if isActive: self.box.set_stroke(self.active_color) else: self.box.set_stroke(self.deactive_color) def box_on_mouse_press(self, mob, event_data) -> bool: self.isActive = not self.isActive self.active_anim(self.isActive) return False def on_key_press(self, mob: Mobject, event_data: dict[str, int]) -> bool | None: symbol = event_data["symbol"] modifiers = event_data["modifiers"] char = chr(symbol) if mob.isActive: old_value = mob.get_value() new_value = old_value if char.isalnum(): if (modifiers & PygletWindowKeys.MOD_SHIFT) or (modifiers & PygletWindowKeys.MOD_CAPSLOCK): new_value = old_value + char.upper() else: new_value = old_value + char.lower() elif symbol in [PygletWindowKeys.SPACE]: new_value = old_value + char elif symbol == PygletWindowKeys.TAB: new_value = old_value + '\t' elif symbol == PygletWindowKeys.BACKSPACE: new_value = old_value[:-1] or '' mob.set_value(new_value) return False
def scroll_through_patrons(self): logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) 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 = list( map( self.modify_patron_name, self.specific_patrons, )) changed_patron_names.sort() 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) ]) column_x_spacing = 0.5 + max([c.get_width() for c in columns]) for i, column in enumerate(columns): for n, name in enumerate(column): name.shift(n * self.name_y_spacing * DOWN) name.align_to(ORIGIN, LEFT) column.move_to(i * column_x_spacing * RIGHT, UL) columns.center() 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=4) columns.generate_target() columns.target.to_edge(DOWN, buff=4) 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)
def __init__(self, value: bool = True, **kwargs): digest_config(self, kwargs) self.box = Rectangle(**self.rect_kwargs) super().__init__(value, self.box, **kwargs) self.add_mouse_press_listner(self.on_mouse_press)
def __init__(self, mobject, **kwargs): digest_config(self, kwargs) kwargs["width"] = mobject.get_width() + 2 * self.buff kwargs["height"] = mobject.get_height() + 2 * self.buff Rectangle.__init__(self, **kwargs) self.move_to(mobject)
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
class Checkbox(ContolMobject): CONFIG = { "value_type": np.dtype(bool), "rect_kwargs": { "width": 0.5, "height": 0.5, "fill_opacity": 0.0 }, "checkmark_kwargs": { "stroke_color": GREEN, "stroke_width": 6, }, "cross_kwargs": { "stroke_color": RED, "stroke_width": 6, }, "box_content_buff": SMALL_BUFF } def __init__(self, value=True, **kwargs): digest_config(self, kwargs) self.box = Rectangle(**self.rect_kwargs) self.box_content = self.get_checkmark() if value else self.get_cross() super().__init__(value, self.box, self.box_content, **kwargs) def assert_value(self, value): assert (isinstance(value, bool)) def toggle_value(self): super().set_value(not self.get_value()) def set_value_anim(self, value): if value: self.box_content.become(self.get_checkmark()) else: self.box_content.become(self.get_cross()) def on_mouse_press(self, point, button, mods): self.toggle_value() return False # Helper methods def get_checkmark(self): checkmark = VGroup( Line(UP / 2 + 2 * LEFT, DOWN + LEFT, **self.checkmark_kwargs), Line(DOWN + LEFT, UP + RIGHT, **self.checkmark_kwargs)) checkmark.stretch_to_fit_width(self.box.get_width()) checkmark.stretch_to_fit_height(self.box.get_height()) checkmark.scale(0.5) checkmark.move_to(self.box) return checkmark def get_cross(self): cross = VGroup(Line(UP + LEFT, DOWN + RIGHT, **self.cross_kwargs), Line(UP + RIGHT, DOWN + LEFT, **self.cross_kwargs)) cross.stretch_to_fit_width(self.box.get_width()) cross.stretch_to_fit_height(self.box.get_height()) cross.scale(0.5) cross.move_to(self.box) return cross
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, ) if columns.get_width() > self.max_patron_width: columns.set_width(total_width - 1) 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)