manim 0.17.0__py3-none-any.whl → 0.19.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. manim/__init__.py +11 -6
  2. manim/__main__.py +62 -19
  3. manim/_config/__init__.py +10 -9
  4. manim/_config/cli_colors.py +26 -9
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +23 -13
  7. manim/_config/utils.py +662 -468
  8. manim/animation/animation.py +164 -18
  9. manim/animation/changing.py +34 -23
  10. manim/animation/composition.py +265 -67
  11. manim/animation/creation.py +208 -26
  12. manim/animation/fading.py +16 -18
  13. manim/animation/growing.py +35 -15
  14. manim/animation/indication.py +150 -76
  15. manim/animation/movement.py +56 -22
  16. manim/animation/numbers.py +64 -6
  17. manim/animation/rotation.py +78 -7
  18. manim/animation/specialized.py +6 -7
  19. manim/animation/speedmodifier.py +13 -10
  20. manim/animation/transform.py +14 -11
  21. manim/animation/transform_matching_parts.py +3 -4
  22. manim/animation/updaters/mobject_update_utils.py +152 -30
  23. manim/animation/updaters/update.py +10 -7
  24. manim/camera/camera.py +182 -118
  25. manim/camera/mapping_camera.py +34 -3
  26. manim/camera/moving_camera.py +95 -74
  27. manim/camera/multi_camera.py +23 -15
  28. manim/camera/three_d_camera.py +70 -52
  29. manim/cli/__init__.py +17 -0
  30. manim/cli/cfg/group.py +76 -44
  31. manim/cli/checkhealth/checks.py +192 -0
  32. manim/cli/checkhealth/commands.py +90 -0
  33. manim/cli/default_group.py +158 -25
  34. manim/cli/init/commands.py +33 -25
  35. manim/cli/plugins/commands.py +16 -3
  36. manim/cli/render/commands.py +72 -60
  37. manim/cli/render/ease_of_access_options.py +4 -3
  38. manim/cli/render/global_options.py +59 -17
  39. manim/cli/render/output_options.py +6 -5
  40. manim/cli/render/render_options.py +98 -33
  41. manim/constants.py +109 -59
  42. manim/data_structures.py +31 -0
  43. manim/mobject/frame.py +8 -5
  44. manim/mobject/geometry/__init__.py +1 -0
  45. manim/mobject/geometry/arc.py +277 -135
  46. manim/mobject/geometry/boolean_ops.py +32 -31
  47. manim/mobject/geometry/labeled.py +376 -0
  48. manim/mobject/geometry/line.py +192 -87
  49. manim/mobject/geometry/polygram.py +224 -58
  50. manim/mobject/geometry/shape_matchers.py +61 -25
  51. manim/mobject/geometry/tips.py +122 -48
  52. manim/mobject/graph.py +1027 -419
  53. manim/mobject/graphing/coordinate_systems.py +533 -278
  54. manim/mobject/graphing/functions.py +53 -32
  55. manim/mobject/graphing/number_line.py +123 -65
  56. manim/mobject/graphing/probability.py +88 -62
  57. manim/mobject/graphing/scale.py +33 -19
  58. manim/mobject/logo.py +118 -28
  59. manim/mobject/matrix.py +87 -83
  60. manim/mobject/mobject.py +912 -442
  61. manim/mobject/opengl/dot_cloud.py +16 -5
  62. manim/mobject/opengl/opengl_compatibility.py +4 -2
  63. manim/mobject/opengl/opengl_geometry.py +254 -153
  64. manim/mobject/opengl/opengl_image_mobject.py +3 -1
  65. manim/mobject/opengl/opengl_mobject.py +779 -482
  66. manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
  67. manim/mobject/opengl/opengl_surface.py +14 -92
  68. manim/mobject/opengl/opengl_three_dimensions.py +12 -8
  69. manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
  70. manim/mobject/svg/brace.py +173 -41
  71. manim/mobject/svg/svg_mobject.py +139 -53
  72. manim/mobject/table.py +61 -68
  73. manim/mobject/text/code_mobject.py +193 -539
  74. manim/mobject/text/numbers.py +81 -34
  75. manim/mobject/text/tex_mobject.py +130 -78
  76. manim/mobject/text/text_mobject.py +288 -164
  77. manim/mobject/three_d/polyhedra.py +111 -13
  78. manim/mobject/three_d/three_d_utils.py +17 -8
  79. manim/mobject/three_d/three_dimensions.py +239 -106
  80. manim/mobject/types/image_mobject.py +50 -30
  81. manim/mobject/types/point_cloud_mobject.py +120 -75
  82. manim/mobject/types/vectorized_mobject.py +841 -408
  83. manim/mobject/value_tracker.py +105 -38
  84. manim/mobject/vector_field.py +50 -31
  85. manim/opengl/__init__.py +3 -3
  86. manim/plugins/__init__.py +14 -1
  87. manim/plugins/plugins_flags.py +10 -14
  88. manim/renderer/cairo_renderer.py +65 -50
  89. manim/renderer/opengl_renderer.py +89 -69
  90. manim/renderer/opengl_renderer_window.py +39 -18
  91. manim/renderer/shader.py +123 -87
  92. manim/renderer/shader_wrapper.py +44 -28
  93. manim/renderer/vectorized_mobject_rendering.py +38 -10
  94. manim/scene/moving_camera_scene.py +32 -3
  95. manim/scene/scene.py +507 -242
  96. manim/scene/scene_file_writer.py +371 -220
  97. manim/scene/section.py +20 -16
  98. manim/scene/three_d_scene.py +14 -22
  99. manim/scene/vector_space_scene.py +223 -129
  100. manim/scene/zoomed_scene.py +46 -41
  101. manim/typing.py +990 -0
  102. manim/utils/bezier.py +1823 -371
  103. manim/utils/caching.py +12 -5
  104. manim/utils/color/AS2700.py +236 -0
  105. manim/utils/color/BS381.py +318 -0
  106. manim/utils/color/DVIPSNAMES.py +96 -0
  107. manim/utils/color/SVGNAMES.py +179 -0
  108. manim/utils/color/X11.py +533 -0
  109. manim/utils/color/XKCD.py +952 -0
  110. manim/utils/color/__init__.py +61 -0
  111. manim/utils/color/core.py +1667 -0
  112. manim/utils/color/manim_colors.py +218 -0
  113. manim/utils/commands.py +48 -20
  114. manim/utils/config_ops.py +39 -19
  115. manim/utils/debug.py +8 -7
  116. manim/utils/deprecation.py +86 -39
  117. manim/utils/docbuild/__init__.py +17 -0
  118. manim/utils/docbuild/autoaliasattr_directive.py +236 -0
  119. manim/utils/docbuild/autocolor_directive.py +99 -0
  120. manim/utils/docbuild/manim_directive.py +94 -41
  121. manim/utils/docbuild/module_parsing.py +245 -0
  122. manim/utils/exceptions.py +6 -0
  123. manim/utils/family.py +5 -3
  124. manim/utils/family_ops.py +17 -4
  125. manim/utils/file_ops.py +27 -17
  126. manim/utils/hashing.py +55 -45
  127. manim/utils/images.py +13 -7
  128. manim/utils/ipython_magic.py +13 -7
  129. manim/utils/iterables.py +163 -120
  130. manim/utils/module_ops.py +66 -24
  131. manim/utils/opengl.py +77 -24
  132. manim/utils/parameter_parsing.py +32 -0
  133. manim/utils/paths.py +30 -33
  134. manim/utils/polylabel.py +235 -0
  135. manim/utils/qhull.py +218 -0
  136. manim/utils/rate_functions.py +98 -32
  137. manim/utils/simple_functions.py +25 -33
  138. manim/utils/sounds.py +7 -1
  139. manim/utils/space_ops.py +188 -115
  140. manim/utils/testing/__init__.py +17 -0
  141. manim/utils/testing/_frames_testers.py +13 -8
  142. manim/utils/testing/_show_diff.py +5 -3
  143. manim/utils/testing/_test_class_makers.py +34 -18
  144. manim/utils/testing/frames_comparison.py +37 -19
  145. manim/utils/tex.py +130 -198
  146. manim/utils/tex_file_writing.py +77 -47
  147. manim/utils/tex_templates.py +2 -1
  148. manim/utils/unit.py +6 -5
  149. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
  150. manim-0.19.1.dist-info/RECORD +220 -0
  151. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
  152. manim-0.19.1.dist-info/entry_points.txt +3 -0
  153. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
  154. manim/cli/new/group.py +0 -189
  155. manim/communitycolors.py +0 -9
  156. manim/gui/__init__.py +0 -0
  157. manim/gui/gui.py +0 -82
  158. manim/plugins/import_plugins.py +0 -43
  159. manim/utils/color.py +0 -552
  160. manim-0.17.0.dist-info/RECORD +0 -206
  161. manim-0.17.0.dist-info/entry_points.txt +0 -4
  162. /manim/cli/{new → checkhealth}/__init__.py +0 -0
  163. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
