def get_graph_label( self, graph, label="f(x)", x_val=None, direction=consts.RIGHT, buff=consts.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] < consts.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 __init__(self, mobject, direction=consts.DOWN, **kwargs): digest_config(self, kwargs, locals()) angle = -np.arctan2(*direction[:2]) + np.pi mobject.rotate(-angle, about_point=consts.ORIGIN) left = mobject.get_corner(consts.DOWN + consts.LEFT) right = mobject.get_corner(consts.DOWN + consts.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(consts.UP + consts.LEFT) + self.buff * consts.DOWN) for mob in mobject, self: mob.rotate(angle, about_point=consts.ORIGIN)
def add_T_label(self, x_val, side=consts.RIGHT, label=None, color=Color('WHITE'), animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.set_height(consts.MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), consts.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, consts.DOWN) v_line = self.get_vertical_line_to_graph( x_val, self.v_graph, color=Color('YELLOW') ) if animated: self.play( DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs ) if np.all(side == consts.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 == consts.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 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(consts.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( consts.LEFT, consts.UP, consts.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=consts.ORIGIN) self.add(needle) self.needle = needle self.center_offset = self.get_center()
def get_subdivision_braces_and_labels(self, parts, labels, direction, buff=consts.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_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 * consts.RIGHT, consts.DOWN + consts.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, consts.DOWN, consts.SMALL_BUFF) bar_labels.add(label) self.add(bars, bar_labels) self.bars = bars self.bar_labels = bar_labels
def add_axes(self): x_axis = Line(self.tick_width * consts.LEFT / 2, self.width * consts.RIGHT) y_axis = Line(consts.MED_LARGE_BUFF * consts.DOWN, self.height * consts.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(consts.LEFT, consts.RIGHT) tick.set_width(self.tick_width) tick.move_to(y * consts.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, consts.LEFT, consts.SMALL_BUFF) labels.add(label) self.y_axis_labels = labels self.add(labels)
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, consts.LEFT, self.bracket_h_buff) r_bracket.next_to(self, consts.RIGHT, self.bracket_h_buff) self.add(l_bracket, r_bracket) self.brackets = VGroup(l_bracket, r_bracket) return self
def get_axis_label(self, label_tex, axis, edge, direction, buff=consts.MED_SMALL_BUFF): label = TexMobject(label_tex) label.next_to(axis.get_edge_center(edge), direction, buff=buff) label.shift_onto_screen(buff=consts.MED_SMALL_BUFF) return label
def matrix_to_mobject(matrix): return TexMobject(matrix_to_tex_string(matrix))
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, consts.LEFT, buff=0.1) r_paren.next_to(matrix, consts.RIGHT, buff=0.1) det = TextMobject("det") det.scale(initial_scale_factor) det.next_to(l_paren, consts.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, consts.RIGHT, buff=0.1) result = TexMobject(str(determinant)) result.next_to(eq, consts.RIGHT, buff=0.2) det_text.add(eq, result) return det_text
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] * consts.RIGHT + p1[1] * consts.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) * consts.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) * consts.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 get_tex(self, *tex, **kwargs): tex_mob = TexMobject(*tex) self.put_at_tip(tex_mob, **kwargs) return tex_mob
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=consts.SMALL_BUFF) else: angle = vector.get_angle() if not rotate: label.rotate(-angle, about_point=consts.ORIGIN) if direction == "left": label.shift(-label.get_bottom() + 0.1 * consts.UP) else: label.shift(-label.get_top() + 0.1 * consts.DOWN) label.rotate(angle, about_point=consts.ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label