manim 0.17.3__py3-none-any.whl → 0.18.0.post0__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.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +1 -0
- manim/__main__.py +2 -0
- manim/_config/__init__.py +0 -1
- manim/_config/logger_utils.py +1 -0
- manim/_config/utils.py +14 -5
- manim/animation/changing.py +9 -5
- manim/animation/creation.py +8 -3
- manim/animation/indication.py +4 -4
- manim/animation/speedmodifier.py +2 -4
- manim/animation/updaters/mobject_update_utils.py +134 -16
- manim/camera/camera.py +31 -17
- manim/cli/checkhealth/__init__.py +0 -0
- manim/cli/checkhealth/checks.py +173 -0
- manim/cli/checkhealth/commands.py +81 -0
- manim/cli/render/global_options.py +6 -0
- manim/constants.py +58 -54
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +126 -91
- manim/mobject/geometry/boolean_ops.py +6 -10
- manim/mobject/geometry/labeled.py +155 -0
- manim/mobject/geometry/line.py +66 -50
- manim/mobject/geometry/polygram.py +23 -15
- manim/mobject/geometry/shape_matchers.py +24 -15
- manim/mobject/geometry/tips.py +62 -40
- manim/mobject/graph.py +3 -4
- manim/mobject/graphing/coordinate_systems.py +190 -139
- manim/mobject/graphing/number_line.py +5 -2
- manim/mobject/graphing/probability.py +4 -3
- manim/mobject/graphing/scale.py +7 -7
- manim/mobject/logo.py +108 -22
- manim/mobject/matrix.py +33 -37
- manim/mobject/mobject.py +327 -260
- manim/mobject/opengl/opengl_image_mobject.py +1 -1
- manim/mobject/opengl/opengl_mobject.py +18 -12
- manim/mobject/opengl/opengl_point_cloud_mobject.py +1 -1
- manim/mobject/opengl/opengl_surface.py +1 -1
- manim/mobject/opengl/opengl_vectorized_mobject.py +21 -17
- manim/mobject/svg/brace.py +3 -1
- manim/mobject/svg/svg_mobject.py +9 -11
- manim/mobject/table.py +50 -54
- manim/mobject/text/numbers.py +48 -6
- manim/mobject/text/tex_mobject.py +8 -12
- manim/mobject/text/text_mobject.py +32 -24
- manim/mobject/three_d/three_d_utils.py +13 -8
- manim/mobject/three_d/three_dimensions.py +61 -43
- manim/mobject/types/image_mobject.py +5 -4
- manim/mobject/types/point_cloud_mobject.py +8 -6
- manim/mobject/types/vectorized_mobject.py +385 -258
- manim/mobject/vector_field.py +19 -11
- manim/plugins/import_plugins.py +1 -1
- manim/plugins/plugins_flags.py +1 -6
- manim/renderer/shader.py +2 -2
- manim/scene/scene.py +15 -7
- manim/scene/scene_file_writer.py +1 -2
- manim/scene/three_d_scene.py +1 -1
- manim/scene/vector_space_scene.py +17 -7
- manim/typing.py +133 -0
- manim/utils/bezier.py +267 -83
- manim/utils/color/AS2700.py +234 -0
- manim/utils/color/BS381.py +315 -0
- manim/utils/color/X11.py +530 -0
- manim/utils/color/XKCD.py +949 -0
- manim/utils/color/__init__.py +58 -0
- manim/utils/color/core.py +1036 -0
- manim/utils/color/manim_colors.py +220 -0
- manim/utils/docbuild/autocolor_directive.py +92 -0
- manim/utils/docbuild/manim_directive.py +40 -6
- manim/utils/file_ops.py +1 -1
- manim/utils/hashing.py +1 -1
- manim/utils/iterables.py +1 -1
- manim/utils/rate_functions.py +33 -0
- manim/utils/simple_functions.py +0 -18
- manim/utils/space_ops.py +55 -42
- manim/utils/testing/frames_comparison.py +9 -0
- manim/utils/tex.py +2 -0
- manim/utils/tex_file_writing.py +29 -2
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/METADATA +14 -14
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/RECORD +82 -71
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/WHEEL +1 -1
- manim/communitycolors.py +0 -9
- manim/utils/color.py +0 -552
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE +0 -0
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE.community +0 -0
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/entry_points.txt +0 -0
manim/mobject/mobject.py
CHANGED
|
@@ -1,35 +1,25 @@
|
|
|
1
1
|
"""Base classes for objects that can be displayed."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
__all__ = ["Mobject", "Group", "override_animate"]
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
import copy
|
|
9
|
+
import inspect
|
|
8
10
|
import itertools as it
|
|
11
|
+
import math
|
|
9
12
|
import operator as op
|
|
10
13
|
import random
|
|
11
14
|
import sys
|
|
12
15
|
import types
|
|
13
16
|
import warnings
|
|
14
17
|
from functools import partialmethod, reduce
|
|
15
|
-
from math import ceil
|
|
16
18
|
from pathlib import Path
|
|
17
|
-
from typing import
|
|
18
|
-
TYPE_CHECKING,
|
|
19
|
-
Callable,
|
|
20
|
-
Dict,
|
|
21
|
-
Iterable,
|
|
22
|
-
List,
|
|
23
|
-
Optional,
|
|
24
|
-
Sequence,
|
|
25
|
-
Tuple,
|
|
26
|
-
Type,
|
|
27
|
-
TypeVar,
|
|
28
|
-
Union,
|
|
29
|
-
)
|
|
19
|
+
from typing import TYPE_CHECKING, Callable, Iterable, Literal, TypeVar, Union
|
|
30
20
|
|
|
31
21
|
import numpy as np
|
|
32
|
-
from
|
|
22
|
+
from typing_extensions import Self, TypeAlias
|
|
33
23
|
|
|
34
24
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
35
25
|
|
|
@@ -39,22 +29,37 @@ from ..utils.color import (
|
|
|
39
29
|
BLACK,
|
|
40
30
|
WHITE,
|
|
41
31
|
YELLOW_C,
|
|
42
|
-
|
|
32
|
+
ManimColor,
|
|
33
|
+
ParsableManimColor,
|
|
43
34
|
color_gradient,
|
|
44
35
|
interpolate_color,
|
|
45
36
|
)
|
|
46
37
|
from ..utils.exceptions import MultiAnimationOverrideException
|
|
47
38
|
from ..utils.iterables import list_update, remove_list_redundancies
|
|
48
39
|
from ..utils.paths import straight_path
|
|
49
|
-
from ..utils.simple_functions import get_parameters
|
|
50
40
|
from ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix
|
|
51
41
|
|
|
52
42
|
# TODO: Explain array_attrs
|
|
53
43
|
|
|
54
|
-
|
|
44
|
+
TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], None]
|
|
45
|
+
NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], None]
|
|
46
|
+
Updater: TypeAlias = Union[NonTimeBasedUpdater, TimeBasedUpdater]
|
|
55
47
|
T = TypeVar("T", bound="Mobject")
|
|
56
48
|
|
|
57
49
|
if TYPE_CHECKING:
|
|
50
|
+
from manim.typing import (
|
|
51
|
+
FunctionOverride,
|
|
52
|
+
Image,
|
|
53
|
+
ManimFloat,
|
|
54
|
+
ManimInt,
|
|
55
|
+
MappingFunction,
|
|
56
|
+
PathFuncType,
|
|
57
|
+
Point3D,
|
|
58
|
+
Point3D_Array,
|
|
59
|
+
Vector,
|
|
60
|
+
Vector3,
|
|
61
|
+
)
|
|
62
|
+
|
|
58
63
|
from ..animation.animation import Animation
|
|
59
64
|
|
|
60
65
|
|
|
@@ -81,26 +86,33 @@ class Mobject:
|
|
|
81
86
|
animation_overrides = {}
|
|
82
87
|
|
|
83
88
|
@classmethod
|
|
84
|
-
def __init_subclass__(cls, **kwargs):
|
|
89
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
85
90
|
super().__init_subclass__(**kwargs)
|
|
86
91
|
|
|
87
92
|
cls.animation_overrides: dict[
|
|
88
93
|
type[Animation],
|
|
89
|
-
|
|
94
|
+
FunctionOverride,
|
|
90
95
|
] = {}
|
|
91
96
|
cls._add_intrinsic_animation_overrides()
|
|
92
97
|
cls._original__init__ = cls.__init__
|
|
93
98
|
|
|
94
|
-
def __init__(
|
|
99
|
+
def __init__(
|
|
100
|
+
self,
|
|
101
|
+
color: ParsableManimColor | list[ParsableManimColor] = WHITE,
|
|
102
|
+
name: str | None = None,
|
|
103
|
+
dim: int = 3,
|
|
104
|
+
target=None,
|
|
105
|
+
z_index: float = 0,
|
|
106
|
+
) -> None:
|
|
95
107
|
self.name = self.__class__.__name__ if name is None else name
|
|
96
108
|
self.dim = dim
|
|
97
109
|
self.target = target
|
|
98
110
|
self.z_index = z_index
|
|
99
111
|
self.point_hash = None
|
|
100
112
|
self.submobjects = []
|
|
101
|
-
self.updaters = []
|
|
113
|
+
self.updaters: list[Updater] = []
|
|
102
114
|
self.updating_suspended = False
|
|
103
|
-
self.color =
|
|
115
|
+
self.color = ManimColor.parse(color)
|
|
104
116
|
|
|
105
117
|
self.reset_points()
|
|
106
118
|
self.generate_points()
|
|
@@ -110,7 +122,7 @@ class Mobject:
|
|
|
110
122
|
def animation_override_for(
|
|
111
123
|
cls,
|
|
112
124
|
animation_class: type[Animation],
|
|
113
|
-
) ->
|
|
125
|
+
) -> FunctionOverride | None:
|
|
114
126
|
"""Returns the function defining a specific animation override for this class.
|
|
115
127
|
|
|
116
128
|
Parameters
|
|
@@ -130,7 +142,7 @@ class Mobject:
|
|
|
130
142
|
return None
|
|
131
143
|
|
|
132
144
|
@classmethod
|
|
133
|
-
def _add_intrinsic_animation_overrides(cls):
|
|
145
|
+
def _add_intrinsic_animation_overrides(cls) -> None:
|
|
134
146
|
"""Initializes animation overrides marked with the :func:`~.override_animation`
|
|
135
147
|
decorator.
|
|
136
148
|
"""
|
|
@@ -148,8 +160,8 @@ class Mobject:
|
|
|
148
160
|
def add_animation_override(
|
|
149
161
|
cls,
|
|
150
162
|
animation_class: type[Animation],
|
|
151
|
-
override_func:
|
|
152
|
-
):
|
|
163
|
+
override_func: FunctionOverride,
|
|
164
|
+
) -> None:
|
|
153
165
|
"""Add an animation override.
|
|
154
166
|
|
|
155
167
|
This does not apply to subclasses.
|
|
@@ -160,7 +172,7 @@ class Mobject:
|
|
|
160
172
|
The animation type to be overridden
|
|
161
173
|
override_func
|
|
162
174
|
The function returning an animation replacing the default animation. It gets
|
|
163
|
-
passed the parameters given to the
|
|
175
|
+
passed the parameters given to the animation constructor.
|
|
164
176
|
|
|
165
177
|
Raises
|
|
166
178
|
------
|
|
@@ -178,7 +190,7 @@ class Mobject:
|
|
|
178
190
|
)
|
|
179
191
|
|
|
180
192
|
@classmethod
|
|
181
|
-
def set_default(cls, **kwargs):
|
|
193
|
+
def set_default(cls, **kwargs) -> None:
|
|
182
194
|
"""Sets the default values of keyword arguments.
|
|
183
195
|
|
|
184
196
|
If this method is called without any additional keyword
|
|
@@ -201,10 +213,10 @@ class Mobject:
|
|
|
201
213
|
>>> from manim import Square, GREEN
|
|
202
214
|
>>> Square.set_default(color=GREEN, fill_opacity=0.25)
|
|
203
215
|
>>> s = Square(); s.color, s.fill_opacity
|
|
204
|
-
(
|
|
216
|
+
(ManimColor('#83C167'), 0.25)
|
|
205
217
|
>>> Square.set_default()
|
|
206
218
|
>>> s = Square(); s.color, s.fill_opacity
|
|
207
|
-
(
|
|
219
|
+
(ManimColor('#FFFFFF'), 0.0)
|
|
208
220
|
|
|
209
221
|
.. manim:: ChangedDefaultTextcolor
|
|
210
222
|
:save_last_frame:
|
|
@@ -323,7 +335,7 @@ class Mobject:
|
|
|
323
335
|
"""
|
|
324
336
|
return _AnimationBuilder(self)
|
|
325
337
|
|
|
326
|
-
def __deepcopy__(self, clone_from_id):
|
|
338
|
+
def __deepcopy__(self, clone_from_id) -> Self:
|
|
327
339
|
cls = self.__class__
|
|
328
340
|
result = cls.__new__(cls)
|
|
329
341
|
clone_from_id[id(self)] = result
|
|
@@ -332,30 +344,28 @@ class Mobject:
|
|
|
332
344
|
result.original_id = str(id(self))
|
|
333
345
|
return result
|
|
334
346
|
|
|
335
|
-
def __repr__(self):
|
|
347
|
+
def __repr__(self) -> str:
|
|
336
348
|
return str(self.name)
|
|
337
349
|
|
|
338
|
-
def reset_points(self):
|
|
350
|
+
def reset_points(self) -> None:
|
|
339
351
|
"""Sets :attr:`points` to be an empty array."""
|
|
340
352
|
self.points = np.zeros((0, self.dim))
|
|
341
353
|
|
|
342
|
-
def init_colors(self):
|
|
354
|
+
def init_colors(self) -> None:
|
|
343
355
|
"""Initializes the colors.
|
|
344
356
|
|
|
345
357
|
Gets called upon creation. This is an empty method that can be implemented by
|
|
346
358
|
subclasses.
|
|
347
359
|
"""
|
|
348
|
-
pass
|
|
349
360
|
|
|
350
|
-
def generate_points(self):
|
|
361
|
+
def generate_points(self) -> None:
|
|
351
362
|
"""Initializes :attr:`points` and therefore the shape.
|
|
352
363
|
|
|
353
364
|
Gets called upon creation. This is an empty method that can be implemented by
|
|
354
365
|
subclasses.
|
|
355
366
|
"""
|
|
356
|
-
pass
|
|
357
367
|
|
|
358
|
-
def add(self, *mobjects: Mobject):
|
|
368
|
+
def add(self, *mobjects: Mobject) -> Self:
|
|
359
369
|
"""Add mobjects as submobjects.
|
|
360
370
|
|
|
361
371
|
The mobjects are added to :attr:`submobjects`.
|
|
@@ -441,7 +451,7 @@ class Mobject:
|
|
|
441
451
|
self.submobjects = list_update(self.submobjects, unique_mobjects)
|
|
442
452
|
return self
|
|
443
453
|
|
|
444
|
-
def insert(self, index: int, mobject: Mobject):
|
|
454
|
+
def insert(self, index: int, mobject: Mobject) -> None:
|
|
445
455
|
"""Inserts a mobject at a specific position into self.submobjects
|
|
446
456
|
|
|
447
457
|
Effectively just calls ``self.submobjects.insert(index, mobject)``,
|
|
@@ -462,13 +472,13 @@ class Mobject:
|
|
|
462
472
|
raise ValueError("Mobject cannot contain self")
|
|
463
473
|
self.submobjects.insert(index, mobject)
|
|
464
474
|
|
|
465
|
-
def __add__(self, mobject):
|
|
475
|
+
def __add__(self, mobject: Mobject):
|
|
466
476
|
raise NotImplementedError
|
|
467
477
|
|
|
468
|
-
def __iadd__(self, mobject):
|
|
478
|
+
def __iadd__(self, mobject: Mobject):
|
|
469
479
|
raise NotImplementedError
|
|
470
480
|
|
|
471
|
-
def add_to_back(self, *mobjects: Mobject):
|
|
481
|
+
def add_to_back(self, *mobjects: Mobject) -> Self:
|
|
472
482
|
"""Add all passed mobjects to the back of the submobjects.
|
|
473
483
|
|
|
474
484
|
If :attr:`submobjects` already contains the given mobjects, they just get moved
|
|
@@ -524,7 +534,7 @@ class Mobject:
|
|
|
524
534
|
self.submobjects = list(dict.fromkeys(mobjects)) + self.submobjects
|
|
525
535
|
return self
|
|
526
536
|
|
|
527
|
-
def remove(self, *mobjects: Mobject):
|
|
537
|
+
def remove(self, *mobjects: Mobject) -> Self:
|
|
528
538
|
"""Remove :attr:`submobjects`.
|
|
529
539
|
|
|
530
540
|
The mobjects are removed from :attr:`submobjects`, if they exist.
|
|
@@ -557,7 +567,7 @@ class Mobject:
|
|
|
557
567
|
def __isub__(self, other):
|
|
558
568
|
raise NotImplementedError
|
|
559
569
|
|
|
560
|
-
def set(self, **kwargs):
|
|
570
|
+
def set(self, **kwargs) -> Self:
|
|
561
571
|
"""Sets attributes.
|
|
562
572
|
|
|
563
573
|
I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``.
|
|
@@ -614,7 +624,7 @@ class Mobject:
|
|
|
614
624
|
|
|
615
625
|
return self
|
|
616
626
|
|
|
617
|
-
def __getattr__(self, attr):
|
|
627
|
+
def __getattr__(self, attr: str) -> types.MethodType:
|
|
618
628
|
# Add automatic compatibility layer
|
|
619
629
|
# between properties and get_* and set_*
|
|
620
630
|
# methods.
|
|
@@ -662,7 +672,7 @@ class Mobject:
|
|
|
662
672
|
raise AttributeError(f"{type(self).__name__} object has no attribute '{attr}'")
|
|
663
673
|
|
|
664
674
|
@property
|
|
665
|
-
def width(self):
|
|
675
|
+
def width(self) -> float:
|
|
666
676
|
"""The width of the mobject.
|
|
667
677
|
|
|
668
678
|
Returns
|
|
@@ -695,11 +705,11 @@ class Mobject:
|
|
|
695
705
|
return self.length_over_dim(0)
|
|
696
706
|
|
|
697
707
|
@width.setter
|
|
698
|
-
def width(self, value):
|
|
708
|
+
def width(self, value: float):
|
|
699
709
|
self.scale_to_fit_width(value)
|
|
700
710
|
|
|
701
711
|
@property
|
|
702
|
-
def height(self):
|
|
712
|
+
def height(self) -> float:
|
|
703
713
|
"""The height of the mobject.
|
|
704
714
|
|
|
705
715
|
Returns
|
|
@@ -732,11 +742,11 @@ class Mobject:
|
|
|
732
742
|
return self.length_over_dim(1)
|
|
733
743
|
|
|
734
744
|
@height.setter
|
|
735
|
-
def height(self, value):
|
|
745
|
+
def height(self, value: float):
|
|
736
746
|
self.scale_to_fit_height(value)
|
|
737
747
|
|
|
738
748
|
@property
|
|
739
|
-
def depth(self):
|
|
749
|
+
def depth(self) -> float:
|
|
740
750
|
"""The depth of the mobject.
|
|
741
751
|
|
|
742
752
|
Returns
|
|
@@ -753,20 +763,21 @@ class Mobject:
|
|
|
753
763
|
return self.length_over_dim(2)
|
|
754
764
|
|
|
755
765
|
@depth.setter
|
|
756
|
-
def depth(self, value):
|
|
766
|
+
def depth(self, value: float):
|
|
757
767
|
self.scale_to_fit_depth(value)
|
|
758
768
|
|
|
759
|
-
|
|
769
|
+
# Can't be staticmethod because of point_cloud_mobject.py
|
|
770
|
+
def get_array_attrs(self) -> list[Literal["points"]]:
|
|
760
771
|
return ["points"]
|
|
761
772
|
|
|
762
|
-
def apply_over_attr_arrays(self, func):
|
|
773
|
+
def apply_over_attr_arrays(self, func: MappingFunction) -> Self:
|
|
763
774
|
for attr in self.get_array_attrs():
|
|
764
775
|
setattr(self, attr, func(getattr(self, attr)))
|
|
765
776
|
return self
|
|
766
777
|
|
|
767
778
|
# Displaying
|
|
768
779
|
|
|
769
|
-
def get_image(self, camera=None):
|
|
780
|
+
def get_image(self, camera=None) -> Image:
|
|
770
781
|
if camera is None:
|
|
771
782
|
from ..camera.camera import Camera
|
|
772
783
|
|
|
@@ -774,17 +785,17 @@ class Mobject:
|
|
|
774
785
|
camera.capture_mobject(self)
|
|
775
786
|
return camera.get_image()
|
|
776
787
|
|
|
777
|
-
def show(self, camera=None):
|
|
788
|
+
def show(self, camera=None) -> None:
|
|
778
789
|
self.get_image(camera=camera).show()
|
|
779
790
|
|
|
780
|
-
def save_image(self, name=None):
|
|
791
|
+
def save_image(self, name: str | None = None) -> None:
|
|
781
792
|
"""Saves an image of only this :class:`Mobject` at its position to a png
|
|
782
793
|
file."""
|
|
783
794
|
self.get_image().save(
|
|
784
795
|
Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"),
|
|
785
796
|
)
|
|
786
797
|
|
|
787
|
-
def copy(self
|
|
798
|
+
def copy(self) -> Self:
|
|
788
799
|
"""Create and return an identical copy of the :class:`Mobject` including all
|
|
789
800
|
:attr:`submobjects`.
|
|
790
801
|
|
|
@@ -799,7 +810,7 @@ class Mobject:
|
|
|
799
810
|
"""
|
|
800
811
|
return copy.deepcopy(self)
|
|
801
812
|
|
|
802
|
-
def generate_target(self, use_deepcopy=False):
|
|
813
|
+
def generate_target(self, use_deepcopy: bool = False) -> Self:
|
|
803
814
|
self.target = None # Prevent unbounded linear recursion
|
|
804
815
|
if use_deepcopy:
|
|
805
816
|
self.target = copy.deepcopy(self)
|
|
@@ -809,7 +820,7 @@ class Mobject:
|
|
|
809
820
|
|
|
810
821
|
# Updating
|
|
811
822
|
|
|
812
|
-
def update(self, dt: float = 0, recursive: bool = True):
|
|
823
|
+
def update(self, dt: float = 0, recursive: bool = True) -> Self:
|
|
813
824
|
"""Apply all updaters.
|
|
814
825
|
|
|
815
826
|
Does nothing if updating is suspended.
|
|
@@ -836,8 +847,7 @@ class Mobject:
|
|
|
836
847
|
if self.updating_suspended:
|
|
837
848
|
return self
|
|
838
849
|
for updater in self.updaters:
|
|
839
|
-
|
|
840
|
-
if "dt" in parameters:
|
|
850
|
+
if "dt" in inspect.signature(updater).parameters:
|
|
841
851
|
updater(self, dt)
|
|
842
852
|
else:
|
|
843
853
|
updater(self)
|
|
@@ -846,7 +856,7 @@ class Mobject:
|
|
|
846
856
|
submob.update(dt, recursive)
|
|
847
857
|
return self
|
|
848
858
|
|
|
849
|
-
def get_time_based_updaters(self) -> list[
|
|
859
|
+
def get_time_based_updaters(self) -> list[TimeBasedUpdater]:
|
|
850
860
|
"""Return all updaters using the ``dt`` parameter.
|
|
851
861
|
|
|
852
862
|
The updaters use this parameter as the input for difference in time.
|
|
@@ -862,7 +872,11 @@ class Mobject:
|
|
|
862
872
|
:meth:`has_time_based_updater`
|
|
863
873
|
|
|
864
874
|
"""
|
|
865
|
-
return [
|
|
875
|
+
return [
|
|
876
|
+
updater
|
|
877
|
+
for updater in self.updaters
|
|
878
|
+
if "dt" in inspect.signature(updater).parameters
|
|
879
|
+
]
|
|
866
880
|
|
|
867
881
|
def has_time_based_updater(self) -> bool:
|
|
868
882
|
"""Test if ``self`` has a time based updater.
|
|
@@ -878,7 +892,9 @@ class Mobject:
|
|
|
878
892
|
:meth:`get_time_based_updaters`
|
|
879
893
|
|
|
880
894
|
"""
|
|
881
|
-
return any(
|
|
895
|
+
return any(
|
|
896
|
+
"dt" in inspect.signature(updater).parameters for updater in self.updaters
|
|
897
|
+
)
|
|
882
898
|
|
|
883
899
|
def get_updaters(self) -> list[Updater]:
|
|
884
900
|
"""Return all updaters.
|
|
@@ -896,7 +912,7 @@ class Mobject:
|
|
|
896
912
|
"""
|
|
897
913
|
return self.updaters
|
|
898
914
|
|
|
899
|
-
def get_family_updaters(self):
|
|
915
|
+
def get_family_updaters(self) -> list[Updater]:
|
|
900
916
|
return list(it.chain(*(sm.get_updaters() for sm in self.get_family())))
|
|
901
917
|
|
|
902
918
|
def add_updater(
|
|
@@ -904,7 +920,7 @@ class Mobject:
|
|
|
904
920
|
update_function: Updater,
|
|
905
921
|
index: int | None = None,
|
|
906
922
|
call_updater: bool = False,
|
|
907
|
-
):
|
|
923
|
+
) -> Self:
|
|
908
924
|
"""Add an update function to this mobject.
|
|
909
925
|
|
|
910
926
|
Update functions, or updaters in short, are functions that are applied to the
|
|
@@ -971,14 +987,14 @@ class Mobject:
|
|
|
971
987
|
else:
|
|
972
988
|
self.updaters.insert(index, update_function)
|
|
973
989
|
if call_updater:
|
|
974
|
-
parameters =
|
|
990
|
+
parameters = inspect.signature(update_function).parameters
|
|
975
991
|
if "dt" in parameters:
|
|
976
992
|
update_function(self, 0)
|
|
977
993
|
else:
|
|
978
994
|
update_function(self)
|
|
979
995
|
return self
|
|
980
996
|
|
|
981
|
-
def remove_updater(self, update_function: Updater):
|
|
997
|
+
def remove_updater(self, update_function: Updater) -> Self:
|
|
982
998
|
"""Remove an updater.
|
|
983
999
|
|
|
984
1000
|
If the same updater is applied multiple times, every instance gets removed.
|
|
@@ -1005,7 +1021,7 @@ class Mobject:
|
|
|
1005
1021
|
self.updaters.remove(update_function)
|
|
1006
1022
|
return self
|
|
1007
1023
|
|
|
1008
|
-
def clear_updaters(self, recursive: bool = True):
|
|
1024
|
+
def clear_updaters(self, recursive: bool = True) -> Self:
|
|
1009
1025
|
"""Remove every updater.
|
|
1010
1026
|
|
|
1011
1027
|
Parameters
|
|
@@ -1031,7 +1047,7 @@ class Mobject:
|
|
|
1031
1047
|
submob.clear_updaters()
|
|
1032
1048
|
return self
|
|
1033
1049
|
|
|
1034
|
-
def match_updaters(self, mobject: Mobject):
|
|
1050
|
+
def match_updaters(self, mobject: Mobject) -> Self:
|
|
1035
1051
|
"""Match the updaters of the given mobject.
|
|
1036
1052
|
|
|
1037
1053
|
Parameters
|
|
@@ -1061,7 +1077,7 @@ class Mobject:
|
|
|
1061
1077
|
self.add_updater(updater)
|
|
1062
1078
|
return self
|
|
1063
1079
|
|
|
1064
|
-
def suspend_updating(self, recursive: bool = True):
|
|
1080
|
+
def suspend_updating(self, recursive: bool = True) -> Self:
|
|
1065
1081
|
"""Disable updating from updaters and animations.
|
|
1066
1082
|
|
|
1067
1083
|
|
|
@@ -1088,7 +1104,7 @@ class Mobject:
|
|
|
1088
1104
|
submob.suspend_updating(recursive)
|
|
1089
1105
|
return self
|
|
1090
1106
|
|
|
1091
|
-
def resume_updating(self, recursive: bool = True):
|
|
1107
|
+
def resume_updating(self, recursive: bool = True) -> Self:
|
|
1092
1108
|
"""Enable updating from updaters and animations.
|
|
1093
1109
|
|
|
1094
1110
|
Parameters
|
|
@@ -1116,7 +1132,7 @@ class Mobject:
|
|
|
1116
1132
|
|
|
1117
1133
|
# Transforming operations
|
|
1118
1134
|
|
|
1119
|
-
def apply_to_family(self, func: Callable[[Mobject], None]):
|
|
1135
|
+
def apply_to_family(self, func: Callable[[Mobject], None]) -> None:
|
|
1120
1136
|
"""Apply a function to ``self`` and every submobject with points recursively.
|
|
1121
1137
|
|
|
1122
1138
|
Parameters
|
|
@@ -1138,7 +1154,7 @@ class Mobject:
|
|
|
1138
1154
|
for mob in self.family_members_with_points():
|
|
1139
1155
|
func(mob)
|
|
1140
1156
|
|
|
1141
|
-
def shift(self, *vectors:
|
|
1157
|
+
def shift(self, *vectors: Vector3) -> Self:
|
|
1142
1158
|
"""Shift by the given vectors.
|
|
1143
1159
|
|
|
1144
1160
|
Parameters
|
|
@@ -1164,7 +1180,7 @@ class Mobject:
|
|
|
1164
1180
|
|
|
1165
1181
|
return self
|
|
1166
1182
|
|
|
1167
|
-
def scale(self, scale_factor: float, **kwargs):
|
|
1183
|
+
def scale(self, scale_factor: float, **kwargs) -> Self:
|
|
1168
1184
|
r"""Scale the size by a factor.
|
|
1169
1185
|
|
|
1170
1186
|
Default behavior is to scale about the center of the mobject.
|
|
@@ -1210,17 +1226,17 @@ class Mobject:
|
|
|
1210
1226
|
)
|
|
1211
1227
|
return self
|
|
1212
1228
|
|
|
1213
|
-
def rotate_about_origin(self, angle, axis=OUT, axes=[]):
|
|
1229
|
+
def rotate_about_origin(self, angle: float, axis: Vector3 = OUT, axes=[]) -> Self:
|
|
1214
1230
|
"""Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]."""
|
|
1215
1231
|
return self.rotate(angle, axis, about_point=ORIGIN)
|
|
1216
1232
|
|
|
1217
1233
|
def rotate(
|
|
1218
1234
|
self,
|
|
1219
|
-
angle,
|
|
1220
|
-
axis=OUT,
|
|
1221
|
-
about_point:
|
|
1235
|
+
angle: float,
|
|
1236
|
+
axis: Vector3 = OUT,
|
|
1237
|
+
about_point: Point3D | None = None,
|
|
1222
1238
|
**kwargs,
|
|
1223
|
-
):
|
|
1239
|
+
) -> Self:
|
|
1224
1240
|
"""Rotates the :class:`~.Mobject` about a certain point."""
|
|
1225
1241
|
rot_matrix = rotation_matrix(angle, axis)
|
|
1226
1242
|
self.apply_points_function_about_point(
|
|
@@ -1228,7 +1244,7 @@ class Mobject:
|
|
|
1228
1244
|
)
|
|
1229
1245
|
return self
|
|
1230
1246
|
|
|
1231
|
-
def flip(self, axis=UP, **kwargs):
|
|
1247
|
+
def flip(self, axis: Vector3 = UP, **kwargs) -> Self:
|
|
1232
1248
|
"""Flips/Mirrors an mobject about its center.
|
|
1233
1249
|
|
|
1234
1250
|
Examples
|
|
@@ -1247,7 +1263,7 @@ class Mobject:
|
|
|
1247
1263
|
"""
|
|
1248
1264
|
return self.rotate(TAU / 2, axis, **kwargs)
|
|
1249
1265
|
|
|
1250
|
-
def stretch(self, factor, dim, **kwargs):
|
|
1266
|
+
def stretch(self, factor: float, dim: int, **kwargs) -> Self:
|
|
1251
1267
|
def func(points):
|
|
1252
1268
|
points[:, dim] *= factor
|
|
1253
1269
|
return points
|
|
@@ -1255,7 +1271,7 @@ class Mobject:
|
|
|
1255
1271
|
self.apply_points_function_about_point(func, **kwargs)
|
|
1256
1272
|
return self
|
|
1257
1273
|
|
|
1258
|
-
def apply_function(self, function, **kwargs):
|
|
1274
|
+
def apply_function(self, function: MappingFunction, **kwargs) -> Self:
|
|
1259
1275
|
# Default to applying matrix about the origin, not mobjects center
|
|
1260
1276
|
if len(kwargs) == 0:
|
|
1261
1277
|
kwargs["about_point"] = ORIGIN
|
|
@@ -1264,16 +1280,16 @@ class Mobject:
|
|
|
1264
1280
|
)
|
|
1265
1281
|
return self
|
|
1266
1282
|
|
|
1267
|
-
def apply_function_to_position(self, function):
|
|
1283
|
+
def apply_function_to_position(self, function: MappingFunction) -> Self:
|
|
1268
1284
|
self.move_to(function(self.get_center()))
|
|
1269
1285
|
return self
|
|
1270
1286
|
|
|
1271
|
-
def apply_function_to_submobject_positions(self, function):
|
|
1287
|
+
def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self:
|
|
1272
1288
|
for submob in self.submobjects:
|
|
1273
1289
|
submob.apply_function_to_position(function)
|
|
1274
1290
|
return self
|
|
1275
1291
|
|
|
1276
|
-
def apply_matrix(self, matrix, **kwargs):
|
|
1292
|
+
def apply_matrix(self, matrix, **kwargs) -> Self:
|
|
1277
1293
|
# Default to applying matrix about the origin, not mobjects center
|
|
1278
1294
|
if ("about_point" not in kwargs) and ("about_edge" not in kwargs):
|
|
1279
1295
|
kwargs["about_point"] = ORIGIN
|
|
@@ -1285,9 +1301,11 @@ class Mobject:
|
|
|
1285
1301
|
)
|
|
1286
1302
|
return self
|
|
1287
1303
|
|
|
1288
|
-
def apply_complex_function(
|
|
1304
|
+
def apply_complex_function(
|
|
1305
|
+
self, function: Callable[[complex], complex], **kwargs
|
|
1306
|
+
) -> Self:
|
|
1289
1307
|
"""Applies a complex function to a :class:`Mobject`.
|
|
1290
|
-
The x and y
|
|
1308
|
+
The x and y Point3Ds correspond to the real and imaginary parts respectively.
|
|
1291
1309
|
|
|
1292
1310
|
Example
|
|
1293
1311
|
-------
|
|
@@ -1319,7 +1337,9 @@ class Mobject:
|
|
|
1319
1337
|
|
|
1320
1338
|
return self.apply_function(R3_func)
|
|
1321
1339
|
|
|
1322
|
-
def wag(
|
|
1340
|
+
def wag(
|
|
1341
|
+
self, direction: Vector3 = RIGHT, axis: Vector3 = DOWN, wag_factor: float = 1.0
|
|
1342
|
+
) -> Self:
|
|
1323
1343
|
for mob in self.family_members_with_points():
|
|
1324
1344
|
alphas = np.dot(mob.points, np.transpose(axis))
|
|
1325
1345
|
alphas -= min(alphas)
|
|
@@ -1331,12 +1351,12 @@ class Mobject:
|
|
|
1331
1351
|
)
|
|
1332
1352
|
return self
|
|
1333
1353
|
|
|
1334
|
-
def reverse_points(self):
|
|
1354
|
+
def reverse_points(self) -> Self:
|
|
1335
1355
|
for mob in self.family_members_with_points():
|
|
1336
1356
|
mob.apply_over_attr_arrays(lambda arr: np.array(list(reversed(arr))))
|
|
1337
1357
|
return self
|
|
1338
1358
|
|
|
1339
|
-
def repeat(self, count: int):
|
|
1359
|
+
def repeat(self, count: int) -> Self:
|
|
1340
1360
|
"""This can make transition animations nicer"""
|
|
1341
1361
|
|
|
1342
1362
|
def repeat_array(array):
|
|
@@ -1352,10 +1372,10 @@ class Mobject:
|
|
|
1352
1372
|
|
|
1353
1373
|
def apply_points_function_about_point(
|
|
1354
1374
|
self,
|
|
1355
|
-
func,
|
|
1356
|
-
about_point=None,
|
|
1375
|
+
func: MappingFunction,
|
|
1376
|
+
about_point: Point3D = None,
|
|
1357
1377
|
about_edge=None,
|
|
1358
|
-
):
|
|
1378
|
+
) -> Self:
|
|
1359
1379
|
if about_point is None:
|
|
1360
1380
|
if about_edge is None:
|
|
1361
1381
|
about_edge = ORIGIN
|
|
@@ -1372,11 +1392,20 @@ class Mobject:
|
|
|
1372
1392
|
|
|
1373
1393
|
# Positioning methods
|
|
1374
1394
|
|
|
1375
|
-
def center(self):
|
|
1395
|
+
def center(self) -> Self:
|
|
1396
|
+
"""Moves the center of the mobject to the center of the scene.
|
|
1397
|
+
|
|
1398
|
+
Returns
|
|
1399
|
+
-------
|
|
1400
|
+
:class:`.Mobject`
|
|
1401
|
+
The centered mobject.
|
|
1402
|
+
"""
|
|
1376
1403
|
self.shift(-self.get_center())
|
|
1377
1404
|
return self
|
|
1378
1405
|
|
|
1379
|
-
def align_on_border(
|
|
1406
|
+
def align_on_border(
|
|
1407
|
+
self, direction: Vector3, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1408
|
+
) -> Self:
|
|
1380
1409
|
"""Direction just needs to be a vector pointing towards side or
|
|
1381
1410
|
corner in the 2d plane.
|
|
1382
1411
|
"""
|
|
@@ -1391,23 +1420,27 @@ class Mobject:
|
|
|
1391
1420
|
self.shift(shift_val)
|
|
1392
1421
|
return self
|
|
1393
1422
|
|
|
1394
|
-
def to_corner(
|
|
1423
|
+
def to_corner(
|
|
1424
|
+
self, corner: Vector3 = DL, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1425
|
+
) -> Self:
|
|
1395
1426
|
return self.align_on_border(corner, buff)
|
|
1396
1427
|
|
|
1397
|
-
def to_edge(
|
|
1428
|
+
def to_edge(
|
|
1429
|
+
self, edge: Vector3 = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1430
|
+
) -> Self:
|
|
1398
1431
|
return self.align_on_border(edge, buff)
|
|
1399
1432
|
|
|
1400
1433
|
def next_to(
|
|
1401
1434
|
self,
|
|
1402
|
-
mobject_or_point,
|
|
1403
|
-
direction=RIGHT,
|
|
1404
|
-
buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
1405
|
-
aligned_edge=ORIGIN,
|
|
1406
|
-
submobject_to_align=None,
|
|
1407
|
-
index_of_submobject_to_align=None,
|
|
1408
|
-
coor_mask=np.array([1, 1, 1]),
|
|
1409
|
-
):
|
|
1410
|
-
"""Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or
|
|
1435
|
+
mobject_or_point: Mobject | Point3D,
|
|
1436
|
+
direction: Vector3 = RIGHT,
|
|
1437
|
+
buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
1438
|
+
aligned_edge: Vector3 = ORIGIN,
|
|
1439
|
+
submobject_to_align: Mobject | None = None,
|
|
1440
|
+
index_of_submobject_to_align: int | None = None,
|
|
1441
|
+
coor_mask: Vector3 = np.array([1, 1, 1]),
|
|
1442
|
+
) -> Self:
|
|
1443
|
+
"""Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or Point3D.
|
|
1411
1444
|
|
|
1412
1445
|
Examples
|
|
1413
1446
|
--------
|
|
@@ -1446,7 +1479,7 @@ class Mobject:
|
|
|
1446
1479
|
self.shift((target_point - point_to_align + buff * direction) * coor_mask)
|
|
1447
1480
|
return self
|
|
1448
1481
|
|
|
1449
|
-
def shift_onto_screen(self, **kwargs):
|
|
1482
|
+
def shift_onto_screen(self, **kwargs) -> Self:
|
|
1450
1483
|
space_lengths = [config["frame_x_radius"], config["frame_y_radius"]]
|
|
1451
1484
|
for vect in UP, DOWN, LEFT, RIGHT:
|
|
1452
1485
|
dim = np.argmax(np.abs(vect))
|
|
@@ -1468,10 +1501,12 @@ class Mobject:
|
|
|
1468
1501
|
return True
|
|
1469
1502
|
return False
|
|
1470
1503
|
|
|
1471
|
-
def stretch_about_point(self, factor, dim, point):
|
|
1504
|
+
def stretch_about_point(self, factor: float, dim: int, point: Point3D) -> Self:
|
|
1472
1505
|
return self.stretch(factor, dim, about_point=point)
|
|
1473
1506
|
|
|
1474
|
-
def rescale_to_fit(
|
|
1507
|
+
def rescale_to_fit(
|
|
1508
|
+
self, length: float, dim: int, stretch: bool = False, **kwargs
|
|
1509
|
+
) -> Self:
|
|
1475
1510
|
old_length = self.length_over_dim(dim)
|
|
1476
1511
|
if old_length == 0:
|
|
1477
1512
|
return self
|
|
@@ -1481,7 +1516,7 @@ class Mobject:
|
|
|
1481
1516
|
self.scale(length / old_length, **kwargs)
|
|
1482
1517
|
return self
|
|
1483
1518
|
|
|
1484
|
-
def scale_to_fit_width(self, width, **kwargs):
|
|
1519
|
+
def scale_to_fit_width(self, width: float, **kwargs) -> Self:
|
|
1485
1520
|
"""Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional.
|
|
1486
1521
|
|
|
1487
1522
|
Returns
|
|
@@ -1507,7 +1542,7 @@ class Mobject:
|
|
|
1507
1542
|
|
|
1508
1543
|
return self.rescale_to_fit(width, 0, stretch=False, **kwargs)
|
|
1509
1544
|
|
|
1510
|
-
def stretch_to_fit_width(self, width, **kwargs):
|
|
1545
|
+
def stretch_to_fit_width(self, width: float, **kwargs) -> Self:
|
|
1511
1546
|
"""Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional.
|
|
1512
1547
|
|
|
1513
1548
|
Returns
|
|
@@ -1533,7 +1568,7 @@ class Mobject:
|
|
|
1533
1568
|
|
|
1534
1569
|
return self.rescale_to_fit(width, 0, stretch=True, **kwargs)
|
|
1535
1570
|
|
|
1536
|
-
def scale_to_fit_height(self, height, **kwargs):
|
|
1571
|
+
def scale_to_fit_height(self, height: float, **kwargs) -> Self:
|
|
1537
1572
|
"""Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional.
|
|
1538
1573
|
|
|
1539
1574
|
Returns
|
|
@@ -1559,7 +1594,7 @@ class Mobject:
|
|
|
1559
1594
|
|
|
1560
1595
|
return self.rescale_to_fit(height, 1, stretch=False, **kwargs)
|
|
1561
1596
|
|
|
1562
|
-
def stretch_to_fit_height(self, height, **kwargs):
|
|
1597
|
+
def stretch_to_fit_height(self, height: float, **kwargs) -> Self:
|
|
1563
1598
|
"""Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional.
|
|
1564
1599
|
|
|
1565
1600
|
Returns
|
|
@@ -1585,36 +1620,36 @@ class Mobject:
|
|
|
1585
1620
|
|
|
1586
1621
|
return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
|
|
1587
1622
|
|
|
1588
|
-
def scale_to_fit_depth(self, depth, **kwargs):
|
|
1623
|
+
def scale_to_fit_depth(self, depth: float, **kwargs) -> Self:
|
|
1589
1624
|
"""Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional."""
|
|
1590
1625
|
|
|
1591
1626
|
return self.rescale_to_fit(depth, 2, stretch=False, **kwargs)
|
|
1592
1627
|
|
|
1593
|
-
def stretch_to_fit_depth(self, depth, **kwargs):
|
|
1628
|
+
def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self:
|
|
1594
1629
|
"""Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional."""
|
|
1595
1630
|
|
|
1596
1631
|
return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
|
|
1597
1632
|
|
|
1598
|
-
def set_coord(self, value, dim, direction=ORIGIN):
|
|
1633
|
+
def set_coord(self, value, dim: int, direction: Vector3 = ORIGIN) -> Self:
|
|
1599
1634
|
curr = self.get_coord(dim, direction)
|
|
1600
1635
|
shift_vect = np.zeros(self.dim)
|
|
1601
1636
|
shift_vect[dim] = value - curr
|
|
1602
1637
|
self.shift(shift_vect)
|
|
1603
1638
|
return self
|
|
1604
1639
|
|
|
1605
|
-
def set_x(self, x, direction=ORIGIN):
|
|
1640
|
+
def set_x(self, x: float, direction: Vector3 = ORIGIN) -> Self:
|
|
1606
1641
|
"""Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1607
1642
|
return self.set_coord(x, 0, direction)
|
|
1608
1643
|
|
|
1609
|
-
def set_y(self, y, direction=ORIGIN):
|
|
1644
|
+
def set_y(self, y: float, direction: Vector3 = ORIGIN) -> Self:
|
|
1610
1645
|
"""Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1611
1646
|
return self.set_coord(y, 1, direction)
|
|
1612
1647
|
|
|
1613
|
-
def set_z(self, z, direction=ORIGIN):
|
|
1648
|
+
def set_z(self, z: float, direction: Vector3 = ORIGIN) -> Self:
|
|
1614
1649
|
"""Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1615
1650
|
return self.set_coord(z, 2, direction)
|
|
1616
1651
|
|
|
1617
|
-
def space_out_submobjects(self, factor=1.5, **kwargs):
|
|
1652
|
+
def space_out_submobjects(self, factor: float = 1.5, **kwargs) -> Self:
|
|
1618
1653
|
self.scale(factor, **kwargs)
|
|
1619
1654
|
for submob in self.submobjects:
|
|
1620
1655
|
submob.scale(1.0 / factor)
|
|
@@ -1622,11 +1657,11 @@ class Mobject:
|
|
|
1622
1657
|
|
|
1623
1658
|
def move_to(
|
|
1624
1659
|
self,
|
|
1625
|
-
point_or_mobject,
|
|
1626
|
-
aligned_edge=ORIGIN,
|
|
1627
|
-
coor_mask=np.array([1, 1, 1]),
|
|
1628
|
-
):
|
|
1629
|
-
"""Move center of the :class:`~.Mobject` to certain
|
|
1660
|
+
point_or_mobject: Point3D | Mobject,
|
|
1661
|
+
aligned_edge: Vector3 = ORIGIN,
|
|
1662
|
+
coor_mask: Vector3 = np.array([1, 1, 1]),
|
|
1663
|
+
) -> Self:
|
|
1664
|
+
"""Move center of the :class:`~.Mobject` to certain Point3D."""
|
|
1630
1665
|
if isinstance(point_or_mobject, Mobject):
|
|
1631
1666
|
target = point_or_mobject.get_critical_point(aligned_edge)
|
|
1632
1667
|
else:
|
|
@@ -1635,7 +1670,9 @@ class Mobject:
|
|
|
1635
1670
|
self.shift((target - point_to_align) * coor_mask)
|
|
1636
1671
|
return self
|
|
1637
1672
|
|
|
1638
|
-
def replace(
|
|
1673
|
+
def replace(
|
|
1674
|
+
self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False
|
|
1675
|
+
) -> Self:
|
|
1639
1676
|
if not mobject.get_num_points() and not mobject.submobjects:
|
|
1640
1677
|
raise Warning("Attempting to replace mobject with no points")
|
|
1641
1678
|
if stretch:
|
|
@@ -1653,16 +1690,16 @@ class Mobject:
|
|
|
1653
1690
|
def surround(
|
|
1654
1691
|
self,
|
|
1655
1692
|
mobject: Mobject,
|
|
1656
|
-
dim_to_match=0,
|
|
1657
|
-
stretch=False,
|
|
1658
|
-
buff=MED_SMALL_BUFF,
|
|
1659
|
-
):
|
|
1693
|
+
dim_to_match: int = 0,
|
|
1694
|
+
stretch: bool = False,
|
|
1695
|
+
buff: float = MED_SMALL_BUFF,
|
|
1696
|
+
) -> Self:
|
|
1660
1697
|
self.replace(mobject, dim_to_match, stretch)
|
|
1661
1698
|
length = mobject.length_over_dim(dim_to_match)
|
|
1662
1699
|
self.scale((length + buff) / length)
|
|
1663
1700
|
return self
|
|
1664
1701
|
|
|
1665
|
-
def put_start_and_end_on(self, start, end):
|
|
1702
|
+
def put_start_and_end_on(self, start: Point3D, end: Point3D) -> Self:
|
|
1666
1703
|
curr_start, curr_end = self.get_start_and_end()
|
|
1667
1704
|
curr_vect = curr_end - curr_start
|
|
1668
1705
|
if np.all(curr_vect == 0):
|
|
@@ -1687,8 +1724,8 @@ class Mobject:
|
|
|
1687
1724
|
|
|
1688
1725
|
# Background rectangle
|
|
1689
1726
|
def add_background_rectangle(
|
|
1690
|
-
self, color:
|
|
1691
|
-
):
|
|
1727
|
+
self, color: ParsableManimColor | None = None, opacity: float = 0.75, **kwargs
|
|
1728
|
+
) -> Self:
|
|
1692
1729
|
"""Add a BackgroundRectangle as submobject.
|
|
1693
1730
|
|
|
1694
1731
|
The BackgroundRectangle is added behind other submobjects.
|
|
@@ -1727,19 +1764,21 @@ class Mobject:
|
|
|
1727
1764
|
self.add_to_back(self.background_rectangle)
|
|
1728
1765
|
return self
|
|
1729
1766
|
|
|
1730
|
-
def add_background_rectangle_to_submobjects(self, **kwargs):
|
|
1767
|
+
def add_background_rectangle_to_submobjects(self, **kwargs) -> Self:
|
|
1731
1768
|
for submobject in self.submobjects:
|
|
1732
1769
|
submobject.add_background_rectangle(**kwargs)
|
|
1733
1770
|
return self
|
|
1734
1771
|
|
|
1735
|
-
def add_background_rectangle_to_family_members_with_points(self, **kwargs):
|
|
1772
|
+
def add_background_rectangle_to_family_members_with_points(self, **kwargs) -> Self:
|
|
1736
1773
|
for mob in self.family_members_with_points():
|
|
1737
1774
|
mob.add_background_rectangle(**kwargs)
|
|
1738
1775
|
return self
|
|
1739
1776
|
|
|
1740
1777
|
# Color functions
|
|
1741
1778
|
|
|
1742
|
-
def set_color(
|
|
1779
|
+
def set_color(
|
|
1780
|
+
self, color: ParsableManimColor = YELLOW_C, family: bool = True
|
|
1781
|
+
) -> Self:
|
|
1743
1782
|
"""Condition is function which takes in one arguments, (x, y, z).
|
|
1744
1783
|
Here it just recurses to submobjects, but in subclasses this
|
|
1745
1784
|
should be further implemented based on the the inner workings
|
|
@@ -1748,20 +1787,30 @@ class Mobject:
|
|
|
1748
1787
|
if family:
|
|
1749
1788
|
for submob in self.submobjects:
|
|
1750
1789
|
submob.set_color(color, family=family)
|
|
1751
|
-
|
|
1790
|
+
|
|
1791
|
+
self.color = ManimColor.parse(color)
|
|
1752
1792
|
return self
|
|
1753
1793
|
|
|
1754
|
-
def set_color_by_gradient(self, *colors):
|
|
1794
|
+
def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:
|
|
1795
|
+
"""
|
|
1796
|
+
Parameters
|
|
1797
|
+
----------
|
|
1798
|
+
colors
|
|
1799
|
+
The colors to use for the gradient. Use like `set_color_by_gradient(RED, BLUE, GREEN)`.
|
|
1800
|
+
|
|
1801
|
+
self.color = ManimColor.parse(color)
|
|
1802
|
+
return self
|
|
1803
|
+
"""
|
|
1755
1804
|
self.set_submobject_colors_by_gradient(*colors)
|
|
1756
1805
|
return self
|
|
1757
1806
|
|
|
1758
1807
|
def set_colors_by_radial_gradient(
|
|
1759
1808
|
self,
|
|
1760
|
-
center=None,
|
|
1761
|
-
radius=1,
|
|
1762
|
-
inner_color=WHITE,
|
|
1763
|
-
outer_color=BLACK,
|
|
1764
|
-
):
|
|
1809
|
+
center: Point3D | None = None,
|
|
1810
|
+
radius: float = 1,
|
|
1811
|
+
inner_color: ParsableManimColor = WHITE,
|
|
1812
|
+
outer_color: ParsableManimColor = BLACK,
|
|
1813
|
+
) -> Self:
|
|
1765
1814
|
self.set_submobject_colors_by_radial_gradient(
|
|
1766
1815
|
center,
|
|
1767
1816
|
radius,
|
|
@@ -1770,7 +1819,7 @@ class Mobject:
|
|
|
1770
1819
|
)
|
|
1771
1820
|
return self
|
|
1772
1821
|
|
|
1773
|
-
def set_submobject_colors_by_gradient(self, *colors):
|
|
1822
|
+
def set_submobject_colors_by_gradient(self, *colors: Iterable[ParsableManimColor]):
|
|
1774
1823
|
if len(colors) == 0:
|
|
1775
1824
|
raise ValueError("Need at least one color")
|
|
1776
1825
|
elif len(colors) == 1:
|
|
@@ -1785,11 +1834,11 @@ class Mobject:
|
|
|
1785
1834
|
|
|
1786
1835
|
def set_submobject_colors_by_radial_gradient(
|
|
1787
1836
|
self,
|
|
1788
|
-
center=None,
|
|
1789
|
-
radius=1,
|
|
1790
|
-
inner_color=WHITE,
|
|
1791
|
-
outer_color=BLACK,
|
|
1792
|
-
):
|
|
1837
|
+
center: Point3D | None = None,
|
|
1838
|
+
radius: float = 1,
|
|
1839
|
+
inner_color: ParsableManimColor = WHITE,
|
|
1840
|
+
outer_color: ParsableManimColor = BLACK,
|
|
1841
|
+
) -> Self:
|
|
1793
1842
|
if center is None:
|
|
1794
1843
|
center = self.get_center()
|
|
1795
1844
|
|
|
@@ -1801,11 +1850,13 @@ class Mobject:
|
|
|
1801
1850
|
|
|
1802
1851
|
return self
|
|
1803
1852
|
|
|
1804
|
-
def to_original_color(self):
|
|
1853
|
+
def to_original_color(self) -> Self:
|
|
1805
1854
|
self.set_color(self.color)
|
|
1806
1855
|
return self
|
|
1807
1856
|
|
|
1808
|
-
def fade_to(
|
|
1857
|
+
def fade_to(
|
|
1858
|
+
self, color: ParsableManimColor, alpha: float, family: bool = True
|
|
1859
|
+
) -> Self:
|
|
1809
1860
|
if self.get_num_points() > 0:
|
|
1810
1861
|
new_color = interpolate_color(self.get_color(), color, alpha)
|
|
1811
1862
|
self.set_color(new_color, family=False)
|
|
@@ -1814,19 +1865,19 @@ class Mobject:
|
|
|
1814
1865
|
submob.fade_to(color, alpha)
|
|
1815
1866
|
return self
|
|
1816
1867
|
|
|
1817
|
-
def fade(self, darkness=0.5, family=True):
|
|
1868
|
+
def fade(self, darkness: float = 0.5, family: bool = True) -> Self:
|
|
1818
1869
|
if family:
|
|
1819
1870
|
for submob in self.submobjects:
|
|
1820
1871
|
submob.fade(darkness, family)
|
|
1821
1872
|
return self
|
|
1822
1873
|
|
|
1823
|
-
def get_color(self):
|
|
1874
|
+
def get_color(self) -> ManimColor:
|
|
1824
1875
|
"""Returns the color of the :class:`~.Mobject`"""
|
|
1825
1876
|
return self.color
|
|
1826
1877
|
|
|
1827
1878
|
##
|
|
1828
1879
|
|
|
1829
|
-
def save_state(self):
|
|
1880
|
+
def save_state(self) -> Self:
|
|
1830
1881
|
"""Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`."""
|
|
1831
1882
|
if hasattr(self, "saved_state"):
|
|
1832
1883
|
# Prevent exponential growth of data
|
|
@@ -1835,14 +1886,14 @@ class Mobject:
|
|
|
1835
1886
|
|
|
1836
1887
|
return self
|
|
1837
1888
|
|
|
1838
|
-
def restore(self):
|
|
1889
|
+
def restore(self) -> Self:
|
|
1839
1890
|
"""Restores the state that was previously saved with :meth:`~.Mobject.save_state`."""
|
|
1840
1891
|
if not hasattr(self, "saved_state") or self.save_state is None:
|
|
1841
1892
|
raise Exception("Trying to restore without having saved")
|
|
1842
1893
|
self.become(self.saved_state)
|
|
1843
1894
|
return self
|
|
1844
1895
|
|
|
1845
|
-
def reduce_across_dimension(self, reduce_func, dim: int)
|
|
1896
|
+
def reduce_across_dimension(self, reduce_func: Callable, dim: int):
|
|
1846
1897
|
"""Find the min or max value from a dimension across all points in this and submobjects."""
|
|
1847
1898
|
assert dim >= 0 and dim <= 2
|
|
1848
1899
|
if len(self.submobjects) == 0 and len(self.points) == 0:
|
|
@@ -1866,14 +1917,14 @@ class Mobject:
|
|
|
1866
1917
|
rv = reduce_func([value, rv])
|
|
1867
1918
|
return rv
|
|
1868
1919
|
|
|
1869
|
-
def nonempty_submobjects(self):
|
|
1920
|
+
def nonempty_submobjects(self) -> list[Self]:
|
|
1870
1921
|
return [
|
|
1871
1922
|
submob
|
|
1872
1923
|
for submob in self.submobjects
|
|
1873
1924
|
if len(submob.submobjects) != 0 or len(submob.points) != 0
|
|
1874
1925
|
]
|
|
1875
1926
|
|
|
1876
|
-
def get_merged_array(self, array_attr) -> np.ndarray:
|
|
1927
|
+
def get_merged_array(self, array_attr: str) -> np.ndarray:
|
|
1877
1928
|
"""Return all of a given attribute from this mobject and all submobjects.
|
|
1878
1929
|
|
|
1879
1930
|
May contain duplicates; the order is in a depth-first (pre-order)
|
|
@@ -1884,7 +1935,7 @@ class Mobject:
|
|
|
1884
1935
|
result = np.append(result, submob.get_merged_array(array_attr), axis=0)
|
|
1885
1936
|
return result
|
|
1886
1937
|
|
|
1887
|
-
def get_all_points(self) ->
|
|
1938
|
+
def get_all_points(self) -> Point3D_Array:
|
|
1888
1939
|
"""Return all points from this mobject and all submobjects.
|
|
1889
1940
|
|
|
1890
1941
|
May contain duplicates; the order is in a depth-first (pre-order)
|
|
@@ -1894,13 +1945,15 @@ class Mobject:
|
|
|
1894
1945
|
|
|
1895
1946
|
# Getters
|
|
1896
1947
|
|
|
1897
|
-
def get_points_defining_boundary(self):
|
|
1948
|
+
def get_points_defining_boundary(self) -> Point3D_Array:
|
|
1898
1949
|
return self.get_all_points()
|
|
1899
1950
|
|
|
1900
|
-
def get_num_points(self):
|
|
1951
|
+
def get_num_points(self) -> int:
|
|
1901
1952
|
return len(self.points)
|
|
1902
1953
|
|
|
1903
|
-
def get_extremum_along_dim(
|
|
1954
|
+
def get_extremum_along_dim(
|
|
1955
|
+
self, points: Point3D_Array | None = None, dim: int = 0, key: int = 0
|
|
1956
|
+
) -> np.ndarray | float:
|
|
1904
1957
|
if points is None:
|
|
1905
1958
|
points = self.get_points_defining_boundary()
|
|
1906
1959
|
values = points[:, dim]
|
|
@@ -1911,7 +1964,7 @@ class Mobject:
|
|
|
1911
1964
|
else:
|
|
1912
1965
|
return np.max(values)
|
|
1913
1966
|
|
|
1914
|
-
def get_critical_point(self, direction):
|
|
1967
|
+
def get_critical_point(self, direction: Vector3) -> Point3D:
|
|
1915
1968
|
"""Picture a box bounding the :class:`~.Mobject`. Such a box has
|
|
1916
1969
|
9 'critical points': 4 corners, 4 edge center, the
|
|
1917
1970
|
center. This returns one of them, along the given direction.
|
|
@@ -1940,28 +1993,28 @@ class Mobject:
|
|
|
1940
1993
|
|
|
1941
1994
|
# Pseudonyms for more general get_critical_point method
|
|
1942
1995
|
|
|
1943
|
-
def get_edge_center(self, direction) ->
|
|
1944
|
-
"""Get edge
|
|
1996
|
+
def get_edge_center(self, direction: Vector3) -> Point3D:
|
|
1997
|
+
"""Get edge Point3Ds for certain direction."""
|
|
1945
1998
|
return self.get_critical_point(direction)
|
|
1946
1999
|
|
|
1947
|
-
def get_corner(self, direction) ->
|
|
1948
|
-
"""Get corner
|
|
2000
|
+
def get_corner(self, direction: Vector3) -> Point3D:
|
|
2001
|
+
"""Get corner Point3Ds for certain direction."""
|
|
1949
2002
|
return self.get_critical_point(direction)
|
|
1950
2003
|
|
|
1951
|
-
def get_center(self) ->
|
|
1952
|
-
"""Get center
|
|
2004
|
+
def get_center(self) -> Point3D:
|
|
2005
|
+
"""Get center Point3Ds"""
|
|
1953
2006
|
return self.get_critical_point(np.zeros(self.dim))
|
|
1954
2007
|
|
|
1955
|
-
def get_center_of_mass(self):
|
|
2008
|
+
def get_center_of_mass(self) -> Point3D:
|
|
1956
2009
|
return np.apply_along_axis(np.mean, 0, self.get_all_points())
|
|
1957
2010
|
|
|
1958
|
-
def get_boundary_point(self, direction):
|
|
2011
|
+
def get_boundary_point(self, direction: Vector3) -> Point3D:
|
|
1959
2012
|
all_points = self.get_points_defining_boundary()
|
|
1960
2013
|
index = np.argmax(np.dot(all_points, np.array(direction).T))
|
|
1961
2014
|
return all_points[index]
|
|
1962
2015
|
|
|
1963
|
-
def get_midpoint(self) ->
|
|
1964
|
-
"""Get
|
|
2016
|
+
def get_midpoint(self) -> Point3D:
|
|
2017
|
+
"""Get Point3Ds of the middle of the path that forms the :class:`~.Mobject`.
|
|
1965
2018
|
|
|
1966
2019
|
Examples
|
|
1967
2020
|
--------
|
|
@@ -1983,74 +2036,74 @@ class Mobject:
|
|
|
1983
2036
|
"""
|
|
1984
2037
|
return self.point_from_proportion(0.5)
|
|
1985
2038
|
|
|
1986
|
-
def get_top(self) ->
|
|
1987
|
-
"""Get top
|
|
2039
|
+
def get_top(self) -> Point3D:
|
|
2040
|
+
"""Get top Point3Ds of a box bounding the :class:`~.Mobject`"""
|
|
1988
2041
|
return self.get_edge_center(UP)
|
|
1989
2042
|
|
|
1990
|
-
def get_bottom(self) ->
|
|
1991
|
-
"""Get bottom
|
|
2043
|
+
def get_bottom(self) -> Point3D:
|
|
2044
|
+
"""Get bottom Point3Ds of a box bounding the :class:`~.Mobject`"""
|
|
1992
2045
|
return self.get_edge_center(DOWN)
|
|
1993
2046
|
|
|
1994
|
-
def get_right(self) ->
|
|
1995
|
-
"""Get right
|
|
2047
|
+
def get_right(self) -> Point3D:
|
|
2048
|
+
"""Get right Point3Ds of a box bounding the :class:`~.Mobject`"""
|
|
1996
2049
|
return self.get_edge_center(RIGHT)
|
|
1997
2050
|
|
|
1998
|
-
def get_left(self) ->
|
|
1999
|
-
"""Get left
|
|
2051
|
+
def get_left(self) -> Point3D:
|
|
2052
|
+
"""Get left Point3Ds of a box bounding the :class:`~.Mobject`"""
|
|
2000
2053
|
return self.get_edge_center(LEFT)
|
|
2001
2054
|
|
|
2002
|
-
def get_zenith(self) ->
|
|
2003
|
-
"""Get zenith
|
|
2055
|
+
def get_zenith(self) -> Point3D:
|
|
2056
|
+
"""Get zenith Point3Ds of a box bounding a 3D :class:`~.Mobject`."""
|
|
2004
2057
|
return self.get_edge_center(OUT)
|
|
2005
2058
|
|
|
2006
|
-
def get_nadir(self) ->
|
|
2007
|
-
"""Get nadir (opposite the zenith)
|
|
2059
|
+
def get_nadir(self) -> Point3D:
|
|
2060
|
+
"""Get nadir (opposite the zenith) Point3Ds of a box bounding a 3D :class:`~.Mobject`."""
|
|
2008
2061
|
return self.get_edge_center(IN)
|
|
2009
2062
|
|
|
2010
|
-
def length_over_dim(self, dim):
|
|
2063
|
+
def length_over_dim(self, dim: int) -> float:
|
|
2011
2064
|
"""Measure the length of an :class:`~.Mobject` in a certain direction."""
|
|
2012
2065
|
return self.reduce_across_dimension(
|
|
2013
2066
|
max,
|
|
2014
2067
|
dim,
|
|
2015
2068
|
) - self.reduce_across_dimension(min, dim)
|
|
2016
2069
|
|
|
2017
|
-
def get_coord(self, dim, direction=ORIGIN):
|
|
2070
|
+
def get_coord(self, dim: int, direction: Vector3 = ORIGIN):
|
|
2018
2071
|
"""Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
|
|
2019
2072
|
return self.get_extremum_along_dim(dim=dim, key=direction[dim])
|
|
2020
2073
|
|
|
2021
|
-
def get_x(self, direction=ORIGIN) ->
|
|
2022
|
-
"""Returns x
|
|
2074
|
+
def get_x(self, direction: Vector3 = ORIGIN) -> ManimFloat:
|
|
2075
|
+
"""Returns x Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2023
2076
|
return self.get_coord(0, direction)
|
|
2024
2077
|
|
|
2025
|
-
def get_y(self, direction=ORIGIN) ->
|
|
2026
|
-
"""Returns y
|
|
2078
|
+
def get_y(self, direction: Vector3 = ORIGIN) -> ManimFloat:
|
|
2079
|
+
"""Returns y Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2027
2080
|
return self.get_coord(1, direction)
|
|
2028
2081
|
|
|
2029
|
-
def get_z(self, direction=ORIGIN) ->
|
|
2030
|
-
"""Returns z
|
|
2082
|
+
def get_z(self, direction: Vector3 = ORIGIN) -> ManimFloat:
|
|
2083
|
+
"""Returns z Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2031
2084
|
return self.get_coord(2, direction)
|
|
2032
2085
|
|
|
2033
|
-
def get_start(self):
|
|
2086
|
+
def get_start(self) -> Point3D:
|
|
2034
2087
|
"""Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts."""
|
|
2035
2088
|
self.throw_error_if_no_points()
|
|
2036
2089
|
return np.array(self.points[0])
|
|
2037
2090
|
|
|
2038
|
-
def get_end(self):
|
|
2091
|
+
def get_end(self) -> Point3D:
|
|
2039
2092
|
"""Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends."""
|
|
2040
2093
|
self.throw_error_if_no_points()
|
|
2041
2094
|
return np.array(self.points[-1])
|
|
2042
2095
|
|
|
2043
|
-
def get_start_and_end(self):
|
|
2096
|
+
def get_start_and_end(self) -> tuple[Point3D, Point3D]:
|
|
2044
2097
|
"""Returns starting and ending point of a stroke as a ``tuple``."""
|
|
2045
2098
|
return self.get_start(), self.get_end()
|
|
2046
2099
|
|
|
2047
|
-
def point_from_proportion(self, alpha):
|
|
2100
|
+
def point_from_proportion(self, alpha: float) -> Point3D:
|
|
2048
2101
|
raise NotImplementedError("Please override in a child class.")
|
|
2049
2102
|
|
|
2050
|
-
def proportion_from_point(self, point):
|
|
2103
|
+
def proportion_from_point(self, point: Point3D) -> float:
|
|
2051
2104
|
raise NotImplementedError("Please override in a child class.")
|
|
2052
2105
|
|
|
2053
|
-
def get_pieces(self, n_pieces):
|
|
2106
|
+
def get_pieces(self, n_pieces: float) -> Group:
|
|
2054
2107
|
template = self.copy()
|
|
2055
2108
|
template.submobjects = []
|
|
2056
2109
|
alphas = np.linspace(0, 1, n_pieces + 1)
|
|
@@ -2061,7 +2114,7 @@ class Mobject:
|
|
|
2061
2114
|
)
|
|
2062
2115
|
)
|
|
2063
2116
|
|
|
2064
|
-
def get_z_index_reference_point(self):
|
|
2117
|
+
def get_z_index_reference_point(self) -> Point3D:
|
|
2065
2118
|
# TODO, better place to define default z_index_group?
|
|
2066
2119
|
z_index_group = getattr(self, "z_index_group", self)
|
|
2067
2120
|
return z_index_group.get_center()
|
|
@@ -2076,51 +2129,53 @@ class Mobject:
|
|
|
2076
2129
|
|
|
2077
2130
|
# Match other mobject properties
|
|
2078
2131
|
|
|
2079
|
-
def match_color(self, mobject: Mobject):
|
|
2132
|
+
def match_color(self, mobject: Mobject) -> Self:
|
|
2080
2133
|
"""Match the color with the color of another :class:`~.Mobject`."""
|
|
2081
2134
|
return self.set_color(mobject.get_color())
|
|
2082
2135
|
|
|
2083
|
-
def match_dim_size(self, mobject: Mobject, dim, **kwargs):
|
|
2136
|
+
def match_dim_size(self, mobject: Mobject, dim: int, **kwargs) -> Self:
|
|
2084
2137
|
"""Match the specified dimension with the dimension of another :class:`~.Mobject`."""
|
|
2085
2138
|
return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs)
|
|
2086
2139
|
|
|
2087
|
-
def match_width(self, mobject: Mobject, **kwargs):
|
|
2140
|
+
def match_width(self, mobject: Mobject, **kwargs) -> Self:
|
|
2088
2141
|
"""Match the width with the width of another :class:`~.Mobject`."""
|
|
2089
2142
|
return self.match_dim_size(mobject, 0, **kwargs)
|
|
2090
2143
|
|
|
2091
|
-
def match_height(self, mobject: Mobject, **kwargs):
|
|
2144
|
+
def match_height(self, mobject: Mobject, **kwargs) -> Self:
|
|
2092
2145
|
"""Match the height with the height of another :class:`~.Mobject`."""
|
|
2093
2146
|
return self.match_dim_size(mobject, 1, **kwargs)
|
|
2094
2147
|
|
|
2095
|
-
def match_depth(self, mobject: Mobject, **kwargs):
|
|
2148
|
+
def match_depth(self, mobject: Mobject, **kwargs) -> Self:
|
|
2096
2149
|
"""Match the depth with the depth of another :class:`~.Mobject`."""
|
|
2097
2150
|
return self.match_dim_size(mobject, 2, **kwargs)
|
|
2098
2151
|
|
|
2099
|
-
def match_coord(
|
|
2100
|
-
|
|
2152
|
+
def match_coord(
|
|
2153
|
+
self, mobject: Mobject, dim: int, direction: Vector3 = ORIGIN
|
|
2154
|
+
) -> Self:
|
|
2155
|
+
"""Match the Point3Ds with the Point3Ds of another :class:`~.Mobject`."""
|
|
2101
2156
|
return self.set_coord(
|
|
2102
2157
|
mobject.get_coord(dim, direction),
|
|
2103
2158
|
dim=dim,
|
|
2104
2159
|
direction=direction,
|
|
2105
2160
|
)
|
|
2106
2161
|
|
|
2107
|
-
def match_x(self, mobject: Mobject, direction=ORIGIN):
|
|
2162
|
+
def match_x(self, mobject: Mobject, direction=ORIGIN) -> Self:
|
|
2108
2163
|
"""Match x coord. to the x coord. of another :class:`~.Mobject`."""
|
|
2109
2164
|
return self.match_coord(mobject, 0, direction)
|
|
2110
2165
|
|
|
2111
|
-
def match_y(self, mobject: Mobject, direction=ORIGIN):
|
|
2166
|
+
def match_y(self, mobject: Mobject, direction=ORIGIN) -> Self:
|
|
2112
2167
|
"""Match y coord. to the x coord. of another :class:`~.Mobject`."""
|
|
2113
2168
|
return self.match_coord(mobject, 1, direction)
|
|
2114
2169
|
|
|
2115
|
-
def match_z(self, mobject: Mobject, direction=ORIGIN):
|
|
2170
|
+
def match_z(self, mobject: Mobject, direction=ORIGIN) -> Self:
|
|
2116
2171
|
"""Match z coord. to the x coord. of another :class:`~.Mobject`."""
|
|
2117
2172
|
return self.match_coord(mobject, 2, direction)
|
|
2118
2173
|
|
|
2119
2174
|
def align_to(
|
|
2120
2175
|
self,
|
|
2121
|
-
mobject_or_point: Mobject |
|
|
2122
|
-
direction=ORIGIN,
|
|
2123
|
-
):
|
|
2176
|
+
mobject_or_point: Mobject | Point3D,
|
|
2177
|
+
direction: Vector3 = ORIGIN,
|
|
2178
|
+
) -> Self:
|
|
2124
2179
|
"""Aligns mobject to another :class:`~.Mobject` in a certain direction.
|
|
2125
2180
|
|
|
2126
2181
|
Examples:
|
|
@@ -2152,33 +2207,33 @@ class Mobject:
|
|
|
2152
2207
|
def __len__(self):
|
|
2153
2208
|
return len(self.split())
|
|
2154
2209
|
|
|
2155
|
-
def get_group_class(self):
|
|
2210
|
+
def get_group_class(self) -> type[Group]:
|
|
2156
2211
|
return Group
|
|
2157
2212
|
|
|
2158
2213
|
@staticmethod
|
|
2159
|
-
def get_mobject_type_class():
|
|
2214
|
+
def get_mobject_type_class() -> type[Mobject]:
|
|
2160
2215
|
"""Return the base class of this mobject type."""
|
|
2161
2216
|
return Mobject
|
|
2162
2217
|
|
|
2163
|
-
def split(self):
|
|
2218
|
+
def split(self) -> list[Self]:
|
|
2164
2219
|
result = [self] if len(self.points) > 0 else []
|
|
2165
2220
|
return result + self.submobjects
|
|
2166
2221
|
|
|
2167
|
-
def get_family(self, recurse=True):
|
|
2168
|
-
sub_families =
|
|
2222
|
+
def get_family(self, recurse: bool = True) -> list[Self]:
|
|
2223
|
+
sub_families = [x.get_family() for x in self.submobjects]
|
|
2169
2224
|
all_mobjects = [self] + list(it.chain(*sub_families))
|
|
2170
2225
|
return remove_list_redundancies(all_mobjects)
|
|
2171
2226
|
|
|
2172
|
-
def family_members_with_points(self):
|
|
2227
|
+
def family_members_with_points(self) -> list[Self]:
|
|
2173
2228
|
return [m for m in self.get_family() if m.get_num_points() > 0]
|
|
2174
2229
|
|
|
2175
2230
|
def arrange(
|
|
2176
2231
|
self,
|
|
2177
|
-
direction:
|
|
2178
|
-
buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
2179
|
-
center=True,
|
|
2232
|
+
direction: Vector3 = RIGHT,
|
|
2233
|
+
buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
2234
|
+
center: bool = True,
|
|
2180
2235
|
**kwargs,
|
|
2181
|
-
):
|
|
2236
|
+
) -> Self:
|
|
2182
2237
|
"""Sorts :class:`~.Mobject` next to each other on screen.
|
|
2183
2238
|
|
|
2184
2239
|
Examples
|
|
@@ -2207,14 +2262,14 @@ class Mobject:
|
|
|
2207
2262
|
rows: int | None = None,
|
|
2208
2263
|
cols: int | None = None,
|
|
2209
2264
|
buff: float | tuple[float, float] = MED_SMALL_BUFF,
|
|
2210
|
-
cell_alignment:
|
|
2265
|
+
cell_alignment: Vector3 = ORIGIN,
|
|
2211
2266
|
row_alignments: str | None = None, # "ucd"
|
|
2212
2267
|
col_alignments: str | None = None, # "lcr"
|
|
2213
2268
|
row_heights: Iterable[float | None] | None = None,
|
|
2214
2269
|
col_widths: Iterable[float | None] | None = None,
|
|
2215
2270
|
flow_order: str = "rd",
|
|
2216
2271
|
**kwargs,
|
|
2217
|
-
):
|
|
2272
|
+
) -> Self:
|
|
2218
2273
|
"""Arrange submobjects in a grid.
|
|
2219
2274
|
|
|
2220
2275
|
Parameters
|
|
@@ -2320,15 +2375,15 @@ class Mobject:
|
|
|
2320
2375
|
|
|
2321
2376
|
# calculate rows cols
|
|
2322
2377
|
if rows is None and cols is None:
|
|
2323
|
-
cols = ceil(
|
|
2378
|
+
cols = math.ceil(math.sqrt(len(mobs)))
|
|
2324
2379
|
# make the grid as close to quadratic as possible.
|
|
2325
2380
|
# choosing cols first can results in cols>rows.
|
|
2326
2381
|
# This is favored over rows>cols since in general
|
|
2327
2382
|
# the sceene is wider than high.
|
|
2328
2383
|
if rows is None:
|
|
2329
|
-
rows = ceil(len(mobs) / cols)
|
|
2384
|
+
rows = math.ceil(len(mobs) / cols)
|
|
2330
2385
|
if cols is None:
|
|
2331
|
-
cols = ceil(len(mobs) / rows)
|
|
2386
|
+
cols = math.ceil(len(mobs) / rows)
|
|
2332
2387
|
if rows * cols < len(mobs):
|
|
2333
2388
|
raise ValueError("Too few rows and columns to fit all submobjetcs.")
|
|
2334
2389
|
# rows and cols are now finally valid.
|
|
@@ -2443,24 +2498,28 @@ class Mobject:
|
|
|
2443
2498
|
self.move_to(start_pos)
|
|
2444
2499
|
return self
|
|
2445
2500
|
|
|
2446
|
-
def sort(
|
|
2501
|
+
def sort(
|
|
2502
|
+
self,
|
|
2503
|
+
point_to_num_func: Callable[[Point3D], ManimInt] = lambda p: p[0],
|
|
2504
|
+
submob_func: Callable[[Mobject], ManimInt] | None = None,
|
|
2505
|
+
) -> Self:
|
|
2447
2506
|
"""Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``."""
|
|
2448
2507
|
if submob_func is None:
|
|
2449
2508
|
|
|
2450
|
-
def submob_func(m):
|
|
2509
|
+
def submob_func(m: Mobject):
|
|
2451
2510
|
return point_to_num_func(m.get_center())
|
|
2452
2511
|
|
|
2453
2512
|
self.submobjects.sort(key=submob_func)
|
|
2454
2513
|
return self
|
|
2455
2514
|
|
|
2456
|
-
def shuffle(self, recursive=False):
|
|
2515
|
+
def shuffle(self, recursive: bool = False) -> None:
|
|
2457
2516
|
"""Shuffles the list of :attr:`submobjects`."""
|
|
2458
2517
|
if recursive:
|
|
2459
2518
|
for submob in self.submobjects:
|
|
2460
2519
|
submob.shuffle(recursive=True)
|
|
2461
2520
|
random.shuffle(self.submobjects)
|
|
2462
2521
|
|
|
2463
|
-
def invert(self, recursive=False):
|
|
2522
|
+
def invert(self, recursive: bool = False) -> None:
|
|
2464
2523
|
"""Inverts the list of :attr:`submobjects`.
|
|
2465
2524
|
|
|
2466
2525
|
Parameters
|
|
@@ -2484,10 +2543,10 @@ class Mobject:
|
|
|
2484
2543
|
if recursive:
|
|
2485
2544
|
for submob in self.submobjects:
|
|
2486
2545
|
submob.invert(recursive=True)
|
|
2487
|
-
|
|
2546
|
+
self.submobjects.reverse()
|
|
2488
2547
|
|
|
2489
2548
|
# Just here to keep from breaking old scenes.
|
|
2490
|
-
def arrange_submobjects(self, *args, **kwargs):
|
|
2549
|
+
def arrange_submobjects(self, *args, **kwargs) -> Self:
|
|
2491
2550
|
"""Arrange the position of :attr:`submobjects` with a small buffer.
|
|
2492
2551
|
|
|
2493
2552
|
Examples
|
|
@@ -2508,11 +2567,11 @@ class Mobject:
|
|
|
2508
2567
|
"""
|
|
2509
2568
|
return self.arrange(*args, **kwargs)
|
|
2510
2569
|
|
|
2511
|
-
def sort_submobjects(self, *args, **kwargs):
|
|
2570
|
+
def sort_submobjects(self, *args, **kwargs) -> Self:
|
|
2512
2571
|
"""Sort the :attr:`submobjects`"""
|
|
2513
2572
|
return self.sort(*args, **kwargs)
|
|
2514
2573
|
|
|
2515
|
-
def shuffle_submobjects(self, *args, **kwargs):
|
|
2574
|
+
def shuffle_submobjects(self, *args, **kwargs) -> None:
|
|
2516
2575
|
"""Shuffles the order of :attr:`submobjects`
|
|
2517
2576
|
|
|
2518
2577
|
Examples
|
|
@@ -2531,7 +2590,7 @@ class Mobject:
|
|
|
2531
2590
|
return self.shuffle(*args, **kwargs)
|
|
2532
2591
|
|
|
2533
2592
|
# Alignment
|
|
2534
|
-
def align_data(self, mobject: Mobject, skip_point_alignment: bool = False):
|
|
2593
|
+
def align_data(self, mobject: Mobject, skip_point_alignment: bool = False) -> None:
|
|
2535
2594
|
"""Aligns the data of this mobject with another mobject.
|
|
2536
2595
|
|
|
2537
2596
|
Afterwards, the two mobjects will have the same number of submobjects
|
|
@@ -2562,7 +2621,7 @@ class Mobject:
|
|
|
2562
2621
|
msg = f"get_point_mobject not implemented for {self.__class__.__name__}"
|
|
2563
2622
|
raise NotImplementedError(msg)
|
|
2564
2623
|
|
|
2565
|
-
def align_points(self, mobject):
|
|
2624
|
+
def align_points(self, mobject: Mobject) -> Self:
|
|
2566
2625
|
count1 = self.get_num_points()
|
|
2567
2626
|
count2 = mobject.get_num_points()
|
|
2568
2627
|
if count1 < count2:
|
|
@@ -2571,10 +2630,10 @@ class Mobject:
|
|
|
2571
2630
|
mobject.align_points_with_larger(self)
|
|
2572
2631
|
return self
|
|
2573
2632
|
|
|
2574
|
-
def align_points_with_larger(self, larger_mobject):
|
|
2633
|
+
def align_points_with_larger(self, larger_mobject: Mobject):
|
|
2575
2634
|
raise NotImplementedError("Please override in a child class.")
|
|
2576
2635
|
|
|
2577
|
-
def align_submobjects(self, mobject):
|
|
2636
|
+
def align_submobjects(self, mobject: Mobject) -> Self:
|
|
2578
2637
|
mob1 = self
|
|
2579
2638
|
mob2 = mobject
|
|
2580
2639
|
n1 = len(mob1.submobjects)
|
|
@@ -2599,14 +2658,14 @@ class Mobject:
|
|
|
2599
2658
|
m2.push_self_into_submobjects()
|
|
2600
2659
|
return self
|
|
2601
2660
|
|
|
2602
|
-
def push_self_into_submobjects(self):
|
|
2661
|
+
def push_self_into_submobjects(self) -> Self:
|
|
2603
2662
|
copy = self.copy()
|
|
2604
2663
|
copy.submobjects = []
|
|
2605
2664
|
self.reset_points()
|
|
2606
2665
|
self.add(copy)
|
|
2607
2666
|
return self
|
|
2608
2667
|
|
|
2609
|
-
def add_n_more_submobjects(self, n):
|
|
2668
|
+
def add_n_more_submobjects(self, n: int) -> Self | None:
|
|
2610
2669
|
if n == 0:
|
|
2611
2670
|
return
|
|
2612
2671
|
|
|
@@ -2629,10 +2688,16 @@ class Mobject:
|
|
|
2629
2688
|
self.submobjects = new_submobs
|
|
2630
2689
|
return self
|
|
2631
2690
|
|
|
2632
|
-
def repeat_submobject(self, submob):
|
|
2691
|
+
def repeat_submobject(self, submob: Mobject) -> Self:
|
|
2633
2692
|
return submob.copy()
|
|
2634
2693
|
|
|
2635
|
-
def interpolate(
|
|
2694
|
+
def interpolate(
|
|
2695
|
+
self,
|
|
2696
|
+
mobject1: Mobject,
|
|
2697
|
+
mobject2: Mobject,
|
|
2698
|
+
alpha: float,
|
|
2699
|
+
path_func: PathFuncType = straight_path(),
|
|
2700
|
+
) -> Self:
|
|
2636
2701
|
"""Turns this :class:`~.Mobject` into an interpolation between ``mobject1``
|
|
2637
2702
|
and ``mobject2``.
|
|
2638
2703
|
|
|
@@ -2657,7 +2722,7 @@ class Mobject:
|
|
|
2657
2722
|
self.interpolate_color(mobject1, mobject2, alpha)
|
|
2658
2723
|
return self
|
|
2659
2724
|
|
|
2660
|
-
def interpolate_color(self, mobject1, mobject2, alpha):
|
|
2725
|
+
def interpolate_color(self, mobject1: Mobject, mobject2: Mobject, alpha: float):
|
|
2661
2726
|
raise NotImplementedError("Please override in a child class.")
|
|
2662
2727
|
|
|
2663
2728
|
def become(
|
|
@@ -2669,7 +2734,7 @@ class Mobject:
|
|
|
2669
2734
|
match_depth: bool = False,
|
|
2670
2735
|
match_center: bool = False,
|
|
2671
2736
|
stretch: bool = False,
|
|
2672
|
-
):
|
|
2737
|
+
) -> Self:
|
|
2673
2738
|
"""Edit points, colors and submobjects to be identical
|
|
2674
2739
|
to another :class:`~.Mobject`
|
|
2675
2740
|
|
|
@@ -2726,7 +2791,7 @@ class Mobject:
|
|
|
2726
2791
|
sm1.interpolate_color(sm1, sm2, 1)
|
|
2727
2792
|
return self
|
|
2728
2793
|
|
|
2729
|
-
def match_points(self, mobject: Mobject, copy_submobjects: bool = True):
|
|
2794
|
+
def match_points(self, mobject: Mobject, copy_submobjects: bool = True) -> Self:
|
|
2730
2795
|
"""Edit points, positions, and submobjects to be identical
|
|
2731
2796
|
to another :class:`~.Mobject`, while keeping the style unchanged.
|
|
2732
2797
|
|
|
@@ -2748,7 +2813,7 @@ class Mobject:
|
|
|
2748
2813
|
return self
|
|
2749
2814
|
|
|
2750
2815
|
# Errors
|
|
2751
|
-
def throw_error_if_no_points(self):
|
|
2816
|
+
def throw_error_if_no_points(self) -> None:
|
|
2752
2817
|
if self.has_no_points():
|
|
2753
2818
|
caller_name = sys._getframe(1).f_code.co_name
|
|
2754
2819
|
raise Exception(
|
|
@@ -2760,7 +2825,7 @@ class Mobject:
|
|
|
2760
2825
|
self,
|
|
2761
2826
|
z_index_value: float,
|
|
2762
2827
|
family: bool = True,
|
|
2763
|
-
) ->
|
|
2828
|
+
) -> T:
|
|
2764
2829
|
"""Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`.
|
|
2765
2830
|
|
|
2766
2831
|
Parameters
|
|
@@ -2799,8 +2864,8 @@ class Mobject:
|
|
|
2799
2864
|
self.z_index = z_index_value
|
|
2800
2865
|
return self
|
|
2801
2866
|
|
|
2802
|
-
def
|
|
2803
|
-
"""Sets the :class:`~.Mobject`'s z
|
|
2867
|
+
def set_z_index_by_z_Point3D(self) -> Self:
|
|
2868
|
+
"""Sets the :class:`~.Mobject`'s z Point3D to the value of :attr:`z_index`.
|
|
2804
2869
|
|
|
2805
2870
|
Returns
|
|
2806
2871
|
-------
|
|
@@ -2822,13 +2887,13 @@ class Group(Mobject, metaclass=ConvertToOpenGL):
|
|
|
2822
2887
|
be added to the group.
|
|
2823
2888
|
"""
|
|
2824
2889
|
|
|
2825
|
-
def __init__(self, *mobjects, **kwargs):
|
|
2890
|
+
def __init__(self, *mobjects, **kwargs) -> None:
|
|
2826
2891
|
super().__init__(**kwargs)
|
|
2827
2892
|
self.add(*mobjects)
|
|
2828
2893
|
|
|
2829
2894
|
|
|
2830
2895
|
class _AnimationBuilder:
|
|
2831
|
-
def __init__(self, mobject):
|
|
2896
|
+
def __init__(self, mobject) -> None:
|
|
2832
2897
|
self.mobject = mobject
|
|
2833
2898
|
self.mobject.generate_target()
|
|
2834
2899
|
|
|
@@ -2840,7 +2905,7 @@ class _AnimationBuilder:
|
|
|
2840
2905
|
self.cannot_pass_args = False
|
|
2841
2906
|
self.anim_args = {}
|
|
2842
2907
|
|
|
2843
|
-
def __call__(self, **kwargs):
|
|
2908
|
+
def __call__(self, **kwargs) -> Self:
|
|
2844
2909
|
if self.cannot_pass_args:
|
|
2845
2910
|
raise ValueError(
|
|
2846
2911
|
"Animation arguments must be passed before accessing methods and can only be passed once",
|
|
@@ -2851,7 +2916,7 @@ class _AnimationBuilder:
|
|
|
2851
2916
|
|
|
2852
2917
|
return self
|
|
2853
2918
|
|
|
2854
|
-
def __getattr__(self, method_name):
|
|
2919
|
+
def __getattr__(self, method_name) -> types.MethodType:
|
|
2855
2920
|
method = getattr(self.mobject.target, method_name)
|
|
2856
2921
|
has_overridden_animation = hasattr(method, "_override_animate")
|
|
2857
2922
|
|
|
@@ -2879,8 +2944,10 @@ class _AnimationBuilder:
|
|
|
2879
2944
|
|
|
2880
2945
|
return update_target
|
|
2881
2946
|
|
|
2882
|
-
def build(self):
|
|
2883
|
-
from ..animation.transform import
|
|
2947
|
+
def build(self) -> Animation:
|
|
2948
|
+
from ..animation.transform import ( # is this to prevent circular import?
|
|
2949
|
+
_MethodAnimation,
|
|
2950
|
+
)
|
|
2884
2951
|
|
|
2885
2952
|
if self.overridden_animation:
|
|
2886
2953
|
anim = self.overridden_animation
|
|
@@ -2893,7 +2960,7 @@ class _AnimationBuilder:
|
|
|
2893
2960
|
return anim
|
|
2894
2961
|
|
|
2895
2962
|
|
|
2896
|
-
def override_animate(method):
|
|
2963
|
+
def override_animate(method) -> types.FunctionType:
|
|
2897
2964
|
r"""Decorator for overriding method animations.
|
|
2898
2965
|
|
|
2899
2966
|
This allows to specify a method (returning an :class:`~.Animation`)
|