@@ -25,27 +25,32 @@ 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 Any
41
44
 
42
45
  import numpy as np
43
- from colour import Color
46
+ from typing_extensions import Self
44
47
 
45
48
  from manim.mobject.geometry.arc import Circle, Dot
46
49
  from manim.mobject.geometry.line import Line
47
50
  from manim.mobject.geometry.polygram import Rectangle
48
51
  from manim.mobject.geometry.shape_matchers import SurroundingRectangle
52
+ from manim.mobject.opengl.opengl_mobject import OpenGLMobject
53
+ from manim.scene.scene import Scene
49
54
 
50
55
  from .. import config
51
56
  from ..animation.animation import Animation
@@ -54,13 +59,14 @@ from ..animation.creation import Create, ShowPartial, Uncreate
54
59
  from ..animation.fading import FadeIn, FadeOut
55
60
  from ..animation.movement import Homotopy
56
61
  from ..animation.transform import Transform
62
+ from ..animation.updaters.update import UpdateFromFunc
57
63
  from ..constants import *
58
64
  from ..mobject.mobject import Mobject
59
65
  from ..mobject.types.vectorized_mobject import VGroup, VMobject
66
+ from ..typing import Point3D, Point3DLike, Vector3DLike
60
67
  from ..utils.bezier import interpolate, inverse_interpolate
