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/scene/scene.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from manim.utils.parameter_parsing import flatten_iterable_parameters
6
+
5
7
  __all__ = ["Scene"]
6
8
 
7
9
  import copy
@@ -13,7 +15,6 @@ import threading
13
15
  import time
14
16
  import types
15
17
  from queue import Queue
16
- from typing import Callable
17
18
 
18
19
  import srt
19
20
 
@@ -25,6 +26,8 @@ try:
25
26
  dearpygui_imported = True
26
27
  except ImportError:
27
28
  dearpygui_imported = False
29
+ from typing import TYPE_CHECKING
30
+
28
31
  import numpy as np
29
32
  from tqdm import tqdm
30
33
  from watchdog.events import FileSystemEventHandler
@@ -48,6 +51,12 @@ from ..utils.family_ops import restructure_list_to_exclude_certain_family_member
48
51
  from ..utils.file_ops import open_media_file
49
52
  from ..utils.iterables import list_difference_update, list_update
50
53
 
54
+ if TYPE_CHECKING:
55
+ from collections.abc import Sequence
56
+ from typing import Callable
57
+
58
+ from manim.mobject.mobject import _AnimationBuilder
59
+
51
60
 
52
61
  class RerunSceneHandler(FileSystemEventHandler):
53
62
  """A class to handle rerunning a Scene after the input file is modified."""
@@ -93,12 +102,12 @@ class Scene:
93
102
 
94
103
  def __init__(
95
104
  self,
96
- renderer=None,
97
- camera_class=Camera,
98
- always_update_mobjects=False,
99
- random_seed=None,
100
- skip_animations=False,
101
- ):
105
+ renderer: CairoRenderer | OpenGLRenderer | None = None,
106
+ camera_class: type[Camera] = Camera,
107
+ always_update_mobjects: bool = False,
108
+ random_seed: int | None = None,
109
+ skip_animations: bool = False,
110
+ ) -> None:
102
111
  self.camera_class = camera_class
103
112
  self.always_update_mobjects = always_update_mobjects
104
113
  self.random_seed = random_seed
@@ -151,6 +160,11 @@ class Scene:
151
160
  def camera(self):
152
161
  return self.renderer.camera
153
162
 
163
+ @property
164
+ def time(self) -> float:
165
+ """The time since the start of the scene."""
166
+ return self.renderer.time
167
+
154
168
  def __deepcopy__(self, clone_from_id):
155
169
  cls = self.__class__
156
170
  result = cls.__new__(cls)
@@ -223,7 +237,7 @@ class Scene:
223
237
  self.construct()
224
238
  except EndSceneEarlyException:
225
239
  pass
226
- except RerunSceneException as e:
240
+ except RerunSceneException:
227
241
  self.remove(*self.mobjects)
228
242
  self.renderer.clear_screen()
229
243
  self.renderer.num_plays = 0
@@ -281,7 +295,7 @@ class Scene:
281
295
  Examples
282
296
  --------
283
297
  A typical manim script includes a class derived from :class:`Scene` with an
284
- overridden :meth:`Scene.contruct` method:
298
+ overridden :meth:`Scene.construct` method:
285
299
 
286
300
  .. code-block:: python
287
301
 
@@ -301,14 +315,14 @@ class Scene:
301
315
  def next_section(
302
316
  self,
303
317
  name: str = "unnamed",
304
- type: str = DefaultSectionType.NORMAL,
318
+ section_type: str = DefaultSectionType.NORMAL,
305
319
  skip_animations: bool = False,
306
320
  ) -> None:
307
321
  """Create separation here; the last section gets finished and a new one gets created.
308
322
  ``skip_animations`` skips the rendering of all animations in this section.
309
323
  Refer to :doc:`the documentation</tutorials/output_and_config>` on how to use sections.
310
324
  """
311
- self.renderer.file_writer.next_section(name, type, skip_animations)
325
+ self.renderer.file_writer.next_section(name, section_type, skip_animations)
312
326
 
313
327
  def __str__(self):
314
328
  return self.__class__.__name__
@@ -474,7 +488,7 @@ class Scene:
474
488
  self.moving_mobjects += mobjects
475
489
  return self
476
490
 
477
- def add_mobjects_from_animations(self, animations):
491
+ def add_mobjects_from_animations(self, animations: list[Animation]) -> None:
478
492
  curr_mobjects = self.get_mobject_family_members()
479
493
  for animation in animations:
480
494
  if animation.is_introducer():
@@ -613,7 +627,7 @@ class Scene:
613
627
 
614
628
  def restructure_mobjects(
615
629
  self,
616
- to_remove: Mobject,
630
+ to_remove: Sequence[Mobject],
617
631
  mobject_list_name: str = "mobjects",
618
632
  extract_families: bool = True,
619
633
  ):
