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.

Files changed (129) hide show
  1. manim/__main__.py +45 -12
  2. manim/_config/__init__.py +2 -2
  3. manim/_config/cli_colors.py +8 -4
  4. manim/_config/default.cfg +0 -2
  5. manim/_config/logger_utils.py +5 -0
  6. manim/_config/utils.py +29 -38
  7. manim/animation/animation.py +148 -8
  8. manim/animation/composition.py +16 -13
  9. manim/animation/creation.py +184 -8
  10. manim/animation/fading.py +5 -8
  11. manim/animation/indication.py +93 -26
  12. manim/animation/movement.py +21 -3
  13. manim/animation/rotation.py +2 -1
  14. manim/animation/specialized.py +3 -5
  15. manim/animation/speedmodifier.py +3 -3
  16. manim/animation/transform.py +4 -5
  17. manim/animation/updaters/mobject_update_utils.py +17 -14
  18. manim/camera/camera.py +2 -2
  19. manim/cli/__init__.py +17 -0
  20. manim/cli/cfg/group.py +52 -36
  21. manim/cli/checkhealth/checks.py +92 -76
  22. manim/cli/checkhealth/commands.py +12 -5
  23. manim/cli/default_group.py +148 -24
  24. manim/cli/init/commands.py +28 -23
  25. manim/cli/plugins/commands.py +13 -3
  26. manim/cli/render/commands.py +47 -42
  27. manim/cli/render/global_options.py +43 -9
  28. manim/cli/render/render_options.py +84 -19
  29. manim/constants.py +11 -4
  30. manim/mobject/frame.py +0 -1
  31. manim/mobject/geometry/arc.py +109 -75
  32. manim/mobject/geometry/boolean_ops.py +20 -17
  33. manim/mobject/geometry/labeled.py +300 -77
  34. manim/mobject/geometry/line.py +120 -60
  35. manim/mobject/geometry/polygram.py +109 -25
  36. manim/mobject/geometry/shape_matchers.py +35 -15
  37. manim/mobject/geometry/tips.py +36 -27
  38. manim/mobject/graph.py +48 -40
  39. manim/mobject/graphing/coordinate_systems.py +110 -45
  40. manim/mobject/graphing/functions.py +16 -10
  41. manim/mobject/graphing/number_line.py +23 -9
  42. manim/mobject/graphing/probability.py +2 -10
  43. manim/mobject/graphing/scale.py +6 -5
  44. manim/mobject/matrix.py +17 -19
  45. manim/mobject/mobject.py +149 -103
  46. manim/mobject/opengl/opengl_geometry.py +4 -8
  47. manim/mobject/opengl/opengl_mobject.py +506 -343
  48. manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
  49. manim/mobject/opengl/opengl_surface.py +1 -2
  50. manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
  51. manim/mobject/svg/brace.py +61 -13
  52. manim/mobject/svg/svg_mobject.py +2 -1
  53. manim/mobject/table.py +11 -12
  54. manim/mobject/text/code_mobject.py +186 -550
  55. manim/mobject/text/numbers.py +7 -7
  56. manim/mobject/text/tex_mobject.py +22 -13
  57. manim/mobject/text/text_mobject.py +29 -20
  58. manim/mobject/three_d/polyhedra.py +98 -1
  59. manim/mobject/three_d/three_dimensions.py +59 -31
  60. manim/mobject/types/image_mobject.py +37 -23
  61. manim/mobject/types/point_cloud_mobject.py +103 -67
  62. manim/mobject/types/vectorized_mobject.py +387 -214
  63. manim/mobject/value_tracker.py +2 -1
  64. manim/mobject/vector_field.py +2 -4
  65. manim/opengl/__init__.py +3 -3
  66. manim/plugins/__init__.py +2 -3
  67. manim/plugins/plugins_flags.py +3 -3
  68. manim/renderer/cairo_renderer.py +11 -11
  69. manim/renderer/opengl_renderer.py +19 -20
  70. manim/renderer/shader.py +2 -3
  71. manim/renderer/shader_wrapper.py +3 -2
  72. manim/scene/moving_camera_scene.py +23 -0
  73. manim/scene/scene.py +72 -41
  74. manim/scene/scene_file_writer.py +313 -164
  75. manim/scene/section.py +15 -15
  76. manim/scene/three_d_scene.py +8 -15
  77. manim/scene/vector_space_scene.py +3 -6
  78. manim/typing.py +326 -66
  79. manim/utils/bezier.py +1658 -381
  80. manim/utils/caching.py +11 -5
  81. manim/utils/color/AS2700.py +2 -0
  82. manim/utils/color/BS381.py +2 -0
  83. manim/utils/color/DVIPSNAMES.py +96 -0
  84. manim/utils/color/SVGNAMES.py +179 -0
  85. manim/utils/color/X11.py +3 -0
  86. manim/utils/color/XKCD.py +2 -0
  87. manim/utils/color/__init__.py +8 -5
  88. manim/utils/color/core.py +818 -301
  89. manim/utils/color/manim_colors.py +7 -9
  90. manim/utils/commands.py +40 -19
  91. manim/utils/config_ops.py +18 -13
  92. manim/utils/debug.py +8 -6
  93. manim/utils/deprecation.py +92 -43
  94. manim/utils/docbuild/autoaliasattr_directive.py +45 -8
  95. manim/utils/docbuild/autocolor_directive.py +12 -13
  96. manim/utils/docbuild/manim_directive.py +35 -29
  97. manim/utils/docbuild/module_parsing.py +74 -27
  98. manim/utils/family.py +3 -3
  99. manim/utils/family_ops.py +12 -4
  100. manim/utils/file_ops.py +22 -16
  101. manim/utils/hashing.py +7 -7
  102. manim/utils/images.py +10 -4
  103. manim/utils/ipython_magic.py +12 -8
  104. manim/utils/iterables.py +161 -119
  105. manim/utils/module_ops.py +55 -19
  106. manim/utils/opengl.py +68 -23
  107. manim/utils/parameter_parsing.py +3 -2
  108. manim/utils/paths.py +11 -5
  109. manim/utils/polylabel.py +168 -0
  110. manim/utils/qhull.py +218 -0
  111. manim/utils/rate_functions.py +69 -32
  112. manim/utils/simple_functions.py +24 -15
  113. manim/utils/sounds.py +7 -1
  114. manim/utils/space_ops.py +48 -37
  115. manim/utils/testing/_frames_testers.py +13 -8
  116. manim/utils/testing/_show_diff.py +5 -3
  117. manim/utils/testing/_test_class_makers.py +33 -18
  118. manim/utils/testing/frames_comparison.py +20 -14
  119. manim/utils/tex.py +4 -2
  120. manim/utils/tex_file_writing.py +45 -45
  121. manim/utils/tex_templates.py +1 -1
  122. manim/utils/unit.py +6 -5
  123. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
  124. manim-0.19.0.dist-info/RECORD +221 -0
  125. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
  126. manim-0.18.1.dist-info/RECORD +0 -217
  127. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
  128. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
  129. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/mobject/mobject.py CHANGED