61
- from ..utils.color import GREY, YELLOW
62
- from ..utils.deprecation import deprecated
63
- from ..utils.rate_functions import smooth, there_and_back, wiggle
68
+ from ..utils.color import GREY, YELLOW, ParsableManimColor
69
+ from ..utils.rate_functions import RateFunction, smooth, there_and_back, wiggle
64
70
  from ..utils.space_ops import normalize
65
71
 
66
72
 
@@ -77,8 +83,6 @@ class FocusOn(Transform):
77
83
  The color of the spotlight.
78
84
  run_time
79
85
  The duration of the animation.
80
- kwargs
81
- Additional arguments to be passed to the :class:`~.Succession` constructor
82
86
 
83
87
  Examples
84
88
  --------
@@ -94,12 +98,12 @@ class FocusOn(Transform):
94
98
 
95
99
  def __init__(
96
100
  self,
97
- focus_point: Union[np.ndarray, Mobject],
101
+ focus_point: Point3DLike | Mobject,
98
102
  opacity: float = 0.2,
99
- color: str = GREY,
103
+ color: ParsableManimColor = GREY,
100
104
  run_time: float = 2,
101
- **kwargs
102
- ) -> None:
105
+ **kwargs: Any,
106
+ ):
103
107
  self.focus_point = focus_point
104
108
  self.color = color
105
109
  self.opacity = opacity
@@ -131,7 +135,7 @@ class Indicate(Transform):
131
135
  color
132
136
  The color the mobject temporally takes.
133
137
  rate_func
134
- The function definig the animation progress at every point in time.
138
+ The function defining the animation progress at every point in time.
135
139
  kwargs
136
140
  Additional arguments to be passed to the :class:`~.Succession` constructor
137
141
 
@@ -148,17 +152,17 @@ class Indicate(Transform):
148
152
 
149
153
  def __init__(
150
154
  self,
151
- mobject: "Mobject",
155
+ mobject: Mobject,
152
156
  scale_factor: float = 1.2,
153
- color: str = YELLOW,
154
- rate_func: Callable[[float, Optional[float]], np.ndarray] = there_and_back,
155
- **kwargs
156
- ) -> None:
157
+ color: ParsableManimColor = YELLOW,
158
+ rate_func: RateFunction = there_and_back,
159
+ **kwargs: Any,
160
+ ):
157
161
  self.color = color
