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
@@ -4,11 +4,13 @@ from __future__ import annotations
4
4
 
5
5
  __all__ = ["VectorScene", "LinearTransformationScene"]
6
6
 
7
- from typing import Callable
7
+ from collections.abc import Callable, Iterable
8
+ from typing import TYPE_CHECKING, Any, cast
8
9
 
9
10
  import numpy as np
10
- from colour import Color
11
11
 
12
+ from manim.animation.creation import DrawBorderThenFill, Group
13
+ from manim.camera.camera import Camera
12
14
  from manim.mobject.geometry.arc import Dot
13
15
  from manim.mobject.geometry.line import Arrow, Line, Vector
14
16
  from manim.mobject.geometry.polygram import Rectangle
@@ -28,10 +30,33 @@ from ..mobject.matrix import Matrix
28
30
  from ..mobject.mobject import Mobject
29
31
  from ..mobject.types.vectorized_mobject import VGroup, VMobject
30
32
  from ..scene.scene import Scene
31
- from ..utils.color import BLUE_D, GREEN_C, GREY, RED_C, WHITE, YELLOW
33
+ from ..utils.color import (
34
+ BLACK,
35
+ BLUE_D,
36
+ GREEN_C,
37
+ GREY,
38
+ RED_C,
39
+ WHITE,
40
+ YELLOW,
41
+ ManimColor,
42
+ ParsableManimColor,
43
+ )
32
44
  from ..utils.rate_functions import rush_from, rush_into
33
45
  from ..utils.space_ops import angle_of_vector
34
46
 
47
+ if TYPE_CHECKING:
48
+ from typing_extensions import Self
49
+
50
+ from manim.typing import (
51
+ MappingFunction,
52
+ Point3D,
53
+ Point3DLike,
54
+ Vector2DLike,
55
+ Vector3D,
56
+ Vector3DLike,
57
+ )
58
+
59
+
35
60
  X_COLOR = GREEN_C
36
61
  Y_COLOR = RED_C
37
62
  Z_COLOR = BLUE_D
@@ -44,11 +69,11 @@ Z_COLOR = BLUE_D
44
69
  # Also, methods I would have thought of as getters, like coords_to_vector, are
45
70
  # actually doing a lot of animating.
46
71
  class VectorScene(Scene):
47
- def __init__(self, basis_vector_stroke_width=6, **kwargs):
72
+ def __init__(self, basis_vector_stroke_width: float = 6.0, **kwargs: Any) -> None:
48
73
  super().__init__(**kwargs)
49
74
  self.basis_vector_stroke_width = basis_vector_stroke_width
50
75
 
51
- def add_plane(self, animate: bool = False, **kwargs):
76
+ def add_plane(self, animate: bool = False, **kwargs: Any) -> NumberPlane:
52
77
  """
53
78
  Adds a NumberPlane object to the background.
54
79
 
@@ -70,7 +95,11 @@ class VectorScene(Scene):
70
95
  self.add(plane)
71
96
  return plane
72
97
 
73
- def add_axes(self, animate: bool = False, color: bool = WHITE, **kwargs):
98
+ def add_axes(
99
+ self,
100
+ animate: bool = False,
101
+ color: ParsableManimColor | Iterable[ParsableManimColor] = WHITE,
102
+ ) -> Axes:
74
103
  """
75
104
  Adds a pair of Axes to the Scene.
76
105
 
@@ -87,7 +116,9 @@ class VectorScene(Scene):
87
116
  self.add(axes)
88
117
  return axes
89
118
 
90
- def lock_in_faded_grid(self, dimness: float = 0.7, axes_dimness: float = 0.5):
119
+ def lock_in_faded_grid(
120
+ self, dimness: float = 0.7, axes_dimness: float = 0.5
121
+ ) -> None:
91
122
  """
92
123
  This method freezes the NumberPlane and Axes that were already
93
124
  in the background, and adds new, manipulatable ones to the foreground.
@@ -107,11 +138,13 @@ class VectorScene(Scene):
107
138
  axes.fade(axes_dimness)
108
139
  self.add(axes)
109
140
 
110
- self.renderer.update_frame()
141
+ # TODO
142
+ # error: Missing positional argument "scene" in call to "update_frame" of "CairoRenderer" [call-arg]
143
+ self.renderer.update_frame() # type: ignore[call-arg]
111
144
  self.renderer.camera = Camera(self.renderer.get_frame())
112
145
  self.clear()
113
146
 
114
- def get_vector(self, numerical_vector: np.ndarray | list | tuple, **kwargs):
147
+ def get_vector(self, numerical_vector: Vector3DLike, **kwargs: Any) -> Arrow:
115
148
  """
116
149
  Returns an arrow on the Plane given an input numerical vector.
117
150
 
@@ -128,19 +161,21 @@ class VectorScene(Scene):
128
161
  The Arrow representing the Vector.
