manim 0.18.0.post0__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.

Files changed (146) hide show
  1. manim/__init__.py +3 -6
  2. manim/__main__.py +61 -20
  3. manim/_config/__init__.py +6 -3
  4. manim/_config/cli_colors.py +16 -8
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +14 -8
  7. manim/_config/utils.py +651 -472
  8. manim/animation/animation.py +152 -5
  9. manim/animation/composition.py +80 -39
  10. manim/animation/creation.py +196 -14
  11. manim/animation/fading.py +5 -9
  12. manim/animation/indication.py +103 -47
  13. manim/animation/movement.py +22 -5
  14. manim/animation/rotation.py +3 -2
  15. manim/animation/specialized.py +4 -6
  16. manim/animation/speedmodifier.py +10 -5
  17. manim/animation/transform.py +4 -5
  18. manim/animation/transform_matching_parts.py +1 -1
  19. manim/animation/updaters/mobject_update_utils.py +17 -14
  20. manim/camera/camera.py +15 -6
  21. manim/cli/__init__.py +17 -0
  22. manim/cli/cfg/group.py +70 -44
  23. manim/cli/checkhealth/checks.py +93 -75
  24. manim/cli/checkhealth/commands.py +14 -5
  25. manim/cli/default_group.py +157 -25
  26. manim/cli/init/commands.py +32 -24
  27. manim/cli/plugins/commands.py +16 -3
  28. manim/cli/render/commands.py +72 -60
  29. manim/cli/render/ease_of_access_options.py +4 -3
  30. manim/cli/render/global_options.py +51 -15
  31. manim/cli/render/output_options.py +6 -5
  32. manim/cli/render/render_options.py +97 -32
  33. manim/constants.py +65 -19
  34. manim/gui/gui.py +2 -0
  35. manim/mobject/frame.py +0 -1
  36. manim/mobject/geometry/arc.py +112 -78
  37. manim/mobject/geometry/boolean_ops.py +32 -25
  38. manim/mobject/geometry/labeled.py +300 -77
  39. manim/mobject/geometry/line.py +132 -64
  40. manim/mobject/geometry/polygram.py +126 -30
  41. manim/mobject/geometry/shape_matchers.py +35 -15
  42. manim/mobject/geometry/tips.py +38 -29
  43. manim/mobject/graph.py +414 -133
  44. manim/mobject/graphing/coordinate_systems.py +126 -64
  45. manim/mobject/graphing/functions.py +25 -15
  46. manim/mobject/graphing/number_line.py +24 -10
  47. manim/mobject/graphing/probability.py +2 -10
  48. manim/mobject/graphing/scale.py +6 -5
  49. manim/mobject/matrix.py +17 -19
  50. manim/mobject/mobject.py +314 -165
  51. manim/mobject/opengl/opengl_compatibility.py +2 -0
  52. manim/mobject/opengl/opengl_geometry.py +30 -9
  53. manim/mobject/opengl/opengl_image_mobject.py +2 -0
  54. manim/mobject/opengl/opengl_mobject.py +509 -343
  55. manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
  56. manim/mobject/opengl/opengl_surface.py +3 -2
  57. manim/mobject/opengl/opengl_three_dimensions.py +2 -0
  58. manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
  59. manim/mobject/svg/brace.py +63 -13
  60. manim/mobject/svg/svg_mobject.py +4 -3
  61. manim/mobject/table.py +11 -13
  62. manim/mobject/text/code_mobject.py +186 -548
  63. manim/mobject/text/numbers.py +9 -7
  64. manim/mobject/text/tex_mobject.py +23 -14
  65. manim/mobject/text/text_mobject.py +70 -24
  66. manim/mobject/three_d/polyhedra.py +98 -1
  67. manim/mobject/three_d/three_d_utils.py +4 -4
  68. manim/mobject/three_d/three_dimensions.py +62 -34
  69. manim/mobject/types/image_mobject.py +42 -24
  70. manim/mobject/types/point_cloud_mobject.py +105 -67
  71. manim/mobject/types/vectorized_mobject.py +496 -228
  72. manim/mobject/value_tracker.py +5 -4
  73. manim/mobject/vector_field.py +5 -5
  74. manim/opengl/__init__.py +3 -3
  75. manim/plugins/__init__.py +14 -1
  76. manim/plugins/plugins_flags.py +14 -8
  77. manim/renderer/cairo_renderer.py +20 -10
  78. manim/renderer/opengl_renderer.py +21 -23
  79. manim/renderer/opengl_renderer_window.py +2 -0
  80. manim/renderer/shader.py +2 -3
  81. manim/renderer/shader_wrapper.py +5 -2
  82. manim/renderer/vectorized_mobject_rendering.py +5 -0
  83. manim/scene/moving_camera_scene.py +23 -0
  84. manim/scene/scene.py +90 -43
  85. manim/scene/scene_file_writer.py +316 -165
  86. manim/scene/section.py +17 -15
  87. manim/scene/three_d_scene.py +13 -21
  88. manim/scene/vector_space_scene.py +22 -9
  89. manim/typing.py +830 -70
  90. manim/utils/bezier.py +1667 -399
  91. manim/utils/caching.py +13 -5
  92. manim/utils/color/AS2700.py +2 -0
  93. manim/utils/color/BS381.py +3 -0
  94. manim/utils/color/DVIPSNAMES.py +96 -0
  95. manim/utils/color/SVGNAMES.py +179 -0
  96. manim/utils/color/X11.py +3 -0
  97. manim/utils/color/XKCD.py +3 -0
  98. manim/utils/color/__init__.py +8 -5
  99. manim/utils/color/core.py +844 -309
  100. manim/utils/color/manim_colors.py +7 -9
  101. manim/utils/commands.py +48 -20
  102. manim/utils/config_ops.py +18 -13
  103. manim/utils/debug.py +8 -7
  104. manim/utils/deprecation.py +90 -40
  105. manim/utils/docbuild/__init__.py +17 -0
  106. manim/utils/docbuild/autoaliasattr_directive.py +234 -0
  107. manim/utils/docbuild/autocolor_directive.py +21 -17
  108. manim/utils/docbuild/manim_directive.py +50 -35
  109. manim/utils/docbuild/module_parsing.py +245 -0
  110. manim/utils/exceptions.py +6 -0
  111. manim/utils/family.py +5 -3
  112. manim/utils/family_ops.py +17 -4
  113. manim/utils/file_ops.py +26 -16
  114. manim/utils/hashing.py +9 -7
  115. manim/utils/images.py +10 -4
  116. manim/utils/ipython_magic.py +14 -8
  117. manim/utils/iterables.py +161 -119
  118. manim/utils/module_ops.py +57 -19
  119. manim/utils/opengl.py +83 -24
  120. manim/utils/parameter_parsing.py +32 -0
  121. manim/utils/paths.py +21 -23
  122. manim/utils/polylabel.py +168 -0
  123. manim/utils/qhull.py +218 -0
  124. manim/utils/rate_functions.py +74 -39
  125. manim/utils/simple_functions.py +24 -15
  126. manim/utils/sounds.py +7 -1
  127. manim/utils/space_ops.py +125 -69
  128. manim/utils/testing/__init__.py +17 -0
  129. manim/utils/testing/_frames_testers.py +13 -8
  130. manim/utils/testing/_show_diff.py +5 -3
  131. manim/utils/testing/_test_class_makers.py +33 -18
  132. manim/utils/testing/frames_comparison.py +27 -19
  133. manim/utils/tex.py +127 -197
  134. manim/utils/tex_file_writing.py +47 -45
  135. manim/utils/tex_templates.py +2 -1
  136. manim/utils/unit.py +6 -5
  137. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
  138. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
  139. manim-0.19.0.dist-info/RECORD +221 -0
  140. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
  141. manim/cli/new/__init__.py +0 -0
  142. manim/cli/new/group.py +0 -189
  143. manim/plugins/import_plugins.py +0 -43
  144. manim-0.18.0.post0.dist-info/RECORD +0 -217
  145. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
  146. {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/animation/fading.py CHANGED
@@ -12,7 +12,6 @@
12
12
 
13
13
  """
14
14
 
15
-
16
15
  from __future__ import annotations
17
16
 
18
17
  __all__ = [
@@ -58,10 +57,7 @@ class _Fade(Transform):
58
57
  ) -> None:
59
58
  if not mobjects:
60
59
  raise ValueError("At least one mobject must be passed.")
61
- if len(mobjects) == 1:
62
- mobject = mobjects[0]
63
- else:
64
- mobject = Group(*mobjects)
60
+ mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects)
65
61
 
66
62
  self.point_target = False
67
63
  if shift is None:
@@ -98,7 +94,7 @@ class _Fade(Transform):
98
94
 
99
95
 
100
96
  class FadeIn(_Fade):
101
- """Fade in :class:`~.Mobject` s.
97
+ r"""Fade in :class:`~.Mobject` s.
102
98
 
103
99
  Parameters
104
100
  ----------
@@ -123,7 +119,7 @@ class FadeIn(_Fade):
123
119
  dot = Dot(UP * 2 + LEFT)
124
120
  self.add(dot)
125
121
  tex = Tex(
126
- "FadeIn with ", "shift ", " or target\\_position", " and scale"
122
+ "FadeIn with ", "shift ", r" or target\_position", " and scale"
127
123
  ).scale(1)
128
124
  animations = [
129
125
  FadeIn(tex[0]),
@@ -146,7 +142,7 @@ class FadeIn(_Fade):
146
142
 
147
143
 
148
144
  class FadeOut(_Fade):
149
- """Fade out :class:`~.Mobject` s.
145
+ r"""Fade out :class:`~.Mobject` s.
150
146
 
151
147
  Parameters
152
148
  ----------
@@ -170,7 +166,7 @@ class FadeOut(_Fade):
170
166
  dot = Dot(UP * 2 + LEFT)
171
167
  self.add(dot)
172
168
  tex = Tex(
173
- "FadeOut with ", "shift ", " or target\\_position", " and scale"
169
+ "FadeOut with ", "shift ", r" or target\_position", " and scale"
174
170
  ).scale(1)
175
171
  animations = [
176
172
  FadeOut(tex[0]),
@@ -25,19 +25,22 @@ Examples
25
25
 
26
26
  """
27
27
 
28
+ from __future__ import annotations
29
+
28
30
  __all__ = [
29
31
  "FocusOn",
30
32
  "Indicate",
31
33
  "Flash",
32
34
  "ShowPassingFlash",
33
35
  "ShowPassingFlashWithThinningStrokeWidth",
34
- "ShowCreationThenFadeOut",
35
36
  "ApplyWave",
36
37
  "Circumscribe",
37
38
  "Wiggle",
39
+ "Blink",
38
40
  ]
39
41
 
40
- from typing import Callable, Iterable, Optional, Tuple, Type, Union
42
+ from collections.abc import Iterable
43
+ from typing import Callable
41
44
 
42
45
  import numpy as np
43
46
 
@@ -54,12 +57,12 @@ from ..animation.creation import Create, ShowPartial, Uncreate
54
57
  from ..animation.fading import FadeIn, FadeOut
55
58
  from ..animation.movement import Homotopy
56
59
  from ..animation.transform import Transform
60
+ from ..animation.updaters.update import UpdateFromFunc
57
61
  from ..constants import *
58
62
  from ..mobject.mobject import Mobject
59
63
  from ..mobject.types.vectorized_mobject import VGroup, VMobject
60
64
  from ..utils.bezier import interpolate, inverse_interpolate
61
65
  from ..utils.color import GREY, YELLOW, ParsableManimColor
62
- from ..utils.deprecation import deprecated
63
66
  from ..utils.rate_functions import smooth, there_and_back, wiggle
64
67
  from ..utils.space_ops import normalize
65
68
 
@@ -77,8 +80,6 @@ class FocusOn(Transform):
77
80
  The color of the spotlight.
78
81
  run_time
79
82
  The duration of the animation.
80
- kwargs
81
- Additional arguments to be passed to the :class:`~.Succession` constructor
82
83
 
83
84
  Examples
84
85
  --------
@@ -94,11 +95,11 @@ class FocusOn(Transform):
94
95
 
95
96
  def __init__(
96
97
  self,
97
- focus_point: Union[np.ndarray, Mobject],
98
+ focus_point: np.ndarray | Mobject,
98
99
  opacity: float = 0.2,
99
100
  color: str = GREY,
100
101
  run_time: float = 2,
101
- **kwargs
102
+ **kwargs,
102
103
  ) -> None:
103
104
  self.focus_point = focus_point
104
105
  self.color = color
@@ -131,7 +132,7 @@ class Indicate(Transform):
131
132
  color
132
133
  The color the mobject temporally takes.
133
134
  rate_func
134
- The function definig the animation progress at every point in time.
135
+ The function defining the animation progress at every point in time.
135
136
  kwargs
136
137
  Additional arguments to be passed to the :class:`~.Succession` constructor
137
138
 
@@ -148,17 +149,17 @@ class Indicate(Transform):
148
149
 
149
150
  def __init__(
150
151
  self,
151
- mobject: "Mobject",
152
+ mobject: Mobject,
152
153
  scale_factor: float = 1.2,
153
154
  color: str = YELLOW,
154
- rate_func: Callable[[float, Optional[float]], np.ndarray] = there_and_back,
155
- **kwargs
155
+ rate_func: Callable[[float, float | None], np.ndarray] = there_and_back,
156
+ **kwargs,
156
157
  ) -> None:
157
158
  self.color = color
158
159
  self.scale_factor = scale_factor
159
160
  super().__init__(mobject, rate_func=rate_func, **kwargs)
160
161
 
161
- def create_target(self) -> "Mobject":
162
+ def create_target(self) -> Mobject:
162
163
  target = self.mobject.copy()
163
164
  target.scale(self.scale_factor)
164
165
  target.set_color(self.color)
@@ -218,7 +219,7 @@ class Flash(AnimationGroup):
218
219
 
219
220
  def __init__(
220
221
  self,
221
- point: Union[np.ndarray, Mobject],
222
+ point: np.ndarray | Mobject,
222
223
  line_length: float = 0.2,
223
224
  num_lines: int = 12,
224
225
  flash_radius: float = 0.1,
@@ -226,7 +227,7 @@ class Flash(AnimationGroup):
226
227
  color: str = YELLOW,
227
228
  time_width: float = 1,
228
229
  run_time: float = 1.0,
229
- **kwargs
230
+ **kwargs,
230
231
  ) -> None:
231
232
  if isinstance(point, Mobject):
232
233
  self.point = point.get_center()
@@ -256,7 +257,7 @@ class Flash(AnimationGroup):
256
257
  lines.set_stroke(width=self.line_stroke_width)
257
258
  return lines
258
259
 
259
- def create_line_anims(self) -> Iterable["ShowPassingFlash"]:
260
+ def create_line_anims(self) -> Iterable[ShowPassingFlash]:
260
261
  return [
261
262
  ShowPassingFlash(
262
263
  line,
@@ -269,7 +270,7 @@ class Flash(AnimationGroup):
269
270
 
270
271
 
271
272
  class ShowPassingFlash(ShowPartial):
272
- """Show only a sliver of the VMobject each frame.
273
+ r"""Show only a sliver of the VMobject each frame.
273
274
 
274
275
  Parameters
275
276
  ----------
@@ -289,7 +290,7 @@ class ShowPassingFlash(ShowPartial):
289
290
  self.add(p, lbl)
290
291
  p = p.copy().set_color(BLUE)
291
292
  for time_width in [0.2, 0.5, 1, 2]:
292
- lbl.become(Tex(r"\\texttt{time\\_width={{%.1f}}}"%time_width))
293
+ lbl.become(Tex(r"\texttt{time\_width={{%.1f}}}"%time_width))
293
294
  self.play(ShowPassingFlash(
294
295
  p.copy().set_color(BLUE),
295
296
  run_time=2,
@@ -302,11 +303,11 @@ class ShowPassingFlash(ShowPartial):
302
303
 
303
304
  """
304
305
 
305
- def __init__(self, mobject: "VMobject", time_width: float = 0.1, **kwargs) -> None:
306
+ def __init__(self, mobject: VMobject, time_width: float = 0.1, **kwargs) -> None:
306
307
  self.time_width = time_width
307
308
  super().__init__(mobject, remover=True, introducer=True, **kwargs)
308
309
 
309
- def _get_bounds(self, alpha: float) -> Tuple[float]:
310
+ def _get_bounds(self, alpha: float) -> tuple[float]:
310
311
  tw = self.time_width
311
312
  upper = interpolate(0, 1 + tw, alpha)
312
313
  lower = upper - tw
@@ -342,16 +343,6 @@ class ShowPassingFlashWithThinningStrokeWidth(AnimationGroup):
342
343
  )
343
344
 
344
345
 
345
- @deprecated(
346
- since="v0.15.0",
347
- until="v0.16.0",
348
- message="Use Create then FadeOut to achieve this effect.",
349
- )
350
- class ShowCreationThenFadeOut(Succession):
351
- def __init__(self, mobject: "Mobject", remover: bool = True, **kwargs) -> None:
352
- super().__init__(Create(mobject), FadeOut(mobject), remover=remover, **kwargs)
353
-
354
-
355
346
  class ApplyWave(Homotopy):
356
347
  """Send a wave through the Mobject distorting it temporarily.
357
348
 
@@ -397,14 +388,14 @@ class ApplyWave(Homotopy):
397
388
 
398
389
  def __init__(
399
390
  self,
400
- mobject: "Mobject",
391
+ mobject: Mobject,
401
392
  direction: np.ndarray = UP,
402
393
  amplitude: float = 0.2,
403
394
  wave_func: Callable[[float], float] = smooth,
404
395
  time_width: float = 1,
405
396
  ripples: int = 1,
406
397
  run_time: float = 2,
407
- **kwargs
398
+ **kwargs,
408
399
  ) -> None:
409
400
  x_min = mobject.get_left()[0]
410
401
  x_max = mobject.get_right()[0]
@@ -415,7 +406,7 @@ class ApplyWave(Homotopy):
415
406
  # This wave is build up as follows:
416
407
  # The time is split into 2*ripples phases. In every phase the amplitude
417
408
  # either rises to one or goes down to zero. Consecutive ripples will have
418
- # their amplitudes in oppising directions (first ripple from 0 to 1 to 0,
409
+ # their amplitudes in opposing directions (first ripple from 0 to 1 to 0,
419
410
  # second from 0 to -1 to 0 and so on). This is how two ripples would be
420
411
  # divided into phases:
421
412
 
@@ -454,7 +445,7 @@ class ApplyWave(Homotopy):
454
445
  return wave_func(t * phases)
455
446
  elif phase == phases - 1:
456
447
  # last ripple. Rising or falling depending on the number of ripples
457
- # The (ripples % 2)-term is used to make this destinction.
448
+ # The (ripples % 2)-term is used to make this distinction.
458
449
  t -= phase / phases # Time relative to the phase
459
450
  return (1 - wave_func(t * phases)) * (2 * (ripples % 2) - 1)
460
451
  else:
@@ -470,7 +461,7 @@ class ApplyWave(Homotopy):
470
461
  y: float,
471
462
  z: float,
472
463
  t: float,
473
- ) -> Tuple[float, float, float]:
464
+ ) -> tuple[float, float, float]:
474
465
  upper = interpolate(0, 1 + time_width, t)
475
466
  lower = upper - time_width
476
467
  relative_x = inverse_interpolate(x_min, x_max, x)
@@ -516,14 +507,14 @@ class Wiggle(Animation):
516
507
 
517
508
  def __init__(
518
509
  self,
519
- mobject: "Mobject",
510
+ mobject: Mobject,
520
511
  scale_value: float = 1.1,
521
512
  rotation_angle: float = 0.01 * TAU,
522
513
  n_wiggles: int = 6,
523
- scale_about_point: Optional[np.ndarray] = None,
524
- rotate_about_point: Optional[np.ndarray] = None,
514
+ scale_about_point: np.ndarray | None = None,
515
+ rotate_about_point: np.ndarray | None = None,
525
516
  run_time: float = 2,
526
- **kwargs
517
+ **kwargs,
527
518
  ) -> None:
528
519
  self.scale_value = scale_value
529
520
  self.rotation_angle = rotation_angle
@@ -544,8 +535,8 @@ class Wiggle(Animation):
544
535
 
545
536
  def interpolate_submobject(
546
537
  self,
547
- submobject: "Mobject",
548
- starting_submobject: "Mobject",
538
+ submobject: Mobject,
539
+ starting_submobject: Mobject,
549
540
  alpha: float,
550
541
  ) -> None:
551
542
  submobject.points[:, :] = starting_submobject.points
@@ -560,14 +551,14 @@ class Wiggle(Animation):
560
551
 
561
552
 
562
553
  class Circumscribe(Succession):
563
- """Draw a temporary line surrounding the mobject.
554
+ r"""Draw a temporary line surrounding the mobject.
564
555
 
565
556
  Parameters
566
557
  ----------
567
558
  mobject
568
559
  The mobject to be circumscribed.
569
560
  shape
570
- The shape with which to surrond the given mobject. Should be either
561
+ The shape with which to surround the given mobject. Should be either
571
562
  :class:`~.Rectangle` or :class:`~.Circle`
572
563
  fade_in
573
564
  Whether to make the surrounding shape to fade in. It will be drawn otherwise.
@@ -591,7 +582,7 @@ class Circumscribe(Succession):
591
582
 
592
583
  class UsingCircumscribe(Scene):
593
584
  def construct(self):
594
- lbl = Tex(r"Circum-\\\\scribe").scale(2)
585
+ lbl = Tex(r"Circum-\\scribe").scale(2)
595
586
  self.add(lbl)
596
587
  self.play(Circumscribe(lbl))
597
588
  self.play(Circumscribe(lbl, Circle))
@@ -604,7 +595,7 @@ class Circumscribe(Succession):
604
595
  def __init__(
605
596
  self,
606
597
  mobject: Mobject,
607
- shape: Type = Rectangle,
598
+ shape: type = Rectangle,
608
599
  fade_in=False,
609
600
  fade_out=False,
610
601
  time_width=0.3,
@@ -612,13 +603,13 @@ class Circumscribe(Succession):
612
603
  color: ParsableManimColor = YELLOW,
613
604
  run_time=1,
614
605
  stroke_width=DEFAULT_STROKE_WIDTH,
615
- **kwargs
606
+ **kwargs,
616
607
  ):
617
608
  if shape is Rectangle:
618
609
  frame = SurroundingRectangle(
619
610
  mobject,
620
- color,
621
- buff,
611
+ color=color,
612
+ buff=buff,
622
613
  stroke_width=stroke_width,
623
614
  )
624
615
  elif shape is Circle:
@@ -654,3 +645,68 @@ class Circumscribe(Succession):
654
645
  super().__init__(
655
646
  ShowPassingFlash(frame, time_width, run_time=run_time), **kwargs
656
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)
@@ -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,
@@ -136,8 +154,7 @@ class PhaseFlow(Animation):
136
154
 
137
155
  class MoveAlongPath(Animation):
138
156
  """Make one mobject move along the path of another mobject.
139
- Example
140
- --------
157
+
141
158
  .. manim:: MoveAlongPathExample
142
159
 
143
160
  class MoveAlongPathExample(Scene):
@@ -4,7 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  __all__ = ["Rotating", "Rotate"]
6
6
 
7
- from typing import TYPE_CHECKING, Callable, Sequence
7
+ from collections.abc import Sequence
8
+ from typing import TYPE_CHECKING, Callable
8
9
 
9
10
  import numpy as np
10
11
 
@@ -59,7 +60,7 @@ class Rotate(Transform):
59
60
  about_point
60
61
  The rotation center.
61
62
  about_edge
62
- If ``about_point``is ``None``, this argument specifies
63
+ If ``about_point`` is ``None``, this argument specifies
63
64
  the direction of the bounding box point to be taken as
64
65
  the rotation center.
65
66
 
@@ -2,7 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  __all__ = ["Broadcast"]
4
4
 
5
- from typing import Any, Sequence
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
- if mobject.fill_opacity:
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()
@@ -84,7 +82,7 @@ class Broadcast(LaggedStart):
84
82
 
85
83
  mob.move_to(self.focal_point)
86
84
  mob.save_state()
87
- mob.set_width(self.initial_width)
85
+ mob.set(width=self.initial_width)
88
86
 
89
87
  if fill_o:
90
88
  mob.set_opacity(self.initial_opacity)
@@ -4,15 +4,20 @@ from __future__ import annotations
4
4
 
5
5
  import inspect
6
6
  import types
7
- from typing import Callable
7
+ from typing import TYPE_CHECKING, Callable
8
8
 
9
9
  from numpy import piecewise
10
10
 
11
11
  from ..animation.animation import Animation, Wait, prepare_animation
12
12
  from ..animation.composition import AnimationGroup
13
- from ..mobject.mobject import Mobject, Updater, _AnimationBuilder
13
+ from ..mobject.mobject import Mobject, _AnimationBuilder
14
14
  from ..scene.scene import Scene
15
15
 
16
+ if TYPE_CHECKING:
17
+ from ..mobject.mobject import Updater
18
+
19
+ __all__ = ["ChangeSpeed"]
20
+
16
21
 
17
22
  class ChangeSpeed(Animation):
18
23
  """Modifies the speed of passed animation.
@@ -108,9 +113,9 @@ class ChangeSpeed(Animation):
108
113
  self.anim = self.setup(anim)
109
114
 
110
115
  if affects_speed_updaters:
111
- assert (
112
- ChangeSpeed.is_changing_dt is False
113
- ), "Only one animation at a time can play that changes speed (dt) for ChangeSpeed updaters"
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
+ )
114
119
  ChangeSpeed.is_changing_dt = True
115
120
  self.t = 0
116
121
  self.affects_speed_updaters = affects_speed_updaters
@@ -28,7 +28,8 @@ __all__ = [
28
28
 
29
29
  import inspect
30
30
  import types
31
- from typing import TYPE_CHECKING, Any, Callable, Iterable, Sequence
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 mobject" "without attribute 'target'",
432
+ "MoveToTarget called on mobjectwithout attribute 'target'",
434
433
  )
435
434
 
436
435
 
@@ -225,7 +225,7 @@ class TransformMatchingShapes(TransformMatchingAbstractBase):
225
225
  def get_mobject_key(mobject: Mobject) -> int:
226
226
  mobject.save_state()
227
227
  mobject.center()
228
- mobject.set_height(1)
228
+ mobject.set(height=1)
229
229
  result = hash(np.round(mobject.points, 3).tobytes())
230
230
  mobject.restore()
231
231
  return result
@@ -178,7 +178,7 @@ def always_rotate(mobject: Mobject, rate: float = 20 * DEGREES, **kwargs) -> Mob
178
178
 
179
179
 
180
180
  def turn_animation_into_updater(
181
- animation: Animation, cycle: bool = False, **kwargs
181
+ animation: Animation, cycle: bool = False, delay: float = 0, **kwargs
182
182
  ) -> Mobject:
183
183
  """
184
184
  Add an updater to the animation's mobject which applies
@@ -187,6 +187,8 @@ def turn_animation_into_updater(
187
187
  If cycle is True, this repeats over and over. Otherwise,
188
188
  the updater will be popped upon completion
189
189
 
190
+ The ``delay`` parameter is the delay (in seconds) before the animation starts..
191
+
190
192
  Examples
191
193
  --------
192
194
 
@@ -206,21 +208,22 @@ def turn_animation_into_updater(
206
208
  mobject = animation.mobject
207
209
  animation.suspend_mobject_updating = False
208
210
  animation.begin()
209
- animation.total_time = 0
211
+ animation.total_time = -delay
210
212
 
211
213
  def update(m: Mobject, dt: float):
212
- run_time = animation.get_run_time()
213
- time_ratio = animation.total_time / run_time
214
- if cycle:
215
- alpha = time_ratio % 1
216
- else:
217
- alpha = np.clip(time_ratio, 0, 1)
218
- if alpha >= 1:
219
- animation.finish()
220
- m.remove_updater(update)
221
- return
222
- animation.interpolate(alpha)
223
- animation.update_mobjects(dt)
214
+ if animation.total_time >= 0:
215
+ run_time = animation.get_run_time()
216
+ time_ratio = animation.total_time / run_time
217
+ if cycle:
218
+ alpha = time_ratio % 1
219
+ else:
220
+ alpha = np.clip(time_ratio, 0, 1)
221
+ if alpha >= 1:
222
+ animation.finish()
223
+ m.remove_updater(update)
224
+ return
225
+ animation.interpolate(alpha)
226
+ animation.update_mobjects(dt)
224
227
  animation.total_time += dt
225
228
 
226
229
  mobject.add_updater(update)