Through coordinates section in chapter 1

This commit is contained in:
Grant Sanderson
2016-07-15 18:16:06 -07:00
parent ba73032c90
commit 4e3f7292af
9 changed files with 742 additions and 77 deletions

View File

@ -117,7 +117,7 @@ class Rotate(ApplyMethod):
"in_place" : False, "in_place" : False,
} }
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs): def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
kwargs["path_func"] = path_along_arc(angle) kwargs["path_arc"] = angle
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
if self.in_place: if self.in_place:
method = mobject.rotate_in_place method = mobject.rotate_in_place

View File

@ -51,12 +51,42 @@ class OpeningQuote(Scene):
self.play(Write(author, run_time = 4)) self.play(Write(author, run_time = 4))
self.dither() self.dither()
class IntroVector(Scene):
class DifferentConceptions(Scene):
def construct(self): def construct(self):
physy = Physicist()
mathy = Mathematician(mode = "pondering")
compy = ComputerScientist()
creatures = [physy, compy, mathy]
physy.title = TextMobject("Physics student").to_corner(DOWN+LEFT)
compy.title = TextMobject("CS student").to_corner(DOWN+RIGHT)
mathy.title = TextMobject("Mathematician").to_edge(DOWN)
names = VMobject(physy.title, mathy.title, compy.title)
names.arrange_submobjects(RIGHT, buff = 1)
names.to_corner(DOWN+LEFT)
for pi in creatures:
pi.next_to(pi.title, UP)
vector, symbol, coordinates = self.intro_vector()
for pi in creatures:
self.play(
Write(pi.title),
FadeIn(pi),
run_time = 1
)
self.dither(2)
self.remove(symbol, coordinates)
self.physics_conception(creatures, vector)
self.cs_conception(creatures)
self.handle_mathy(creatures)
def intro_vector(self):
plane = NumberPlane() plane = NumberPlane()
labels = plane.get_coordinate_labels() labels = VMobject(*plane.get_coordinate_labels())
vector = Vector(RIGHT+2*UP, color = YELLOW) vector = Vector(RIGHT+2*UP, color = YELLOW)
coordinates = vector_coordinate_label(vector) coordinates = vector_coordinate_label(vector)
symbol = TexMobject("\\vec{\\textbf{v}}")
symbol.shift(0.5*(RIGHT+UP))
self.play(ShowCreation( self.play(ShowCreation(
plane, plane,
@ -67,71 +97,542 @@ class IntroVector(Scene):
vector, vector,
submobject_mode = "one_at_a_time" submobject_mode = "one_at_a_time"
)) ))
self.play(Write(VMobject(*labels)), Write(coordinates)) self.play(
Write(labels),
Write(coordinates),
Write(symbol)
)
self.dither(2)
self.play(
FadeOut(plane),
FadeOut(labels),
ApplyMethod(vector.shift, 4*LEFT+UP),
ApplyMethod(coordinates.shift, 2.5*RIGHT+0.5*DOWN),
ApplyMethod(symbol.shift, 0.5*(UP+LEFT))
)
self.remove(plane, labels)
return vector, symbol, coordinates
def physics_conception(self, creatures, original_vector):
self.fade_all_but(creatures, 0)
physy, compy, mathy = creatures
vector = Vector(2*RIGHT)
vector.next_to(physy, UP+RIGHT)
brace = Brace(vector, DOWN)
length = TextMobject("Length")
length.next_to(brace, DOWN)
group = VMobject(vector, brace, length)
group.rotate_in_place(np.pi/6)
vector.get_center = lambda : vector.get_start()
direction = TextMobject("Direction")
direction.next_to(vector, RIGHT)
direction.shift(UP)
two_dimensional = TextMobject("Two-dimensional")
three_dimensional = TextMobject("Three-dimensional")
two_dimensional.to_corner(UP+RIGHT)
three_dimensional.to_corner(UP+RIGHT)
random_vectors = VMobject(*[
Vector(
random.uniform(-2, 2)*RIGHT + \
random.uniform(-2, 2)*UP
).shift(
random.uniform(0, 4)*RIGHT + \
random.uniform(-1, 2)*UP
).highlight(random_color())
for x in range(5)
])
self.play(
Transform(original_vector, vector),
ApplyMethod(physy.change_mode, "speaking")
)
self.remove(original_vector)
self.add(vector )
self.dither()
self.play(
GrowFromCenter(brace),
Write(length),
run_time = 1
)
self.dither()
self.remove(brace, length)
self.play(
Rotate(vector, np.pi/3, in_place = True),
Write(direction),
run_time = 1
)
for angle in -2*np.pi/3, np.pi/3:
self.play(Rotate(
vector, angle,
in_place = True,
run_time = 1
))
self.play(ApplyMethod(physy.change_mode, "plain"))
self.remove(direction)
for point in 2*UP, 4*RIGHT, ORIGIN:
self.play(ApplyMethod(vector.move_to, point))
self.dither()
self.play(
Write(two_dimensional),
ApplyMethod(physy.change_mode, "pondering"),
ShowCreation(random_vectors, submobject_mode = "lagged_start"),
run_time = 1
)
self.dither(2)
self.remove(random_vectors, vector)
self.play(Transform(two_dimensional, three_dimensional))
self.dither(5)
self.remove(two_dimensional)
self.restore_creatures(creatures)
def cs_conception(self, creatures):
self.fade_all_but(creatures, 1)
physy, compy, mathy = creatures
title = TextMobject("Vectors $\\Leftrightarrow$ lists of numbers")
title.to_edge(UP)
vectors = VMobject(*map(matrix_to_mobject, [
[2, 1],
[5, 0, 0, -3],
[2.3, -7.1, 0.1],
]))
vectors.arrange_submobjects(RIGHT, buff = 1)
vectors.to_edge(LEFT)
self.play(
ApplyMethod(compy.change_mode, "sassy"),
Write(title, run_time = 1)
)
self.play(Write(vectors))
self.dither()
self.play(ApplyMethod(compy.change_mode, "pondering"))
self.house_example(vectors, title)
self.restore_creatures(creatures)
def house_example(self, starter_mobject, title):
house = SVGMobject("house")
house.set_stroke(width = 0)
house.set_fill(BLUE_C, opacity = 1)
house.scale_to_fit_height(3)
house.center()
square_footage_words = TextMobject("Square footage:")
price_words = TextMobject("Price: ")
square_footage = TexMobject("2{,}600\\text{ ft}^2")
price = TextMobject("\\$300{,}000")
house.to_edge(LEFT).shift(UP)
square_footage_words.next_to(house, RIGHT)
square_footage_words.shift(0.5*UP)
square_footage_words.highlight(RED)
price_words.next_to(square_footage_words, DOWN, aligned_edge = LEFT)
price_words.highlight(GREEN)
square_footage.next_to(square_footage_words)
square_footage.highlight(RED)
price.next_to(price_words)
price.highlight(GREEN)
vector = Matrix([square_footage.copy(), price.copy()])
vector.next_to(house, RIGHT).shift(0.25*UP)
new_square_footage, new_price = vector.get_mob_matrix().flatten()
not_equals = TexMobject("\\ne")
not_equals.next_to(vector)
alt_vector = Matrix([
TextMobject("300{,}000\\text{ ft}^2").highlight(RED),
TextMobject("\\$2{,}600").highlight(GREEN)
])
alt_vector.next_to(not_equals)
brace = Brace(vector, RIGHT)
two_dimensional = TextMobject("2 dimensional")
two_dimensional.next_to(brace)
brackets = vector.get_brackets()
self.play(Transform(starter_mobject, house))
self.remove(starter_mobject)
self.add(house)
self.add(square_footage_words)
self.play(Write(square_footage, run_time = 2))
self.add(price_words)
self.play(Write(price, run_time = 2))
self.dither()
self.play(
FadeOut(square_footage_words), FadeOut(price_words),
Transform(square_footage, new_square_footage),
Transform(price, new_price),
Write(brackets),
run_time = 1
)
self.remove(square_footage_words, price_words)
self.dither()
self.play(
Write(not_equals),
Write(alt_vector),
run_time = 1
)
self.dither()
self.play(FadeOut(not_equals), FadeOut(alt_vector))
self.remove(not_equals, alt_vector)
self.dither()
self.play(
GrowFromCenter(brace),
Write(two_dimensional),
run_time = 1
)
self.dither()
everything = VMobject(
house, square_footage, price, brackets, brace,
two_dimensional, title
)
self.play(ApplyMethod(everything.shift, 2*SPACE_WIDTH*LEFT))
self.remove(everything)
def handle_mathy(self, creatures):
self.fade_all_but(creatures, 2)
physy, compy, mathy = creatures
v_color = YELLOW
w_color = BLUE
sum_color = GREEN
v_arrow = Vector([1, 1])
w_arrow = Vector([2, 1])
w_arrow.shift(v_arrow.get_end())
sum_arrow = Vector(w_arrow.get_end())
arrows = VMobject(v_arrow, w_arrow, sum_arrow)
arrows.scale(0.7)
arrows.to_edge(LEFT, buff = 2)
v_array = matrix_to_mobject([3, -5])
w_array = matrix_to_mobject([2, 1])
sum_array = matrix_to_mobject(["3+2", "-5+1"])
arrays = VMobject(
v_array, TexMobject("+"), w_array, TexMobject("="), sum_array
)
arrays.arrange_submobjects(RIGHT)
arrays.scale(0.5)
arrays.to_edge(RIGHT).shift(UP)
v_sym = TexMobject("\\vec{\\textbf{v}}")
w_sym = TexMobject("\\vec{\\textbf{w}}")
syms = VMobject(v_sym, TexMobject("+"), w_sym)
syms.arrange_submobjects(RIGHT)
syms.center().shift(2*UP)
VMobject(v_arrow, v_array, v_sym).highlight(v_color)
VMobject(w_arrow, w_array, w_sym).highlight(w_color)
VMobject(sum_arrow, sum_array).highlight(sum_color)
self.play(
Write(syms), Write(arrays),
ShowCreation(arrows, submobject_mode = "one_at_a_time"),
ApplyMethod(mathy.change_mode, "pondering"),
run_time = 2
)
self.play(Blink(mathy))
self.add_scaling(arrows, syms, arrays)
def add_scaling(self, arrows, syms, arrays):
s_arrows = VMobject(
TexMobject("2"), Vector([1, 1]).highlight(YELLOW),
TexMobject("="), Vector([2, 2]).highlight(WHITE)
)
s_arrows.arrange_submobjects(RIGHT)
s_arrows.scale(0.75)
s_arrows.next_to(arrows, DOWN)
s_arrays = VMobject(
TexMobject("2"),
matrix_to_mobject([3, -5]).highlight(YELLOW),
TextMobject("="),
matrix_to_mobject(["2(3)", "2(-5)"])
)
s_arrays.arrange_submobjects(RIGHT)
s_arrays.scale(0.5)
s_arrays.next_to(arrays, DOWN)
s_syms = TexMobject(["2", "\\vec{\\textbf{v}}"])
s_syms.split()[-1].highlight(YELLOW)
s_syms.next_to(syms, DOWN)
self.play(
Write(s_arrows), Write(s_arrays), Write(s_syms),
run_time = 2
)
self.dither() self.dither()
class DifferentConceptions(Scene):
def fade_all_but(self, creatures, index):
self.play(*[
FadeOut(VMobject(pi, pi.title))
for pi in creatures[:index] + creatures[index+1:]
])
def restore_creatures(self, creatures):
self.play(*[
ApplyFunction(lambda m : m.change_mode("plain").highlight(m.color), pi)
for pi in creatures
] + [
ApplyMethod(pi.title.set_fill, WHITE, 1.0)
for pi in creatures
])
class HelpsToHaveOneThought(Scene):
def construct(self): def construct(self):
physy = Physicist() morty = Mortimer()
mathy = Mathematician(mode = "pondering") morty.to_corner(DOWN+RIGHT)
compy = ComputerScientist() morty.look(DOWN+LEFT)
people = [physy, compy, mathy] new_morty = morty.copy().change_mode("speaking")
physy.name = TextMobject("Physics student").to_corner(DOWN+LEFT) new_morty.look(DOWN+LEFT)
compy.name = TextMobject("CS student").to_corner(DOWN+RIGHT)
mathy.name = TextMobject("Mathematician").to_edge(DOWN)
names = VMobject(physy.name, mathy.name, compy.name)
names.arrange_submobjects(RIGHT, buff = 1)
names.to_corner(DOWN+LEFT)
for pi in people:
pi.next_to(pi.name, UP)
self.add(pi)
for pi in people:
self.play(Write(pi.name), run_time = 1)
self.preview_conceptions(people)
self.physics_conception(people)
self.cs_conception(people)
self.handle_mathy(people)
def preview_conceptions(self, people):
arrow = Vector(2*RIGHT+ UP)
array = matrix_to_mobject([[2], [1]])
tex = TextMobject("""
Set $V$ with operations \\\\
$a : V \\times V \\to V$ and \\\\
$s : \\mathds{R} \\times V \\to V$ such that...
""")
physy, compy, mathy = people
physy.bubble = physy.get_bubble("speech")
compy.bubble = compy.get_bubble("speech")
mathy.bubble = mathy.get_bubble(width = 4)
for pi, sym in zip(people, [arrow, array, tex]):
pi.bubble.set_fill(BLACK, opacity = 1.0)
pi.bubble.add_content(sym)
self.play(FadeIn(pi.bubble))
self.dither()
for pi in people:
self.remove(pi.bubble)
def physics_conception(self, people):
pass
def cs_conception(self, people):
pass
def handle_mathy(self, people):
pass
randys = VMobject(*[
Randolph(color = color).scale(0.8)
for color in BLUE_D, BLUE_C, BLUE_E
])
randys.arrange_submobjects(RIGHT)
randys.to_corner(DOWN+LEFT)
randy = randys.split()[1]
speech_bubble = morty.get_bubble("speech")
words = TextMobject("Think of some vector...")
speech_bubble.position_mobject_inside(words)
thought_bubble = randy.get_bubble()
arrow = Vector([2, 1]).scale(0.7)
or_word = TextMobject("or")
array = Matrix([2, 1]).scale(0.5)
q_mark = TextMobject("?")
thought = VMobject(arrow, or_word, array, q_mark)
thought.arrange_submobjects(RIGHT, buff = 0.2)
thought_bubble.position_mobject_inside(thought)
thought_bubble.set_fill(BLACK, opacity = 1)
self.add(morty, randys)
self.play(
ShowCreation(speech_bubble),
Transform(morty, new_morty),
Write(words)
)
self.dither(2)
self.play(
FadeOut(speech_bubble),
FadeOut(words),
ApplyMethod(randy.change_mode, "pondering"),
ShowCreation(thought_bubble),
Write(thought)
)
self.dither(2)
class HowIWantYouToThinkAboutVectors(Scene):
def construct(self):
vector = Vector([-2, 3])
plane = NumberPlane()
axis_labels = plane.get_axis_labels()
other_vectors = VMobject(*map(Vector, [
[1, 2], [2, -1], [4, 0]
]))
colors = [GREEN_B, MAROON_B, PINK]
for v, color in zip(other_vectors.split(), colors):
v.highlight(color)
shift_val = 4*RIGHT+DOWN
dot = Dot(radius = 0.1)
dot.highlight(RED)
tail_word = TextMobject("Tail")
tail_word.shift(0.5*DOWN+2.5*LEFT)
line = Line(tail_word, dot)
self.play(ShowCreation(vector, submobject_mode = "one_at_a_time"))
self.dither(2)
self.play(
ShowCreation(plane, summobject_mode = "lagged_start"),
Animation(vector)
)
self.play(Write(axis_labels, run_time = 1))
self.dither()
self.play(
GrowFromCenter(dot),
ShowCreation(line),
Write(tail_word, run_time = 1)
)
self.dither()
self.play(
FadeOut(tail_word),
ApplyMethod(VMobject(dot, line).scale, 0.01)
)
self.remove(tail_word, line, dot)
self.dither()
self.play(ApplyMethod(
vector.shift, shift_val,
path_arc = 3*np.pi/2,
run_time = 3
))
self.play(ApplyMethod(
vector.shift, -shift_val,
rate_func = rush_into,
run_time = 0.5
))
self.dither(3)
self.play(ShowCreation(
other_vectors,
submobject_mode = "one_at_a_time",
run_time = 3
))
self.dither(3)
x_axis, y_axis = plane.get_axes().split()
x_label = axis_labels.split()[0]
x_axis = x_axis.copy()
x_label = x_label.copy()
everything = VMobject(*self.mobjects)
self.play(
FadeOut(everything),
Animation(x_axis), Animation(x_label)
)
class ListsOfNumbersAddOn(Scene):
def construct(self):
arrays = VMobject(*map(matrix_to_mobject, [
[-2, 3], [1, 2], [2, -1], [4, 0]
]))
arrays.arrange_submobjects(buff = 0.4)
arrays.scale(2)
self.play(Write(arrays))
self.dither(2)
class CoordinateSystemWalkthrough(VectorCoordinateScene):
def construct(self):
self.introduce_coordinate_plane()
self.show_vector_coordinates()
self.coords_to_vector([3, -1])
self.vector_to_coords([-2, -1.5], integer_labels = False)
def introduce_coordinate_plane(self):
plane = NumberPlane()
x_axis, y_axis = plane.get_axes().copy().split()
x_label, y_label = plane.get_axis_labels().split()
number_line = NumberLine(tick_frequency = 1)
x_tick_marks = number_line.get_tick_marks()
y_tick_marks = x_tick_marks.copy().rotate(np.pi/2)
tick_marks = VMobject(x_tick_marks, y_tick_marks)
tick_marks.highlight(WHITE)
plane_lines = filter(
lambda m : isinstance(m, Line),
plane.submobject_family()
)
origin_words = TextMobject("Origin")
origin_words.shift(2*UP+2*LEFT)
dot = Dot(radius = 0.1).highlight(RED)
line = Line(origin_words.get_bottom(), dot.get_corner(UP+LEFT))
unit_brace = Brace(Line(RIGHT, 2*RIGHT))
one = TexMobject("1").next_to(unit_brace, DOWN)
self.add(x_axis, x_label)
self.dither()
self.play(ShowCreation(y_axis))
self.play(Write(y_label, run_time = 1))
self.dither(2)
self.play(
Write(origin_words),
GrowFromCenter(dot),
ShowCreation(line),
run_time = 1
)
self.dither(2)
self.play(
FadeOut(VMobject(origin_words, dot, line))
)
self.remove(origin_words, dot, line)
self.dither()
self.play(
ShowCreation(tick_marks, submobject_mode = "one_at_a_time")
)
self.play(
GrowFromCenter(unit_brace),
Write(one, run_time = 1)
)
self.dither(2)
self.remove(unit_brace, one)
self.play(
*map(GrowFromCenter, plane_lines) + [
Animation(x_axis), Animation(y_axis)
])
self.dither()
self.play(
FadeOut(plane),
Animation(VMobject(x_axis, y_axis, tick_marks))
)
self.remove(plane)
self.add(tick_marks)
def show_vector_coordinates(self):
starting_mobjects = list(self.mobjects)
vector = Vector([-2, 3])
x_line = Line(ORIGIN, -2*RIGHT)
y_line = Line(-2*RIGHT, -2*RIGHT+3*UP)
x_line.highlight(X_COLOR)
y_line.highlight(Y_COLOR)
array = vector_coordinate_label(vector)
x_label, y_label = array.get_mob_matrix().flatten()
x_label_copy = x_label.copy()
x_label_copy.highlight(X_COLOR)
y_label_copy = y_label.copy()
y_label_copy.highlight(Y_COLOR)
point = Dot(4*LEFT+2*UP)
point_word = TextMobject("(-4, 2) as \\\\ a point")
point_word.scale(0.7)
point_word.next_to(point, DOWN)
point.add(point_word)
self.play(ShowCreation(vector, submobject_mode = "one_at_a_time"))
self.play(Write(array))
self.dither(2)
self.play(ApplyMethod(x_label_copy.next_to, x_line, DOWN))
self.play(ShowCreation(x_line))
self.dither(2)
self.play(ApplyMethod(y_label_copy.next_to, y_line, LEFT))
self.play(ShowCreation(y_line))
self.dither(2)
self.play(FadeIn(point))
self.dither()
self.play(ApplyFunction(
lambda m : m.scale_in_place(1.25).highlight(YELLOW),
array.get_brackets(),
rate_func = there_and_back
))
self.dither()
self.play(FadeOut(point))
self.remove(point)
self.dither()
self.clear()
self.add(*starting_mobjects)
class ThreeAxisLabels(Scene):
def construct(self):
z = TexMobject("z").scale(2)
z.show()
self.play(Write(z, run_time = 1))
self.dither(2)

