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)
|
self.add_foreground_mobject(title)
|
||||||
|
|
||||||
def edit_background_plane(self):
|
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.background.secondary_lines.set_stroke(DARK_GREY, 1)
|
||||||
self.add_foreground_mobject(self.background.coordinate_labels)
|
self.add_foreground_mobject(self.background.coordinate_labels)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ from manimlib.utils.config_ops import digest_config
|
||||||
|
|
||||||
|
|
||||||
class Container(object):
|
class Container(object):
|
||||||
def __init__(self, *submobjects, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
|
||||||
def add(self, *items):
|
def add(self, *items):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import itertools as it
|
||||||
|
|
||||||
from manimlib.constants import *
|
from manimlib.constants import *
|
||||||
from manimlib.mobject.functions import ParametricFunction
|
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.number_line import NumberLine
|
||||||
from manimlib.mobject.svg.tex_mobject import TexMobject
|
from manimlib.mobject.svg.tex_mobject import TexMobject
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
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 digest_config
|
||||||
from manimlib.utils.config_ops import merge_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
|
from manimlib.utils.space_ops import angle_of_vector
|
||||||
|
|
||||||
# TODO: There should be much more code reuse between Axes, NumberPlane and GraphScene
|
# 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 = {
|
CONFIG = {
|
||||||
"three_d": False,
|
|
||||||
"number_line_config": {
|
"number_line_config": {
|
||||||
"color": LIGHT_GREY,
|
"color": LIGHT_GREY,
|
||||||
"include_tip": True,
|
"include_tip": True,
|
||||||
|
@ -26,24 +100,26 @@ class Axes(VGroup):
|
||||||
"y_axis_config": {
|
"y_axis_config": {
|
||||||
"label_direction": LEFT,
|
"label_direction": LEFT,
|
||||||
},
|
},
|
||||||
"x_min": -FRAME_X_RADIUS,
|
"center_point": ORIGIN,
|
||||||
"x_max": FRAME_X_RADIUS,
|
|
||||||
"y_min": -FRAME_Y_RADIUS,
|
|
||||||
"y_max": FRAME_Y_RADIUS,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
VGroup.__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.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_min, self.y_max, self.y_axis_config
|
||||||
)
|
)
|
||||||
self.y_axis.rotate(90 * DEGREES, about_point=ORIGIN)
|
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([
|
new_config = merge_config([
|
||||||
axis_config,
|
axis_config,
|
||||||
{"x_min": min_val, "x_max": max_val},
|
{"x_min": min_val, "x_max": max_val},
|
||||||
|
@ -54,63 +130,23 @@ class Axes(VGroup):
|
||||||
def coords_to_point(self, *coords):
|
def coords_to_point(self, *coords):
|
||||||
origin = self.x_axis.number_to_point(0)
|
origin = self.x_axis.number_to_point(0)
|
||||||
result = np.array(origin)
|
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)
|
result += (axis.number_to_point(coord) - origin)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def point_to_coords(self, point):
|
def point_to_coords(self, point):
|
||||||
return tuple([
|
return tuple([
|
||||||
axis.point_to_number(point)
|
axis.point_to_number(point)
|
||||||
for axis in self
|
for axis in self.get_axes()
|
||||||
if isinstance(axis, NumberLine)
|
|
||||||
])
|
])
|
||||||
|
|
||||||
def get_graph(
|
def get_axes(self):
|
||||||
self, function,
|
return self.axes
|
||||||
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))
|
|
||||||
|
|
||||||
|
|
||||||
class ThreeDAxes(Axes):
|
class ThreeDAxes(Axes):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
"dimension": 3,
|
||||||
"x_min": -5.5,
|
"x_min": -5.5,
|
||||||
"x_max": 5.5,
|
"x_max": 5.5,
|
||||||
"y_min": -5.5,
|
"y_min": -5.5,
|
||||||
|
@ -125,7 +161,7 @@ class ThreeDAxes(Axes):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
Axes.__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
|
self.z_min, self.z_max, self.z_axis_config
|
||||||
)
|
)
|
||||||
z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN)
|
z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN)
|
||||||
|
@ -133,18 +169,19 @@ class ThreeDAxes(Axes):
|
||||||
angle_of_vector(self.z_normal), OUT,
|
angle_of_vector(self.z_normal), OUT,
|
||||||
about_point=ORIGIN
|
about_point=ORIGIN
|
||||||
)
|
)
|
||||||
|
self.axes.append(z_axis)
|
||||||
self.add(z_axis)
|
self.add(z_axis)
|
||||||
|
|
||||||
self.add_3d_pieces()
|
self.add_3d_pieces()
|
||||||
self.set_axis_shading()
|
self.set_axis_shading()
|
||||||
|
|
||||||
def add_3d_pieces(self):
|
def add_3d_pieces(self):
|
||||||
for axis in self:
|
for axis in self.axes:
|
||||||
axis.pieces = VGroup(
|
axis.pieces = VGroup(
|
||||||
*axis.main_line.get_pieces(self.num_axis_pieces)
|
*axis.get_pieces(self.num_axis_pieces)
|
||||||
)
|
)
|
||||||
axis.add(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)
|
axis.set_shade_in_3d(True)
|
||||||
|
|
||||||
def set_axis_shading(self):
|
def set_axis_shading(self):
|
||||||
|
@ -161,195 +198,180 @@ class ThreeDAxes(Axes):
|
||||||
submob.set_sheen(0.2)
|
submob.set_sheen(0.2)
|
||||||
|
|
||||||
|
|
||||||
class NumberPlane(VMobject):
|
class NumberPlane(Axes):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"color": BLUE_D,
|
"axis_config": {
|
||||||
"secondary_color": BLUE_E,
|
"stroke_color": WHITE,
|
||||||
"axes_color": WHITE,
|
"stroke_width": 2,
|
||||||
"secondary_stroke_width": 1,
|
"include_ticks": False,
|
||||||
# TODO: Allow coordinate center of NumberPlane to not be at (0, 0)
|
"include_tip": False,
|
||||||
"x_radius": None,
|
"line_to_number_buff": SMALL_BUFF,
|
||||||
"y_radius": None,
|
"label_direction": DR,
|
||||||
"x_unit_size": 1,
|
"number_scale_val": 0.5,
|
||||||
"y_unit_size": 1,
|
},
|
||||||
"center_point": ORIGIN,
|
"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,
|
"x_line_frequency": 1,
|
||||||
"y_line_frequency": 1,
|
"y_line_frequency": 1,
|
||||||
"secondary_line_ratio": 1,
|
"faded_line_ratio": 1,
|
||||||
"written_coordinate_height": 0.2,
|
|
||||||
"propagate_style_to_family": False,
|
|
||||||
"make_smooth_after_applying_functions": True,
|
"make_smooth_after_applying_functions": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def generate_points(self):
|
def __init__(self, **kwargs):
|
||||||
if self.x_radius is None:
|
digest_config(self, kwargs)
|
||||||
center_to_edge = (FRAME_X_RADIUS + abs(self.center_point[0]))
|
kwargs["number_line_config"] = self.axis_config
|
||||||
self.x_radius = center_to_edge / self.x_unit_size
|
Axes.__init__(self, **kwargs)
|
||||||
if self.y_radius is None:
|
self.init_background_lines()
|
||||||
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):
|
def init_background_lines(self):
|
||||||
VMobject.init_colors(self)
|
if self.faded_line_style is None:
|
||||||
self.axes.set_stroke(self.axes_color, self.stroke_width)
|
background_line_style = self.background_line_style
|
||||||
self.main_lines.set_stroke(self.color, self.stroke_width)
|
color = background_line_style.get(
|
||||||
self.secondary_lines.set_stroke(
|
"stroke_color", WHITE
|
||||||
self.secondary_color, self.secondary_stroke_width
|
)
|
||||||
|
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,
|
||||||
)
|
)
|
||||||
return self
|
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):
|
def get_center_point(self):
|
||||||
return self.coords_to_point(0, 0)
|
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):
|
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):
|
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):
|
def get_coordinate_labels(self, x_vals=None, y_vals=None):
|
||||||
coordinate_labels = VGroup()
|
x_vals = x_vals or []
|
||||||
if x_vals is None:
|
y_vals = y_vals or []
|
||||||
x_vals = list(range(-int(self.x_radius), int(self.x_radius) + 1))
|
x_mobs = self.get_x_axis().get_number_mobjects(*x_vals)
|
||||||
if y_vals is None:
|
y_mobs = self.get_y_axis().get_number_mobjects(*y_vals)
|
||||||
y_vals = list(range(-int(self.y_radius), int(self.y_radius) + 1))
|
|
||||||
for index, vals in enumerate([x_vals, y_vals]):
|
self.coordinate_labels = VGroup(x_mobs, y_mobs)
|
||||||
num_pair = [0, 0]
|
return self.coordinate_labels
|
||||||
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
|
|
||||||
|
|
||||||
def get_axes(self):
|
def get_axes(self):
|
||||||
return self.axes
|
return self.axes
|
||||||
|
|
||||||
def get_axis_labels(self, x_label="x", y_label="y"):
|
def get_x_axis_label(self, label_tex, edge=RIGHT, direction=DL, **kwargs):
|
||||||
x_axis, y_axis = self.get_axes().split()
|
return self.get_axis_label(
|
||||||
quads = [
|
label_tex, self.get_x_axis(),
|
||||||
(x_axis, x_label, UP, RIGHT),
|
edge, direction, **kwargs
|
||||||
(y_axis, y_label, RIGHT, UP),
|
)
|
||||||
]
|
|
||||||
labels = VGroup()
|
def get_y_axis_label(self, label_tex, edge=UP, direction=DR, **kwargs):
|
||||||
for axis, tex, vect, edge in quads:
|
return self.get_axis_label(
|
||||||
label = TexMobject(tex)
|
label_tex, self.get_y_axis(),
|
||||||
label.add_background_rectangle()
|
edge, direction, **kwargs
|
||||||
label.next_to(axis, vect)
|
)
|
||||||
label.to_edge(edge)
|
|
||||||
labels.add(label)
|
def get_axis_label(self, label_tex, axis, edge, direction, buff=MED_SMALL_BUFF):
|
||||||
self.axis_labels = labels
|
label = TexMobject(label_tex)
|
||||||
return labels
|
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):
|
def add_coordinates(self, x_vals=None, y_vals=None):
|
||||||
self.add(*self.get_coordinate_labels(x_vals, y_vals))
|
self.add(self.get_coordinate_labels(x_vals, y_vals))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_vector(self, coords, **kwargs):
|
def get_vector(self, coords, **kwargs):
|
||||||
point = coords[0] * RIGHT + coords[1] * UP
|
kwargs["buff"] = 0
|
||||||
arrow = Arrow(ORIGIN, point, **kwargs)
|
return Arrow(
|
||||||
return arrow
|
self.coords_to_point(0, 0),
|
||||||
|
self.coords_to_point(*coords),
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
def prepare_for_nonlinear_transform(self, num_inserted_curves=50):
|
def prepare_for_nonlinear_transform(self, num_inserted_curves=50):
|
||||||
for mob in self.family_members_with_points():
|
for mob in self.family_members_with_points():
|
||||||
num_curves = mob.get_num_curves()
|
num_curves = mob.get_num_curves()
|
||||||
if num_inserted_curves > num_curves:
|
if num_inserted_curves > num_curves:
|
||||||
mob.insert_n_curves(
|
mob.insert_n_curves(
|
||||||
num_inserted_curves - num_curves)
|
num_inserted_curves - num_curves
|
||||||
mob.make_smooth()
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class ComplexPlane(NumberPlane):
|
class ComplexPlane(NumberPlane):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"color": BLUE,
|
"color": BLUE,
|
||||||
"unit_size": 1,
|
|
||||||
"line_frequency": 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):
|
def number_to_point(self, number):
|
||||||
number = complex(number)
|
number = complex(number)
|
||||||
return self.coords_to_point(number.real, number.imag)
|
return self.coords_to_point(number.real, number.imag)
|
||||||
|
@ -358,35 +380,35 @@ class ComplexPlane(NumberPlane):
|
||||||
x, y = self.point_to_coords(point)
|
x, y = self.point_to_coords(point)
|
||||||
return complex(x, y)
|
return complex(x, y)
|
||||||
|
|
||||||
def get_coordinate_labels(self, *numbers):
|
def get_default_coordinate_values(self):
|
||||||
# TODO: Should merge this with the code from NumberPlane.get_coordinate_labels
|
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]
|
||||||
|
|
||||||
result = VGroup()
|
def get_coordinate_labels(self, *numbers, **kwargs):
|
||||||
if len(numbers) == 0:
|
if len(numbers) == 0:
|
||||||
numbers = list(range(-int(self.x_radius), int(self.x_radius) + 1))
|
numbers = self.get_default_coordinate_values()
|
||||||
numbers += [
|
|
||||||
complex(0, y)
|
self.coordinate_labels = VGroup()
|
||||||
for y in range(-int(self.y_radius), int(self.y_radius) + 1)
|
|
||||||
if y != 0
|
|
||||||
]
|
|
||||||
for number in numbers:
|
for number in numbers:
|
||||||
# if number == complex(0, 0):
|
z = complex(number)
|
||||||
# continue
|
if abs(z.imag) > abs(z.real):
|
||||||
point = self.number_to_point(number)
|
axis = self.get_y_axis()
|
||||||
num_str = str(number).replace("j", "i")
|
value = z.imag
|
||||||
if num_str.startswith("0"):
|
kwargs = merge_config([
|
||||||
num_str = "0"
|
{"number_config": {"unit": "i"}},
|
||||||
elif num_str in ["1i", "-1i"]:
|
kwargs,
|
||||||
num_str = num_str.replace("1", "")
|
])
|
||||||
num_mob = TexMobject(num_str)
|
else:
|
||||||
num_mob.add_background_rectangle()
|
axis = self.get_x_axis()
|
||||||
num_mob.set_height(self.written_coordinate_height)
|
value = z.real
|
||||||
num_mob.next_to(point, DOWN + LEFT, SMALL_BUFF)
|
number_mob = axis.get_number_mobject(value, **kwargs)
|
||||||
result.add(num_mob)
|
self.coordinate_labels.add(number_mob)
|
||||||
self.coordinate_labels = result
|
return self.coordinate_labels
|
||||||
return result
|
|
||||||
|
|
||||||
def add_coordinates(self, *numbers):
|
def add_coordinates(self, *numbers):
|
||||||
self.coordinate_labels = self.get_coordinate_labels(*numbers)
|
self.add(self.get_coordinate_labels(*numbers))
|
||||||
self.add(self.coordinate_labels)
|
|
||||||
return self
|
return self
|
||||||
|
|
|
@ -36,11 +36,9 @@ class Mobject(Container):
|
||||||
"target": None,
|
"target": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *submobjects, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
Container.__init__(self, *submobjects, **kwargs)
|
Container.__init__(self, **kwargs)
|
||||||
if not all([isinstance(m, Mobject) for m in submobjects]):
|
self.submobjects = []
|
||||||
raise Exception("All submobjects must be of type Mobject")
|
|
||||||
self.submobjects = list(submobjects)
|
|
||||||
self.color = Color(self.color)
|
self.color = Color(self.color)
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
self.name = self.__class__.__name__
|
self.name = self.__class__.__name__
|
||||||
|
@ -1031,7 +1029,8 @@ class Mobject(Container):
|
||||||
|
|
||||||
|
|
||||||
class Group(Mobject):
|
class Group(Mobject):
|
||||||
# Alternate name to improve readibility in cases where
|
def __init__(self, *mobjects, **kwargs):
|
||||||
# the mobject is used primarily for its submobject housing
|
if not all([isinstance(m, Mobject) for m in mobjects]):
|
||||||
# functionality.
|
raise Exception("All submobjects must be of type Mobject")
|
||||||
pass
|
Mobject.__init__(self, **kwargs)
|
||||||
|
self.add(*mobjects)
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
|
import operator as op
|
||||||
|
|
||||||
from manimlib.constants import *
|
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.geometry import Line
|
||||||
from manimlib.mobject.numbers import DecimalNumber
|
from manimlib.mobject.numbers import DecimalNumber
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
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.bezier import interpolate
|
||||||
from manimlib.utils.config_ops import digest_config
|
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.simple_functions import fdiv
|
||||||
from manimlib.utils.space_ops import get_norm
|
|
||||||
from manimlib.utils.space_ops import normalize
|
from manimlib.utils.space_ops import normalize
|
||||||
|
|
||||||
|
|
||||||
class NumberLine(VMobject):
|
class NumberLine(Line):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"color": LIGHT_GREY,
|
"color": LIGHT_GREY,
|
||||||
"x_min": -FRAME_X_RADIUS,
|
"x_min": -FRAME_X_RADIUS,
|
||||||
"x_max": FRAME_X_RADIUS,
|
"x_max": FRAME_X_RADIUS,
|
||||||
"unit_size": 1,
|
"unit_size": 1,
|
||||||
|
"include_ticks": True,
|
||||||
"tick_size": 0.1,
|
"tick_size": 0.1,
|
||||||
"tick_frequency": 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],
|
"numbers_with_elongated_ticks": [0],
|
||||||
"include_numbers": False,
|
"include_numbers": False,
|
||||||
"numbers_to_show": None,
|
"numbers_to_show": None,
|
||||||
|
@ -29,6 +34,8 @@ class NumberLine(VMobject):
|
||||||
"label_direction": DOWN,
|
"label_direction": DOWN,
|
||||||
"line_to_number_buff": MED_SMALL_BUFF,
|
"line_to_number_buff": MED_SMALL_BUFF,
|
||||||
"include_tip": False,
|
"include_tip": False,
|
||||||
|
"tip_width": 0.25,
|
||||||
|
"tip_height": 0.25,
|
||||||
"decimal_number_config": {
|
"decimal_number_config": {
|
||||||
"num_decimal_places": 0,
|
"num_decimal_places": 0,
|
||||||
}
|
}
|
||||||
|
@ -36,68 +43,72 @@ class NumberLine(VMobject):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
if self.leftmost_tick is None:
|
start = self.unit_size * self.x_min * RIGHT
|
||||||
tf = self.tick_frequency
|
end = self.unit_size * self.x_max * RIGHT
|
||||||
self.leftmost_tick = tf * np.ceil(self.x_min / tf)
|
Line.__init__(self, start, end, **kwargs)
|
||||||
VMobject.__init__(self, **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:
|
if self.include_tip:
|
||||||
self.add_tip()
|
self.add_tip()
|
||||||
if self.include_numbers:
|
if self.include_numbers:
|
||||||
self.add_numbers()
|
self.add_numbers()
|
||||||
|
|
||||||
def generate_points(self):
|
def init_leftmost_tick(self):
|
||||||
self.main_line = Line(self.x_min * RIGHT, self.x_max * RIGHT)
|
if self.leftmost_tick is None:
|
||||||
self.tick_marks = VGroup()
|
self.leftmost_tick = op.mul(
|
||||||
self.add(self.main_line, self.tick_marks)
|
self.tick_frequency,
|
||||||
rounding_value = int(-np.log10(0.1 * self.tick_frequency))
|
np.ceil(self.x_min / self.tick_frequency)
|
||||||
rounded_numbers_with_elongated_ticks = np.round(
|
)
|
||||||
self.numbers_with_elongated_ticks,
|
|
||||||
rounding_value
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
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 get_tick(self, x, size=None):
|
def get_tick(self, x, size=None):
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.tick_size
|
size = self.tick_size
|
||||||
result = Line(size * DOWN, size * UP)
|
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.move_to(self.number_to_point(x))
|
||||||
|
result.match_style(self)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_tick_marks(self):
|
def get_tick_marks(self):
|
||||||
return self.tick_marks
|
return VGroup(
|
||||||
|
*self.tick_marks,
|
||||||
|
*self.big_tick_marks,
|
||||||
|
)
|
||||||
|
|
||||||
def get_tick_numbers(self):
|
def get_tick_numbers(self):
|
||||||
epsilon = 0.001
|
|
||||||
return np.arange(
|
return np.arange(
|
||||||
self.leftmost_tick, self.x_max + epsilon,
|
self.leftmost_tick,
|
||||||
|
self.x_max + self.tick_frequency / 2,
|
||||||
self.tick_frequency
|
self.tick_frequency
|
||||||
)
|
)
|
||||||
|
|
||||||
def number_to_point(self, number):
|
def number_to_point(self, number):
|
||||||
alpha = float(number - self.x_min) / (self.x_max - self.x_min)
|
alpha = float(number - self.x_min) / (self.x_max - self.x_min)
|
||||||
return interpolate(
|
return interpolate(
|
||||||
self.main_line.get_start(),
|
self.get_start(), self.get_end(), alpha
|
||||||
self.main_line.get_end(),
|
|
||||||
alpha
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def point_to_number(self, point):
|
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
|
full_vect = end_point - start_point
|
||||||
unit_vect = normalize(full_vect)
|
unit_vect = normalize(full_vect)
|
||||||
|
|
||||||
|
@ -110,28 +121,43 @@ class NumberLine(VMobject):
|
||||||
)
|
)
|
||||||
return interpolate(self.x_min, self.x_max, proportion)
|
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):
|
def default_numbers_to_display(self):
|
||||||
if self.numbers_to_show is not None:
|
if self.numbers_to_show is not None:
|
||||||
return self.numbers_to_show
|
return self.numbers_to_show
|
||||||
return np.arange(int(self.leftmost_tick), int(self.x_max) + 1)
|
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):
|
def get_number_mobjects(self, *numbers, **kwargs):
|
||||||
# TODO, handle decimals
|
|
||||||
if len(numbers) == 0:
|
if len(numbers) == 0:
|
||||||
numbers = self.default_numbers_to_display()
|
numbers = self.default_numbers_to_display()
|
||||||
result = VGroup()
|
return VGroup(*[
|
||||||
for number in numbers:
|
self.get_number_mobject(number, **kwargs)
|
||||||
mob = DecimalNumber(
|
for number in numbers
|
||||||
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
|
|
||||||
|
|
||||||
def get_labels(self):
|
def get_labels(self):
|
||||||
return self.get_number_mobjects()
|
return self.get_number_mobjects()
|
||||||
|
@ -144,12 +170,13 @@ class NumberLine(VMobject):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_tip(self):
|
def add_tip(self):
|
||||||
start, end = self.main_line.get_start_and_end()
|
tip = RegularPolygon(3)
|
||||||
vect = (end - start) / get_norm(end - start)
|
color = self.color
|
||||||
arrow = Arrow(start, end + MED_SMALL_BUFF * vect, buff=0)
|
tip.set_stroke(color, width=self.get_stroke_width())
|
||||||
tip = arrow.tip
|
tip.set_fill(color, opacity=1)
|
||||||
tip.set_stroke(width=self.get_stroke_width())
|
tip.set_width(self.tip_width)
|
||||||
tip.set_color(self.color)
|
tip.set_height(self.tip_height, stretch=True)
|
||||||
|
tip.move_to(self.get_end(), LEFT)
|
||||||
self.tip = tip
|
self.tip = tip
|
||||||
self.add(tip)
|
self.add(tip)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class DecimalNumber(VMobject):
|
||||||
formatter = self.get_formatter()
|
formatter = self.get_formatter()
|
||||||
num_string = formatter.format(number)
|
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 num_string.startswith("-") and rounded_num == 0:
|
||||||
if self.include_sign:
|
if self.include_sign:
|
||||||
num_string = "+" + num_string[1:]
|
num_string = "+" + num_string[1:]
|
||||||
|
|
|
@ -11,7 +11,6 @@ from manimlib.mobject.geometry import Rectangle
|
||||||
from manimlib.mobject.geometry import RoundedRectangle
|
from manimlib.mobject.geometry import RoundedRectangle
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||||
from manimlib.utils.bezier import is_closed
|
|
||||||
from manimlib.utils.color import *
|
from manimlib.utils.color import *
|
||||||
from manimlib.utils.config_ops import digest_config
|
from manimlib.utils.config_ops import digest_config
|
||||||
from manimlib.utils.config_ops import digest_locals
|
from manimlib.utils.config_ops import digest_locals
|
||||||
|
@ -105,14 +104,14 @@ class SVGMobject(VMobject):
|
||||||
pass # TODO
|
pass # TODO
|
||||||
# warnings.warn("Unknown element type: " + element.tagName)
|
# warnings.warn("Unknown element type: " + element.tagName)
|
||||||
result = [m for m in result if m is not None]
|
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:
|
if len(result) > 1 and not self.unpack_groups:
|
||||||
result = [VGroup(*result)]
|
result = [VGroup(*result)]
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def g_to_mobjects(self, g_element):
|
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)
|
self.handle_transforms(g_element, mob)
|
||||||
return mob.submobjects
|
return mob.submobjects
|
||||||
|
|
||||||
|
@ -124,7 +123,7 @@ class SVGMobject(VMobject):
|
||||||
ref = use_element.getAttribute("xlink:href")[1:]
|
ref = use_element.getAttribute("xlink:href")[1:]
|
||||||
if ref not in self.ref_to_element:
|
if ref not in self.ref_to_element:
|
||||||
warnings.warn("%s not recognized" % ref)
|
warnings.warn("%s not recognized" % ref)
|
||||||
return VMobject()
|
return VGroup()
|
||||||
return self.get_mobjects_from(
|
return self.get_mobjects_from(
|
||||||
self.ref_to_element[ref]
|
self.ref_to_element[ref]
|
||||||
)
|
)
|
||||||
|
|
|
@ -796,18 +796,11 @@ class VMobject(Mobject):
|
||||||
|
|
||||||
|
|
||||||
class VGroup(VMobject):
|
class VGroup(VMobject):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *vmobjects, **kwargs):
|
||||||
if len(args) == 1 and isinstance(args[0], (tuple, list)):
|
if not all([isinstance(m, VMobject) for m in vmobjects]):
|
||||||
args = args[0]
|
raise Exception("All submobjects must be of type VMobject")
|
||||||
|
VMobject.__init__(self, **kwargs)
|
||||||
packed_args = []
|
self.add(*vmobjects)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class VectorizedPoint(VMobject):
|
class VectorizedPoint(VMobject):
|
||||||
|
|
|
@ -96,7 +96,7 @@ class ComplexTransformationScene(Scene):
|
||||||
# TODO...
|
# TODO...
|
||||||
|
|
||||||
def paint_plane(self, plane):
|
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(
|
lines.set_color_by_gradient(
|
||||||
self.vert_start_color,
|
self.vert_start_color,
|
||||||
self.vert_end_color,
|
self.vert_end_color,
|
||||||
|
|
|
@ -156,10 +156,10 @@ class SpecialThreeDScene(ThreeDScene):
|
||||||
axes = ThreeDAxes(**self.three_d_axes_config)
|
axes = ThreeDAxes(**self.three_d_axes_config)
|
||||||
for axis in axes:
|
for axis in axes:
|
||||||
if self.cut_axes_at_radius:
|
if self.cut_axes_at_radius:
|
||||||
p0 = axis.main_line.get_start()
|
p0 = axis.get_start()
|
||||||
p1 = axis.number_to_point(-1)
|
p1 = axis.number_to_point(-1)
|
||||||
p2 = axis.number_to_point(1)
|
p2 = axis.number_to_point(1)
|
||||||
p3 = axis.main_line.get_end()
|
p3 = axis.get_end()
|
||||||
new_pieces = VGroup(
|
new_pieces = VGroup(
|
||||||
Line(p0, p1), Line(p1, p2), Line(p2, p3),
|
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)
|
obj.__dict__ = merge_config(all_dicts)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO, priority here is backwards from dict.update.
|
||||||
|
# Should I change the convention?
|
||||||
def merge_config(all_dicts):
|
def merge_config(all_dicts):
|
||||||
"""
|
"""
|
||||||
Creates a dict whose keyset is the union of all the
|
Creates a dict whose keyset is the union of all the
|
||||||
input dictionaries. The value for each key is based
|
input dictionaries. The value for each key is based
|
||||||
on the first dict in the list with that key.
|
on the first dict in the list with that key.
|
||||||
|
|
||||||
|
First dicts have higher priority
|
||||||
|
|
||||||
When values are dictionaries, it is applied recursively
|
When values are dictionaries, it is applied recursively
|
||||||
"""
|
"""
|
||||||
all_config = reduce(op.add, [list(d.items()) for d in all_dicts])
|
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
|
where = True
|
||||||
|
|
||||||
return np.true_divide(a, b, out=out, where=where)
|
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.add_coordinates(x_vals = list(range(-2, 3)), y_vals = list(range(-2, 3)))
|
||||||
plane.white_parts = VGroup(plane.axes, plane.coordinate_labels)
|
plane.white_parts = VGroup(plane.axes, plane.coordinate_labels)
|
||||||
plane.coordinate_labels.set_background_stroke(width=0)
|
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)
|
plane.move_to(vect*FRAME_X_RADIUS/2 + self.y_shift*DOWN)
|
||||||
label = TextMobject(text)
|
label = TextMobject(text)
|
||||||
label.scale(1.5)
|
label.scale(1.5)
|
||||||
|
|
|
@ -76,7 +76,7 @@ class NumberlineTransformationScene(ZoomedScene):
|
||||||
full_config = dict(self.number_line_config)
|
full_config = dict(self.number_line_config)
|
||||||
full_config.update(added_config)
|
full_config.update(added_config)
|
||||||
number_line = NumberLine(**full_config)
|
number_line = NumberLine(**full_config)
|
||||||
number_line.main_line.insert_n_curves(
|
number_line.insert_n_curves(
|
||||||
self.num_inserted_number_line_curves
|
self.num_inserted_number_line_curves
|
||||||
)
|
)
|
||||||
number_line.shift(zero_point - number_line.number_to_point(0))
|
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
|
self.moving_input_line = input_line_copy
|
||||||
input_line_copy.remove(input_line_copy.numbers)
|
input_line_copy.remove(input_line_copy.numbers)
|
||||||
# input_line_copy.set_stroke(width=2)
|
# 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
|
self.num_inserted_number_line_curves
|
||||||
)
|
)
|
||||||
return AnimationGroup(
|
return AnimationGroup(
|
||||||
self.get_mapping_animation(
|
self.get_mapping_animation(
|
||||||
func, input_line_copy.main_line,
|
func, input_line_copy,
|
||||||
apply_function_to_points
|
apply_function_to_points
|
||||||
),
|
),
|
||||||
self.get_mapping_animation(
|
self.get_mapping_animation(
|
||||||
|
@ -242,7 +242,7 @@ class NumberlineTransformationScene(ZoomedScene):
|
||||||
zoom_anim.update(1)
|
zoom_anim.update(1)
|
||||||
target_mini_line = Line(frame.get_left(), frame.get_right())
|
target_mini_line = Line(frame.get_left(), frame.get_right())
|
||||||
target_mini_line.scale(self.mini_line_scale_factor)
|
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)
|
zoom_anim.update(0)
|
||||||
zcbr_group.submobjects.insert(1, target_mini_line)
|
zcbr_group.submobjects.insert(1, target_mini_line)
|
||||||
if target_coordinate_values:
|
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 = self.mini_line = Line(frame.get_left(), frame.get_right())
|
||||||
mini_line.scale(self.mini_line_scale_factor)
|
mini_line.scale(self.mini_line_scale_factor)
|
||||||
mini_line.insert_n_curves(self.num_inserted_number_line_curves)
|
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()
|
mini_line_copy = mini_line.copy()
|
||||||
zcbr_group.add(mini_line_copy, mini_line)
|
zcbr_group.add(mini_line_copy, mini_line)
|
||||||
anims += [FadeIn(mini_line), FadeIn(mini_line_copy)]
|
anims += [FadeIn(mini_line), FadeIn(mini_line_copy)]
|
||||||
|
@ -2935,7 +2935,7 @@ class AnalyzeFunctionWithTransformations(NumberlineTransformationScene):
|
||||||
def setup_number_lines(self):
|
def setup_number_lines(self):
|
||||||
NumberlineTransformationScene.setup_number_lines(self)
|
NumberlineTransformationScene.setup_number_lines(self)
|
||||||
for line in self.input_line, self.output_line:
|
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):
|
def add_function_title(self):
|
||||||
title = TexMobject("f(x)", "=", "1 +", "\\frac{1}{x}")
|
title = TexMobject("f(x)", "=", "1 +", "\\frac{1}{x}")
|
||||||
|
|
|
@ -3883,7 +3883,7 @@ class ThinkBackToHowAmazingThisIs(ThreeDScene):
|
||||||
self.number_line = number_line
|
self.number_line = number_line
|
||||||
|
|
||||||
def show_giant_circle(self):
|
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)
|
everything = VGroup(*self.mobjects)
|
||||||
circle = everything.copy()
|
circle = everything.copy()
|
||||||
circle.move_to(ORIGIN)
|
circle.move_to(ORIGIN)
|
||||||
|
|
|
@ -3223,7 +3223,7 @@ class PhaseSpaceOfPopulationModel(ShowTwoPopulations, PiCreatureScene, MovingCam
|
||||||
])
|
])
|
||||||
for axis, label, vect in zip(axes, axes_labels, [RIGHT, UP]):
|
for axis, label, vect in zip(axes, axes_labels, [RIGHT, UP]):
|
||||||
label.next_to(
|
label.next_to(
|
||||||
axis.main_line, vect,
|
axis, vect,
|
||||||
submobject_to_align=label[0]
|
submobject_to_align=label[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4297,7 +4297,7 @@ class ZToHalfFlowNearWall(ComplexTransformationScene, MovingCameraScene):
|
||||||
secondary_line_ratio=0,
|
secondary_line_ratio=0,
|
||||||
)
|
)
|
||||||
plane.next_to(ORIGIN, UP, buff=0.001)
|
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)
|
plane.set_stroke(MAROON_B, width=2)
|
||||||
horizontal_lines.set_stroke(BLUE, width=2)
|
horizontal_lines.set_stroke(BLUE, width=2)
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ class SlopeOfCircleExample(ZoomedScene):
|
||||||
|
|
||||||
def setup_plane(self):
|
def setup_plane(self):
|
||||||
self.plane = NumberPlane(**self.plane_kwargs)
|
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(self.plane.get_axis_labels())
|
||||||
self.plane.add_coordinates()
|
self.plane.add_coordinates()
|
||||||
|
|
||||||
|
|
|
@ -652,7 +652,7 @@ class ConstantVelocityPlot(PlotVelocity):
|
||||||
|
|
||||||
def note_units(self):
|
def note_units(self):
|
||||||
x_line, y_line = lines = VGroup(*[
|
x_line, y_line = lines = VGroup(*[
|
||||||
axis.main_line.copy()
|
axis.copy()
|
||||||
for axis in (self.x_axis, self.y_axis)
|
for axis in (self.x_axis, self.y_axis)
|
||||||
])
|
])
|
||||||
lines.set_color(TIME_COLOR)
|
lines.set_color(TIME_COLOR)
|
||||||
|
|
|
@ -2221,7 +2221,7 @@ class ChangeToEigenBasis(ExampleTranformationScene):
|
||||||
self.play(FadeOut(self.plane))
|
self.play(FadeOut(self.plane))
|
||||||
cob_transform = self.get_matrix_transformation([[1, 0], [-1, 1]])
|
cob_transform = self.get_matrix_transformation([[1, 0], [-1, 1]])
|
||||||
ApplyMethod(self.plane.apply_function, cob_transform).update(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.plane.axes.set_color(WHITE)
|
||||||
self.play(
|
self.play(
|
||||||
FadeIn(self.plane),
|
FadeIn(self.plane),
|
||||||
|
|
|
@ -2047,8 +2047,8 @@ class ShowCommutativeDiagram(ShowLinearity):
|
||||||
VGroup(ta_group[1], fa_group[1]).shift(MED_LARGE_BUFF*UP)
|
VGroup(ta_group[1], fa_group[1]).shift(MED_LARGE_BUFF*UP)
|
||||||
for ta, fa in zip(ta_group, fa_group):
|
for ta, fa in zip(ta_group, fa_group):
|
||||||
fa.next_to(
|
fa.next_to(
|
||||||
ta.x_axis.main_line, RIGHT,
|
ta.x_axis, RIGHT,
|
||||||
submobject_to_align = fa.x_axis.main_line
|
submobject_to_align = fa.x_axis
|
||||||
)
|
)
|
||||||
fa.to_edge(RIGHT)
|
fa.to_edge(RIGHT)
|
||||||
ta.remove(ta.labels)
|
ta.remove(ta.labels)
|
||||||
|
@ -2084,7 +2084,7 @@ class ShowCommutativeDiagram(ShowLinearity):
|
||||||
fourier_graph.set_color(self.center_of_mass_color)
|
fourier_graph.set_color(self.center_of_mass_color)
|
||||||
|
|
||||||
arrow = Arrow(
|
arrow = Arrow(
|
||||||
ta.x_axis.main_line, fa.x_axis.main_line,
|
ta.x_axis, fa.x_axis,
|
||||||
color = WHITE,
|
color = WHITE,
|
||||||
buff = MED_LARGE_BUFF,
|
buff = MED_LARGE_BUFF,
|
||||||
)
|
)
|
||||||
|
@ -3712,7 +3712,7 @@ class SummarizeTheFullTransform(DrawFrequencyPlot):
|
||||||
)
|
)
|
||||||
imaginary_fourier_graph.set_color(BLUE)
|
imaginary_fourier_graph.set_color(BLUE)
|
||||||
imaginary_fourier_graph.shift(
|
imaginary_fourier_graph.shift(
|
||||||
frequency_axes.x_axis.main_line.get_right() - \
|
frequency_axes.x_axis.get_right() - \
|
||||||
imaginary_fourier_graph.points[-1],
|
imaginary_fourier_graph.points[-1],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Slider(NumberLine):
|
||||||
def add_label(self, tex):
|
def add_label(self, tex):
|
||||||
label = TexMobject(tex)
|
label = TexMobject(tex)
|
||||||
label.scale(self.label_scale_val)
|
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)
|
label.shift(MED_LARGE_BUFF*UP)
|
||||||
self.add(label)
|
self.add(label)
|
||||||
self.label = label
|
self.label = label
|
||||||
|
|
|
@ -674,7 +674,7 @@ class QuarterTurn(Scene):
|
||||||
class UsingTheta(Scene):
|
class UsingTheta(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
plane = NumberPlane(x_unit_size = 3, y_unit_size = 3)
|
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.secondary_lines.fade(0.5)
|
||||||
plane.fade(0.5)
|
plane.fade(0.5)
|
||||||
self.add(plane)
|
self.add(plane)
|
||||||
|
|
|
@ -1245,7 +1245,7 @@ class IntroduceLinusTheLinelander(Scene):
|
||||||
algebra.shift(3 * RIGHT)
|
algebra.shift(3 * RIGHT)
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
ShowCreation(number_line.main_line),
|
ShowCreation(number_line),
|
||||||
linus.look_at, number_line
|
linus.look_at, number_line
|
||||||
)
|
)
|
||||||
self.play(
|
self.play(
|
||||||
|
@ -3123,9 +3123,9 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
||||||
z_axis.set_color(WHITE)
|
z_axis.set_color(WHITE)
|
||||||
z_axis_top = Line(
|
z_axis_top = Line(
|
||||||
z_axis.number_to_point(0),
|
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_unit_line = Line(
|
||||||
z_axis.number_to_point(0),
|
z_axis.number_to_point(0),
|
||||||
|
@ -3155,7 +3155,7 @@ class IntroduceThreeDNumbers(SpecialThreeDScene):
|
||||||
colored_coord_lines = VGroup(colored_, y_line, z_line)
|
colored_coord_lines = VGroup(colored_, y_line, z_line)
|
||||||
|
|
||||||
coord_lines = VGroup(
|
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)]:
|
for i1, i2 in [(0, 2), (1, 0), (2, 1)]:
|
||||||
coord_lines[i1].target = coord_lines[i2].copy()
|
coord_lines[i1].target = coord_lines[i2].copy()
|
||||||
|
|
|
@ -1700,7 +1700,7 @@ class VisualizeZSquared(Scene):
|
||||||
color_grid = self.get_color_grid()
|
color_grid = self.get_color_grid()
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
self.background_plane.main_lines.set_stroke, None, 1,
|
self.background_planes.set_stroke, None, 1,
|
||||||
LaggedStart(
|
LaggedStart(
|
||||||
FadeIn, color_grid,
|
FadeIn, color_grid,
|
||||||
run_time = 2
|
run_time = 2
|
||||||
|
@ -1807,7 +1807,7 @@ class VisualizeZSquared(Scene):
|
||||||
secondary_line_ratio = 0,
|
secondary_line_ratio = 0,
|
||||||
stroke_width = 2,
|
stroke_width = 2,
|
||||||
)
|
)
|
||||||
color_grid.main_lines.set_color_by_gradient(
|
color_grids.set_color_by_gradient(
|
||||||
*[GREEN, RED, MAROON_B, TEAL]*2
|
*[GREEN, RED, MAROON_B, TEAL]*2
|
||||||
)
|
)
|
||||||
color_grid.remove(color_grid.axes[0])
|
color_grid.remove(color_grid.axes[0])
|
||||||
|
|
|
@ -877,7 +877,7 @@ class TwoCarsAtRedLight(Scene):
|
||||||
))
|
))
|
||||||
self.play(
|
self.play(
|
||||||
ApplyMethod(
|
ApplyMethod(
|
||||||
self.time_axes.x_axis.main_line.stretch, 2.5, 0,
|
self.time_axes.x_axis.stretch, 2.5, 0,
|
||||||
{"about_edge" : LEFT},
|
{"about_edge" : LEFT},
|
||||||
run_time = 4,
|
run_time = 4,
|
||||||
rate_func = squish_rate_func(smooth, 0.3, 0.6),
|
rate_func = squish_rate_func(smooth, 0.3, 0.6),
|
||||||
|
@ -885,7 +885,7 @@ class TwoCarsAtRedLight(Scene):
|
||||||
UpdateFromFunc(
|
UpdateFromFunc(
|
||||||
self.time_axes.x_axis.tip,
|
self.time_axes.x_axis.tip,
|
||||||
lambda m : m.move_to(
|
lambda m : m.move_to(
|
||||||
self.time_axes.x_axis.main_line.get_right(),
|
self.time_axes.x_axis.get_right(),
|
||||||
LEFT
|
LEFT
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -1364,7 +1364,7 @@ class CenterOfMassDescription(FourierRecapScene):
|
||||||
circle_plane.target.set_height(FRAME_HEIGHT)
|
circle_plane.target.set_height(FRAME_HEIGHT)
|
||||||
circle_plane.target.center()
|
circle_plane.target.center()
|
||||||
circle_plane.target.axes.set_stroke(width = 2)
|
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)
|
circle_plane.target.secondary_lines.set_stroke(width = 1)
|
||||||
|
|
||||||
start_coords = (0.5, 0.5)
|
start_coords = (0.5, 0.5)
|
||||||
|
@ -2940,7 +2940,7 @@ class IntroduceDeBroglie(Scene):
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
#Transform time_line
|
#Transform time_line
|
||||||
line = time_line.main_line
|
line = time_line
|
||||||
self.play(
|
self.play(
|
||||||
FadeOut(time_line.numbers),
|
FadeOut(time_line.numbers),
|
||||||
VGroup(arrow, words, date).shift, MED_LARGE_BUFF*UP,
|
VGroup(arrow, words, date).shift, MED_LARGE_BUFF*UP,
|
||||||
|
|
Loading…
Add table
Reference in a new issue