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
@@ -1,6 +1,5 @@
1
1
  """Mobjects that represent coordinate systems."""
2
2
 
3
-
4
3
  from __future__ import annotations
5
4
 
6
5
  __all__ = [
@@ -14,10 +13,11 @@ __all__ = [
14
13
 
15
14
  import fractions as fr
16
15
  import numbers
17
- from typing import TYPE_CHECKING, Any, Callable, Iterable, Sequence
16
+ from collections.abc import Callable, Iterable, Sequence
17
+ from typing import TYPE_CHECKING, Any, TypeVar, overload
18
18
 
19
19
  import numpy as np
20
- from colour import Color
20
+ from typing_extensions import Self
21
21
 
22
22
  from manim import config
23
23
  from manim.constants import *
@@ -27,6 +27,7 @@ from manim.mobject.geometry.polygram import Polygon, Rectangle, RegularPolygon
27
27
  from manim.mobject.graphing.functions import ImplicitFunction, ParametricFunction
28
28
  from manim.mobject.graphing.number_line import NumberLine
29
29
  from manim.mobject.graphing.scale import LinearBase
30
+ from manim.mobject.mobject import Mobject
30
31
  from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
31
32
  from manim.mobject.opengl.opengl_surface import OpenGLSurface
32
33
  from manim.mobject.text.tex_mobject import MathTex
@@ -44,7 +45,10 @@ from manim.utils.color import (
44
45
  GREEN,
45
46
  WHITE,
46
47
  YELLOW,
48
+ ManimColor,
49
+ ParsableManimColor,
47
50
  color_gradient,
51
+ interpolate_color,
48
52
  invert_color,
49
53
  )
50
54
  from manim.utils.config_ops import merge_dicts_recursively, update_dict_recursively
@@ -53,6 +57,17 @@ from manim.utils.space_ops import angle_of_vector
53
57
 
54
58
  if TYPE_CHECKING:
55
59
  from manim.mobject.mobject import Mobject
60
+ from manim.typing import (
61
+ ManimFloat,
62
+ Point2D,
63
+ Point2DLike,
64
+ Point3D,
65
+ Point3DLike,
66
+ Vector3D,
67
+ Vector3DLike,
68
+ )
69
+
70
+ LineType = TypeVar("LineType", bound=Line)
56
71
 
57
72
 
58
73
  class CoordinateSystem:
@@ -91,10 +106,10 @@ class CoordinateSystem:
91
106
  )
92
107
 
93
108
  # Extra lines and labels for point (1,1)
94
- graphs += grid.get_horizontal_line(grid.c2p(1, 1, 0), color=BLUE)
95
- graphs += grid.get_vertical_line(grid.c2p(1, 1, 0), color=BLUE)
96
- graphs += Dot(point=grid.c2p(1, 1, 0), color=YELLOW)
97
- graphs += Tex("(1,1)").scale(0.75).next_to(grid.c2p(1, 1, 0))
109
+ graphs += grid.get_horizontal_line(grid @ (1, 1, 0), color=BLUE)
110
+ graphs += grid.get_vertical_line(grid @ (1, 1, 0), color=BLUE)
111
+ graphs += Dot(point=grid @ (1, 1, 0), color=YELLOW)
112
+ graphs += Tex("(1,1)").scale(0.75).next_to(grid @ (1, 1, 0))
98
113
  title = Title(
99
114
  # spaces between braces to prevent SyntaxError
100
115
  r"Graphs of $y=x^{ {1}\over{n} }$ and $y=x^n (n=1,2,3,...,20)$",
@@ -107,11 +122,11 @@ class CoordinateSystem:
107
122
 
108
123
  def __init__(
109
124
  self,
110
- x_range=None,
111
- y_range=None,
112
- x_length=None,
113
- y_length=None,
114
- dimension=2,
125
+ x_range: Sequence[float] | None = None,
126
+ y_range: Sequence[float] | None = None,
127
+ x_length: float | None = None,
128
+ y_length: float | None = None,
129
+ dimension: int = 2,
115
130
  ):
116
131
  self.dimension = dimension
117
132
 
@@ -139,14 +154,17 @@ class CoordinateSystem:
139
154
  self.x_length = x_length
140
155
  self.y_length = y_length
141
156
  self.num_sampled_graph_points_per_tick = 10
157
+ self.x_axis: NumberLine
142
158
 
143
- def coords_to_point(self, *coords):
159
+ def coords_to_point(self, *coords: ManimFloat) -> Point3D:
160
+ # TODO: I think the method should be able to return more than just a single point.
161
+ # E.g. see the implementation of it on line 2065.
144
162
  raise NotImplementedError()
145
163
 
146
- def point_to_coords(self, point):
164
+ def point_to_coords(self, point: Point3DLike) -> list[ManimFloat]:
147
165
  raise NotImplementedError()
148
166
 
149
- def polar_to_point(self, radius: float, azimuth: float) -> np.ndarray:
167
+ def polar_to_point(self, radius: float, azimuth: float) -> Point2D:
150
168
  r"""Gets a point from polar coordinates.
151
169
 
152
170
  Parameters
@@ -177,7 +195,7 @@ class CoordinateSystem:
177
195
  """
178
196
  return self.coords_to_point(radius * np.cos(azimuth), radius * np.sin(azimuth))
179
197
 
180
- def point_to_polar(self, point: np.ndarray) -> tuple[float, float]:
198
+ def point_to_polar(self, point: Point2DLike) -> Point2D:
181
199
  r"""Gets polar coordinates from a point.
182
200
 
183
201
  Parameters
@@ -187,17 +205,19 @@ class CoordinateSystem:
187
205
 
188
206
  Returns
189
207
  -------
190
- Tuple[:class:`float`, :class:`float`]
208
+ Point2D
191
209
  The coordinate radius (:math:`r`) and the coordinate azimuth (:math:`\theta`).
192
210
  """
193
211
  x, y = self.point_to_coords(point)
194
212
  return np.sqrt(x**2 + y**2), np.arctan2(y, x)
195
213
 
196
- def c2p(self, *coords):
214
+ def c2p(
215
+ self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray
216
+ ) -> np.ndarray:
197
217
  """Abbreviation for :meth:`coords_to_point`"""
198
218
  return self.coords_to_point(*coords)
199
219
 
200
- def p2c(self, point):
220
+ def p2c(self, point: Point3DLike) -> list[ManimFloat]:
201
221
  """Abbreviation for :meth:`point_to_coords`"""
202
222
  return self.point_to_coords(point)
203
223
 
@@ -205,17 +225,18 @@ class CoordinateSystem:
205
225
  """Abbreviation for :meth:`polar_to_point`"""
206
226
  return self.polar_to_point(radius, azimuth)
207
227
 
208
- def pt2pr(self, point: np.ndarray) -> tuple[float, float]:
228
+ def pt2pr(self, point: np.ndarray) -> Point2D:
209
229
  """Abbreviation for :meth:`point_to_polar`"""
210
230
  return self.point_to_polar(point)
211
231
 
212
- def get_axes(self):
232
+ def get_axes(self) -> VGroup:
213
233
  raise NotImplementedError()
214
234
 
215
- def get_axis(self, index):
216
- return self.get_axes()[index]
235
+ def get_axis(self, index: int) -> NumberLine:
236
+ val: NumberLine = self.get_axes()[index]
237
+ return val
217
238
 
218
- def get_origin(self) -> np.ndarray:
239
+ def get_origin(self) -> Point3D:
219
240
  """Gets the origin of :class:`~.Axes`.
220
241
 
221
242
  Returns
@@ -225,28 +246,28 @@ class CoordinateSystem:
225
246
  """
226
247
  return self.coords_to_point(0, 0)
227
248
 
228
- def get_x_axis(self):
249
+ def get_x_axis(self) -> NumberLine:
229
250
  return self.get_axis(0)
230
251
 
231
- def get_y_axis(self):
252
+ def get_y_axis(self) -> NumberLine:
232
253
  return self.get_axis(1)
233
254
 
234
- def get_z_axis(self):
255
+ def get_z_axis(self) -> NumberLine:
235
256
  return self.get_axis(2)
236
257
 
237
- def get_x_unit_size(self):
258
+ def get_x_unit_size(self) -> float:
238
259
  return self.get_x_axis().get_unit_size()
239
260
 
240
- def get_y_unit_size(self):
261
+ def get_y_unit_size(self) -> float:
241
262
  return self.get_y_axis().get_unit_size()
242
263
 
243
264
  def get_x_axis_label(
244
265
  self,
245
- label: float | str | Mobject,
246
- edge: Sequence[float] = UR,
247
- direction: Sequence[float] = UR,
266
+ label: float | str | VMobject,
267
+ edge: Vector3D = UR,
268
+ direction: Vector3D = UR,
248
269
  buff: float = SMALL_BUFF,
249
- **kwargs,
270
+ **kwargs: Any,
250
271
  ) -> Mobject:
251
272
  """Generate an x-axis label.
252
273
 
@@ -285,12 +306,12 @@ class CoordinateSystem:
285
306
 
286
307
  def get_y_axis_label(
287
308
  self,
288
- label: float | str | Mobject,
289
- edge: Sequence[float] = UR,
290
- direction: Sequence[float] = UP * 0.5 + RIGHT,
309
+ label: float | str | VMobject,
310
+ edge: Vector3D = UR,
311
+ direction: Vector3D = UP * 0.5 + RIGHT,
291
312
  buff: float = SMALL_BUFF,
292
- **kwargs,
293
- ):
313
+ **kwargs: Any,
314
+ ) -> Mobject:
294
315
  """Generate a y-axis label.
295
316
 
296
317
  Parameters
@@ -298,7 +319,7 @@ class CoordinateSystem:
298
319
  label
299
320
  The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
300
321
  edge
301
- The edge of the x-axis to which the label will be added, by default ``UR``.
322
+ The edge of the y-axis to which the label will be added, by default ``UR``.
302
323
  direction
303
324
  Allows for further positioning of the label from an edge, by default ``UR``
304
325
  buff
@@ -325,17 +346,16 @@ class CoordinateSystem:
325
346
  )
326
347
  self.add(ax, y_label)
327
348
  """
328
-
329
349
  return self._get_axis_label(
330
350
  label, self.get_y_axis(), edge, direction, buff=buff, **kwargs
331
351
  )
332
352
 
333
353
  def _get_axis_label(
334
354
  self,
335
- label: float | str | Mobject,
355
+ label: float | str | VMobject,
336
356
  axis: Mobject,
337
- edge: Sequence[float],
338
- direction: Sequence[float],
357
+ edge: Vector3DLike,
358
+ direction: Vector3DLike,
339
359
  buff: float = SMALL_BUFF,
340
360
  ) -> Mobject:
341
361
  """Gets the label for an axis.
@@ -358,64 +378,21 @@ class CoordinateSystem:
358
378
  :class:`~.Mobject`
359
379
  The positioned label along the given axis.
360
380
  """
361
-
362
- label = self.x_axis._create_label_tex(label)
363
- label.next_to(axis.get_edge_center(edge), direction=direction, buff=buff)
364
- label.shift_onto_screen(buff=MED_SMALL_BUFF)
365
- return label
366
-
367
- def get_axis_labels(
368
- self,
369
- x_label: float | str | Mobject = "x",
370
- y_label: float | str | Mobject = "y",
371
- ) -> VGroup:
372
- """Defines labels for the x_axis and y_axis of the graph.
373
-
374
- For increased control over the position of the labels,
375
- use :meth:`get_x_axis_label` and :meth:`get_y_axis_label`.
376
-
377
- Parameters
378
- ----------
379
- x_label
380
- The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
381
- y_label
382
- The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
383
-
384
- Returns
385
- -------
386
- :class:`~.VGroup`
387
- A :class:`~.Vgroup` of the labels for the x_axis and y_axis.
388
-
389
-
390
- .. seealso::
391
- :class:`get_x_axis_label`
392
- :class:`get_y_axis_label`
393
-
394
- Examples
395
- --------
396
- .. manim:: GetAxisLabelsExample
397
- :save_last_frame:
398
-
399
- class GetAxisLabelsExample(Scene):
400
- def construct(self):
401
- ax = Axes()
402
- labels = ax.get_axis_labels(
403
- Tex("x-axis").scale(0.7), Text("y-axis").scale(0.45)
404
- )
405
- self.add(ax, labels)
406
- """
407
-
408
- self.axis_labels = VGroup(
409
- self.get_x_axis_label(x_label),
410
- self.get_y_axis_label(y_label),
381
+ label_mobject: Mobject = self.x_axis._create_label_tex(label)
382
+ label_mobject.next_to(
383
+ axis.get_edge_center(edge), direction=direction, buff=buff
411
384
  )
412
- return self.axis_labels
385
+ label_mobject.shift_onto_screen(buff=MED_SMALL_BUFF)
386
+ return label_mobject
387
+
388
+ def get_axis_labels(self) -> VGroup:
389
+ raise NotImplementedError()
413
390
 
414
391
  def add_coordinates(
415
392
  self,
416
- *axes_numbers: (Iterable[float] | None | dict[float, str | float | Mobject]),
417
- **kwargs,
418
- ):
393
+ *axes_numbers: Iterable[float] | None | dict[float, str | float | Mobject],
394
+ **kwargs: Any,
395
+ ) -> Self:
419
396
  """Adds labels to the axes. Use ``Axes.coordinate_labels`` to
420
397
  access the coordinates after creation.
421
398
 
@@ -431,7 +408,9 @@ class CoordinateSystem:
431
408
  ax = ThreeDAxes()
432
409
  x_labels = range(-4, 5)
433
410
  z_labels = range(-4, 4, 2)
434
- ax.add_coordinates(x_labels, None, z_labels) # default y labels, custom x & z labels
411
+ ax.add_coordinates(
412
+ x_labels, None, z_labels
413
+ ) # default y labels, custom x & z labels
435
414
  ax.add_coordinates(x_labels) # only x labels
436
415
 
437
416
  You can also specifically control the position and value of the labels using a dict.
@@ -442,11 +421,18 @@ class CoordinateSystem:
442
421
  x_pos = [x for x in range(1, 8)]
443
422
 
444
423
  # strings are automatically converted into a Tex mobject.
445
- x_vals = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
424
+ x_vals = [
425
+ "Monday",
426
+ "Tuesday",
427
+ "Wednesday",
428
+ "Thursday",
429
+ "Friday",
430
+ "Saturday",
431
+ "Sunday",
432
+ ]
446
433
  x_dict = dict(zip(x_pos, x_vals))
447
434
  ax.add_coordinates(x_dict)
448
435
  """
449
-
450
436
  self.coordinate_labels = VGroup()
451
437
  # if nothing is passed to axes_numbers, produce axes with default labelling
452
438
  if not axes_numbers:
@@ -469,15 +455,37 @@ class CoordinateSystem:
469
455
 
470
456
  return self
471
457
 
458
+ # overload necessary until https://github.com/python/mypy/issues/3737 is supported
459
+ @overload
472
460
  def get_line_from_axis_to_point(
473
461
  self,
474
462
  index: int,
475
- point: Sequence[float],
476
- line_func: Line = DashedLine,
477
- line_config: dict | None = None,
478
- color: Color | None = None,
479
- stroke_width: float = 2,
480
- ) -> Line:
463
+ point: Point3DLike,
464
+ line_config: dict | None = ...,
465
+ color: ParsableManimColor | None = ...,
466
+ stroke_width: float = ...,
467
+ ) -> DashedLine: ...
468
+
469
+ @overload
470
+ def get_line_from_axis_to_point(
471
+ self,
472
+ index: int,
473
+ point: Point3DLike,
474
+ line_func: type[LineType],
475
+ line_config: dict | None = ...,
476
+ color: ParsableManimColor | None = ...,
477
+ stroke_width: float = ...,
478
+ ) -> LineType: ...
479
+
480
+ def get_line_from_axis_to_point( # type: ignore[no-untyped-def]
481
+ self,
482
+ index,
483
+ point,
484
+ line_func=DashedLine,
485
+ line_config=None,
486
+ color=None,
487
+ stroke_width=2,
488
+ ):
481
489
  """Returns a straight line from a given axis to a point in the scene.
482
490
 
483
491
  Parameters
@@ -505,20 +513,19 @@ class CoordinateSystem:
505
513
  :meth:`~.CoordinateSystem.get_vertical_line`
506
514
  :meth:`~.CoordinateSystem.get_horizontal_line`
507
515
  """
508
-
509
516
  line_config = line_config if line_config is not None else {}
510
517
 
511
518
  if color is None:
512
519
  color = VMobject().color
513
520
 
514
- line_config["color"] = color
521
+ line_config["color"] = ManimColor.parse(color)
515
522
  line_config["stroke_width"] = stroke_width
516
523
 
517
524
  axis = self.get_axis(index)
518
525
  line = line_func(axis.get_projection(point), point, **line_config)
519
526
  return line
520
527
 
521
- def get_vertical_line(self, point: Sequence[float], **kwargs) -> Line:
528
+ def get_vertical_line(self, point: Point3DLike, **kwargs: Any) -> Line:
522
529
  """A vertical line from the x-axis to a given point in the scene.
523
530
 
524
531
  Parameters
@@ -552,7 +559,7 @@ class CoordinateSystem:
552
559
  """
553
560
  return self.get_line_from_axis_to_point(0, point, **kwargs)
554
561
 
555
- def get_horizontal_line(self, point: Sequence[float], **kwargs) -> Line:
562
+ def get_horizontal_line(self, point: Point3DLike, **kwargs: Any) -> Line:
556
563
  """A horizontal line from the y-axis to a given point in the scene.
557
564
 
558
565
  Parameters
@@ -575,17 +582,16 @@ class CoordinateSystem:
575
582
  class GetHorizontalLineExample(Scene):
576
583
  def construct(self):
577
584
  ax = Axes().add_coordinates()
578
- point = ax.c2p(-4, 1.5)
585
+ point = ax @ (-4, 1.5)
579
586
 
580
587
  dot = Dot(point)
581
588
  line = ax.get_horizontal_line(point, line_func=Line)
582
589
 
583
590
  self.add(ax, line, dot)
584
591
  """
585
-
586
592
  return self.get_line_from_axis_to_point(1, point, **kwargs)
587
593
 
588
- def get_lines_to_point(self, point: Sequence[float], **kwargs) -> VGroup:
594
+ def get_lines_to_point(self, point: Point3DLike, **kwargs: Any) -> VGroup:
589
595
  """Generate both horizontal and vertical lines from the axis to a point.
590
596
 
591
597
  Parameters
@@ -619,7 +625,6 @@ class CoordinateSystem:
619
625
  lines_2 = ax.get_lines_to_point(circ.get_corner(DL), color=BLUE_B)
620
626
  self.add(ax, lines_1, lines_2, circ)
621
627
  """
622
-
623
628
  return VGroup(
624
629
  self.get_horizontal_line(point, **kwargs),
625
630
  self.get_vertical_line(point, **kwargs),
@@ -632,8 +637,12 @@ class CoordinateSystem:
632
637
  function: Callable[[float], float],
633
638
  x_range: Sequence[float] | None = None,
634
639
  use_vectorized: bool = False,
635
- **kwargs,
636
- ):
640
+ colorscale: Iterable[ParsableManimColor]
641
+ | Iterable[ParsableManimColor, float]
642
+ | None = None,
643
+ colorscale_axis: int = 1,
644
+ **kwargs: Any,
645
+ ) -> ParametricFunction:
637
646
  """Generates a curve based on a function.
638
647
 
639
648
  Parameters
@@ -645,6 +654,12 @@ class CoordinateSystem:
645
654
  use_vectorized
646
655
  Whether to pass in the generated t value array to the function. Only use this if your function supports it.
647
656
  Output should be a numpy array of shape ``[y_0, y_1, ...]``
657
+ colorscale
658
+ Colors of the function. Optional parameter used when coloring a function by values. Passing a list of colors
659
+ and a colorscale_axis will color the function by y-value. Passing a list of tuples in the form ``(color, pivot)``
660
+ allows user-defined pivots where the color transitions.
661
+ colorscale_axis
662
+ Defines the axis on which the colorscale is applied (0 = x, 1 = y), default is y-axis (1).
648
663
  kwargs
649
664
  Additional parameters to be passed to :class:`~.ParametricFunction`.
650
665
 
@@ -704,7 +719,6 @@ class CoordinateSystem:
704
719
 
705
720
  self.add(axes, curves)
706
721
  """
707
-
708
722
  t_range = np.array(self.x_range, dtype=float)
709
723
  if x_range is not None:
710
724
  t_range[: len(x_range)] = x_range
@@ -723,15 +737,65 @@ class CoordinateSystem:
723
737
  use_vectorized=use_vectorized,
724
738
  **kwargs,
725
739
  )
740
+
726
741
  graph.underlying_function = function
742
+
743
+ if colorscale:
744
+ if type(colorscale[0]) in (list, tuple):
745
+ new_colors, pivots = [
746
+ [i for i, j in colorscale],
747
+ [j for i, j in colorscale],
748
+ ]
749
+ else:
750
+ new_colors = colorscale
751
+
752
+ ranges = [self.x_range, self.y_range]
753
+ pivot_min = ranges[colorscale_axis][0]
754
+ pivot_max = ranges[colorscale_axis][1]
755
+ pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1)
756
+ pivots = np.arange(
757
+ start=pivot_min,
758
+ stop=pivot_max + pivot_frequency,
759
+ step=pivot_frequency,
760
+ )
761
+
762
+ resolution = 0.01 if len(x_range) == 2 else x_range[2]
763
+ sample_points = np.arange(x_range[0], x_range[1] + resolution, resolution)
764
+ color_list = []
765
+ for samp_x in sample_points:
766
+ axis_value = (samp_x, function(samp_x))[colorscale_axis]
767
+ if axis_value <= pivots[0]:
768
+ color_list.append(new_colors[0])
769
+ elif axis_value >= pivots[-1]:
770
+ color_list.append(new_colors[-1])
771
+ else:
772
+ for i, pivot in enumerate(pivots):
773
+ if pivot > axis_value:
774
+ color_index = (axis_value - pivots[i - 1]) / (
775
+ pivots[i] - pivots[i - 1]
776
+ )
777
+ color_index = min(color_index, 1)
778
+ mob_color = interpolate_color(
779
+ new_colors[i - 1],
780
+ new_colors[i],
781
+ color_index,
782
+ )
783
+ color_list.append(mob_color)
784
+ break
785
+ if config.renderer == RendererType.OPENGL:
786
+ graph.set_color(color_list)
787
+ else:
788
+ graph.set_stroke(color_list)
789
+ graph.set_sheen_direction(RIGHT)
790
+
727
791
  return graph
728
792
 
729
793
  def plot_implicit_curve(
730
794
  self,
731
- func: Callable,
795
+ func: Callable[[float, float], float],
732
796
  min_depth: int = 5,
733
797
  max_quads: int = 1500,
734
- **kwargs,
798
+ **kwargs: Any,
735
799
  ) -> ImplicitFunction:
736
800
  """Creates the curves of an implicit function.
737
801
 
@@ -759,8 +823,10 @@ class CoordinateSystem:
759
823
  )