158
162
  self.scale_factor = scale_factor
159
163
  super().__init__(mobject, rate_func=rate_func, **kwargs)
160
164
 
161
- def create_target(self) -> "Mobject":
165
+ def create_target(self) -> Mobject | OpenGLMobject:
162
166
  target = self.mobject.copy()
163
167
  target.scale(self.scale_factor)
164
168
  target.set_color(self.color)
@@ -218,20 +222,20 @@ class Flash(AnimationGroup):
218
222
 
219
223
  def __init__(
220
224
  self,
221
- point: Union[np.ndarray, Mobject],
225
+ point: Point3DLike | Mobject,
222
226
  line_length: float = 0.2,
223
227
  num_lines: int = 12,
224
228
  flash_radius: float = 0.1,
225
229
  line_stroke_width: int = 3,
226
- color: str = YELLOW,
230
+ color: ParsableManimColor = YELLOW,
227
231
  time_width: float = 1,
228
232
  run_time: float = 1.0,
229
- **kwargs
230
- ) -> None:
233
+ **kwargs: Any,
234
+ ):
231
235
  if isinstance(point, Mobject):
232
- self.point = point.get_center()
236
+ self.point: Point3D = point.get_center()
233
237
  else:
234
- self.point = point
238
+ self.point = np.asarray(point)
235
239
  self.color = color
236
240
  self.line_length = line_length
237
241
  self.num_lines = num_lines
@@ -256,7 +260,7 @@ class Flash(AnimationGroup):
256
260
  lines.set_stroke(width=self.line_stroke_width)
257
261
  return lines
258
262
 
