def generate_points(self): self.cell_height = self.height / self.nrows self.cell_width = self.width / self.nrows self.bottom_left = (self.cell_width * self.nrows / 2.0)*LEFT + \ (self.cell_height * self.nrows / 2.0)*DOWN num_to_num_mob = {} self.coords_to_mobs = {} self.coords = [ (n, k) for n in range(self.nrows) for k in range(n+1) ] for n, k in self.coords: num = choose(n, k) center = self.coords_to_center(n, k) num_mob = TexMobject(str(num)) scale_factor = min( 1, self.portion_to_fill * self.cell_height / num_mob.get_height(), self.portion_to_fill * self.cell_width / num_mob.get_width(), ) num_mob.center().scale(scale_factor).shift(center) if n not in self.coords_to_mobs: self.coords_to_mobs[n] = {} self.coords_to_mobs[n][k] = num_mob self.add(*[ self.coords_to_mobs[n][k] for n, k in self.coords ]) return self
def cycle_through_shapes(self): circle = Circle(radius = 2.5, color = WHITE) ellipse = circle.copy() ellipse.stretch(1.5, 0) ellipse.stretch(0.7, 1) ellipse.rotate(-np.pi/2) ellipse.scale_to_fit_height(4) pi_loop = TexMobject("\\pi")[0] pi_loop.set_fill(opacity = 0) pi_loop.set_stroke( color = WHITE, width = DEFAULT_POINT_THICKNESS ) pi_loop.scale_to_fit_height(4) randy = Randolph() randy.look(DOWN) randy.scale_to_fit_width(pi_loop.get_width()) randy.move_to(pi_loop, aligned_edge = DOWN) randy.body.set_fill(opacity = 0) randy.mouth.set_stroke(width = 0) self.transform_loop(circle) self.dither() odd_eigths = np.linspace(1./8, 7./8, 4) self.move_dots_to_alphas(odd_eigths) self.dither() for nudge in 0.1, -0.1, 0: self.move_dots_to_alphas(odd_eigths+nudge) self.dither() self.transform_loop(ellipse) self.dither() nudge = 0.055 self.move_dots_to_alphas( odd_eigths + [nudge, -nudge, nudge, -nudge] ) self.dither(2) self.transform_loop(pi_loop) self.let_dots_wonder() randy_anims = [ FadeIn(randy), Animation(randy), Blink(randy), Animation(randy), Blink(randy, rate_func = smooth) ] for anim in randy_anims: self.let_dots_wonder( run_time = 1, random_seed = 0, added_anims = [anim] ) self.remove(randy) self.transform_loop(self.get_default_loop())
def get_number_mobjects(self, *numbers): # TODO, handle decimals if len(numbers) == 0: numbers = self.default_numbers_to_display() result = [] for number in numbers: mob = TexMobject(str(int(number))) vert_scale = 2 * self.tick_size / mob.get_height() hori_scale = self.tick_frequency * self.unit_length_to_spatial_width / mob.get_width() mob.scale(min(vert_scale, hori_scale)) mob.shift(self.number_to_point(number)) mob.shift(self.get_vertical_number_offset()) result.append(mob) return result
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 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_number_mobjects(self, *numbers): #TODO, handle decimals if len(numbers) == 0: numbers = self.default_numbers_to_display() result = [] for number in numbers: mob = TexMobject(str(int(number))) vert_scale = 2 * self.tick_size / mob.get_height() hori_scale = self.tick_frequency * self.unit_length_to_spatial_width / mob.get_width( ) mob.scale(min(vert_scale, hori_scale)) mob.shift(self.number_to_point(number)) mob.shift(self.get_vertical_number_offset()) result.append(mob) return result
def scale_vector(self, v, factor, v_label, v_name = "v", factor_tex = None): starting_mobjects = list(self.mobjects) if factor_tex is None: factor_tex = str(factor) scaled_vector = self.add_vector( factor*v.get_end(), animate = False ) self.remove(scaled_vector) label_tex = "%s\\vec{\\textbf{%s}}"%(factor_tex, v_name) label = self.label_vector( scaled_vector, label_tex, animate = False, add_to_vector = False ) self.remove(label) factor_mob = TexMobject(factor_tex) if factor_mob.get_height() > 1: factor_mob.scale_to_fit_height(0.9) if factor_mob.get_width() > 1: factor_mob.scale_to_fit_width(0.9) factor_mob.shift(1.5*RIGHT+2.5*UP) num_factor_parts = len(factor_mob.split()) factor_mob_parts_in_label = label.split()[:num_factor_parts] label_remainder_parts = label.split()[num_factor_parts:] factor_in_label = VMobject(*factor_mob_parts_in_label) label_remainder = VMobject(*label_remainder_parts) self.play(Write(factor_mob, run_time = 1)) self.dither() self.play( ApplyMethod(v.copy().highlight, DARK_GREY), ApplyMethod(v_label.copy().highlight, DARK_GREY), Transform(factor_mob, factor_in_label), Transform(v.copy(), scaled_vector), Transform(v_label.copy(), label_remainder), ) self.dither(2) self.clear() self.add(*starting_mobjects)
def scale_vector(self, v, factor, v_label, v_name = "v", factor_tex = None): starting_mobjects = list(self.mobjects) if factor_tex is None: factor_tex = str(factor) scaled_vector = self.add_vector( factor*v.get_end(), animate = False ) self.remove(scaled_vector) label_tex = "%s\\vec{\\textbf{%s}}"%(factor_tex, v_name) label = self.label_vector( scaled_vector, label_tex, animate = False, add_to_vector = False ) self.remove(label) factor_mob = TexMobject(factor_tex) if factor_mob.get_height() > 1: factor_mob.scale_to_fit_height(0.9) if factor_mob.get_width() > 1: factor_mob.scale_to_fit_width(0.9) factor_mob.shift(1.5*RIGHT+2.5*UP) num_factor_parts = len(factor_mob.split()) factor_mob_parts_in_label = label.split()[:num_factor_parts] label_remainder_parts = label.split()[num_factor_parts:] factor_in_label = VMobject(*factor_mob_parts_in_label) label_remainder = VMobject(*label_remainder_parts) self.play(Write(factor_mob, run_time = 1)) self.wait() self.play( ApplyMethod(v.copy().highlight, DARK_GREY), ApplyMethod(v_label.copy().highlight, DARK_GREY), Transform(factor_mob, factor_in_label), Transform(v.copy(), scaled_vector), Transform(v_label.copy(), label_remainder), ) self.wait(2) self.clear() self.add(*starting_mobjects)
def take_derivatives_of_monomial(self, term): """ Must be a group of pure TexMobjects, last part must be of the form x^n """ n = int(term[-1].get_tex_string()[-1]) curr_term = term for k in range(n, 0, -1): exponent = curr_term[-1][-1] exponent_copy = exponent.copy() front_num = TexMobject("%d \\cdot"%k) front_num.move_to(curr_term[0][0], DOWN+LEFT) new_monomial = TexMobject("x^%d"%(k-1)) new_monomial.replace(curr_term[-1]) Transform(curr_term[-1], new_monomial).update(1) curr_term.generate_target() curr_term.target.shift( (front_num.get_width()+SMALL_BUFF)*RIGHT ) curr_term[-1][-1].set_fill(opacity = 0) self.play( ApplyMethod( exponent_copy.replace, front_num[0], path_arc = np.pi, ), Write( front_num[1], rate_func = squish_rate_func(smooth, 0.5, 1) ), MoveToTarget(curr_term), run_time = 2 ) self.remove(exponent_copy) self.add(front_num) curr_term = VGroup(front_num, *curr_term) self.dither() self.play(FadeOut(curr_term[-1])) return VGroup(*curr_term[:-1])
def construct(self): MAX_OPACITY = 0.4 INDICATOR_RADIUS = 0.6 OPACITY_FOR_UNIT_INTENSITY = 0.5 A = np.array([5., -3., 0.]) B = np.array([-5., 3., 0.]) C = np.array([-5., -3., 0.]) morty = self.get_primary_pi_creature() morty.scale(0.3).flip() right_pupil = morty.pupils[1] morty.next_to(C, LEFT, buff=0, submobject_to_align=right_pupil) horizontal = VMobject(stroke_width=1) horizontal.set_points_as_corners([C, A]) vertical = VMobject(stroke_width=1) vertical.set_points_as_corners([C, B]) self.play(ShowCreation(horizontal), ShowCreation(vertical)) indicator = LightIndicator( color=LIGHT_COLOR, radius=INDICATOR_RADIUS, opacity_for_unit_intensity=OPACITY_FOR_UNIT_INTENSITY, show_reading=True, precision=2) indicator.next_to(morty, LEFT) self.play(Write(indicator)) ls1 = LightSource(radius=20, num_levels=50) ls2 = ls1.deepcopy() #print "===" #print ls1.get_source_point() ls1.move_source_to(A) #print ls1.get_source_point() #print "===" #print ls2.get_source_point() ls2.move_source_to(B) #print ls2.get_source_point() self.play(FadeIn(ls1.lighthouse), FadeIn(ls2.lighthouse), SwitchOn(ls1.ambient_light), SwitchOn(ls2.ambient_light)) distance1 = np.linalg.norm(C - ls1.get_source_point()) intensity = ls1.ambient_light.opacity_function( distance1) / indicator.opacity_for_unit_intensity distance2 = np.linalg.norm(C - ls2.get_source_point()) intensity += ls2.ambient_light.opacity_function( distance2) / indicator.opacity_for_unit_intensity self.play(UpdateLightIndicator(indicator, intensity)) self.wait() ls3 = ls1.deepcopy() ls3.move_to(np.array([6, 3.5, 0])) new_indicator = indicator.copy() new_indicator.light_source = ls3 new_indicator.measurement_point = C self.add(new_indicator) self.play(indicator.shift, 2 * UP) #intensity = intensity_for_light_source(ls3) self.play( SwitchOff(ls1.ambient_light), #FadeOut(ls1.lighthouse), SwitchOff(ls2.ambient_light), #FadeOut(ls2.lighthouse), UpdateLightIndicator(new_indicator, 0.0)) # create a *continual* animation for the replacement source updater = ContinualLightIndicatorUpdate(new_indicator) self.add(updater) self.play( SwitchOn(ls3.ambient_light), FadeIn(ls3.lighthouse), ) self.wait() # move the light source around # TODO: moving along a path arc location = np.array([-3, -2., 0.]) self.play(ls3.move_source_to, location) location = np.array([6., 1., 0.]) self.play(ls3.move_source_to, location) location = np.array([5., 2., 0.]) self.play(ls3.move_source_to, location) closer_location = interpolate(location, C, 0.5) self.play(ls3.move_source_to, closer_location) self.play(ls3.move_source_to, location) # maybe move in a circle around C using a loop? # find the coords of the altitude point H # as the solution of a certain LSE xA = A[0] yA = A[1] xB = B[0] yB = B[1] xC = C[0] yC = C[1] matrix = np.array([[yA - yB, xB - xA], [xA - xB, yA - yB]]) # sic vector = np.array([xB * yA - xA * yB, xC * (xA - xB) + yC * (yA - yB)]) H2 = np.linalg.solve(matrix, vector) H = np.append(H2, 0.) self.play(ls3.move_source_to, H) # draw lines to complete the geometric picture # and label the lengths line_a = VMobject() line_a.set_points_as_corners([B, C]) line_b = VMobject() line_b.set_points_as_corners([A, C]) line_c = VMobject() line_c.set_points_as_corners([A, B]) line_h = VMobject() line_h.set_points_as_corners([H, C]) label_a = TexMobject("a") label_a.next_to(line_a, LEFT, buff=0.5) label_b = TexMobject("b") label_b.next_to(line_b, DOWN, buff=0.5) label_h = TexMobject("h") label_h.next_to(line_h.get_center(), RIGHT, buff=0.5) self.play(ShowCreation(line_a), Write(label_a)) self.play(ShowCreation(line_b), Write(label_b)) self.play(ShowCreation(line_c), ) self.play(ShowCreation(line_h), Write(label_h)) # state the IPT theorem_location = np.array([3., 2., 0.]) theorem = TexMobject("{1\over a^2} + {1\over b^2} = {1\over h^2}") theorem_name = TextMobject("Inverse Pythagorean Theorem") buffer = 1.2 theorem_box = Rectangle(width=buffer * theorem.get_width(), height=buffer * theorem.get_height()) theorem.move_to(theorem_location) theorem_box.move_to(theorem_location) theorem_name.next_to(theorem_box, UP) self.play(Write(theorem), ) self.play( ShowCreation(theorem_box), Write(theorem_name), )