760
824
  self.add(ax, a)
761
825
  """
826
+ x_scale = self.get_x_axis().scaling
827
+ y_scale = self.get_y_axis().scaling
762
828
  graph = ImplicitFunction(
763
- func=func,
829
+ func=(lambda x, y: func(x_scale.function(x), y_scale.function(y))),
764
830
  x_range=self.x_range[:2],
765
831
  y_range=self.y_range[:2],
766
832
  min_depth=min_depth,
@@ -778,7 +844,7 @@ class CoordinateSystem:
778
844
  self,
779
845
  function: Callable[[float], np.ndarray],
780
846
  use_vectorized: bool = False,
781
- **kwargs,
847
+ **kwargs: Any,
782
848
  ) -> ParametricFunction:
783
849
  """A parametric curve.
784
850
 
@@ -825,8 +891,8 @@ class CoordinateSystem:
825
891
  def plot_polar_graph(
826
892
  self,
827
893
  r_func: Callable[[float], float],
828
- theta_range: Sequence[float] = [0, 2 * PI],
829
- **kwargs,
894
+ theta_range: Sequence[float] | None = None,
895
+ **kwargs: Any,
830
896
  ) -> ParametricFunction:
831
897
  """A polar graph.
832
898
 
@@ -852,6 +918,7 @@ class CoordinateSystem:
852
918
  graph = plane.plot_polar_graph(r, [0, 2 * PI], color=ORANGE)
853
919
  self.add(plane, graph)
854
920
  """