129
162
  """
130
163
  return Arrow(
131
- self.plane.coords_to_point(0, 0),
132
- self.plane.coords_to_point(*numerical_vector[:2]),
164
+ # TODO
165
+ # error: "VectorScene" has no attribute "plane" [attr-defined]
166
+ self.plane.coords_to_point(0, 0), # type: ignore[attr-defined]
167
+ self.plane.coords_to_point(*numerical_vector[:2]), # type: ignore[attr-defined]
133
168
  buff=0,
134
169
  **kwargs,
135
170
  )
136
171
 
137
172
  def add_vector(
138
173
  self,
139
- vector: Arrow | list | tuple | np.ndarray,
140
- color: str = YELLOW,
174
+ vector: Arrow | Vector3DLike,
175
+ color: ParsableManimColor | Iterable[ParsableManimColor] = YELLOW,
141
176
  animate: bool = True,
142
- **kwargs,
143
- ):
177
+ **kwargs: Any,
178
+ ) -> Arrow:
144
179
  """
145
180
  Returns the Vector after adding it to the Plane.
146
181
 
@@ -170,13 +205,13 @@ class VectorScene(Scene):
170
205
  The arrow representing the vector.
171
206
  """
172
207
  if not isinstance(vector, Arrow):
173
- vector = Vector(vector, color=color, **kwargs)
208
+ vector = Vector(np.asarray(vector), color=color, **kwargs)
174
209
  if animate:
175
210
  self.play(GrowArrow(vector))
176
211
  self.add(vector)
177
212
  return vector
178
213
 
179
- def write_vector_coordinates(self, vector: Arrow, **kwargs):
214
+ def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix:
180
215
  """
181
216
  Returns a column matrix indicating the vector coordinates,
182
217
  after writing them to the screen.
@@ -194,11 +229,15 @@ class VectorScene(Scene):
194
229
  :class:`.Matrix`
195
230
  The column matrix representing the vector.
196
231
  """
197
- coords = vector.coordinate_label(**kwargs)
232
+ coords: Matrix = vector.coordinate_label(**kwargs)
198
233
  self.play(Write(coords))
199
234
  return coords
200
235
 
201
- def get_basis_vectors(self, i_hat_color: str = X_COLOR, j_hat_color: str = Y_COLOR):
236
+ def get_basis_vectors(
237
+ self,
238
+ i_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = X_COLOR,
239
+ j_hat_color: ParsableManimColor | Iterable[ParsableManimColor] = Y_COLOR,
240
+ ) -> VGroup:
202
241
  """
203
242
  Returns a VGroup of the Basis Vectors (1,0) and (0,1)
204
243
 
@@ -217,12 +256,16 @@ class VectorScene(Scene):
217
256
  """
218
257
  return VGroup(
219
258
  *(
220
- Vector(vect, color=color, stroke_width=self.basis_vector_stroke_width)
259
+ Vector(
260
+ np.asarray(vect),
261
+ color=color,
262
+ stroke_width=self.basis_vector_stroke_width,
263
+ )
221
264
  for vect, color in [([1, 0], i_hat_color), ([0, 1], j_hat_color)]
222
265
  )
223
266
  )
224
267
 
225
- def get_basis_vector_labels(self, **kwargs):
268
+ def get_basis_vector_labels(self, **kwargs: Any) -> VGroup:
226
269
  """
227
270
  Returns naming labels for the basis vectors.
228
271
 
@@ -254,13 +297,13 @@ class VectorScene(Scene):
254
297
  def get_vector_label(
255
298
  self,
256
299
  vector: Vector,
257
- label,
300
+ label: MathTex | str,
258
301
  at_tip: bool = False,
259
302
  direction: str = "left",
260
303
  rotate: bool = False,
261
- color: str | None = None,
304
+ color: ParsableManimColor | None = None,
262
305
  label_scale_factor: float = LARGE_BUFF - 0.2,
263
- ):
306
+ ) -> MathTex:
264
307
  """
265
308
  Returns naming labels for the passed vector.
266
309
 
@@ -288,11 +331,14 @@ class VectorScene(Scene):
288
331
  """
289
332
  if not isinstance(label, MathTex):
290
333
  if len(label) == 1:
291
- label = "\\vec{\\textbf{%s}}" % label
334
+ label = "\\vec{\\textbf{%s}}" % label # noqa: UP031
292
335
  label = MathTex(label)
293
336
  if color is None:
294
- color = vector.get_color()
295
- label.set_color(color)
337
+ prepared_color: ParsableManimColor = vector.get_color()
338
+ else:
339
+ prepared_color = color
340
+ label.set_color(prepared_color)
341
+ assert isinstance(label, MathTex)
296
342
  label.scale(label_scale_factor)
297
343
  label.add_background_rectangle()
298
344
 
@@ -305,16 +351,18 @@ class VectorScene(Scene):
305
351
  if not rotate:
306
352
  label.rotate(-angle, about_point=ORIGIN)
307
353
  if direction == "left":
308
- label.shift(-label.get_bottom() + 0.1 * UP)
354
+ temp_shift_1: Vector3D = np.asarray(label.get_bottom())
355
+ label.shift(-temp_shift_1 + 0.1 * UP)
309
356
  else:
310
- label.shift(-label.get_top() + 0.1 * DOWN)
357
+ temp_shift_2: Vector3D = np.asarray(label.get_top())
358
+ label.shift(-temp_shift_2 + 0.1 * DOWN)
311
359
  label.rotate(angle, about_point=ORIGIN)
312
360
  label.shift((vector.get_end() - vector.get_start()) / 2)
313
361
  return label
314
362
 
315
363
  def label_vector(
316
- self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs
317
- ):
364
+ self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs: Any
365
+ ) -> MathTex:
318
366
  """
319
367
  Shortcut method for creating, and animating the addition of
320
368
  a label for the vector.
@@ -338,38 +386,38 @@ class VectorScene(Scene):
338
386
  :class:`~.MathTex`
339
387
  The MathTex of the label.
340
388
  """
341
- label = self.get_vector_label(vector, label, **kwargs)
389
+ mathtex_label = self.get_vector_label(vector, label, **kwargs)
342
390
  if animate:
343
- self.play(Write(label, run_time=1))
344
- self.add(label)
345
- return label
391
+ self.play(Write(mathtex_label, run_time=1))
392
+ self.add(mathtex_label)
393
+ return mathtex_label
346
394
 
347
395
  def position_x_coordinate(
348
396
  self,
349
- x_coord,
350
- x_line,
351
- vector,
352
- ): # TODO Write DocStrings for this.
397
+ x_coord: MathTex,
398
+ x_line: Line,
399
+ vector: Vector3DLike,
400
+ ) -> MathTex: # TODO Write DocStrings for this.
353
401
  x_coord.next_to(x_line, -np.sign(vector[1]) * UP)
354
402
  x_coord.set_color(X_COLOR)
355
403
  return x_coord
356
404
 
357
405
  def position_y_coordinate(
358
406
  self,
359
- y_coord,
360
- y_line,
361
- vector,
362
- ): # TODO Write DocStrings for this.
407
+ y_coord: MathTex,
408
+ y_line: Line,
409
+ vector: Vector3DLike,
410
+ ) -> MathTex: # TODO Write DocStrings for this.
363
411
  y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT)
364
412
  y_coord.set_color(Y_COLOR)
365
413
  return y_coord
366
414
 
367
415
  def coords_to_vector(
368
416
  self,
369
- vector: np.ndarray | list | tuple,
370
- coords_start: np.ndarray | list | tuple = 2 * RIGHT + 2 * UP,
417
+ vector: Vector2DLike,
418
+ coords_start: Point3DLike = 2 * RIGHT + 2 * UP,
371
419
  clean_up: bool = True,
372
- ):
420
+ ) -> None:
373
421
  """
374
422
  This method writes the vector as a column matrix (henceforth called the label),
375
423
  takes the values in it one by one, and form the corresponding
@@ -400,26 +448,29 @@ class VectorScene(Scene):
400
448
  y_line = Line(x_line.get_end(), arrow.get_end())
401
449
  x_line.set_color(X_COLOR)
402
450
  y_line.set_color(Y_COLOR)
403
- x_coord, y_coord = array.get_mob_matrix().flatten()
451
+ mob_matrix = array.get_mob_matrix()
452
+ x_coord = mob_matrix[0][0]
453
+ y_coord = mob_matrix[1][0]
404
454
 
405
455
  self.play(Write(array, run_time=1))
406
456
  self.wait()
407
457
  self.play(
408
458
  ApplyFunction(
409
- lambda x: self.position_x_coordinate(x, x_line, vector),
459
+ lambda x: self.position_x_coordinate(x, x_line, vector), # type: ignore[arg-type]
410
460
  x_coord,
411
461
  ),
412
462
  )
413
463
  self.play(Create(x_line))
414
464
  animations = [
415
465
  ApplyFunction(
416
- lambda y: self.position_y_coordinate(y, y_line, vector),
466
+ lambda y: self.position_y_coordinate(y, y_line, vector), # type: ignore[arg-type]
417
467
  y_coord,
418
468
  ),
419
469
  FadeOut(array.get_brackets()),
420
470
  ]
421
471
  self.play(*animations)
422
- y_coord, _ = (anim.mobject for anim in animations)
472
+ # TODO: Can we delete the line below? I don't think it have any purpose.
473
+ # y_coord, _ = (anim.mobject for anim in animations)
423
474
  self.play(Create(y_line))
424
475
  self.play(Create(arrow))
425
476
  self.wait()
@@ -429,10 +480,10 @@ class VectorScene(Scene):
429
480
 
430
481
  def vector_to_coords(
431
482
  self,
432
- vector: np.ndarray | list | tuple,
483
+ vector: Vector3DLike,
433
484
  integer_labels: bool = True,
434
485
  clean_up: bool = True,
435
- ):
486
+ ) -> tuple[Matrix, Line, Line]:
436
487
  """