View File

@ -5,17 +5,22 @@ from mobject import Mobject
from mobject.vectorized_mobject import VMobject from mobject.vectorized_mobject import VMobject
from mobject.tex_mobject import TexMobject, TextMobject from mobject.tex_mobject import TexMobject, TextMobject
from animation.transform import ApplyPointwiseFunction, Transform, \ from animation.transform import ApplyPointwiseFunction, Transform, \
ApplyMethod, FadeOut ApplyMethod, FadeOut, ApplyFunction
from animation.simple_animations import ShowCreation from animation.simple_animations import ShowCreation, Write
from topics.number_line import NumberPlane from topics.number_line import NumberPlane
from topics.geometry import Vector, Line, Circle from topics.geometry import Vector, Line, Circle, Arrow
from helpers import * from helpers import *
VECTOR_LABEL_SCALE_VAL = 0.7 VECTOR_LABEL_SCALE_VAL = 0.7
X_COLOR = GREEN_C
Y_COLOR = RED_C
def matrix_to_tex_string(matrix): def matrix_to_tex_string(matrix):
matrix = np.array(matrix).astype("string") matrix = np.array(matrix).astype("string")
if matrix.ndim == 1:
matrix = matrix.reshape((matrix.size, 1))
n_rows, n_cols = matrix.shape n_rows, n_cols = matrix.shape
prefix = "\\left[ \\begin{array}{%s}"%("c"*n_cols) prefix = "\\left[ \\begin{array}{%s}"%("c"*n_cols)
suffix = "\\end{array} \\right]" suffix = "\\end{array} \\right]"
@ -35,7 +40,7 @@ def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2):
vect = vect.astype(int) vect = vect.astype(int)
vect = vect[:n_dim] vect = vect[:n_dim]
vect = vect.reshape((n_dim, 1)) vect = vect.reshape((n_dim, 1))
label = matrix_to_mobject(vect) label = Matrix(vect)
label.scale(VECTOR_LABEL_SCALE_VAL) label.scale(VECTOR_LABEL_SCALE_VAL)
shift_dir = np.array(vector_mob.get_end()) shift_dir = np.array(vector_mob.get_end())
@ -146,7 +151,8 @@ class Matrix(VMobject):
""" """
VMobject.__init__(self, **kwargs) VMobject.__init__(self, **kwargs)
matrix = np.array(matrix) matrix = np.array(matrix)
assert(matrix.ndim == 2) if matrix.ndim == 1:
matrix = matrix.reshape((matrix.size, 1))
if not isinstance(matrix[0][0], Mobject): if not isinstance(matrix[0][0], Mobject):
matrix = matrix.astype("string") matrix = matrix.astype("string")
matrix = self.string_matrix_to_mob_matrix(matrix) matrix = self.string_matrix_to_mob_matrix(matrix)
@ -174,9 +180,6 @@ class Matrix(VMobject):
mob.next_to(matrix[i-1][j], DOWN, self.v_buff) mob.next_to(matrix[i-1][j], DOWN, self.v_buff)
return self return self
def get_mob_matrix(self):
return self.mob_matrix
def add_brackets(self): def add_brackets(self):
bracket_pair = TexMobject("\\big[ \\big]") bracket_pair = TexMobject("\\big[ \\big]")
bracket_pair.scale(2) bracket_pair.scale(2)
@ -185,8 +188,15 @@ class Matrix(VMobject):
l_bracket.next_to(self, LEFT) l_bracket.next_to(self, LEFT)
r_bracket.next_to(self, RIGHT) r_bracket.next_to(self, RIGHT)
self.add(l_bracket, r_bracket) self.add(l_bracket, r_bracket)
self.brackets = VMobject(l_bracket, r_bracket)
return self return self
def get_mob_matrix(self):
return self.mob_matrix
def get_brackets(self):
return self.brackets
class NumericalMatrixMultiplication(Scene): class NumericalMatrixMultiplication(Scene):
CONFIG = { CONFIG = {
@ -316,6 +326,100 @@ class NumericalMatrixMultiplication(Scene):
class VectorCoordinateScene(Scene):
def position_x_coordinate(self, x_coord, x_line, vector):
x_coord.next_to(x_line, -vector[1]*UP)
x_coord.highlight(X_COLOR)
return x_coord
def position_y_coordinate(self, y_coord, y_line, vector):
y_coord.next_to(y_line, vector[0]*RIGHT)
y_coord.highlight(Y_COLOR)
return y_coord
def coords_to_vector(self, vector, coords_start = 2*RIGHT+2*UP, cleanup = True):
starting_mobjects = list(self.mobjects)
array = Matrix(vector)
array.shift(coords_start)
arrow = Vector(vector)
x_line = Line(ORIGIN, vector[0]*RIGHT)
y_line = Line(x_line.get_end(), arrow.get_end())
x_line.highlight(X_COLOR)
y_line.highlight(Y_COLOR)
x_coord, y_coord = array.get_mob_matrix().flatten()
self.play(Write(array, run_time = 1))
self.dither()
self.play(ApplyFunction(
lambda x : self.position_x_coordinate(x, x_line, vector),
x_coord
))
self.play(ShowCreation(x_line))
self.play(
ApplyFunction(
lambda y : self.position_y_coordinate(y, y_line, vector),
y_coord
),
FadeOut(array.get_brackets())
)
self.play(ShowCreation(y_line))
self.play(ShowCreation(arrow, submobject_mode = "one_at_a_time"))
self.dither()
if cleanup:
self.clear()
self.add(*starting_mobjects)
def vector_to_coords(self, vector, integer_labels = True, cleanup = True):
starting_mobjects = list(self.mobjects)
show_creation = False
if isinstance(vector, Arrow):
arrow = vector
vector = arrow.get_end()[:2]
else:
arrow = Vector(vector)
show_creation = True
array = vector_coordinate_label(arrow, integer_labels = integer_labels)
x_line = Line(ORIGIN, vector[0]*RIGHT)
y_line = Line(x_line.get_end(), arrow.get_end())
x_line.highlight(X_COLOR)
y_line.highlight(Y_COLOR)
x_coord, y_coord = array.get_mob_matrix().flatten()
x_coord_start = self.position_x_coordinate(
x_coord.copy(), x_line, vector
)
y_coord_start = self.position_y_coordinate(
y_coord.copy(), y_line, vector
)
brackets = array.get_brackets()
if show_creation:
self.play(ShowCreation(arrow, submobject_mode = "one_at_a_time"))
self.play(
ShowCreation(x_line),
Write(x_coord_start),
run_time = 1
)
self.play(
ShowCreation(y_line),
Write(y_coord_start),
run_time = 1
)
self.dither()
self.play(
Transform(x_coord_start, x_coord),
Transform(y_coord_start, y_coord),
Write(brackets),
run_time = 1
)
self.dither()
self.remove(x_coord_start, y_coord_start)
self.add(x_coord, y_coord)
if cleanup:
self.clear()
self.add(*starting_mobjects)

View File

@ -431,7 +431,7 @@ def z_to_vector(vector):
v = np.array(vector) / norm v = np.array(vector) / norm
phi = np.arccos(v[2]) phi = np.arccos(v[2])
if any(v[:2]): if any(v[:2]):
#projection of vector to {x^2 + y^2 = 1} #projection of vector to unit circle
axis_proj = v[:2] / np.linalg.norm(v[:2]) axis_proj = v[:2] / np.linalg.norm(v[:2])
theta = np.arccos(axis_proj[0]) theta = np.arccos(axis_proj[0])
if axis_proj[1] < 0: if axis_proj[1] < 0:

View File

@ -219,9 +219,14 @@ class Mobject(object):
self.shift(target_point - anchor_point + buff*direction) self.shift(target_point - anchor_point + buff*direction)
return self return self
def stretch_to_fit(self, length, dim): def stretch_to_fit(self, length, dim, stretch = True):
old_length = self.length_over_dim(dim) old_length = self.length_over_dim(dim)
self.do_in_place(self.stretch, length/old_length, dim) if old_length == 0:
return self
if stretch:
self.do_in_place(self.stretch, length/old_length, dim)
else:
self.do_in_place(self.scale, length/old_length)
return self return self
def stretch_to_fit_width(self, width): def stretch_to_fit_width(self, width):
@ -231,10 +236,19 @@ class Mobject(object):
return self.stretch_to_fit(height, 1) return self.stretch_to_fit(height, 1)
def scale_to_fit_width(self, width): def scale_to_fit_width(self, width):
return self.scale(width/self.get_width()) return self.stretch_to_fit(width, 0, stretch = False)
def scale_to_fit_height(self, height): def scale_to_fit_height(self, height):
return self.scale(height/self.get_height()) return self.stretch_to_fit(height, 1, stretch = False)
def move_to(self, point_or_mobject, side_to_align = ORIGIN):
if isinstance(point_or_mobject, Mobject):
target = point_or_mobject.get_critical_point(side_to_align)
else:
target = point_or_mobject
anchor_point = self.get_critical_point(side_to_align)
self.shift(target - anchor_point)
return self
def replace(self, mobject, stretch = False): def replace(self, mobject, stretch = False):
if not mobject.get_num_points() and not mobject.submobjects: if not mobject.get_num_points() and not mobject.submobjects:
@ -244,8 +258,8 @@ class Mobject(object):
self.stretch_to_fit_width(mobject.get_width()) self.stretch_to_fit_width(mobject.get_width())
self.stretch_to_fit_height(mobject.get_height()) self.stretch_to_fit_height(mobject.get_height())
else: else:
self.scale(mobject.get_width()/self.get_width()) self.scale_to_fit_width(mobject.get_width())
self.center().shift(mobject.get_center()) self.shift(mobject.get_center() - self.get_center())
return self return self
def position_endpoints_on(self, start, end): def position_endpoints_on(self, start, end):

View File

@ -74,6 +74,11 @@ class VMobject(Mobject):
self.set_stroke(color = color) self.set_stroke(color = color)
return self return self
def fade(self, darkness = 0.5):
self.set_fill(opacity = 1-darkness)
Mobject.fade(self, darkness)
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[self.fill_rgb<0] = 0

View File

@ -77,18 +77,36 @@ class PiCreature(SVGMobject):
def change_mode(self, mode): def change_mode(self, mode):
curr_center = self.get_center() curr_center = self.get_center()
curr_height = self.get_height() curr_height = self.get_height()
looking_direction = None
looking_direction = self.get_looking_direction()
should_be_flipped = self.is_flipped() should_be_flipped = self.is_flipped()
self.__init__(mode) self.__init__(mode)
self.scale_to_fit_height(curr_height) self.scale_to_fit_height(curr_height)
self.shift(curr_center) self.shift(curr_center)
if should_be_flipped^self.is_flipped(): self.look(looking_direction)
if should_be_flipped ^ self.is_flipped():
self.flip() self.flip()
return self return self
def look_left(self): def look(self, direction):
self.change_mode(self.mode + "_looking_left") x, y = direction[:2]
for pupil, eye in zip(self.pupils.split(), self.eyes.split()):
pupil.move_to(eye, side_to_align = direction)
if y > 0 and x != 0: # Look up and to a side
nudge_size = pupil.get_height()/4.
if x > 0:
nudge = nudge_size*(DOWN+LEFT)
else:
nudge = nudge_size*(DOWN+RIGHT)
pupil.shift(nudge)
return self return self
def get_looking_direction(self):
return np.sign(np.round(
self.pupils.get_center() - self.eyes.get_center(),
decimals = 1
))
def is_flipped(self): def is_flipped(self):
return self.eyes.submobjects[0].get_center()[0] > \ return self.eyes.submobjects[0].get_center()[0] > \
self.eyes.submobjects[1].get_center()[0] self.eyes.submobjects[1].get_center()[0]

View File

@ -172,6 +172,8 @@ class Vector(Arrow):
"buff" : 0, "buff" : 0,
} }
def __init__(self, direction, **kwargs): def __init__(self, direction, **kwargs):
if len(direction) == 2:
direction = np.append(np.array(direction), 0)
Arrow.__init__(self, ORIGIN, direction, **kwargs) Arrow.__init__(self, ORIGIN, direction, **kwargs)
class DoubleArrow(Arrow): class DoubleArrow(Arrow):

