def get_graph_label( self, graph, label="f(x)", x_val=None, direction=RIGHT, buff=MED_SMALL_BUFF, color=None, ): label = TexMobject(label) color = color or graph.get_color() label.set_color(color) if x_val is None: # Search from right to left for x in np.linspace(self.x_max, self.x_min, 100): point = self.input_to_graph_point(x, graph) if point[1] < FRAME_Y_RADIUS: break x_val = x label.next_to( self.input_to_graph_point(x_val, graph), direction, buff=buff ) label.shift_onto_screen() return label
def add_axes(self): x_axis = Line(self.tick_width * LEFT / 2, self.width * RIGHT) y_axis = Line(MED_LARGE_BUFF * DOWN, self.height * UP) ticks = VGroup() heights = np.linspace(0, self.height, self.n_ticks + 1) values = np.linspace(0, self.max_value, self.n_ticks + 1) for y, value in zip(heights, values): tick = Line(LEFT, RIGHT) tick.set_width(self.tick_width) tick.move_to(y * UP) ticks.add(tick) y_axis.add(ticks) self.add(x_axis, y_axis) self.x_axis, self.y_axis = x_axis, y_axis if self.label_y_axis: labels = VGroup() for tick, value in zip(ticks, values): label = TexMobject(str(np.round(value, 2))) label.set_height(self.y_axis_label_height) label.next_to(tick, LEFT, SMALL_BUFF) labels.add(label) self.y_axis_labels = labels self.add(labels)
def add_T_label(self, x_val, side=RIGHT, label=None, color=WHITE, animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.set_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(color, 1) triangle.set_stroke(width=0) if label is None: T_label = TexMobject(self.variable_point_label, fill_color=color) else: T_label = TexMobject(label, fill_color=color) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph( x_val, self.v_graph, color=YELLOW ) if animated: self.play( DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs ) if np.all(side == LEFT): self.left_T_label_group = VGroup(T_label, triangle) self.left_v_line = v_line self.add(self.left_T_label_group, self.left_v_line) elif np.all(side == RIGHT): self.right_T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line self.add(self.right_T_label_group, self.right_v_line)
def construct(self): eq1a = TexMobject("4x + 3y") eq1b = TexMobject("=") eq1c = TexMobject("0") eq2a = TexMobject("5x - 2y") eq2b = TexMobject("=") eq2c = TexMobject("3") eq1b.next_to(eq1a, RIGHT) eq1c.next_to(eq1b, RIGHT) eq2a.shift(DOWN) eq2b.shift(DOWN) eq2c.shift(DOWN) eq2a.align_to(eq1a, LEFT) eq2b.align_to(eq1b, LEFT) eq2c.align_to(eq1c, LEFT) eq_group = VGroup(eq1a, eq2a) braces = Brace(eq_group, LEFT) eq_text = braces.get_text("A pair of equations") self.play(Write(eq1a)) self.play(Write(eq1b)) self.play(Write(eq1c)) self.play(Write(eq2a)) self.play(Write(eq2b)) self.play(Write(eq2c)) self.play(GrowFromCenter(braces), Write(eq_text)) self.wait(3)
def add_T_label(self, x_val, side=RIGHT, label=None, color=WHITE, animated=False, **kwargs): """ This method adds to the Scene: -- a Vertical line from the x-axis to the corresponding point on the graph/curve. -- a small vertical Triangle whose top point lies on the base of the vertical line -- a TexMobject to be a label for the Line and Triangle, at the bottom of the Triangle. The scene needs to have the graph have the identifier/variable name self.v_graph. Parameters ---------- x_val (Union[float, int]) The x value at which the secant enters, and intersects the graph for the first time. side (np.ndarray()) label (str) The label to give the vertline and triangle color (str) The hex color of the label. animated (bool=False) Whether or not to animate the addition of the T_label **kwargs Any valid keyword argument of a self.play call. """ triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.set_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(color, 1) triangle.set_stroke(width=0) if label is None: T_label = TexMobject(self.variable_point_label, fill_color=color) else: T_label = TexMobject(label, fill_color=color) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph( x_val, self.v_graph, color=YELLOW ) if animated: self.play( DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs ) if np.all(side == LEFT): self.left_T_label_group = VGroup(T_label, triangle) self.left_v_line = v_line self.add(self.left_T_label_group, self.left_v_line) elif np.all(side == RIGHT): self.right_T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line self.add(self.right_T_label_group, self.right_v_line)
def get_graph_label( self, graph, label="f(x)", x_val=None, direction=RIGHT, buff=MED_SMALL_BUFF, color=None, ): label = TexMobject(label) color = color or graph.get_color() label.set_color(color) if x_val is None: # Search from right to left for x in np.linspace(self.x_max, self.x_min, 100): point = self.input_to_graph_point(x, graph) if point[1] < FRAME_Y_RADIUS: break x_val = x label.next_to( self.input_to_graph_point(x_val, graph), direction, buff=buff ) label.shift_onto_screen() return label
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)
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)
def get_vector_label(self, vector, label, at_tip=False, direction="left", rotate=False, color=None, label_scale_factor=VECTOR_LABEL_SCALE_FACTOR): if not isinstance(label, TexMobject): if len(label) == 1: label = "\\vec{\\textbf{%s}}" % label label = TexMobject(label) if color is None: color = vector.get_color() label.set_color(color) label.scale(label_scale_factor) label.add_background_rectangle() if at_tip: vect = vector.get_vector() vect /= get_norm(vect) label.next_to(vector.get_end(), vect, buff=SMALL_BUFF) else: angle = vector.get_angle() if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": label.shift(-label.get_bottom() + 0.1 * UP) else: label.shift(-label.get_top() + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label
def add_T_label(self, x_val, side=RIGHT, label=None, color=WHITE, animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.set_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(color, 1) triangle.set_stroke(width=0) if label is None: T_label = TexMobject(self.variable_point_label, fill_color=color) else: T_label = TexMobject(label, fill_color=color) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph(x_val, self.v_graph, color=YELLOW) if animated: self.play(DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs) if np.all(side == LEFT): self.left_T_label_group = VGroup(T_label, triangle) self.left_v_line = v_line self.add(self.left_T_label_group, self.left_v_line) elif np.all(side == RIGHT): self.right_T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line self.add(self.right_T_label_group, self.right_v_line)
def add_axes(self): x_axis = Line(self.tick_width * LEFT / 2, self.width * RIGHT) y_axis = Line(MED_LARGE_BUFF * DOWN, self.height * UP) ticks = VGroup() heights = np.linspace(0, self.height, self.n_ticks + 1) values = np.linspace(0, self.max_value, self.n_ticks + 1) for y, value in zip(heights, values): tick = Line(LEFT, RIGHT) tick.set_width(self.tick_width) tick.move_to(y * UP) ticks.add(tick) y_axis.add(ticks) self.add(x_axis, y_axis) self.x_axis, self.y_axis = x_axis, y_axis if self.label_y_axis: labels = VGroup() for tick, value in zip(ticks, values): label = TexMobject(str(np.round(value, 2))) label.set_height(self.y_axis_label_height) label.next_to(tick, LEFT, SMALL_BUFF) labels.add(label) self.y_axis_labels = labels self.add(labels)
def get_coordinate_labels(self, *numbers): # TODO: Should merge this with the code from NumberPlane.get_coordinate_labels result = VGroup() if len(numbers) == 0: numbers = list(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) if y != 0 ] 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.set_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 get_vector_label(self, vector, label, at_tip=False, direction="left", rotate=False, color=None, label_scale_factor=VECTOR_LABEL_SCALE_FACTOR): if not isinstance(label, TexMobject): if len(label) == 1: label = "\\vec{\\textbf{%s}}" % label label = TexMobject(label) if color is None: color = vector.get_color() label.set_color(color) label.scale(label_scale_factor) label.add_background_rectangle() if at_tip: vect = vector.get_vector() vect /= get_norm(vect) label.next_to(vector.get_end(), vect, buff=SMALL_BUFF) else: angle = vector.get_angle() if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": label.shift(-label.get_bottom() + 0.1 * UP) else: label.shift(-label.get_top() + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label
def get_axis_label(self, label_tex, axis, edge, direction, buff=MED_SMALL_BUFF): label = TexMobject(label_tex) label.next_to( axis.get_edge_center(edge), direction, buff=buff ) label.shift_onto_screen(buff=MED_SMALL_BUFF) return label
def get_graph_label( self, graph, label="f(x)", x_val=None, direction=RIGHT, buff=MED_SMALL_BUFF, color=None, ): """ This method returns a properly positioned label for the passed graph, styled with the passed parameters. Parameters ---------- graph : ParametricFunction The curve of the function plotted. label : str = "f(x)" The label for the function's curve. x_val : Union[float, int] The x_value with which the label should be aligned. direction : Union[np.ndarray,list,tuple]=RIGHT The position, relative to the curve that the label will be at. e.g LEFT, RIGHT buff : Union[float, int] The buffer space between the curve and the label color : str The color of the label. Returns ------- TexMobject The LaTeX of the passed 'label' parameter """ label = TexMobject(label) color = color or graph.get_color() label.set_color(color) if x_val is None: # Search from right to left for x in np.linspace(self.x_max, self.x_min, 100): point = self.input_to_graph_point(x, graph) if point[1] < FRAME_Y_RADIUS: break x_val = x label.next_to( self.input_to_graph_point(x_val, graph), direction, buff=buff ) label.shift_onto_screen() return label
def get_vector_label(self, vector, label, at_tip=False, direction="left", rotate=False, color=None, label_scale_factor=VECTOR_LABEL_SCALE_FACTOR): """ Returns naming labels for the passed vector. Parameters ---------- vector Vector Object for which to get the label. at_tip (bool) Whether or not to place the label at the tip of the vector. direction (str="left") If the label should be on the "left" or right of the vector. rotate (bool=False) Whether or not to rotate it to align it with the vector. color (str) The color to give the label. label_scale_factor (Union[int,float]) How much to scale the label by. Returns ------- TexMobject The TexMobject of the label. """ if not isinstance(label, TexMobject): if len(label) == 1: label = "\\vec{\\textbf{%s}}" % label label = TexMobject(label) if color is None: color = vector.get_color() label.set_color(color) label.scale(label_scale_factor) label.add_background_rectangle() if at_tip: vect = vector.get_vector() vect /= get_norm(vect) label.next_to(vector.get_end(), vect, buff=SMALL_BUFF) else: angle = vector.get_angle() if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": label.shift(-label.get_bottom() + 0.1 * UP) else: label.shift(-label.get_top() + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label
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
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
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
def get_det_text(matrix, determinant=None, background_rect=False, initial_scale_factor=2): parens = TexMobject("(", ")") parens.scale(initial_scale_factor) parens.stretch_to_fit_height(matrix.get_height()) l_paren, r_paren = parens.split() l_paren.next_to(matrix, LEFT, buff=0.1) r_paren.next_to(matrix, RIGHT, buff=0.1) det = TextMobject("det") det.scale(initial_scale_factor) det.next_to(l_paren, LEFT, buff=0.1) if background_rect: det.add_background_rectangle() det_text = VGroup(det, l_paren, r_paren) if determinant is not None: eq = TexMobject("=") eq.next_to(r_paren, RIGHT, buff=0.1) result = TexMobject(str(determinant)) result.next_to(eq, RIGHT, buff=0.2) det_text.add(eq, result) return det_text
def get_det_text(matrix, determinant=None, background_rect=False, initial_scale_factor=2): parens = TexMobject("(", ")") parens.scale(initial_scale_factor) parens.stretch_to_fit_height(matrix.get_height()) l_paren, r_paren = parens.split() l_paren.next_to(matrix, LEFT, buff=0.1) r_paren.next_to(matrix, RIGHT, buff=0.1) det = TextMobject("det") det.scale(initial_scale_factor) det.next_to(l_paren, LEFT, buff=0.1) if background_rect: det.add_background_rectangle() det_text = VGroup(det, l_paren, r_paren) if determinant is not None: eq = TexMobject("=") eq.next_to(r_paren, RIGHT, buff=0.1) result = TexMobject(str(determinant)) result.next_to(eq, RIGHT, buff=0.2) det_text.add(eq, result) return det_text
def get_coordinate_labels(self, x_vals=None, y_vals=None): coordinate_labels = VGroup() if x_vals is None: x_vals = list(range(-int(self.x_radius), int(self.x_radius) + 1)) if y_vals is None: y_vals = list(range(-int(self.y_radius), int(self.y_radius) + 1)) for index, vals in enumerate([x_vals, y_vals]): num_pair = [0, 0] for val in vals: if val == 0: continue num_pair[index] = val point = self.coords_to_point(*num_pair) num = TexMobject(str(val)) num.add_background_rectangle() num.set_height(self.written_coordinate_height) num.next_to(point, DOWN + LEFT, buff=SMALL_BUFF) coordinate_labels.add(num) self.coordinate_labels = coordinate_labels return coordinate_labels
def construct(self): self.setup_axes(animate=True) func_graph = self.get_graph(self.func_to_graph, color=RED) func_graph2 = self.get_graph(self.func_to_graph2) vert_line = self.get_vertical_line_to_graph(TAU, func_graph, color=YELLOW) graph_lab = self.get_graph_label(func_graph, label=r"\cos(x)") graph_lab2 = self.get_graph_label(func_graph2, label=r"\sin(x)", x_val=-10, direction=LEFT) two_pi = TexMobject(r"x = 2 \pi") label_coord = self.input_to_graph_point(TAU, func_graph) two_pi.next_to(label_coord, RIGHT + UP) self.play(ShowCreation(func_graph), ShowCreation(func_graph2)) self.play(ShowCreation(vert_line), ShowCreation(graph_lab), ShowCreation(graph_lab2), ShowCreation(two_pi)) self.wait(2)
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 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