259
- def create_line_anims(self) -> Iterable["ShowPassingFlash"]:
263
+ def create_line_anims(self) -> Iterable[ShowPassingFlash]:
260
264
  return [
261
265
  ShowPassingFlash(
262
266
  line,
@@ -269,7 +273,7 @@ class Flash(AnimationGroup):
269
273
 
270
274
 
271
275
  class ShowPassingFlash(ShowPartial):
272
- """Show only a sliver of the VMobject each frame.
276
+ r"""Show only a sliver of the VMobject each frame.
273
277
 
274
278
  Parameters
275
279
  ----------
@@ -289,7 +293,7 @@ class ShowPassingFlash(ShowPartial):
289
293
  self.add(p, lbl)
290
294
  p = p.copy().set_color(BLUE)
291
295
  for time_width in [0.2, 0.5, 1, 2]:
292
- lbl.become(Tex(r"\\texttt{time\\_width={{%.1f}}}"%time_width))
296
+ lbl.become(Tex(r"\texttt{time\_width={{%.1f}}}"%time_width))
293
297
  self.play(ShowPassingFlash(
294
298
  p.copy().set_color(BLUE),
295
299
  run_time=2,
@@ -302,11 +306,13 @@ class ShowPassingFlash(ShowPartial):
302
306
 
303
307
  """
304
308
 
305
- def __init__(self, mobject: "VMobject", time_width: float = 0.1, **kwargs) -> None:
309
+ def __init__(
310
+ self, mobject: VMobject, time_width: float = 0.1, **kwargs: Any
311
+ ) -> None:
306
312
  self.time_width = time_width
307
313
  super().__init__(mobject, remover=True, introducer=True, **kwargs)
308
314
 
309
- def _get_bounds(self, alpha: float) -> Tuple[float]:
315
+ def _get_bounds(self, alpha: float) -> tuple[float, float]:
310
316
  tw = self.time_width
311
317
  upper = interpolate(0, 1 + tw, alpha)
312
318
  lower = upper - tw
@@ -314,14 +320,21 @@ class ShowPassingFlash(ShowPartial):
314
320
  lower = max(lower, 0)
315
321
  return (lower, upper)
316
322
 
317
- def clean_up_from_scene(self, scene: "Scene") -> None:
323
+ def clean_up_from_scene(self, scene: Scene) -> None:
318
324
  super().clean_up_from_scene(scene)
319
325
  for submob, start in self.get_all_families_zipped():
320
326
  submob.pointwise_become_partial(start, 0, 1)
321
327
 
322
328
 
323
329
  class ShowPassingFlashWithThinningStrokeWidth(AnimationGroup):
324
- def __init__(self, vmobject, n_segments=10, time_width=0.1, remover=True, **kwargs):
330
+ def __init__(
331
+ self,
332
+ vmobject: VMobject,
333
+ n_segments: int = 10,
334
+ time_width: float = 0.1,
335
+ remover: bool = True,
336
+ **kwargs: Any,
337
+ ):
325
338
  self.n_segments = n_segments
326
339
  self.time_width = time_width
327
340
  self.remover = remover
@@ -342,16 +355,6 @@ class ShowPassingFlashWithThinningStrokeWidth(AnimationGroup):
342
355
  )
343
356
 
344
357
 
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
358
  class ApplyWave(Homotopy):
356
359
  """Send a wave through the Mobject distorting it temporarily.
357
360
 
@@ -397,25 +400,25 @@ class ApplyWave(Homotopy):
397
400
 
398
401
  def __init__(
399
402
  self,
400
- mobject: "Mobject",
401
- direction: np.ndarray = UP,
403
+ mobject: Mobject,
404
+ direction: Vector3DLike = UP,
402
405
  amplitude: float = 0.2,
403
- wave_func: Callable[[float], float] = smooth,
406
+ wave_func: RateFunction = smooth,
404
407
  time_width: float = 1,
405
408
  ripples: int = 1,
406
409
  run_time: float = 2,
407
- **kwargs
408
- ) -> None:
410
+ **kwargs: Any,
411
+ ):
409
412
  x_min = mobject.get_left()[0]
410
413
  x_max = mobject.get_right()[0]
411
414
  vect = amplitude * normalize(direction)
412
415
 
413
- def wave(t):
416
+ def wave(t: float) -> float:
414
417
  # Creates a wave with n ripples from a simple rate_func
415
418
  # This wave is build up as follows:
416
419
  # The time is split into 2*ripples phases. In every phase the amplitude
417
420
  # 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,
421
+ # their amplitudes in opposing directions (first ripple from 0 to 1 to 0,
419
422
  # second from 0 to -1 to 0 and so on). This is how two ripples would be
420
423
  # divided into phases:
421
424
 
@@ -454,7 +457,7 @@ class ApplyWave(Homotopy):
454
457
  return wave_func(t * phases)
455
458
  elif phase == phases - 1:
456
459
  # last ripple. Rising or falling depending on the number of ripples
457
- # The (ripples % 2)-term is used to make this destinction.
460
+ # The (ripples % 2)-term is used to make this distinction.
458
461
  t -= phase / phases # Time relative to the phase
459
462
  return (1 - wave_func(t * phases)) * (2 * (ripples % 2) - 1)
460
463
  else:
@@ -470,13 +473,14 @@ class ApplyWave(Homotopy):
470
473
  y: float,
471
474
  z: float,
472
475
  t: float,
473
- ) -> Tuple[float, float, float]:
476
+ ) -> tuple[float, float, float]:
474
477
  upper = interpolate(0, 1 + time_width, t)
475
478
  lower = upper - time_width
476
479
  relative_x = inverse_interpolate(x_min, x_max, x)
477
480
  wave_phase = inverse_interpolate(lower, upper, relative_x)
478
481
  nudge = wave(wave_phase) * vect
479
- return np.array([x, y, z]) + nudge
482
+ return_value: tuple[float, float, float] = np.array([x, y, z]) + nudge
483
+ return return_value
480
484
 
481
485
  super().__init__(homotopy, mobject, run_time=run_time, **kwargs)
482
486
 
@@ -516,38 +520,42 @@ class Wiggle(Animation):
516
520
 
517
521
  def __init__(
518
522
  self,
519
- mobject: "Mobject",
523
+ mobject: Mobject,
520
524
  scale_value: float = 1.1,
521
525
  rotation_angle: float = 0.01 * TAU,
522
526
  n_wiggles: int = 6,
523
- scale_about_point: Optional[np.ndarray] = None,
524
- rotate_about_point: Optional[np.ndarray] = None,
527
+ scale_about_point: Point3DLike | None = None,
528
+ rotate_about_point: Point3DLike | None = None,
525
529
  run_time: float = 2,
526
- **kwargs
527
- ) -> None:
530
+ **kwargs: Any,
531
+ ):
528
532
  self.scale_value = scale_value