921
+ theta_range = theta_range if theta_range is not None else [0, 2 * PI]
855
922
  graph = ParametricFunction(
856
923
  function=lambda th: self.pr2pt(r_func(th), th),
857
924
  t_range=theta_range,
@@ -865,10 +932,14 @@ class CoordinateSystem:
865
932
  function: Callable[[float], float],
866
933
  u_range: Sequence[float] | None = None,
867
934
  v_range: Sequence[float] | None = None,
868
- colorscale: Sequence[[color], float] | None = None,
935
+ colorscale: (
936
+ Sequence[ParsableManimColor]
937
+ | Sequence[tuple[ParsableManimColor, float]]
938
+ | None
939
+ ) = None,
869
940
  colorscale_axis: int = 2,
870
- **kwargs,
871
- ):
941
+ **kwargs: Any,
942
+ ) -> Surface | OpenGLSurface:
872
943
  """Generates a surface based on a function.
873
944
 
874
945
  Parameters
@@ -948,7 +1019,7 @@ class CoordinateSystem:
948
1019
  self,
949
1020
  x: float,
950
1021
  graph: ParametricFunction | VMobject,
951
- ) -> np.ndarray:
1022
+ ) -> Point3D:
952
1023
  """Returns the coordinates of the point on a ``graph`` corresponding to an ``x`` value.
953
1024
 
954
1025
  Parameters
@@ -984,7 +1055,6 @@ class CoordinateSystem:
984
1055
 
985
1056
  self.add(ax, curve, sq)
986
1057
  """
987
-
988
1058
  if hasattr(graph, "underlying_function"):
989
1059
  return graph.function(x)
990
1060
  else:
@@ -1003,7 +1073,9 @@ class CoordinateSystem:
1003
1073
  f"x={x} not located in the range of the graph ([{self.p2c(graph.get_start())[0]}, {self.p2c(graph.get_end())[0]}])",
1004
1074
  )
1005
1075
 
1006
- def input_to_graph_coords(self, x: float, graph: ParametricFunction) -> tuple:
1076
+ def input_to_graph_coords(
1077
+ self, x: float, graph: ParametricFunction
1078
+ ) -> tuple[float, float]:
1007
1079
  """Returns a tuple of the axis relative coordinates of the point
1008
1080
  on the graph based on the x-value given.
1009
1081
 
