Added coordinate_systems.py in mobject/ to house Axes, NumberPlane, ComplexPlane

This commit is contained in:
Grant Sanderson
2018-03-31 18:31:56 -07:00
parent 16dde2f84d
commit a61f5b044f
6 changed files with 358 additions and 358 deletions

View File

@ -0,0 +1,351 @@
from __future__ import absolute_import
import numpy as np
from constants import *
from mobject.geometry import Arrow
from mobject.geometry import Line
from mobject.svg.tex_mobject import TexMobject
from mobject.types.vectorized_mobject import VGroup
from mobject.types.vectorized_mobject import VMobject
from topics.functions import ParametricFunction
from topics.number_line import NumberLine
from utils.config_ops import digest_config
from utils.space_ops import angle_of_vector
from utils.space_ops import R3_to_complex
from utils.space_ops import complex_to_R3
#TODO: There should be much more code reuse between Axes, NumberPlane and GraphScene
class Axes(VGroup):
CONFIG = {
"propagate_style_to_family" : True,
"three_d" : False,
"number_line_config" : {
"color" : LIGHT_GREY,
"include_tip" : True,
},
"x_axis_config" : {},
"y_axis_config" : {},
"z_axis_config" : {},
"x_min" : -FRAME_X_RADIUS,
"x_max" : FRAME_X_RADIUS,
"y_min" : -FRAME_Y_RADIUS,
"y_max" : FRAME_Y_RADIUS,
"z_min" : -3.5,
"z_max" : 3.5,
"z_normal" : DOWN,
"default_num_graph_points" : 100,
}
def __init__(self, **kwargs):
VGroup.__init__(self, **kwargs)
self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config)
self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config)
self.y_axis.rotate(np.pi/2, about_point = ORIGIN)
self.add(self.x_axis, self.y_axis)
if self.three_d:
self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config)
self.z_axis.rotate(-np.pi/2, UP, about_point = ORIGIN)
self.z_axis.rotate(
angle_of_vector(self.z_normal), OUT,
about_point = ORIGIN
)
self.add(self.z_axis)
def get_axis(self, min_val, max_val, extra_config):
config = dict(self.number_line_config)
config.update(extra_config)
return NumberLine(x_min = min_val, x_max = max_val, **config)
def coords_to_point(self, x, y):
origin = self.x_axis.number_to_point(0)
x_axis_projection = self.x_axis.number_to_point(x)
y_axis_projection = self.y_axis.number_to_point(y)
return x_axis_projection + y_axis_projection - origin
def point_to_coords(self, point):
return (
self.x_axis.point_to_number(point),
self.y_axis.point_to_number(point),
)
def get_graph(
self, function, num_graph_points = None,
x_min = None,
x_max = None,
**kwargs
):
kwargs["fill_opacity"] = kwargs.get("fill_opacity", 0)
kwargs["num_anchor_points"] = \
num_graph_points or self.default_num_graph_points
x_min = x_min or self.x_min
x_max = x_max or self.x_max
graph = ParametricFunction(
lambda t : self.coords_to_point(t, function(t)),
t_min = x_min,
t_max = x_max,
**kwargs
)
graph.underlying_function = function
return graph
def input_to_graph_point(self, x, graph):
if hasattr(graph, "underlying_function"):
return self.coords_to_point(x, graph.underlying_function(x))
else:
#binary search
lh, rh = 0, 1
while abs(lh - rh) > 0.001:
mh = np.mean([lh, rh])
hands = [lh, mh, rh]
points = map(graph.point_from_proportion, hands)
lx, mx, rx = map(self.x_axis.point_to_number, points)
if lx <= x and rx >= x:
if mx > x:
rh = mh
else:
lh = mh
elif lx <= x and rx <= x:
return points[2]
elif lx >= x and rx >= x:
return points[0]
elif lx > x and rx < x:
lh, rh = rh, lh
return points[1]
return self.coords_to_point(x, graph.underlying_function(x))
class ThreeDAxes(Axes):
CONFIG = {
"x_min" : -5.5,
"x_max" : 5.5,
"y_min" : -4.5,
"y_max" : 4.5,
"three_d" : True,
}
class NumberPlane(VMobject):
CONFIG = {
"color" : BLUE_D,
"secondary_color" : BLUE_E,
"axes_color" : WHITE,
"secondary_stroke_width" : 1,
# TODO: Allow coordinate center of NumberPlane to not be at (0, 0)
"x_radius": None,
"y_radius": None,
"x_unit_size" : 1,
"y_unit_size" : 1,
"center_point" : ORIGIN,
"x_line_frequency" : 1,
"y_line_frequency" : 1,
"secondary_line_ratio" : 1,
"written_coordinate_height" : 0.2,
"propagate_style_to_family" : False,
"make_smooth_after_applying_functions" : True,
}
def generate_points(self):
if self.x_radius is None:
center_to_edge = (FRAME_X_RADIUS + abs(self.center_point[0]))
self.x_radius = center_to_edge / self.x_unit_size
if self.y_radius is None:
center_to_edge = (FRAME_Y_RADIUS + abs(self.center_point[1]))
self.y_radius = center_to_edge / self.y_unit_size
self.axes = VMobject()
self.main_lines = VMobject()
self.secondary_lines = VMobject()
tuples = [
(
self.x_radius,
self.x_line_frequency,
self.y_radius*DOWN,
self.y_radius*UP,
RIGHT
),
(
self.y_radius,
self.y_line_frequency,
self.x_radius*LEFT,
self.x_radius*RIGHT,
UP,
),
]
for radius, freq, start, end, unit in tuples:
main_range = np.arange(0, radius, freq)
step = freq/float(freq + self.secondary_line_ratio)
for v in np.arange(0, radius, step):
line1 = Line(start+v*unit, end+v*unit)
line2 = Line(start-v*unit, end-v*unit)
if v == 0:
self.axes.add(line1)
elif v in main_range:
self.main_lines.add(line1, line2)
else:
self.secondary_lines.add(line1, line2)
self.add(self.secondary_lines, self.main_lines, self.axes)
self.stretch(self.x_unit_size, 0)
self.stretch(self.y_unit_size, 1)
self.shift(self.center_point)
#Put x_axis before y_axis
y_axis, x_axis = self.axes.split()
self.axes = VMobject(x_axis, y_axis)
def init_colors(self):
VMobject.init_colors(self)
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):
return self.coords_to_point(0, 0)
def coords_to_point(self, x, y):
x, y = np.array([x, y])
result = self.axes.get_center()
result += x*self.get_x_unit_size()*RIGHT
result += y*self.get_y_unit_size()*UP
return result
def point_to_coords(self, point):
new_point = point - self.axes.get_center()
x = new_point[0]/self.get_x_unit_size()
y = new_point[1]/self.get_y_unit_size()
return x, y
# Does not recompute center, unit_sizes for each call; useful for
# iterating over large lists of points, but does assume these
# attributes are kept accurate. (Could alternatively have a method
# which returns a function dynamically created after a single
# call to each of get_center(), get_x_unit_size(), etc.)
def point_to_coords_cheap(self, point):
new_point = point - self.center_point
x = new_point[0]/self.x_unit_size
y = new_point[1]/self.y_unit_size
return x, y
def get_x_unit_size(self):
return self.axes.get_width() / (2.0*self.x_radius)
def get_y_unit_size(self):
return self.axes.get_height() / (2.0*self.y_radius)
def get_coordinate_labels(self, x_vals = None, y_vals = None):
coordinate_labels = VGroup()
if x_vals == None:
x_vals = range(-int(self.x_radius), int(self.x_radius)+1)
if y_vals == None:
y_vals = range(-int(self.y_radius), int(self.y_radius)+1)
for index, vals in enumerate([x_vals, y_vals]):
num_pair = [0, 0]
for val in vals:
if val == 0:
continue
num_pair[index] = val
point = self.coords_to_point(*num_pair)
num = TexMobject(str(val))
num.add_background_rectangle()
num.scale_to_fit_height(
self.written_coordinate_height
)
num.next_to(point, DOWN+LEFT, buff = SMALL_BUFF)
coordinate_labels.add(num)
self.coordinate_labels = coordinate_labels
return coordinate_labels
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()
quads = [
(x_axis, x_label, UP, RIGHT),
(y_axis, y_label, RIGHT, UP),
]
labels = VGroup()
for axis, tex, vect, edge in quads:
label = TexMobject(tex)
label.add_background_rectangle()
label.next_to(axis, vect)
label.to_edge(edge)
labels.add(label)
self.axis_labels = labels
return labels
def add_coordinates(self, x_vals = None, y_vals = None):
self.add(*self.get_coordinate_labels(x_vals, y_vals))
return self
def get_vector(self, coords, **kwargs):
point = coords[0]*RIGHT + coords[1]*UP
arrow = Arrow(ORIGIN, coords, **kwargs)
return arrow
def prepare_for_nonlinear_transform(self, num_inserted_anchor_points = 50):
for mob in self.family_members_with_points():
num_anchors = mob.get_num_anchor_points()
if num_inserted_anchor_points > num_anchors:
mob.insert_n_anchor_points(num_inserted_anchor_points-num_anchors)
mob.make_smooth()
return self
class ComplexPlane(NumberPlane):
CONFIG = {
"color" : BLUE,
"unit_size" : 1,
"line_frequency" : 1,
"faded_line_frequency" : 0.5,
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
kwargs.update({
"x_unit_size" : self.unit_size,
"y_unit_size" : self.unit_size,
"x_line_frequency" : self.line_frequency,
"x_faded_line_frequency" : self.faded_line_frequency,
"y_line_frequency" : self.line_frequency,
"y_faded_line_frequency" : self.faded_line_frequency,
})
NumberPlane.__init__(self, **kwargs)
def number_to_point(self, number):
number = complex(number)
return self.coords_to_point(number.real, number.imag)
def point_to_number(self, point):
x, y = self.point_to_coords(point)
return complex(x, y)
def get_coordinate_labels(self, *numbers):
# TODO: Should merge this with the code from NumberPlane.get_coordinate_labels
result = VGroup()
nudge = 0.1*(DOWN+RIGHT)
if len(numbers) == 0:
numbers = range(-int(self.x_radius), int(self.x_radius)+1)
numbers += [
complex(0, y)
for y in range(-int(self.y_radius), int(self.y_radius)+1)
]
for number in numbers:
if number == complex(0, 0):
continue
point = self.number_to_point(number)
num_str = str(number).replace("j", "i")
if num_str.startswith("0"):
num_str = "0"
elif num_str in ["1i", "-1i"]:
num_str = num_str.replace("1", "")
num_mob = TexMobject(num_str)
num_mob.add_background_rectangle()
num_mob.scale_to_fit_height(self.written_coordinate_height)
num_mob.next_to(point, DOWN+LEFT, SMALL_BUFF)
result.add(num_mob)
self.coordinate_labels = result
return result
def add_coordinates(self, *numbers):
self.add(*self.get_coordinate_labels(*numbers))
return self

View File

@ -4089,7 +4089,6 @@ class SubscribeOrBinge(PiCreatureScene):
) )
) )
class CloseWithAPuzzle(TeacherStudentsScene): class CloseWithAPuzzle(TeacherStudentsScene):
def construct(self): def construct(self):
self.teacher_says("Close with a puzzle!", run_time = 1) self.teacher_says("Close with a puzzle!", run_time = 1)