@@ -14,9 +14,10 @@ import random
14
14
  import sys
15
15
  import types
16
16
  import warnings
17
+ from collections.abc import Iterable
17
18
  from functools import partialmethod, reduce
18
19
  from pathlib import Path
19
- from typing import TYPE_CHECKING, Callable, Iterable, Literal
20
+ from typing import TYPE_CHECKING
20
21
 
21
22
  import numpy as np
22
23
 
@@ -39,17 +40,19 @@ from ..utils.paths import straight_path
39
40
  from ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix
40
41
 
41
42
  if TYPE_CHECKING:
43
+ from typing import Any, Callable, Literal
44
+
42
45
  from typing_extensions import Self, TypeAlias
43
46
 
44
47
  from manim.typing import (
45
48
  FunctionOverride,
46
- Image,
47
- ManimFloat,
48
- ManimInt,
49
49
  MappingFunction,
50
+ MultiMappingFunction,
50
51
  PathFuncType,
52
+ PixelArray,
51
53
  Point3D,
52
- Point3D_Array,
54
+ Point3DLike,
55
+ Point3DLike_Array,
53
56
  Vector3D,
54
57
  )
55
58
 
@@ -115,6 +118,63 @@ class Mobject:
115
118
  self.generate_points()
116
119
  self.init_colors()
117
120
 