View File

@ -28,7 +28,8 @@ class NumberLine(VMobject):
def generate_points(self): def generate_points(self):
self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT) self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT)
self.add(self.main_line) self.tick_marks = VMobject()
self.add(self.main_line, self.tick_marks)
for x in self.get_tick_numbers(): for x in self.get_tick_numbers():
self.add_tick(x, self.tick_size) self.add_tick(x, self.tick_size)
for x in self.numbers_with_elongated_ticks: for x in self.numbers_with_elongated_ticks:
@ -37,12 +38,15 @@ class NumberLine(VMobject):
self.shift(-self.number_to_point(self.number_at_center)) self.shift(-self.number_to_point(self.number_at_center))
def add_tick(self, x, size): def add_tick(self, x, size):
self.add(Line( self.tick_marks.add(Line(
x*RIGHT+size*DOWN, x*RIGHT+size*DOWN,
x*RIGHT+size*UP, x*RIGHT+size*UP,
)) ))
return self return self
def get_tick_marks(self):
return self.tick_marks
def get_tick_numbers(self): def get_tick_numbers(self):
return np.arange(self.leftmost_tick, self.x_max, self.tick_frequency) return np.arange(self.leftmost_tick, self.x_max, self.tick_frequency)
@ -160,6 +164,9 @@ class NumberPlane(VMobject):
self.add(self.axes, self.main_lines, self.secondary_lines) self.add(self.axes, self.main_lines, self.secondary_lines)
self.stretch(self.space_unit_to_x_unit, 0) self.stretch(self.space_unit_to_x_unit, 0)
self.stretch(self.space_unit_to_y_unit, 1) self.stretch(self.space_unit_to_y_unit, 1)
#Put x_axis before y_axis
y_axis, x_axis = self.axes.split()
self.axes = VMobject(x_axis, y_axis)
def init_colors(self): def init_colors(self):
VMobject.init_colors(self) VMobject.init_colors(self)
@ -206,6 +213,20 @@ class NumberPlane(VMobject):
result.append(num) result.append(num)
return result return result
def get_axes(self):
return self.axes
def get_axis_labels(self, x_label = "x", y_label = "y"):
x_axis, y_axis = self.get_axes().split()
x_label_mob = TexMobject(x_label)
y_label_mob = TexMobject(y_label)
x_label_mob.next_to(x_axis, DOWN)
x_label_mob.to_edge(RIGHT)
y_label_mob.next_to(y_axis, RIGHT)
y_label_mob.to_edge(UP)
return VMobject(x_label_mob, y_label_mob)
def add_coordinates(self, x_vals = None, y_vals = None): def add_coordinates(self, x_vals = None, y_vals = None):
self.add(*self.get_coordinate_labels(x_vals, y_vals)) self.add(*self.get_coordinate_labels(x_vals, y_vals))
return self return self