437
488
  This method displays vector as a Vector() based vector, and then shows
438
489
  the corresponding lines that make up the x and y components of the vector.
@@ -466,7 +517,7 @@ class VectorScene(Scene):
466
517
  y_line = Line(x_line.get_end(), arrow.get_end())
467
518
  x_line.set_color(X_COLOR)
468
519
  y_line.set_color(Y_COLOR)
469
- x_coord, y_coord = array.get_entries()
520
+ x_coord, y_coord = cast(VGroup, array.get_entries())
470
521
  x_coord_start = self.position_x_coordinate(x_coord.copy(), x_line, vector)
471
522
  y_coord_start = self.position_y_coordinate(y_coord.copy(), y_line, vector)
472
523
  brackets = array.get_brackets()
@@ -490,7 +541,7 @@ class VectorScene(Scene):
490
541
  self.add(*starting_mobjects)
491
542
  return array, x_line, y_line
492
543
 
493
- def show_ghost_movement(self, vector: Arrow | list | tuple | np.ndarray):
544
+ def show_ghost_movement(self, vector: Arrow | Vector2DLike | Vector3DLike) -> None:
494
545
  """
495
546
  This method plays an animation that partially shows the entire plane moving
496
547
  in the direction of a particular vector. This is useful when you wish to
@@ -504,20 +555,26 @@ class VectorScene(Scene):
504
555
  """
505
556
  if isinstance(vector, Arrow):
506
557
  vector = vector.get_end() - vector.get_start()
507
- elif len(vector) == 2:
508
- vector = np.append(np.array(vector), 0.0)
509
- x_max = int(config["frame_x_radius"] + abs(vector[0]))
510
- y_max = int(config["frame_y_radius"] + abs(vector[1]))
558
+ else:
559
+ vector = np.asarray(vector)
560
+ if len(vector) == 2:
561
+ vector = np.append(np.array(vector), 0.0)
562
+ vector_cleaned: Vector3D = vector
563
+
564
+ x_max = int(config["frame_x_radius"] + abs(vector_cleaned[0]))
565
+ y_max = int(config["frame_y_radius"] + abs(vector_cleaned[1]))
566
+ # TODO:
567
+ # I think that this should be a VGroup instead of a VMobject.
511
568
  dots = VMobject(
512
- *(
569
+ *( # type: ignore[arg-type]
513
570
  Dot(x * RIGHT + y * UP)
514
571
  for x in range(-x_max, x_max)
515
572
  for y in range(-y_max, y_max)
516
573
  )
517
574
  )
518
575
  dots.set_fill(BLACK, opacity=0)
519
- dots_halfway = dots.copy().shift(vector / 2).set_fill(WHITE, 1)
520
- dots_end = dots.copy().shift(vector)
576
+ dots_halfway = dots.copy().shift(vector_cleaned / 2).set_fill(WHITE, 1)
577
+ dots_end = dots.copy().shift(vector_cleaned)
521
578
 
522
579
  self.play(Transform(dots, dots_halfway, rate_func=rush_into))
523
580
  self.play(Transform(dots, dots_end, rate_func=rush_from))
@@ -558,11 +615,12 @@ class LinearTransformationScene(VectorScene):
558
615
  .. manim:: LinearTransformationSceneExample
559
616
 
560
617
  class LinearTransformationSceneExample(LinearTransformationScene):
561
- def __init__(self):
618
+ def __init__(self, **kwargs):
562
619
  LinearTransformationScene.__init__(
563
620
  self,
564
621
  show_coordinates=True,
565
622
  leave_ghost_vectors=True,
623
+ **kwargs
566
624
  )
567
625
 
568
626
  def construct(self):
@@ -575,17 +633,16 @@ class LinearTransformationScene(VectorScene):
575
633
  self,
576
634
  include_background_plane: bool = True,
577
635
  include_foreground_plane: bool = True,
578
- background_plane_kwargs: dict | None = None,
579
- foreground_plane_kwargs: dict | None = None,
636
+ background_plane_kwargs: dict[str, Any] | None = None,
637
+ foreground_plane_kwargs: dict[str, Any] | None = None,
580
638
  show_coordinates: bool = False,
581
639
  show_basis_vectors: bool = True,
582
640
  basis_vector_stroke_width: float = 6,
583
- i_hat_color: Color = X_COLOR,
584
- j_hat_color: Color = Y_COLOR,
641
+ i_hat_color: ParsableManimColor = X_COLOR,
642
+ j_hat_color: ParsableManimColor = Y_COLOR,
585
643
  leave_ghost_vectors: bool = False,
586
- **kwargs,
587
- ):
588
-
644
+ **kwargs: Any,
645
+ ) -> None:
589
646
  super().__init__(**kwargs)
