From c2eb3606844136a9f73dfe0bf98f84dd6ae02605 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Thu, 23 Feb 2017 18:13:36 -0800 Subject: [PATCH] Moved complex transformation out of zeta --- old_projects/zeta.py | 153 +-------------------- topics/complex_numbers.py | 274 ++++++++++++++++++++++++-------------- topics/number_line.py | 2 +- 3 files changed, 178 insertions(+), 251 deletions(-) diff --git a/old_projects/zeta.py b/old_projects/zeta.py index c04c506c..f9b858a8 100644 --- a/old_projects/zeta.py +++ b/old_projects/zeta.py @@ -18,6 +18,7 @@ from topics.combinatorics import * from topics.numerals import * from topics.three_dimensions import * from topics.objects import * +from topics.complex_numbers import * from scene import Scene from camera import Camera from mobject.svg_mobject import * @@ -38,158 +39,6 @@ def d_zeta(z): epsilon = 0.01 return (zeta(z + epsilon) - zeta(z))/epsilon -class ComplexTransformationScene(Scene): - CONFIG = { - "plane_config" : { - "x_line_frequency" : 1, - "y_line_frequency" : 1, - "secondary_line_ratio" : 1, - }, - "x_min" : -int(SPACE_WIDTH), - "x_max" : int(SPACE_WIDTH), - "y_min" : -SPACE_HEIGHT, - "y_max" : SPACE_HEIGHT, - "vert_start_color" : MAROON_B, - "vert_end_color" : RED, - "horiz_start_color" : GREEN_B, - "horiz_end_color" : YELLOW, - "num_anchors_to_add_per_line" : 50, - "post_transformation_stroke_width" : None, - "default_apply_complex_function_kwargs" : { - "run_time" : 5, - }, - "background_label_scale_val" : 0.5, - } - def setup(self): - self.foreground_mobjects = [] - self.transformable_mobjects = [] - self.add_background_plane() - - def add_foreground_mobject(self, mobject): - self.add_foreground_mobjects(mobject) - - def add_transformable_mobjects(self, *mobjects): - self.transformable_mobjects += list(mobjects) - self.add(*mobjects) - - def add_foreground_mobjects(self, *mobjects): - self.foreground_mobjects += list(mobjects) - Scene.add(self, *mobjects) - - def add(self, *mobjects): - Scene.add(self, *list(mobjects)+self.foreground_mobjects) - - def play(self, *animations, **kwargs): - Scene.play( - self, - *list(animations)+map(Animation, self.foreground_mobjects), - **kwargs - ) - - def add_background_plane(self): - background = NumberPlane(**self.plane_config).fade() - real_labels = VGroup(*[ - TexMobject(str(x)).shift( - background.num_pair_to_point((x, 0)) - ) - for x in range(-int(self.x_max), int(self.x_max)) - ]) - imag_labels = VGroup(*[ - TexMobject("%di"%y).shift( - background.num_pair_to_point((0, y)) - ) - for y in range(-int(self.y_max), int(self.y_max)) - if y != 0 - ]) - for labels in real_labels, imag_labels: - for label in labels: - label.scale_in_place(self.background_label_scale_val) - label.next_to(label.get_center(), DOWN+LEFT, buff = SMALL_BUFF) - label.add_background_rectangle() - background.add(labels) - self.real_labels = real_labels - self.imag_labels = imag_labels - self.add(background) - self.background = background - - def add_transformable_plane(self, animate = False): - self.plane_config.update({ - "x_radius" : (self.x_max - self.x_min)/2., - "y_radius" : (self.y_max - self.y_min)/2., - }) - plane = NumberPlane(**self.plane_config) - plane.shift( - (self.x_max+self.x_min)*RIGHT/2., - (self.y_max+self.y_min)*UP/2., - ) - self.paint_plane(plane) - if animate: - self.play(ShowCreation(plane, run_time = 2)) - else: - self.add(plane) - self.plane = plane - - def prepare_for_transformation(self, mob): - if hasattr(mob, "prepare_for_nonlinear_transform"): - mob.prepare_for_nonlinear_transform( - self.num_anchors_to_add_per_line - ) - #TODO... - - def paint_plane(self, plane): - for lines in plane.main_lines, plane.secondary_lines: - lines.gradient_highlight( - self.vert_start_color, - self.vert_end_color, - self.horiz_start_color, - self.horiz_end_color, - ) - plane.axes.gradient_highlight( - self.horiz_start_color, - self.vert_start_color - ) - - def z_to_point(self, z): - return self.background.num_pair_to_point((z.real, z.imag)) - - def get_transformer(self, **kwargs): - transform_kwargs = dict(self.default_apply_complex_function_kwargs) - transform_kwargs.update(kwargs) - plane = self.plane - self.prepare_for_transformation(plane) - transformer = VGroup( - plane, *self.transformable_mobjects - ) - return transformer, transform_kwargs - - - def apply_complex_function(self, func, added_anims = [], **kwargs): - transformer, transform_kwargs = self.get_transformer(**kwargs) - transformer.generate_target() - transformer.target.apply_complex_function(func) - for mob in transformer.target[0].family_members_with_points(): - mob.make_smooth() - if self.post_transformation_stroke_width is not None: - transformer.target.set_stroke(width = self.post_transformation_stroke_width) - self.play( - MoveToTarget(transformer, **transform_kwargs), - *added_anims - ) - - def apply_complex_homotopy(self, complex_homotopy, added_anims = [], **kwargs): - transformer, transform_kwargs = self.get_transformer(**kwargs) - def homotopy(x, y, z, t): - output = complex_homotopy(complex(x, y), t) - return (output.real, output.imag, z) - - self.play( - SmoothedVectorizedHomotopy( - homotopy, transformer, - **transform_kwargs - ), - *added_anims - ) - class ZetaTransformationScene(ComplexTransformationScene): CONFIG = { "anchor_density" : 35, diff --git a/topics/complex_numbers.py b/topics/complex_numbers.py index f9db54d1..a4d1ae37 100644 --- a/topics/complex_numbers.py +++ b/topics/complex_numbers.py @@ -1,11 +1,174 @@ from helpers import * + +from mobject import VGroup +from mobject.tex_mobject import TexMobject, TextMobject from number_line import NumberPlane +from animation import Animation from animation.transform import ApplyPointwiseFunction from animation.simple_animations import Homotopy from scene import Scene +class ComplexTransformationScene(Scene): + CONFIG = { + "plane_config" : { + "x_line_frequency" : 1, + "y_line_frequency" : 1, + "secondary_line_ratio" : 1, + }, + "background_fade_factor" : 0.5, + "x_min" : -int(SPACE_WIDTH), + "x_max" : int(SPACE_WIDTH), + "y_min" : -SPACE_HEIGHT, + "y_max" : SPACE_HEIGHT, + "use_multicolored_plane" : False, + "vert_start_color" : MAROON_B, + "vert_end_color" : RED, + "horiz_start_color" : GREEN_B, + "horiz_end_color" : YELLOW, + "num_anchors_to_add_per_line" : 50, + "post_transformation_stroke_width" : None, + "default_apply_complex_function_kwargs" : { + "run_time" : 5, + }, + "background_label_scale_val" : 0.5, + } + def setup(self): + self.foreground_mobjects = [] + self.transformable_mobjects = [] + self.add_background_plane() + + def add_foreground_mobject(self, mobject): + self.add_foreground_mobjects(mobject) + + def add_transformable_mobjects(self, *mobjects): + self.transformable_mobjects += list(mobjects) + self.add(*mobjects) + + def add_foreground_mobjects(self, *mobjects): + self.foreground_mobjects += list(mobjects) + Scene.add(self, *mobjects) + + def add(self, *mobjects): + Scene.add(self, *list(mobjects)+self.foreground_mobjects) + + def play(self, *animations, **kwargs): + Scene.play( + self, + *list(animations)+map(Animation, self.foreground_mobjects), + **kwargs + ) + + def add_background_plane(self): + background = NumberPlane(**self.plane_config).fade( + self.background_fade_factor + ) + real_labels = VGroup(*[ + TexMobject(str(x)).shift( + background.num_pair_to_point((x, 0)) + ) + for x in range(-int(self.x_max), int(self.x_max)) + ]) + imag_labels = VGroup(*[ + TexMobject("%di"%y).shift( + background.num_pair_to_point((0, y)) + ) + for y in range(-int(self.y_max), int(self.y_max)) + if y != 0 + ]) + for labels in real_labels, imag_labels: + for label in labels: + label.scale_in_place(self.background_label_scale_val) + label.next_to(label.get_center(), DOWN+LEFT, buff = SMALL_BUFF) + label.add_background_rectangle() + background.add(labels) + self.real_labels = real_labels + self.imag_labels = imag_labels + self.add(background) + self.background = background + + def add_transformable_plane(self, animate = False): + self.plane_config.update({ + "x_radius" : (self.x_max - self.x_min)/2., + "y_radius" : (self.y_max - self.y_min)/2., + }) + plane = NumberPlane(**self.plane_config) + plane.shift( + (self.x_max+self.x_min)*RIGHT/2., + (self.y_max+self.y_min)*UP/2., + ) + self.paint_plane(plane) + if animate: + self.play(ShowCreation(plane, run_time = 2)) + else: + self.add(plane) + self.plane = plane + + def prepare_for_transformation(self, mob): + if hasattr(mob, "prepare_for_nonlinear_transform"): + mob.prepare_for_nonlinear_transform( + self.num_anchors_to_add_per_line + ) + #TODO... + + def paint_plane(self, plane): + if self.use_multicolored_plane: + for lines in plane.main_lines, plane.secondary_lines: + lines.gradient_highlight( + self.vert_start_color, + self.vert_end_color, + self.horiz_start_color, + self.horiz_end_color, + ) + plane.axes.gradient_highlight( + self.horiz_start_color, + self.vert_start_color + ) + + def z_to_point(self, z): + return self.background.num_pair_to_point((z.real, z.imag)) + + def get_transformer(self, **kwargs): + transform_kwargs = dict(self.default_apply_complex_function_kwargs) + transform_kwargs.update(kwargs) + plane = self.plane + self.prepare_for_transformation(plane) + transformer = VGroup( + plane, *self.transformable_mobjects + ) + return transformer, transform_kwargs + + + def apply_complex_function(self, func, added_anims = [], **kwargs): + transformer, transform_kwargs = self.get_transformer(**kwargs) + transformer.generate_target() + transformer.target.apply_complex_function(func) + for mob in transformer.target[0].family_members_with_points(): + mob.make_smooth() + if self.post_transformation_stroke_width is not None: + transformer.target.set_stroke(width = self.post_transformation_stroke_width) + self.play( + MoveToTarget(transformer, **transform_kwargs), + *added_anims + ) + + def apply_complex_homotopy(self, complex_homotopy, added_anims = [], **kwargs): + transformer, transform_kwargs = self.get_transformer(**kwargs) + def homotopy(x, y, z, t): + output = complex_homotopy(complex(x, y), t) + return (output.real, output.imag, z) + + self.play( + SmoothedVectorizedHomotopy( + homotopy, transformer, + **transform_kwargs + ), + *added_anims + ) + +##### Unsure about what comes under here... + def complex_string(complex_num): return filter(lambda c : c not in "()", str(complex_num)) @@ -99,107 +262,22 @@ class ComplexHomotopy(Homotopy): Homotopy.__init__(self, homotopy, mobject, *args, **kwargs) -class ComplexMultiplication(Scene): - @staticmethod - def args_to_string(multiplier, mark_one = False): - num_str = complex_string(multiplier) - arrow_str = "MarkOne" if mark_one else "" - return num_str + arrow_str - - @staticmethod - def string_to_args(arg_string): - parts = arg_string.split() - multiplier = complex(parts[0]) - mark_one = len(parts) > 1 and parts[1] == "MarkOne" - return (multiplier, mark_one) - - def construct(self, multiplier, mark_one = False, **plane_config): - norm = np.linalg.norm(multiplier) - arg = np.log(multiplier).imag - plane_config["faded_line_frequency"] = 0 - plane_config.update(DEFAULT_PLANE_CONFIG) - if norm > 1 and "density" not in plane_config: - plane_config["density"] = norm*DEFAULT_POINT_DENSITY_1D - if "radius" not in plane_config: - radius = SPACE_WIDTH - if norm > 0 and norm < 1: - radius /= norm - else: - radius = plane_config["radius"] - plane_config["x_radius"] = plane_config["y_radius"] = radius - plane = ComplexPlane(**plane_config) - self.plane = plane - self.add(plane) - # plane.add_spider_web() - self.anim_config = { - "run_time" : 2.0, - "path_func" : path_along_arc(arg) - } - - plane_config["faded_line_frequency"] = 0.5 - background = ComplexPlane(color = "grey", **plane_config) - # background.add_spider_web() - labels = background.get_coordinate_labels() - self.paint_into_background(background, *labels) - self.mobjects_to_move_without_molding = [] - if mark_one: - self.draw_dot("1", 1, True) - self.draw_dot("z", multiplier) - self.mobjects_to_multiply = [plane] - - self.additional_animations = [] - self.multiplier = multiplier - if self.__class__ == ComplexMultiplication: - self.apply_multiplication() - - def draw_dot(self, tex_string, value, move_dot = False): - dot = Dot( - self.plane.number_to_point(value), - radius = 0.1*self.plane.unit_to_spatial_width, - color = BLUE if value == 1 else YELLOW - ) - label = TexMobject(tex_string) - label.shift(dot.get_center()+1.5*UP+RIGHT) - arrow = Arrow(label, dot) - self.add(label) - self.play(ShowCreation(arrow)) - self.play(ShowCreation(dot)) - self.dither() - - self.remove(label, arrow) - if move_dot: - self.mobjects_to_move_without_molding.append(dot) - return dot - def apply_multiplication(self): - def func((x, y, z)): - complex_num = self.multiplier*complex(x, y) - return (complex_num.real, complex_num.imag, z) - mobjects = self.mobjects_to_multiply - mobjects += self.mobjects_to_move_without_molding - mobjects += [anim.mobject for anim in self.additional_animations] - self.add(*mobjects) - full_multiplications = [ - ApplyMethod(mobject.apply_function, func, **self.anim_config) - for mobject in self.mobjects_to_multiply - ] - movements_with_plane = [ - ApplyMethod( - mobject.shift, - func(mobject.get_center())-mobject.get_center(), - **self.anim_config - ) - for mobject in self.mobjects_to_move_without_molding - ] - self.dither() - self.play(*reduce(op.add, [ - full_multiplications, - movements_with_plane, - self.additional_animations - ])) - self.dither() + + + + + + + + + + + + + diff --git a/topics/number_line.py b/topics/number_line.py index bf2606a0..37386cf3 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -176,7 +176,7 @@ class NumberPlane(VMobject): self.main_lines.add(line1, line2) else: self.secondary_lines.add(line1, line2) - self.add(self.axes, self.main_lines, self.secondary_lines) + self.add(self.secondary_lines, self.main_lines, self.axes) self.stretch(self.space_unit_to_x_unit, 0) self.stretch(self.space_unit_to_y_unit, 1) #Put x_axis before y_axis