@@ -673,7 +687,6 @@ class Scene:
673
687
  list
674
688
  The list of mobjects with the mobjects to remove removed.
675
689
  """
676
-
677
690
  new_mobjects = []
678
691
 
679
692
  def add_safe_mobjects_from_list(list_to_examine, set_to_remove):
@@ -865,7 +878,11 @@ class Scene:
865
878
  )
866
879
  return all_moving_mobject_families, static_mobjects
867
880
 
868
- def compile_animations(self, *args: Animation, **kwargs):
881
+ def compile_animations(
882
+ self,
883
+ *args: Animation | Mobject | _AnimationBuilder,
884
+ **kwargs,
885
+ ):
869
886
  """
870
887
  Creates _MethodAnimations from any _AnimationBuilders and updates animation
871
888
  kwargs with kwargs passed to play().
@@ -883,19 +900,21 @@ class Scene:
883
900
  Animations to be played.
884
901
  """
885
902
  animations = []
886
- for arg in args:
903
+ arg_anims = flatten_iterable_parameters(args)
904
+ # Allow passing a generator to self.play instead of comma separated arguments
905
+ for arg in arg_anims:
887
906
  try:
888
907
  animations.append(prepare_animation(arg))
889
- except TypeError:
908
+ except TypeError as e:
890
909
  if inspect.ismethod(arg):
891
910
  raise TypeError(
892
911
  "Passing Mobject methods to Scene.play is no longer"
893
912
  " supported. Use Mobject.animate instead.",
894
- )
913
+ ) from e
895
914
  else:
896
915
  raise TypeError(
897
916
  f"Unexpected argument {arg} passed to Scene.play().",
898
- )
917
+ ) from e
899
918
 
900
919
  for animation in animations:
901
920
  for k, v in kwargs.items():
@@ -1003,6 +1022,35 @@ class Scene:
1003
1022
  )
1004
1023
  return time_progression
1005
1024
 
1025
+ @classmethod
1026
+ def validate_run_time(
1027
+ cls,
1028
+ run_time: float,
1029
+ method: Callable[[Any, ...], Any],
1030
+ parameter_name: str = "run_time",
1031
+ ) -> float:
1032
+ method_name = f"{cls.__name__}.{method.__name__}()"
1033
+ if run_time <= 0:
1034
+ raise ValueError(
1035
+ f"{method_name} has a {parameter_name} of "
1036
+ f"{run_time:g} <= 0 seconds which Manim cannot render. "
1037
+ f"The {parameter_name} must be a positive number."
1038
+ )
1039
+
1040
+ # config.frame_rate holds the number of frames per second
1041
+ fps = config.frame_rate
1042
+ seconds_per_frame = 1 / fps
1043
+ if run_time < seconds_per_frame:
1044
+ logger.warning(
1045
+ f"The original {parameter_name} of {method_name}, "
1046
+ f"{run_time:g} seconds, is too short for the current frame "
1047
+ f"rate of {fps:g} FPS. Rendering with the shortest possible "
1048
+ f"{parameter_name} of {seconds_per_frame:g} seconds instead."
1049
+ )
1050
+ run_time = seconds_per_frame
1051
+
1052
+ return run_time
1053
+
1006
1054
  def get_run_time(self, animations: list[Animation]):
1007
1055
  """
1008
1056
  Gets the total run time for a list of animations.
@@ -1018,16 +1066,13 @@ class Scene:
1018
1066
  float
1019
1067
  The total ``run_time`` of all of the animations in the list.
1020
1068
  """
1021
-
1022
- if len(animations) == 1 and isinstance(animations[0], Wait):
1023
- return animations[0].duration
1024
-
1025
- else:
1026
- return np.max([animation.run_time for animation in animations])
1069
+ run_time = max(animation.run_time for animation in animations)
1070
+ run_time = self.validate_run_time(run_time, self.play, "total run_time")
1071
+ return run_time
1027
1072
 
1028
1073
  def play(
1029
1074
  self,
1030
- *args,
1075
+ *args: Animation | Mobject | _AnimationBuilder,
1031
1076
  subcaption=None,
1032
1077
  subcaption_duration=None,
1033
1078
  subcaption_offset=0,
@@ -1076,15 +1121,15 @@ class Scene:
1076
1121
  )
1077
1122
  return
1078
1123
 
1079
- start_time = self.renderer.time
1124
+ start_time = self.time
1080
1125
  self.renderer.play(self, *args, **kwargs)
1081
- run_time = self.renderer.time - start_time
1126
+ run_time = self.time - start_time
1082
1127
  if subcaption:
1083
1128
  if subcaption_duration is None:
1084
1129
  subcaption_duration = run_time
1085
1130
  # The start of the subcaption needs to be offset by the
1086
1131
  # run_time of the animation because it is added after
1087
- # the animation has already been played (and Scene.renderer.time
1132
+ # the animation has already been played (and Scene.time
1088
1133
  # has already been updated).
1089
1134
  self.add_subcaption(
1090
1135
  content=subcaption,
@@ -1119,6 +1164,7 @@ class Scene:
1119
1164
  --------
1120
1165
  :class:`.Wait`, :meth:`.should_mobjects_update`
1121
1166
  """