590
647
 
591
648
  self.include_background_plane = include_background_plane
@@ -593,10 +650,10 @@ class LinearTransformationScene(VectorScene):
593
650
  self.show_coordinates = show_coordinates
594
651
  self.show_basis_vectors = show_basis_vectors
595
652
  self.basis_vector_stroke_width = basis_vector_stroke_width
596
- self.i_hat_color = i_hat_color
597
- self.j_hat_color = j_hat_color
653
+ self.i_hat_color = ManimColor(i_hat_color)
654
+ self.j_hat_color = ManimColor(j_hat_color)
598
655
  self.leave_ghost_vectors = leave_ghost_vectors
599
- self.background_plane_kwargs = {
656
+ self.background_plane_kwargs: dict[str, Any] = {
600
657
  "color": GREY,
601
658
  "axis_config": {
602
659
  "color": GREY,
@@ -607,7 +664,9 @@ class LinearTransformationScene(VectorScene):
607
664
  },
608
665
  }
609
666
 
610
- self.foreground_plane_kwargs = {
667
+ self.ghost_vectors = VGroup()
668
+
669
+ self.foreground_plane_kwargs: dict[str, Any] = {
611
670
  "x_range": np.array([-config["frame_width"], config["frame_width"], 1.0]),
612
671
  "y_range": np.array([-config["frame_width"], config["frame_width"], 1.0]),
613
672
  "faded_line_ratio": 1,
@@ -619,22 +678,25 @@ class LinearTransformationScene(VectorScene):
619
678
  )
620
679
 
621
680
  @staticmethod
622
- def update_default_configs(default_configs, passed_configs):
681
+ def update_default_configs(
682
+ default_configs: Iterable[dict[str, Any]],
683
+ passed_configs: Iterable[dict[str, Any] | None],
684
+ ) -> None:
623
685
  for default_config, passed_config in zip(default_configs, passed_configs):
624
686
  if passed_config is not None:
625
687
  update_dict_recursively(default_config, passed_config)
626
688
 
627
- def setup(self):
689
+ def setup(self) -> None:
628
690
  # The has_already_setup attr is to not break all the old Scenes
629
691
  if hasattr(self, "has_already_setup"):
630
692
  return
631
693
  self.has_already_setup = True
632
- self.background_mobjects = []
633
- self.foreground_mobjects = []
634
- self.transformable_mobjects = []
635
- self.moving_vectors = []
636
- self.transformable_labels = []
637
- self.moving_mobjects = []
694
+ self.background_mobjects: list[Mobject] = []
695
+ self.foreground_mobjects: list[Mobject] = []
696
+ self.transformable_mobjects: list[Mobject] = []
697
+ self.moving_vectors: list[Mobject] = []
698
+ self.transformable_labels: list[MathTex] = []
699
+ self.moving_mobjects: list[Mobject] = []
638
700
 
639
701
  self.background_plane = NumberPlane(**self.background_plane_kwargs)
640
702
 
@@ -654,7 +716,9 @@ class LinearTransformationScene(VectorScene):
654
716
  self.i_hat, self.j_hat = self.basis_vectors
655
717
  self.add(self.basis_vectors)
656
718
 
657
- def add_special_mobjects(self, mob_list: list, *mobs_to_add: Mobject):
719
+ def add_special_mobjects(
720
+ self, mob_list: list[Mobject], *mobs_to_add: Mobject
721
+ ) -> None:
658
722
  """
659
723
  Adds mobjects to a separate list that can be tracked,
660
724
  if these mobjects have some extra importance.
@@ -674,7 +738,7 @@ class LinearTransformationScene(VectorScene):
674
738
  mob_list.append(mobject)
675
739
  self.add(mobject)
676
740
 
677
- def add_background_mobject(self, *mobjects: Mobject):
741
+ def add_background_mobject(self, *mobjects: Mobject) -> None:
678
742
  """
679
743
  Adds the mobjects to the special list
680
744
  self.background_mobjects.
@@ -686,8 +750,9 @@ class LinearTransformationScene(VectorScene):
686
750
  """
687
751
  self.add_special_mobjects(self.background_mobjects, *mobjects)
688
752
 
689
- # TODO, this conflicts with Scene.add_fore
690
- def add_foreground_mobject(self, *mobjects: Mobject):
753
+ # TODO, this conflicts with Scene.add_foreground_mobject
754
+ # Please be aware that there is also the method Scene.add_foreground_mobjects.
755
+ def add_foreground_mobject(self, *mobjects: Mobject) -> None: # type: ignore[override]
691
756
  """
692
757
  Adds the mobjects to the special list
693
758
  self.foreground_mobjects.
@@ -699,7 +764,7 @@ class LinearTransformationScene(VectorScene):
699
764
  """
700
765
  self.add_special_mobjects(self.foreground_mobjects, *mobjects)
701
766
 
702
- def add_transformable_mobject(self, *mobjects: Mobject):
767
+ def add_transformable_mobject(self, *mobjects: Mobject) -> None:
703
768
  """
704
769
  Adds the mobjects to the special list
705
770
  self.transformable_mobjects.
@@ -713,7 +778,7 @@ class LinearTransformationScene(VectorScene):
713
778
 
714
779
  def add_moving_mobject(
715
780
  self, mobject: Mobject, target_mobject: Mobject | None = None
716
- ):
781
+ ) -> None:
717
782
  """
718
783
  Adds the mobject to the special list
719
784
  self.moving_mobject, and adds a property
@@ -732,9 +797,19 @@ class LinearTransformationScene(VectorScene):
732
797
  mobject.target = target_mobject
733
798
  self.add_special_mobjects(self.moving_mobjects, mobject)
734
799
 
800
+ def get_ghost_vectors(self) -> VGroup:
801
+ """
802
+ Returns all ghost vectors ever added to ``self``. Each element is a ``VGroup`` of
803
+ two ghost vectors.
804
+ """
805
+ return self.ghost_vectors
806
+
735
807
  def get_unit_square(
736
- self, color: str = YELLOW, opacity: float = 0.3, stroke_width: float = 3
737
- ):
808
+ self,
809
+ color: ParsableManimColor | Iterable[ParsableManimColor] = YELLOW,
810
+ opacity: float = 0.3,
811
+ stroke_width: float = 3,
812
+ ) -> Rectangle:
738
813
  """
739
814
  Returns a unit square for the current NumberPlane.
740
815
 
@@ -765,7 +840,7 @@ class LinearTransformationScene(VectorScene):
765
840
  square.move_to(self.plane.coords_to_point(0, 0), DL)
766
841
  return square
767
842
 
768
- def add_unit_square(self, animate: bool = False, **kwargs):
843
+ def add_unit_square(self, animate: bool = False, **kwargs: Any) -> Self:
769
844
  """
770
845
  Adds a unit square to the scene via
771
846
  self.get_unit_square.
@@ -796,8 +871,12 @@ class LinearTransformationScene(VectorScene):
796
871
  return self
797
872
 
798
873
  def add_vector(
799
- self, vector: Arrow | list | tuple | np.ndarray, color: str = YELLOW, **kwargs
800
- ):
874
+ self,
875
+ vector: Arrow | list | tuple | np.ndarray,
876
+ color: ParsableManimColor = YELLOW,
877
+ animate: bool = False,
878
+ **kwargs: Any,
879
+ ) -> Arrow:
801
880
  """
802
881
  Adds a vector to the scene, and puts it in the special
803
882
  list self.moving_vectors.
@@ -821,11 +900,11 @@ class LinearTransformationScene(VectorScene):
821
900
  Arrow
822
901
  The arrow representing the vector.
823
902
  """
824
- vector = super().add_vector(vector, color=color, **kwargs)
903
+ vector = super().add_vector(vector, color=color, animate=animate, **kwargs)
825
904
  self.moving_vectors.append(vector)
826
905
  return vector
827
906
 
828
- def write_vector_coordinates(self, vector: Arrow, **kwargs):
907
+ def write_vector_coordinates(self, vector: Vector, **kwargs: Any) -> Matrix:
829
908
  """
830
909
  Returns a column matrix indicating the vector coordinates,
831
910
  after writing them to the screen, and adding them to the
@@ -854,8 +933,8 @@ class LinearTransformationScene(VectorScene):
854
933
  label: MathTex | str,
855
934
  transformation_name: str | MathTex = "L",
856
935
  new_label: str | MathTex | None = None,
857
- **kwargs,
858
- ):
936
+ **kwargs: Any,
937
+ ) -> MathTex:
859
938
  """
860
939
  Method for creating, and animating the addition of
861
940
  a transformable label for the vector.
@@ -882,27 +961,27 @@ class LinearTransformationScene(VectorScene):
882
961
  :class:`~.MathTex`
883
962
  The MathTex of the label.
884
963
  """
