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=0, 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) self.add(line) thanks = TextMobject("Funded by the community, with special thanks to:") thanks.scale(0.9) thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF) thanks.set_color(YELLOW) underline = Line(LEFT, RIGHT) underline.scale_to_fit_width(thanks.get_width() + MED_SMALL_BUFF) underline.next_to(thanks, DOWN, SMALL_BUFF) thanks.add(underline) self.add(thanks) 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]) 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_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) thanks.align_to(columns, alignment_vect=RIGHT) self.play( columns.move_to, 2 * DOWN, DOWN, columns.to_edge, RIGHT, Animation(black_rect), Animation(line), Animation(thanks), rate_func=None, run_time=self.run_time, )
def __init__(self, **kwargs): digest_config(self, kwargs) height = self.height if "height" in kwargs: kwargs.pop("height") Rectangle.__init__(self, width=self.aspect_ratio[0], height=self.aspect_ratio[1], **kwargs) self.scale_to_fit_height(height)
def get_unit_square(self, color=YELLOW, opacity=0.3, stroke_width=3): square = Rectangle(color=color, width=self.plane.get_x_unit_size(), height=self.plane.get_y_unit_size(), stroke_color=color, stroke_width=stroke_width, fill_color=color, fill_opacity=opacity) square.move_to(self.plane.coords_to_point(0, 0), DL) return square
def generate_big_rectangle(self): height, width = self.zoomed_canvas_frame_shape self.big_rectangle = Rectangle(height=height, width=width, color=self.square_color) if self.zoomed_canvas_center is not None: self.big_rectangle.shift(self.zoomed_canvas_center) elif self.zoomed_canvas_corner is not None: self.big_rectangle.to_corner(self.zoomed_canvas_corner, buff=self.zoomed_canvas_corner_buff) self.add(self.big_rectangle)
def __init__(self, **kwargs): digest_config(self, kwargs) height = self.height if "height" in kwargs: kwargs.pop("height") Rectangle.__init__( self, width=self.aspect_ratio[0], height=self.aspect_ratio[1], **kwargs ) self.scale_to_fit_height(height)
def get_unit_square(self, color=YELLOW, opacity=0.3, stroke_width=3): square = Rectangle( color=color, width=self.plane.get_x_unit_size(), height=self.plane.get_y_unit_size(), stroke_color=color, stroke_width=stroke_width, fill_color=color, fill_opacity=opacity ) square.move_to(self.plane.coords_to_point(0, 0), DL) return square
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=0, width=FRAME_WIDTH, height=1.1 * FRAME_Y_RADIUS) black_rect.to_edge(UP, buff=0) line = DashedLine(FRAME_X_RADIUS * LEFT, FRAME_X_RADIUS * 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]) 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_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.move_to, 2 * DOWN, DOWN, columns.to_edge, RIGHT, Animation(black_rect), rate_func=None, run_time=self.run_time, )
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, about_point=ORIGIN) self.rotate(np.pi / 6, DOWN, about_point=ORIGIN)
def generate_rectangle(self, i, j): height, width = self.get_side_lengths(i, j) fill_color = self.get_fill_color(i, j) rect = Rectangle(width=width, height=height, stroke_color=WHITE, stroke_width=0, fill_color=fill_color, fill_opacity=1) return rect
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) screen_plate = body.copy() 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.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 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.scale_to_fit_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 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 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 generate_symbol(self): symbol = VGroup(*[ Rectangle( length=2, width=0.5, stroke_width=0, fill_color=self.color, fill_opacity=1, ) for i in range(2) ]) symbol.arrange_submobjects(RIGHT, buff=0.5) symbol.set_height(self.inner_radius) return symbol
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.scale_to_fit_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 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 rect_to_mobject(self, rect_element): if rect_element.hasAttribute("fill"): if Color(str(rect_element.getAttribute("fill"))) == Color(WHITE): return mob = Rectangle(width=float(rect_element.getAttribute("width")), height=float(rect_element.getAttribute("height")), stroke_width=0, fill_color=WHITE, fill_opacity=1.0) mob.shift(mob.get_center() - mob.get_corner(UP + LEFT)) return mob
def generate_points(self): outer_rect = Rectangle( width=self.diameter, height=self.thickness, fill_color=self.fill_color, fill_opacity=self.fill_opacity, stroke_color=self.stroke_color, stroke_width=0, # self.stroke_width ) self.add(outer_rect) PI = TAU / 2 ridge_angles = np.arange(PI / self.nb_ridges, PI, PI / self.nb_ridges) ridge_positions = 0.5 * self.diameter * np.array( [np.cos(theta) for theta in ridge_angles]) ridge_color = interpolate_color(BLACK, self.stroke_color, 0.5) for x in ridge_positions: ridge = Line(x * RIGHT + 0.5 * self.thickness * DOWN, x * RIGHT + 0.5 * self.thickness * UP, stroke_color=ridge_color, stroke_width=self.stroke_width) self.add(ridge)
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=float(rect_element.getAttribute("width")), height=float(rect_element.getAttribute("height")), stroke_width=stroke_width, stroke_color=stroke_color, fill_color=fill_color, fill_opacity=opacity ) else: mob = RoundedRectangle( width=float(rect_element.getAttribute("width")), height=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 generate_points(self): self.add(Rectangle( height = self.height, width = self.height/self.height_to_width, stroke_color = WHITE, stroke_width = 2, fill_color = self.color, fill_opacity = 1, )) if self.turned_over: self.set_fill(DARK_GREY) self.set_stroke(LIGHT_GREY) contents = VectorizedPoint(self.get_center()) else: value = self.get_value() symbol = self.get_symbol() design = self.get_design(value, symbol) corner_numbers = self.get_corner_numbers(value, symbol) contents = VGroup(design, corner_numbers) self.design = design self.corner_numbers = corner_numbers self.add(contents)
def generate_points(self): self.width = self.width_to_height_ratio * self.height Rectangle.generate_points(self)
class ZoomedScene(Scene): """ Move around self.little_rectangle to determine which part of the screen is zoomed in on. """ CONFIG = { "zoomed_canvas_frame_shape": (3, 3), "zoomed_canvas_center": None, "zoomed_canvas_corner": UP + RIGHT, "zoomed_canvas_corner_buff": DEFAULT_MOBJECT_TO_EDGE_BUFFER, "zoomed_camera_background": None, "little_rectangle_start_position": ORIGIN, "zoom_factor": 6, "square_color": WHITE, "zoom_activated": False, } def activate_zooming(self): self.generate_big_rectangle() self.setup_zoomed_canvas() self.setup_zoomed_camera() self.zoom_activated = True def animate_activate_zooming(self): self.activate_zooming() self.play(*map(FadeIn, [self.little_rectangle, self.big_rectangle])) def disactivate_zooming(self): self.remove(self.big_rectangle, self.little_rectangle) self.zoom_activated = False def get_zoomed_camera_mobject(self): return self.little_rectangle def get_zoomed_screen(self): return self.big_rectangle def generate_big_rectangle(self): height, width = self.zoomed_canvas_frame_shape self.big_rectangle = Rectangle(height=height, width=width, color=self.square_color) if self.zoomed_canvas_center is not None: self.big_rectangle.shift(self.zoomed_canvas_center) elif self.zoomed_canvas_corner is not None: self.big_rectangle.to_corner(self.zoomed_canvas_corner, buff=self.zoomed_canvas_corner_buff) self.add(self.big_rectangle) def setup_zoomed_canvas(self): upper_left = self.big_rectangle.get_corner(UP + LEFT) lower_right = self.big_rectangle.get_corner(DOWN + RIGHT) pixel_coords = self.camera.points_to_pixel_coords( np.array([upper_left, lower_right])) self.zoomed_canvas_pixel_indices = pixel_coords (up, left), (down, right) = pixel_coords self.zoomed_canvas_pixel_shape = ( right - left, down - up, ) def setup_zoomed_camera(self): self.little_rectangle = self.big_rectangle.copy() self.little_rectangle.scale(1. / self.zoom_factor) self.little_rectangle.move_to(self.little_rectangle_start_position) self.zoomed_camera = MovingCamera( self.little_rectangle, pixel_shape=self.zoomed_canvas_pixel_shape, background=self.zoomed_camera_background) self.add(self.little_rectangle) #TODO, is there a better way to hanld this? self.zoomed_camera.adjusted_thickness = lambda x: x def get_frame(self): frame = Scene.get_frame(self) if self.zoom_activated: (up, left), (down, right) = self.zoomed_canvas_pixel_indices frame[left:right, up:down, :] = self.zoomed_camera.get_image() return frame def set_camera_pixel_array(self, pixel_array): self.camera.set_pixel_array(pixel_array) if self.zoom_activated: (up, left), (down, right) = self.zoomed_canvas_pixel_indices self.zoomed_camera.set_pixel_array(pixel_array[left:right, up:down]) def set_camera_background(self, background): self.set_camera_pixel_array(self, background) #TODO, check this... def reset_camera(self): self.camera.reset() if self.zoom_activated: self.zoomed_camera.reset() def capture_mobjects_in_camera(self, mobjects, **kwargs): self.camera.capture_mobjects(mobjects, **kwargs) if self.zoom_activated: if self.big_rectangle in mobjects: mobjects = list(mobjects) mobjects.remove(self.big_rectangle) self.zoomed_camera.capture_mobjects(mobjects, **kwargs) def get_moving_mobjects(self, *animations): moving_mobjects = Scene.get_moving_mobjects(self, *animations) if self.zoom_activated and self.little_rectangle in moving_mobjects: # When the camera is moving, so is everything, return self.mobjects else: return moving_mobjects
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)