1167
+ duration = self.validate_run_time(duration, self.wait, "duration")
1122
1168
  self.play(
1123
1169
  Wait(
1124
1170
  run_time=duration,
@@ -1142,6 +1188,7 @@ class Scene:
1142
1188
  --------
1143
1189
  :meth:`.wait`, :class:`.Wait`
1144
1190
  """
1191
+ duration = self.validate_run_time(duration, self.pause, "duration")
1145
1192
  self.wait(duration=duration, frozen_frame=True)
1146
1193
 
1147
1194
  def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60):
@@ -1155,9 +1202,14 @@ class Scene:
1155
1202
  max_time
1156
1203
  The maximum wait time in seconds.
1157
1204
  """
1205
+ max_time = self.validate_run_time(max_time, self.wait_until, "max_time")
1158
1206
  self.wait(max_time, stop_condition=stop_condition)
1159
1207
 
1160
- def compile_animation_data(self, *animations: Animation, **play_kwargs):
1208
+ def compile_animation_data(
1209
+ self,
1210
+ *animations: Animation | Mobject | _AnimationBuilder,
1211
+ **play_kwargs,
1212
+ ):
1161
1213
  """Given a list of animations, compile the corresponding
1162
1214
  static and moving mobjects, and gather the animation durations.
1163
1215
 
@@ -1189,16 +1241,16 @@ class Scene:
1189
1241
  self.moving_mobjects = []
1190
1242
  self.static_mobjects = []
1191
1243
 
1244
+ self.duration = self.get_run_time(self.animations)
1192
1245
  if len(self.animations) == 1 and isinstance(self.animations[0], Wait):
1193
1246
  if self.should_update_mobjects():
1194
1247
  self.update_mobjects(dt=0) # Any problems with this?
1195
1248
  self.stop_condition = self.animations[0].stop_condition
1196
1249
  else:
1197
- self.duration = self.animations[0].duration
1198
1250
  # Static image logic when the wait is static is done by the renderer, not here.
1199
1251
  self.animations[0].is_static_wait = True
1200
1252
  return None
1201
- self.duration = self.get_run_time(self.animations)
1253
+
1202
1254
  return self
1203
1255
 
1204
1256
  def begin_animations(self) -> None:
@@ -1282,9 +1334,7 @@ class Scene:
1282
1334
  return True
1283
1335
 
1284
1336
  def interactive_embed(self):
1285
- """
1286
- Like embed(), but allows for screen interaction.
1287
- """
1337
+ """Like embed(), but allows for screen interaction."""
1288
1338
  if not self.check_interactive_embed_is_valid():
1289
1339
  return
1290
1340
  self.interactive_mode = True
@@ -1492,7 +1542,7 @@ class Scene:
1492
1542
  r"""Adds an entry in the corresponding subcaption file
1493
1543
  at the current time stamp.
1494
1544
 
1495
- The current time stamp is obtained from ``Scene.renderer.time``.
1545
+ The current time stamp is obtained from ``Scene.time``.
1496
1546
 
1497
1547
  Parameters
1498
1548
  ----------
@@ -1522,18 +1572,15 @@ class Scene:
1522
1572
 
1523
1573
  # second option: within the call to Scene.play
1524
1574
  self.play(
1525
- Transform(square, circle),
1526
- subcaption="The square transforms."
1575
+ Transform(square, circle), subcaption="The square transforms."
1527
1576
  )
1528
1577
 
1529
1578
  """
1530
1579
  subtitle = srt.Subtitle(
1531
1580
  index=len(self.renderer.file_writer.subcaptions),
1532
1581
  content=content,
1533
- start=datetime.timedelta(seconds=float(self.renderer.time + offset)),
1534
- end=datetime.timedelta(
1535
- seconds=float(self.renderer.time + offset + duration)
1536
- ),
1582
+ start=datetime.timedelta(seconds=float(self.time + offset)),
1583
+ end=datetime.timedelta(seconds=float(self.time + offset + duration)),
1537
1584
  )
1538
1585
  self.renderer.file_writer.subcaptions.append(subtitle)
1539
1586
 
@@ -1581,7 +1628,7 @@ class Scene:
1581
1628
  """
1582
1629
  if self.renderer.skip_animations:
1583
1630
  return
1584
- time = self.renderer.time + time_offset
1631
+ time = self.time + time_offset
1585
1632
  self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs)
1586
1633
 
1587
1634
  def on_mouse_motion(self, point, d_point):