964
+ # TODO: Clear up types in this function. This is currently a mess.
885
965
  label_mob = self.label_vector(vector, label, **kwargs)
886
966
  if new_label:
887
- label_mob.target_text = new_label
967
+ label_mob.target_text = new_label # type: ignore[attr-defined]
888
968
  else:
889
- label_mob.target_text = "{}({})".format(
890
- transformation_name,
891
- label_mob.get_tex_string(),
969
+ label_mob.target_text = ( # type: ignore[attr-defined]
970
+ f"{transformation_name}({label_mob.get_tex_string()})"
892
971
  )
893
- label_mob.vector = vector
894
- label_mob.kwargs = kwargs
972
+ label_mob.vector = vector # type: ignore[attr-defined]
973
+ label_mob.kwargs = kwargs # type: ignore[attr-defined]
895
974
  if "animate" in label_mob.kwargs:
896
975
  label_mob.kwargs.pop("animate")
897
976
  self.transformable_labels.append(label_mob)
898
- return label_mob
977
+ return cast(MathTex, label_mob)
899
978
 
900
979
  def add_title(
901
980
  self,
902
981
  title: str | MathTex | Tex,
903
982
  scale_factor: float = 1.5,
904
983
  animate: bool = False,
905
- ):
984
+ ) -> Self:
906
985
  """
907
986
  Adds a title, after scaling it, adding a background rectangle,
908
987
  moving it to the top and adding it to foreground_mobjects adding
@@ -934,7 +1013,9 @@ class LinearTransformationScene(VectorScene):
934
1013
  self.title = title
935
1014
  return self
936
1015
 
937
- def get_matrix_transformation(self, matrix: np.ndarray | list | tuple):
1016
+ def get_matrix_transformation(
1017
+ self, matrix: np.ndarray | list | tuple
1018
+ ) -> Callable[[Point3D], Point3D]:
938
1019
  """