@@ -1019,7 +1091,7 @@ class CoordinateSystem:
1019
1091
  """
1020
1092
  return x, graph.underlying_function(x)
1021
1093
 
1022
- def i2gc(self, x: float, graph: ParametricFunction) -> tuple:
1094
+ def i2gc(self, x: float, graph: ParametricFunction) -> tuple[float, float]:
1023
1095
  """Alias for :meth:`input_to_graph_coords`."""
1024
1096
  return self.input_to_graph_coords(x, graph)
1025
1097
 
@@ -1030,15 +1102,15 @@ class CoordinateSystem:
1030
1102
  def get_graph_label(
1031
1103
  self,
1032
1104
  graph: ParametricFunction,
1033
- label: float | str | Mobject = "f(x)",
1105
+ label: float | str | VMobject = "f(x)",
1034
1106
  x_val: float | None = None,
1035
1107
  direction: Sequence[float] = RIGHT,
1036
1108
  buff: float = MED_SMALL_BUFF,
1037
- color: Color | None = None,
1109
+ color: ParsableManimColor | None = None,
1038
1110
  dot: bool = False,
1039
- dot_config: dict | None = None,
1111
+ dot_config: dict[str, Any] | None = None,
1040
1112
  ) -> Mobject:
1041
- """Creates a properly positioned label for the passed graph, with an optional dot.
1113
+ r"""Creates a properly positioned label for the passed graph, with an optional dot.
1042
1114
 
1043
1115
  Parameters
1044
1116
  ----------
@@ -1075,7 +1147,7 @@ class CoordinateSystem:
1075
1147
  sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B)
1076
1148
  label = ax.get_graph_label(
1077
1149
  graph=sin,
1078
- label= MathTex(r"\\frac{\\pi}{2}"),
1150
+ label= MathTex(r"\frac{\pi}{2}"),
1079
1151
  x_val=PI / 2,
1080
1152
  dot=True,
1081
1153
  direction=UR,
@@ -1083,11 +1155,11 @@ class CoordinateSystem:
1083
1155
 
1084
1156
  self.add(ax, sin, label)
1085
1157
  """
1086
-
1087
1158
  if dot_config is None:
1088
1159
  dot_config = {}
1089
- color = color or graph.get_color()
1090
- label = self.x_axis._create_label_tex(label).set_color(color)
1160
+ if color is None:
1161
+ color = graph.get_color()
1162
+ label_object: Mobject = self.x_axis._create_label_tex(label).set_color(color)
1091
1163
 
1092
1164
  if x_val is None:
1093
1165
  # Search from right to left
@@ -1098,14 +1170,14 @@ class CoordinateSystem:
1098
1170
  else:
1099
1171
  point = self.input_to_graph_point(x_val, graph)
1100
1172
 
1101
- label.next_to(point, direction, buff=buff)
1102
- label.shift_onto_screen()
1173
+ label_object.next_to(point, direction, buff=buff)
1174
+ label_object.shift_onto_screen()
1103
1175
 
1104
1176
  if dot:
1105
1177
  dot = Dot(point=point, **dot_config)
1106
- label.add(dot)
1107
- label.dot = dot
1108
- return label
1178
+ label_object.add(dot)
1179
+ label_object.dot = dot
1180
+ return label_object
1109
1181
 
1110
1182
  # calculus
1111
1183
 
@@ -1113,14 +1185,14 @@ class CoordinateSystem:
1113
1185
  self,
1114
1186
  graph: ParametricFunction,
1115
1187
  x_range: Sequence[float] | None = None,
1116
- dx: float | None = 0.1,
1188
+ dx: float = 0.1,
1117
1189
  input_sample_type: str = "left",
1118
1190
  stroke_width: float = 1,
1119
- stroke_color: Color = BLACK,
1191
+ stroke_color: ParsableManimColor = BLACK,
1120
1192
  fill_opacity: float = 1,
1121
- color: Iterable[Color] | Color = np.array((BLUE, GREEN)),
1193
+ color: Iterable[ParsableManimColor] | ParsableManimColor = (BLUE, GREEN),
1122
1194
  show_signed_area: bool = True,
1123
- bounded_graph: ParametricFunction = None,
1195
+ bounded_graph: ParametricFunction | None = None,
1124
1196
  blend: bool = False,
1125
1197
  width_scale_factor: float = 1.001,
1126
1198
  ) -> VGroup:
@@ -1202,7 +1274,6 @@ class CoordinateSystem:
1202
1274
  ax, bounding_line, quadratic, rects_right, rects_left, bounded_rects
1203
1275
  )
1204
1276
  """
1205
-
1206
1277
  # setting up x_range, overwrite user's third input
1207
1278
  if x_range is None:
1208
1279
  if bounded_graph is None:
@@ -1215,15 +1286,16 @@ class CoordinateSystem:
1215
1286
  x_range = [*x_range[:2], dx]
1216
1287
 
1217
1288
  rectangles = VGroup()
1218
- x_range = np.arange(*x_range)
1289
+ x_range_array = np.arange(*x_range)
1219
1290
 
1220
- # allows passing a string to color the graph
1221
- if type(color) is str:
1222
- colors = [color] * len(x_range)
1291
+ if isinstance(color, (list, tuple)):
1292
+ color = [ManimColor(c) for c in color]
1223
1293
  else:
1224
- colors = color_gradient(color, len(x_range))
1294
+ color = [ManimColor(color)]
1295
+
1296
+ colors = color_gradient(color, len(x_range_array))
1225
1297
 
1226
- for x, color in zip(x_range, colors):
1298
+ for x, color in zip(x_range_array, colors):
1227
1299
  if input_sample_type == "left":
1228
1300
  sample_input = x
1229
1301
  elif input_sample_type == "right":
@@ -1276,11 +1348,11 @@ class CoordinateSystem:
1276
1348
  self,
1277
1349
  graph: ParametricFunction,
1278
1350
  x_range: tuple[float, float] | None = None,
1279
- color: Color | Iterable[Color] = [BLUE, GREEN],
1351
+ color: ParsableManimColor | Iterable[ParsableManimColor] = (BLUE, GREEN),
1280
1352
  opacity: float = 0.3,
1281
- bounded_graph: ParametricFunction = None,
1282
- **kwargs,
1283
- ):
1353
+ bounded_graph: ParametricFunction | None = None,
1354
+ **kwargs: Any,
1355
+ ) -> Polygon:
1284
1356
  """Returns a :class:`~.Polygon` representing the area under the graph passed.
1285
1357
 
1286
1358
  Parameters
@@ -1391,12 +1463,13 @@ class CoordinateSystem:
1391
1463
  ax.angle_of_tangent(x=3, graph=curve)
1392
1464
  # 1.4056476493802699
1393
1465
  """
1394
-
1395
1466
  p0 = np.array([*self.input_to_graph_coords(x, graph)])
1396
1467
  p1 = np.array([*self.input_to_graph_coords(x + dx, graph)])
1397
1468
  return angle_of_vector(p1 - p0)
1398
1469
 
1399
- def slope_of_tangent(self, x: float, graph: ParametricFunction, **kwargs) -> float:
1470
+ def slope_of_tangent(
1471
+ self, x: float, graph: ParametricFunction, **kwargs: Any
1472
+ ) -> float:
1400
1473
  """Returns the slope of the tangent to the plotted curve
1401
1474
  at a particular x-value.
1402
1475
 
@@ -1421,11 +1494,14 @@ class CoordinateSystem:
1421
1494
  ax.slope_of_tangent(x=-2, graph=curve)
1422
1495
  # -3.5000000259052038
1423
1496
  """
1424
-
1425
- return np.tan(self.angle_of_tangent(x, graph, **kwargs))
1497
+ val: float = np.tan(self.angle_of_tangent(x, graph, **kwargs))
1498
+ return val
1426
1499
 
1427
1500
  def plot_derivative_graph(
1428
- self, graph: ParametricFunction, color: Color = GREEN, **kwargs
1501
+ self,
1502
+ graph: ParametricFunction,
1503
+ color: ParsableManimColor = GREEN,
1504
+ **kwargs: Any,
1429
1505
  ) -> ParametricFunction:
1430
1506
  """Returns the curve of the derivative of the passed graph.
1431
1507
 
@@ -1463,7 +1539,7 @@ class CoordinateSystem:
1463
1539
  self.add(ax, curves, labels)
1464
1540
  """
1465
1541
 
1466
- def deriv(x):
1542
+ def deriv(x: float) -> float:
1467
1543
  return self.slope_of_tangent(x, graph)
1468
1544
 
1469
1545
  return self.plot(deriv, color=color, **kwargs)
@@ -1474,8 +1550,8 @@ class CoordinateSystem:
1474
1550
  y_intercept: float = 0,
1475
1551
  samples: int = 50,
1476
1552
  use_vectorized: bool = False,
1477
- **kwargs,
1478
- ):
1553
+ **kwargs: Any,
1554
+ ) -> ParametricFunction:
1479
1555
  """Plots an antiderivative graph.
1480
1556
 
1481
1557
  Parameters
@@ -1524,7 +1600,7 @@ class CoordinateSystem:
1524
1600
  x_vals = np.linspace(0, x, samples, axis=1 if use_vectorized else 0)
1525
1601
  f_vec = np.vectorize(graph.underlying_function)
1526
1602
  y_vals = f_vec(x_vals)
1527
- return np.trapz(y_vals, x_vals) + y_intercept
1603
+ return np.trapezoid(y_vals, x_vals) + y_intercept
1528
1604
 
1529
1605
  return self.plot(antideriv, use_vectorized=use_vectorized, **kwargs)
1530
1606
 
@@ -1533,12 +1609,12 @@ class CoordinateSystem:
1533
1609
  x: float,
1534
1610
  graph: ParametricFunction,
1535
1611
  dx: float | None = None,
1536
- dx_line_color: Color = YELLOW,
1537
- dy_line_color: Color | None = None,
1612
+ dx_line_color: ParsableManimColor = YELLOW,
1613
+ dy_line_color: ParsableManimColor | None = None,
1538
1614
  dx_label: float | str | None = None,
1539
1615
  dy_label: float | str | None = None,
