manim 0.18.1__py3-none-any.whl → 0.19.0__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/__main__.py +45 -12
- manim/_config/__init__.py +2 -2
- manim/_config/cli_colors.py +8 -4
- manim/_config/default.cfg +0 -2
- manim/_config/logger_utils.py +5 -0
- manim/_config/utils.py +29 -38
- manim/animation/animation.py +148 -8
- manim/animation/composition.py +16 -13
- manim/animation/creation.py +184 -8
- manim/animation/fading.py +5 -8
- manim/animation/indication.py +93 -26
- manim/animation/movement.py +21 -3
- manim/animation/rotation.py +2 -1
- manim/animation/specialized.py +3 -5
- manim/animation/speedmodifier.py +3 -3
- manim/animation/transform.py +4 -5
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +2 -2
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +52 -36
- manim/cli/checkhealth/checks.py +92 -76
- manim/cli/checkhealth/commands.py +12 -5
- manim/cli/default_group.py +148 -24
- manim/cli/init/commands.py +28 -23
- manim/cli/plugins/commands.py +13 -3
- manim/cli/render/commands.py +47 -42
- manim/cli/render/global_options.py +43 -9
- manim/cli/render/render_options.py +84 -19
- manim/constants.py +11 -4
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +109 -75
- manim/mobject/geometry/boolean_ops.py +20 -17
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +120 -60
- manim/mobject/geometry/polygram.py +109 -25
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +36 -27
- manim/mobject/graph.py +48 -40
- manim/mobject/graphing/coordinate_systems.py +110 -45
- manim/mobject/graphing/functions.py +16 -10
- manim/mobject/graphing/number_line.py +23 -9
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +149 -103
- manim/mobject/opengl/opengl_geometry.py +4 -8
- manim/mobject/opengl/opengl_mobject.py +506 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
- manim/mobject/opengl/opengl_surface.py +1 -2
- manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
- manim/mobject/svg/brace.py +61 -13
- manim/mobject/svg/svg_mobject.py +2 -1
- manim/mobject/table.py +11 -12
- manim/mobject/text/code_mobject.py +186 -550
- manim/mobject/text/numbers.py +7 -7
- manim/mobject/text/tex_mobject.py +22 -13
- manim/mobject/text/text_mobject.py +29 -20
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_dimensions.py +59 -31
- manim/mobject/types/image_mobject.py +37 -23
- manim/mobject/types/point_cloud_mobject.py +103 -67
- manim/mobject/types/vectorized_mobject.py +387 -214
- manim/mobject/value_tracker.py +2 -1
- manim/mobject/vector_field.py +2 -4
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +2 -3
- manim/plugins/plugins_flags.py +3 -3
- manim/renderer/cairo_renderer.py +11 -11
- manim/renderer/opengl_renderer.py +19 -20
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +3 -2
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +72 -41
- manim/scene/scene_file_writer.py +313 -164
- manim/scene/section.py +15 -15
- manim/scene/three_d_scene.py +8 -15
- manim/scene/vector_space_scene.py +3 -6
- manim/typing.py +326 -66
- manim/utils/bezier.py +1658 -381
- manim/utils/caching.py +11 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +2 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +2 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +818 -301
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +40 -19
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -6
- manim/utils/deprecation.py +92 -43
- manim/utils/docbuild/autoaliasattr_directive.py +45 -8
- manim/utils/docbuild/autocolor_directive.py +12 -13
- manim/utils/docbuild/manim_directive.py +35 -29
- manim/utils/docbuild/module_parsing.py +74 -27
- manim/utils/family.py +3 -3
- manim/utils/family_ops.py +12 -4
- manim/utils/file_ops.py +22 -16
- manim/utils/hashing.py +7 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +12 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +55 -19
- manim/utils/opengl.py +68 -23
- manim/utils/parameter_parsing.py +3 -2
- manim/utils/paths.py +11 -5
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +69 -32
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +48 -37
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +20 -14
- manim/utils/tex.py +4 -2
- manim/utils/tex_file_writing.py +45 -45
- manim/utils/tex_templates.py +1 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim-0.18.1.dist-info/RECORD +0 -217
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/animation/creation.py
CHANGED
|
@@ -70,17 +70,22 @@ __all__ = [
|
|
|
70
70
|
"RemoveTextLetterByLetter",
|
|
71
71
|
"ShowSubmobjectsOneByOne",
|
|
72
72
|
"AddTextWordByWord",
|
|
73
|
+
"TypeWithCursor",
|
|
74
|
+
"UntypeWithCursor",
|
|
73
75
|
]
|
|
74
76
|
|
|
75
77
|
|
|
76
78
|
import itertools as it
|
|
77
|
-
from
|
|
79
|
+
from collections.abc import Iterable, Sequence
|
|
80
|
+
from typing import TYPE_CHECKING, Callable
|
|
78
81
|
|
|
79
82
|
import numpy as np
|
|
80
83
|
|
|
81
84
|
if TYPE_CHECKING:
|
|
82
85
|
from manim.mobject.text.text_mobject import Text
|
|
86
|
+
from manim.scene.scene import Scene
|
|
83
87
|
|
|
88
|
+
from manim.constants import RIGHT, TAU
|
|
84
89
|
from manim.mobject.opengl.opengl_surface import OpenGLSurface
|
|
85
90
|
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
|
|
86
91
|
from manim.utils.color import ManimColor
|
|
@@ -88,7 +93,6 @@ from manim.utils.color import ManimColor
|
|
|
88
93
|
from .. import config
|
|
89
94
|
from ..animation.animation import Animation
|
|
90
95
|
from ..animation.composition import Succession
|
|
91
|
-
from ..constants import TAU
|
|
92
96
|
from ..mobject.mobject import Group, Mobject
|
|
93
97
|
from ..mobject.types.vectorized_mobject import VMobject
|
|
94
98
|
from ..utils.bezier import integer_interpolate
|
|
@@ -246,7 +250,9 @@ class DrawBorderThenFill(Animation):
|
|
|
246
250
|
|
|
247
251
|
def _typecheck_input(self, vmobject: VMobject | OpenGLVMobject) -> None:
|
|
248
252
|
if not isinstance(vmobject, (VMobject, OpenGLVMobject)):
|
|
249
|
-
raise TypeError(
|
|
253
|
+
raise TypeError(
|
|
254
|
+
f"{self.__class__.__name__} only works for vectorized Mobjects"
|
|
255
|
+
)
|
|
250
256
|
|
|
251
257
|
def begin(self) -> None:
|
|
252
258
|
self.outline = self.get_outline()
|
|
@@ -277,7 +283,7 @@ class DrawBorderThenFill(Animation):
|
|
|
277
283
|
alpha: float,
|
|
278
284
|
) -> None: # Fixme: not matching the parent class? What is outline doing here?
|
|
279
285
|
index: int
|
|
280
|
-
subalpha:
|
|
286
|
+
subalpha: float
|
|
281
287
|
index, subalpha = integer_interpolate(0, 2, alpha)
|
|
282
288
|
if index == 0:
|
|
283
289
|
submobject.pointwise_become_partial(outline, 0, subalpha)
|
|
@@ -347,10 +353,7 @@ class Write(DrawBorderThenFill):
|
|
|
347
353
|
) -> tuple[float, float]:
|
|
348
354
|
length = len(vmobject.family_members_with_points())
|
|
349
355
|
if run_time is None:
|
|
350
|
-
if length < 15
|
|
351
|
-
run_time = 1
|
|
352
|
-
else:
|
|
353
|
-
run_time = 2
|
|
356
|
+
run_time = 1 if length < 15 else 2
|
|
354
357
|
if lag_ratio is None:
|
|
355
358
|
lag_ratio = min(4.0 / max(1.0, length), 0.2)
|
|
356
359
|
return run_time, lag_ratio
|
|
@@ -674,3 +677,176 @@ class AddTextWordByWord(Succession):
|
|
|
674
677
|
)
|
|
675
678
|
)
|
|
676
679
|
super().__init__(*anims, **kwargs)
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
class TypeWithCursor(AddTextLetterByLetter):
|
|
683
|
+
"""Similar to :class:`~.AddTextLetterByLetter` , but with an additional cursor mobject at the end.
|
|
684
|
+
|
|
685
|
+
Parameters
|
|
686
|
+
----------
|
|
687
|
+
time_per_char
|
|
688
|
+
Frequency of appearance of the letters.
|
|
689
|
+
cursor
|
|
690
|
+
:class:`~.Mobject` shown after the last added letter.
|
|
691
|
+
buff
|
|
692
|
+
Controls how far away the cursor is to the right of the last added letter.
|
|
693
|
+
keep_cursor_y
|
|
694
|
+
If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter.
|
|
695
|
+
leave_cursor_on
|
|
696
|
+
Whether to show the cursor after the animation.
|
|
697
|
+
|
|
698
|
+
.. tip::
|
|
699
|
+
This is currently only possible for class:`~.Text` and not for class:`~.MathTex`.
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
Examples
|
|
703
|
+
--------
|
|
704
|
+
|
|
705
|
+
.. manim:: InsertingTextExample
|
|
706
|
+
:ref_classes: Blink
|
|
707
|
+
|
|
708
|
+
class InsertingTextExample(Scene):
|
|
709
|
+
def construct(self):
|
|
710
|
+
text = Text("Inserting", color=PURPLE).scale(1.5).to_edge(LEFT)
|
|
711
|
+
cursor = Rectangle(
|
|
712
|
+
color = GREY_A,
|
|
713
|
+
fill_color = GREY_A,
|
|
714
|
+
fill_opacity = 1.0,
|
|
715
|
+
height = 1.1,
|
|
716
|
+
width = 0.5,
|
|
717
|
+
).move_to(text[0]) # Position the cursor
|
|
718
|
+
|
|
719
|
+
self.play(TypeWithCursor(text, cursor))
|
|
720
|
+
self.play(Blink(cursor, blinks=2))
|
|
721
|
+
|
|
722
|
+
"""
|
|
723
|
+
|
|
724
|
+
def __init__(
|
|
725
|
+
self,
|
|
726
|
+
text: Text,
|
|
727
|
+
cursor: Mobject,
|
|
728
|
+
buff: float = 0.1,
|
|
729
|
+
keep_cursor_y: bool = True,
|
|
730
|
+
leave_cursor_on: bool = True,
|
|
731
|
+
time_per_char: float = 0.1,
|
|
732
|
+
reverse_rate_function=False,
|
|
733
|
+
introducer=True,
|
|
734
|
+
**kwargs,
|
|
735
|
+
) -> None:
|
|
736
|
+
self.cursor = cursor
|
|
737
|
+
self.buff = buff
|
|
738
|
+
self.keep_cursor_y = keep_cursor_y
|
|
739
|
+
self.leave_cursor_on = leave_cursor_on
|
|
740
|
+
super().__init__(
|
|
741
|
+
text,
|
|
742
|
+
time_per_char=time_per_char,
|
|
743
|
+
reverse_rate_function=reverse_rate_function,
|
|
744
|
+
introducer=introducer,
|
|
745
|
+
**kwargs,
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
def begin(self) -> None:
|
|
749
|
+
self.y_cursor = self.cursor.get_y()
|
|
750
|
+
self.cursor.initial_position = self.mobject.get_center()
|
|
751
|
+
if self.keep_cursor_y:
|
|
752
|
+
self.cursor.set_y(self.y_cursor)
|
|
753
|
+
|
|
754
|
+
self.cursor.set_opacity(0)
|
|
755
|
+
self.mobject.add(self.cursor)
|
|
756
|
+
super().begin()
|
|
757
|
+
|
|
758
|
+
def finish(self) -> None:
|
|
759
|
+
if self.leave_cursor_on:
|
|
760
|
+
self.cursor.set_opacity(1)
|
|
761
|
+
else:
|
|
762
|
+
self.cursor.set_opacity(0)
|
|
763
|
+
self.mobject.remove(self.cursor)
|
|
764
|
+
super().finish()
|
|
765
|
+
|
|
766
|
+
def clean_up_from_scene(self, scene: Scene) -> None:
|
|
767
|
+
if not self.leave_cursor_on:
|
|
768
|
+
scene.remove(self.cursor)
|
|
769
|
+
super().clean_up_from_scene(scene)
|
|
770
|
+
|
|
771
|
+
def update_submobject_list(self, index: int) -> None:
|
|
772
|
+
for mobj in self.all_submobs[:index]:
|
|
773
|
+
mobj.set_opacity(1)
|
|
774
|
+
|
|
775
|
+
for mobj in self.all_submobs[index:]:
|
|
776
|
+
mobj.set_opacity(0)
|
|
777
|
+
|
|
778
|
+
if index != 0:
|
|
779
|
+
self.cursor.next_to(
|
|
780
|
+
self.all_submobs[index - 1], RIGHT, buff=self.buff
|
|
781
|
+
).set_y(self.cursor.initial_position[1])
|
|
782
|
+
else:
|
|
783
|
+
self.cursor.move_to(self.all_submobs[0]).set_y(
|
|
784
|
+
self.cursor.initial_position[1]
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
if self.keep_cursor_y:
|
|
788
|
+
self.cursor.set_y(self.y_cursor)
|
|
789
|
+
self.cursor.set_opacity(1)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
class UntypeWithCursor(TypeWithCursor):
|
|
793
|
+
"""Similar to :class:`~.RemoveTextLetterByLetter` , but with an additional cursor mobject at the end.
|
|
794
|
+
|
|
795
|
+
Parameters
|
|
796
|
+
----------
|
|
797
|
+
time_per_char
|
|
798
|
+
Frequency of appearance of the letters.
|
|
799
|
+
cursor
|
|
800
|
+
:class:`~.Mobject` shown after the last added letter.
|
|
801
|
+
buff
|
|
802
|
+
Controls how far away the cursor is to the right of the last added letter.
|
|
803
|
+
keep_cursor_y
|
|
804
|
+
If ``True``, the cursor's y-coordinate is set to the center of the ``Text`` and remains the same throughout the animation. Otherwise, it is set to the center of the last added letter.
|
|
805
|
+
leave_cursor_on
|
|
806
|
+
Whether to show the cursor after the animation.
|
|
807
|
+
|
|
808
|
+
.. tip::
|
|
809
|
+
This is currently only possible for class:`~.Text` and not for class:`~.MathTex`.
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
Examples
|
|
813
|
+
--------
|
|
814
|
+
|
|
815
|
+
.. manim:: DeletingTextExample
|
|
816
|
+
:ref_classes: Blink
|
|
817
|
+
|
|
818
|
+
class DeletingTextExample(Scene):
|
|
819
|
+
def construct(self):
|
|
820
|
+
text = Text("Deleting", color=PURPLE).scale(1.5).to_edge(LEFT)
|
|
821
|
+
cursor = Rectangle(
|
|
822
|
+
color = GREY_A,
|
|
823
|
+
fill_color = GREY_A,
|
|
824
|
+
fill_opacity = 1.0,
|
|
825
|
+
height = 1.1,
|
|
826
|
+
width = 0.5,
|
|
827
|
+
).move_to(text[0]) # Position the cursor
|
|
828
|
+
|
|
829
|
+
self.play(UntypeWithCursor(text, cursor))
|
|
830
|
+
self.play(Blink(cursor, blinks=2))
|
|
831
|
+
|
|
832
|
+
"""
|
|
833
|
+
|
|
834
|
+
def __init__(
|
|
835
|
+
self,
|
|
836
|
+
text: Text,
|
|
837
|
+
cursor: VMobject | None = None,
|
|
838
|
+
time_per_char: float = 0.1,
|
|
839
|
+
reverse_rate_function=True,
|
|
840
|
+
introducer=False,
|
|
841
|
+
remover=True,
|
|
842
|
+
**kwargs,
|
|
843
|
+
) -> None:
|
|
844
|
+
super().__init__(
|
|
845
|
+
text,
|
|
846
|
+
cursor=cursor,
|
|
847
|
+
time_per_char=time_per_char,
|
|
848
|
+
reverse_rate_function=reverse_rate_function,
|
|
849
|
+
introducer=introducer,
|
|
850
|
+
remover=remover,
|
|
851
|
+
**kwargs,
|
|
852
|
+
)
|
manim/animation/fading.py
CHANGED
|
@@ -57,10 +57,7 @@ class _Fade(Transform):
|
|
|
57
57
|
) -> None:
|
|
58
58
|
if not mobjects:
|
|
59
59
|
raise ValueError("At least one mobject must be passed.")
|
|
60
|
-
if len(mobjects) == 1
|
|
61
|
-
mobject = mobjects[0]
|
|
62
|
-
else:
|
|
63
|
-
mobject = Group(*mobjects)
|
|
60
|
+
mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects)
|
|
64
61
|
|
|
65
62
|
self.point_target = False
|
|
66
63
|
if shift is None:
|
|
@@ -97,7 +94,7 @@ class _Fade(Transform):
|
|
|
97
94
|
|
|
98
95
|
|
|
99
96
|
class FadeIn(_Fade):
|
|
100
|
-
"""Fade in :class:`~.Mobject` s.
|
|
97
|
+
r"""Fade in :class:`~.Mobject` s.
|
|
101
98
|
|
|
102
99
|
Parameters
|
|
103
100
|
----------
|
|
@@ -122,7 +119,7 @@ class FadeIn(_Fade):
|
|
|
122
119
|
dot = Dot(UP * 2 + LEFT)
|
|
123
120
|
self.add(dot)
|
|
124
121
|
tex = Tex(
|
|
125
|
-
"FadeIn with ", "shift ", " or target
|
|
122
|
+
"FadeIn with ", "shift ", r" or target\_position", " and scale"
|
|
126
123
|
).scale(1)
|
|
127
124
|
animations = [
|
|
128
125
|
FadeIn(tex[0]),
|
|
@@ -145,7 +142,7 @@ class FadeIn(_Fade):
|
|
|
145
142
|
|
|
146
143
|
|
|
147
144
|
class FadeOut(_Fade):
|
|
148
|
-
"""Fade out :class:`~.Mobject` s.
|
|
145
|
+
r"""Fade out :class:`~.Mobject` s.
|
|
149
146
|
|
|
150
147
|
Parameters
|
|
151
148
|
----------
|
|
@@ -169,7 +166,7 @@ class FadeOut(_Fade):
|
|
|
169
166
|
dot = Dot(UP * 2 + LEFT)
|
|
170
167
|
self.add(dot)
|
|
171
168
|
tex = Tex(
|
|
172
|
-
"FadeOut with ", "shift ", " or target
|
|
169
|
+
"FadeOut with ", "shift ", r" or target\_position", " and scale"
|
|
173
170
|
).scale(1)
|
|
174
171
|
animations = [
|
|
175
172
|
FadeOut(tex[0]),
|
manim/animation/indication.py
CHANGED
|
@@ -25,6 +25,8 @@ Examples
|
|
|
25
25
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
28
30
|
__all__ = [
|
|
29
31
|
"FocusOn",
|
|
30
32
|
"Indicate",
|
|
@@ -34,9 +36,11 @@ __all__ = [
|
|
|
34
36
|
"ApplyWave",
|
|
35
37
|
"Circumscribe",
|
|
36
38
|
"Wiggle",
|
|
39
|
+
"Blink",
|
|
37
40
|
]
|
|
38
41
|
|
|
39
|
-
from
|
|
42
|
+
from collections.abc import Iterable
|
|
43
|
+
from typing import Callable
|
|
40
44
|
|
|
41
45
|
import numpy as np
|
|
42
46
|
|
|
@@ -53,12 +57,12 @@ from ..animation.creation import Create, ShowPartial, Uncreate
|
|
|
53
57
|
from ..animation.fading import FadeIn, FadeOut
|
|
54
58
|
from ..animation.movement import Homotopy
|
|
55
59
|
from ..animation.transform import Transform
|
|
60
|
+
from ..animation.updaters.update import UpdateFromFunc
|
|
56
61
|
from ..constants import *
|
|
57
62
|
from ..mobject.mobject import Mobject
|
|
58
63
|
from ..mobject.types.vectorized_mobject import VGroup, VMobject
|
|
59
64
|
from ..utils.bezier import interpolate, inverse_interpolate
|
|
60
65
|
from ..utils.color import GREY, YELLOW, ParsableManimColor
|
|
61
|
-
from ..utils.deprecation import deprecated
|
|
62
66
|
from ..utils.rate_functions import smooth, there_and_back, wiggle
|
|
63
67
|
from ..utils.space_ops import normalize
|
|
64
68
|
|
|
@@ -76,8 +80,6 @@ class FocusOn(Transform):
|
|
|
76
80
|
The color of the spotlight.
|
|
77
81
|
run_time
|
|
78
82
|
The duration of the animation.
|
|
79
|
-
kwargs
|
|
80
|
-
Additional arguments to be passed to the :class:`~.Succession` constructor
|
|
81
83
|
|
|
82
84
|
Examples
|
|
83
85
|
--------
|
|
@@ -93,11 +95,11 @@ class FocusOn(Transform):
|
|
|
93
95
|
|
|
94
96
|
def __init__(
|
|
95
97
|
self,
|
|
96
|
-
focus_point:
|
|
98
|
+
focus_point: np.ndarray | Mobject,
|
|
97
99
|
opacity: float = 0.2,
|
|
98
100
|
color: str = GREY,
|
|
99
101
|
run_time: float = 2,
|
|
100
|
-
**kwargs
|
|
102
|
+
**kwargs,
|
|
101
103
|
) -> None:
|
|
102
104
|
self.focus_point = focus_point
|
|
103
105
|
self.color = color
|
|
@@ -150,8 +152,8 @@ class Indicate(Transform):
|
|
|
150
152
|
mobject: Mobject,
|
|
151
153
|
scale_factor: float = 1.2,
|
|
152
154
|
color: str = YELLOW,
|
|
153
|
-
rate_func: Callable[[float,
|
|
154
|
-
**kwargs
|
|
155
|
+
rate_func: Callable[[float, float | None], np.ndarray] = there_and_back,
|
|
156
|
+
**kwargs,
|
|
155
157
|
) -> None:
|
|
156
158
|
self.color = color
|
|
157
159
|
self.scale_factor = scale_factor
|
|
@@ -217,7 +219,7 @@ class Flash(AnimationGroup):
|
|
|
217
219
|
|
|
218
220
|
def __init__(
|
|
219
221
|
self,
|
|
220
|
-
point:
|
|
222
|
+
point: np.ndarray | Mobject,
|
|
221
223
|
line_length: float = 0.2,
|
|
222
224
|
num_lines: int = 12,
|
|
223
225
|
flash_radius: float = 0.1,
|
|
@@ -225,7 +227,7 @@ class Flash(AnimationGroup):
|
|
|
225
227
|
color: str = YELLOW,
|
|
226
228
|
time_width: float = 1,
|
|
227
229
|
run_time: float = 1.0,
|
|
228
|
-
**kwargs
|
|
230
|
+
**kwargs,
|
|
229
231
|
) -> None:
|
|
230
232
|
if isinstance(point, Mobject):
|
|
231
233
|
self.point = point.get_center()
|
|
@@ -255,7 +257,7 @@ class Flash(AnimationGroup):
|
|
|
255
257
|
lines.set_stroke(width=self.line_stroke_width)
|
|
256
258
|
return lines
|
|
257
259
|
|
|
258
|
-
def create_line_anims(self) -> Iterable[
|
|
260
|
+
def create_line_anims(self) -> Iterable[ShowPassingFlash]:
|
|
259
261
|
return [
|
|
260
262
|
ShowPassingFlash(
|
|
261
263
|
line,
|
|
@@ -268,7 +270,7 @@ class Flash(AnimationGroup):
|
|
|
268
270
|
|
|
269
271
|
|
|
270
272
|
class ShowPassingFlash(ShowPartial):
|
|
271
|
-
"""Show only a sliver of the VMobject each frame.
|
|
273
|
+
r"""Show only a sliver of the VMobject each frame.
|
|
272
274
|
|
|
273
275
|
Parameters
|
|
274
276
|
----------
|
|
@@ -288,7 +290,7 @@ class ShowPassingFlash(ShowPartial):
|
|
|
288
290
|
self.add(p, lbl)
|
|
289
291
|
p = p.copy().set_color(BLUE)
|
|
290
292
|
for time_width in [0.2, 0.5, 1, 2]:
|
|
291
|
-
lbl.become(Tex(r"
|
|
293
|
+
lbl.become(Tex(r"\texttt{time\_width={{%.1f}}}"%time_width))
|
|
292
294
|
self.play(ShowPassingFlash(
|
|
293
295
|
p.copy().set_color(BLUE),
|
|
294
296
|
run_time=2,
|
|
@@ -301,11 +303,11 @@ class ShowPassingFlash(ShowPartial):
|
|
|
301
303
|
|
|
302
304
|
"""
|
|
303
305
|
|
|
304
|
-
def __init__(self, mobject:
|
|
306
|
+
def __init__(self, mobject: VMobject, time_width: float = 0.1, **kwargs) -> None:
|
|
305
307
|
self.time_width = time_width
|
|
306
308
|
super().__init__(mobject, remover=True, introducer=True, **kwargs)
|
|
307
309
|
|
|
308
|
-
def _get_bounds(self, alpha: float) ->
|
|
310
|
+
def _get_bounds(self, alpha: float) -> tuple[float]:
|
|
309
311
|
tw = self.time_width
|
|
310
312
|
upper = interpolate(0, 1 + tw, alpha)
|
|
311
313
|
lower = upper - tw
|
|
@@ -393,7 +395,7 @@ class ApplyWave(Homotopy):
|
|
|
393
395
|
time_width: float = 1,
|
|
394
396
|
ripples: int = 1,
|
|
395
397
|
run_time: float = 2,
|
|
396
|
-
**kwargs
|
|
398
|
+
**kwargs,
|
|
397
399
|
) -> None:
|
|
398
400
|
x_min = mobject.get_left()[0]
|
|
399
401
|
x_max = mobject.get_right()[0]
|
|
@@ -459,7 +461,7 @@ class ApplyWave(Homotopy):
|
|
|
459
461
|
y: float,
|
|
460
462
|
z: float,
|
|
461
463
|
t: float,
|
|
462
|
-
) ->
|
|
464
|
+
) -> tuple[float, float, float]:
|
|
463
465
|
upper = interpolate(0, 1 + time_width, t)
|
|
464
466
|
lower = upper - time_width
|
|
465
467
|
relative_x = inverse_interpolate(x_min, x_max, x)
|
|
@@ -509,10 +511,10 @@ class Wiggle(Animation):
|
|
|
509
511
|
scale_value: float = 1.1,
|
|
510
512
|
rotation_angle: float = 0.01 * TAU,
|
|
511
513
|
n_wiggles: int = 6,
|
|
512
|
-
scale_about_point:
|
|
513
|
-
rotate_about_point:
|
|
514
|
+
scale_about_point: np.ndarray | None = None,
|
|
515
|
+
rotate_about_point: np.ndarray | None = None,
|
|
514
516
|
run_time: float = 2,
|
|
515
|
-
**kwargs
|
|
517
|
+
**kwargs,
|
|
516
518
|
) -> None:
|
|
517
519
|
self.scale_value = scale_value
|
|
518
520
|
self.rotation_angle = rotation_angle
|
|
@@ -549,7 +551,7 @@ class Wiggle(Animation):
|
|
|
549
551
|
|
|
550
552
|
|
|
551
553
|
class Circumscribe(Succession):
|
|
552
|
-
"""Draw a temporary line surrounding the mobject.
|
|
554
|
+
r"""Draw a temporary line surrounding the mobject.
|
|
553
555
|
|
|
554
556
|
Parameters
|
|
555
557
|
----------
|
|
@@ -580,7 +582,7 @@ class Circumscribe(Succession):
|
|
|
580
582
|
|
|
581
583
|
class UsingCircumscribe(Scene):
|
|
582
584
|
def construct(self):
|
|
583
|
-
lbl = Tex(r"Circum
|
|
585
|
+
lbl = Tex(r"Circum-\\scribe").scale(2)
|
|
584
586
|
self.add(lbl)
|
|
585
587
|
self.play(Circumscribe(lbl))
|
|
586
588
|
self.play(Circumscribe(lbl, Circle))
|
|
@@ -593,7 +595,7 @@ class Circumscribe(Succession):
|
|
|
593
595
|
def __init__(
|
|
594
596
|
self,
|
|
595
597
|
mobject: Mobject,
|
|
596
|
-
shape:
|
|
598
|
+
shape: type = Rectangle,
|
|
597
599
|
fade_in=False,
|
|
598
600
|
fade_out=False,
|
|
599
601
|
time_width=0.3,
|
|
@@ -601,13 +603,13 @@ class Circumscribe(Succession):
|
|
|
601
603
|
color: ParsableManimColor = YELLOW,
|
|
602
604
|
run_time=1,
|
|
603
605
|
stroke_width=DEFAULT_STROKE_WIDTH,
|
|
604
|
-
**kwargs
|
|
606
|
+
**kwargs,
|
|
605
607
|
):
|
|
606
608
|
if shape is Rectangle:
|
|
607
609
|
frame = SurroundingRectangle(
|
|
608
610
|
mobject,
|
|
609
|
-
color,
|
|
610
|
-
buff,
|
|
611
|
+
color=color,
|
|
612
|
+
buff=buff,
|
|
611
613
|
stroke_width=stroke_width,
|
|
612
614
|
)
|
|
613
615
|
elif shape is Circle:
|
|
@@ -643,3 +645,68 @@ class Circumscribe(Succession):
|
|
|
643
645
|
super().__init__(
|
|
644
646
|
ShowPassingFlash(frame, time_width, run_time=run_time), **kwargs
|
|
645
647
|
)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
class Blink(Succession):
|
|
651
|
+
"""Blink the mobject.
|
|
652
|
+
|
|
653
|
+
Parameters
|
|
654
|
+
----------
|
|
655
|
+
mobject
|
|
656
|
+
The mobject to be blinked.
|
|
657
|
+
time_on
|
|
658
|
+
The duration that the mobject is shown for one blink.
|
|
659
|
+
time_off
|
|
660
|
+
The duration that the mobject is hidden for one blink.
|
|
661
|
+
blinks
|
|
662
|
+
The number of blinks
|
|
663
|
+
hide_at_end
|
|
664
|
+
Whether to hide the mobject at the end of the animation.
|
|
665
|
+
kwargs
|
|
666
|
+
Additional arguments to be passed to the :class:`~.Succession` constructor.
|
|
667
|
+
|
|
668
|
+
Examples
|
|
669
|
+
--------
|
|
670
|
+
|
|
671
|
+
.. manim:: BlinkingExample
|
|
672
|
+
|
|
673
|
+
class BlinkingExample(Scene):
|
|
674
|
+
def construct(self):
|
|
675
|
+
text = Text("Blinking").scale(1.5)
|
|
676
|
+
self.add(text)
|
|
677
|
+
self.play(Blink(text, blinks=3))
|
|
678
|
+
|
|
679
|
+
"""
|
|
680
|
+
|
|
681
|
+
def __init__(
|
|
682
|
+
self,
|
|
683
|
+
mobject: Mobject,
|
|
684
|
+
time_on: float = 0.5,
|
|
685
|
+
time_off: float = 0.5,
|
|
686
|
+
blinks: int = 1,
|
|
687
|
+
hide_at_end: bool = False,
|
|
688
|
+
**kwargs,
|
|
689
|
+
):
|
|
690
|
+
animations = [
|
|
691
|
+
UpdateFromFunc(
|
|
692
|
+
mobject,
|
|
693
|
+
update_function=lambda mob: mob.set_opacity(1.0),
|
|
694
|
+
run_time=time_on,
|
|
695
|
+
),
|
|
696
|
+
UpdateFromFunc(
|
|
697
|
+
mobject,
|
|
698
|
+
update_function=lambda mob: mob.set_opacity(0.0),
|
|
699
|
+
run_time=time_off,
|
|
700
|
+
),
|
|
701
|
+
] * blinks
|
|
702
|
+
|
|
703
|
+
if not hide_at_end:
|
|
704
|
+
animations.append(
|
|
705
|
+
UpdateFromFunc(
|
|
706
|
+
mobject,
|
|
707
|
+
update_function=lambda mob: mob.set_opacity(1.0),
|
|
708
|
+
run_time=time_on,
|
|
709
|
+
),
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
super().__init__(*animations, **kwargs)
|
manim/animation/movement.py
CHANGED
|
@@ -44,6 +44,26 @@ class Homotopy(Animation):
|
|
|
44
44
|
Keyword arguments propagated to :meth:`.Mobject.apply_function`.
|
|
45
45
|
kwargs
|
|
46
46
|
Further keyword arguments passed to the parent class.
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
|
|
51
|
+
.. manim:: HomotopyExample
|
|
52
|
+
|
|
53
|
+
class HomotopyExample(Scene):
|
|
54
|
+
def construct(self):
|
|
55
|
+
square = Square()
|
|
56
|
+
|
|
57
|
+
def homotopy(x, y, z, t):
|
|
58
|
+
if t <= 0.25:
|
|
59
|
+
progress = t / 0.25
|
|
60
|
+
return (x, y + progress * 0.2 * np.sin(x), z)
|
|
61
|
+
else:
|
|
62
|
+
wave_progress = (t - 0.25) / 0.75
|
|
63
|
+
return (x, y + 0.2 * np.sin(x + 10 * wave_progress), z)
|
|
64
|
+
|
|
65
|
+
self.play(Homotopy(homotopy, square, rate_func= linear, run_time=2))
|
|
66
|
+
|
|
47
67
|
"""
|
|
48
68
|
|
|
49
69
|
def __init__(
|
|
@@ -90,9 +110,7 @@ class ComplexHomotopy(Homotopy):
|
|
|
90
110
|
def __init__(
|
|
91
111
|
self, complex_homotopy: Callable[[complex], float], mobject: Mobject, **kwargs
|
|
92
112
|
) -> None:
|
|
93
|
-
"""
|
|
94
|
-
Complex Homotopy a function Cx[0, 1] to C
|
|
95
|
-
"""
|
|
113
|
+
"""Complex Homotopy a function Cx[0, 1] to C"""
|
|
96
114
|
|
|
97
115
|
def homotopy(
|
|
98
116
|
x: float,
|
manim/animation/rotation.py
CHANGED
manim/animation/specialized.py
CHANGED
|
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
__all__ = ["Broadcast"]
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from manim.animation.transform import Restore
|
|
8
9
|
|
|
@@ -69,10 +70,7 @@ class Broadcast(LaggedStart):
|
|
|
69
70
|
anims = []
|
|
70
71
|
|
|
71
72
|
# Works by saving the mob that is passed into the animation, scaling it to 0 (or the initial_width) and then restoring the original mob.
|
|
72
|
-
|
|
73
|
-
fill_o = True
|
|
74
|
-
else:
|
|
75
|
-
fill_o = False
|
|
73
|
+
fill_o = bool(mobject.fill_opacity)
|
|
76
74
|
|
|
77
75
|
for _ in range(self.n_mobs):
|
|
78
76
|
mob = mobject.copy()
|
manim/animation/speedmodifier.py
CHANGED
|
@@ -113,9 +113,9 @@ class ChangeSpeed(Animation):
|
|
|
113
113
|
self.anim = self.setup(anim)
|
|
114
114
|
|
|
115
115
|
if affects_speed_updaters:
|
|
116
|
-
assert (
|
|
117
|
-
ChangeSpeed
|
|
118
|
-
)
|
|
116
|
+
assert ChangeSpeed.is_changing_dt is False, (
|
|
117
|
+
"Only one animation at a time can play that changes speed (dt) for ChangeSpeed updaters"
|
|
118
|
+
)
|
|
119
119
|
ChangeSpeed.is_changing_dt = True
|
|
120
120
|
self.t = 0
|
|
121
121
|
self.affects_speed_updaters = affects_speed_updaters
|
manim/animation/transform.py
CHANGED
|
@@ -28,7 +28,8 @@ __all__ = [
|
|
|
28
28
|
|
|
29
29
|
import inspect
|
|
30
30
|
import types
|
|
31
|
-
from
|
|
31
|
+
from collections.abc import Iterable, Sequence
|
|
32
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
32
33
|
|
|
33
34
|
import numpy as np
|
|
34
35
|
|
|
@@ -297,9 +298,7 @@ class ReplacementTransform(Transform):
|
|
|
297
298
|
|
|
298
299
|
|
|
299
300
|
class TransformFromCopy(Transform):
|
|
300
|
-
"""
|
|
301
|
-
Performs a reversed Transform
|
|
302
|
-
"""
|
|
301
|
+
"""Performs a reversed Transform"""
|
|
303
302
|
|
|
304
303
|
def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None:
|
|
305
304
|
super().__init__(target_mobject, mobject, **kwargs)
|
|
@@ -430,7 +429,7 @@ class MoveToTarget(Transform):
|
|
|
430
429
|
def check_validity_of_input(self, mobject: Mobject) -> None:
|
|
431
430
|
if not hasattr(mobject, "target"):
|
|
432
431
|
raise ValueError(
|
|
433
|
-
"MoveToTarget called on
|
|
432
|
+
"MoveToTarget called on mobjectwithout attribute 'target'",
|
|
434
433
|
)
|
|
435
434
|
|
|
436
435
|
|