def generate_points(self): start_angle = np.pi / 2 + self.arc_angle / 2 end_angle = np.pi / 2 - self.arc_angle / 2 self.add(Arc( start_angle=start_angle, angle=-self.arc_angle )) tick_angle_range = np.linspace(start_angle, end_angle, self.num_ticks) for index, angle in enumerate(tick_angle_range): vect = rotate_vector(RIGHT, angle) tick = Line((1 - self.tick_length) * vect, vect) label = TexMobject(str(10 * index)) label.set_height(self.tick_length) label.shift((1 + self.tick_length) * vect) self.add(tick, label) needle = Polygon( LEFT, UP, RIGHT, stroke_width=0, fill_opacity=1, fill_color=self.needle_color ) needle.stretch_to_fit_width(self.needle_width) needle.stretch_to_fit_height(self.needle_height) needle.rotate(start_angle - np.pi / 2, about_point=ORIGIN) self.add(needle) self.needle = needle self.center_offset = self.get_center()
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 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 generate_sea_of_zeros(self): zero = TexMobject("0") self.sea_of_zeros = [] for n in range(self.nrows): for a in range((self.nrows - n) / 2 + 1): for k in (n + a + 1, -a - 1): self.coords.append((n, k)) mob = zero.copy() mob.shift(self.coords_to_center(n, k)) self.coords_to_mobs[n][k] = mob self.add(mob) return self
def generate_n_choose_k_mobs(self): self.coords_to_n_choose_k = {} for n, k in self.coords: nck_mob = TexMobject(r"{%d \choose %d}" % (n, k)) scale_factor = min( 1, self.portion_to_fill * self.cell_height / nck_mob.get_height(), self.portion_to_fill * self.cell_width / nck_mob.get_width(), ) center = self.coords_to_mobs[n][k].get_center() nck_mob.center().scale(scale_factor).shift(center) if n not in self.coords_to_n_choose_k: self.coords_to_n_choose_k[n] = {} self.coords_to_n_choose_k[n][k] = nck_mob return self
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 count_mobjects( self, mobjects, mode="highlight", color="red", display_numbers=True, num_offset=DEFAULT_COUNT_NUM_OFFSET, run_time=DEFAULT_COUNT_RUN_TIME, ): """ Note, leaves final number mobject as "number" attribute mode can be "highlight", "show_creation" or "show", otherwise a warning is given and nothing is animating during the count """ if len(mobjects) > 50: # TODO raise Exception("I don't know if you should be counting \ too many mobjects...") if len(mobjects) == 0: raise Exception("Counting mobject list of length 0") if mode not in ["highlight", "show_creation", "show"]: raise Warning("Unknown mode") frame_time = run_time / len(mobjects) if mode == "highlight": self.add(*mobjects) for mob, num in zip(mobjects, it.count(1)): if display_numbers: num_mob = TexMobject(str(num)) num_mob.center().shift(num_offset) self.add(num_mob) if mode == "highlight": original_color = mob.color mob.set_color(color) self.wait(frame_time) mob.set_color(original_color) if mode == "show_creation": self.play(ShowCreation(mob, run_time=frame_time)) if mode == "show": self.add(mob) self.wait(frame_time) if display_numbers: self.remove(num_mob) if display_numbers: self.add(num_mob) self.number = num_mob return self
def interpolate_mobject(self, alpha): new_tex = self.tex_list[np.ceil(alpha * len(self.tex_list)) - 1] if new_tex != self.curr_tex: self.curr_tex = new_tex self.mobject = TexMobject(new_tex).shift(self.start_center) if not all(self.start_center == self.end_center): self.mobject.center().shift( (1 - alpha) * self.start_center + alpha * self.end_center )
class FlipThroughSymbols(Animation): CONFIG = { "start_center": ORIGIN, "end_center": ORIGIN, } def __init__(self, tex_list, **kwargs): mobject = TexMobject(self.curr_tex).shift(start_center) Animation.__init__(self, mobject, **kwargs) def interpolate_mobject(self, alpha): new_tex = self.tex_list[np.ceil(alpha * len(self.tex_list)) - 1] if new_tex != self.curr_tex: self.curr_tex = new_tex self.mobject = TexMobject(new_tex).shift(self.start_center) if not all(self.start_center == self.end_center): self.mobject.center().shift( (1 - alpha) * self.start_center + alpha * self.end_center )
def __init__(self, mobject, direction=DOWN, **kwargs): digest_config(self, kwargs, locals()) angle = -np.arctan2(*direction[:2]) + np.pi mobject.rotate(-angle, about_point=ORIGIN) left = mobject.get_corner(DOWN + LEFT) right = mobject.get_corner(DOWN + RIGHT) target_width = right[0] - left[0] # Adding int(target_width) qquads gives approximately the right width num_quads = np.clip( int(self.width_multiplier * target_width), self.min_num_quads, self.max_num_quads ) tex_string = "\\underbrace{%s}" % (num_quads * "\\qquad") TexMobject.__init__(self, tex_string, **kwargs) self.tip_point_index = np.argmin(self.get_all_points()[:, 1]) self.stretch_to_fit_width(target_width) self.shift(left - self.get_corner(UP + LEFT) + self.buff * DOWN) for mob in mobject, self: mob.rotate(angle, about_point=ORIGIN)
def count_regions(self, regions, mode="one_at_a_time", num_offset=DEFAULT_COUNT_NUM_OFFSET, run_time=DEFAULT_COUNT_RUN_TIME, **unused_kwargsn): if mode not in ["one_at_a_time", "show_all"]: raise Warning("Unknown mode") frame_time = run_time / (len(regions)) for region, count in zip(regions, it.count(1)): num_mob = TexMobject(str(count)) num_mob.center().shift(num_offset) self.add(num_mob) self.set_color_region(region) self.wait(frame_time) if mode == "one_at_a_time": self.reset_background() self.remove(num_mob) self.add(num_mob) self.number = num_mob return self
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_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 add_brackets(self): bracket_pair = TexMobject("\\big[", "\\big]") bracket_pair.scale(2) bracket_pair.stretch_to_fit_height( self.get_height() + 2 * self.bracket_v_buff ) l_bracket, r_bracket = bracket_pair.split() l_bracket.next_to(self, LEFT, self.bracket_h_buff) r_bracket.next_to(self, RIGHT, self.bracket_h_buff) self.add(l_bracket, r_bracket) self.brackets = VGroup(l_bracket, r_bracket) return self
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_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 generate_symbol(self): symbol = TexMobject("\\checkmark") symbol.set_color(self.color) symbol.set_height(self.inner_radius) return symbol
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_secant_slope_group( self, x, graph, dx=None, dx_line_color=None, df_line_color=None, dx_label=None, df_label=None, include_secant_line=True, secant_line_color=None, secant_line_length=10, ): """ Resulting group is of the form VGroup( dx_line, df_line, dx_label, (if applicable) df_label, (if applicable) secant_line, (if applicable) ) with attributes of those names. """ kwargs = locals() kwargs.pop("self") group = VGroup() group.kwargs = kwargs dx = dx or float(self.x_max - self.x_min) / 10 dx_line_color = dx_line_color or self.default_input_color df_line_color = df_line_color or graph.get_color() p1 = self.input_to_graph_point(x, graph) p2 = self.input_to_graph_point(x + dx, graph) interim_point = p2[0] * RIGHT + p1[1] * UP group.dx_line = Line(p1, interim_point, color=dx_line_color) group.df_line = Line(interim_point, p2, color=df_line_color) group.add(group.dx_line, group.df_line) labels = VGroup() if dx_label is not None: group.dx_label = TexMobject(dx_label) labels.add(group.dx_label) group.add(group.dx_label) if df_label is not None: group.df_label = TexMobject(df_label) labels.add(group.df_label) group.add(group.df_label) if len(labels) > 0: max_width = 0.8 * group.dx_line.get_width() max_height = 0.8 * group.df_line.get_height() if labels.get_width() > max_width: labels.set_width(max_width) if labels.get_height() > max_height: labels.set_height(max_height) if dx_label is not None: group.dx_label.next_to(group.dx_line, np.sign(dx) * DOWN, buff=group.dx_label.get_height() / 2) group.dx_label.set_color(group.dx_line.get_color()) if df_label is not None: group.df_label.next_to(group.df_line, np.sign(dx) * RIGHT, buff=group.df_label.get_height() / 2) group.df_label.set_color(group.df_line.get_color()) if include_secant_line: secant_line_color = secant_line_color or self.default_derivative_color group.secant_line = Line(p1, p2, color=secant_line_color) group.secant_line.scale_in_place(secant_line_length / group.secant_line.get_length()) group.add(group.secant_line) return group
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 organize_matrices(self, left, right, result): equals = TexMobject("=") everything = VGroup(left, right, equals, result) everything.arrange() everything.set_width(FRAME_WIDTH - 1) self.add(everything)
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 generate_counter_tex(self, counter): color = self.get_fill_color() counter_str = str(counter) if isinstance(counter, int) else counter counter_tex = TexMobject(counter_str) counter_tex.set_color(color).next_to(self.rhombus, DOWN) return counter_tex
def __init__(self, *tex_strings, **kwargs): self.tex_list = tex_strings TexMobject.__init__(self, *tex_strings, **kwargs) self.new_font_texs = VGroup()
def __init__(self, **kwargs): Circle.__init__(self, **kwargs) plus = TexMobject("+") plus.scale(0.7) plus.move_to(self) self.add(plus)
def add_letter(self, text, scale=1, buff=0.1, **moreargs): linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) texto = TexMobject(text, **moreargs).scale(scale).move_to(self) ancho = texto.get_height() / 2 texto.shift(self.direccion * (buff + 1) * ancho) return self.add(texto)
def __init__(self, tex_list, **kwargs): mobject = TexMobject(self.curr_tex).shift(start_center) Animation.__init__(self, mobject, **kwargs)
def get_tex(self, tex, scale=1, buff=1, invert_dir=False, invert_texto=False, remove_rot=True, **moreargs): linea_referencia = Line(self[0][0].get_start(), self[0][-1].get_end()) texto = TexMobject(tex, **moreargs) ancho = texto.get_height() / 2 if invert_texto: inv = PI else: inv = 0 if remove_rot: texto.scale(scale).move_to(self) else: texto.rotate( linea_referencia.get_angle()).scale(scale).move_to(self) texto.rotate(inv) if invert_dir: inv = -1 else: inv = 1 texto.shift(self.direccion * (buff + 1) * ancho) return texto
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_tex(self, *tex, **kwargs): tex_mob = TexMobject(*tex) self.put_at_tip(tex_mob, **kwargs) return tex_mob
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 matrix_to_mobject(matrix): return TexMobject(matrix_to_tex_string(matrix))
def get_secant_slope_group( self, x, graph, dx=None, dx_line_color=None, df_line_color=None, dx_label=None, df_label=None, include_secant_line=True, secant_line_color=None, secant_line_length=10, ): """ This method returns a VGroup of (two lines representing dx and df, the labels for dx and df, and the Secant to the Graph/curve at a particular x value. Parameters ---------- x (Union[float, int]) The x value at which the secant enters, and intersects the graph for the first time. graph (ParametricFunction) The curve/graph for which the secant must be found. dx (Union[float, int]) The change in x after which the secant exits. dx_line_color (str) The line color for the line that indicates the change in x. df_line_color (str) The line color for the line that indicates the change in y. dx_label (str) The label to be provided for the change in x. df_label (str) The label to be provided for the change in y. include_secant_line (bool=True) Whether or not to include the secant line in the graph, or just have the df and dx lines and labels. secant_line_color (str) The color of the secant line. secant_line_length (Union[float,int=10]) How long the secant line should be. Returns: -------- VGroup Resulting group is of the form VGroup( dx_line, df_line, dx_label, (if applicable) df_label, (if applicable) secant_line, (if applicable) ) with attributes of those names. """ kwargs = locals() kwargs.pop("self") group = VGroup() group.kwargs = kwargs dx = dx or float(self.x_max - self.x_min) / 10 dx_line_color = dx_line_color or self.default_input_color df_line_color = df_line_color or graph.get_color() p1 = self.input_to_graph_point(x, graph) p2 = self.input_to_graph_point(x + dx, graph) interim_point = p2[0] * RIGHT + p1[1] * UP group.dx_line = Line( p1, interim_point, color=dx_line_color ) group.df_line = Line( interim_point, p2, color=df_line_color ) group.add(group.dx_line, group.df_line) labels = VGroup() if dx_label is not None: group.dx_label = TexMobject(dx_label) labels.add(group.dx_label) group.add(group.dx_label) if df_label is not None: group.df_label = TexMobject(df_label) labels.add(group.df_label) group.add(group.df_label) if len(labels) > 0: max_width = 0.8 * group.dx_line.get_width() max_height = 0.8 * group.df_line.get_height() if labels.get_width() > max_width: labels.set_width(max_width) if labels.get_height() > max_height: labels.set_height(max_height) if dx_label is not None: group.dx_label.next_to( group.dx_line, np.sign(dx) * DOWN, buff=group.dx_label.get_height() / 2 ) group.dx_label.set_color(group.dx_line.get_color()) if df_label is not None: group.df_label.next_to( group.df_line, np.sign(dx) * RIGHT, buff=group.df_label.get_height() / 2 ) group.df_label.set_color(group.df_line.get_color()) if include_secant_line: secant_line_color = secant_line_color or self.default_derivative_color group.secant_line = Line(p1, p2, color=secant_line_color) group.secant_line.scale_in_place( secant_line_length / group.secant_line.get_length() ) group.add(group.secant_line) return group
def construct(self): self.phase = 0 point_x, point_y = self.comp_point(0) self.make_axes() self.ellipse = VMobject(color=self.path_color) self.phi = TexMobject(r"\Delta \Phi = ").set_color(BLACK).shift(4 * RIGHT + 2 * UP) self.phi_0 = TexMobject("0").set_color(BLACK).next_to(self.phi, RIGHT) self.phi_pi_2 = TexMobject(r"\frac{\pi}{2}").set_color(BLACK).next_to( self.phi, RIGHT).shift(0.06 * DOWN) self.phi_3_pi_4 = TexMobject(r"\frac{3 \pi}{4}").set_color( BLACK).next_to(self.phi, RIGHT) self.x_vector = Vector(point_x * RIGHT, color=self.axes_vector_color, **self.vector_args) self.y_vector = Vector(point_y * UP, color=self.axes_vector_color, **self.vector_args) self.xy_vector = Vector(point_x * RIGHT + point_y * UP, color=self.xy_vector_color, **self.vector_args) update_group = VGroup( self.ellipse, self.xy_vector, self.x_vector, self.y_vector, ) self.wait(1.6) self.add(self.ellipse) self.play(FadeIn(self.x_vector)) # self.wait(1) self.play(FadeIn(self.y_vector)) self.wait(4) self.play(FadeIn(self.xy_vector)) self.play(UpdateFromAlphaFunc(update_group, self.do_vectors_and_ellipse_period), run_time=self.period, rate_func=linear) self.play( UpdateFromAlphaFunc(update_group, self.do_vectors_only_period, run_time=self.period, rate_func=linear)) self.play( AnimationGroup(UpdateFromAlphaFunc(update_group, self.do_vectors_only_period, run_time=self.period, rate_func=linear), AnimationGroup(FadeIn(self.phi), FadeIn(self.phi_0)), lag_ratio=0.7)) self.play( UpdateFromAlphaFunc(update_group, self.do_vectors_only_period, run_time=self.period, rate_func=linear)) self.x_vector.set_color(BLACK) self.play(UpdateFromAlphaFunc(update_group, self.do_90_phase_shift, rate_func=linear), FadeOut(self.ellipse), FadeOut(self.phi_0), FadeIn(self.phi_pi_2), run_time=self.period / 4) self.phase = np.pi / 2 self.ellipse.set_points([]) self.x_vector.set_color(self.axes_vector_color) self.play(UpdateFromAlphaFunc(update_group, self.do_vectors_and_ellipse_period), run_time=self.period, rate_func=linear) for _ in range(3): self.play(UpdateFromAlphaFunc(update_group, self.do_vectors_only_period), run_time=self.period, rate_func=linear) self.x_vector.set_color(BLACK) self.play(UpdateFromAlphaFunc(update_group, self.do_45_phase_shift, rate_func=linear), FadeOut(self.ellipse), FadeOut(self.phi_pi_2), FadeIn(self.phi_3_pi_4), run_time=self.period / 8) self.phase = 3 * np.pi / 4 self.ellipse.set_points([]) self.x_vector.set_color(self.axes_vector_color) self.play(UpdateFromAlphaFunc(update_group, self.do_vectors_and_ellipse_period), run_time=self.period, rate_func=linear) self.play( AnimationGroup(UpdateFromAlphaFunc( update_group, self.do_vectors_only_period_hide, rate_func=linear, run_time=self.period), AnimationGroup(FadeOut(self.phi_3_pi_4), FadeOut(self.phi)), lag_ratio=0.7)) self.play(FadeOut(self.axes), FadeOut(self.axes_labels)) self.wait()