121
+ def _assert_valid_submobjects(self, submobjects: Iterable[Mobject]) -> Self:
122
+ """Check that all submobjects are actually instances of
123
+ :class:`Mobject`, and that none of them is ``self`` (a
124
+ :class:`Mobject` cannot contain itself).
125
+
126
+ This is an auxiliary function called when adding Mobjects to the
127
+ :attr:`submobjects` list.
128
+
129
+ This function is intended to be overridden by subclasses such as
130
+ :class:`VMobject`, which should assert that only other VMobjects
131
+ may be added into it.
132
+
133
+ Parameters
134
+ ----------
135
+ submobjects
136
+ The list containing values to validate.
137
+
138
+ Returns
139
+ -------
140
+ :class:`Mobject`
141
+ The Mobject itself.
142
+
143
+ Raises
144
+ ------
145
+ TypeError
146
+ If any of the values in `submobjects` is not a :class:`Mobject`.
147
+ ValueError
148
+ If there was an attempt to add a :class:`Mobject` as its own
149
+ submobject.
150
+ """
151
+ return self._assert_valid_submobjects_internal(submobjects, Mobject)
152
+
153
+ def _assert_valid_submobjects_internal(
154
+ self, submobjects: list[Mobject], mob_class: type[Mobject]
155
+ ) -> Self:
156
+ for i, submob in enumerate(submobjects):
157
+ if not isinstance(submob, mob_class):
158
+ error_message = (
159
+ f"Only values of type {mob_class.__name__} can be added "
160
+ f"as submobjects of {type(self).__name__}, but the value "
161
+ f"{submob} (at index {i}) is of type "
162
+ f"{type(submob).__name__}."
163
+ )
164
+ # Intended for subclasses such as VMobject, which
165
+ # cannot have regular Mobjects as submobjects
166
+ if isinstance(submob, Mobject):
167
+ error_message += (
168
+ " You can try adding this value into a Group instead."
169
+ )
170
+ raise TypeError(error_message)
171
+ if submob is self:
172
+ raise ValueError(
173
+ f"Cannot add {type(self).__name__} as a submobject of "
174
+ f"itself (at index {i})."
175
+ )
176
+ return self
177
+
118
178
  @classmethod
119
179
  def animation_override_for(
120
180
  cls,
@@ -258,7 +318,9 @@ class Mobject:
258
318
 
259
319
  ::
260
320
 
261
- self.play(my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI))
321
+ self.play(
322
+ my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI)
323
+ )
262
324
 
263
325
  make use of method chaining.
264
326
 
@@ -348,14 +410,14 @@ class Mobject:
348
410
  """Sets :attr:`points` to be an empty array."""
349
411
  self.points = np.zeros((0, self.dim))
350
412
 
351
- def init_colors(self) -> None:
413
+ def init_colors(self) -> object:
352
414
  """Initializes the colors.
353
415
 
354
416
  Gets called upon creation. This is an empty method that can be implemented by
355
417
  subclasses.
356
418
  """
357
419
 
358
- def generate_points(self) -> None:
420
+ def generate_points(self) -> object:
359
421
  """Initializes :attr:`points` and therefore the shape.
360
422
 
361
423
  Gets called upon creation. This is an empty method that can be implemented by
@@ -413,12 +475,19 @@ class Mobject:
413
475
  >>> len(outer.submobjects)
414
476
  1
415
477
 
478
+ Only Mobjects can be added::
479
+
480
+ >>> outer.add(3)
481
+ Traceback (most recent call last):
482
+ ...
483
+ TypeError: Only values of type Mobject can be added as submobjects of Mobject, but the value 3 (at index 0) is of type int.
484
+
416
485
  Adding an object to itself raises an error::
417
486
 
418
487
  >>> outer.add(outer)
419
488
  Traceback (most recent call last):
420
489
  ...
421
- ValueError: Mobject cannot contain self
490
+ ValueError: Cannot add Mobject as a submobject of itself (at index 0).
422
491
 
423
492
  A given mobject cannot be added as a submobject
424
493
  twice to some parent::
@@ -432,12 +501,7 @@ class Mobject:
432
501
  [child]
433
502
 
434
503
  """
435
- for m in mobjects:
436
- if not isinstance(m, Mobject):
437
- raise TypeError("All submobjects must be of type Mobject")
438
- if m is self:
439
- raise ValueError("Mobject cannot contain self")
440
-
504
+ self._assert_valid_submobjects(mobjects)
441
505
  unique_mobjects = remove_list_redundancies(mobjects)
442
506
  if len(mobjects) != len(unique_mobjects):