1540
1616
  include_secant_line: bool = True,
1541
- secant_line_color: Color = GREEN,
1617
+ secant_line_color: ParsableManimColor = GREEN,
1542
1618
  secant_line_length: float = 10,
1543
1619
  ) -> VGroup:
1544
1620
  """Creates two lines representing `dx` and `df`, the labels for `dx` and `df`, and
@@ -1656,7 +1732,7 @@ class CoordinateSystem:
1656
1732
  graph: ParametricFunction,
1657
1733
  x_range: Sequence[float] | None = None,
1658
1734
  num_lines: int = 20,
1659
- **kwargs,
1735
+ **kwargs: Any,
1660
1736
  ) -> VGroup:
1661
1737
  """Obtains multiple lines from the x-axis to the curve.
1662
1738
 
@@ -1697,7 +1773,6 @@ class CoordinateSystem:
1697
1773
 
1698
1774
  self.add(ax, curve, lines)
1699
1775
  """
1700
-
1701
1776
  x_range = x_range if x_range is not None else self.x_range
1702
1777
 
1703
1778
  return VGroup(
@@ -1712,11 +1787,11 @@ class CoordinateSystem:
1712
1787
  x_val: float,
1713
1788
  graph: ParametricFunction,
1714
1789
  label: float | str | Mobject | None = None,
1715
- label_color: Color | None = None,
1790
+ label_color: ParsableManimColor | None = None,
1716
1791
  triangle_size: float = MED_SMALL_BUFF,
1717
- triangle_color: Color | None = WHITE,
1718
- line_func: Line = Line,
1719
- line_color: Color = YELLOW,
1792
+ triangle_color: ParsableManimColor | None = WHITE,
1793
+ line_func: type[Line] = Line,
1794
+ line_color: ParsableManimColor = YELLOW,
1720
1795
  ) -> VGroup:
1721
1796
  """Creates a labelled triangle marker with a vertical line from the x-axis
1722
1797
  to a curve at a given x-value.
@@ -1759,7 +1834,6 @@ class CoordinateSystem:
1759
1834
  t_label = axes.get_T_label(x_val=4, graph=func, label=Tex("x-value"))
1760
1835
  self.add(axes, func, t_label)
1761
1836
  """
1762
-
1763
1837
  T_label_group = VGroup()
1764
1838
  triangle = RegularPolygon(n=3, start_angle=np.pi / 2, stroke_width=0).set_fill(
1765
1839
  color=triangle_color,
@@ -1782,6 +1856,17 @@ class CoordinateSystem:
1782
1856
 
1783
1857
  return T_label_group
1784
1858
 
1859
+ def __matmul__(self, coord: Point3DLike | Mobject) -> Point3DLike:
1860
+ if isinstance(coord, Mobject):
1861
+ coord = coord.get_center()
1862
+ return self.coords_to_point(*coord)
1863
+
1864
+ def __rmatmul__(self, point: Point3DLike) -> Point3DLike:
1865
+ return self.point_to_coords(point)
1866
+
1867
+ @staticmethod
1868
+ def _origin_shift(axis_range: Sequence[float]) -> float: ...
1869
+
1785
1870
 
1786
1871
  class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1787
1872
  """Creates a set of axes.
@@ -1825,6 +1910,17 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1825
1910
  # x_min must be > 0 because log is undefined at 0.
1826
1911
  graph = ax.plot(lambda x: x ** 2, x_range=[0.001, 10], use_smoothing=False)
1827
1912
  self.add(ax, graph)
1913
+
1914
+ Styling arguments can be passed to the underlying :class:`.NumberLine`
1915
+ mobjects that represent the axes:
1916
+
1917
+ .. manim:: AxesWithDifferentTips
1918
+ :save_last_frame:
1919
+
1920
+ class AxesWithDifferentTips(Scene):
1921
+ def construct(self):
1922
+ ax = Axes(axis_config={'tip_shape': StealthTip})
1923
+ self.add(ax)
1828
1924
  """
1829
1925
 
1830
1926
  def __init__(
@@ -1837,7 +1933,7 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1837
1933
  x_axis_config: dict | None = None,
1838
1934
  y_axis_config: dict | None = None,
1839
1935
  tips: bool = True,
1840
- **kwargs,
1936
+ **kwargs: Any,
1841
1937
  ):
1842
1938
  VGroup.__init__(self, **kwargs)
1843
1939
  CoordinateSystem.__init__(self, x_range, y_range, x_length, y_length)
@@ -1846,8 +1942,11 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1846
1942
  "include_tip": tips,
1847
1943
  "numbers_to_exclude": [0],
1848
1944
  }
1849
- self.x_axis_config = {}
1850
- self.y_axis_config = {"rotation": 90 * DEGREES, "label_direction": LEFT}
1945
+ self.x_axis_config: dict[str, Any] = {}
1946
+ self.y_axis_config: dict[str, Any] = {
1947
+ "rotation": 90 * DEGREES,
1948
+ "label_direction": LEFT,
1949
+ }
1851
1950
 
1852
1951
  self._update_default_configs(
1853
1952
  (self.axis_config, self.x_axis_config, self.y_axis_config),
@@ -1905,7 +2004,7 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1905
2004
  @staticmethod
1906
2005
  def _update_default_configs(
1907
2006
  default_configs: tuple[dict[Any, Any]], passed_configs: tuple[dict[Any, Any]]
1908
- ):
2007
+ ) -> None:
1909
2008
  """Takes in two tuples of dicts and return modifies the first such that values from
1910
2009
  ``passed_configs`` overwrite values in ``default_configs``. If a key does not exist
1911
2010
  in default_configs, it is added to the dict.
@@ -1920,6 +2019,8 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1920
2019
  passed_configs
1921
2020
  The dict that will be used to update.
1922
2021
 
2022
+ Examples
2023
+ --------
1923
2024
  To create a tuple with one dictionary, add a comma after the element:
1924
2025
 
1925
2026
  .. code-block:: python
@@ -1930,7 +2031,6 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1930
2031
  )
1931
2032
  )
1932
2033
  """
1933
-
1934
2034
  for default_config, passed_config in zip(default_configs, passed_configs):
1935
2035
  if passed_config is not None:
1936
2036
  update_dict_recursively(default_config, passed_config)
@@ -1938,7 +2038,7 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1938
2038
  def _create_axis(
1939
2039
  self,
1940
2040
  range_terms: Sequence[float],
1941
- axis_config: dict,
2041
+ axis_config: dict[str, Any],
1942
2042
  length: float,
1943
2043
  ) -> NumberLine:
1944
2044
  """Creates an axis and dynamically adjusts its position depending on where 0 is located on the line.
@@ -1969,6 +2069,7 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1969
2069
  self, *coords: float | Sequence[float] | Sequence[Sequence[float]] | np.ndarray
1970
2070
  ) -> np.ndarray:
1971
2071
  """Accepts coordinates from the axes and returns a point with respect to the scene.
2072
+ Equivalent to `ax @ (coord1)`
1972
2073
 
1973
2074
  Parameters
1974
2075
  ----------
@@ -1997,6 +2098,8 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
1997
2098
  >>> ax = Axes()
1998
2099
  >>> np.around(ax.coords_to_point(1, 0, 0), 2)
1999
2100
  array([0.86, 0. , 0. ])
2101
+ >>> np.around(ax @ (1, 0, 0), 2)
2102
+ array([0.86, 0. , 0. ])
2000
2103
  >>> np.around(ax.coords_to_point([[0, 1], [1, 1], [1, 0]]), 2)
2001
2104
  array([[0. , 0.75, 0. ],
2002
2105
  [0.86, 0.75, 0. ],
@@ -2026,40 +2129,47 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
2026
2129
 
2027
2130
  self.add(plane, dot_scene, ax, dot_axes, lines)
2028
2131
  """
2132
+ coords = np.asarray(coords)
2029
2133
  origin = self.x_axis.number_to_point(
2030
2134
  self._origin_shift([self.x_axis.x_min, self.x_axis.x_max]),
2031
2135
  )
2032
2136
 
