mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Updating coordinate system mobjects
This commit is contained in:
parent
24d6113bba
commit
d88c301622
25 changed files with 425 additions and 354 deletions
|
@ -41,7 +41,7 @@ class AnalyzeZSquared(ComplexTransformationScene, ZoomedScene):
|
|||
self.add_foreground_mobject(title)
|
||||
|
||||
def edit_background_plane(self):
|
||||
self.background.main_lines.set_stroke(GREY, 2)
|
||||
self.backgrounds.set_stroke(GREY, 2)
|
||||
self.background.secondary_lines.set_stroke(DARK_GREY, 1)
|
||||
self.add_foreground_mobject(self.background.coordinate_labels)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from manimlib.utils.config_ops import digest_config
|
|||
|
||||
|
||||
class Container(object):
|
||||
def __init__(self, *submobjects, **kwargs):
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
|
||||
def add(self, *items):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import numpy as np
|
||||
import itertools as it
|
||||
|
||||
from manimlib.constants import *
|
||||
from manimlib.mobject.functions import ParametricFunction
|
||||
|
@ -7,17 +8,90 @@ from manimlib.mobject.geometry import Line
|
|||
from manimlib.mobject.number_line import NumberLine
|
||||
from manimlib.mobject.svg.tex_mobject import TexMobject
|
||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.config_ops import merge_config
|
||||
from manimlib.utils.simple_functions import binary_search
|
||||
from manimlib.utils.space_ops import angle_of_vector
|
||||
|
||||
# TODO: There should be much more code reuse between Axes, NumberPlane and GraphScene
|
||||
|
||||
|
||||
class Axes(VGroup):
|
||||
class CoordinateSystem():
|
||||
"""
|
||||
Abstract class for Axes and NumberPlane
|
||||
"""
|
||||
CONFIG = {
|
||||
"dimension": 2,
|
||||
"x_min": -FRAME_X_RADIUS,
|
||||
"x_max": FRAME_X_RADIUS,
|
||||
"y_min": -FRAME_Y_RADIUS,
|
||||
"y_max": FRAME_Y_RADIUS,
|
||||
}
|
||||
|
||||
def coords_to_point(self, *coords):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def point_to_coords(self, point):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def get_axes(self):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def get_axis(self, index):
|
||||
return self.get_axes()[index]
|
||||
|
||||
def get_x_axis(self):
|
||||
return self.get_axis(0)
|
||||
|
||||
def get_y_axis(self):
|
||||
return self.get_axis(1)
|
||||
|
||||
def get_z_axis(self):
|
||||
return self.get_axis(2)
|
||||
|
||||
def get_graph(self, function, **kwargs):
|
||||
x_min = kwargs.pop("x_min", self.x_min)
|
||||
x_max = kwargs.pop("x_max", 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 get_parametric_curve(self, function, **kwargs):
|
||||
dim = self.dimension
|
||||
graph = ParametricFunction(
|
||||
lambda t: self.coords_to_point(
|
||||
*function(t)[:dim]
|
||||
),
|
||||
**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:
|
||||
alpha = binary_search(
|
||||
function=lambda a: self.point_to_coords(
|
||||
graph.point_from_proportion(a)
|
||||
)[0],
|
||||
target=x,
|
||||
lower_bound=self.x_min,
|
||||
uplper_bound=self.x_max,
|
||||
)
|
||||
if alpha is not None:
|
||||
return graph.point_from_proportion(alpha)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Axes(VGroup, CoordinateSystem):
|
||||
CONFIG = {
|
||||
"three_d": False,
|
||||
"number_line_config": {
|
||||
"color": LIGHT_GREY,
|
||||
"include_tip": True,
|
||||
|
@ -26,24 +100,26 @@ class Axes(VGroup):
|
|||
"y_axis_config": {
|
||||
"label_direction": LEFT,
|
||||
},
|
||||
"x_min": -FRAME_X_RADIUS,
|
||||
"x_max": FRAME_X_RADIUS,
|
||||
"y_min": -FRAME_Y_RADIUS,
|
||||
"y_max": FRAME_Y_RADIUS,
|
||||
"center_point": ORIGIN,
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
self.x_axis = self.get_axis(
|
||||
self.x_axis = self.create_axis(
|
||||
self.x_min, self.x_max, self.x_axis_config
|
||||
)
|
||||
self.y_axis = self.get_axis(
|
||||
self.y_axis = self.create_axis(
|
||||
self.y_min, self.y_max, self.y_axis_config
|
||||
)
|
||||
self.y_axis.rotate(90 * DEGREES, about_point=ORIGIN)
|
||||
self.add(self.x_axis, self.y_axis)
|
||||
# Add as a separate group incase various other
|
||||
# mobjects are added to self, as for example in
|
||||
# NumberPlane below
|
||||
self.axes = VGroup(self.x_axis, self.y_axis)
|
||||
self.add(*self.axes)
|
||||
self.shift(self.center_point)
|
||||
|
||||
def get_axis(self, min_val, max_val, axis_config):
|
||||
def create_axis(self, min_val, max_val, axis_config):
|
||||
new_config = merge_config([
|
||||
axis_config,
|
||||
{"x_min": min_val, "x_max": max_val},
|
||||
|
@ -54,63 +130,23 @@ class Axes(VGroup):
|
|||
def coords_to_point(self, *coords):
|
||||
origin = self.x_axis.number_to_point(0)
|
||||
result = np.array(origin)
|
||||
for axis, coord in zip(self, coords):
|
||||
for axis, coord in zip(self.get_axes(), coords):
|
||||
result += (axis.number_to_point(coord) - origin)
|
||||
return result
|
||||
|
||||
def point_to_coords(self, point):
|
||||
return tuple([
|
||||
axis.point_to_number(point)
|
||||
for axis in self
|
||||
if isinstance(axis, NumberLine)
|
||||
for axis in self.get_axes()
|
||||
])
|
||||
|
||||
def get_graph(
|
||||
self, function,
|
||||
x_min=None,
|
||||
x_max=None,
|
||||
**kwargs
|
||||
):
|
||||
kwargs["fill_opacity"] = kwargs.get("fill_opacity", 0)
|
||||
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 = list(map(graph.point_from_proportion, hands))
|
||||
lx, mx, rx = list(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))
|
||||
def get_axes(self):
|
||||
return self.axes
|
||||
|
||||
|
||||
class ThreeDAxes(Axes):
|
||||
CONFIG = {
|
||||
"dimension": 3,
|
||||
"x_min": -5.5,
|
||||
"x_max": 5.5,
|
||||
"y_min": -5.5,
|
||||
|
@ -125,7 +161,7 @@ class ThreeDAxes(Axes):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
Axes.__init__(self, **kwargs)
|
||||
z_axis = self.z_axis = self.get_axis(
|
||||
z_axis = self.z_axis = self.create_axis(
|
||||
self.z_min, self.z_max, self.z_axis_config
|
||||
)
|
||||
z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN)
|
||||
|
@ -133,18 +169,19 @@ class ThreeDAxes(Axes):
|
|||
angle_of_vector(self.z_normal), OUT,
|
||||
about_point=ORIGIN
|
||||
)
|
||||
self.axes.append(z_axis)
|
||||
self.add(z_axis)
|
||||
|
||||
self.add_3d_pieces()
|
||||
self.set_axis_shading()
|
||||
|
||||
def add_3d_pieces(self):
|
||||
for axis in self:
|
||||
for axis in self.axes:
|
||||
axis.pieces = VGroup(
|
||||
*axis.main_line.get_pieces(self.num_axis_pieces)
|
||||
*axis.get_pieces(self.num_axis_pieces)
|
||||
)
|
||||
axis.add(axis.pieces)
|
||||
axis.main_line.set_stroke(width=0, family=False)
|
||||
axis.set_stroke(width=0, family=False)
|
||||
axis.set_shade_in_3d(True)
|
||||
|
||||
def set_axis_shading(self):
|
||||
|
@ -161,195 +198,180 @@ class ThreeDAxes(Axes):
|
|||
submob.set_sheen(0.2)
|
||||
|
||||
|
||||
class NumberPlane(VMobject):
|
||||
class NumberPlane(Axes):
|
||||
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,
|
||||
"axis_config": {
|
||||
"stroke_color": WHITE,
|
||||
"stroke_width": 2,
|
||||
"include_ticks": False,
|
||||
"include_tip": False,
|
||||
"line_to_number_buff": SMALL_BUFF,
|
||||
"label_direction": DR,
|
||||
"number_scale_val": 0.5,
|
||||
},
|
||||
"y_axis_config": {
|
||||
"label_direction": DR,
|
||||
},
|
||||
"background_line_style": {
|
||||
"stroke_color": BLUE_D,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
# Defaults to a faded version of line_config
|
||||
"faded_line_style": None,
|
||||
"x_line_frequency": 1,
|
||||
"y_line_frequency": 1,
|
||||
"secondary_line_ratio": 1,
|
||||
"written_coordinate_height": 0.2,
|
||||
"propagate_style_to_family": False,
|
||||
"faded_line_ratio": 1,
|
||||
"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__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
kwargs["number_line_config"] = self.axis_config
|
||||
Axes.__init__(self, **kwargs)
|
||||
self.init_background_lines()
|
||||
|
||||
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
|
||||
def init_background_lines(self):
|
||||
if self.faded_line_style is None:
|
||||
background_line_style = self.background_line_style
|
||||
color = background_line_style.get(
|
||||
"stroke_color", WHITE
|
||||
)
|
||||
return self
|
||||
stroke_width = background_line_style.get("stroke_width", 2) / 2
|
||||
self.faded_line_style = {
|
||||
"stroke_color": color,
|
||||
"stroke_width": stroke_width,
|
||||
"stroke_opacity": 0.5,
|
||||
}
|
||||
|
||||
self.background_lines, self.faded_lines = self.get_lines()
|
||||
self.background_lines.set_style(
|
||||
**self.background_line_style,
|
||||
)
|
||||
self.faded_lines.set_style(
|
||||
**self.faded_line_style,
|
||||
)
|
||||
self.add_to_back(
|
||||
self.faded_lines,
|
||||
self.background_lines,
|
||||
)
|
||||
|
||||
def get_lines(self):
|
||||
x_axis = self.get_x_axis()
|
||||
y_axis = self.get_y_axis()
|
||||
x_freq = self.x_line_frequency
|
||||
y_freq = self.y_line_frequency
|
||||
|
||||
x_lines1, x_lines2 = self.get_lines_parallel_to_axis(
|
||||
x_axis, y_axis, x_freq,
|
||||
self.faded_line_ratio,
|
||||
)
|
||||
y_lines1, y_lines2 = self.get_lines_parallel_to_axis(
|
||||
y_axis, x_axis, y_freq,
|
||||
self.faded_line_ratio,
|
||||
)
|
||||
lines1 = VGroup(*x_lines1, *y_lines1)
|
||||
lines2 = VGroup(*x_lines2, *y_lines2)
|
||||
return lines1, lines2
|
||||
|
||||
def get_lines_parallel_to_axis(self, axis1, axis2, freq, ratio):
|
||||
line = Line(axis1.get_start(), axis1.get_end())
|
||||
vect = line.get_vector()
|
||||
dense_freq = (1 + ratio)
|
||||
step = 1 / dense_freq
|
||||
|
||||
lines1 = VGroup()
|
||||
lines2 = VGroup()
|
||||
ranges = (
|
||||
np.arange(0, axis2.x_max, step),
|
||||
np.arange(0, axis2.x_min, -step),
|
||||
)
|
||||
for inputs in ranges:
|
||||
for k, x in enumerate(inputs):
|
||||
new_line = line.copy()
|
||||
new_line.move_to(axis2.number_to_point(x))
|
||||
new_line.align_to(line, vect)
|
||||
if k % (1 + ratio) == 0:
|
||||
lines1.add(new_line)
|
||||
else:
|
||||
lines2.add(new_line)
|
||||
return lines1, lines2
|
||||
|
||||
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)
|
||||
return self.get_x_axis().get_unit_size()
|
||||
|
||||
def get_y_unit_size(self):
|
||||
return self.axes.get_height() / (2.0 * self.y_radius)
|
||||
return self.get_x_axis().get_unit_size()
|
||||
|
||||
def get_coordinate_labels(self, x_vals=None, y_vals=None):
|
||||
coordinate_labels = VGroup()
|
||||
if x_vals is None:
|
||||
x_vals = list(range(-int(self.x_radius), int(self.x_radius) + 1))
|
||||
if y_vals is None:
|
||||
y_vals = list(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.set_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
|
||||
x_vals = x_vals or []
|
||||
y_vals = y_vals or []
|
||||
x_mobs = self.get_x_axis().get_number_mobjects(*x_vals)
|
||||
y_mobs = self.get_y_axis().get_number_mobjects(*y_vals)
|
||||
|
||||
self.coordinate_labels = VGroup(x_mobs, y_mobs)
|
||||
return self.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 get_x_axis_label(self, label_tex, edge=RIGHT, direction=DL, **kwargs):
|
||||
return self.get_axis_label(
|
||||
label_tex, self.get_x_axis(),
|
||||
edge, direction, **kwargs
|
||||
)
|
||||
|
||||
def get_y_axis_label(self, label_tex, edge=UP, direction=DR, **kwargs):
|
||||
return self.get_axis_label(
|
||||
label_tex, self.get_y_axis(),
|
||||
edge, direction, **kwargs
|
||||
)
|
||||
|
||||
def get_axis_label(self, label_tex, axis, edge, direction, buff=MED_SMALL_BUFF):
|
||||
label = TexMobject(label_tex)
|
||||
label.next_to(
|
||||
axis.get_edge_center(edge), direction,
|
||||
buff=buff
|
||||
)
|
||||
return label
|
||||
|
||||
def get_axis_labels(self, x_label_tex="x", y_label_tex="y"):
|
||||
self.axis_labels = VGroup(
|
||||
self.get_x_axis_label(x_label_tex),
|
||||
self.get_y_axis_label(y_label_tex),
|
||||
)
|
||||
return self.axis_labels
|
||||
|
||||
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
|
||||
|
||||
def get_vector(self, coords, **kwargs):
|
||||
point = coords[0] * RIGHT + coords[1] * UP
|
||||
arrow = Arrow(ORIGIN, point, **kwargs)
|
||||
return arrow
|
||||
kwargs["buff"] = 0
|
||||
return Arrow(
|
||||
self.coords_to_point(0, 0),
|
||||
self.coords_to_point(*coords),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def prepare_for_nonlinear_transform(self, num_inserted_curves=50):
|
||||
for mob in self.family_members_with_points():
|
||||
num_curves = mob.get_num_curves()
|
||||
if num_inserted_curves > num_curves:
|
||||
mob.insert_n_curves(
|
||||
num_inserted_curves - num_curves)
|
||||
mob.make_smooth()
|
||||
num_inserted_curves - num_curves
|
||||
)
|
||||
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)
|
||||
|
@ -358,35 +380,35 @@ class ComplexPlane(NumberPlane):
|
|||
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()
|
||||
if len(numbers) == 0:
|
||||
numbers = list(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)
|
||||
if y != 0
|
||||
def get_default_coordinate_values(self):
|
||||
x_numbers = self.get_x_axis().default_numbers_to_display()
|
||||
y_numbers = self.get_y_axis().default_numbers_to_display()
|
||||
y_numbers = [
|
||||
complex(0, y) for y in y_numbers if y != 0
|
||||
]
|
||||
return [*x_numbers, *y_numbers]
|
||||
|
||||
def get_coordinate_labels(self, *numbers, **kwargs):
|
||||
if len(numbers) == 0:
|
||||
numbers = self.get_default_coordinate_values()
|
||||
|
||||
self.coordinate_labels = VGroup()
|
||||
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.set_height(self.written_coordinate_height)
|
||||
num_mob.next_to(point, DOWN + LEFT, SMALL_BUFF)
|
||||
result.add(num_mob)
|
||||
self.coordinate_labels = result
|
||||
return result
|
||||
z = complex(number)
|
||||
if abs(z.imag) > abs(z.real):
|
||||
axis = self.get_y_axis()
|
||||
value = z.imag
|
||||
kwargs = merge_config([
|
||||
{"number_config": {"unit": "i"}},
|
||||
kwargs,
|
||||
])
|
||||
else:
|
||||
axis = self.get_x_axis()
|
||||
value = z.real
|
||||
number_mob = axis.get_number_mobject(value, **kwargs)
|
||||
self.coordinate_labels.add(number_mob)
|
||||
return self.coordinate_labels
|
||||
|
||||
def add_coordinates(self, *numbers):
|
||||
self.coordinate_labels = self.get_coordinate_labels(*numbers)
|
||||
self.add(self.coordinate_labels)
|
||||
self.add(self.get_coordinate_labels(*numbers))
|
||||
return self
|
||||
|
|
|
@ -36,11 +36,9 @@ class Mobject(Container):
|
|||
"target": None,
|
||||
}
|
||||
|
||||
def __init__(self, *submobjects, **kwargs):
|
||||
Container.__init__(self, *submobjects, **kwargs)
|
||||
if not all([isinstance(m, Mobject) for m in submobjects]):
|
||||
raise Exception("All submobjects must be of type Mobject")
|
||||
self.submobjects = list(submobjects)
|
||||
def __init__(self, **kwargs):
|
||||
Container.__init__(self, **kwargs)
|
||||
self.submobjects = []
|
||||
self.color = Color(self.color)
|
||||
if self.name is None:
|
||||
self.name = self.__class__.__name__
|
||||
|
@ -1031,7 +1029,8 @@ class Mobject(Container):
|
|||
|
||||
|
||||
class Group(Mobject):
|
||||
# Alternate name to improve readibility in cases where
|
||||
# the mobject is used primarily for its submobject housing
|
||||
# functionality.
|
||||
pass
|
||||
def __init__(self, *mobjects, **kwargs):
|
||||
if not all([isinstance(m, Mobject) for m in mobjects]):
|
||||
raise Exception("All submobjects must be of type Mobject")
|
||||
Mobject.__init__(self, **kwargs)
|
||||
self.add(*mobjects)
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
import operator as op
|
||||
|
||||
from manimlib.constants import *
|
||||
from manimlib.mobject.geometry import Arrow
|
||||
from manimlib.mobject.geometry import RegularPolygon
|
||||
from manimlib.mobject.geometry import Line
|
||||
from manimlib.mobject.numbers import DecimalNumber
|
||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.bezier import interpolate
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.config_ops import merge_config
|
||||
from manimlib.utils.simple_functions import fdiv
|
||||
from manimlib.utils.space_ops import get_norm
|
||||
from manimlib.utils.space_ops import normalize
|
||||
|
||||
|
||||
class NumberLine(VMobject):
|
||||
class NumberLine(Line):
|
||||
CONFIG = {
|
||||
"color": LIGHT_GREY,
|
||||
"x_min": -FRAME_X_RADIUS,
|
||||
"x_max": FRAME_X_RADIUS,
|
||||
"unit_size": 1,
|
||||
"include_ticks": True,
|
||||
"tick_size": 0.1,
|
||||
"tick_frequency": 1,
|
||||
"leftmost_tick": None, # Defaults to value near x_min s.t. 0 is a tick
|
||||
# Defaults to value near x_min s.t. 0 is a tick
|
||||
# TODO, rename this
|
||||
"leftmost_tick": None,
|
||||
# Change name
|
||||
"numbers_with_elongated_ticks": [0],
|
||||
"include_numbers": False,
|
||||
"numbers_to_show": None,
|
||||
|
@ -29,6 +34,8 @@ class NumberLine(VMobject):
|
|||
"label_direction": DOWN,
|
||||
"line_to_number_buff": MED_SMALL_BUFF,
|
||||
"include_tip": False,
|
||||
"tip_width": 0.25,
|
||||
"tip_height": 0.25,
|
||||
"decimal_number_config": {
|
||||
"num_decimal_places": 0,
|
||||
}
|
||||
|
@ -36,68 +43,72 @@ class NumberLine(VMobject):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
if self.leftmost_tick is None:
|
||||
tf = self.tick_frequency
|
||||
self.leftmost_tick = tf * np.ceil(self.x_min / tf)
|
||||
VMobject.__init__(self, **kwargs)
|
||||
start = self.unit_size * self.x_min * RIGHT
|
||||
end = self.unit_size * self.x_max * RIGHT
|
||||
Line.__init__(self, start, end, **kwargs)
|
||||
self.shift(-self.number_to_point(self.number_at_center))
|
||||
|
||||
self.init_leftmost_tick()
|
||||
if self.include_ticks:
|
||||
self.add_tick_marks()
|
||||
if self.include_tip:
|
||||
self.add_tip()
|
||||
if self.include_numbers:
|
||||
self.add_numbers()
|
||||
|
||||
def generate_points(self):
|
||||
self.main_line = Line(self.x_min * RIGHT, self.x_max * RIGHT)
|
||||
self.tick_marks = VGroup()
|
||||
self.add(self.main_line, self.tick_marks)
|
||||
rounding_value = int(-np.log10(0.1 * self.tick_frequency))
|
||||
rounded_numbers_with_elongated_ticks = np.round(
|
||||
self.numbers_with_elongated_ticks,
|
||||
rounding_value
|
||||
def init_leftmost_tick(self):
|
||||
if self.leftmost_tick is None:
|
||||
self.leftmost_tick = op.mul(
|
||||
self.tick_frequency,
|
||||
np.ceil(self.x_min / self.tick_frequency)
|
||||
)
|
||||
|
||||
for x in self.get_tick_numbers():
|
||||
rounded_x = np.round(x, rounding_value)
|
||||
if rounded_x in rounded_numbers_with_elongated_ticks:
|
||||
tick_size_used = self.longer_tick_multiple * self.tick_size
|
||||
else:
|
||||
tick_size_used = self.tick_size
|
||||
self.add_tick(x, tick_size_used)
|
||||
|
||||
self.stretch(self.unit_size, 0)
|
||||
self.shift(-self.number_to_point(self.number_at_center))
|
||||
|
||||
def add_tick(self, x, size=None):
|
||||
self.tick_marks.add(self.get_tick(x, size))
|
||||
return self
|
||||
def add_tick_marks(self):
|
||||
tick_size = self.tick_size
|
||||
self.tick_marks = VGroup(*[
|
||||
self.get_tick(x, tick_size)
|
||||
for x in self.get_tick_numbers()
|
||||
])
|
||||
big_tick_size = tick_size * self.longer_tick_multiple
|
||||
self.big_tick_marks = VGroup(*[
|
||||
self.get_tick(x, big_tick_size)
|
||||
for x in self.numbers_with_elongated_ticks
|
||||
])
|
||||
self.add(
|
||||
self.tick_marks,
|
||||
self.big_tick_marks,
|
||||
)
|
||||
|
||||
def get_tick(self, x, size=None):
|
||||
if size is None:
|
||||
size = self.tick_size
|
||||
result = Line(size * DOWN, size * UP)
|
||||
result.rotate(self.main_line.get_angle())
|
||||
result.rotate(self.get_angle())
|
||||
result.move_to(self.number_to_point(x))
|
||||
result.match_style(self)
|
||||
return result
|
||||
|
||||
def get_tick_marks(self):
|
||||
return self.tick_marks
|
||||
return VGroup(
|
||||
*self.tick_marks,
|
||||
*self.big_tick_marks,
|
||||
)
|
||||
|
||||
def get_tick_numbers(self):
|
||||
epsilon = 0.001
|
||||
return np.arange(
|
||||
self.leftmost_tick, self.x_max + epsilon,
|
||||
self.leftmost_tick,
|
||||
self.x_max + self.tick_frequency / 2,
|
||||
self.tick_frequency
|
||||
)
|
||||
|
||||
def number_to_point(self, number):
|
||||
alpha = float(number - self.x_min) / (self.x_max - self.x_min)
|
||||
return interpolate(
|
||||
self.main_line.get_start(),
|
||||
self.main_line.get_end(),
|
||||
alpha
|
||||
self.get_start(), self.get_end(), alpha
|
||||
)
|
||||
|
||||
def point_to_number(self, point):
|
||||
start_point, end_point = self.main_line.get_start_and_end()
|
||||
start_point, end_point = self.get_start_and_end()
|
||||
full_vect = end_point - start_point
|
||||
unit_vect = normalize(full_vect)
|
||||
|
||||
|
@ -110,28 +121,43 @@ class NumberLine(VMobject):
|
|||
)
|
||||
return interpolate(self.x_min, self.x_max, proportion)
|
||||
|
||||
def get_unit_size(self):
|
||||
return (self.x_max - self.x_min) / self.get_length()
|
||||
|
||||
def default_numbers_to_display(self):
|
||||
if self.numbers_to_show is not None:
|
||||
return self.numbers_to_show
|
||||
return np.arange(int(self.leftmost_tick), int(self.x_max) + 1)
|
||||
|
||||
def get_number_mobject(self, number,
|
||||
number_config=None,
|
||||
scale_val=None,
|
||||
direction=None,
|
||||
buff=None):
|
||||
number_config = merge_config([
|
||||
number_config or {},
|
||||
self.decimal_number_config
|
||||
])
|
||||
scale_val = scale_val or self.number_scale_val
|
||||
direction = direction or self.label_direction
|
||||
buff = buff or self.line_to_number_buff
|
||||
|
||||
num_mob = DecimalNumber(number, **number_config)
|
||||
num_mob.scale(scale_val)
|
||||
num_mob.next_to(
|
||||
self.number_to_point(number),
|
||||
direction=direction,
|
||||
buff=buff
|
||||
)
|
||||
return num_mob
|
||||
|
||||
def get_number_mobjects(self, *numbers, **kwargs):
|
||||
# TODO, handle decimals
|
||||
if len(numbers) == 0:
|
||||
numbers = self.default_numbers_to_display()
|
||||
result = VGroup()
|
||||
for number in numbers:
|
||||
mob = DecimalNumber(
|
||||
number, **self.decimal_number_config
|
||||
)
|
||||
mob.scale(self.number_scale_val)
|
||||
mob.next_to(
|
||||
self.number_to_point(number),
|
||||
self.label_direction,
|
||||
self.line_to_number_buff,
|
||||
)
|
||||
result.add(mob)
|
||||
return result
|
||||
return VGroup(*[
|
||||
self.get_number_mobject(number, **kwargs)
|
||||
for number in numbers
|
||||
])
|
||||
|
||||
def get_labels(self):
|
||||
return self.get_number_mobjects()
|
||||
|
@ -144,12 +170,13 @@ class NumberLine(VMobject):
|
|||
return self
|
||||
|
||||
def add_tip(self):
|
||||
start, end = self.main_line.get_start_and_end()
|
||||
vect = (end - start) / get_norm(end - start)
|
||||
arrow = Arrow(start, end + MED_SMALL_BUFF * vect, buff=0)
|
||||
tip = arrow.tip
|
||||
tip.set_stroke(width=self.get_stroke_width())
|
||||
tip.set_color(self.color)
|
||||
tip = RegularPolygon(3)
|
||||
color = self.color
|
||||
tip.set_stroke(color, width=self.get_stroke_width())
|
||||
tip.set_fill(color, opacity=1)
|
||||
tip.set_width(self.tip_width)
|
||||
tip.set_height(self.tip_height, stretch=True)
|
||||
tip.move_to(self.get_end(), LEFT)
|
||||
self.tip = tip
|
||||
self.add(tip)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class DecimalNumber(VMobject):
|
|||
formatter = self.get_formatter()
|
||||
num_string = formatter.format(number)
|
||||
|
||||
rounded_num = np.round(float(number), self.num_decimal_places)
|
||||
rounded_num = np.round(number, self.num_decimal_places)
|
||||
if num_string.startswith("-") and rounded_num == 0:
|
||||
if self.include_sign:
|
||||
num_string = "+" + num_string[1:]
|
||||
|
|
|
@ -11,7 +11,6 @@ from manimlib.mobject.geometry import Rectangle
|
|||
from manimlib.mobject.geometry import RoundedRectangle
|
||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.bezier import is_closed
|
||||
from manimlib.utils.color import *
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.config_ops import digest_locals
|
||||
|
@ -105,14 +104,14 @@ class SVGMobject(VMobject):
|
|||
pass # TODO
|
||||
# warnings.warn("Unknown element type: " + element.tagName)
|
||||
result = [m for m in result if m is not None]
|
||||
self.handle_transforms(element, VMobject(*result))
|
||||
self.handle_transforms(element, VGroup(*result))
|
||||
if len(result) > 1 and not self.unpack_groups:
|
||||
result = [VGroup(*result)]
|
||||
|
||||
return result
|
||||
|
||||
def g_to_mobjects(self, g_element):
|
||||
mob = VMobject(*self.get_mobjects_from(g_element))
|
||||
mob = VGroup(*self.get_mobjects_from(g_element))
|
||||
self.handle_transforms(g_element, mob)
|
||||
return mob.submobjects
|
||||
|
||||
|
@ -124,7 +123,7 @@ class SVGMobject(VMobject):
|
|||
ref = use_element.getAttribute("xlink:href")[1:]
|
||||
if ref not in self.ref_to_element:
|
||||
warnings.warn("%s not recognized" % ref)
|
||||
return VMobject()
|
||||
return VGroup()
|
||||
return self.get_mobjects_from(
|
||||
self.ref_to_element[ref]
|
||||
)
|
||||
|
|
|
@ -796,18 +796,11 @@ class VMobject(Mobject):
|
|||
|
||||
|
||||
class VGroup(VMobject):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1 and isinstance(args[0], (tuple, list)):
|
||||
args = args[0]
|
||||
|
||||
packed_args = []
|
||||
for arg in args:
|
||||
if isinstance(arg, (tuple, list)):
|
||||
packed_args.append(VGroup(arg))
|
||||
else:
|
||||
packed_args.append(arg)
|
||||
|
||||
VMobject.__init__(self, *packed_args, **kwargs)
|
||||
def __init__(self, *vmobjects, **kwargs):
|
||||
if not all([isinstance(m, VMobject) for m in vmobjects]):
|
||||
raise Exception("All submobjects must be of type VMobject")
|
||||
VMobject.__init__(self, **kwargs)
|
||||
self.add(*vmobjects)
|
||||
|
||||
|
||||
class VectorizedPoint(VMobject):
|
||||
|
|
|
@ -96,7 +96,7 @@ class ComplexTransformationScene(Scene):
|
|||
# TODO...
|
||||
|
||||
def paint_plane(self, plane):
|
||||
for lines in plane.main_lines, plane.secondary_lines:
|
||||
for lines in planes, plane.secondary_lines:
|
||||
lines.set_color_by_gradient(
|
||||
self.vert_start_color,
|
||||
self.vert_end_color,
|
||||
|
|
|
@ -156,10 +156,10 @@ class SpecialThreeDScene(ThreeDScene):
|
|||
axes = ThreeDAxes(**self.three_d_axes_config)
|
||||
for axis in axes:
|
||||
if self.cut_axes_at_radius:
|
||||
p0 = axis.main_line.get_start()
|
||||
p0 = axis.get_start()
|
||||
p1 = axis.number_to_point(-1)
|
||||
p2 = axis.number_to_point(1)
|
||||
p3 = axis.main_line.get_end()
|
||||
p3 = axis.get_end()
|
||||
new_pieces = VGroup(
|
||||
Line(p0, p1), Line(p1, p2), Line(p2, p3),
|
||||
)
|
||||
|
|
|
@ -56,12 +56,16 @@ def digest_config(obj, kwargs, caller_locals={}):
|
|||
obj.__dict__ = merge_config(all_dicts)
|
||||
|
||||
|
||||
# TODO, priority here is backwards from dict.update.
|
||||
# Should I change the convention?
|
||||
def merge_config(all_dicts):
|
||||
"""
|
||||
Creates a dict whose keyset is the union of all the
|
||||
input dictionaries. The value for each key is based
|
||||
on the first dict in the list with that key.
|
||||
|
||||
First dicts have higher priority
|
||||
|
||||
When values are dictionaries, it is applied recursively
|
||||
"""
|
||||
all_config = reduce(op.add, [list(d.items()) for d in all_dicts])
|
||||
|
|
|
@ -62,3 +62,30 @@ def fdiv(a, b, zero_over_zero_value=None):
|
|||
where = True
|
||||
|
||||
return np.true_divide(a, b, out=out, where=where)
|
||||
|
||||
|
||||
def binary_search(function,
|
||||
target,
|
||||
lower_bound,
|
||||
upper_bound,
|
||||
tolerance=1e-4):
|
||||
lh = lower_bound
|
||||
rh = upper_bound
|
||||
while abs(rh - lh) > tolerance:
|
||||
mh = np.mean([lh, rh])
|
||||
lx, mx, rx = [function(h) for h in (lh, mh, rh)]
|
||||
if lx == target:
|
||||
return lx
|
||||
if rx == target:
|
||||
return rx
|
||||
|
||||
if lx <= target and rx >= target:
|
||||
if mx > target:
|
||||
rh = mh
|
||||
else:
|
||||
lh = mh
|
||||
elif lx > target and rx < target:
|
||||
lh, rh = rh, lh
|
||||
else:
|
||||
return None
|
||||
return mh
|
||||
|
|
|
@ -781,7 +781,7 @@ class InputOutputScene(Scene):
|
|||
plane.add_coordinates(x_vals = list(range(-2, 3)), y_vals = list(range(-2, 3)))
|
||||
plane.white_parts = VGroup(plane.axes, plane.coordinate_labels)
|
||||
plane.coordinate_labels.set_background_stroke(width=0)
|
||||
plane.lines_to_fade = VGroup(plane.main_lines, plane.secondary_lines)
|
||||
plane.lines_to_fade = VGroup(planes, plane.secondary_lines)
|
||||
plane.move_to(vect*FRAME_X_RADIUS/2 + self.y_shift*DOWN)
|
||||
label = TextMobject(text)
|
||||
label.scale(1.5)
|
||||
|
|
|
@ -76,7 +76,7 @@ class NumberlineTransformationScene(ZoomedScene):
|
|||
full_config = dict(self.number_line_config)
|
||||
full_config.update(added_config)
|
||||
number_line = NumberLine(**full_config)
|
||||
number_line.main_line.insert_n_curves(
|
||||
number_line.insert_n_curves(
|
||||
self.num_inserted_number_line_curves
|
||||
)
|
||||
number_line.shift(zero_point - number_line.number_to_point(0))
|
||||
|
@ -179,12 +179,12 @@ class NumberlineTransformationScene(ZoomedScene):
|
|||
self.moving_input_line = input_line_copy
|
||||
input_line_copy.remove(input_line_copy.numbers)
|
||||
# input_line_copy.set_stroke(width=2)
|
||||
input_line_copy.main_line.insert_n_curves(
|
||||
input_line_copy.insert_n_curves(
|
||||
self.num_inserted_number_line_curves
|
||||
)
|
||||
return AnimationGroup(
|
||||
self.get_mapping_animation(
|
||||
func, input_line_copy.main_line,
|
||||
func, input_line_copy,
|
||||
apply_function_to_points
|
||||
),
|
||||
self.get_mapping_animation(
|
||||
|
@ -242,7 +242,7 @@ class NumberlineTransformationScene(ZoomedScene):
|
|||
zoom_anim.update(1)
|
||||
target_mini_line = Line(frame.get_left(), frame.get_right())
|
||||
target_mini_line.scale(self.mini_line_scale_factor)
|
||||
target_mini_line.match_style(self.output_line.main_line)
|
||||
target_mini_line.match_style(self.output_line)
|
||||
zoom_anim.update(0)
|
||||
zcbr_group.submobjects.insert(1, target_mini_line)
|
||||
if target_coordinate_values:
|
||||
|
@ -312,7 +312,7 @@ class NumberlineTransformationScene(ZoomedScene):
|
|||
mini_line = self.mini_line = Line(frame.get_left(), frame.get_right())
|
||||
mini_line.scale(self.mini_line_scale_factor)
|
||||
mini_line.insert_n_curves(self.num_inserted_number_line_curves)
|
||||
mini_line.match_style(self.input_line.main_line)
|
||||
mini_line.match_style(self.input_line)
|
||||
mini_line_copy = mini_line.copy()
|
||||
zcbr_group.add(mini_line_copy, mini_line)
|
||||
anims += [FadeIn(mini_line), FadeIn(mini_line_copy)]
|
||||
|
@ -2935,7 +2935,7 @@ class AnalyzeFunctionWithTransformations(NumberlineTransformationScene):
|
|||
def setup_number_lines(self):
|
||||
NumberlineTransformationScene.setup_number_lines(self)
|
||||
for line in self.input_line, self.output_line:
|
||||
VGroup(line.main_line, line.tick_marks).set_stroke(width=2)
|
||||
VGroup(line, line.tick_marks).set_stroke(width=2)
|
||||
|
||||
def add_function_title(self):
|
||||
title = TexMobject("f(x)", "=", "1 +", "\\frac{1}{x}")
|
||||
|
|
|
@ -3883,7 +3883,7 @@ class ThinkBackToHowAmazingThisIs(ThreeDScene):
|
|||
self.number_line = number_line
|
||||
|
||||
def show_giant_circle(self):
|
||||
self.number_line.main_line.insert_n_curves(10000)
|
||||
self.number_line.insert_n_curves(10000)
|
||||
everything = VGroup(*self.mobjects)
|
||||
circle = everything.copy()
|
||||
circle.move_to(ORIGIN)
|
||||
|
|
|
@ -3223,7 +3223,7 @@ class PhaseSpaceOfPopulationModel(ShowTwoPopulations, PiCreatureScene, MovingCam
|
|||
])
|
||||
for axis, label, vect in zip(axes, axes_labels, [RIGHT, UP]):
|
||||
label.next_to(
|
||||
axis.main_line, vect,
|
||||
axis, vect,
|
||||
submobject_to_align=label[0]
|
||||
)
|
||||
|
||||
|
@ -4297,7 +4297,7 @@ class ZToHalfFlowNearWall(ComplexTransformationScene, MovingCameraScene):
|
|||
secondary_line_ratio=0,
|
||||
)
|
||||
plane.next_to(ORIGIN, UP, buff=0.001)
|
||||
horizontal_lines = VGroup(*[l for l in list(plane.main_lines) + [plane.axes[0]] if np.abs(l.get_center()[0]) < 0.1])
|
||||
horizontal_lines = VGroup(*[l for l in list(planes) + [plane.axes[0]] if np.abs(l.get_center()[0]) < 0.1])
|
||||
plane.set_stroke(MAROON_B, width=2)
|
||||
horizontal_lines.set_stroke(BLUE, width=2)
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||
|
||||
def setup_plane(self):
|
||||
self.plane = NumberPlane(**self.plane_kwargs)
|
||||
self.plane.main_lines.fade()
|
||||
self.planes.fade()
|
||||
self.plane.add(self.plane.get_axis_labels())
|
||||
self.plane.add_coordinates()
|
||||
|
||||
|
|
|
@ -652,7 +652,7 @@ class ConstantVelocityPlot(PlotVelocity):
|
|||
|
||||
def note_units(self):
|
||||
x_line, y_line = lines = VGroup(*[
|
||||
axis.main_line.copy()
|
||||
axis.copy()
|
||||
for axis in (self.x_axis, self.y_axis)
|
||||
])
|
||||
lines.set_color(TIME_COLOR)
|
||||
|
|
|
@ -2221,7 +2221,7 @@ class ChangeToEigenBasis(ExampleTranformationScene):
|
|||
self.play(FadeOut(self.plane))
|
||||
cob_transform = self.get_matrix_transformation([[1, 0], [-1, 1]])
|
||||
ApplyMethod(self.plane.apply_function, cob_transform).update(1)
|
||||
self.plane.main_lines.set_color(BLUE_D)
|
||||
self.planes.set_color(BLUE_D)
|
||||
self.plane.axes.set_color(WHITE)
|
||||
self.play(
|
||||
FadeIn(self.plane),
|
||||
|
|
|
@ -2047,8 +2047,8 @@ class ShowCommutativeDiagram(ShowLinearity):
|
|||
VGroup(ta_group[1], fa_group[1]).shift(MED_LARGE_BUFF*UP)
|
||||
for ta, fa in zip(ta_group, fa_group):
|
||||
fa.next_to(
|
||||
ta.x_axis.main_line, RIGHT,
|
||||
submobject_to_align = fa.x_axis.main_line
|
||||
ta.x_axis, RIGHT,
|
||||
submobject_to_align = fa.x_axis
|
||||
)
|
||||
fa.to_edge(RIGHT)
|
||||
ta.remove(ta.labels)
|
||||
|
@ -2084,7 +2084,7 @@ class ShowCommutativeDiagram(ShowLinearity):
|
|||
fourier_graph.set_color(self.center_of_mass_color)
|
||||
|
||||
arrow = Arrow(
|
||||
ta.x_axis.main_line, fa.x_axis.main_line,
|
||||
ta.x_axis, fa.x_axis,
|
||||
color = WHITE,
|
||||
buff = MED_LARGE_BUFF,
|
||||
)
|
||||
|
@ -3712,7 +3712,7 @@ class SummarizeTheFullTransform(DrawFrequencyPlot):
|
|||
)
|
||||
imaginary_fourier_graph.set_color(BLUE)
|
||||
imaginary_fourier_graph.shift(
|
||||
frequency_axes.x_axis.main_line.get_right() - \
|
||||
frequency_axes.x_axis.get_right() - \
|
||||
imaginary_fourier_graph.points[-1],
|
||||
)
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Slider(NumberLine):
|
|||
def add_label(self, tex):
|
||||
label = TexMobject(tex)
|
||||
label.scale(self.label_scale_val)
|
||||
label.move_to(self.main_line.get_top())
|
||||
label.move_to(self.get_top())
|
||||
label.shift(MED_LARGE_BUFF*UP)
|
||||
self.add(label)
|
||||
self.label = label
|
||||
|
|
|
@ -674,7 +674,7 @@ class QuarterTurn(Scene):
|
|||
class UsingTheta(Scene):
|
||||
def construct(self):
|
||||
plane = NumberPlane(x_unit_size = 3, y_unit_size = 3)
|
||||
# plane.main_lines.fade(0.5)
|
||||
# planes.fade(0.5)
|
||||
# plane.secondary_lines.fade(0.5)
|
||||
plane.fade(0.5)
|
||||
self.add(plane)
|
||||
|
|
|
@ -1245,7 +1245,7 @@ class IntroduceLinusTheLinelander(Scene):
|
|||
algebra.shift(3 * RIGHT)
|
||||
|
||||
self.play(
|
||||
ShowCreation(number_line.main_line),
|
||||
ShowCreation(number_line),
|
||||
linus.look_at, number_line
|
||||
)
|
||||
self.play(
|
||||
|
@ -3123,9 +3123,9 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
|||
z_axis.set_color(WHITE)
|
||||
z_axis_top = Line(
|
||||
z_axis.number_to_point(0),
|
||||
z_axis.main_line.get_end(),
|
||||
z_axis.get_end(),
|
||||
)
|
||||
z_axis_top.match_style(z_axis.main_line)
|
||||
z_axis_top.match_style(z_axis)
|
||||
|
||||
z_unit_line = Line(
|
||||
z_axis.number_to_point(0),
|
||||
|
@ -3155,7 +3155,7 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
|||
colored_coord_lines = VGroup(colored_, y_line, z_line)
|
||||
|
||||
coord_lines = VGroup(
|
||||
plane.axes[0], plane.axes[1], z_axis.main_line,
|
||||
plane.axes[0], plane.axes[1], z_axis,
|
||||
)
|
||||
for i1, i2 in [(0, 2), (1, 0), (2, 1)]:
|
||||
coord_lines[i1].target = coord_lines[i2].copy()
|
||||
|
|
|
@ -1700,7 +1700,7 @@ class VisualizeZSquared(Scene):
|
|||
color_grid = self.get_color_grid()
|
||||
|
||||
self.play(
|
||||
self.background_plane.main_lines.set_stroke, None, 1,
|
||||
self.background_planes.set_stroke, None, 1,
|
||||
LaggedStart(
|
||||
FadeIn, color_grid,
|
||||
run_time = 2
|
||||
|
@ -1807,7 +1807,7 @@ class VisualizeZSquared(Scene):
|
|||
secondary_line_ratio = 0,
|
||||
stroke_width = 2,
|
||||
)
|
||||
color_grid.main_lines.set_color_by_gradient(
|
||||
color_grids.set_color_by_gradient(
|
||||
*[GREEN, RED, MAROON_B, TEAL]*2
|
||||
)
|
||||
color_grid.remove(color_grid.axes[0])
|
||||
|
|
|
@ -877,7 +877,7 @@ class TwoCarsAtRedLight(Scene):
|
|||
))
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
self.time_axes.x_axis.main_line.stretch, 2.5, 0,
|
||||
self.time_axes.x_axis.stretch, 2.5, 0,
|
||||
{"about_edge" : LEFT},
|
||||
run_time = 4,
|
||||
rate_func = squish_rate_func(smooth, 0.3, 0.6),
|
||||
|
@ -885,7 +885,7 @@ class TwoCarsAtRedLight(Scene):
|
|||
UpdateFromFunc(
|
||||
self.time_axes.x_axis.tip,
|
||||
lambda m : m.move_to(
|
||||
self.time_axes.x_axis.main_line.get_right(),
|
||||
self.time_axes.x_axis.get_right(),
|
||||
LEFT
|
||||
)
|
||||
),
|
||||
|
@ -1364,7 +1364,7 @@ class CenterOfMassDescription(FourierRecapScene):
|
|||
circle_plane.target.set_height(FRAME_HEIGHT)
|
||||
circle_plane.target.center()
|
||||
circle_plane.target.axes.set_stroke(width = 2)
|
||||
circle_plane.target.main_lines.set_stroke(width = 2)
|
||||
circle_plane.targets.set_stroke(width = 2)
|
||||
circle_plane.target.secondary_lines.set_stroke(width = 1)
|
||||
|
||||
start_coords = (0.5, 0.5)
|
||||
|
@ -2940,7 +2940,7 @@ class IntroduceDeBroglie(Scene):
|
|||
self.wait()
|
||||
|
||||
#Transform time_line
|
||||
line = time_line.main_line
|
||||
line = time_line
|
||||
self.play(
|
||||
FadeOut(time_line.numbers),
|
||||
VGroup(arrow, words, date).shift, MED_LARGE_BUFF*UP,
|
||||
|
|
Loading…
Add table
Reference in a new issue