939
1020
  Returns a function corresponding to the linear
940
1021
  transformation represented by the matrix passed.
@@ -948,7 +1029,7 @@ class LinearTransformationScene(VectorScene):
948
1029
 
949
1030
  def get_transposed_matrix_transformation(
950
1031
  self, transposed_matrix: np.ndarray | list | tuple
951
- ):
1032
+ ) -> Callable[[Point3D], Point3D]:
952
1033
  """
953
1034
  Returns a function corresponding to the linear
954
1035
  transformation represented by the transposed
@@ -968,7 +1049,7 @@ class LinearTransformationScene(VectorScene):
968
1049
  raise ValueError("Matrix has bad dimensions")
969
1050
  return lambda point: np.dot(point, transposed_matrix)
970
1051
 
971
- def get_piece_movement(self, pieces: list | tuple | np.ndarray):
1052
+ def get_piece_movement(self, pieces: Iterable[Mobject]) -> Transform:
972
1053
  """
973
1054
  This method returns an animation that moves an arbitrary
974
1055
  mobject in "pieces" to its corresponding .target value.
@@ -985,13 +1066,18 @@ class LinearTransformationScene(VectorScene):
985
1066
  Animation
986
1067
  The animation of the movement.
987
1068
  """
988
- start = VGroup(*pieces)
989
- target = VGroup(*(mob.target for mob in pieces))
990
- if self.leave_ghost_vectors:
991
- self.add(start.copy().fade(0.7))
1069
+ v_pieces = [piece for piece in pieces if isinstance(piece, VMobject)]
1070
+ start = VGroup(*v_pieces)
1071
+ target = VGroup(*(mob.target for mob in v_pieces))
1072
+
1073
+ # don't add empty VGroups
1074
+ if self.leave_ghost_vectors and start.submobjects:
1075
+ # start.copy() gives a VGroup of Vectors
1076
+ self.ghost_vectors.add(start.copy().fade(0.7))
1077
+ self.add(self.ghost_vectors[-1])
992
1078
  return Transform(start, target, lag_ratio=0)
993
1079
 
994
- def get_moving_mobject_movement(self, func: Callable[[np.ndarray], np.ndarray]):
1080
+ def get_moving_mobject_movement(self, func: MappingFunction) -> Transform:
995
1081
  """
996
1082
  This method returns an animation that moves a mobject
997
1083
  in "self.moving_mobjects" to its corresponding .target value.
@@ -1012,11 +1098,12 @@ class LinearTransformationScene(VectorScene):
1012
1098
  for m in self.moving_mobjects:
1013
1099
  if m.target is None:
1014
1100
  m.target = m.copy()
1015
- target_point = func(m.get_center())
1101
+ temp: Point3D = m.get_center()
1102
+ target_point = func(temp)
1016
1103
  m.target.move_to(target_point)
1017
1104
  return self.get_piece_movement(self.moving_mobjects)
1018
1105
 
1019
- def get_vector_movement(self, func: Callable[[np.ndarray], np.ndarray]):
1106
+ def get_vector_movement(self, func: MappingFunction) -> Transform:
1020
1107
  """
1021
1108
  This method returns an animation that moves a mobject
1022
1109
  in "self.moving_vectors" to its corresponding .target value.
@@ -1036,12 +1123,12 @@ class LinearTransformationScene(VectorScene):
1036
1123
  """
1037
1124
  for v in self.moving_vectors:
1038
1125
  v.target = Vector(func(v.get_end()), color=v.get_color())