2033
- coords = np.asarray(coords)
2034
-
2035
- # if called like coords_to_point(1, 2, 3), then coords is a 1x3 array
2036
- transposed = False
2037
- if coords.ndim == 1:
2038
- # original implementation of coords_to_point for performance in the legacy case
2039
- result = np.array(origin)
2040
- for axis, number in zip(self.get_axes(), coords):
2041
- result += axis.number_to_point(number) - origin
2042
- return result
2043
- # if called like coords_to_point([1, 2, 3],[4, 5, 6]), then it shall be used as [1,4], [2,5], [3,6] and return the points as ([x_0,x_1],[y_0,y_1],[z_0,z_1])
2044
- elif coords.ndim == 2:
2045
- coords = coords.T
2046
- transposed = True
2047
- # if called like coords_to_point(np.array([[1, 2, 3],[4,5,6]])), reduce dimension by 1
2048
- elif coords.ndim == 3:
2049
- coords = np.squeeze(coords)
2050
- # else the coords is a Nx1, Nx2, Nx3 array so we do not need to modify the array
2051
-
2052
- points = origin + np.sum(
2053
- [
2054
- axis.number_to_point(number) - origin
2055
- for number, axis in zip(coords.T, self.get_axes())
2056
- ],
2057
- axis=0,
2058
- )
2059
- # if called with single coord, then return a point instead of a list of points
2060
- if transposed:
2061
- return points.T
2062
- return points
2137
+ # Is coords in the format ([[x1 y1 z1] [x2 y2 z2] ...])? (True)
2138
+ # Or is coords in the format (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...])? (False)
2139
+ # The latter is preferred.
2140
+ are_coordinates_transposed = False
2141
+
2142
+ # If coords is in the format ([[x1 y1 z1] [x2 y2 z2] ...]):
2143
+ if coords.ndim == 3:
2144
+ # Extract from original tuple: now coords looks like [[x y z]] or [[x1 y1 z1] [x2 y2 z2] ...].
2145
+ coords = coords[0]
2146
+ # If there's a single coord (coords = [[x y z]]), extract it so that
2147
+ # coords = [x y z] and coords_to_point returns a single point.
2148
+ if coords.shape[0] == 1:
2149
+ coords = coords[0]
2150
+ # Else, if coords looks more like [[x1 y1 z1] [x2 y2 z2] ...], transform them (by
2151
+ # transposing) into the format [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]] for later processing.
2152
+ else:
2153
+ coords = coords.T
2154
+ are_coordinates_transposed = True
2155
+ # Otherwise, coords already looked like (x, y, z) or ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]),
2156
+ # so no further processing is needed.
2157
+
2158
+ # Now coords should either look like [x y z] or [[x1 x2 ...] [y1 y2 ...] [z1 z2 ...]],
2159
+ # so it can be iterated directly. Each element is either a float representing a single
2160
+ # coordinate, or a float ndarray of coordinates corresponding to a single axis.
2161
+ # Although "points" and "nums" are in plural, there might be a single point or number.
2162
+ points = self.x_axis.number_to_point(coords[0])
2163
+ other_axes = self.axes.submobjects[1:]
2164
+ for axis, nums in zip(other_axes, coords[1:]):
2165
+ points += axis.number_to_point(nums) - origin
2166
+
2167
+ # Return points as is, except if coords originally looked like
2168
+ # ([x1 x2 ...], [y1 y2 ...], [z1 z2 ...]), which is determined by the conditions below. In
2169
+ # that case, the current implementation requires that the results have to be transposed.
2170
+ if are_coordinates_transposed or points.ndim == 1:
2171
+ return points
2172
+ return points.T
2063
2173
 
2064
2174
  def point_to_coords(self, point: Sequence[float]) -> np.ndarray:
2065
2175
  """Accepts a point from the scene and returns its coordinates with respect to the axes.
@@ -2124,16 +2234,63 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL):
2124
2234
  """
2125
2235
  return self.axes
2126
2236
 
2237
+ def get_axis_labels(
2238
+ self,
2239
+ x_label: float | str | Mobject = "x",
2240
+ y_label: float | str | Mobject = "y",
2241
+ ) -> VGroup:
2242
+ """Defines labels for the x-axis and y-axis of the graph.
2243
+
2244
+ For increased control over the position of the labels,
2245
+ use :meth:`~.CoordinateSystem.get_x_axis_label` and
2246
+ :meth:`~.CoordinateSystem.get_y_axis_label`.
2247
+
2248
+ Parameters
2249
+ ----------
2250
+ x_label
2251
+ The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2252
+ y_label
2253
+ The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2254
+
2255
+ Returns
2256
+ -------
2257
+ :class:`~.VGroup`
2258
+ A :class:`~.VGroup` of the labels for the x_axis and y_axis.
2259
+
2260
+
2261
+ .. seealso::
2262
+ :meth:`~.CoordinateSystem.get_x_axis_label`
2263
+ :meth:`~.CoordinateSystem.get_y_axis_label`
2264
+
2265
+ Examples
2266
+ --------
2267
+ .. manim:: GetAxisLabelsExample
2268
+ :save_last_frame:
2269
+
2270
+ class GetAxisLabelsExample(Scene):
2271
+ def construct(self):
2272
+ ax = Axes()
2273
+ labels = ax.get_axis_labels(
2274
+ Tex("x-axis").scale(0.7), Text("y-axis").scale(0.45)
2275
+ )
2276
+ self.add(ax, labels)
2277
+ """
2278
+ self.axis_labels = VGroup(
2279
+ self.get_x_axis_label(x_label),
2280
+ self.get_y_axis_label(y_label),
2281
+ )
2282
+ return self.axis_labels
2283
+
2127
2284
  def plot_line_graph(
2128
2285
  self,
2129
2286
  x_values: Iterable[float],
2130
2287
  y_values: Iterable[float],
2131
2288
  z_values: Iterable[float] | None = None,
2132
- line_color: Color = YELLOW,
2289
+ line_color: ParsableManimColor = YELLOW,
2133
2290
  add_vertex_dots: bool = True,
2134
2291
  vertex_dot_radius: float = DEFAULT_DOT_RADIUS,
2135
- vertex_dot_style: dict | None = None,
2136
- **kwargs,
2292
+ vertex_dot_style: dict[str, Any] | None = None,
2293
+ **kwargs: Any,
2137
2294
  ) -> VDict:
2138
2295
  """Draws a line graph.
2139
2296
 
@@ -2275,16 +2432,15 @@ class ThreeDAxes(Axes):
2275
2432
  x_length: float | None = config.frame_height + 2.5,
2276
2433
  y_length: float | None = config.frame_height + 2.5,
2277
2434
  z_length: float | None = config.frame_height - 1.5,
2278
- z_axis_config: dict | None = None,
2279
- z_normal: Sequence[float] = DOWN,
2435
+ z_axis_config: dict[str, Any] | None = None,
2436
+ z_normal: Vector3DLike = DOWN,
2280
2437
  num_axis_pieces: int = 20,
2281
- light_source: Sequence[float] = 9 * DOWN + 7 * LEFT + 10 * OUT,
2438
+ light_source: Point3DLike = 9 * DOWN + 7 * LEFT + 10 * OUT,
2282
2439
  # opengl stuff (?)
2283
- depth=None,
2284
- gloss=0.5,
2285
- **kwargs,
2440
+ depth: Any = None,
2441
+ gloss: float = 0.5,
2442
+ **kwargs: dict[str, Any],
2286
2443
  ):
2287
-
2288
2444
  super().__init__(
2289
2445
  x_range=x_range,
2290
2446
  x_length=x_length,
@@ -2296,7 +2452,7 @@ class ThreeDAxes(Axes):
2296
2452
  self.z_range = z_range
2297
2453
  self.z_length = z_length
2298
2454
 
2299
- self.z_axis_config = {}
2455
+ self.z_axis_config: dict[str, Any] = {}
2300
2456
  self._update_default_configs((self.z_axis_config,), (z_axis_config,))
2301
2457
  self.z_axis_config = merge_dicts_recursively(
2302
2458
  self.axis_config,
@@ -2306,7 +2462,7 @@ class ThreeDAxes(Axes):
2306
2462
  self.z_normal = z_normal
2307
2463
  self.num_axis_pieces = num_axis_pieces
2308
2464
 
2309
- self.light_source = light_source
2465
+ self.light_source = np.array(light_source)
2310
2466
 
2311
2467
  self.dimension = 3
2312
2468
 
@@ -2340,14 +2496,14 @@ class ThreeDAxes(Axes):
2340
2496
  self._add_3d_pieces()
2341
2497
  self._set_axis_shading()
2342
2498
 
2343
- def _add_3d_pieces(self):
2499
+ def _add_3d_pieces(self) -> None:
2344
2500
  for axis in self.axes:
2345
2501
  axis.pieces = VGroup(*axis.get_pieces(self.num_axis_pieces))
2346
2502
  axis.add(axis.pieces)
2347
2503
  axis.set_stroke(width=0, family=False)
2348
2504
  axis.set_shade_in_3d(True)
2349
2505
 
2350
- def _set_axis_shading(self):
2506
+ def _set_axis_shading(self) -> None:
2351
2507
  def make_func(axis):
2352
2508
  vect = self.light_source
2353
2509
  return lambda: (
@@ -2361,15 +2517,65 @@ class ThreeDAxes(Axes):
2361
2517
  submob.get_unit_normal = lambda a: np.ones(3)
2362
2518
  submob.set_sheen(0.2)
2363
2519
 
2520
+ def get_y_axis_label(
2521
+ self,
2522
+ label: float | str | VMobject,
2523
+ edge: Vector3DLike = UR,
2524
+ direction: Vector3DLike = UR,
2525
+ buff: float = SMALL_BUFF,
2526
+ rotation: float = PI / 2,
2527
+ rotation_axis: Vector3DLike = OUT,
2528
+ **kwargs: dict[str, Any],
2529
+ ) -> Mobject:
2530
+ """Generate a y-axis label.
2531
+
2532
+ Parameters
2533
+ ----------
2534
+ label
2535
+ The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2536
+ edge
2537
+ The edge of the y-axis to which the label will be added, by default ``UR``.
2538
+ direction
2539
+ Allows for further positioning of the label from an edge, by default ``UR``.
2540
+ buff
2541
+ The distance of the label from the line, by default ``SMALL_BUFF``.
2542
+ rotation
2543
+ The angle at which to rotate the label, by default ``PI/2``.
2544
+ rotation_axis
2545
+ The axis about which to rotate the label, by default ``OUT``.
2546
+
2547
+ Returns
2548
+ -------
2549
+ :class:`~.Mobject`
2550
+ The positioned label.
2551
+
2552
+ Examples
2553
+ --------
2554
+ .. manim:: GetYAxisLabelExample
2555
+ :save_last_frame:
2556
+
2557
+ class GetYAxisLabelExample(ThreeDScene):
2558
+ def construct(self):
2559
+ ax = ThreeDAxes()
2560
+ lab = ax.get_y_axis_label(Tex("$y$-label"))
2561
+ self.set_camera_orientation(phi=2*PI/5, theta=PI/5)
2562
+ self.add(ax, lab)
2563
+ """
2564
+ positioned_label = self._get_axis_label(
2565
+ label, self.get_y_axis(), edge, direction, buff=buff, **kwargs
2566
+ )
2567
+ positioned_label.rotate(rotation, axis=rotation_axis)
2568
+ return positioned_label
2569
+
2364
2570
  def get_z_axis_label(
2365
2571
  self,
2366
- label: float | str | Mobject,
2367
- edge: Sequence[float] = OUT,
2368
- direction: Sequence[float] = RIGHT,
2572
+ label: float | str | VMobject,
2573
+ edge: Vector3DLike = OUT,
2574
+ direction: Vector3DLike = RIGHT,
2369
2575
  buff: float = SMALL_BUFF,
2370
- rotation=PI / 2,
2371
- rotation_axis=RIGHT,
2372
- **kwargs,
2576
+ rotation: float = PI / 2,
2577
+ rotation_axis: Vector3DLike = RIGHT,
2578
+ **kwargs: Any,
2373
2579
  ) -> Mobject:
2374
2580
  """Generate a z-axis label.
