Farther along EoLA chapter 3

This commit is contained in:
Grant Sanderson 2016-07-22 11:22:31 -07:00
parent b16695b6f3
commit 627f16b057
12 changed files with 408 additions and 168 deletions

View file

@ -30,6 +30,12 @@ class Animation(object):
self.name = self.__class__.__name__ + str(self.mobject) self.name = self.__class__.__name__ + str(self.mobject)
self.update(0) 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): def __str__(self):
return self.name return self.name
@ -65,7 +71,7 @@ class Animation(object):
def set_name(self, name): def set_name(self, name):
self.name = name self.name = name
return self return self
def update_mobject(self, alpha): def update_mobject(self, alpha):
#Typically ipmlemented by subclass #Typically ipmlemented by subclass

View file

@ -26,6 +26,11 @@ class Transform(Animation):
self.name += "To" + str(ending_mobject) self.name += "To" + str(ending_mobject)
self.mobject.stroke_width = ending_mobject.stroke_width 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): def init_path_func(self):
if self.path_func is not None: if self.path_func is not None:
return return

View file

@ -57,7 +57,7 @@ class CoordinatesAsScalars(VectorScene):
} }
def construct(self): def construct(self):
self.lock_in_dim_grid() self.lock_in_faded_grid()
vector = self.add_vector(self.vector_coords) vector = self.add_vector(self.vector_coords)
array, x_line, y_line = self.vector_to_coords(vector) array, x_line, y_line = self.vector_to_coords(vector)
@ -194,7 +194,7 @@ class CoordinatesAsScalarsExample2(CoordinatesAsScalars):
} }
def construct(self): def construct(self):
self.lock_in_dim_grid() self.lock_in_faded_grid()
basis_vectors = self.get_basis_vectors() basis_vectors = self.get_basis_vectors()
labels = self.get_basis_vector_labels() labels = self.get_basis_vector_labels()
@ -246,7 +246,7 @@ class ShowVaryingLinearCombinations(VectorScene):
"finish_by_drawing_lines" : False, "finish_by_drawing_lines" : False,
} }
def construct(self): def construct(self):
self.lock_in_dim_grid() self.lock_in_faded_grid()
v1 = self.add_vector(self.vector1, color = self.vector1_color) v1 = self.add_vector(self.vector1, color = self.vector1_color)
v2 = self.add_vector(self.vector2, color = self.vector2_color) v2 = self.add_vector(self.vector2, color = self.vector2_color)
v1_label = self.label_vector( v1_label = self.label_vector(
@ -651,7 +651,7 @@ class VectorsToDotsScene(VectorScene):
"end_color" : BLUE_E, "end_color" : BLUE_E,
} }
def construct(self): def construct(self):
self.lock_in_dim_grid() self.lock_in_faded_grid()
vectors = self.get_vectors() vectors = self.get_vectors()
colors = Color(self.start_color).range_to( colors = Color(self.start_color).range_to(
@ -761,9 +761,6 @@ class VectorsInThePlane(VectorsToDotsScene):
) )
self.remove(*vectors) self.remove(*vectors)
self.dither() 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): class HowToThinkVectorsVsPoint(Scene):
@ -1238,7 +1235,6 @@ class CheckYourUnderstanding(TeacherStudentsScene):
self.random_blink() self.random_blink()
class TechnicalDefinitionOfBasis(Scene): class TechnicalDefinitionOfBasis(Scene):
def construct(self): def construct(self):
title = TextMobject("Technical definition of basis:") title = TextMobject("Technical definition of basis:")
@ -1288,4 +1284,3 @@ class NextVideo(Scene):

View file

@ -75,32 +75,226 @@ class Introduction(TeacherStudentsScene):
class ShowGridCreation(Scene): class ShowGridCreation(Scene):
def construct(self): def construct(self):
plane = NumberPlane() plane = NumberPlane()
coords = plane.get_coordinate_labels() coords = VMobject(*plane.get_coordinate_labels())
self.play(ShowCreation(plane)) self.play(ShowCreation(plane, run_time = 3))
self.play(Write(coords, run_time = 5)) self.play(Write(coords, run_time = 3))
self.dither() 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): 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 = { CONFIG = {
"show_basis_vectors" : False "show_basis_vectors" : False
} }
def construct(self): def construct(self):
self.setup() 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()

View file

