def construct(self): # Setup line = NumberLine() house = House() drunk = Drunk(direction=RIGHT) house.place_on(ORIGIN) drunk.step_on(ORIGIN) t_equals = TexMobject("t = ") time = TexMobject("0") time.next_to(t_equals, RIGHT, buff=0.15) VGroup(t_equals, time).next_to(line, DOWN, buff=0.5) old_drunk = drunk.copy() old_time = time.copy() self.add(house, line, drunk, t_equals) # Start wandering for k in range(20): new_time = TexMobject("%s" % str(k + 1)) new_time.next_to(t_equals, RIGHT, buff=0.15) self.play( DrunkWander(drunk, random.choice([-1, 1]), total_time=0.5), Transform(time, new_time, rate_func=snap_head_and_tail(smooth), run_time=0.5), ) self.wait() # Reset self.play(Transform(time, old_time), Transform(drunk, old_drunk)) self.wait()
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.scale_to_fit_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 update_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 construct(self): axes = Axes(x_min=-0.5, x_max=6.5, y_min=-0.5, y_max=6.5, color=GREY, number_line_config={"tick_size": 0}) axes.center() wallis_rects_5 = WallisRectangles(rect_colors=[ "#FF0000", "#FF8000", "#FFFF00", "#00FF00", "#0080FF" ], order=5) wallis_rects_5.move_corner_to(axes.coords_to_point(0, 0)) quarter_circle = Sector( outer_radius=wallis_rects_5.get_height(), stroke_color=GREY, stroke_width=5.70, fill_opacity=0, ) quarter_circle.move_arc_center_to(wallis_rects_5.get_bottom_left()) self.add(wallis_rects_5, axes, quarter_circle) order = wallis_rects_5.get_order() inner_corners = [ rect.get_critical_point(UP + RIGHT) for rect in wallis_rects_5.get_layer(3) ] outer_corners = [ rect.get_critical_point(UP + RIGHT) for rect in wallis_rects_5.get_layer(4) ] inner_dots = VGroup(*[ Dot(corner, color=PINK, stroke_width=2, stroke_color=BLACK) for corner in inner_corners ]) outer_dots = VGroup(*[ Dot(corner, stroke_width=2, stroke_color=BLACK) for corner in outer_corners ]) inner_texts = VGroup(*[ TexMobject("(s_%d, s_%d)" % (order - k, k)) \ .scale(0.8) \ .set_color(PINK) \ .next_to(dot, LEFT+DOWN, buff = 0.05) for k, dot in zip(range(1, len(inner_dots) + 1), inner_dots) ]) outer_texts = VGroup(*[ TexMobject("(s_%d, s_%d)" % (order + 1 - k, k)) \ .scale(0.8) \ .set_color(WHITE) \ .next_to(dot, RIGHT+UP, buff = 0.05) for k, dot in zip(range(1, len(outer_dots) + 1), outer_dots) ]) self.add(inner_dots, outer_dots, inner_texts, outer_texts) self.wait()
def construct(self): formula = TexMobject(*([ "{%d \\over %d} \\cdot" % (wallis_numer(n), wallis_denom(n)) for n in range(1, self.n_terms + 1) ] + ["\\cdots"])) result = TexMobject("=", "{\\pi \\over 2}") result.scale(2) pi = result[-1][0] pi.set_color(YELLOW) circle = Circle(color=YELLOW) circle.surround(pi) question = TexMobject("?", color=YELLOW) question.scale(2).next_to(circle, RIGHT, buff=0.4) result_group = VGroup(result, circle, question) result_group.next_to(formula, DOWN) group = VGroup(formula, result_group) group.center().set_width(10) bg_rect = BackgroundRectangle(group, fill_opacity=0.5, buff=0.2) random_walks = VGroup(*[ RandomWalk1DArrow(random_walk_string(30), step_size=0.5) for k in range(self.n_walks) ]) for k, walk in enumerate(random_walks): walk.shift(random.randrange(-5, 5) * 2 * walk.step_size * UP) random_walks.center() text = TextMobject(self.part).scale(3).set_color(YELLOW) text.to_corner(RIGHT + DOWN) self.add(random_walks) self.add(FullScreenFadeRectangle()) self.add(bg_rect, group, text)
def construct(self): exp_tower = ExpTower(element = "x", order = 10) exp_tower.set_height(6) exp_tower.gradient_highlight(YELLOW, BLUE) two, equal_sign, four = equation = TexMobject("2", "=", "4") two.set_color(GREEN) four.set_color(RED) equation.scale(10) question_mark = TexMobject("?") question_mark.set_height(2) question_mark.next_to(equal_sign, UP, buff = 0.5) notations = VGroup(*[ TexMobject("{}^{\\infty} x"), TexMobject("x \\uparrow \\uparrow \\infty"), ]) for notation, num, direction, angle, color in \ zip(notations, [two, four], [UP+RIGHT, DOWN+LEFT], [-TAU/15, TAU/24], [YELLOW, BLUE]): notation.scale(3) notation.rotate(angle) notation.next_to(num, direction) notation.set_color(color) self.add(exp_tower, notations) self.add(FullScreenFadeRectangle()) self.add(equation, question_mark)
class DecimalNumber(VMobject): CONFIG = { "num_decimal_places": 2, "digit_to_digit_buff": 0.05, "show_ellipsis": False, "unit": None, # Aligned to bottom unless it starts with "^" "include_background_rectangle": False, } def __init__(self, number, **kwargs): VMobject.__init__(self, **kwargs) # TODO, make this more ediable with a getter and setter self.number = number ndp = self.num_decimal_places # Build number string if isinstance(number, complex): num_string = '%.*f%s%.*fi' % (ndp, number.real, "-" if number.imag < 0 else "+", ndp, abs(number.imag)) else: num_string = '%.*f' % (ndp, number) negative_zero_string = "-%.*f" % (ndp, 0.) if num_string == negative_zero_string: num_string = num_string[1:] self.add(*[TexMobject(char, **kwargs) for char in num_string]) # Add non-numerical bits if self.show_ellipsis: self.add(TexMobject("\\dots")) if num_string.startswith("-"): minus = self.submobjects[0] minus.next_to(self.submobjects[1], LEFT, buff=self.digit_to_digit_buff) if self.unit is not None: self.unit_sign = TexMobject(self.unit, color=self.color) self.add(self.unit_sign) self.arrange_submobjects(buff=self.digit_to_digit_buff, aligned_edge=DOWN) # Handle alignment of parts that should be aligned # to the bottom for i, c in enumerate(num_string): if c == "-" and len(num_string) > i + 1: self[i].align_to(self[i + 1], alignment_vect=UP) if self.unit and self.unit.startswith("^"): self.unit_sign.align_to(self, UP) # if self.include_background_rectangle: self.add_background_rectangle()
def build_the_equation(self): l_part = self.tower.copy() r_part = TexMobject("=", "2") r_part.match_height(l_part.get_base()) equation = VGroup(l_part, r_part) equation.arrange_submobjects(RIGHT, aligned_edge = DOWN) self.play( ReplacementTransform(self.tower, l_part, run_time = 1), Write(r_part, run_time = 2), ) self.equation = equation
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 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_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 choose_two_special_numbers(self): two_and_four_text = TextMobject("现在选择两个特殊的数...") two_and_four_text.set_color(YELLOW) two_and_four_text.to_edge(UP) self.play(Transform(self.anything_text, two_and_four_text)) self.wait() two_equation = self.equation four_equation = two_equation.copy() self.play(four_equation.to_edge, RIGHT, self.tower_edge_buff) self.wait() nums = [2, 4] colors = [GREEN, RED] equations = [two_equation, four_equation] targets = [equation[1][1] for equation in equations] two, four = num_texs = [ TexMobject(str(num)).set_color(color).match_height(target).move_to(target) for num, color, equation, target in zip(nums, colors, equations, targets) ] for N_tex, num_tex in zip(targets, num_texs): self.play(Transform(N_tex, num_tex)) self.wait(0.5) self.wait(0.5) self.nums = nums self.colors = colors self.equations = equations self.x_towers = VGroup(*[equation[0] for equation in equations])
def countdown(self): for k in range(5, -1, -1): countdown_text = TexMobject(str(k)) countdown_text.scale(1.5) countdown_text.set_color(YELLOW) countdown_text.to_corner(RIGHT+UP) self.add(countdown_text) self.wait() self.remove(countdown_text)
def solve_the_equations(self): rects = VGroup(*[ CoverRectangle( equation[0].get_exponent(), stroke_color = color, text = str(num), text_color = color ) for equation, color, num in zip(self.equations, self.colors, self.nums) ]) self.play(DrawBorderThenFill(rects)) self.wait() sps = VGroup() for equation, num, color in zip(self.equations, self.nums, self.colors): sp = TexMobject("x", "^{%d}" % num, "=", "%d" % num) sp[1::2].set_color(color) sp.scale(2) sp.next_to(equation, DOWN, buff = 1) sps.add(sp) rss = VGroup() for num, sp, color in zip(self.nums, sps, self.colors): rs = TexMobject("x", "=", "%d" % num , "^{{1}\\over{%d}}" % num, "=\\sqrt{2}") for tex in (rs[2], rs[3][2]): tex.set_color(color) rs.match_height(sp).move_to(sp) rss.add(rs) tf_anims = [] for sp, rs in zip(sps, rss): tf_anims.append(ReplacementTransform(sp[0], rs[0])) tf_anims.append(ReplacementTransform(sp[1], rs[3][2], path_arc = -TAU/4)) tf_anims.append(ReplacementTransform(sp[2], rs[1])) tf_anims.append(ReplacementTransform(sp[3], rs[2])) tf_anims.append(Write(rs[3][:2])) self.play(FadeIn(sps)) self.wait() self.play(AnimationGroup(*tf_anims), run_time = 2) self.wait() self.play(Write(VGroup(*[rs[4:] for rs in rss]), submobject_mode = "all_at_once")) self.wait() self.play(FadeOut(rects)) self.wait() self.rss = rss
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 = 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) ] 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.scale_to_fit_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 __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_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 __init__(self, number, **kwargs): VMobject.__init__(self, **kwargs) self.number = number ndp = self.num_decimal_points #Build number string if isinstance(number, complex): num_string = '%.*f%s%.*fi' % (ndp, number.real, "-" if number.imag < 0 else "+", ndp, abs(number.imag)) else: num_string = '%.*f' % (ndp, number) negative_zero_string = "-%.*f" % (ndp, 0.) if num_string == negative_zero_string: num_string = num_string[1:] self.add(*[TexMobject(char, **kwargs) for char in num_string]) #Add non-numerical bits if self.show_ellipsis: self.add(TexMobject("\\dots")) if num_string.startswith("-"): minus = self.submobjects[0] minus.next_to(self.submobjects[1], LEFT, buff=self.digit_to_digit_buff) if self.unit != None: self.unit_sign = TexMobject(self.unit) self.add(self.unit_sign) self.arrange_submobjects(buff=self.digit_to_digit_buff, aligned_edge=DOWN) #Handle alignment of parts that should be aligned #to the bottom for i, c in enumerate(num_string): if c == "-" and len(num_string) > i + 1: self[i].align_to(self[i + 1], alignment_vect=UP) if self.unit and self.unit.startswith("^"): self.unit_sign.align_to(self, UP) # if self.include_background_rectangle: self.add_background_rectangle()
def update_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 update_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 rhs_could_be_any_number(self): rhs_list = [ "2", # The journey starts here. "3", # The first number that pops into your head when you hear "2". "\\pi", # The good ol' pi. "\\sqrt{2}", # The (most) famous irrational number. "42", # The answer to everything. "17.29", # TAXI.CAB "-1", # A negative number, because why not? "e", # The (most) famous mathematical constant. "\\dfrac{3+\\sqrt{13}}{2}", # The bronze ratio... and a fraction. "570", # 1/3 of the author. "\\varphi", # The golden ratio. "g_{64}", # Gigigigigigigigantic... "0", # And... stop! "N", ] anything_text = TextMobject("等号右边似乎可以放任何数...") anything_text.set_color(YELLOW) anything_text.to_edge(UP) equations = [ VGroup(ExpTower(order = 5), TexMobject("=", rhs).scale(0.8)).scale(2.5) for rhs in rhs_list ] init_equation = equations[0] init_equation.arrange_submobjects(RIGHT, aligned_edge = DOWN) init_equation.next_to(anything_text, DOWN, buff = self.tower_edge_buff) init_equation.to_edge(LEFT, buff = self.tower_edge_buff) for equation in equations: equation[0].move_to(init_equation[0]) equation[1][0].move_to(init_equation[1][0]) equation[1][1].move_to(init_equation[1][1], aligned_edge = LEFT) self.play(FadeIn(init_equation)) self.wait() self.play(Write(anything_text), run_time = 1) self.play( ShowCreationThenDestruction(SurroundingRectangle(init_equation[1][1])), run_time = 2 ) self.wait() for k, equation in enumerate(equations): if k > 0 and k != len(equations)-1: equation[0].move_to(init_equation[0]) equation[1].move_to(init_equation[1], aligned_edge = LEFT) self.remove(equations[k-1]) self.add(equations[k]) self.wait(1./3) elif k == len(equations)-1: self.wait() self.play(ReplacementTransform(equations[k-1], equations[k])) self.wait() self.anything_text = anything_text self.equation = equations[-1]
def add_T_label(self, x_val, color=WHITE, animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.scale_to_fit_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) T_label = TexMobject(self.variable_point_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) else: self.add(triangle, v_line, T_label) self.T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line
def get_mobs_from_terms(self, start_terms, end_terms): """ Need to ensure that all image mobjects for a tex expression stemming from the same string are point-for-point copies of one and other. This makes transitions much smoother, and not look like point-clouds. """ num_start_terms = len(start_terms) all_mobs = np.array( TexMobject(start_terms).split() + TexMobject(end_terms).split()) all_terms = np.array(start_terms + end_terms) for term in set(all_terms): matches = all_terms == term if sum(matches) > 1: base_mob = all_mobs[list(all_terms).index(term)] all_mobs[matches] = [ base_mob.copy().replace(target_mob) for target_mob in all_mobs[matches] ] return all_mobs[:num_start_terms], all_mobs[num_start_terms:]
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 update_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 get_result_matrix(self, left, right): (m, k), n = left.shape, right.shape[1] mob_matrix = np.array([VGroup()]).repeat(m * n).reshape((m, n)) for a in range(m): for b in range(n): template = "(%s)(%s)" if self.use_parens else "%s%s" parts = [ prefix + template % (left[a][c], right[c][b]) for c in range(k) for prefix in ["" if c == 0 else "+"] ] mob_matrix[a][b] = TexMobject(parts, next_to_buff=0.1) return Matrix(mob_matrix)
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_brackets(self): bracket_pair = TexMobject("\\big[ \\big]") bracket_pair.scale(2) bracket_pair.stretch_to_fit_height(self.get_height() + 0.5) l_bracket, r_bracket = bracket_pair.split() l_bracket.next_to(self, LEFT) r_bracket.next_to(self, RIGHT) self.add(l_bracket, r_bracket) self.brackets = VGroup(l_bracket, r_bracket) return self
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 generate_points(self): hollow_tri = HollowTriangle(**self.triangle_config) bang = TexMobject("!") bang.set_height(hollow_tri.inner_height * 0.7) bang.move_to(hollow_tri.get_center_of_mass()) self.add(hollow_tri, bang) self.set_color(self.color)
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.scale_to_fit_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_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.scale_to_fit_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.scale_to_fit_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_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 add_words(self): # Wallis product product = TexMobject(*(["\\text{Wallis公式:}"] + [ "{%d \\over %d} \\," % (wallis_numer(n), wallis_denom(n)) for n in range(1, 8) ] + ["\\cdots = {\\pi \\over 2}"])).set_color(YELLOW) rect = SurroundingRectangle(product, color=YELLOW, buff=0.25) wallis_product = VGroup(product, rect) wallis_product.set_width(6) # All those steps nums = [TextMobject("%d. " % k) for k in [1, 2, 3, 4]] words = [ TextMobject(word) for word in [ "构造合适的矩形边长", "同种颜色的矩形的面积之和恒为1", "整个图形又像一个${1 \\over 4}$圆,半径是", "比较${1 \\over 4}$圆与矩形的面积", ] ] formulae = [ TextMobject(formula) for formula in [ "$a_0 = 1,\\, a_n = {1 \\over 2} \cdot {3 \\over 4} \cdots {2n-1 \\over 2n} (n \geq 1)$", "$a_0 a_n + a_1 a_{n-1} + \\cdots + a_n a_0 = 1$", "$\\begin{aligned} \ r_n & = a_0 + a_1 + \\cdots + a_{n-1} \\\\ \ & = \\textstyle{3 \\over 2} \cdot {5 \\over 4} \cdots {2n-1 \\over 2n-2} \ \\quad (n \geq 2) \ \\end{aligned}$", "${1 \\over 4} \\pi {r_n}^2 \\approx n \\quad \\Rightarrow \\quad \\text{Wallis公式}$" ] ] steps = VGroup() for num, word, formula in zip(nums, words, formulae): num.next_to(word, LEFT) formula.next_to(word, DOWN, aligned_edge=LEFT) steps.add(VGroup(num, word, formula)) steps.arrange_submobjects(DOWN, buff=0.6, aligned_edge=LEFT) steps.set_width(6) steps.next_to(wallis_product, DOWN) VGroup(wallis_product, steps).center().to_edge(RIGHT, buff=0.15) # Sep line and QED sep_line = DashedLine(2 * TOP, 2 * BOTTOM, color=GREY, buff=0.5) sep_line.next_to(steps, LEFT) qed = QEDSymbol(height=0.570 / 2) qed.next_to(steps[-1][-1][-1], RIGHT, aligned_edge=DOWN) # Add everything self.add(wallis_product, steps, sep_line, qed)
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_coordinate_labels(self, x_vals=None, y_vals=None): coordinate_labels = VGroup() if x_vals is None: x_vals = range(-int(self.x_radius), int(self.x_radius) + 1) if y_vals is None: y_vals = 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.scale_to_fit_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 get_det_text(matrix, determinant=None, background_rect=True, 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 = VMobject(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 /= np.linalg.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 is "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