manim 0.17.0__py3-none-any.whl → 0.19.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- manim/__init__.py +11 -6
- manim/__main__.py +62 -19
- manim/_config/__init__.py +10 -9
- manim/_config/cli_colors.py +26 -9
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +23 -13
- manim/_config/utils.py +662 -468
- manim/animation/animation.py +164 -18
- manim/animation/changing.py +34 -23
- manim/animation/composition.py +265 -67
- manim/animation/creation.py +208 -26
- manim/animation/fading.py +16 -18
- manim/animation/growing.py +35 -15
- manim/animation/indication.py +150 -76
- manim/animation/movement.py +56 -22
- manim/animation/numbers.py +64 -6
- manim/animation/rotation.py +78 -7
- manim/animation/specialized.py +6 -7
- manim/animation/speedmodifier.py +13 -10
- manim/animation/transform.py +14 -11
- manim/animation/transform_matching_parts.py +3 -4
- manim/animation/updaters/mobject_update_utils.py +152 -30
- manim/animation/updaters/update.py +10 -7
- manim/camera/camera.py +182 -118
- manim/camera/mapping_camera.py +34 -3
- manim/camera/moving_camera.py +95 -74
- manim/camera/multi_camera.py +23 -15
- manim/camera/three_d_camera.py +70 -52
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +76 -44
- manim/cli/checkhealth/checks.py +192 -0
- manim/cli/checkhealth/commands.py +90 -0
- manim/cli/default_group.py +158 -25
- manim/cli/init/commands.py +33 -25
- manim/cli/plugins/commands.py +16 -3
- manim/cli/render/commands.py +72 -60
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +59 -17
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +98 -33
- manim/constants.py +109 -59
- manim/data_structures.py +31 -0
- manim/mobject/frame.py +8 -5
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +277 -135
- manim/mobject/geometry/boolean_ops.py +32 -31
- manim/mobject/geometry/labeled.py +376 -0
- manim/mobject/geometry/line.py +192 -87
- manim/mobject/geometry/polygram.py +224 -58
- manim/mobject/geometry/shape_matchers.py +61 -25
- manim/mobject/geometry/tips.py +122 -48
- manim/mobject/graph.py +1027 -419
- manim/mobject/graphing/coordinate_systems.py +533 -278
- manim/mobject/graphing/functions.py +53 -32
- manim/mobject/graphing/number_line.py +123 -65
- manim/mobject/graphing/probability.py +88 -62
- manim/mobject/graphing/scale.py +33 -19
- manim/mobject/logo.py +118 -28
- manim/mobject/matrix.py +87 -83
- manim/mobject/mobject.py +912 -442
- manim/mobject/opengl/dot_cloud.py +16 -5
- manim/mobject/opengl/opengl_compatibility.py +4 -2
- manim/mobject/opengl/opengl_geometry.py +254 -153
- manim/mobject/opengl/opengl_image_mobject.py +3 -1
- manim/mobject/opengl/opengl_mobject.py +779 -482
- manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
- manim/mobject/opengl/opengl_surface.py +14 -92
- manim/mobject/opengl/opengl_three_dimensions.py +12 -8
- manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
- manim/mobject/svg/brace.py +173 -41
- manim/mobject/svg/svg_mobject.py +139 -53
- manim/mobject/table.py +61 -68
- manim/mobject/text/code_mobject.py +193 -539
- manim/mobject/text/numbers.py +81 -34
- manim/mobject/text/tex_mobject.py +130 -78
- manim/mobject/text/text_mobject.py +288 -164
- manim/mobject/three_d/polyhedra.py +111 -13
- manim/mobject/three_d/three_d_utils.py +17 -8
- manim/mobject/three_d/three_dimensions.py +239 -106
- manim/mobject/types/image_mobject.py +50 -30
- manim/mobject/types/point_cloud_mobject.py +120 -75
- manim/mobject/types/vectorized_mobject.py +841 -408
- manim/mobject/value_tracker.py +105 -38
- manim/mobject/vector_field.py +50 -31
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +10 -14
- manim/renderer/cairo_renderer.py +65 -50
- manim/renderer/opengl_renderer.py +89 -69
- manim/renderer/opengl_renderer_window.py +39 -18
- manim/renderer/shader.py +123 -87
- manim/renderer/shader_wrapper.py +44 -28
- manim/renderer/vectorized_mobject_rendering.py +38 -10
- manim/scene/moving_camera_scene.py +32 -3
- manim/scene/scene.py +507 -242
- manim/scene/scene_file_writer.py +371 -220
- manim/scene/section.py +20 -16
- manim/scene/three_d_scene.py +14 -22
- manim/scene/vector_space_scene.py +223 -129
- manim/scene/zoomed_scene.py +46 -41
- manim/typing.py +990 -0
- manim/utils/bezier.py +1823 -371
- manim/utils/caching.py +12 -5
- manim/utils/color/AS2700.py +236 -0
- manim/utils/color/BS381.py +318 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +533 -0
- manim/utils/color/XKCD.py +952 -0
- manim/utils/color/__init__.py +61 -0
- manim/utils/color/core.py +1667 -0
- manim/utils/color/manim_colors.py +218 -0
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +39 -19
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +86 -39
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +236 -0
- manim/utils/docbuild/autocolor_directive.py +99 -0
- manim/utils/docbuild/manim_directive.py +94 -41
- manim/utils/docbuild/module_parsing.py +245 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +5 -3
- manim/utils/family_ops.py +17 -4
- manim/utils/file_ops.py +27 -17
- manim/utils/hashing.py +55 -45
- manim/utils/images.py +13 -7
- manim/utils/ipython_magic.py +13 -7
- manim/utils/iterables.py +163 -120
- manim/utils/module_ops.py +66 -24
- manim/utils/opengl.py +77 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +30 -33
- manim/utils/polylabel.py +235 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +98 -32
- manim/utils/simple_functions.py +25 -33
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +188 -115
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +34 -18
- manim/utils/testing/frames_comparison.py +37 -19
- manim/utils/tex.py +130 -198
- manim/utils/tex_file_writing.py +77 -47
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
- manim-0.19.1.dist-info/RECORD +220 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
- manim-0.19.1.dist-info/entry_points.txt +3 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
- manim/cli/new/group.py +0 -189
- manim/communitycolors.py +0 -9
- manim/gui/__init__.py +0 -0
- manim/gui/gui.py +0 -82
- manim/plugins/import_plugins.py +0 -43
- manim/utils/color.py +0 -552
- manim-0.17.0.dist-info/RECORD +0 -206
- manim-0.17.0.dist-info/entry_points.txt +0 -4
- /manim/cli/{new → checkhealth}/__init__.py +0 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -5,7 +5,8 @@ from __future__ import annotations
|
|
|
5
5
|
__all__ = ["ParametricFunction", "FunctionGraph", "ImplicitFunction"]
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
9
10
|
|
|
10
11
|
import numpy as np
|
|
11
12
|
from isosurfaces import plot_isoline
|
|
@@ -14,6 +15,15 @@ from manim import config
|
|
|
14
15
|
from manim.mobject.graphing.scale import LinearBase, _ScaleBase
|
|
15
16
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
16
17
|
from manim.mobject.types.vectorized_mobject import VMobject
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from typing_extensions import Self
|
|
23
|
+
|
|
24
|
+
from manim.typing import Point3D, Point3DLike
|
|
25
|
+
from manim.utils.color import ParsableManimColor
|
|
26
|
+
|
|
17
27
|
from manim.utils.color import YELLOW
|
|
18
28
|
|
|
19
29
|
|
|
@@ -23,9 +33,9 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
23
33
|
Parameters
|
|
24
34
|
----------
|
|
25
35
|
function
|
|
26
|
-
The function to be plotted in the form of ``(lambda
|
|
36
|
+
The function to be plotted in the form of ``(lambda t: (x(t), y(t), z(t)))``
|
|
27
37
|
t_range
|
|
28
|
-
Determines the length that the function spans. By default ``[0, 1]``
|
|
38
|
+
Determines the length that the function spans in the form of (t_min, t_max, step=0.01). By default ``[0, 1]``
|
|
29
39
|
scaling
|
|
30
40
|
Scaling class applied to the points of the function. Default of :class:`~.LinearBase`.
|
|
31
41
|
use_smoothing
|
|
@@ -49,10 +59,10 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
49
59
|
|
|
50
60
|
class PlotParametricFunction(Scene):
|
|
51
61
|
def func(self, t):
|
|
52
|
-
return
|
|
62
|
+
return (np.sin(2 * t), np.sin(3 * t), 0)
|
|
53
63
|
|
|
54
64
|
def construct(self):
|
|
55
|
-
func = ParametricFunction(self.func, t_range =
|
|
65
|
+
func = ParametricFunction(self.func, t_range = (0, TAU), fill_opacity=0).set_color(RED)
|
|
56
66
|
self.add(func.scale(3))
|
|
57
67
|
|
|
58
68
|
.. manim:: ThreeDParametricSpring
|
|
@@ -61,11 +71,11 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
61
71
|
class ThreeDParametricSpring(ThreeDScene):
|
|
62
72
|
def construct(self):
|
|
63
73
|
curve1 = ParametricFunction(
|
|
64
|
-
lambda u:
|
|
74
|
+
lambda u: (
|
|
65
75
|
1.2 * np.cos(u),
|
|
66
76
|
1.2 * np.sin(u),
|
|
67
77
|
u * 0.05
|
|
68
|
-
|
|
78
|
+
), color=RED, t_range = (-3*TAU, 5*TAU, 0.01)
|
|
69
79
|
).set_shade_in_3d(True)
|
|
70
80
|
axes = ThreeDAxes()
|
|
71
81
|
self.add(axes, curve1)
|
|
@@ -97,19 +107,22 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
97
107
|
|
|
98
108
|
def __init__(
|
|
99
109
|
self,
|
|
100
|
-
function: Callable[[float
|
|
101
|
-
t_range:
|
|
110
|
+
function: Callable[[float], Point3DLike],
|
|
111
|
+
t_range: tuple[float, float] | tuple[float, float, float] = (0, 1),
|
|
102
112
|
scaling: _ScaleBase = LinearBase(),
|
|
103
113
|
dt: float = 1e-8,
|
|
104
114
|
discontinuities: Iterable[float] | None = None,
|
|
105
115
|
use_smoothing: bool = True,
|
|
106
116
|
use_vectorized: bool = False,
|
|
107
|
-
**kwargs,
|
|
117
|
+
**kwargs: Any,
|
|
108
118
|
):
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
def internal_parametric_function(t: float) -> Point3D:
|
|
120
|
+
"""Wrap ``function``'s output inside a NumPy array."""
|
|
121
|
+
return np.asarray(function(t))
|
|
122
|
+
|
|
123
|
+
self.function = internal_parametric_function
|
|
111
124
|
if len(t_range) == 2:
|
|
112
|
-
t_range =
|
|
125
|
+
t_range = (*t_range, 0.01)
|
|
113
126
|
|
|
114
127
|
self.scaling = scaling
|
|
115
128
|
|
|
@@ -121,26 +134,25 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
121
134
|
|
|
122
135
|
super().__init__(**kwargs)
|
|
123
136
|
|
|
124
|
-
def get_function(self):
|
|
137
|
+
def get_function(self) -> Callable[[float], Point3D]:
|
|
125
138
|
return self.function
|
|
126
139
|
|
|
127
|
-
def get_point_from_function(self, t):
|
|
140
|
+
def get_point_from_function(self, t: float) -> Point3D:
|
|
128
141
|
return self.function(t)
|
|
129
142
|
|
|
130
|
-
def generate_points(self):
|
|
131
|
-
|
|
143
|
+
def generate_points(self) -> Self:
|
|
132
144
|
if self.discontinuities is not None:
|
|
133
145
|
discontinuities = filter(
|
|
134
146
|
lambda t: self.t_min <= t <= self.t_max,
|
|
135
147
|
self.discontinuities,
|
|
136
148
|
)
|
|
137
|
-
|
|
149
|
+
discontinuities_array = np.array(list(discontinuities))
|
|
138
150
|
boundary_times = np.array(
|
|
139
151
|
[
|
|
140
152
|
self.t_min,
|
|
141
153
|
self.t_max,
|
|
142
|
-
*(
|
|
143
|
-
*(
|
|
154
|
+
*(discontinuities_array - self.dt),
|
|
155
|
+
*(discontinuities_array + self.dt),
|
|
144
156
|
],
|
|
145
157
|
)
|
|
146
158
|
boundary_times.sort()
|
|
@@ -159,7 +171,7 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
159
171
|
x, y, z = self.function(t_range)
|
|
160
172
|
if not isinstance(z, np.ndarray):
|
|
161
173
|
z = np.zeros_like(x)
|
|
162
|
-
points = np.stack(
|
|
174
|
+
points = np.stack([x, y, z], axis=1)
|
|
163
175
|
else:
|
|
164
176
|
points = np.array([self.function(t) for t in t_range])
|
|
165
177
|
|
|
@@ -170,7 +182,8 @@ class ParametricFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
170
182
|
self.make_smooth()
|
|
171
183
|
return self
|
|
172
184
|
|
|
173
|
-
init_points
|
|
185
|
+
def init_points(self) -> None:
|
|
186
|
+
self.generate_points()
|
|
174
187
|
|
|
175
188
|
|
|
176
189
|
class FunctionGraph(ParametricFunction):
|
|
@@ -202,20 +215,27 @@ class FunctionGraph(ParametricFunction):
|
|
|
202
215
|
self.add(cos_func, sin_func_1, sin_func_2)
|
|
203
216
|
"""
|
|
204
217
|
|
|
205
|
-
def __init__(
|
|
206
|
-
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
function: Callable[[float], Any],
|
|
221
|
+
x_range: tuple[float, float] | tuple[float, float, float] | None = None,
|
|
222
|
+
color: ParsableManimColor = YELLOW,
|
|
223
|
+
**kwargs: Any,
|
|
224
|
+
) -> None:
|
|
207
225
|
if x_range is None:
|
|
208
|
-
x_range =
|
|
226
|
+
x_range = (-config["frame_x_radius"], config["frame_x_radius"])
|
|
209
227
|
|
|
210
228
|
self.x_range = x_range
|
|
211
|
-
self.parametric_function = lambda t: np.array(
|
|
212
|
-
|
|
229
|
+
self.parametric_function: Callable[[float], Point3D] = lambda t: np.array(
|
|
230
|
+
[t, function(t), 0]
|
|
231
|
+
)
|
|
232
|
+
self.function = function # type: ignore[assignment]
|
|
213
233
|
super().__init__(self.parametric_function, self.x_range, color=color, **kwargs)
|
|
214
234
|
|
|
215
|
-
def get_function(self):
|
|
235
|
+
def get_function(self) -> Callable[[float], Any]:
|
|
216
236
|
return self.function
|
|
217
237
|
|
|
218
|
-
def get_point_from_function(self, x):
|
|
238
|
+
def get_point_from_function(self, x: float) -> Point3D:
|
|
219
239
|
return self.parametric_function(x)
|
|
220
240
|
|
|
221
241
|
|
|
@@ -228,7 +248,7 @@ class ImplicitFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
228
248
|
min_depth: int = 5,
|
|
229
249
|
max_quads: int = 1500,
|
|
230
250
|
use_smoothing: bool = True,
|
|
231
|
-
**kwargs,
|
|
251
|
+
**kwargs: Any,
|
|
232
252
|
):
|
|
233
253
|
"""An implicit function.
|
|
234
254
|
|
|
@@ -287,7 +307,7 @@ class ImplicitFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
287
307
|
|
|
288
308
|
super().__init__(**kwargs)
|
|
289
309
|
|
|
290
|
-
def generate_points(self):
|
|
310
|
+
def generate_points(self) -> Self:
|
|
291
311
|
p_min, p_max = (
|
|
292
312
|
np.array([self.x_range[0], self.y_range[0]]),
|
|
293
313
|
np.array([self.x_range[1], self.y_range[1]]),
|
|
@@ -309,4 +329,5 @@ class ImplicitFunction(VMobject, metaclass=ConvertToOpenGL):
|
|
|
309
329
|
self.make_smooth()
|
|
310
330
|
return self
|
|
311
331
|
|
|
312
|
-
init_points
|
|
332
|
+
def init_points(self) -> None:
|
|
333
|
+
self.generate_points()
|
|
@@ -2,9 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from manim.mobject.mobject import Mobject
|
|
6
|
+
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
|
|
7
|
+
|
|
5
8
|
__all__ = ["NumberLine", "UnitInterval"]
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from typing_extensions import Self
|
|
18
|
+
|
|
19
|
+
from manim.mobject.geometry.tips import ArrowTip
|
|
20
|
+
from manim.typing import Point3D, Point3DLike, Vector3D
|
|
8
21
|
|
|
9
22
|
import numpy as np
|
|
10
23
|
|
|
@@ -12,8 +25,9 @@ from manim import config
|
|
|
12
25
|
from manim.constants import *
|
|
13
26
|
from manim.mobject.geometry.line import Line
|
|
14
27
|
from manim.mobject.graphing.scale import LinearBase, _ScaleBase
|
|
15
|
-
from manim.mobject.text.numbers import DecimalNumber
|
|
28
|
+
from manim.mobject.text.numbers import DecimalNumber, Integer
|
|
16
29
|
from manim.mobject.text.tex_mobject import MathTex, Tex
|
|
30
|
+
from manim.mobject.text.text_mobject import Text
|
|
17
31
|
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
18
32
|
from manim.utils.bezier import interpolate
|
|
19
33
|
from manim.utils.config_ops import merge_dicts_recursively
|
|
@@ -49,6 +63,10 @@ class NumberLine(Line):
|
|
|
49
63
|
The width of the tip.
|
|
50
64
|
tip_height
|
|
51
65
|
The height of the tip.
|
|
66
|
+
tip_shape
|
|
67
|
+
The mobject class used to construct the tip, or ``None`` (the
|
|
68
|
+
default) for the default arrow tip. Passed classes have to inherit
|
|
69
|
+
from :class:`.ArrowTip`.
|
|
52
70
|
include_numbers
|
|
53
71
|
Whether to add numbers to the tick marks. The number of decimal places is determined
|
|
54
72
|
by the step size, this default can be overridden by ``decimal_number_config``.
|
|
@@ -140,17 +158,18 @@ class NumberLine(Line):
|
|
|
140
158
|
include_tip: bool = False,
|
|
141
159
|
tip_width: float = DEFAULT_ARROW_TIP_LENGTH,
|
|
142
160
|
tip_height: float = DEFAULT_ARROW_TIP_LENGTH,
|
|
161
|
+
tip_shape: type[ArrowTip] | None = None,
|
|
143
162
|
# numbers/labels
|
|
144
163
|
include_numbers: bool = False,
|
|
145
164
|
font_size: float = 36,
|
|
146
|
-
label_direction:
|
|
147
|
-
label_constructor:
|
|
165
|
+
label_direction: Point3DLike = DOWN,
|
|
166
|
+
label_constructor: type[MathTex] = MathTex,
|
|
148
167
|
scaling: _ScaleBase = LinearBase(),
|
|
149
168
|
line_to_number_buff: float = MED_SMALL_BUFF,
|
|
150
169
|
decimal_number_config: dict | None = None,
|
|
151
170
|
numbers_to_exclude: Iterable[float] | None = None,
|
|
152
171
|
numbers_to_include: Iterable[float] | None = None,
|
|
153
|
-
**kwargs,
|
|
172
|
+
**kwargs: Any,
|
|
154
173
|
):
|
|
155
174
|
# avoid mutable arguments in defaults
|
|
156
175
|
if numbers_to_exclude is None:
|
|
@@ -173,8 +192,11 @@ class NumberLine(Line):
|
|
|
173
192
|
"num_decimal_places": self._decimal_places_from_step(x_range[2]),
|
|
174
193
|
}
|
|
175
194
|
|
|
176
|
-
# turn into
|
|
195
|
+
# turn into a NumPy array to scale by just applying the function
|
|
177
196
|
self.x_range = np.array(x_range, dtype=float)
|
|
197
|
+
self.x_min: float
|
|
198
|
+
self.x_max: float
|
|
199
|
+
self.x_step: float
|
|
178
200
|
self.x_min, self.x_max, self.x_step = scaling.function(self.x_range)
|
|
179
201
|
self.length = length
|
|
180
202
|
self.unit_size = unit_size
|
|
@@ -217,7 +239,11 @@ class NumberLine(Line):
|
|
|
217
239
|
self.center()
|
|
218
240
|
|
|
219
241
|
if self.include_tip:
|
|
220
|
-
self.add_tip(
|
|
242
|
+
self.add_tip(
|
|
243
|
+
tip_length=self.tip_height,
|
|
244
|
+
tip_width=self.tip_width,
|
|
245
|
+
tip_shape=tip_shape,
|
|
246
|
+
)
|
|
221
247
|
self.tip.set_stroke(self.stroke_color, self.stroke_width)
|
|
222
248
|
|
|
223
249
|
if self.include_ticks:
|
|
@@ -228,16 +254,16 @@ class NumberLine(Line):
|
|
|
228
254
|
if self.scaling.custom_labels:
|
|
229
255
|
tick_range = self.get_tick_range()
|
|
230
256
|
|
|
257
|
+
custom_labels = self.scaling.get_custom_labels(
|
|
258
|
+
tick_range,
|
|
259
|
+
unit_decimal_places=decimal_number_config["num_decimal_places"],
|
|
260
|
+
)
|
|
261
|
+
|
|
231
262
|
self.add_labels(
|
|
232
263
|
dict(
|
|
233
264
|
zip(
|
|
234
265
|
tick_range,
|
|
235
|
-
|
|
236
|
-
tick_range,
|
|
237
|
-
unit_decimal_places=decimal_number_config[
|
|
238
|
-
"num_decimal_places"
|
|
239
|
-
],
|
|
240
|
-
),
|
|
266
|
+
custom_labels,
|
|
241
267
|
)
|
|
242
268
|
),
|
|
243
269
|
)
|
|
@@ -249,22 +275,28 @@ class NumberLine(Line):
|
|
|
249
275
|
font_size=self.font_size,
|
|
250
276
|
)
|
|
251
277
|
|
|
252
|
-
def rotate_about_zero(
|
|
278
|
+
def rotate_about_zero(
|
|
279
|
+
self, angle: float, axis: Vector3D = OUT, **kwargs: Any
|
|
280
|
+
) -> Self:
|
|
253
281
|
return self.rotate_about_number(0, angle, axis, **kwargs)
|
|
254
282
|
|
|
255
283
|
def rotate_about_number(
|
|
256
|
-
self, number: float, angle: float, axis:
|
|
257
|
-
):
|
|
284
|
+
self, number: float, angle: float, axis: Vector3D = OUT, **kwargs: Any
|
|
285
|
+
) -> Self:
|
|
258
286
|
return self.rotate(angle, axis, about_point=self.n2p(number), **kwargs)
|
|
259
287
|
|
|
260
|
-
def add_ticks(self):
|
|
288
|
+
def add_ticks(self) -> None:
|
|
261
289
|
"""Adds ticks to the number line. Ticks can be accessed after creation
|
|
262
|
-
via ``self.ticks``.
|
|
290
|
+
via ``self.ticks``.
|
|
291
|
+
"""
|
|
263
292
|
ticks = VGroup()
|
|
264
293
|
elongated_tick_size = self.tick_size * self.longer_tick_multiple
|
|
294
|
+
elongated_tick_offsets = (
|
|
295
|
+
np.array(self.numbers_with_elongated_ticks) - self.x_min
|
|
296
|
+
)
|
|
265
297
|
for x in self.get_tick_range():
|
|
266
298
|
size = self.tick_size
|
|
267
|
-
if x
|
|
299
|
+
if np.any(np.isclose(x - self.x_min, elongated_tick_offsets)):
|
|
268
300
|
size = elongated_tick_size
|
|
269
301
|
ticks.add(self.get_tick(x, size))
|
|
270
302
|
self.add(ticks)
|
|
@@ -327,6 +359,7 @@ class NumberLine(Line):
|
|
|
327
359
|
def number_to_point(self, number: float | np.ndarray) -> np.ndarray:
|
|
328
360
|
"""Accepts a value along the number line and returns a point with
|
|
329
361
|
respect to the scene.
|
|
362
|
+
Equivalent to `NumberLine @ number`
|
|
330
363
|
|
|
331
364
|
Parameters
|
|
332
365
|
----------
|
|
@@ -347,7 +380,9 @@ class NumberLine(Line):
|
|
|
347
380
|
array([0., 0., 0.])
|
|
348
381
|
>>> number_line.number_to_point(1)
|
|
349
382
|
array([1., 0., 0.])
|
|
350
|
-
>>> number_line
|
|
383
|
+
>>> number_line @ 1
|
|
384
|
+
array([1., 0., 0.])
|
|
385
|
+
>>> number_line.number_to_point([1, 2, 3])
|
|
351
386
|
array([[1., 0., 0.],
|
|
352
387
|
[2., 0., 0.],
|
|
353
388
|
[3., 0., 0.]])
|
|
@@ -379,42 +414,45 @@ class NumberLine(Line):
|
|
|
379
414
|
|
|
380
415
|
>>> from manim import NumberLine
|
|
381
416
|
>>> number_line = NumberLine()
|
|
382
|
-
>>> number_line.point_to_number((0,0,0))
|
|
383
|
-
0.0
|
|
384
|
-
>>> number_line.point_to_number((1,0,0))
|
|
385
|
-
1.0
|
|
386
|
-
>>> number_line.point_to_number([[0.5,0,0],[1,0,0],[1.5,0,0]])
|
|
417
|
+
>>> number_line.point_to_number((0, 0, 0))
|
|
418
|
+
np.float64(0.0)
|
|
419
|
+
>>> number_line.point_to_number((1, 0, 0))
|
|
420
|
+
np.float64(1.0)
|
|
421
|
+
>>> number_line.point_to_number([[0.5, 0, 0], [1, 0, 0], [1.5, 0, 0]])
|
|
387
422
|
array([0.5, 1. , 1.5])
|
|
388
423
|
|
|
389
424
|
"""
|
|
390
425
|
point = np.asarray(point)
|
|
391
426
|
start, end = self.get_start_and_end()
|
|
392
427
|
unit_vect = normalize(end - start)
|
|
393
|
-
proportion = np.dot(point - start, unit_vect) / np.dot(
|
|
428
|
+
proportion: float = np.dot(point - start, unit_vect) / np.dot(
|
|
429
|
+
end - start, unit_vect
|
|
430
|
+
)
|
|
394
431
|
return interpolate(self.x_min, self.x_max, proportion)
|
|
395
432
|
|
|
396
|
-
def n2p(self, number: float | np.ndarray) ->
|
|
433
|
+
def n2p(self, number: float | np.ndarray) -> Point3D:
|
|
397
434
|
"""Abbreviation for :meth:`~.NumberLine.number_to_point`."""
|
|
398
435
|
return self.number_to_point(number)
|
|
399
436
|
|
|
400
|
-
def p2n(self, point:
|
|
437
|
+
def p2n(self, point: Point3DLike) -> float:
|
|
401
438
|
"""Abbreviation for :meth:`~.NumberLine.point_to_number`."""
|
|
402
439
|
return self.point_to_number(point)
|
|
403
440
|
|
|
404
441
|
def get_unit_size(self) -> float:
|
|
405
|
-
|
|
442
|
+
val: float = self.get_length() / (self.x_range[1] - self.x_range[0])
|
|
443
|
+
return val
|
|
406
444
|
|
|
407
|
-
def get_unit_vector(self) ->
|
|
445
|
+
def get_unit_vector(self) -> Vector3D:
|
|
408
446
|
return super().get_unit_vector() * self.unit_size
|
|
409
447
|
|
|
410
448
|
def get_number_mobject(
|
|
411
449
|
self,
|
|
412
450
|
x: float,
|
|
413
|
-
direction:
|
|
451
|
+
direction: Vector3D | None = None,
|
|
414
452
|
buff: float | None = None,
|
|
415
453
|
font_size: float | None = None,
|
|
416
|
-
label_constructor:
|
|
417
|
-
**number_config,
|
|
454
|
+
label_constructor: type[MathTex] | None = None,
|
|
455
|
+
**number_config: dict[str, Any],
|
|
418
456
|
) -> VMobject:
|
|
419
457
|
"""Generates a positioned :class:`~.DecimalNumber` mobject
|
|
420
458
|
generated according to ``label_constructor``.
|
|
@@ -439,7 +477,7 @@ class NumberLine(Line):
|
|
|
439
477
|
:class:`~.DecimalNumber`
|
|
440
478
|
The positioned mobject.
|
|
441
479
|
"""
|
|
442
|
-
|
|
480
|
+
number_config_merged = merge_dicts_recursively(
|
|
443
481
|
self.decimal_number_config,
|
|
444
482
|
number_config,
|
|
445
483
|
)
|
|
@@ -453,16 +491,19 @@ class NumberLine(Line):
|
|
|
453
491
|
label_constructor = self.label_constructor
|
|
454
492
|
|
|
455
493
|
num_mob = DecimalNumber(
|
|
456
|
-
x,
|
|
494
|
+
x,
|
|
495
|
+
font_size=font_size,
|
|
496
|
+
mob_class=label_constructor,
|
|
497
|
+
**number_config_merged,
|
|
457
498
|
)
|
|
458
499
|
|
|
459
500
|
num_mob.next_to(self.number_to_point(x), direction=direction, buff=buff)
|
|
460
501
|
if x < 0 and self.label_direction[0] == 0:
|
|
461
502
|
# Align without the minus sign
|
|
462
|
-
num_mob.shift(num_mob[0].
|
|
503
|
+
num_mob.shift(num_mob[0].width * LEFT / 2)
|
|
463
504
|
return num_mob
|
|
464
505
|
|
|
465
|
-
def get_number_mobjects(self, *numbers, **kwargs) -> VGroup:
|
|
506
|
+
def get_number_mobjects(self, *numbers: float, **kwargs: Any) -> VGroup:
|
|
466
507
|
if len(numbers) == 0:
|
|
467
508
|
numbers = self.default_numbers_to_display()
|
|
468
509
|
return VGroup([self.get_number_mobject(number, **kwargs) for number in numbers])
|
|
@@ -475,9 +516,9 @@ class NumberLine(Line):
|
|
|
475
516
|
x_values: Iterable[float] | None = None,
|
|
476
517
|
excluding: Iterable[float] | None = None,
|
|
477
518
|
font_size: float | None = None,
|
|
478
|
-
label_constructor:
|
|
479
|
-
**kwargs,
|
|
480
|
-
):
|
|
519
|
+
label_constructor: type[MathTex] | None = None,
|
|
520
|
+
**kwargs: Any,
|
|
521
|
+
) -> Self:
|
|
481
522
|
"""Adds :class:`~.DecimalNumber` mobjects representing their position
|
|
482
523
|
at each tick of the number line. The numbers can be accessed after creation
|
|
483
524
|
via ``self.numbers``.
|
|
@@ -528,11 +569,11 @@ class NumberLine(Line):
|
|
|
528
569
|
def add_labels(
|
|
529
570
|
self,
|
|
530
571
|
dict_values: dict[float, str | float | VMobject],
|
|
531
|
-
direction:
|
|
572
|
+
direction: Point3DLike | None = None,
|
|
532
573
|
buff: float | None = None,
|
|
533
574
|
font_size: float | None = None,
|
|
534
|
-
label_constructor:
|
|
535
|
-
):
|
|
575
|
+
label_constructor: type[MathTex] | None = None,
|
|
576
|
+
) -> Self:
|
|
536
577
|
"""Adds specifically positioned labels to the :class:`~.NumberLine` using a ``dict``.
|
|
537
578
|
The labels can be accessed after creation via ``self.labels``.
|
|
538
579
|
|
|
@@ -558,26 +599,24 @@ class NumberLine(Line):
|
|
|
558
599
|
AttributeError
|
|
559
600
|
If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised.
|
|
560
601
|
"""
|
|
561
|
-
|
|
562
602
|
direction = self.label_direction if direction is None else direction
|
|
563
603
|
buff = self.line_to_number_buff if buff is None else buff
|
|
564
604
|
font_size = self.font_size if font_size is None else font_size
|
|
565
|
-
label_constructor
|
|
566
|
-
|
|
567
|
-
)
|
|
605
|
+
if label_constructor is None:
|
|
606
|
+
label_constructor = self.label_constructor
|
|
568
607
|
|
|
569
608
|
labels = VGroup()
|
|
570
609
|
for x, label in dict_values.items():
|
|
571
|
-
|
|
572
610
|
# TODO: remove this check and ability to call
|
|
573
611
|
# this method via CoordinateSystem.add_coordinates()
|
|
574
612
|
# must be explicitly called
|
|
575
|
-
if isinstance(label, str) and
|
|
613
|
+
if isinstance(label, str) and label_constructor is MathTex:
|
|
576
614
|
label = Tex(label)
|
|
577
615
|
else:
|
|
578
|
-
label = self._create_label_tex(label)
|
|
616
|
+
label = self._create_label_tex(label, label_constructor)
|
|
579
617
|
|
|
580
618
|
if hasattr(label, "font_size"):
|
|
619
|
+
assert isinstance(label, (MathTex, Tex, Text, Integer)), label
|
|
581
620
|
label.font_size = font_size
|
|
582
621
|
else:
|
|
583
622
|
raise AttributeError(f"{label} is not compatible with add_labels.")
|
|
@@ -589,42 +628,61 @@ class NumberLine(Line):
|
|
|
589
628
|
return self
|
|
590
629
|
|
|
591
630
|
def _create_label_tex(
|
|
592
|
-
self,
|
|
631
|
+
self,
|
|
632
|
+
label_tex: str | float | VMobject,
|
|
633
|
+
label_constructor: Callable | None = None,
|
|
634
|
+
**kwargs: Any,
|
|
593
635
|
) -> VMobject:
|
|
594
636
|
"""Checks if the label is a :class:`~.VMobject`, otherwise, creates a
|
|
595
|
-
label
|
|
637
|
+
label by passing ``label_tex`` to ``label_constructor``.
|
|
596
638
|
|
|
597
639
|
Parameters
|
|
598
640
|
----------
|
|
599
641
|
label_tex
|
|
600
|
-
The label
|
|
642
|
+
The label for which a mobject should be created. If the label already
|
|
643
|
+
is a mobject, no new mobject is created.
|
|
644
|
+
label_constructor
|
|
645
|
+
Optional. A class or function returning a mobject when
|
|
646
|
+
passing ``label_tex`` as an argument. If ``None`` is passed
|
|
647
|
+
(the default), the label constructor from the :attr:`.label_constructor`
|
|
648
|
+
attribute is used.
|
|
601
649
|
|
|
602
650
|
Returns
|
|
603
651
|
-------
|
|
604
652
|
:class:`~.VMobject`
|
|
605
653
|
The label.
|
|
606
654
|
"""
|
|
607
|
-
|
|
608
|
-
if isinstance(label_tex, VMobject):
|
|
655
|
+
if isinstance(label_tex, (VMobject, OpenGLVMobject)):
|
|
609
656
|
return label_tex
|
|
610
|
-
|
|
611
|
-
|
|
657
|
+
if label_constructor is None:
|
|
658
|
+
label_constructor = self.label_constructor
|
|
659
|
+
if isinstance(label_tex, str):
|
|
660
|
+
return label_constructor(label_tex, **kwargs)
|
|
661
|
+
return label_constructor(str(label_tex), **kwargs)
|
|
612
662
|
|
|
613
663
|
@staticmethod
|
|
614
|
-
def _decimal_places_from_step(step) -> int:
|
|
615
|
-
|
|
616
|
-
if "." not in
|
|
664
|
+
def _decimal_places_from_step(step: float) -> int:
|
|
665
|
+
step_str = str(step)
|
|
666
|
+
if "." not in step_str:
|
|
617
667
|
return 0
|
|
618
|
-
return len(
|
|
668
|
+
return len(step_str.split(".")[-1])
|
|
669
|
+
|
|
670
|
+
def __matmul__(self, other: float) -> Point3D:
|
|
671
|
+
return self.n2p(other)
|
|
672
|
+
|
|
673
|
+
def __rmatmul__(self, other: Point3DLike | Mobject) -> float:
|
|
674
|
+
if isinstance(other, Mobject):
|
|
675
|
+
other = other.get_center()
|
|
676
|
+
return self.p2n(other)
|
|
619
677
|
|
|
620
678
|
|
|
621
679
|
class UnitInterval(NumberLine):
|
|
622
680
|
def __init__(
|
|
623
681
|
self,
|
|
624
|
-
unit_size=10,
|
|
625
|
-
numbers_with_elongated_ticks=None,
|
|
626
|
-
decimal_number_config=None,
|
|
627
|
-
**kwargs,
|
|
682
|
+
unit_size: float = 10,
|
|
683
|
+
numbers_with_elongated_ticks: list[float] | None = None,
|
|
684
|
+
decimal_number_config: dict[str, Any] | None = None,
|
|
685
|
+
**kwargs: Any,
|
|
628
686
|
):
|
|
629
687
|
numbers_with_elongated_ticks = (
|
|
630
688
|
[0, 1]
|