2375
2581
 
@@ -2378,11 +2584,11 @@ class ThreeDAxes(Axes):
2378
2584
  label
2379
2585
  The label. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2380
2586
  edge
2381
- The edge of the x-axis to which the label will be added, by default ``UR``.
2587
+ The edge of the z-axis to which the label will be added, by default ``OUT``.
2382
2588
  direction
2383
- Allows for further positioning of the label from an edge, by default ``UR``.
2589
+ Allows for further positioning of the label from an edge, by default ``RIGHT``.
2384
2590
  buff
2385
- The distance of the label from the line.
2591
+ The distance of the label from the line, by default ``SMALL_BUFF``.
2386
2592
  rotation
2387
2593
  The angle at which to rotate the label, by default ``PI/2``.
2388
2594
  rotation_axis
@@ -2405,13 +2611,66 @@ class ThreeDAxes(Axes):
2405
2611
  self.set_camera_orientation(phi=2*PI/5, theta=PI/5)
2406
2612
  self.add(ax, lab)
2407
2613
  """
2408
-
2409
2614
  positioned_label = self._get_axis_label(
2410
2615
  label, self.get_z_axis(), edge, direction, buff=buff, **kwargs
2411
2616
  )
2412
2617
  positioned_label.rotate(rotation, axis=rotation_axis)
2413
2618
  return positioned_label
2414
2619
 
2620
+ def get_axis_labels(
2621
+ self,
2622
+ x_label: float | str | VMobject = "x",
2623
+ y_label: float | str | VMobject = "y",
2624
+ z_label: float | str | VMobject = "z",
2625
+ ) -> VGroup:
2626
+ """Defines labels for the x_axis and y_axis of the graph.
2627
+
2628
+ For increased control over the position of the labels,
2629
+ use :meth:`~.CoordinateSystem.get_x_axis_label`,
2630
+ :meth:`~.ThreeDAxes.get_y_axis_label`, and
2631
+ :meth:`~.ThreeDAxes.get_z_axis_label`.
2632
+
2633
+ Parameters
2634
+ ----------
2635
+ x_label
2636
+ The label for the x_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2637
+ y_label
2638
+ The label for the y_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2639
+ z_label
2640
+ The label for the z_axis. Defaults to :class:`~.MathTex` for ``str`` and ``float`` inputs.
2641
+
2642
+ Returns
2643
+ -------
2644
+ :class:`~.VGroup`
2645
+ A :class:`~.VGroup` of the labels for the x_axis, y_axis, and z_axis.
2646
+
2647
+
2648
+ .. seealso::
2649
+ :meth:`~.CoordinateSystem.get_x_axis_label`
2650
+ :meth:`~.ThreeDAxes.get_y_axis_label`
2651
+ :meth:`~.ThreeDAxes.get_z_axis_label`
2652
+
2653
+ Examples
2654
+ --------
2655
+ .. manim:: GetAxisLabelsExample
2656
+ :save_last_frame:
2657
+
2658
+ class GetAxisLabelsExample(ThreeDScene):
2659
+ def construct(self):
2660
+ self.set_camera_orientation(phi=2*PI/5, theta=PI/5)
2661
+ axes = ThreeDAxes()
2662
+ labels = axes.get_axis_labels(
2663
+ Text("x-axis").scale(0.7), Text("y-axis").scale(0.45), Text("z-axis").scale(0.45)
2664
+ )
2665
+ self.add(axes, labels)
2666
+ """
2667
+ self.axis_labels = VGroup(
2668
+ self.get_x_axis_label(x_label),
2669
+ self.get_y_axis_label(y_label),
2670
+ self.get_z_axis_label(z_label),
2671
+ )
2672
+ return self.axis_labels
2673
+
2415
2674
 
2416
2675
  class NumberPlane(Axes):
2417
2676
  """Creates a cartesian plane with background lines.
@@ -2482,29 +2741,26 @@ class NumberPlane(Axes):
2482
2741
 