View File

@ -2,15 +2,16 @@ from constants import *
from animation.animation import Animation from animation.animation import Animation
from animation.movement import Homotopy
from animation.creation import ShowCreation from animation.creation import ShowCreation
from animation.movement import Homotopy
from animation.movement import SmoothedVectorizedHomotopy from animation.movement import SmoothedVectorizedHomotopy
from animation.transform import ApplyPointwiseFunction from animation.transform import ApplyPointwiseFunction
from animation.transform import MoveToTarget from animation.transform import MoveToTarget
from mobject.coordinate_systems import NumberPlane
from mobject.coordinate_systems import ComplexPlane
from mobject.svg.tex_mobject import TexMobject from mobject.svg.tex_mobject import TexMobject
from mobject.svg.tex_mobject import TextMobject from mobject.svg.tex_mobject import TextMobject
from mobject.types.vectorized_mobject import VGroup from mobject.types.vectorized_mobject import VGroup
from number_line import NumberPlane
from scene.scene import Scene from scene.scene import Scene
from utils.config_ops import digest_config from utils.config_ops import digest_config
from utils.config_ops import instantiate from utils.config_ops import instantiate
@ -171,81 +172,6 @@ class ComplexTransformationScene(Scene):
def complex_string(complex_num): def complex_string(complex_num):
return filter(lambda c : c not in "()", str(complex_num)) return filter(lambda c : c not in "()", str(complex_num))
class ComplexPlane(NumberPlane):
CONFIG = {
"color" : BLUE,
"unit_size" : 1,
"line_frequency" : 1,
"faded_line_frequency" : 0.5,
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
kwargs.update({
"x_unit_size" : self.unit_size,
"y_unit_size" : self.unit_size,
"x_line_frequency" : self.line_frequency,
"x_faded_line_frequency" : self.faded_line_frequency,
"y_line_frequency" : self.line_frequency,
"y_faded_line_frequency" : self.faded_line_frequency,
})
NumberPlane.__init__(self, **kwargs)
def number_to_point(self, number):
number = complex(number)
return self.coords_to_point(number.real, number.imag)
def point_to_number(self, point):
x, y = self.point_to_coords(point)
return complex(x, y)
def get_coordinate_labels(self, *numbers):
# TODO: Should merge this with the code from NumberPlane.get_coordinate_labels
result = VGroup()
nudge = 0.1*(DOWN+RIGHT)
if len(numbers) == 0:
numbers = range(-int(self.x_radius), int(self.x_radius)+1)
numbers += [
complex(0, y)
for y in range(-int(self.y_radius), int(self.y_radius)+1)
]
for number in numbers:
if number == complex(0, 0):
continue
point = self.number_to_point(number)
num_str = str(number).replace("j", "i")
if num_str.startswith("0"):
num_str = "0"
elif num_str in ["1i", "-1i"]:
num_str = num_str.replace("1", "")
num_mob = TexMobject(num_str)
num_mob.add_background_rectangle()
num_mob.scale_to_fit_height(self.written_coordinate_height)
num_mob.next_to(point, DOWN+LEFT, SMALL_BUFF)
result.add(num_mob)
self.coordinate_labels = result
return result
def add_coordinates(self, *numbers):
self.add(*self.get_coordinate_labels(*numbers))
return self
def add_spider_web(self, circle_freq = 1, angle_freq = np.pi/6):
# This code no longer works because it has this reference to self.fade_factor
# which is never initialized. Shall we delete this little-used function entirely?
self.fade(self.fade_factor)
config = {
"color" : self.color,
"density" : self.density,
}
for radius in np.arange(circle_freq, FRAME_X_RADIUS, circle_freq):
self.add(Circle(radius = radius, **config))
for angle in np.arange(0, 2*np.pi, angle_freq):
end_point = np.cos(angle)*RIGHT + np.sin(angle)*UP
end_point *= FRAME_X_RADIUS
self.add(Line(ORIGIN, end_point, **config))
return self
class ComplexFunction(ApplyPointwiseFunction): class ComplexFunction(ApplyPointwiseFunction):
def __init__(self, function, mobject = ComplexPlane, **kwargs): def __init__(self, function, mobject = ComplexPlane, **kwargs):
if "path_func" not in kwargs: if "path_func" not in kwargs:

View File

@ -19,8 +19,8 @@ from mobject.geometry import Circle
from mobject.geometry import Dot from mobject.geometry import Dot
from mobject.geometry import Line from mobject.geometry import Line
from mobject.geometry import Vector from mobject.geometry import Vector
from topics.number_line import Axes from mobject.coordinate_systems import Axes
from topics.number_line import NumberPlane from mobject.coordinate_systems import NumberPlane
from constants import * from constants import *

View File

@ -3,13 +3,10 @@ from constants import *
from mobject.svg.tex_mobject import TexMobject from mobject.svg.tex_mobject import TexMobject
from mobject.types.vectorized_mobject import VGroup from mobject.types.vectorized_mobject import VGroup
from mobject.types.vectorized_mobject import VMobject from mobject.types.vectorized_mobject import VMobject
from scene.scene import Scene
from topics.functions import ParametricFunction
from mobject.geometry import Arrow from mobject.geometry import Arrow
from mobject.geometry import Line from mobject.geometry import Line
from utils.bezier import interpolate from utils.bezier import interpolate
from utils.config_ops import digest_config from utils.config_ops import digest_config
from utils.space_ops import angle_of_vector
class NumberLine(VMobject): class NumberLine(VMobject):
CONFIG = { CONFIG = {
@ -153,279 +150,6 @@ class UnitInterval(NumberLine):
"number_at_center" : 0.5, "number_at_center" : 0.5,
} }
class Axes(VGroup):
CONFIG = {
"propagate_style_to_family" : True,
"three_d" : False,
"number_line_config" : {
"color" : LIGHT_GREY,
"include_tip" : True,
},
"x_axis_config" : {},
"y_axis_config" : {},
"z_axis_config" : {},
"x_min" : -FRAME_X_RADIUS,
"x_max" : FRAME_X_RADIUS,
"y_min" : -FRAME_Y_RADIUS,
"y_max" : FRAME_Y_RADIUS,
"z_min" : -3.5,
"z_max" : 3.5,
"z_normal" : DOWN,
"default_num_graph_points" : 100,
}
def __init__(self, **kwargs):
VGroup.__init__(self, **kwargs)
self.x_axis = self.get_axis(self.x_min, self.x_max, self.x_axis_config)
self.y_axis = self.get_axis(self.y_min, self.y_max, self.y_axis_config)
self.y_axis.rotate(np.pi/2, about_point = ORIGIN)
self.add(self.x_axis, self.y_axis)
if self.three_d:
self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config)
self.z_axis.rotate(-np.pi/2, UP, about_point = ORIGIN)
self.z_axis.rotate(
angle_of_vector(self.z_normal), OUT,
about_point = ORIGIN
)
self.add(self.z_axis)
def get_axis(self, min_val, max_val, extra_config):
config = dict(self.number_line_config)
config.update(extra_config)
return NumberLine(x_min = min_val, x_max = max_val, **config)
def coords_to_point(self, x, y):
origin = self.x_axis.number_to_point(0)
x_axis_projection = self.x_axis.number_to_point(x)
y_axis_projection = self.y_axis.number_to_point(y)
return x_axis_projection + y_axis_projection - origin
def point_to_coords(self, point):
return (
self.x_axis.point_to_number(point),
self.y_axis.point_to_number(point),
)
def get_graph(
self, function, num_graph_points = None,
x_min = None,
x_max = None,
**kwargs
):
kwargs["fill_opacity"] = kwargs.get("fill_opacity", 0)
kwargs["num_anchor_points"] = \
num_graph_points or self.default_num_graph_points
x_min = x_min or self.x_min
x_max = x_max or self.x_max
graph = ParametricFunction(
lambda t : self.coords_to_point(t, function(t)),
t_min = x_min,
t_max = x_max,
**kwargs
)
graph.underlying_function = function
return graph
def input_to_graph_point(self, x, graph):
if hasattr(graph, "underlying_function"):
return self.coords_to_point(x, graph.underlying_function(x))
else:
#binary search
lh, rh = 0, 1
while abs(lh - rh) > 0.001:
mh = np.mean([lh, rh])
hands = [lh, mh, rh]
points = map(graph.point_from_proportion, hands)
lx, mx, rx = map(self.x_axis.point_to_number, points)
if lx <= x and rx >= x:
if mx > x:
rh = mh
else:
lh = mh
elif lx <= x and rx <= x:
return points[2]
elif lx >= x and rx >= x:
return points[0]
elif lx > x and rx < x:
lh, rh = rh, lh
return points[1]
return self.coords_to_point(x, graph.underlying_function(x))
class ThreeDAxes(Axes):
CONFIG = {
"x_min" : -5.5,
"x_max" : 5.5,
"y_min" : -4.5,
"y_max" : 4.5,
"three_d" : True,
}
class NumberPlane(VMobject):
CONFIG = {
"color" : BLUE_D,
"secondary_color" : BLUE_E,
"axes_color" : WHITE,
"secondary_stroke_width" : 1,
# TODO: Allow coordinate center of NumberPlane to not be at (0, 0)
"x_radius": None,
"y_radius": None,
"x_unit_size" : 1,
"y_unit_size" : 1,
"center_point" : ORIGIN,
"x_line_frequency" : 1,
"y_line_frequency" : 1,
"secondary_line_ratio" : 1,
"written_coordinate_height" : 0.2,
"propagate_style_to_family" : False,
"make_smooth_after_applying_functions" : True,
}
def generate_points(self):
if self.x_radius is None:
center_to_edge = (FRAME_X_RADIUS + abs(self.center_point[0]))
self.x_radius = center_to_edge / self.x_unit_size
if self.y_radius is None:
center_to_edge = (FRAME_Y_RADIUS + abs(self.center_point[1]))
self.y_radius = center_to_edge / self.y_unit_size
self.axes = VMobject()
self.main_lines = VMobject()
self.secondary_lines = VMobject()
tuples = [
(
self.x_radius,
self.x_line_frequency,
self.y_radius*DOWN,
self.y_radius*UP,
RIGHT
),
(
self.y_radius,
self.y_line_frequency,
self.x_radius*LEFT,
self.x_radius*RIGHT,
UP,
),
]
for radius, freq, start, end, unit in tuples:
main_range = np.arange(0, radius, freq)
step = freq/float(freq + self.secondary_line_ratio)
for v in np.arange(0, radius, step):
line1 = Line(start+v*unit, end+v*unit)
line2 = Line(start-v*unit, end-v*unit)
if v == 0:
self.axes.add(line1)
elif v in main_range:
self.main_lines.add(line1, line2)
else:
self.secondary_lines.add(line1, line2)
self.add(self.secondary_lines, self.main_lines, self.axes)
self.stretch(self.x_unit_size, 0)
self.stretch(self.y_unit_size, 1)
self.shift(self.center_point)
#Put x_axis before y_axis
y_axis, x_axis = self.axes.split()
self.axes = VMobject(x_axis, y_axis)
def init_colors(self):
VMobject.init_colors(self)
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):
return self.coords_to_point(0, 0)
def coords_to_point(self, x, y):
x, y = np.array([x, y])
result = self.axes.get_center()
result += x*self.get_x_unit_size()*RIGHT
result += y*self.get_y_unit_size()*UP
return result
def point_to_coords(self, point):
new_point = point - self.axes.get_center()
x = new_point[0]/self.get_x_unit_size()
y = new_point[1]/self.get_y_unit_size()
return x, y
# Does not recompute center, unit_sizes for each call; useful for
# iterating over large lists of points, but does assume these
# attributes are kept accurate. (Could alternatively have a method
# which returns a function dynamically created after a single
# call to each of get_center(), get_x_unit_size(), etc.)
def point_to_coords_cheap(self, point):
new_point = point - self.center_point
x = new_point[0]/self.x_unit_size
y = new_point[1]/self.y_unit_size
return x, y
def get_x_unit_size(self):
return self.axes.get_width() / (2.0*self.x_radius)
def get_y_unit_size(self):
return self.axes.get_height() / (2.0*self.y_radius)
def get_coordinate_labels(self, x_vals = None, y_vals = None):
coordinate_labels = VGroup()
if x_vals == None:
x_vals = range(-int(self.x_radius), int(self.x_radius)+1)
if y_vals == None:
y_vals = range(-int(self.y_radius), int(self.y_radius)+1)
for index, vals in enumerate([x_vals, y_vals]):
num_pair = [0, 0]
for val in vals:
if val == 0:
continue
num_pair[index] = val
point = self.coords_to_point(*num_pair)
num = TexMobject(str(val))
num.add_background_rectangle()
num.scale_to_fit_height(
self.written_coordinate_height
)
num.next_to(point, DOWN+LEFT, buff = SMALL_BUFF)
coordinate_labels.add(num)
self.coordinate_labels = coordinate_labels
return coordinate_labels
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()
quads = [
(x_axis, x_label, UP, RIGHT),
(y_axis, y_label, RIGHT, UP),
]
labels = VGroup()
for axis, tex, vect, edge in quads:
label = TexMobject(tex)
label.add_background_rectangle()
label.next_to(axis, vect)
label.to_edge(edge)
labels.add(label)
self.axis_labels = labels
return labels
def add_coordinates(self, x_vals = None, y_vals = None):
self.add(*self.get_coordinate_labels(x_vals, y_vals))
return self
def get_vector(self, coords, **kwargs):
point = coords[0]*RIGHT + coords[1]*UP
arrow = Arrow(ORIGIN, coords, **kwargs)
return arrow
def prepare_for_nonlinear_transform(self, num_inserted_anchor_points = 50):
for mob in self.family_members_with_points():
num_anchors = mob.get_num_anchor_points()
if num_inserted_anchor_points > num_anchors:
mob.insert_n_anchor_points(num_inserted_anchor_points-num_anchors)
mob.make_smooth()
return self

View File

@ -21,8 +21,8 @@ from mobject.geometry import Dot
from mobject.geometry import Line from mobject.geometry import Line
from mobject.geometry import Square from mobject.geometry import Square
from mobject.geometry import Vector from mobject.geometry import Vector
from topics.number_line import Axes from mobject.coordinate_systems import Axes
from topics.number_line import NumberPlane from mobject.coordinate_systems import NumberPlane
from constants import * from constants import *
from topics.matrix import Matrix from topics.matrix import Matrix