@ -19,99 +19,6 @@ Y_COLOR = RED_C
Z_COLOR = BLUE_D 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): class VectorScene(Scene):
CONFIG = { CONFIG = {
"basis_vector_stroke_width" : 6 "basis_vector_stroke_width" : 6
@ -130,7 +37,7 @@ class VectorScene(Scene):
self.add(axes) self.add(axes)
return 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() plane = self.add_plane()
axes = plane.get_axes() axes = plane.get_axes()
plane.fade(dimness) 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
)

View file

@ -22,8 +22,10 @@ class Mobject(object):
"name" : None, "name" : None,
"dim" : 3, "dim" : 3,
"target" : None, "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", "submobject_partial_creation_mode" : "lagged_start",
#TODO, probably make this Animations's responsibility?
} }
def __init__(self, *submobjects, **kwargs): def __init__(self, *submobjects, **kwargs):
digest_config(self, kwargs) digest_config(self, kwargs)
@ -286,14 +288,21 @@ class Mobject(object):
## Color functions ## 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). Condition is function which takes in one arguments, (x, y, z).
""" """
raise Exception("Not implemented") raise Exception("Not implemented")
def gradient_highlight(self, start_color, end_color): 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): def set_color(self, color):
self.highlight(color) self.highlight(color)
@ -305,10 +314,10 @@ class Mobject(object):
return self return self
def fade_to(self, color, alpha): 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(): 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)) mob.highlight(Color(rgb = new_rgb))
return self return self
@ -554,8 +563,10 @@ class Mobject(object):
mobject.family_members_with_points() mobject.family_members_with_points()
) )
for i, (self_sub, mob_sub) in enumerate(pairs): 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) prop = float(i)/len(pairs)
if spcm is "smoothed_lagged_start":
prop = smooth(prop)
sub_a = np.clip(2*a - prop, 0, 1) sub_a = np.clip(2*a - prop, 0, 1)
sub_b = np.clip(2*b - prop, 0, 1) sub_b = np.clip(2*b - prop, 0, 1)
elif spcm == "one_at_a_time": elif spcm == "one_at_a_time":

View file

@ -26,9 +26,10 @@ class PMobject(Mobject):
self.rgbs = np.append(self.rgbs, rgbs, axis = 0) self.rgbs = np.append(self.rgbs, rgbs, axis = 0)
return self 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() 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: if condition:
to_change = np.apply_along_axis(condition, 1, mob.points) to_change = np.apply_along_axis(condition, 1, mob.points)
mob.rgbs[to_change, :] = rgb mob.rgbs[to_change, :] = rgb

View file

