def get_matrix_multiplication_question(self): why = TextMobject("Why?").highlight(BLUE) mult = self.get_matrix_multiplication() why.next_to(mult, UP) result = VMobject(why, mult) result.get_center = lambda : mult.get_center() return result
def get_matrix_multiplication_question(self): why = TextMobject("Why?").highlight(BLUE) mult = self.get_matrix_multiplication() why.next_to(mult, UP) result = VMobject(why, mult) result.get_center = lambda: mult.get_center() return result
def get_cross_product_question(self): cross = TexMobject("\\vec{v} \\times \\vec{w}") left_right_arrow = DoubleArrow(Point(LEFT), Point(RIGHT)) det = TextMobject("Det") q_mark = TextMobject("?") left_right_arrow.next_to(cross) det.next_to(left_right_arrow) q_mark.next_to(left_right_arrow, UP) cross_question = VMobject(cross, left_right_arrow, q_mark, det) cross_question.get_center = lambda: left_right_arrow.get_center() return cross_question
def get_cross_product_question(self): cross = TexMobject("\\vec{v} \\times \\vec{w}") left_right_arrow = DoubleArrow(Point(LEFT), Point(RIGHT)) det = TextMobject("Det") q_mark = TextMobject("?") left_right_arrow.next_to(cross) det.next_to(left_right_arrow) q_mark.next_to(left_right_arrow, UP) cross_question = VMobject(cross, left_right_arrow, q_mark, det) cross_question.get_center = lambda : left_right_arrow.get_center() return cross_question
class PiCreature(SVGMobject): CONFIG = { "color": BLUE_E, "stroke_width": 0, "fill_opacity": 1.0, "initial_scale_factor": 0.01, "corner_scale_factor": 0.75, "flip_at_start": False, "is_looking_direction_purposeful": False, "start_corner": None, } def __init__(self, mode="plain", **kwargs): self.parts_named = False svg_file = os.path.join(PI_CREATURE_DIR, "PiCreatures_%s.svg" % mode) digest_config(self, kwargs, locals()) SVGMobject.__init__(self, svg_file, **kwargs) self.init_colors() if self.flip_at_start: self.flip() if self.start_corner is not None: self.to_corner(self.start_corner) def name_parts(self): self.mouth = self.submobjects[MOUTH_INDEX] self.body = self.submobjects[BODY_INDEX] self.pupils = VMobject(*[ self.submobjects[LEFT_PUPIL_INDEX], self.submobjects[RIGHT_PUPIL_INDEX] ]) self.eyes = VMobject(*[ self.submobjects[LEFT_EYE_INDEX], self.submobjects[RIGHT_EYE_INDEX] ]) self.submobjects = [] self.add(self.body, self.mouth, self.eyes, self.pupils) self.parts_named = True def init_colors(self): self.set_stroke(color=BLACK, width=self.stroke_width) if not self.parts_named: self.name_parts() self.mouth.set_fill(BLACK, opacity=1) self.body.set_fill(self.color, opacity=1) self.pupils.set_fill(BLACK, opacity=1) self.eyes.set_fill(WHITE, opacity=1) return self def highlight(self, color): self.body.set_fill(color) return self def change_mode(self, mode): curr_eye_center = self.eyes.get_center() curr_height = self.get_height() should_be_flipped = self.is_flipped() should_look = hasattr(self, "purposeful_looking_direction") if should_look: looking_direction = self.purposeful_looking_direction self.__init__(mode) self.scale_to_fit_height(curr_height) self.shift(curr_eye_center - self.eyes.get_center()) if should_be_flipped ^ self.is_flipped(): self.flip() if should_look: self.look(looking_direction) return self def look(self, direction): direction = direction / np.linalg.norm(direction) self.purposeful_looking_direction = direction for pupil, eye in zip(self.pupils.split(), self.eyes.split()): pupil_radius = pupil.get_width() / 2. eye_radius = eye.get_width() / 2. pupil.move_to(eye) if direction[1] < 0: pupil.shift(pupil_radius * DOWN / 3) pupil.shift(direction * (eye_radius - pupil_radius)) bottom_diff = eye.get_bottom()[1] - pupil.get_bottom()[1] if bottom_diff > 0: pupil.shift(bottom_diff * UP) return self def look_at(self, point_or_mobject): if isinstance(point_or_mobject, Mobject): point = point_or_mobject.get_center() else: point = point_or_mobject self.look(point - self.eyes.get_center()) return self def get_looking_direction(self): return np.sign( np.round(self.pupils.get_center() - self.eyes.get_center(), decimals=2)) def is_flipped(self): return self.eyes.submobjects[0].get_center()[0] > \ self.eyes.submobjects[1].get_center()[0] def blink(self): eye_bottom_y = self.eyes.get_bottom()[1] for mob in self.eyes, self.pupils: mob.apply_function(lambda p: [p[0], eye_bottom_y, p[2]]) return self def to_corner(self, vect=None): if vect is not None: SVGMobject.to_corner(self, vect) else: self.scale(self.corner_scale_factor) self.to_corner(DOWN + LEFT) return self def get_bubble(self, bubble_type="thought", **kwargs): if bubble_type == "thought": bubble = ThoughtBubble(**kwargs) elif bubble_type == "speech": bubble = SpeechBubble(**kwargs) else: raise Exception("%s is an invalid bubble type" % bubble_type) bubble.pin_to(self) return bubble
class NumberPlane(VMobject): CONFIG = { "color" : BLUE_D, "secondary_color" : BLUE_E, "axes_color" : WHITE, "secondary_stroke_width" : 1, "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, } def generate_points(self): if self.x_radius is None: center_to_edge = (SPACE_WIDTH + abs(self.center_point[0])) self.x_radius = center_to_edge / self.x_unit_size if self.y_radius is None: center_to_edge = (SPACE_HEIGHT + 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 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 def apply_function(self, function, maintain_smoothness = True): VMobject.apply_function(self, function, maintain_smoothness = maintain_smoothness)
def get_center(self): result = VMobject.get_center(self) if hasattr(self, "center_offset"): result -= self.center_offset return result
class NumberPlane(VMobject): CONFIG = { "color": BLUE_D, "secondary_color": BLUE_E, "axes_color": WHITE, "secondary_stroke_width": 1, "x_radius": SPACE_WIDTH, "y_radius": SPACE_HEIGHT, "space_unit_to_x_unit": 1, "space_unit_to_y_unit": 1, "x_line_frequency": 1, "y_line_frequency": 1, "secondary_line_ratio": 1, "written_coordinate_height": 0.2, "written_coordinate_nudge": 0.1 * (DOWN + RIGHT), "num_pair_at_center": (0, 0), "propogate_style_to_family": False, } def generate_points(self): 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.space_unit_to_x_unit, 0) 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): 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.num_pair_to_point(self.num_pair_at_center) def num_pair_to_point(self, pair): pair = np.array(pair) + self.num_pair_at_center result = self.axes.get_center() result[0] += pair[0] * self.space_unit_to_x_unit result[1] += pair[1] * self.space_unit_to_y_unit return result def point_to_num_pair(self, point): new_point = point - self.get_center() center_x, center_y = self.num_pair_at_center x = center_x + point[0] / self.space_unit_to_x_unit y = center_y + point[1] / self.space_unit_to_y_unit return x, y def get_coordinate_labels(self, x_vals=None, y_vals=None): result = [] if x_vals == None and y_vals == None: x_vals = range(-int(self.x_radius), int(self.x_radius)) y_vals = range(-int(self.y_radius), int(self.y_radius)) for index, vals in enumerate([x_vals, y_vals]): num_pair = [0, 0] for val in vals: num_pair[index] = val point = self.num_pair_to_point(num_pair) num = TexMobject(str(val)) num.scale_to_fit_height(self.written_coordinate_height) num.shift(point - num.get_corner(UP + LEFT), self.written_coordinate_nudge) result.append(num) 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): 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 NumberPlane(VMobject): CONFIG = { "color" : BLUE_D, "secondary_color" : BLUE_E, "axes_color" : WHITE, "secondary_stroke_width" : 1, "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, "propogate_style_to_family" : False, } def generate_points(self): if self.x_radius is None: center_to_edge = (SPACE_WIDTH + abs(self.center_point[0])) self.x_radius = center_to_edge / self.x_unit_size if self.y_radius is None: center_to_edge = (SPACE_HEIGHT + 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 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): result = [] if x_vals == None and y_vals == None: x_vals = range(-int(self.x_radius), int(self.x_radius)) y_vals = range(-int(self.y_radius), int(self.y_radius)) 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 ) vect = DOWN if index == 0 else LEFT num.next_to(point, vect, buff = SMALL_BUFF) result.append(num) 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() 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 PiCreature(SVGMobject): CONFIG = { "color" : BLUE_E, "stroke_width" : 0, "fill_opacity" : 1.0, "initial_scale_factor" : 0.01, "corner_scale_factor" : 0.75, "flip_at_start" : False, "is_looking_direction_purposeful" : False, } def __init__(self, mode = "plain", **kwargs): self.parts_named = False svg_file = os.path.join( PI_CREATURE_DIR, "PiCreatures_%s.svg"%mode ) digest_config(self, kwargs, locals()) SVGMobject.__init__(self, svg_file, **kwargs) self.init_colors() if self.flip_at_start: self.flip() def name_parts(self): self.mouth = self.submobjects[MOUTH_INDEX] self.body = self.submobjects[BODY_INDEX] self.pupils = VMobject(*[ self.submobjects[LEFT_PUPIL_INDEX], self.submobjects[RIGHT_PUPIL_INDEX] ]) self.eyes = VMobject(*[ self.submobjects[LEFT_EYE_INDEX], self.submobjects[RIGHT_EYE_INDEX] ]) self.submobjects = [] self.add(self.body, self.mouth, self.eyes, self.pupils) self.parts_named = True def init_colors(self): self.set_stroke(color = BLACK, width = self.stroke_width) if not self.parts_named: self.name_parts() self.mouth.set_fill(BLACK, opacity = 1) self.body.set_fill(self.color, opacity = 1) self.pupils.set_fill(BLACK, opacity = 1) self.eyes.set_fill(WHITE, opacity = 1) return self def highlight(self, color): self.body.set_fill(color) return self def move_to(self, destination): self.shift(destination-self.get_bottom()) return self def change_mode(self, mode): curr_center = self.get_center() curr_height = self.get_height() should_be_flipped = self.is_flipped() if self.is_looking_direction_purposeful: looking_direction = self.get_looking_direction() self.__init__(mode) self.scale_to_fit_height(curr_height) self.shift(curr_center) if should_be_flipped ^ self.is_flipped(): self.flip() if self.is_looking_direction_purposeful: self.look(looking_direction) return self def look(self, direction): self.is_looking_direction_purposeful = True x, y = direction[:2] for pupil, eye in zip(self.pupils.split(), self.eyes.split()): pupil.move_to(eye, aligned_edge = direction) #Some hacky nudging is required here 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) elif y < 0: nudge_size = pupil.get_height()/8. pupil.shift(nudge_size*UP) return self def get_looking_direction(self): return np.sign(np.round( self.pupils.get_center() - self.eyes.get_center(), decimals = 2 )) def is_flipped(self): return self.eyes.submobjects[0].get_center()[0] > \ self.eyes.submobjects[1].get_center()[0] def blink(self): eye_bottom_y = self.eyes.get_bottom()[1] for mob in self.eyes, self.pupils: mob.apply_function( lambda p : [p[0], eye_bottom_y, p[2]] ) return self def to_corner(self, vect = None): if vect is not None: SVGMobject.to_corner(self, vect) else: self.scale(self.corner_scale_factor) self.to_corner(DOWN+LEFT) return self def get_bubble(self, bubble_type = "thought", **kwargs): if bubble_type == "thought": bubble = ThoughtBubble(**kwargs) elif bubble_type == "speech": bubble = SpeechBubble(**kwargs) else: raise Exception("%s is an invalid bubble type"%bubble_type) bubble.pin_to(self) return bubble
def get_center(self): result = VMobject.get_center(self) if hasattr(self, "center_offset"): result -= self.center_offset return result
class NumberPlane(VMobject): CONFIG = { "color" : BLUE_D, "secondary_color" : BLUE_E, "axes_color" : WHITE, "secondary_stroke_width" : 1, "x_radius": SPACE_WIDTH, "y_radius": SPACE_HEIGHT, "space_unit_to_x_unit" : 1, "space_unit_to_y_unit" : 1, "x_line_frequency" : 1, "y_line_frequency" : 1, "secondary_line_ratio" : 1, "written_coordinate_height" : 0.2, "written_coordinate_nudge" : 0.1*(DOWN+RIGHT), "num_pair_at_center" : (0, 0), "propogate_style_to_family" : False, } def generate_points(self): 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.axes, self.main_lines, self.secondary_lines) self.stretch(self.space_unit_to_x_unit, 0) 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): 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.num_pair_to_point(self.num_pair_at_center) def num_pair_to_point(self, pair): pair = np.array(pair) + self.num_pair_at_center result = self.axes.get_center() result[0] += pair[0]*self.space_unit_to_x_unit result[1] += pair[1]*self.space_unit_to_y_unit return result def point_to_num_pair(self, point): new_point = point-self.get_center() center_x, center_y = self.num_pair_at_center x = center_x + point[0]/self.space_unit_to_x_unit y = center_y + point[1]/self.space_unit_to_y_unit return x, y def get_coordinate_labels(self, x_vals = None, y_vals = None): result = [] if x_vals == None and y_vals == None: x_vals = range(-int(self.x_radius), int(self.x_radius)) y_vals = range(-int(self.y_radius), int(self.y_radius)) for index, vals in enumerate([x_vals, y_vals]): num_pair = [0, 0] for val in vals: num_pair[index] = val point = self.num_pair_to_point(num_pair) num = TexMobject(str(val)) num.scale_to_fit_height( self.written_coordinate_height ) num.shift( point-num.get_corner(UP+LEFT), self.written_coordinate_nudge ) result.append(num) 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): 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