diff --git a/animation/animation.py b/animation/animation.py index 4c9b9452..14b7b567 100644 --- a/animation/animation.py +++ b/animation/animation.py @@ -30,6 +30,12 @@ class Animation(object): self.name = self.__class__.__name__ + str(self.mobject) self.update(0) + def update_config(self, **kwargs): + if "path_arc" in kwargs: + kwargs["path_arc"] + digest_config(self, kwargs) + return self + def __str__(self): return self.name @@ -65,7 +71,7 @@ class Animation(object): def set_name(self, name): self.name = name - return self + return self def update_mobject(self, alpha): #Typically ipmlemented by subclass diff --git a/animation/transform.py b/animation/transform.py index 095b4cf9..50f73486 100644 --- a/animation/transform.py +++ b/animation/transform.py @@ -26,6 +26,11 @@ class Transform(Animation): self.name += "To" + str(ending_mobject) self.mobject.stroke_width = ending_mobject.stroke_width + def update_config(self, **kwargs): + Animation.update_config(self, **kwargs) + if "path_arc" in kwargs: + self.path_func = path_along_arc(kwargs["path_arc"]) + def init_path_func(self): if self.path_func is not None: return diff --git a/eola/chapter2.py b/eola/chapter2.py index c1affdc8..9237957c 100644 --- a/eola/chapter2.py +++ b/eola/chapter2.py @@ -57,7 +57,7 @@ class CoordinatesAsScalars(VectorScene): } def construct(self): - self.lock_in_dim_grid() + self.lock_in_faded_grid() vector = self.add_vector(self.vector_coords) array, x_line, y_line = self.vector_to_coords(vector) @@ -194,7 +194,7 @@ class CoordinatesAsScalarsExample2(CoordinatesAsScalars): } def construct(self): - self.lock_in_dim_grid() + self.lock_in_faded_grid() basis_vectors = self.get_basis_vectors() labels = self.get_basis_vector_labels() @@ -246,7 +246,7 @@ class ShowVaryingLinearCombinations(VectorScene): "finish_by_drawing_lines" : False, } def construct(self): - self.lock_in_dim_grid() + self.lock_in_faded_grid() v1 = self.add_vector(self.vector1, color = self.vector1_color) v2 = self.add_vector(self.vector2, color = self.vector2_color) v1_label = self.label_vector( @@ -651,7 +651,7 @@ class VectorsToDotsScene(VectorScene): "end_color" : BLUE_E, } def construct(self): - self.lock_in_dim_grid() + self.lock_in_faded_grid() vectors = self.get_vectors() colors = Color(self.start_color).range_to( @@ -761,9 +761,6 @@ class VectorsInThePlane(VectorsToDotsScene): ) self.remove(*vectors) self.dither() - self.play(Homotopy(plane_wave_homotopy, plane, run_time = 3)) - self.play(Transform(plane, NumberPlane(), rate_func = rush_from)) - self.dither() class HowToThinkVectorsVsPoint(Scene): @@ -1238,7 +1235,6 @@ class CheckYourUnderstanding(TeacherStudentsScene): self.random_blink() - class TechnicalDefinitionOfBasis(Scene): def construct(self): title = TextMobject("Technical definition of basis:") @@ -1288,4 +1284,3 @@ class NextVideo(Scene): - diff --git a/eola/chapter3.py b/eola/chapter3.py index 3d5e1a87..8998c76c 100644 --- a/eola/chapter3.py +++ b/eola/chapter3.py @@ -75,32 +75,226 @@ class Introduction(TeacherStudentsScene): class ShowGridCreation(Scene): def construct(self): plane = NumberPlane() - coords = plane.get_coordinate_labels() - self.play(ShowCreation(plane)) - self.play(Write(coords, run_time = 5)) + coords = VMobject(*plane.get_coordinate_labels()) + self.play(ShowCreation(plane, run_time = 3)) + self.play(Write(coords, run_time = 3)) self.dither() +class IntroduceLinearTransformations(LinearTransformationScene): + CONFIG = { + "show_basis_vectors" : False, + "include_background_plane" : False + } + def construct(self): + self.setup() + self.dither() + self.apply_transposed_matrix([[2, 1], [1, 2]]) + self.dither() + + lines_rule = TextMobject("Lines remain lines") + lines_rule.shift(2*UP).to_edge(LEFT) + origin_rule = TextMobject("Origin remains fixed") + origin_rule.shift(2*UP).to_edge(RIGHT) + arrow = Arrow(origin_rule, ORIGIN) + dot = Dot(ORIGIN, radius = 0.1, color = RED) + + for rule in lines_rule, origin_rule: + rule.add_background_rectangle() + + self.play( + # FadeIn(lines_rule_rect), + Write(lines_rule, run_time = 2), + ) + self.dither() + self.play( + # FadeIn(origin_rule_rect), + Write(origin_rule, run_time = 2), + ShowCreation(arrow), + GrowFromCenter(dot) + ) + self.dither() + + class SimpleLinearTransformationScene(LinearTransformationScene): + CONFIG = { + "show_basis_vectors" : False, + "transposed_matrix" : [[2, 1], [1, 2]] + } + def construct(self): + self.setup() + self.dither() + self.apply_transposed_matrix(self.transposed_matrix) + self.dither() + +class SimpleNonlinearTransformationScene(LinearTransformationScene): + CONFIG = { + "show_basis_vectors" : False, + "words" : "Not linear: some lines get curved" + } + def construct(self): + self.setup() + self.dither() + self.apply_nonlinear_transformation(self.func) + words = TextMobject(self.words) + words.to_corner(UP+RIGHT) + words.highlight(RED) + words.add_background_rectangle() + self.play(Write(words)) + self.dither() + + def func(self, point): + x, y, z = point + return (x+np.cos(y))*RIGHT + (y+np.sin(x))*UP + +class MovingOrigin(SimpleNonlinearTransformationScene): + CONFIG = { + "words" : "Not linear: Origin moves" + } + def setup(self): + LinearTransformationScene.setup(self) + dot = Dot(ORIGIN, color = RED) + self.add_transformable_mobject(dot) + + def func(self, point): + matrix_transform = self.get_matrix_transformation([[2, 0], [1, 1]]) + return matrix_transform(point) + 2*UP+3*LEFT + +class SneakyNonlinearTransformation(SimpleNonlinearTransformationScene): + CONFIG = { + "words" : "\\dots" + } + def func(self, point): + x, y, z = point + new_x = np.sign(x)*SPACE_WIDTH*smooth(abs(x) / SPACE_WIDTH) + new_y = np.sign(y)*SPACE_HEIGHT*smooth(abs(y) / SPACE_HEIGHT) + return [new_x, new_y, 0] + +class SneakyNonlinearTransformationExplained(SneakyNonlinearTransformation): + CONFIG = { + "words" : "Not linear: diagonal lines get curved" + } + def setup(self): + LinearTransformationScene.setup(self) + diag = Line( + SPACE_HEIGHT*LEFT+SPACE_HEIGHT*DOWN, + SPACE_HEIGHT*RIGHT + SPACE_HEIGHT*UP + ) + diag.insert_n_anchor_points(20) + diag.change_anchor_mode("smooth") + diag.highlight(YELLOW) + self.play(ShowCreation(diag)) + self.add_transformable_mobject(diag) + + +class AnotherLinearTransformation(SimpleLinearTransformationScene): + CONFIG = { + "transposed_matrix" : [ + [3, 0], + [1, 2] + ] + } + def construct(self): + SimpleLinearTransformationScene.construct(self) + text = TextMobject([ + "Grid lines remain", + "parallel", + "and", + "evenly spaced", + ]) + glr, p, a, es = text.split() + p.highlight(YELLOW) + es.highlight(GREEN) + text.add_background_rectangle() + text.shift(-text.get_bottom()) + self.play(Write(text)) + self.dither() + + +class Rotation(SimpleLinearTransformationScene): + CONFIG = { + "angle" : np.pi/3, + } + def construct(self): + self.transposed_matrix = [ + [np.cos(self.angle), np.sin(self.angle)], + [-np.sin(self.angle), np.cos(self.angle)] + ] + SimpleLinearTransformationScene.construct(self) + + + +class YetAnotherLinearTransformation(SimpleLinearTransformationScene): + CONFIG = { + "transposed_matrix" : [ + [-1, 1], + [3, 2], + ] + } + + +class MoveAroundAllVectors(LinearTransformationScene): + CONFIG = { + "show_basis_vectors" : False, + "focus_on_one_vector" : False, + } + def construct(self): + self.setup() + vectors = VMobject(*[ + Vector([x, y]) + for x in np.arange(-int(SPACE_WIDTH)+0.5, int(SPACE_WIDTH)+0.5) + for y in np.arange(-int(SPACE_HEIGHT)+0.5, int(SPACE_HEIGHT)+0.5) + ]) + vectors.submobject_gradient_highlight(PINK, BLUE_E) + dots = VMobject(*[ + Dot(v.get_end(), color = v.get_color()) + for v in vectors.split() + ]) + + self.dither() + self.play(ShowCreation(dots)) + self.dither() + self.play(Transform(dots, vectors)) + self.dither() + self.remove(dots) + if self.focus_on_one_vector: + vector = vectors.split()[43]#yeah, great coding Grant + self.remove(vectors) + self.add_vector(vector) + self.play(*[ + FadeOut(v) + for v in vectors.split() + if v is not vector + ]) + self.dither() + self.add(vector.copy().highlight(DARK_GREY)) + else: + for vector in vectors.split(): + self.add_vector(vector) + self.apply_transposed_matrix([[3, 0], [1, 2]]) + self.dither() + + +class MoveAroundJustOneVector(MoveAroundAllVectors): + CONFIG = { + "focus_on_one_vector" : True, + } + + +class RotateIHat(LinearTransformationScene): CONFIG = { "show_basis_vectors" : False } def construct(self): self.setup() - - - - - - - - - - - - - - - + i_hat, j_hat = self.get_basis_vectors() + i_label, j_label = self.get_basis_vector_labels() + self.play(ShowCreation(i_hat)) + self.play(Write(i_label, run_time = 1)) + self.dither() + self.play(FadeOut(i_label)) + self.apply_transposed_matrix([[0, 1], [-1, 0]]) + self.play(Write(j_label, run_time = 1)) + self.dither() diff --git a/eola/two_d_space.py b/eola/two_d_space.py index b1c9b31d..792f57ca 100644 --- a/eola/two_d_space.py +++ b/eola/two_d_space.py @@ -19,99 +19,6 @@ Y_COLOR = RED_C Z_COLOR = BLUE_D -class LinearTransformationScene(Scene): - CONFIG = { - "include_background_plane" : True, - "include_foreground_plane" : True, - "foreground_plane_kwargs" : { - "x_radius" : 2*SPACE_WIDTH, - "y_radius" : 2*SPACE_HEIGHT, - "secondary_line_ratio" : 0 - }, - "background_plane_kwargs" : { - "color" : GREY, - "secondary_color" : DARK_GREY, - "axes_color" : GREY, - }, - "show_coordinates" : False, - "show_basis_vectors" : True, - "i_hat_color" : X_COLOR, - "j_hat_color" : Y_COLOR, - } - def setup(self): - self.background_mobjects = [] - self.transformable_mobject = [] - self.moving_vectors = [] - - self.background_plane = NumberPlane( - **self.background_plane_kwargs - ) - - if self.show_coordinates: - self.background_plane.add_coordinates() - if self.include_background_plane: - self.add_background_mobject(self.background_plane) - if self.include_foreground_plane: - self.plane = NumberPlane(**self.foreground_plane_kwargs) - self.add_transformable_mobject(self.plane) - if self.show_basis_vectors: - self.add_vector((1, 0), self.i_hat_color) - self.add_vector((0, 1), self.j_hat_color) - - def add_background_mobject(self, *mobjects): - for mobject in mobjects: - if mobject not in self.background_mobjects: - self.background_mobjects.append(mobject) - self.add(mobject) - - def add_transformable_mobject(self, *mobjects): - for mobject in mobjects: - if mobject not in self.transformable_mobject: - self.transformable_mobject.append(mobject) - self.add(mobject) - - def add_vector(self, coords, color = YELLOW): - vector = Vector(self.background_plane.num_pair_to_point(coords)) - vector.highlight(color) - self.moving_vectors.append(vector) - return vector - - def apply_matrix(self, matrix, **kwargs): - matrix = np.array(matrix) - if matrix.shape == (2, 2): - new_matrix = np.identity(3) - new_matrix[:2, :2] = matrix - matrix = new_matrix - elif matrix.shape != (3, 3): - raise "Matrix has bad dimensions" - transpose = np.transpose(matrix) - - def func(point): - return np.dot(point, transpose) - - new_vectors = [ - Vector(func(v.get_end()), color = v.get_stroke_color()) - for v in self.moving_vectors - ] - self.play( - ApplyPointwiseFunction( - func, - VMobject(*self.transformable_mobject), - **kwargs - ), - Transform( - VMobject(*self.moving_vectors), - VMobject(*new_vectors), - **kwargs - ) - ) - - def apply_nonlinear_transformation(self, function, **kwargs): - pass #TODO - - - - class VectorScene(Scene): CONFIG = { "basis_vector_stroke_width" : 6 @@ -130,7 +37,7 @@ class VectorScene(Scene): self.add(axes) return axes - def lock_in_dim_grid(self, dimness = 0.7, axes_dimness = 0.5): + def lock_in_faded_grid(self, dimness = 0.7, axes_dimness = 0.5): plane = self.add_plane() axes = plane.get_axes() plane.fade(dimness) @@ -324,6 +231,112 @@ class VectorScene(Scene): +class LinearTransformationScene(VectorScene): + CONFIG = { + "include_background_plane" : True, + "include_foreground_plane" : True, + "foreground_plane_kwargs" : { + "x_radius" : 2*SPACE_WIDTH, + "y_radius" : 2*SPACE_HEIGHT, + "secondary_line_ratio" : 0 + }, + "background_plane_kwargs" : { + "color" : GREY, + "secondary_color" : DARK_GREY, + "axes_color" : GREY, + "stroke_width" : 2, + }, + "show_coordinates" : False, + "show_basis_vectors" : True, + "i_hat_color" : X_COLOR, + "j_hat_color" : Y_COLOR, + } + def setup(self): + self.background_mobjects = [] + self.transformable_mobject = [] + self.moving_vectors = [] + + self.background_plane = NumberPlane( + **self.background_plane_kwargs + ) + + if self.show_coordinates: + self.background_plane.add_coordinates() + if self.include_background_plane: + self.add_background_mobject(self.background_plane) + if self.include_foreground_plane: + self.plane = NumberPlane(**self.foreground_plane_kwargs) + self.add_transformable_mobject(self.plane) + if self.show_basis_vectors: + self.add_vector((1, 0), self.i_hat_color) + self.add_vector((0, 1), self.j_hat_color) + + def add_background_mobject(self, *mobjects): + for mobject in mobjects: + if mobject not in self.background_mobjects: + self.background_mobjects.append(mobject) + self.add(mobject) + + def add_transformable_mobject(self, *mobjects): + for mobject in mobjects: + if mobject not in self.transformable_mobject: + self.transformable_mobject.append(mobject) + self.add(mobject) + + def add_vector(self, vector, color = YELLOW, animate = False): + vector = VectorScene.add_vector( + self, vector, color = color, animate = animate + ) + self.moving_vectors.append(vector) + return vector + + def get_matrix_transformation(self, transposed_matrix): + transposed_matrix = np.array(transposed_matrix) + if transposed_matrix.shape == (2, 2): + new_matrix = np.identity(3) + new_matrix[:2, :2] = transposed_matrix + transposed_matrix = new_matrix + elif transposed_matrix.shape != (3, 3): + raise "Matrix has bad dimensions" + return lambda point: np.dot(point, transposed_matrix) + + + def get_vector_movement(self, func): + start = VMobject(*self.moving_vectors) + target = VMobject(*[ + Vector(func(v.get_end()), color = v.get_color()) + for v in self.moving_vectors + ]) + return Transform(start, target) + + def apply_transposed_matrix(self, transposed_matrix, **kwargs): + func = self.get_matrix_transformation(transposed_matrix) + if "path_arc" not in kwargs: + net_rotation = np.mean([ + angle_of_vector(func(RIGHT)), + angle_of_vector(func(UP))-np.pi/2 + ]) + kwargs["path_arc"] = net_rotation + self.apply_function(func, **kwargs) + + def apply_nonlinear_transformation(self, function, **kwargs): + self.plane.prepare_for_nonlinear_transform(100) + self.apply_function(function, **kwargs) + + def apply_function(self, function, **kwargs): + if "run_time" not in kwargs: + kwargs["run_time"] = 3 + self.play( + ApplyPointwiseFunction( + function, + VMobject(*self.transformable_mobject), + ), + self.get_vector_movement(function), + **kwargs + ) + + + diff --git a/mobject/mobject.py b/mobject/mobject.py index 97875432..b83a44fb 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -22,8 +22,10 @@ class Mobject(object): "name" : None, "dim" : 3, "target" : None, - #Options are lagged_start, one_at_a_time, all_at_once + #Options are lagged_start, smoothed_lagged_start, + #one_at_a_time, all_at_once "submobject_partial_creation_mode" : "lagged_start", + #TODO, probably make this Animations's responsibility? } def __init__(self, *submobjects, **kwargs): digest_config(self, kwargs) @@ -286,14 +288,21 @@ class Mobject(object): ## Color functions - def highlight(self, color = YELLOW_C, condition = None): + def highlight(self, color = YELLOW_C, family = True, condition = None): """ Condition is function which takes in one arguments, (x, y, z). """ raise Exception("Not implemented") def gradient_highlight(self, start_color, end_color): - raise Exception("Not implemented") + raise Exception("Not implemented") + + def submobject_gradient_highlight(self, start_color, end_color): + mobs = self.family_members_with_points() + colors = Color(start_color).range_to(end_color, len(mobs)) + for mob, color in zip(mobs, colors): + mob.highlight(color, family = False) + return self def set_color(self, color): self.highlight(color) @@ -305,10 +314,10 @@ class Mobject(object): return self def fade_to(self, color, alpha): - start = color_to_rgb(self.get_color()) - end = color_to_rgb(color) - new_rgb = interpolate(start, end, alpha) for mob in self.family_members_with_points(): + start = color_to_rgb(mob.get_color()) + end = color_to_rgb(color) + new_rgb = interpolate(start, end, alpha) mob.highlight(Color(rgb = new_rgb)) return self @@ -554,8 +563,10 @@ class Mobject(object): mobject.family_members_with_points() ) for i, (self_sub, mob_sub) in enumerate(pairs): - if spcm == "lagged_start": + if spcm in ["lagged_start", "smoothed_lagged_start"]: prop = float(i)/len(pairs) + if spcm is "smoothed_lagged_start": + prop = smooth(prop) sub_a = np.clip(2*a - prop, 0, 1) sub_b = np.clip(2*b - prop, 0, 1) elif spcm == "one_at_a_time": diff --git a/mobject/point_cloud_mobject.py b/mobject/point_cloud_mobject.py index dc5e9a5a..f73a6450 100644 --- a/mobject/point_cloud_mobject.py +++ b/mobject/point_cloud_mobject.py @@ -26,9 +26,10 @@ class PMobject(Mobject): self.rgbs = np.append(self.rgbs, rgbs, axis = 0) return self - def highlight(self, color = YELLOW_C, condition = None): + def highlight(self, color = YELLOW_C, family = True, condition = None): rgb = Color(color).get_rgb() - for mob in self.family_members_with_points(): + mobs = self.family_members_with_points() if family else [self] + for mob in mobs: if condition: to_change = np.apply_along_axis(condition, 1, mob.points) mob.rgbs[to_change, :] = rgb diff --git a/mobject/tex_mobject.py b/mobject/tex_mobject.py index d96f1db5..7cbcf35f 100644 --- a/mobject/tex_mobject.py +++ b/mobject/tex_mobject.py @@ -1,5 +1,6 @@ from vectorized_mobject import VMobject from svg_mobject import SVGMobject, VMobjectFromSVGPathstring +from topics.geometry import Rectangle from helpers import * import collections @@ -101,7 +102,15 @@ class TexMobject(SVGMobject): lambda m1, m2 : int((m1.get_left()-m2.get_left())[0]) ) - + def add_background_rectangle(self, color = BLACK, opacity = 0.75): + rect = Rectangle( + stroke_width = 0, + fill_color = color, + fill_opacity = opacity + ) + rect.replace(self, stretch = True) + self.submobjects = [rect] + self.submobjects + return self class TextMobject(TexMobject): CONFIG = { diff --git a/mobject/vectorized_mobject.py b/mobject/vectorized_mobject.py index 00a640eb..afd57433 100644 --- a/mobject/vectorized_mobject.py +++ b/mobject/vectorized_mobject.py @@ -6,8 +6,9 @@ from helpers import * class VMobject(Mobject): CONFIG = { - "fill_color" : BLACK, + "fill_color" : None, "fill_opacity" : 0.0, + "stroke_color" : None, #Indicates that it will not be displayed, but #that it should count in parent mobject's path "is_subpath" : False, @@ -21,12 +22,10 @@ class VMobject(Mobject): ## Colors def init_colors(self): - if not hasattr(self, "stroke_color"): - self.stroke_color = self.color self.set_style_data( - stroke_color = self.stroke_color, + stroke_color = self.stroke_color or self.color, stroke_width = self.stroke_width, - fill_color = self.fill_color, + fill_color = self.fill_color or self.color, fill_opacity = self.fill_opacity, family = self.propogate_style_to_family ) @@ -58,6 +57,8 @@ class VMobject(Mobject): return self def set_fill(self, color = None, opacity = None, family = True): + if self.fill_opacity == 0 and opacity is None: + opacity = 1 return self.set_style_data( fill_color = color, fill_opacity = opacity, @@ -71,19 +72,22 @@ class VMobject(Mobject): family = family ) - def highlight(self, color): - self.set_fill(color = color) - self.set_stroke(color = color) + def highlight(self, color, family = True): + self.set_fill( + color = color, + opacity = self.get_fill_opacity(), + family = family + ) + self.set_stroke(color = color, family = family) return self - def fade(self, darkness = 0.5): - Mobject.fade(self, darkness) - return self + # def fade(self, darkness = 0.5): + # Mobject.fade(self, darkness) + # return self def get_fill_color(self): try: - self.fill_rgb[self.fill_rgb<0] = 0 - self.fill_rgb[self.fill_rgb>1] = 1 + self.fill_rgb = np.clip(self.fill_rgb, 0, 1) return Color(rgb = self.fill_rgb) except: return Color(WHITE) @@ -98,8 +102,10 @@ class VMobject(Mobject): except: return Color(WHITE) - #TODO, get color? Specify if stroke or fill - #is the predominant color attribute? + def get_color(self): + if self.fill_opacity == 0: + return self.get_stroke_color() + return self.get_fill_color() ## Drawing def start_at(self, point): diff --git a/scene/scene.py b/scene/scene.py index 7d59a531..1965092b 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -132,20 +132,16 @@ class Scene(object): return [m.copy() for m in self.mobjects] def align_run_times(self, *animations, **kwargs): - if "run_time" in kwargs: - run_time = kwargs["run_time"] - for animation in animations: - animation.set_run_time(run_time) - else: - max_run_time = max([a.run_time for a in animations]) - for animation in animations: - if animation.run_time != max_run_time: - new_rate_func = squish_rate_func( - animation.get_rate_func(), - 0, 1./max_run_time - ) - animation.set_rate_func(new_rate_func) - animation.set_run_time(max_run_time) + max_run_time = max([a.run_time for a in animations]) + for animation in animations: + animation.update_config(**kwargs) + if animation.run_time != max_run_time: + new_rate_func = squish_rate_func( + animation.get_rate_func(), + 0, 1./max_run_time + ) + animation.set_rate_func(new_rate_func) + animation.set_run_time(max_run_time) return animations def separate_moving_and_static_mobjects(self, *animations): diff --git a/topics/geometry.py b/topics/geometry.py index 1daeddf3..445127c3 100644 --- a/topics/geometry.py +++ b/topics/geometry.py @@ -44,8 +44,8 @@ class Dot(Circle): #Use 1D density, even though 2D CONFIG = { "radius" : 0.05, "stroke_width" : 0, - "fill_color" : WHITE, - "fill_opacity" : 1.0 + "fill_opacity" : 1.0, + "color" : WHITE } def __init__(self, point = ORIGIN, **kwargs): Circle.__init__(self, **kwargs) diff --git a/topics/number_line.py b/topics/number_line.py index 11ccff2e..5b0fcd3d 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -116,6 +116,7 @@ class NumberPlane(VMobject): "color" : BLUE_D, "secondary_color" : BLUE_E, "axes_color" : WHITE, + "secondary_stroke_width" : 1, "x_radius": SPACE_WIDTH, "y_radius": SPACE_HEIGHT, "space_unit_to_x_unit" : 1, @@ -127,6 +128,7 @@ class NumberPlane(VMobject): "written_coordinate_nudge" : 0.1*(DOWN+RIGHT), "num_pair_at_center" : (0, 0), "propogate_style_to_family" : False, + "submobject_partial_creation_mode" : "smoothed_lagged_start", } def generate_points(self): @@ -170,9 +172,11 @@ class NumberPlane(VMobject): def init_colors(self): VMobject.init_colors(self) - self.axes.set_stroke(self.axes_color) - self.main_lines.set_stroke(self.color) - self.secondary_lines.set_stroke(self.secondary_color, 1) + self.axes.set_stroke(self.axes_color, self.stroke_width) + self.main_lines.set_stroke(self.color, self.stroke_width) + self.secondary_lines.set_stroke( + self.secondary_color, self.secondary_stroke_width + ) return self def get_center_point(self): @@ -236,10 +240,10 @@ class NumberPlane(VMobject): arrow = Arrow(ORIGIN, coords, **kwargs) return arrow - def prepare_for_nonlinear_transform(self): + def prepare_for_nonlinear_transform(self, num_inserted_anchor_points = 40): for mob in self.submobject_family(): if mob.get_num_points() > 0: - mob.insert_n_anchor_points(20) + mob.insert_n_anchor_points(num_inserted_anchor_points) mob.change_anchor_mode("smooth")