1039
- norm = np.linalg.norm(v.target.get_end())
1126
+ norm = float(np.linalg.norm(v.target.get_end()))
1040
1127
  if norm < 0.1:
1041
1128
  v.target.get_tip().scale(norm)
1042
1129
  return self.get_piece_movement(self.moving_vectors)
1043
1130
 
1044
- def get_transformable_label_movement(self):
1131
+ def get_transformable_label_movement(self) -> Transform:
1045
1132
  """
1046
1133
  This method returns an animation that moves all labels
1047
1134
  in "self.transformable_labels" to its corresponding .target .
@@ -1052,12 +1139,17 @@ class LinearTransformationScene(VectorScene):
1052
1139
  The animation of the movement.
1053
1140
  """
1054
1141
  for label in self.transformable_labels:
1142
+ # TODO: This location and lines 933 and 335 are the only locations in
1143
+ # the code where the target_text property is referenced.
1144
+ target_text: MathTex | str = label.target_text # type: ignore[assignment]
1055
1145
  label.target = self.get_vector_label(
1056
- label.vector.target, label.target_text, **label.kwargs
1146
+ label.vector.target, # type: ignore[attr-defined]
1147
+ target_text,
1148
+ **label.kwargs, # type: ignore[arg-type]
1057
1149
  )
1058
1150
  return self.get_piece_movement(self.transformable_labels)
1059
1151
 
1060
- def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs):
1152
+ def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None:
1061
1153
  """
1062
1154
  Applies the transformation represented by the
1063
1155
  given matrix to the number plane, and each vector/similar
@@ -1072,7 +1164,7 @@ class LinearTransformationScene(VectorScene):
1072
1164
  """
1073
1165
  self.apply_transposed_matrix(np.array(matrix).T, **kwargs)
1074
1166
 
1075
- def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs):
1167
+ def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None:
1076
1168
  """
1077
1169
  This method applies the linear transformation
1078
1170
  represented by the inverse of the passed matrix
@@ -1088,8 +1180,8 @@ class LinearTransformationScene(VectorScene):
1088
1180
  self.apply_matrix(np.linalg.inv(matrix), **kwargs)
1089
1181
 
1090
1182
  def apply_transposed_matrix(
1091
- self, transposed_matrix: np.ndarray | list | tuple, **kwargs
1092
- ):
1183
+ self, transposed_matrix: np.ndarray | list | tuple, **kwargs: Any
1184
+ ) -> None:
1093
1185
  """
1094
1186
  Applies the transformation represented by the
1095
1187
  given transposed matrix to the number plane,
@@ -1110,7 +1202,9 @@ class LinearTransformationScene(VectorScene):
1110
1202
  kwargs["path_arc"] = net_rotation
1111
1203
  self.apply_function(func, **kwargs)
1112
1204
 
1113
- def apply_inverse_transpose(self, t_matrix: np.ndarray | list | tuple, **kwargs):
1205
+ def apply_inverse_transpose(
1206
+ self, t_matrix: np.ndarray | list | tuple, **kwargs: Any
1207
+ ) -> None:
1114
1208
  """
1115
1209
  Applies the inverse of the transformation represented
1116
1210
  by the given transposed matrix to the number plane and each
@@ -1127,8 +1221,8 @@ class LinearTransformationScene(VectorScene):
1127
1221
  self.apply_transposed_matrix(t_inv, **kwargs)
1128
1222
 
1129
1223
  def apply_nonlinear_transformation(
1130
- self, function: Callable[[np.ndarray], np.ndarray], **kwargs
1131
- ):
1224
+ self, function: Callable[[np.ndarray], np.ndarray], **kwargs: Any
1225
+ ) -> None:
1132
1226
  """
1133
1227
  Applies the non-linear transformation represented
1134
1228
  by the given function to the number plane and each
@@ -1146,10 +1240,10 @@ class LinearTransformationScene(VectorScene):
1146
1240
 
1147
1241
  def apply_function(
1148
1242
  self,
1149
- function: Callable[[np.ndarray], np.ndarray],
1150
- added_anims: list = [],
1151
- **kwargs,
1152
- ):
1243
+ function: MappingFunction,
1244
+ added_anims: list[Animation] = [],
1245
+ **kwargs: Any,
1246
+ ) -> None:
1153
1247
  """
1154
1248
  Applies the given function to each of the mobjects in
1155
1249
  self.transformable_mobjects, and plays the animation showing
@@ -1172,7 +1266,7 @@ class LinearTransformationScene(VectorScene):
1172
1266
  kwargs["run_time"] = 3
1173
1267
  anims = (
1174
1268
  [
1175
- ApplyPointwiseFunction(function, t_mob)
1269
+ ApplyPointwiseFunction(function, t_mob) # type: ignore[arg-type]
1176
1270
  for t_mob in self.transformable_mobjects
1177
1271
  ]
1178
1272
  + [