diff --git a/mobject/coordinate_systems.py b/mobject/coordinate_systems.py new file mode 100644 index 00000000..0b92a04c --- /dev/null +++ b/mobject/coordinate_systems.py @@ -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 + diff --git a/old_projects/fourier.py b/old_projects/fourier.py index 571bd341..830f8c78 100644 --- a/old_projects/fourier.py +++ b/old_projects/fourier.py @@ -4089,7 +4089,6 @@ class SubscribeOrBinge(PiCreatureScene): ) ) - class CloseWithAPuzzle(TeacherStudentsScene): def construct(self): self.teacher_says("Close with a puzzle!", run_time = 1) diff --git a/topics/complex_numbers.py b/topics/complex_numbers.py index 7d677b64..3d7370d2 100644 --- a/topics/complex_numbers.py +++ b/topics/complex_numbers.py @@ -2,15 +2,16 @@ from constants import * from animation.animation import Animation -from animation.movement import Homotopy from animation.creation import ShowCreation +from animation.movement import Homotopy from animation.movement import SmoothedVectorizedHomotopy from animation.transform import ApplyPointwiseFunction 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 TextMobject from mobject.types.vectorized_mobject import VGroup -from number_line import NumberPlane from scene.scene import Scene from utils.config_ops import digest_config from utils.config_ops import instantiate @@ -171,81 +172,6 @@ class ComplexTransformationScene(Scene): def complex_string(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): def __init__(self, function, mobject = ComplexPlane, **kwargs): if "path_func" not in kwargs: diff --git a/topics/matrix.py b/topics/matrix.py index 985651a5..3aa60a0c 100644 --- a/topics/matrix.py +++ b/topics/matrix.py @@ -19,8 +19,8 @@ from mobject.geometry import Circle from mobject.geometry import Dot from mobject.geometry import Line from mobject.geometry import Vector -from topics.number_line import Axes -from topics.number_line import NumberPlane +from mobject.coordinate_systems import Axes +from mobject.coordinate_systems import NumberPlane from constants import * diff --git a/topics/number_line.py b/topics/number_line.py index c1e8f6cb..fc47d440 100644 --- a/topics/number_line.py +++ b/topics/number_line.py @@ -3,13 +3,10 @@ from constants import * from mobject.svg.tex_mobject import TexMobject from mobject.types.vectorized_mobject import VGroup 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 Line from utils.bezier import interpolate from utils.config_ops import digest_config -from utils.space_ops import angle_of_vector class NumberLine(VMobject): CONFIG = { @@ -153,279 +150,6 @@ class UnitInterval(NumberLine): "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 - - diff --git a/topics/vector_space_scene.py b/topics/vector_space_scene.py index 591eb966..e22cd90d 100644 --- a/topics/vector_space_scene.py +++ b/topics/vector_space_scene.py @@ -21,8 +21,8 @@ from mobject.geometry import Dot from mobject.geometry import Line from mobject.geometry import Square from mobject.geometry import Vector -from topics.number_line import Axes -from topics.number_line import NumberPlane +from mobject.coordinate_systems import Axes +from mobject.coordinate_systems import NumberPlane from constants import * from topics.matrix import Matrix