2483
2742
  def __init__(
2484
2743
  self,
2485
- x_range: Sequence[float]
2486
- | None = (
2744
+ x_range: Sequence[float] | None = (
2487
2745
  -config["frame_x_radius"],
2488
2746
  config["frame_x_radius"],
2489
2747
  1,
2490
2748
  ),
2491
- y_range: Sequence[float]
2492
- | None = (
2749
+ y_range: Sequence[float] | None = (
2493
2750
  -config["frame_y_radius"],
2494
2751
  config["frame_y_radius"],
2495
2752
  1,
2496
2753
  ),
2497
2754
  x_length: float | None = None,
2498
2755
  y_length: float | None = None,
2499
- background_line_style: dict | None = None,
2500
- faded_line_style: dict | None = None,
2756
+ background_line_style: dict[str, Any] | None = None,
2757
+ faded_line_style: dict[str, Any] | None = None,
2501
2758
  faded_line_ratio: int = 1,
2502
2759
  make_smooth_after_applying_functions: bool = True,
2503
- **kwargs,
2760
+ **kwargs: dict[str, Any],
2504
2761
  ):
2505
-
2506
2762
  # configs
2507
- self.axis_config = {
2763
+ self.axis_config: dict[str, Any] = {
2508
2764
  "stroke_width": 2,
2509
2765
  "include_ticks": False,
2510
2766
  "include_tip": False,
@@ -2512,8 +2768,8 @@ class NumberPlane(Axes):
2512
2768
  "label_direction": DR,
2513
2769
  "font_size": 24,
2514
2770
  }
2515
- self.y_axis_config = {"label_direction": DR}
2516
- self.background_line_style = {
2771
+ self.y_axis_config: dict[str, Any] = {"label_direction": DR}
2772
+ self.background_line_style: dict[str, Any] = {
2517
2773
  "stroke_color": BLUE_D,
2518
2774
  "stroke_width": 2,
2519
2775
  "stroke_opacity": 1,
@@ -2546,7 +2802,7 @@ class NumberPlane(Axes):
2546
2802
 
2547
2803
  self._init_background_lines()
2548
2804
 
2549
- def _init_background_lines(self):
2805
+ def _init_background_lines(self) -> None:
2550
2806
  """Will init all the lines of NumberPlanes (faded or not)"""
2551
2807
  if self.faded_line_style is None:
2552
2808
  style = dict(self.background_line_style)
@@ -2631,7 +2887,6 @@ class NumberPlane(Axes):
2631
2887
  The first (i.e the non-faded lines parallel to `axis_parallel_to`) and second
2632
2888
  (i.e the faded lines parallel to `axis_parallel_to`) sets of lines, respectively.
2633
2889
  """
2634
-
2635
2890
  line = Line(axis_parallel_to.get_start(), axis_parallel_to.get_end())
2636
2891
  if ratio_faded_lines == 0: # don't show faded lines
2637
2892
  ratio_faded_lines = 1 # i.e. set ratio to 1
@@ -2667,13 +2922,13 @@ class NumberPlane(Axes):
2667
2922
  lines2.add(new_line)
2668
2923
  return lines1, lines2
2669
2924
 
2670
- def get_vector(self, coords: Sequence[float], **kwargs):
2925
+ def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow:
2671
2926
  kwargs["buff"] = 0
2672
2927
  return Arrow(
2673
2928
  self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs
2674
2929
  )
2675
2930
 
2676
- def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50):
2931
+ def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self:
2677
2932
  for mob in self.family_members_with_points():
2678
2933
  num_curves = mob.get_num_curves()
2679
2934
  if num_inserted_curves > num_curves:
@@ -2761,18 +3016,18 @@ class PolarPlane(Axes):
2761
3016
  size: float | None = None,
2762
3017
  radius_step: float = 1,
2763
3018
  azimuth_step: float | None = None,
2764
- azimuth_units: str | None = "PI radians",
3019
+ azimuth_units: str = "PI radians",
2765
3020
  azimuth_compact_fraction: bool = True,
2766
3021
  azimuth_offset: float = 0,
2767
3022
  azimuth_direction: str = "CCW",
2768
3023
  azimuth_label_buff: float = SMALL_BUFF,
2769
3024
  azimuth_label_font_size: float = 24,
2770
- radius_config: dict | None = None,
2771
- background_line_style: dict | None = None,
2772
- faded_line_style: dict | None = None,
3025
+ radius_config: dict[str, Any] | None = None,
3026
+ background_line_style: dict[str, Any] | None = None,
3027
+ faded_line_style: dict[str, Any] | None = None,
2773
3028
  faded_line_ratio: int = 1,
2774
3029
  make_smooth_after_applying_functions: bool = True,
2775
- **kwargs,
3030
+ **kwargs: Any,
2776
3031
  ):
2777
3032
  # error catching
2778
3033
  if azimuth_units in ["PI radians", "TAU radians", "degrees", "gradians", None]:
@@ -2844,7 +3099,7 @@ class PolarPlane(Axes):
2844
3099
 
2845
3100
  self._init_background_lines()
2846
3101
 
2847
- def _init_background_lines(self):
3102
+ def _init_background_lines(self) -> None:
2848
3103
  """Will init all the lines of NumberPlanes (faded or not)"""
2849
3104
  if self.faded_line_style is None:
2850
3105
  style = dict(self.background_line_style)
@@ -2894,11 +3149,11 @@ class PolarPlane(Axes):
2894
3149
  unit_vector = self.x_axis.get_unit_vector()[0]
2895
3150
 
2896
3151
  for k, x in enumerate(rinput):
2897
- new_line = Circle(radius=x * unit_vector)
3152
+ new_circle = Circle(radius=x * unit_vector)
2898
3153
  if k % ratio_faded_lines == 0:
2899
- alines1.add(new_line)
3154
+ alines1.add(new_circle)
2900
3155
  else:
2901
- alines2.add(new_line)
3156
+ alines2.add(new_circle)
2902
3157
 
2903
3158
  line = Line(center, self.get_x_axis().get_end())
2904
3159
 
@@ -2924,13 +3179,13 @@ class PolarPlane(Axes):
2924
3179
  """
2925
3180
  return self.axes
2926
3181
 
2927
- def get_vector(self, coords, **kwargs):
3182
+ def get_vector(self, coords: Sequence[ManimFloat], **kwargs: Any) -> Arrow:
2928
3183
  kwargs["buff"] = 0
2929
3184
  return Arrow(
2930
3185
  self.coords_to_point(0, 0), self.coords_to_point(*coords), **kwargs
2931
3186
  )
2932
3187
 
2933
- def prepare_for_nonlinear_transform(self, num_inserted_curves=50):
3188
+ def prepare_for_nonlinear_transform(self, num_inserted_curves: int = 50) -> Self:
2934
3189
  for mob in self.family_members_with_points():
2935
3190
  num_curves = mob.get_num_curves()
2936
3191
  if num_inserted_curves > num_curves:
@@ -2941,7 +3196,7 @@ class PolarPlane(Axes):
2941
3196
  self,
2942
3197
  r_values: Iterable[float] | None = None,
2943
3198
  a_values: Iterable[float] | None = None,
2944
- **kwargs,
3199
+ **kwargs: Any,
2945
3200
  ) -> VDict:
2946
3201
  """Gets labels for the coordinates
2947
3202
 
@@ -2999,7 +3254,7 @@ class PolarPlane(Axes):
2999
3254
  elif self.azimuth_units == "degrees":
3000
3255
  a_tex = [
3001
3256
  MathTex(
3002
- f'{360 * i["label"]:g}' + r"^{\circ}",
3257
+ f"{360 * i['label']:g}" + r"^{\circ}",
3003
3258
  font_size=self.azimuth_label_font_size,
3004
3259
  ).next_to(
3005
3260
  i["point"],
@@ -3012,7 +3267,7 @@ class PolarPlane(Axes):
3012
3267
  elif self.azimuth_units == "gradians":
3013
3268
  a_tex = [
3014
3269
  MathTex(
3015
- f'{400 * i["label"]:g}' + r"^{g}",
3270
+ f"{400 * i['label']:g}" + r"^{g}",
3016
3271
  font_size=self.azimuth_label_font_size,
3017
3272
  ).next_to(
3018
3273
  i["point"],
@@ -3025,7 +3280,7 @@ class PolarPlane(Axes):
3025
3280
  elif self.azimuth_units is None:
3026
3281
  a_tex = [
3027
3282
  MathTex(
3028
- f'{i["label"]:g}',
3283
+ f"{i['label']:g}",
3029
3284
  font_size=self.azimuth_label_font_size,
3030
3285
  ).next_to(
3031
3286
  i["point"],
@@ -3043,7 +3298,7 @@ class PolarPlane(Axes):
3043
3298
  self,
3044
3299
  r_values: Iterable[float] | None = None,
3045
3300
  a_values: Iterable[float] | None = None,
3046
- ):
3301
+ ) -> Self:
3047
3302
  """Adds the coordinates.
3048
3303
 
3049
3304
  Parameters
@@ -3056,7 +3311,9 @@ class PolarPlane(Axes):
3056
3311
  self.add(self.get_coordinate_labels(r_values, a_values))
3057
3312
  return self
3058
3313
 
3059
- def get_radian_label(self, number, font_size=24, **kwargs):
3314
+ def get_radian_label(
3315
+ self, number: float, font_size: float = 24, **kwargs: Any
3316
+ ) -> MathTex:
3060
3317
  constant_label = {"PI radians": r"\pi", "TAU radians": r"\tau"}[
3061
3318
  self.azimuth_units
3062
3319
  ]
@@ -3125,7 +3382,7 @@ class ComplexPlane(NumberPlane):
3125
3382
 
3126
3383
  """
3127
3384
 
3128
- def __init__(self, **kwargs):
3385
+ def __init__(self, **kwargs: Any):
3129
3386
  super().__init__(
3130
3387
  **kwargs,
3131
3388
  )
@@ -3143,7 +3400,6 @@ class ComplexPlane(NumberPlane):
3143
3400
  np.ndarray
3144
3401
  The point on the plane.
3145
3402
  """
3146
-
3147
3403
  number = complex(number)
3148
3404
  return self.coords_to_point(number.real, number.imag)
3149
3405
 
@@ -3151,7 +3407,7 @@ class ComplexPlane(NumberPlane):
3151
3407
  """Abbreviation for :meth:`number_to_point`."""
3152
3408
  return self.number_to_point(number)
3153
3409
 
3154
- def point_to_number(self, point: Sequence[float]) -> complex:
3410
+ def point_to_number(self, point: Point3DLike) -> complex:
3155
3411
  """Accepts a point and returns a complex number equivalent to that point on the plane.
3156
3412
 
3157
3413
  Parameters
@@ -3164,11 +3420,10 @@ class ComplexPlane(NumberPlane):
3164
3420
  complex
3165
3421
  A complex number consisting of real and imaginary components.
3166
3422
  """
3167
-
3168
3423
  x, y = self.point_to_coords(point)
3169
3424
  return complex(x, y)
3170
3425
 
3171
- def p2n(self, point: Sequence[float]) -> complex:
3426
+ def p2n(self, point: Point3DLike) -> complex:
3172
3427
  """Abbreviation for :meth:`point_to_number`."""
3173
3428
  return self.point_to_number(point)
3174
3429
 
@@ -3186,7 +3441,7 @@ class ComplexPlane(NumberPlane):
3186
3441
  return [*x_numbers, *y_numbers]
3187
3442
 
3188
3443
  def get_coordinate_labels(
3189
- self, *numbers: Iterable[float | complex], **kwargs
3444
+ self, *numbers: Iterable[float | complex], **kwargs: Any
3190
3445
  ) -> VGroup:
3191
3446
  """Generates the :class:`~.DecimalNumber` mobjects for the coordinates of the plane.
3192
3447
 
@@ -3202,7 +3457,6 @@ class ComplexPlane(NumberPlane):
3202
3457
  :class:`~.VGroup`
3203
3458
  A :class:`~.VGroup` containing the positioned label mobjects.
3204
3459
  """
3205
-
3206
3460
  # TODO: Make this work the same as coord_sys.add_coordinates()
3207
3461
  if len(numbers) == 0:
3208
3462
  numbers = self._get_default_coordinate_values()
@@ -3221,7 +3475,9 @@ class ComplexPlane(NumberPlane):
3221
3475
  self.coordinate_labels.add(number_mob)
3222
3476
  return self.coordinate_labels
3223
3477
 
3224
- def add_coordinates(self, *numbers: Iterable[float | complex], **kwargs):
3478
+ def add_coordinates(
3479
+ self, *numbers: Iterable[float | complex], **kwargs: Any
3480
+ ) -> Self:
3225
3481
  """Adds the labels produced from :meth:`~.NumberPlane.get_coordinate_labels` to the plane.
3226
3482
 
3227
3483
  Parameters
@@ -3231,6 +3487,5 @@ class ComplexPlane(NumberPlane):
3231
3487
  kwargs
3232
3488
  Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`.
3233
3489
  """
3234
-
3235
3490
  self.add(self.get_coordinate_labels(*numbers, **kwargs))
3236
3491
  return self