443
507
  logger.warning(
@@ -463,10 +527,7 @@ class Mobject:
463
527
  mobject
464
528
  The mobject to be inserted.
465
529
  """
466
- if not isinstance(mobject, Mobject):
467
- raise TypeError("All submobjects must be of type Mobject")
468
- if mobject is self:
469
- raise ValueError("Mobject cannot contain self")
530
+ self._assert_valid_submobjects([mobject])
470
531
  self.submobjects.insert(index, mobject)
471
532
 
472
533
  def __add__(self, mobject: Mobject):
@@ -519,13 +580,7 @@ class Mobject:
519
580
  :meth:`add`
520
581
 
521
582
  """
522
- if self in mobjects:
523
- raise ValueError("A mobject shouldn't contain itself")
524
-
525
- for mobject in mobjects:
526
- if not isinstance(mobject, Mobject):
527
- raise TypeError("All submobjects must be of type Mobject")
528
-
583
+ self._assert_valid_submobjects(mobjects)
529
584
  self.remove(*mobjects)
530
585
  # dict.fromkeys() removes duplicates while maintaining order
531
586
  self.submobjects = list(dict.fromkeys(mobjects)) + self.submobjects
@@ -615,7 +670,6 @@ class Mobject:
615
670
  >>> mob.foo
616
671
  0
617
672
  """
618
-
619
673
  for attr, value in kwargs.items():
620
674
  setattr(self, attr, value)
621
675
 
@@ -697,7 +751,6 @@ class Mobject:
697
751
  :meth:`length_over_dim`
698
752
 
699
753
  """
700
-
701
754
  # Get the length across the X dimension
702
755
  return self.length_over_dim(0)
703
756
 
@@ -734,7 +787,6 @@ class Mobject:
734
787
  :meth:`length_over_dim`
735
788
 
736
789
  """
737
-
738
790
  # Get the length across the Y dimension
739
791
  return self.length_over_dim(1)
740
792
 
@@ -755,7 +807,6 @@ class Mobject:
755
807
  :meth:`length_over_dim`
756
808
 
757
809
  """
758
-
759
810
  # Get the length across the Z dimension
760
811
  return self.length_over_dim(2)
761
812
 
@@ -767,14 +818,14 @@ class Mobject:
767
818
  def get_array_attrs(self) -> list[Literal["points"]]:
768
819
  return ["points"]
769
820
 
770
- def apply_over_attr_arrays(self, func: MappingFunction) -> Self:
821
+ def apply_over_attr_arrays(self, func: MultiMappingFunction) -> Self:
771
822
  for attr in self.get_array_attrs():
772
823
  setattr(self, attr, func(getattr(self, attr)))
773
824
  return self
774
825
 
775
826
  # Displaying
776
827
 
777
- def get_image(self, camera=None) -> Image:
828
+ def get_image(self, camera=None) -> PixelArray:
778
829
  if camera is None:
779
830
  from ..camera.camera import Camera
780
831
 
@@ -787,7 +838,8 @@ class Mobject:
787
838
 
788
839
  def save_image(self, name: str | None = None) -> None:
789
840
  """Saves an image of only this :class:`Mobject` at its position to a png
790
- file."""
841
+ file.
842
+ """
791
843
  self.get_image().save(
792
844
  Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"),
793
845
  )
@@ -978,7 +1030,6 @@ class Mobject:
978
1030
  :meth:`remove_updater`
979
1031
  :class:`~.UpdateFromFunc`
980
1032
  """
981
-
982
1033
  if index is None:
983
1034
  self.updaters.append(update_function)
984
1035
  else:
@@ -1068,7 +1119,6 @@ class Mobject:
1068
1119
  :meth:`clear_updaters`
1069
1120
 
1070
1121
  """
1071
-
1072
1122
  self.clear_updaters()
1073
1123
  for updater in mobject.get_updaters():
1074
1124
  self.add_updater(updater)
@@ -1094,7 +1144,6 @@ class Mobject:
1094
1144
  :meth:`add_updater`
1095
1145
 
1096
1146
  """
1097
-
1098
1147
  self.updating_suspended = True
1099
1148
  if recursive:
1100
1149
  for submob in self.submobjects:
@@ -1169,7 +1218,6 @@ class Mobject:
1169
1218
  --------
1170
1219
  :meth:`move_to`
1171
1220
  """
1172
-
1173
1221
  total_vector = reduce(op.add, vectors)
1174
1222
  for mob in self.family_members_with_points():
1175
1223
  mob.points = mob.points.astype("float")
@@ -1231,7 +1279,7 @@ class Mobject:
1231
1279
  self,
1232
1280
  angle: float,
1233
1281
  axis: Vector3D = OUT,
1234
- about_point: Point3D | None = None,
1282
+ about_point: Point3DLike | None = None,
1235
1283
  **kwargs,
1236
1284
  ) -> Self:
1237
1285
  """Rotates the :class:`~.Mobject` about a certain point."""
@@ -1261,7 +1309,7 @@ class Mobject:
1261
1309
  return self.rotate(TAU / 2, axis, **kwargs)
1262
1310
 
1263
1311
  def stretch(self, factor: float, dim: int, **kwargs) -> Self:
1264
- def func(points):
1312
+ def func(points: Point3D_Array) -> Point3D_Array:
1265
1313
  points[:, dim] *= factor
1266
1314
  return points
1267
1315
 
@@ -1272,9 +1320,12 @@ class Mobject:
1272
1320
  # Default to applying matrix about the origin, not mobjects center
1273
1321
  if len(kwargs) == 0:
1274
1322
  kwargs["about_point"] = ORIGIN
1275
- self.apply_points_function_about_point(
1276
- lambda points: np.apply_along_axis(function, 1, points), **kwargs
1277
- )
1323
+
1324
+ def multi_mapping_function(points: Point3D_Array) -> Point3D_Array:
1325
+ result: Point3D_Array = np.apply_along_axis(function, 1, points)
1326
+ return result
1327
+
1328
+ self.apply_points_function_about_point(multi_mapping_function, **kwargs)
1278
1329
  return self
1279
1330
 
1280
1331
  def apply_function_to_position(self, function: MappingFunction) -> Self:
@@ -1353,11 +1404,12 @@ class Mobject:
1353
1404
  # Note, much of these are now redundant with default behavior of
1354
1405
  # above methods
1355
1406
 
1407
+ # TODO: name is inconsistent with OpenGLMobject.apply_points_function()
1356
1408
  def apply_points_function_about_point(
1357
1409
  self,
1358
- func: MappingFunction,
1359
- about_point: Point3D = None,
1360
- about_edge=None,
1410
+ func: MultiMappingFunction,
1411
+ about_point: Point3DLike | None = None,
1412
+ about_edge: Vector3D | None = None,
1361
1413
  ) -> Self:
1362
1414
  if about_point is None:
1363
1415
  if about_edge is None:
@@ -1454,7 +1506,7 @@ class Mobject:
1454
1506
  tex_top.to_edge(UP)
1455
1507
  tex_side = Tex("I am moving to the side!")
1456
1508
  c = Circle().shift(2*DOWN)
1457
- self.add(tex_top, tex_side)
1509
+ self.add(tex_top, tex_side, c)
1458
1510
  tex_side.to_edge(LEFT)
1459
1511
  c.to_edge(RIGHT, buff=0)
1460
1512
 
@@ -1463,7 +1515,7 @@ class Mobject:
1463
1515
 
1464
1516
  def next_to(
1465
1517
  self,
1466
- mobject_or_point: Mobject | Point3D,
1518
+ mobject_or_point: Mobject | Point3DLike,
1467
1519
  direction: Vector3D = RIGHT,
1468
1520
  buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
1469
1521
  aligned_edge: Vector3D = ORIGIN,
@@ -1528,11 +1580,9 @@ class Mobject:
1528
1580
  return True
1529
1581
  if self.get_bottom()[1] > config["frame_y_radius"]:
1530
1582
  return True
1531
- if self.get_top()[1] < -config["frame_y_radius"]:
1532
- return True
1533
- return False
1583
+ return self.get_top()[1] < -config["frame_y_radius"]
1534
1584
 
1535
- def stretch_about_point(self, factor: float, dim: int, point: Point3D) -> Self:
1585
+ def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self:
1536
1586
  return self.stretch(factor, dim, about_point=point)
1537
1587
 
1538
1588
  def rescale_to_fit(
@@ -1562,15 +1612,14 @@ class Mobject:
1562
1612
  >>> from manim import *
1563
1613
  >>> sq = Square()
1564
1614
  >>> sq.height
1565
- 2.0
1615
+ np.float64(2.0)
1566
1616
  >>> sq.scale_to_fit_width(5)
1567
1617
  Square
1568
1618
  >>> sq.width
1569
- 5.0
1619
+ np.float64(5.0)
1570
1620
  >>> sq.height
1571
- 5.0
1621
+ np.float64(5.0)
1572
1622
  """
1573
-
1574
1623
  return self.rescale_to_fit(width, 0, stretch=False, **kwargs)
1575
1624
 
1576
1625
  def stretch_to_fit_width(self, width: float, **kwargs) -> Self:
@@ -1588,15 +1637,14 @@ class Mobject:
1588
1637
  >>> from manim import *
1589
1638
  >>> sq = Square()
1590
1639
  >>> sq.height
1591
- 2.0
1640
+ np.float64(2.0)
1592
1641
  >>> sq.stretch_to_fit_width(5)
1593
1642
  Square
1594
1643
  >>> sq.width
1595
- 5.0
1644
+ np.float64(5.0)
1596
1645
  >>> sq.height
1597
- 2.0
1646
+ np.float64(2.0)
1598
1647
  """
1599
-
1600
1648
  return self.rescale_to_fit(width, 0, stretch=True, **kwargs)
1601
1649
 
1602
1650
  def scale_to_fit_height(self, height: float, **kwargs) -> Self:
@@ -1614,15 +1662,14 @@ class Mobject:
1614
1662
  >>> from manim import *
1615
1663
  >>> sq = Square()
1616
1664
  >>> sq.width
1617
- 2.0
1665
+ np.float64(2.0)
1618
1666
  >>> sq.scale_to_fit_height(5)
1619
1667
  Square
1620
1668
  >>> sq.height
1621
- 5.0
1669
+ np.float64(5.0)
1622
1670
  >>> sq.width
1623
- 5.0
1671
+ np.float64(5.0)
1624
1672
  """
1625
-
1626
1673
  return self.rescale_to_fit(height, 1, stretch=False, **kwargs)
1627
1674
 
1628
1675
  def stretch_to_fit_height(self, height: float, **kwargs) -> Self:
@@ -1640,25 +1687,22 @@ class Mobject:
1640
1687
  >>> from manim import *
1641
1688
  >>> sq = Square()
1642
1689
  >>> sq.width
1643
- 2.0
1690
+ np.float64(2.0)
1644
1691
  >>> sq.stretch_to_fit_height(5)
1645
1692
  Square
1646
1693
  >>> sq.height
1647
- 5.0
1694
+ np.float64(5.0)
1648
1695
  >>> sq.width
1649
- 2.0
1696
+ np.float64(2.0)
1650
1697
  """
1651
-
1652
1698
  return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
1653
1699
 
1654
1700
  def scale_to_fit_depth(self, depth: float, **kwargs) -> Self:
1655
1701
  """Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional."""
1656
-
1657
1702
  return self.rescale_to_fit(depth, 2, stretch=False, **kwargs)
1658
1703
 
1659
1704
  def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self:
1660
1705
  """Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional."""
1661
-
1662
1706
  return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
1663
1707
 
1664
1708
  def set_coord(self, value, dim: int, direction: Vector3D = ORIGIN) -> Self:
@@ -1688,7 +1732,7 @@ class Mobject:
1688
1732
 
1689
1733
  def move_to(
1690
1734
  self,
1691
- point_or_mobject: Point3D | Mobject,
1735
+ point_or_mobject: Point3DLike | Mobject,
1692
1736
  aligned_edge: Vector3D = ORIGIN,
1693
1737
  coor_mask: Vector3D = np.array([1, 1, 1]),
1694
1738
  ) -> Self:
@@ -1730,13 +1774,16 @@ class Mobject:
1730
1774
  self.scale((length + buff) / length)
1731
1775
  return self
1732
1776
 
1733
- def put_start_and_end_on(self, start: Point3D, end: Point3D) -> Self:
1777
+ def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:
1734
1778
  curr_start, curr_end = self.get_start_and_end()
1735
1779
  curr_vect = curr_end - curr_start
1736
1780
  if np.all(curr_vect == 0):
1737
- self.points = start
1781
+ # TODO: this looks broken. It makes self.points a Point3D instead
1782
+ # of a Point3D_Array. However, modifying this breaks some tests
1783
+ # where this is currently expected.
1784
+ self.points = np.array(start)
1738
1785
  return self
1739
- target_vect = np.array(end) - np.array(start)
1786
+ target_vect = np.asarray(end) - np.asarray(start)
1740
1787
  axis = (
1741
1788
  normalize(np.cross(curr_vect, target_vect))
1742
1789
  if np.linalg.norm(np.cross(curr_vect, target_vect)) != 0
@@ -1785,7 +1832,6 @@ class Mobject:
1785
1832
  :class:`~.BackgroundRectangle`
1786
1833
 
1787
1834
  """
1788
-
1789
1835
  # TODO, this does not behave well when the mobject has points,
1790
1836
  # since it gets displayed on top
1791
1837
  from manim.mobject.geometry.shape_matchers import BackgroundRectangle
@@ -1838,7 +1884,7 @@ class Mobject:
1838
1884
 
1839
1885
  def set_colors_by_radial_gradient(
1840
1886
  self,
1841
- center: Point3D | None = None,
1887
+ center: Point3DLike | None = None,
1842
1888
  radius: float = 1,
1843
1889
  inner_color: ParsableManimColor = WHITE,
1844
1890
  outer_color: ParsableManimColor = BLACK,
@@ -1866,7 +1912,7 @@ class Mobject:
1866
1912
 
1867
1913
  def set_submobject_colors_by_radial_gradient(
1868
1914
  self,
1869
- center: Point3D | None = None,
1915
+ center: Point3DLike | None = None,
1870
1916
  radius: float = 1,
1871
1917
  inner_color: ParsableManimColor = WHITE,
1872
1918
  outer_color: ParsableManimColor = BLACK,
@@ -1937,14 +1983,15 @@ class Mobject:
1937
1983
 
1938
1984
  def reduce_across_dimension(self, reduce_func: Callable, dim: int):
1939
1985
  """Find the min or max value from a dimension across all points in this and submobjects."""
1940
- assert dim >= 0 and dim <= 2
1986
+ assert dim >= 0
1987
+ assert dim <= 2
1941
1988
  if len(self.submobjects) == 0 and len(self.points) == 0:
1942
1989
  # If we have no points and no submobjects, return 0 (e.g. center)
1943
1990
  return 0
1944
1991
 
1945
1992
  # If we do not have points (but do have submobjects)
1946
1993
  # use only the points from those.
1947
- if len(self.points) == 0:
1994
+ if len(self.points) == 0: # noqa: SIM108
1948
1995
  rv = None
1949
1996
  else:
1950
1997
  # Otherwise, be sure to include our own points
@@ -1953,10 +2000,7 @@ class Mobject:
1953
2000
  # smallest dimension they have and compare it to the return value.
1954
2001
  for mobj in self.submobjects:
1955
2002
  value = mobj.reduce_across_dimension(reduce_func, dim)
1956
- if rv is None:
1957
- rv = value
1958
- else:
1959
- rv = reduce_func([value, rv])
2003
+ rv = value if rv is None else reduce_func([value, rv])
1960
2004
  return rv
1961
2005
 
1962
2006
  def nonempty_submobjects(self) -> list[Self]:
@@ -1994,11 +2038,14 @@ class Mobject:
1994
2038
  return len(self.points)
1995
2039
 
1996
2040
  def get_extremum_along_dim(
1997
- self, points: Point3D_Array | None = None, dim: int = 0, key: int = 0
1998
- ) -> np.ndarray | float:
1999
- if points is None:
2000
- points = self.get_points_defining_boundary()
2001
- values = points[:, dim]
2041
+ self, points: Point3DLike_Array | None = None, dim: int = 0, key: int = 0
2042
+ ) -> float:
2043
+ np_points: Point3D_Array = (
2044
+ self.get_points_defining_boundary()
2045
+ if points is None
2046
+ else np.asarray(points)
2047
+ )
2048
+ values = np_points[:, dim]
2002
2049
  if key < 0:
2003
2050
  return np.min(values)
2004
2051
  elif key == 0:
@@ -2013,7 +2060,7 @@ class Mobject:
2013
2060
 
2014
2061
  ::
2015
2062
 
2016
- sample = Arc(start_angle=PI/7, angle = PI/5)
2063
+ sample = Arc(start_angle=PI / 7, angle=PI / 5)
2017
2064
 
2018
2065
  # These are all equivalent
2019
2066
  max_y_1 = sample.get_top()[1]
@@ -2113,15 +2160,15 @@ class Mobject:
2113
2160
  """Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
2114
2161
  return self.get_extremum_along_dim(dim=dim, key=direction[dim])
2115
2162
 
2116
- def get_x(self, direction: Vector3D = ORIGIN) -> ManimFloat:
2163
+ def get_x(self, direction: Vector3D = ORIGIN) -> float:
2117
2164
  """Returns x Point3D of the center of the :class:`~.Mobject` as ``float``"""
2118
2165
  return self.get_coord(0, direction)
2119
2166
 
2120
- def get_y(self, direction: Vector3D = ORIGIN) -> ManimFloat:
2167
+ def get_y(self, direction: Vector3D = ORIGIN) -> float:
2121
2168
  """Returns y Point3D of the center of the :class:`~.Mobject` as ``float``"""
2122
2169
  return self.get_coord(1, direction)
2123
2170
 
2124
- def get_z(self, direction: Vector3D = ORIGIN) -> ManimFloat:
2171
+ def get_z(self, direction: Vector3D = ORIGIN) -> float:
2125
2172
  """Returns z Point3D of the center of the :class:`~.Mobject` as ``float``"""
2126
2173
  return self.get_coord(2, direction)
2127
2174
 
@@ -2142,7 +2189,7 @@ class Mobject:
2142
2189
  def point_from_proportion(self, alpha: float) -> Point3D:
2143
2190
  raise NotImplementedError("Please override in a child class.")
2144
2191
 
2145
- def proportion_from_point(self, point: Point3D) -> float:
2192
+ def proportion_from_point(self, point: Point3DLike) -> float:
2146
2193
  raise NotImplementedError("Please override in a child class.")
2147
2194
 
2148
2195
  def get_pieces(self, n_pieces: float) -> Group:
@@ -2215,7 +2262,7 @@ class Mobject:
2215
2262
 
2216
2263
  def align_to(
2217
2264
  self,
2218
- mobject_or_point: Mobject | Point3D,
2265
+ mobject_or_point: Mobject | Point3DLike,
2219
2266
  direction: Vector3D = ORIGIN,
2220
2267
  ) -> Self:
2221
2268
  """Aligns mobject to another :class:`~.Mobject` in a certain direction.
@@ -2437,10 +2484,10 @@ class Mobject:
2437
2484
  buff_x = buff_y = buff
2438
2485
 
2439
2486
  # Initialize alignments correctly
2440
- def init_alignments(alignments, num, mapping, name, dir):
2487
+ def init_alignments(alignments, num, mapping, name, dir_):
2441
2488
  if alignments is None:
2442
2489
  # Use cell_alignment as fallback
2443
- return [cell_alignment * dir] * num
2490
+ return [cell_alignment * dir_] * num
2444
2491
  if len(alignments) != num:
2445
2492
  raise ValueError(f"{name}_alignments has a mismatching size.")
2446
2493
  alignments = list(alignments)
@@ -2542,13 +2589,13 @@ class Mobject:
2542
2589
 
2543
2590
  def sort(
2544
2591
  self,
2545
- point_to_num_func: Callable[[Point3D], ManimInt] = lambda p: p[0],
2546
- submob_func: Callable[[Mobject], ManimInt] | None = None,
2592
+ point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0],
2593
+ submob_func: Callable[[Mobject], Any] | None = None,
2547
2594
  ) -> Self:
2548
2595
  """Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``."""
2549
2596
  if submob_func is None:
2550
2597
 
2551
- def submob_func(m: Mobject):
2598
+ def submob_func(m: Mobject) -> float:
2552
2599
  return point_to_num_func(m.get_center())
2553
2600
 
2554
2601
  self.submobjects.sort(key=submob_func)
@@ -2835,7 +2882,7 @@ class Mobject:
2835
2882
 
2836
2883
  >>> result = rect.copy().become(circ, stretch=True)
2837
2884
  >>> result.height, result.width
2838
- (2.0, 4.0)
2885
+ (np.float64(2.0), np.float64(4.0))
2839
2886
  >>> ellipse_points = np.array(result.get_anchors())
2840
2887
  >>> ellipse_eq = np.sum(ellipse_points**2 * [1/4, 1, 0], axis=1)
2841
2888
  >>> np.allclose(ellipse_eq, 1)
@@ -2849,14 +2896,14 @@ class Mobject:
2849
2896
 
2850
2897
  >>> result = rect.copy().become(circ, match_height=True)
2851
2898
  >>> result.height, result.width
2852
- (2.0, 2.0)
2899
+ (np.float64(2.0), np.float64(2.0))
2853
2900
  >>> circle_points = np.array(result.get_anchors())
2854
2901
  >>> circle_eq = np.sum(circle_points**2, axis=1)
2855
2902
  >>> np.allclose(circle_eq, 1)
2856
2903
  True
2857
2904
  >>> result = rect.copy().become(circ, match_width=True)
2858
2905
  >>> result.height, result.width
2859
- (4.0, 4.0)
2906
+ (np.float64(4.0), np.float64(4.0))
2860
2907
  >>> circle_points = np.array(result.get_anchors())
2861
2908
  >>> circle_eq = np.sum(circle_points**2, axis=1)
2862
2909
  >>> np.allclose(circle_eq, 2**2)
@@ -3025,8 +3072,7 @@ class _AnimationBuilder:
3025
3072
 
3026
3073
  if (self.is_chaining and has_overridden_animation) or self.overridden_animation:
3027
3074
  raise NotImplementedError(
3028
- "Method chaining is currently not supported for "
3029
- "overridden animations",
3075
+ "Method chaining is currently not supported for overridden animations",
3030
3076
  )
3031
3077
 
3032
3078
  def update_target(*method_args, **method_kwargs):
@@ -187,7 +187,8 @@ class OpenGLTipableVMobject(OpenGLVMobject):
187
187
 
188
188
  def get_tip(self):
189
189
  """Returns the TipableVMobject instance's (first) tip,
190
- otherwise throws an exception."""
190
+ otherwise throws an exception.
191
+ """
191
192
  tips = self.get_tips()
192
193
  if len(tips) == 0:
193
194
  raise Exception("tip not found")
@@ -463,10 +464,7 @@ class OpenGLLine(OpenGLTipableVMobject):
463
464
  if buff == 0:
464
465
  return
465
466
  #
466
- if self.path_arc == 0:
467
- length = self.get_length()
468
- else:
469
- length = self.get_arc_length()
467
+ length = self.get_length() if self.path_arc == 0 else self.get_arc_length()
470
468
  #
471
469
  if length < 2 * buff:
472
470
  return
@@ -519,9 +517,7 @@ class OpenGLLine(OpenGLTipableVMobject):
519
517
  return angle_of_vector(self.get_vector())
520
518
 
521
519
  def get_projection(self, point):
522
- """
523
- Return projection of a point onto the line
524
- """
520
+ """Return projection of a point onto the line"""
525
521
  unit_vect = self.get_unit_vector()
526
522
  start = self.get_start()
527
523
  return start + np.dot(point - start, unit_vect) * unit_vect