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.
- manim/__init__.py +11 -6
- manim/__main__.py +62 -19
- manim/_config/__init__.py +10 -9
- manim/_config/cli_colors.py +26 -9
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +23 -13
- manim/_config/utils.py +662 -468
- manim/animation/animation.py +164 -18
- manim/animation/changing.py +34 -23
- manim/animation/composition.py +265 -67
- manim/animation/creation.py +208 -26
- manim/animation/fading.py +16 -18
- manim/animation/growing.py +35 -15
- manim/animation/indication.py +150 -76
- manim/animation/movement.py +56 -22
- manim/animation/numbers.py +64 -6
- manim/animation/rotation.py +78 -7
- manim/animation/specialized.py +6 -7
- manim/animation/speedmodifier.py +13 -10
- manim/animation/transform.py +14 -11
- manim/animation/transform_matching_parts.py +3 -4
- manim/animation/updaters/mobject_update_utils.py +152 -30
- manim/animation/updaters/update.py +10 -7
- manim/camera/camera.py +182 -118
- manim/camera/mapping_camera.py +34 -3
- manim/camera/moving_camera.py +95 -74
- manim/camera/multi_camera.py +23 -15
- manim/camera/three_d_camera.py +70 -52
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +76 -44
- manim/cli/checkhealth/checks.py +192 -0
- manim/cli/checkhealth/commands.py +90 -0
- manim/cli/default_group.py +158 -25
- manim/cli/init/commands.py +33 -25
- manim/cli/plugins/commands.py +16 -3
- manim/cli/render/commands.py +72 -60
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +59 -17
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +98 -33
- manim/constants.py +109 -59
- manim/data_structures.py +31 -0
- manim/mobject/frame.py +8 -5
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +277 -135
- manim/mobject/geometry/boolean_ops.py +32 -31
- manim/mobject/geometry/labeled.py +376 -0
- manim/mobject/geometry/line.py +192 -87
- manim/mobject/geometry/polygram.py +224 -58
- manim/mobject/geometry/shape_matchers.py +61 -25
- manim/mobject/geometry/tips.py +122 -48
- manim/mobject/graph.py +1027 -419
- manim/mobject/graphing/coordinate_systems.py +533 -278
- manim/mobject/graphing/functions.py +53 -32
- manim/mobject/graphing/number_line.py +123 -65
- manim/mobject/graphing/probability.py +88 -62
- manim/mobject/graphing/scale.py +33 -19
- manim/mobject/logo.py +118 -28
- manim/mobject/matrix.py +87 -83
- manim/mobject/mobject.py +912 -442
- manim/mobject/opengl/dot_cloud.py +16 -5
- manim/mobject/opengl/opengl_compatibility.py +4 -2
- manim/mobject/opengl/opengl_geometry.py +254 -153
- manim/mobject/opengl/opengl_image_mobject.py +3 -1
- manim/mobject/opengl/opengl_mobject.py +779 -482
- manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
- manim/mobject/opengl/opengl_surface.py +14 -92
- manim/mobject/opengl/opengl_three_dimensions.py +12 -8
- manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
- manim/mobject/svg/brace.py +173 -41
- manim/mobject/svg/svg_mobject.py +139 -53
- manim/mobject/table.py +61 -68
- manim/mobject/text/code_mobject.py +193 -539
- manim/mobject/text/numbers.py +81 -34
- manim/mobject/text/tex_mobject.py +130 -78
- manim/mobject/text/text_mobject.py +288 -164
- manim/mobject/three_d/polyhedra.py +111 -13
- manim/mobject/three_d/three_d_utils.py +17 -8
- manim/mobject/three_d/three_dimensions.py +239 -106
- manim/mobject/types/image_mobject.py +50 -30
- manim/mobject/types/point_cloud_mobject.py +120 -75
- manim/mobject/types/vectorized_mobject.py +841 -408
- manim/mobject/value_tracker.py +105 -38
- manim/mobject/vector_field.py +50 -31
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +10 -14
- manim/renderer/cairo_renderer.py +65 -50
- manim/renderer/opengl_renderer.py +89 -69
- manim/renderer/opengl_renderer_window.py +39 -18
- manim/renderer/shader.py +123 -87
- manim/renderer/shader_wrapper.py +44 -28
- manim/renderer/vectorized_mobject_rendering.py +38 -10
- manim/scene/moving_camera_scene.py +32 -3
- manim/scene/scene.py +507 -242
- manim/scene/scene_file_writer.py +371 -220
- manim/scene/section.py +20 -16
- manim/scene/three_d_scene.py +14 -22
- manim/scene/vector_space_scene.py +223 -129
- manim/scene/zoomed_scene.py +46 -41
- manim/typing.py +990 -0
- manim/utils/bezier.py +1823 -371
- manim/utils/caching.py +12 -5
- manim/utils/color/AS2700.py +236 -0
- manim/utils/color/BS381.py +318 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +533 -0
- manim/utils/color/XKCD.py +952 -0
- manim/utils/color/__init__.py +61 -0
- manim/utils/color/core.py +1667 -0
- manim/utils/color/manim_colors.py +218 -0
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +39 -19
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +86 -39
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +236 -0
- manim/utils/docbuild/autocolor_directive.py +99 -0
- manim/utils/docbuild/manim_directive.py +94 -41
- manim/utils/docbuild/module_parsing.py +245 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +5 -3
- manim/utils/family_ops.py +17 -4
- manim/utils/file_ops.py +27 -17
- manim/utils/hashing.py +55 -45
- manim/utils/images.py +13 -7
- manim/utils/ipython_magic.py +13 -7
- manim/utils/iterables.py +163 -120
- manim/utils/module_ops.py +66 -24
- manim/utils/opengl.py +77 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +30 -33
- manim/utils/polylabel.py +235 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +98 -32
- manim/utils/simple_functions.py +25 -33
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +188 -115
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +34 -18
- manim/utils/testing/frames_comparison.py +37 -19
- manim/utils/tex.py +130 -198
- manim/utils/tex_file_writing.py +77 -47
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
- manim-0.19.1.dist-info/RECORD +220 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
- manim-0.19.1.dist-info/entry_points.txt +3 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
- manim/cli/new/group.py +0 -189
- manim/communitycolors.py +0 -9
- manim/gui/__init__.py +0 -0
- manim/gui/gui.py +0 -82
- manim/plugins/import_plugins.py +0 -43
- manim/utils/color.py +0 -552
- manim-0.17.0.dist-info/RECORD +0 -206
- manim-0.17.0.dist-info/entry_points.txt +0 -4
- /manim/cli/{new → checkhealth}/__init__.py +0 -0
- {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
|
|
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
|
|
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
|
|
95
|
-
graphs += grid.get_vertical_line(grid
|
|
96
|
-
graphs += Dot(point=grid
|
|
97
|
-
graphs += Tex("(1,1)").scale(0.75).next_to(grid
|
|
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) ->
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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) ->
|
|
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
|
-
|
|
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) ->
|
|
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 |
|
|
246
|
-
edge:
|
|
247
|
-
direction:
|
|
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 |
|
|
289
|
-
edge:
|
|
290
|
-
direction:
|
|
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
|
|
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 |
|
|
355
|
+
label: float | str | VMobject,
|
|
336
356
|
axis: Mobject,
|
|
337
|
-
edge:
|
|
338
|
-
direction:
|
|
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
|
-
|
|
363
|
-
|
|
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
|
-
|
|
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:
|
|
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(
|
|
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 = [
|
|
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:
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
|
|
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]
|
|
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:
|
|
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
|
-
) ->
|
|
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(
|
|
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 |
|
|
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:
|
|
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"
|
|
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
|
-
|
|
1090
|
-
|
|
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
|
-
|
|
1102
|
-
|
|
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
|
-
|
|
1107
|
-
|
|
1108
|
-
return
|
|
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
|
|
1188
|
+
dx: float = 0.1,
|
|
1117
1189
|
input_sample_type: str = "left",
|
|
1118
1190
|
stroke_width: float = 1,
|
|
1119
|
-
stroke_color:
|
|
1191
|
+
stroke_color: ParsableManimColor = BLACK,
|
|
1120
1192
|
fill_opacity: float = 1,
|
|
1121
|
-
color: Iterable[
|
|
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
|
-
|
|
1289
|
+
x_range_array = np.arange(*x_range)
|
|
1219
1290
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
colors = [color] * len(x_range)
|
|
1291
|
+
if isinstance(color, (list, tuple)):
|
|
1292
|
+
color = [ManimColor(c) for c in color]
|
|
1223
1293
|
else:
|
|
1224
|
-
|
|
1294
|
+
color = [ManimColor(color)]
|
|
1295
|
+
|
|
1296
|
+
colors = color_gradient(color, len(x_range_array))
|
|
1225
1297
|
|
|
1226
|
-
for x, color in zip(
|
|
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:
|
|
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(
|
|
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
|
|
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,
|
|
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.
|
|
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:
|
|
1537
|
-
dy_line_color:
|
|
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:
|
|
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:
|
|
1790
|
+
label_color: ParsableManimColor | None = None,
|
|
1716
1791
|
triangle_size: float = MED_SMALL_BUFF,
|
|
1717
|
-
triangle_color:
|
|
1718
|
-
line_func: Line = Line,
|
|
1719
|
-
line_color:
|
|
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
|
|
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
|
|
2034
|
-
|
|
2035
|
-
#
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
)
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
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:
|
|
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:
|
|
2435
|
+
z_axis_config: dict[str, Any] | None = None,
|
|
2436
|
+
z_normal: Vector3DLike = DOWN,
|
|
2280
2437
|
num_axis_pieces: int = 20,
|
|
2281
|
-
light_source:
|
|
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 |
|
|
2367
|
-
edge:
|
|
2368
|
-
direction:
|
|
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
|
|
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 ``
|
|
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[
|
|
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
|
|
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
|
-
|
|
3152
|
+
new_circle = Circle(radius=x * unit_vector)
|
|
2898
3153
|
if k % ratio_faded_lines == 0:
|
|
2899
|
-
alines1.add(
|
|
3154
|
+
alines1.add(new_circle)
|
|
2900
3155
|
else:
|
|
2901
|
-
alines2.add(
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
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
|