529
533
  self.rotation_angle = rotation_angle
530
534
  self.n_wiggles = n_wiggles
531
535
  self.scale_about_point = scale_about_point
536
+ if scale_about_point is not None:
537
+ self.scale_about_point = np.array(scale_about_point)
532
538
  self.rotate_about_point = rotate_about_point
539
+ if rotate_about_point is not None:
540
+ self.rotate_about_point = np.array(rotate_about_point)
533
541
  super().__init__(mobject, run_time=run_time, **kwargs)
534
542
 
535
- def get_scale_about_point(self) -> np.ndarray:
543
+ def get_scale_about_point(self) -> Point3D:
536
544
  if self.scale_about_point is None:
537
545
  return self.mobject.get_center()
538
546
  return self.scale_about_point
539
547
 
540
- def get_rotate_about_point(self) -> np.ndarray:
548
+ def get_rotate_about_point(self) -> Point3D:
541
549
  if self.rotate_about_point is None:
542
550
  return self.mobject.get_center()
543
551
  return self.rotate_about_point
544
552
 
545
553
  def interpolate_submobject(
546
554
  self,
547
- submobject: "Mobject",
548
- starting_submobject: "Mobject",
555
+ submobject: Mobject,
556
+ starting_submobject: Mobject,
549
557
  alpha: float,
550
- ) -> None:
558
+ ) -> Self:
551
559
  submobject.points[:, :] = starting_submobject.points
552
560
  submobject.scale(
553
561
  interpolate(1, self.scale_value, there_and_back(alpha)),
@@ -557,17 +565,18 @@ class Wiggle(Animation):
557
565
  wiggle(alpha, self.n_wiggles) * self.rotation_angle,
558
566
  about_point=self.get_rotate_about_point(),
559
567
  )
568
+ return self
560
569
 
561
570
 
562
571
  class Circumscribe(Succession):
563
- """Draw a temporary line surrounding the mobject.
572
+ r"""Draw a temporary line surrounding the mobject.
564
573
 
565
574
  Parameters
566
575
  ----------
567
576
  mobject
568
577
  The mobject to be circumscribed.
569
578
  shape
570
- The shape with which to surrond the given mobject. Should be either
579
+ The shape with which to surround the given mobject. Should be either
571
580
  :class:`~.Rectangle` or :class:`~.Circle`
572
581
  fade_in
573
582
  Whether to make the surrounding shape to fade in. It will be drawn otherwise.
@@ -591,7 +600,7 @@ class Circumscribe(Succession):
591
600
 
592
601
  class UsingCircumscribe(Scene):
593
602
  def construct(self):
594
- lbl = Tex(r"Circum-\\\\scribe").scale(2)
603
+ lbl = Tex(r"Circum-\\scribe").scale(2)
595
604
  self.add(lbl)
596
605
  self.play(Circumscribe(lbl))
597
606
  self.play(Circumscribe(lbl, Circle))
@@ -604,21 +613,21 @@ class Circumscribe(Succession):
604
613
  def __init__(
605
614
  self,
606
615
  mobject: Mobject,
607
- shape: Type = Rectangle,
608
- fade_in=False,
609
- fade_out=False,
610
- time_width=0.3,
616
+ shape: type[Rectangle] | type[Circle] = Rectangle,
617
+ fade_in: bool = False,
618
+ fade_out: bool = False,
619
+ time_width: float = 0.3,
611
620
  buff: float = SMALL_BUFF,
612
- color: Color = YELLOW,
613
- run_time=1,
614
- stroke_width=DEFAULT_STROKE_WIDTH,
615
- **kwargs
621
+ color: ParsableManimColor = YELLOW,
622
+ run_time: float = 1,
623
+ stroke_width: float = DEFAULT_STROKE_WIDTH,
624
+ **kwargs: Any,
616
625
  ):
617
626
  if shape is Rectangle:
618
- frame = SurroundingRectangle(
627
+ frame: SurroundingRectangle | Circle = SurroundingRectangle(
619
628
  mobject,
620
- color,
621
- buff,
629
+ color=color,
630
+ buff=buff,
622
631
  stroke_width=stroke_width,
623
632
  )
624
633
  elif shape is Circle:
@@ -654,3 +663,68 @@ class Circumscribe(Succession):
654
663
  super().__init__(
655
664
  ShowPassingFlash(frame, time_width, run_time=run_time), **kwargs
656
665
  )
666
+
667
+
668
+ class Blink(Succession):
669
+ """Blink the mobject.
670
+
671
+ Parameters
672
+ ----------
673
+ mobject
674
+ The mobject to be blinked.
675
+ time_on
676
+ The duration that the mobject is shown for one blink.
677
+ time_off
678
+ The duration that the mobject is hidden for one blink.
679
+ blinks
680
+ The number of blinks
681
+ hide_at_end
682
+ Whether to hide the mobject at the end of the animation.
683
+ kwargs
684
+ Additional arguments to be passed to the :class:`~.Succession` constructor.
685
+
686
+ Examples
687
+ --------
688
+
689
+ .. manim:: BlinkingExample
690
+
691
+ class BlinkingExample(Scene):
692
+ def construct(self):
693
+ text = Text("Blinking").scale(1.5)
694
+ self.add(text)
695
+ self.play(Blink(text, blinks=3))
696
+
697
+ """
698
+
699
+ def __init__(
700
+ self,
701
+ mobject: Mobject,
702
+ time_on: float = 0.5,
703
+ time_off: float = 0.5,
704
+ blinks: int = 1,
705
+ hide_at_end: bool = False,
706
+ **kwargs: Any,
707
+ ):
708
+ animations = [
709
+ UpdateFromFunc(
710
+ mobject,
711
+ update_function=lambda mob: mob.set_opacity(1.0),
712
+ run_time=time_on,
713
+ ),
714
+ UpdateFromFunc(
715
+ mobject,
716
+ update_function=lambda mob: mob.set_opacity(0.0),
717
+ run_time=time_off,
718
+ ),
719
+ ] * blinks
720
+
721
+ if not hide_at_end:
722
+ animations.append(
723
+ UpdateFromFunc(
724
+ mobject,
725
+ update_function=lambda mob: mob.set_opacity(1.0),
726
+ run_time=time_on,
727
+ ),
728
+ )
729
+
730
+ super().__init__(*animations, **kwargs)
@@ -18,7 +18,13 @@ from ..animation.animation import Animation
18
18
  from ..utils.rate_functions import linear
19
19
 
20
20
  if TYPE_CHECKING:
21
- from ..mobject.mobject import Mobject, VMobject
21
+ from typing_extensions import Self
22
+
23
+ from manim.mobject.types.vectorized_mobject import VMobject
24
+ from manim.typing import MappingFunction, Point3D
25
+ from manim.utils.rate_functions import RateFunction
26
+
27
+ from ..mobject.mobject import Mobject
22
28
 
23
29
 
24
30
  class Homotopy(Animation):
@@ -44,6 +50,26 @@ class Homotopy(Animation):
44
50
  Keyword arguments propagated to :meth:`.Mobject.apply_function`.
45
51
  kwargs
46
52
  Further keyword arguments passed to the parent class.
53
+
54
+ Examples
55
+ --------
56
+
57
+ .. manim:: HomotopyExample
58
+
59
+ class HomotopyExample(Scene):
60
+ def construct(self):
61
+ square = Square()
62
+
63
+ def homotopy(x, y, z, t):
64
+ if t <= 0.25:
65
+ progress = t / 0.25
66
+ return (x, y + progress * 0.2 * np.sin(x), z)
67
+ else:
68
+ wave_progress = (t - 0.25) / 0.75
69
+ return (x, y + 0.2 * np.sin(x + 10 * wave_progress), z)
70
+
71
+ self.play(Homotopy(homotopy, square, rate_func= linear, run_time=2))
72
+
47
73
  """
48
74
 
49
75
  def __init__(
@@ -52,27 +78,33 @@ class Homotopy(Animation):
52
78
  mobject: Mobject,
53
79
  run_time: float = 3,
54
80
  apply_function_kwargs: dict[str, Any] | None = None,
55
- **kwargs,
56
- ) -> None:
81
+ **kwargs: Any,
82
+ ):
57
83
  self.homotopy = homotopy
58
84
  self.apply_function_kwargs = (
59
85
  apply_function_kwargs if apply_function_kwargs is not None else {}
60
86
  )
61
87
  super().__init__(mobject, run_time=run_time, **kwargs)
62
88
 
63
- def function_at_time_t(self, t: float) -> tuple[float, float, float]:
64
- return lambda p: self.homotopy(*p, t)
89
+ def function_at_time_t(self, t: float) -> MappingFunction:
90
+ def mapping_function(p: Point3D) -> Point3D:
91
+ x, y, z = p
92
+ return np.array(self.homotopy(x, y, z, t))
93
+
94
+ return mapping_function
65
95
 
66
96
  def interpolate_submobject(
67
97
  self,
68
98
  submobject: Mobject,
69
99
  starting_submobject: Mobject,
70
100
  alpha: float,
71
- ) -> None:
101
+ ) -> Self:
72
102
  submobject.points = starting_submobject.points
73
103
  submobject.apply_function(
74
- self.function_at_time_t(alpha), **self.apply_function_kwargs
104
+ self.function_at_time_t(alpha),
105
+ **self.apply_function_kwargs,
75
106
  )
107
+ return self
76
108
 
77
109
 
78
110
  class SmoothedVectorizedHomotopy(Homotopy):
@@ -81,18 +113,21 @@ class SmoothedVectorizedHomotopy(Homotopy):
81
113
  submobject: Mobject,
82
114
  starting_submobject: Mobject,
83
115
  alpha: float,
84
- ) -> None:
116
+ ) -> Self:
117
+ assert isinstance(submobject, VMobject)
85
118
  super().interpolate_submobject(submobject, starting_submobject, alpha)
86
119
  submobject.make_smooth()
120
+ return self
87
121
 
88
122
 
89
123
  class ComplexHomotopy(Homotopy):
90
124
  def __init__(
91
- self, complex_homotopy: Callable[[complex], float], mobject: Mobject, **kwargs
92
- ) -> None:
93
- """
94
- Complex Homotopy a function Cx[0, 1] to C
95
- """
125
+ self,
126
+ complex_homotopy: Callable[[complex, float], float],
127
+ mobject: Mobject,
128
+ **kwargs: Any,
129
+ ):
130
+ """Complex Homotopy a function Cx[0, 1] to C"""
96
131
 
97
132
  def homotopy(
98
133
  x: float,
@@ -113,9 +148,9 @@ class PhaseFlow(Animation):
113
148
  mobject: Mobject,
114
149
  virtual_time: float = 1,
115
150
  suspend_mobject_updating: bool = False,
116
- rate_func: Callable[[float], float] = linear,
117
- **kwargs,
118
- ) -> None:
151
+ rate_func: RateFunction = linear,
152
+ **kwargs: Any,
153
+ ):
119
154
  self.virtual_time = virtual_time
120
155
  self.function = function
121
156
  super().__init__(
@@ -131,13 +166,12 @@ class PhaseFlow(Animation):
131
166
  self.rate_func(alpha) - self.rate_func(self.last_alpha)
132
167
  )
133
168
  self.mobject.apply_function(lambda p: p + dt * self.function(p))
134
- self.last_alpha = alpha
169
+ self.last_alpha: float = alpha
135
170
 
136
171
 
137
172
  class MoveAlongPath(Animation):
138
173
  """Make one mobject move along the path of another mobject.
139
- Example
140
- --------
174
+
141
175
  .. manim:: MoveAlongPathExample
142
176
 
143
177
  class MoveAlongPathExample(Scene):
@@ -154,9 +188,9 @@ class MoveAlongPath(Animation):
154
188
  self,
155
189
  mobject: Mobject,
156
190
  path: VMobject,
157
- suspend_mobject_updating: bool | None = False,
158
- **kwargs,
159
- ) -> None:
191
+ suspend_mobject_updating: bool = False,
192
+ **kwargs: Any,
193
+ ):
160
194
  self.path = path
161
195
  super().__init__(
162
196
  mobject, suspend_mobject_updating=suspend_mobject_updating, **kwargs