@ -1,5 +1,6 @@
from vectorized_mobject import VMobject from vectorized_mobject import VMobject
from svg_mobject import SVGMobject, VMobjectFromSVGPathstring from svg_mobject import SVGMobject, VMobjectFromSVGPathstring
from topics.geometry import Rectangle
from helpers import * from helpers import *
import collections import collections
@ -101,7 +102,15 @@ class TexMobject(SVGMobject):
lambda m1, m2 : int((m1.get_left()-m2.get_left())[0]) 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): class TextMobject(TexMobject):
CONFIG = { CONFIG = {

View file

@ -6,8 +6,9 @@ from helpers import *
class VMobject(Mobject): class VMobject(Mobject):
CONFIG = { CONFIG = {
"fill_color" : BLACK, "fill_color" : None,
"fill_opacity" : 0.0, "fill_opacity" : 0.0,
"stroke_color" : None,
#Indicates that it will not be displayed, but #Indicates that it will not be displayed, but
#that it should count in parent mobject's path #that it should count in parent mobject's path
"is_subpath" : False, "is_subpath" : False,
@ -21,12 +22,10 @@ class VMobject(Mobject):
## Colors ## Colors
def init_colors(self): def init_colors(self):
if not hasattr(self, "stroke_color"):
self.stroke_color = self.color
self.set_style_data( self.set_style_data(
stroke_color = self.stroke_color, stroke_color = self.stroke_color or self.color,
stroke_width = self.stroke_width, stroke_width = self.stroke_width,
fill_color = self.fill_color, fill_color = self.fill_color or self.color,
fill_opacity = self.fill_opacity, fill_opacity = self.fill_opacity,
family = self.propogate_style_to_family family = self.propogate_style_to_family
) )
@ -58,6 +57,8 @@ class VMobject(Mobject):
return self return self
def set_fill(self, color = None, opacity = None, family = True): 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( return self.set_style_data(
fill_color = color, fill_color = color,
fill_opacity = opacity, fill_opacity = opacity,
@ -71,19 +72,22 @@ class VMobject(Mobject):
family = family family = family
) )
def highlight(self, color): def highlight(self, color, family = True):
self.set_fill(color = color) self.set_fill(
self.set_stroke(color = color) color = color,
opacity = self.get_fill_opacity(),
family = family
)
self.set_stroke(color = color, family = family)
return self return self
def fade(self, darkness = 0.5): # def fade(self, darkness = 0.5):
Mobject.fade(self, darkness) # Mobject.fade(self, darkness)
return self # return self
def get_fill_color(self): def get_fill_color(self):
try: try:
self.fill_rgb[self.fill_rgb<0] = 0 self.fill_rgb = np.clip(self.fill_rgb, 0, 1)
self.fill_rgb[self.fill_rgb>1] = 1
return Color(rgb = self.fill_rgb) return Color(rgb = self.fill_rgb)
except: except:
return Color(WHITE) return Color(WHITE)
@ -98,8 +102,10 @@ class VMobject(Mobject):
except: except:
return Color(WHITE) return Color(WHITE)
#TODO, get color? Specify if stroke or fill def get_color(self):
#is the predominant color attribute? if self.fill_opacity == 0:
return self.get_stroke_color()
return self.get_fill_color()
## Drawing ## Drawing
def start_at(self, point): def start_at(self, point):

View file

@ -132,20 +132,16 @@ class Scene(object):
return [m.copy() for m in self.mobjects] return [m.copy() for m in self.mobjects]
def align_run_times(self, *animations, **kwargs): def align_run_times(self, *animations, **kwargs):
if "run_time" in kwargs: max_run_time = max([a.run_time for a in animations])
run_time = kwargs["run_time"] for animation in animations:
for animation in animations: animation.update_config(**kwargs)
animation.set_run_time(run_time) if animation.run_time != max_run_time:
else: new_rate_func = squish_rate_func(
max_run_time = max([a.run_time for a in animations]) animation.get_rate_func(),
for animation in animations: 0, 1./max_run_time
if animation.run_time != max_run_time: )
new_rate_func = squish_rate_func( animation.set_rate_func(new_rate_func)
animation.get_rate_func(), animation.set_run_time(max_run_time)
0, 1./max_run_time
)
animation.set_rate_func(new_rate_func)
animation.set_run_time(max_run_time)
return animations return animations
def separate_moving_and_static_mobjects(self, *animations): def separate_moving_and_static_mobjects(self, *animations):

View file

@ -44,8 +44,8 @@ class Dot(Circle): #Use 1D density, even though 2D
CONFIG = { CONFIG = {
"radius" : 0.05, "radius" : 0.05,
"stroke_width" : 0, "stroke_width" : 0,
"fill_color" : WHITE, "fill_opacity" : 1.0,
"fill_opacity" : 1.0 "color" : WHITE
} }
def __init__(self, point = ORIGIN, **kwargs): def __init__(self, point = ORIGIN, **kwargs):
Circle.__init__(self, **kwargs) Circle.__init__(self, **kwargs)

View file

@ -116,6 +116,7 @@ class NumberPlane(VMobject):
"color" : BLUE_D, "color" : BLUE_D,
"secondary_color" : BLUE_E, "secondary_color" : BLUE_E,
"axes_color" : WHITE, "axes_color" : WHITE,
"secondary_stroke_width" : 1,
"x_radius": SPACE_WIDTH, "x_radius": SPACE_WIDTH,
"y_radius": SPACE_HEIGHT, "y_radius": SPACE_HEIGHT,
"space_unit_to_x_unit" : 1, "space_unit_to_x_unit" : 1,
@ -127,6 +128,7 @@ class NumberPlane(VMobject):
"written_coordinate_nudge" : 0.1*(DOWN+RIGHT), "written_coordinate_nudge" : 0.1*(DOWN+RIGHT),
"num_pair_at_center" : (0, 0), "num_pair_at_center" : (0, 0),
"propogate_style_to_family" : False, "propogate_style_to_family" : False,
"submobject_partial_creation_mode" : "smoothed_lagged_start",
} }
def generate_points(self): def generate_points(self):
@ -170,9 +172,11 @@ class NumberPlane(VMobject):
def init_colors(self): def init_colors(self):
VMobject.init_colors(self) VMobject.init_colors(self)
self.axes.set_stroke(self.axes_color) self.axes.set_stroke(self.axes_color, self.stroke_width)
self.main_lines.set_stroke(self.color) self.main_lines.set_stroke(self.color, self.stroke_width)
self.secondary_lines.set_stroke(self.secondary_color, 1) self.secondary_lines.set_stroke(
self.secondary_color, self.secondary_stroke_width
)
return self return self
def get_center_point(self): def get_center_point(self):
@ -236,10 +240,10 @@ class NumberPlane(VMobject):
arrow = Arrow(ORIGIN, coords, **kwargs) arrow = Arrow(ORIGIN, coords, **kwargs)
return arrow 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(): for mob in self.submobject_family():
if mob.get_num_points() > 0: 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") mob.change_anchor_mode("smooth")