manim 0.18.1__py3-none-any.whl → 0.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__main__.py +45 -12
- manim/_config/__init__.py +2 -2
- manim/_config/cli_colors.py +8 -4
- manim/_config/default.cfg +0 -2
- manim/_config/logger_utils.py +5 -0
- manim/_config/utils.py +29 -38
- manim/animation/animation.py +148 -8
- manim/animation/composition.py +16 -13
- manim/animation/creation.py +184 -8
- manim/animation/fading.py +5 -8
- manim/animation/indication.py +93 -26
- manim/animation/movement.py +21 -3
- manim/animation/rotation.py +2 -1
- manim/animation/specialized.py +3 -5
- manim/animation/speedmodifier.py +3 -3
- manim/animation/transform.py +4 -5
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +2 -2
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +52 -36
- manim/cli/checkhealth/checks.py +92 -76
- manim/cli/checkhealth/commands.py +12 -5
- manim/cli/default_group.py +148 -24
- manim/cli/init/commands.py +28 -23
- manim/cli/plugins/commands.py +13 -3
- manim/cli/render/commands.py +47 -42
- manim/cli/render/global_options.py +43 -9
- manim/cli/render/render_options.py +84 -19
- manim/constants.py +11 -4
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +109 -75
- manim/mobject/geometry/boolean_ops.py +20 -17
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +120 -60
- manim/mobject/geometry/polygram.py +109 -25
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +36 -27
- manim/mobject/graph.py +48 -40
- manim/mobject/graphing/coordinate_systems.py +110 -45
- manim/mobject/graphing/functions.py +16 -10
- manim/mobject/graphing/number_line.py +23 -9
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +149 -103
- manim/mobject/opengl/opengl_geometry.py +4 -8
- manim/mobject/opengl/opengl_mobject.py +506 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
- manim/mobject/opengl/opengl_surface.py +1 -2
- manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
- manim/mobject/svg/brace.py +61 -13
- manim/mobject/svg/svg_mobject.py +2 -1
- manim/mobject/table.py +11 -12
- manim/mobject/text/code_mobject.py +186 -550
- manim/mobject/text/numbers.py +7 -7
- manim/mobject/text/tex_mobject.py +22 -13
- manim/mobject/text/text_mobject.py +29 -20
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_dimensions.py +59 -31
- manim/mobject/types/image_mobject.py +37 -23
- manim/mobject/types/point_cloud_mobject.py +103 -67
- manim/mobject/types/vectorized_mobject.py +387 -214
- manim/mobject/value_tracker.py +2 -1
- manim/mobject/vector_field.py +2 -4
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +2 -3
- manim/plugins/plugins_flags.py +3 -3
- manim/renderer/cairo_renderer.py +11 -11
- manim/renderer/opengl_renderer.py +19 -20
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +3 -2
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +72 -41
- manim/scene/scene_file_writer.py +313 -164
- manim/scene/section.py +15 -15
- manim/scene/three_d_scene.py +8 -15
- manim/scene/vector_space_scene.py +3 -6
- manim/typing.py +326 -66
- manim/utils/bezier.py +1658 -381
- manim/utils/caching.py +11 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +2 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +2 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +818 -301
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +40 -19
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -6
- manim/utils/deprecation.py +92 -43
- manim/utils/docbuild/autoaliasattr_directive.py +45 -8
- manim/utils/docbuild/autocolor_directive.py +12 -13
- manim/utils/docbuild/manim_directive.py +35 -29
- manim/utils/docbuild/module_parsing.py +74 -27
- manim/utils/family.py +3 -3
- manim/utils/family_ops.py +12 -4
- manim/utils/file_ops.py +22 -16
- manim/utils/hashing.py +7 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +12 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +55 -19
- manim/utils/opengl.py +68 -23
- manim/utils/parameter_parsing.py +3 -2
- manim/utils/paths.py +11 -5
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +69 -32
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +48 -37
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +20 -14
- manim/utils/tex.py +4 -2
- manim/utils/tex_file_writing.py +45 -45
- manim/utils/tex_templates.py +1 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim-0.18.1.dist-info/RECORD +0 -217
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/utils/color/core.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
"""Manim's (internal) color data structure and some utilities for
|
|
2
|
-
color conversion.
|
|
1
|
+
"""Manim's (internal) color data structure and some utilities for color conversion.
|
|
3
2
|
|
|
4
|
-
This module contains the implementation of :class:`.ManimColor`,
|
|
5
|
-
|
|
3
|
+
This module contains the implementation of :class:`.ManimColor`, the data structure
|
|
4
|
+
internally used to represent colors.
|
|
6
5
|
|
|
7
|
-
The preferred way of using these colors is by importing their constants from
|
|
6
|
+
The preferred way of using these colors is by importing their constants from Manim:
|
|
8
7
|
|
|
9
8
|
.. code-block:: pycon
|
|
10
9
|
|
|
@@ -12,12 +11,54 @@ The preferred way of using these colors is by importing their constants from man
|
|
|
12
11
|
>>> print(RED)
|
|
13
12
|
#FC6255
|
|
14
13
|
|
|
15
|
-
Note this way uses the name of the colors in UPPERCASE.
|
|
14
|
+
Note that this way uses the name of the colors in UPPERCASE.
|
|
16
15
|
|
|
17
16
|
.. note::
|
|
18
17
|
|
|
19
|
-
The colors
|
|
20
|
-
|
|
18
|
+
The colors with a ``_C`` suffix have an alias equal to the colorname without a
|
|
19
|
+
letter. For example, ``GREEN = GREEN_C``.
|
|
20
|
+
|
|
21
|
+
===================
|
|
22
|
+
Custom Color Spaces
|
|
23
|
+
===================
|
|
24
|
+
|
|
25
|
+
Hello, dear visitor. You seem to be interested in implementing a custom color class for
|
|
26
|
+
a color space we don't currently support.
|
|
27
|
+
|
|
28
|
+
The current system is using a few indirections for ensuring a consistent behavior with
|
|
29
|
+
all other color types in Manim.
|
|
30
|
+
|
|
31
|
+
To implement a custom color space, you must subclass :class:`ManimColor` and implement
|
|
32
|
+
three important methods:
|
|
33
|
+
|
|
34
|
+
- :attr:`~.ManimColor._internal_value`: a ``@property`` implemented on
|
|
35
|
+
:class:`ManimColor` with the goal of keeping a consistent internal representation
|
|
36
|
+
which can be referenced by other functions in :class:`ManimColor`. This property acts
|
|
37
|
+
as a proxy to whatever representation you need in your class.
|
|
38
|
+
|
|
39
|
+
- The getter should always return a NumPy array in the format ``[r,g,b,a]``, in
|
|
40
|
+
accordance with the type :class:`ManimColorInternal`.
|
|
41
|
+
|
|
42
|
+
- The setter should always accept a value in the format ``[r,g,b,a]`` which can be
|
|
43
|
+
converted to whatever attributes you need.
|
|
44
|
+
|
|
45
|
+
- :attr:`~ManimColor._internal_space`: a read-only ``@property`` implemented on
|
|
46
|
+
:class:`ManimColor` with the goal of providing a useful representation which can be
|
|
47
|
+
used by operators, interpolation and color transform functions.
|
|
48
|
+
|
|
49
|
+
The only constraints on this value are:
|
|
50
|
+
|
|
51
|
+
- It must be a NumPy array.
|
|
52
|
+
|
|
53
|
+
- The last value must be the opacity in a range ``0.0`` to ``1.0``.
|
|
54
|
+
|
|
55
|
+
Additionally, your ``__init__`` must support this format as an initialization value
|
|
56
|
+
without additional parameters to ensure correct functionality of all other methods in
|
|
57
|
+
:class:`ManimColor`.
|
|
58
|
+
|
|
59
|
+
- :meth:`~ManimColor._from_internal`: a ``@classmethod`` which converts an
|
|
60
|
+
``[r,g,b,a]`` value into suitable parameters for your ``__init__`` method and calls
|
|
61
|
+
the ``cls`` parameter.
|
|
21
62
|
"""
|
|
22
63
|
|
|
23
64
|
from __future__ import annotations
|
|
@@ -27,17 +68,24 @@ import colorsys
|
|
|
27
68
|
# logger = _config.logger
|
|
28
69
|
import random
|
|
29
70
|
import re
|
|
30
|
-
from
|
|
71
|
+
from collections.abc import Sequence
|
|
72
|
+
from typing import TypeVar, Union, overload
|
|
31
73
|
|
|
32
74
|
import numpy as np
|
|
33
75
|
import numpy.typing as npt
|
|
34
|
-
from typing_extensions import Self, TypeAlias
|
|
76
|
+
from typing_extensions import Self, TypeAlias, TypeIs, override
|
|
35
77
|
|
|
36
78
|
from manim.typing import (
|
|
79
|
+
HSL_Array_Float,
|
|
80
|
+
HSL_Tuple_Float,
|
|
37
81
|
HSV_Array_Float,
|
|
38
82
|
HSV_Tuple_Float,
|
|
83
|
+
HSVA_Array_Float,
|
|
84
|
+
HSVA_Tuple_Float,
|
|
39
85
|
ManimColorDType,
|
|
40
86
|
ManimColorInternal,
|
|
87
|
+
ManimFloat,
|
|
88
|
+
Point3D,
|
|
41
89
|
RGB_Array_Float,
|
|
42
90
|
RGB_Array_Int,
|
|
43
91
|
RGB_Tuple_Float,
|
|
@@ -46,43 +94,48 @@ from manim.typing import (
|
|
|
46
94
|
RGBA_Array_Int,
|
|
47
95
|
RGBA_Tuple_Float,
|
|
48
96
|
RGBA_Tuple_Int,
|
|
97
|
+
Vector3D,
|
|
49
98
|
)
|
|
50
99
|
|
|
51
100
|
from ...utils.space_ops import normalize
|
|
52
101
|
|
|
53
102
|
# import manim._config as _config
|
|
54
103
|
|
|
55
|
-
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{
|
|
104
|
+
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{3,8}", re.IGNORECASE)
|
|
56
105
|
|
|
57
106
|
|
|
58
107
|
class ManimColor:
|
|
59
108
|
"""Internal representation of a color.
|
|
60
109
|
|
|
61
|
-
The ManimColor class is the main class for the representation of a color.
|
|
62
|
-
|
|
63
|
-
|
|
110
|
+
The :class:`ManimColor` class is the main class for the representation of a color.
|
|
111
|
+
Its internal representation is an array of 4 floats corresponding to a ``[r,g,b,a]``
|
|
112
|
+
value where ``r,g,b,a`` can be between 0.0 and 1.0.
|
|
64
113
|
|
|
65
114
|
This is done in order to reduce the amount of color inconsistencies by constantly
|
|
66
115
|
casting between integers and floats which introduces errors.
|
|
67
116
|
|
|
68
117
|
The class can accept any value of type :class:`ParsableManimColor` i.e.
|
|
69
118
|
|
|
70
|
-
ManimColor, int, str, RGB_Tuple_Int, RGB_Tuple_Float, RGBA_Tuple_Int, RGBA_Tuple_Float, RGB_Array_Int,
|
|
71
|
-
RGB_Array_Float, RGBA_Array_Int, RGBA_Array_Float
|
|
119
|
+
``ManimColor, int, str, RGB_Tuple_Int, RGB_Tuple_Float, RGBA_Tuple_Int, RGBA_Tuple_Float, RGB_Array_Int,
|
|
120
|
+
RGB_Array_Float, RGBA_Array_Int, RGBA_Array_Float``
|
|
72
121
|
|
|
73
|
-
ManimColor itself only accepts singular values and will directly interpret
|
|
74
|
-
|
|
122
|
+
:class:`ManimColor` itself only accepts singular values and will directly interpret
|
|
123
|
+
them into a single color if possible. Be careful when passing strings to
|
|
124
|
+
:class:`ManimColor`: it can create a big overhead for the color processing.
|
|
75
125
|
|
|
76
|
-
If you want to parse a list of colors use the
|
|
77
|
-
you
|
|
126
|
+
If you want to parse a list of colors, use the :meth:`parse` method, which assumes
|
|
127
|
+
that you're going to pass a list of colors so that arrays will not be interpreted as
|
|
128
|
+
a single color.
|
|
78
129
|
|
|
79
130
|
.. warning::
|
|
80
|
-
If you pass an array of numbers to :meth:`parse
|
|
81
|
-
|
|
131
|
+
If you pass an array of numbers to :meth:`parse`, it will interpret the
|
|
132
|
+
``r,g,b,a`` numbers in that array as colors: Instead of the expected
|
|
133
|
+
singular color, you will get an array with 4 colors.
|
|
82
134
|
|
|
83
|
-
For conversion behaviors see the ``_internal`` functions for further documentation
|
|
135
|
+
For conversion behaviors, see the ``_internal`` functions for further documentation.
|
|
84
136
|
|
|
85
|
-
You can create a
|
|
137
|
+
You can create a :class:`ManimColor` instance via its classmethods. See the
|
|
138
|
+
respective methods for more info.
|
|
86
139
|
|
|
87
140
|
.. code-block:: python
|
|
88
141
|
|
|
@@ -131,14 +184,14 @@ class ManimColor:
|
|
|
131
184
|
# This is not expected to be called on module initialization time
|
|
132
185
|
# It can be horribly slow to convert a string to a color because
|
|
133
186
|
# it has to access the dictionary of colors and find the right color
|
|
134
|
-
self._internal_value = ManimColor._internal_from_string(value)
|
|
187
|
+
self._internal_value = ManimColor._internal_from_string(value, alpha)
|
|
135
188
|
elif isinstance(value, (list, tuple, np.ndarray)):
|
|
136
189
|
length = len(value)
|
|
137
190
|
if all(isinstance(x, float) for x in value):
|
|
138
191
|
if length == 3:
|
|
139
|
-
self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore
|
|
192
|
+
self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore[arg-type]
|
|
140
193
|
elif length == 4:
|
|
141
|
-
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore
|
|
194
|
+
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore[arg-type]
|
|
142
195
|
else:
|
|
143
196
|
raise ValueError(
|
|
144
197
|
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
@@ -146,10 +199,11 @@ class ManimColor:
|
|
|
146
199
|
else:
|
|
147
200
|
if length == 3:
|
|
148
201
|
self._internal_value = ManimColor._internal_from_int_rgb(
|
|
149
|
-
value,
|
|
202
|
+
value, # type: ignore[arg-type]
|
|
203
|
+
alpha,
|
|
150
204
|
)
|
|
151
205
|
elif length == 4:
|
|
152
|
-
self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore
|
|
206
|
+
self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore[arg-type]
|
|
153
207
|
else:
|
|
154
208
|
raise ValueError(
|
|
155
209
|
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
@@ -158,7 +212,6 @@ class ManimColor:
|
|
|
158
212
|
result = re_hex.search(value.get_hex())
|
|
159
213
|
if result is None:
|
|
160
214
|
raise ValueError(f"Failed to parse a color from {value}")
|
|
161
|
-
|
|
162
215
|
self._internal_value = ManimColor._internal_from_hex_string(
|
|
163
216
|
result.group(), alpha
|
|
164
217
|
)
|
|
@@ -170,37 +223,59 @@ class ManimColor:
|
|
|
170
223
|
f"list[float, float, float, float], not {type(value)}"
|
|
171
224
|
)
|
|
172
225
|
|
|
226
|
+
@property
|
|
227
|
+
def _internal_space(self) -> npt.NDArray[ManimFloat]:
|
|
228
|
+
"""This is a readonly property which is a custom representation for color space
|
|
229
|
+
operations. It is used for operators and can be used when implementing a custom
|
|
230
|
+
color space.
|
|
231
|
+
"""
|
|
232
|
+
return self._internal_value
|
|
233
|
+
|
|
173
234
|
@property
|
|
174
235
|
def _internal_value(self) -> ManimColorInternal:
|
|
175
|
-
"""
|
|
236
|
+
"""Return the internal value of the current Manim color ``[r,g,b,a]`` float
|
|
237
|
+
array.
|
|
176
238
|
|
|
177
239
|
Returns
|
|
178
240
|
-------
|
|
179
241
|
ManimColorInternal
|
|
180
|
-
|
|
242
|
+
Internal color representation.
|
|
181
243
|
"""
|
|
182
244
|
return self.__value
|
|
183
245
|
|
|
184
246
|
@_internal_value.setter
|
|
185
247
|
def _internal_value(self, value: ManimColorInternal) -> None:
|
|
186
|
-
"""
|
|
248
|
+
"""Overwrite the internal color value of this :class:`ManimColor`.
|
|
187
249
|
|
|
188
250
|
Parameters
|
|
189
251
|
----------
|
|
190
|
-
value
|
|
191
|
-
The value which will overwrite the current color
|
|
252
|
+
value
|
|
253
|
+
The value which will overwrite the current color.
|
|
192
254
|
|
|
193
255
|
Raises
|
|
194
256
|
------
|
|
195
257
|
TypeError
|
|
196
|
-
|
|
258
|
+
If an invalid array is passed.
|
|
197
259
|
"""
|
|
198
260
|
if not isinstance(value, np.ndarray):
|
|
199
|
-
raise TypeError("
|
|
261
|
+
raise TypeError("Value must be a NumPy array.")
|
|
200
262
|
if value.shape[0] != 4:
|
|
201
|
-
raise TypeError("Array must have 4 values
|
|
263
|
+
raise TypeError("Array must have exactly 4 values.")
|
|
202
264
|
self.__value: ManimColorInternal = value
|
|
203
265
|
|
|
266
|
+
@classmethod
|
|
267
|
+
def _construct_from_space(
|
|
268
|
+
cls,
|
|
269
|
+
_space: npt.NDArray[ManimFloat]
|
|
270
|
+
| tuple[float, float, float]
|
|
271
|
+
| tuple[float, float, float, float],
|
|
272
|
+
) -> Self:
|
|
273
|
+
"""This function is used as a proxy for constructing a color with an internal
|
|
274
|
+
value. This can be used by subclasses to hook into the construction of new
|
|
275
|
+
objects using the internal value format.
|
|
276
|
+
"""
|
|
277
|
+
return cls(_space)
|
|
278
|
+
|
|
204
279
|
@staticmethod
|
|
205
280
|
def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal:
|
|
206
281
|
return np.asarray(
|
|
@@ -213,32 +288,41 @@ class ManimColor:
|
|
|
213
288
|
dtype=ManimColorDType,
|
|
214
289
|
)
|
|
215
290
|
|
|
216
|
-
# TODO: Maybe make 8 nibble hex also convertible ?
|
|
217
291
|
@staticmethod
|
|
218
|
-
def _internal_from_hex_string(
|
|
219
|
-
"""Internal function for converting a hex string into the internal representation
|
|
292
|
+
def _internal_from_hex_string(hex_: str, alpha: float) -> ManimColorInternal:
|
|
293
|
+
"""Internal function for converting a hex string into the internal representation
|
|
294
|
+
of a :class:`ManimColor`.
|
|
220
295
|
|
|
221
296
|
.. warning::
|
|
222
297
|
This does not accept any prefixes like # or similar in front of the hex string.
|
|
223
|
-
This is just intended for the raw hex part
|
|
298
|
+
This is just intended for the raw hex part.
|
|
224
299
|
|
|
225
300
|
*For internal use only*
|
|
226
301
|
|
|
227
302
|
Parameters
|
|
228
303
|
----------
|
|
229
|
-
hex
|
|
230
|
-
|
|
231
|
-
alpha
|
|
232
|
-
|
|
304
|
+
hex
|
|
305
|
+
Hex string to be parsed.
|
|
306
|
+
alpha
|
|
307
|
+
Alpha value used for the color, if the color is only 3 bytes long. Otherwise,
|
|
308
|
+
if the color is 4 bytes long, this parameter will not be used.
|
|
233
309
|
|
|
234
310
|
Returns
|
|
235
311
|
-------
|
|
236
312
|
ManimColorInternal
|
|
237
313
|
Internal color representation
|
|
238
314
|
"""
|
|
239
|
-
if len(
|
|
240
|
-
|
|
241
|
-
|
|
315
|
+
if len(hex_) in (3, 4):
|
|
316
|
+
hex_ = "".join([x * 2 for x in hex_])
|
|
317
|
+
if len(hex_) == 6:
|
|
318
|
+
hex_ += "FF"
|
|
319
|
+
elif len(hex_) == 8:
|
|
320
|
+
alpha = (int(hex_, 16) & 0xFF) / 255
|
|
321
|
+
else:
|
|
322
|
+
raise ValueError(
|
|
323
|
+
"Hex colors must be specified with either 0x or # as prefix and contain 6 or 8 hexadecimal numbers"
|
|
324
|
+
)
|
|
325
|
+
tmp = int(hex_, 16)
|
|
242
326
|
return np.asarray(
|
|
243
327
|
(
|
|
244
328
|
((tmp >> 24) & 0xFF) / 255,
|
|
@@ -253,22 +337,22 @@ class ManimColor:
|
|
|
253
337
|
def _internal_from_int_rgb(
|
|
254
338
|
rgb: RGB_Tuple_Int, alpha: float = 1.0
|
|
255
339
|
) -> ManimColorInternal:
|
|
256
|
-
"""Internal function for converting
|
|
340
|
+
"""Internal function for converting an RGB tuple of integers into the internal
|
|
341
|
+
representation of a :class:`ManimColor`.
|
|
257
342
|
|
|
258
343
|
*For internal use only*
|
|
259
344
|
|
|
260
345
|
Parameters
|
|
261
346
|
----------
|
|
262
|
-
rgb
|
|
263
|
-
|
|
264
|
-
alpha
|
|
265
|
-
|
|
347
|
+
rgb
|
|
348
|
+
Integer RGB tuple to be parsed
|
|
349
|
+
alpha
|
|
350
|
+
Optional alpha value. Default is 1.0.
|
|
266
351
|
|
|
267
352
|
Returns
|
|
268
353
|
-------
|
|
269
354
|
ManimColorInternal
|
|
270
|
-
Internal color representation
|
|
271
|
-
|
|
355
|
+
Internal color representation.
|
|
272
356
|
"""
|
|
273
357
|
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() / 255
|
|
274
358
|
value.resize(4, refcheck=False)
|
|
@@ -279,22 +363,22 @@ class ManimColor:
|
|
|
279
363
|
def _internal_from_rgb(
|
|
280
364
|
rgb: RGB_Tuple_Float, alpha: float = 1.0
|
|
281
365
|
) -> ManimColorInternal:
|
|
282
|
-
"""Internal function for converting a rgb tuple of floats into the internal
|
|
366
|
+
"""Internal function for converting a rgb tuple of floats into the internal
|
|
367
|
+
representation of a :class:`ManimColor`.
|
|
283
368
|
|
|
284
369
|
*For internal use only*
|
|
285
370
|
|
|
286
371
|
Parameters
|
|
287
372
|
----------
|
|
288
|
-
rgb
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
optional alpha value, by default 1.0
|
|
373
|
+
rgb
|
|
374
|
+
Float RGB tuple to be parsed.
|
|
375
|
+
alpha
|
|
376
|
+
Optional alpha value. Default is 1.0.
|
|
293
377
|
|
|
294
378
|
Returns
|
|
295
379
|
-------
|
|
296
380
|
ManimColorInternal
|
|
297
|
-
Internal color representation
|
|
381
|
+
Internal color representation.
|
|
298
382
|
"""
|
|
299
383
|
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy()
|
|
300
384
|
value.resize(4, refcheck=False)
|
|
@@ -303,175 +387,178 @@ class ManimColor:
|
|
|
303
387
|
|
|
304
388
|
@staticmethod
|
|
305
389
|
def _internal_from_int_rgba(rgba: RGBA_Tuple_Int) -> ManimColorInternal:
|
|
306
|
-
"""Internal function for converting
|
|
390
|
+
"""Internal function for converting an RGBA tuple of integers into the internal
|
|
391
|
+
representation of a :class:`ManimColor`.
|
|
307
392
|
|
|
308
393
|
*For internal use only*
|
|
309
394
|
|
|
310
395
|
Parameters
|
|
311
396
|
----------
|
|
312
|
-
rgba
|
|
313
|
-
|
|
397
|
+
rgba
|
|
398
|
+
Int RGBA tuple to be parsed.
|
|
314
399
|
|
|
315
400
|
Returns
|
|
316
401
|
-------
|
|
317
402
|
ManimColorInternal
|
|
318
|
-
Internal color representation
|
|
403
|
+
Internal color representation.
|
|
319
404
|
"""
|
|
320
405
|
return np.asarray(rgba, dtype=ManimColorDType) / 255
|
|
321
406
|
|
|
322
407
|
@staticmethod
|
|
323
408
|
def _internal_from_rgba(rgba: RGBA_Tuple_Float) -> ManimColorInternal:
|
|
324
|
-
"""Internal function for converting
|
|
409
|
+
"""Internal function for converting an RGBA tuple of floats into the internal
|
|
410
|
+
representation of a :class:`ManimColor`.
|
|
325
411
|
|
|
326
412
|
*For internal use only*
|
|
327
413
|
|
|
328
414
|
Parameters
|
|
329
415
|
----------
|
|
330
|
-
rgba
|
|
331
|
-
|
|
416
|
+
rgba
|
|
417
|
+
Int RGBA tuple to be parsed.
|
|
332
418
|
|
|
333
419
|
Returns
|
|
334
420
|
-------
|
|
335
421
|
ManimColorInternal
|
|
336
|
-
Internal color representation
|
|
422
|
+
Internal color representation.
|
|
337
423
|
"""
|
|
338
424
|
return np.asarray(rgba, dtype=ManimColorDType)
|
|
339
425
|
|
|
340
426
|
@staticmethod
|
|
341
|
-
def _internal_from_string(name: str) -> ManimColorInternal:
|
|
342
|
-
"""Internal function for converting a string into the internal representation of
|
|
343
|
-
This is not used for hex strings
|
|
427
|
+
def _internal_from_string(name: str, alpha: float) -> ManimColorInternal:
|
|
428
|
+
"""Internal function for converting a string into the internal representation of
|
|
429
|
+
a :class:`ManimColor`. This is not used for hex strings: please refer to
|
|
430
|
+
:meth:`_internal_from_hex` for this functionality.
|
|
344
431
|
|
|
345
432
|
*For internal use only*
|
|
346
433
|
|
|
347
434
|
Parameters
|
|
348
435
|
----------
|
|
349
|
-
name
|
|
350
|
-
The color name to be parsed into a color. Refer to the different color
|
|
351
|
-
find the corresponding
|
|
436
|
+
name
|
|
437
|
+
The color name to be parsed into a color. Refer to the different color
|
|
438
|
+
modules in the documentation page to find the corresponding color names.
|
|
352
439
|
|
|
353
440
|
Returns
|
|
354
441
|
-------
|
|
355
442
|
ManimColorInternal
|
|
356
|
-
Internal color representation
|
|
443
|
+
Internal color representation.
|
|
357
444
|
|
|
358
445
|
Raises
|
|
359
446
|
------
|
|
360
447
|
ValueError
|
|
361
|
-
|
|
448
|
+
If the color name is not present in Manim.
|
|
362
449
|
"""
|
|
363
450
|
from . import _all_color_dict
|
|
364
451
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return _all_color_dict[upper_name]._internal_value
|
|
452
|
+
if tmp := _all_color_dict.get(name.upper()):
|
|
453
|
+
tmp._internal_value[3] = alpha
|
|
454
|
+
return tmp._internal_value.copy()
|
|
369
455
|
else:
|
|
370
456
|
raise ValueError(f"Color {name} not found")
|
|
371
457
|
|
|
372
458
|
def to_integer(self) -> int:
|
|
373
|
-
"""
|
|
459
|
+
"""Convert the current :class:`ManimColor` into an integer.
|
|
460
|
+
|
|
461
|
+
.. warning::
|
|
462
|
+
This will return only the RGB part of the color.
|
|
374
463
|
|
|
375
464
|
Returns
|
|
376
465
|
-------
|
|
377
466
|
int
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
.. warning::
|
|
381
|
-
This will return only the rgb part of the color
|
|
467
|
+
Integer representation of the color.
|
|
382
468
|
"""
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
)
|
|
469
|
+
tmp = (self._internal_value[:3] * 255).astype(dtype=np.byte).tobytes()
|
|
470
|
+
return int.from_bytes(tmp, "big")
|
|
386
471
|
|
|
387
472
|
def to_rgb(self) -> RGB_Array_Float:
|
|
388
|
-
"""
|
|
473
|
+
"""Convert the current :class:`ManimColor` into an RGB array of floats.
|
|
389
474
|
|
|
390
475
|
Returns
|
|
391
476
|
-------
|
|
392
477
|
RGB_Array_Float
|
|
393
|
-
|
|
478
|
+
RGB array of 3 floats from 0.0 to 1.0.
|
|
394
479
|
"""
|
|
395
480
|
return self._internal_value[:3]
|
|
396
481
|
|
|
397
482
|
def to_int_rgb(self) -> RGB_Array_Int:
|
|
398
|
-
"""
|
|
483
|
+
"""Convert the current :class:`ManimColor` into an RGB array of integers.
|
|
399
484
|
|
|
400
485
|
Returns
|
|
401
486
|
-------
|
|
402
487
|
RGB_Array_Int
|
|
403
|
-
|
|
488
|
+
RGB array of 3 integers from 0 to 255.
|
|
404
489
|
"""
|
|
405
490
|
return (self._internal_value[:3] * 255).astype(int)
|
|
406
491
|
|
|
407
492
|
def to_rgba(self) -> RGBA_Array_Float:
|
|
408
|
-
"""
|
|
493
|
+
"""Convert the current :class:`ManimColor` into an RGBA array of floats.
|
|
409
494
|
|
|
410
495
|
Returns
|
|
411
496
|
-------
|
|
412
497
|
RGBA_Array_Float
|
|
413
|
-
|
|
498
|
+
RGBA array of 4 floats from 0.0 to 1.0.
|
|
414
499
|
"""
|
|
415
500
|
return self._internal_value
|
|
416
501
|
|
|
417
502
|
def to_int_rgba(self) -> RGBA_Array_Int:
|
|
418
|
-
"""
|
|
503
|
+
"""Convert the current ManimColor into an RGBA array of integers.
|
|
419
504
|
|
|
420
505
|
|
|
421
506
|
Returns
|
|
422
507
|
-------
|
|
423
508
|
RGBA_Array_Int
|
|
424
|
-
|
|
509
|
+
RGBA array of 4 integers from 0 to 255.
|
|
425
510
|
"""
|
|
426
511
|
return (self._internal_value * 255).astype(int)
|
|
427
512
|
|
|
428
513
|
def to_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Float:
|
|
429
|
-
"""
|
|
430
|
-
value.
|
|
514
|
+
"""Convert the current :class:`ManimColor` into an RGBA array of floats. This is
|
|
515
|
+
similar to :meth:`to_rgba`, but you can change the alpha value.
|
|
431
516
|
|
|
432
517
|
Parameters
|
|
433
518
|
----------
|
|
434
|
-
alpha
|
|
435
|
-
|
|
519
|
+
alpha
|
|
520
|
+
Alpha value to be used in the return value.
|
|
436
521
|
|
|
437
522
|
Returns
|
|
438
523
|
-------
|
|
439
524
|
RGBA_Array_Float
|
|
440
|
-
|
|
525
|
+
RGBA array of 4 floats from 0.0 to 1.0.
|
|
441
526
|
"""
|
|
442
527
|
return np.fromiter((*self._internal_value[:3], alpha), dtype=ManimColorDType)
|
|
443
528
|
|
|
444
529
|
def to_int_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Int:
|
|
445
|
-
"""
|
|
446
|
-
value.
|
|
530
|
+
"""Convert the current :class:`ManimColor` into an RGBA array of integers. This
|
|
531
|
+
is similar to :meth:`to_int_rgba`, but you can change the alpha value.
|
|
447
532
|
|
|
448
533
|
Parameters
|
|
449
534
|
----------
|
|
450
|
-
alpha
|
|
451
|
-
|
|
535
|
+
alpha
|
|
536
|
+
Alpha value to be used for the return value. Pass a float between 0.0 and
|
|
537
|
+
1.0: it will automatically be scaled to an integer between 0 and 255.
|
|
452
538
|
|
|
453
539
|
Returns
|
|
454
540
|
-------
|
|
455
541
|
RGBA_Array_Int
|
|
456
|
-
|
|
542
|
+
RGBA array of 4 integers from 0 to 255.
|
|
457
543
|
"""
|
|
458
544
|
tmp = self._internal_value * 255
|
|
459
545
|
tmp[3] = alpha * 255
|
|
460
546
|
return tmp.astype(int)
|
|
461
547
|
|
|
462
548
|
def to_hex(self, with_alpha: bool = False) -> str:
|
|
463
|
-
"""
|
|
549
|
+
"""Convert the :class:`ManimColor` to a hexadecimal representation of the color.
|
|
464
550
|
|
|
465
551
|
Parameters
|
|
466
552
|
----------
|
|
467
|
-
with_alpha
|
|
468
|
-
|
|
469
|
-
|
|
553
|
+
with_alpha
|
|
554
|
+
If ``True``, append 2 extra characters to the hex string which represent the
|
|
555
|
+
alpha value of the color between 0 and 255. Default is ``False``.
|
|
470
556
|
|
|
471
557
|
Returns
|
|
472
558
|
-------
|
|
473
559
|
str
|
|
474
|
-
A hex string starting with a
|
|
560
|
+
A hex string starting with a ``#``, with either 6 or 8 nibbles depending on
|
|
561
|
+
the ``with_alpha`` parameter. By default, it has 6 nibbles, i.e. ``#XXXXXX``.
|
|
475
562
|
"""
|
|
476
563
|
tmp = (
|
|
477
564
|
f"#{int(self._internal_value[0] * 255):02X}"
|
|
@@ -483,148 +570,344 @@ class ManimColor:
|
|
|
483
570
|
return tmp
|
|
484
571
|
|
|
485
572
|
def to_hsv(self) -> HSV_Array_Float:
|
|
486
|
-
"""
|
|
573
|
+
"""Convert the :class:`ManimColor` to an HSV array.
|
|
487
574
|
|
|
488
575
|
.. note::
|
|
489
|
-
Be careful this returns an array in the form
|
|
490
|
-
This might be confusing because
|
|
491
|
-
of
|
|
492
|
-
|
|
576
|
+
Be careful: this returns an array in the form ``[h, s, v]``, where the
|
|
577
|
+
elements are floats. This might be confusing, because RGB can also be an array
|
|
578
|
+
of floats. You might want to annotate the usage of this function in your code
|
|
579
|
+
by typing your HSV array variables as :class:`HSV_Array_Float` in order to
|
|
580
|
+
differentiate them from RGB arrays.
|
|
493
581
|
|
|
494
582
|
Returns
|
|
495
583
|
-------
|
|
496
584
|
HSV_Array_Float
|
|
497
|
-
|
|
585
|
+
An HSV array of 3 floats from 0.0 to 1.0.
|
|
586
|
+
"""
|
|
587
|
+
return np.array(colorsys.rgb_to_hsv(*self.to_rgb()))
|
|
588
|
+
|
|
589
|
+
def to_hsl(self) -> HSL_Array_Float:
|
|
590
|
+
"""Convert the :class:`ManimColor` to an HSL array.
|
|
591
|
+
|
|
592
|
+
.. note::
|
|
593
|
+
Be careful: this returns an array in the form ``[h, s, l]``, where the
|
|
594
|
+
elements are floats. This might be confusing, because RGB can also be an array
|
|
595
|
+
of floats. You might want to annotate the usage of this function in your code
|
|
596
|
+
by typing your HSL array variables as :class:`HSL_Array_Float` in order to
|
|
597
|
+
differentiate them from RGB arrays.
|
|
598
|
+
|
|
599
|
+
Returns
|
|
600
|
+
-------
|
|
601
|
+
HSL_Array_Float
|
|
602
|
+
An HSL array of 3 floats from 0.0 to 1.0.
|
|
498
603
|
"""
|
|
499
|
-
return colorsys.
|
|
604
|
+
return np.array(colorsys.rgb_to_hls(*self.to_rgb()))
|
|
500
605
|
|
|
501
|
-
def invert(self, with_alpha=False) ->
|
|
502
|
-
"""
|
|
606
|
+
def invert(self, with_alpha: bool = False) -> Self:
|
|
607
|
+
"""Return a new, linearly inverted version of this :class:`ManimColor` (no
|
|
608
|
+
inplace changes).
|
|
503
609
|
|
|
504
610
|
Parameters
|
|
505
611
|
----------
|
|
506
|
-
with_alpha
|
|
507
|
-
|
|
612
|
+
with_alpha
|
|
613
|
+
If ``True``, the alpha value will be inverted too. Default is ``False``.
|
|
508
614
|
|
|
509
615
|
.. note::
|
|
510
|
-
|
|
511
|
-
|
|
616
|
+
Setting ``with_alpha=True`` can result in unintended behavior where
|
|
617
|
+
objects are not displayed because their new alpha value is suddenly 0 or
|
|
618
|
+
very low.
|
|
512
619
|
|
|
513
620
|
Returns
|
|
514
621
|
-------
|
|
515
622
|
ManimColor
|
|
516
|
-
The linearly inverted ManimColor
|
|
623
|
+
The linearly inverted :class:`ManimColor`.
|
|
517
624
|
"""
|
|
518
|
-
|
|
625
|
+
if with_alpha:
|
|
626
|
+
return self._construct_from_space(1.0 - self._internal_space)
|
|
627
|
+
else:
|
|
628
|
+
alpha = self._internal_space[3]
|
|
629
|
+
new = 1.0 - self._internal_space
|
|
630
|
+
new[-1] = alpha
|
|
631
|
+
return self._construct_from_space(new)
|
|
519
632
|
|
|
520
|
-
def interpolate(self, other:
|
|
521
|
-
"""
|
|
633
|
+
def interpolate(self, other: Self, alpha: float) -> Self:
|
|
634
|
+
"""Interpolate between the current and the given :class:`ManimColor`, and return
|
|
635
|
+
the result.
|
|
522
636
|
|
|
523
637
|
Parameters
|
|
524
638
|
----------
|
|
525
|
-
other
|
|
526
|
-
The other ManimColor to be used for interpolation
|
|
527
|
-
alpha
|
|
528
|
-
A point on the line in
|
|
529
|
-
|
|
530
|
-
0 corresponds to the
|
|
639
|
+
other
|
|
640
|
+
The other :class:`ManimColor` to be used for interpolation.
|
|
641
|
+
alpha
|
|
642
|
+
A point on the line in RGBA colorspace connecting the two colors, i.e. the
|
|
643
|
+
interpolation point. 0.0 corresponds to the current :class:`ManimColor` and
|
|
644
|
+
1.0 corresponds to the other :class:`ManimColor`.
|
|
531
645
|
|
|
532
646
|
Returns
|
|
533
647
|
-------
|
|
534
648
|
ManimColor
|
|
535
|
-
The interpolated ManimColor
|
|
649
|
+
The interpolated :class:`ManimColor`.
|
|
536
650
|
"""
|
|
537
|
-
return
|
|
538
|
-
self.
|
|
651
|
+
return self._construct_from_space(
|
|
652
|
+
self._internal_space * (1 - alpha) + other._internal_space * alpha
|
|
539
653
|
)
|
|
540
654
|
|
|
655
|
+
def darker(self, blend: float = 0.2) -> Self:
|
|
656
|
+
"""Return a new color that is darker than the current color, i.e.
|
|
657
|
+
interpolated with ``BLACK``. The opacity is unchanged.
|
|
658
|
+
|
|
659
|
+
Parameters
|
|
660
|
+
----------
|
|
661
|
+
blend
|
|
662
|
+
The blend ratio for the interpolation, from 0.0 (the current color
|
|
663
|
+
unchanged) to 1.0 (pure black). Default is 0.2, which results in a
|
|
664
|
+
slightly darker color.
|
|
665
|
+
|
|
666
|
+
Returns
|
|
667
|
+
-------
|
|
668
|
+
ManimColor
|
|
669
|
+
The darker :class:`ManimColor`.
|
|
670
|
+
|
|
671
|
+
See Also
|
|
672
|
+
--------
|
|
673
|
+
:meth:`lighter`
|
|
674
|
+
"""
|
|
675
|
+
from manim.utils.color.manim_colors import BLACK
|
|
676
|
+
|
|
677
|
+
alpha = self._internal_space[3]
|
|
678
|
+
black = self._from_internal(BLACK._internal_value)
|
|
679
|
+
return self.interpolate(black, blend).opacity(alpha)
|
|
680
|
+
|
|
681
|
+
def lighter(self, blend: float = 0.2) -> Self:
|
|
682
|
+
"""Return a new color that is lighter than the current color, i.e.
|
|
683
|
+
interpolated with ``WHITE``. The opacity is unchanged.
|
|
684
|
+
|
|
685
|
+
Parameters
|
|
686
|
+
----------
|
|
687
|
+
blend
|
|
688
|
+
The blend ratio for the interpolation, from 0.0 (the current color
|
|
689
|
+
unchanged) to 1.0 (pure white). Default is 0.2, which results in a
|
|
690
|
+
slightly lighter color.
|
|
691
|
+
|
|
692
|
+
Returns
|
|
693
|
+
-------
|
|
694
|
+
ManimColor
|
|
695
|
+
The lighter :class:`ManimColor`.
|
|
696
|
+
|
|
697
|
+
See Also
|
|
698
|
+
--------
|
|
699
|
+
:meth:`darker`
|
|
700
|
+
"""
|
|
701
|
+
from manim.utils.color.manim_colors import WHITE
|
|
702
|
+
|
|
703
|
+
alpha = self._internal_space[3]
|
|
704
|
+
white = self._from_internal(WHITE._internal_value)
|
|
705
|
+
return self.interpolate(white, blend).opacity(alpha)
|
|
706
|
+
|
|
707
|
+
def contrasting(
|
|
708
|
+
self,
|
|
709
|
+
threshold: float = 0.5,
|
|
710
|
+
light: Self | None = None,
|
|
711
|
+
dark: Self | None = None,
|
|
712
|
+
) -> Self:
|
|
713
|
+
"""Return one of two colors, light or dark (by default white or black),
|
|
714
|
+
that contrasts with the current color (depending on its luminance).
|
|
715
|
+
This is typically used to set text in a contrasting color that ensures
|
|
716
|
+
it is readable against a background of the current color.
|
|
717
|
+
|
|
718
|
+
Parameters
|
|
719
|
+
----------
|
|
720
|
+
threshold
|
|
721
|
+
The luminance threshold which dictates whether the current color is
|
|
722
|
+
considered light or dark (and thus whether to return the dark or
|
|
723
|
+
light color, respectively). Default is 0.5.
|
|
724
|
+
light
|
|
725
|
+
The light color to return if the current color is considered dark.
|
|
726
|
+
Default is ``None``: in this case, pure ``WHITE`` will be returned.
|
|
727
|
+
dark
|
|
728
|
+
The dark color to return if the current color is considered light,
|
|
729
|
+
Default is ``None``: in this case, pure ``BLACK`` will be returned.
|
|
730
|
+
|
|
731
|
+
Returns
|
|
732
|
+
-------
|
|
733
|
+
ManimColor
|
|
734
|
+
The contrasting :class:`ManimColor`.
|
|
735
|
+
"""
|
|
736
|
+
from manim.utils.color.manim_colors import BLACK, WHITE
|
|
737
|
+
|
|
738
|
+
luminance, _, _ = colorsys.rgb_to_yiq(*self.to_rgb())
|
|
739
|
+
if luminance < threshold:
|
|
740
|
+
if light is not None:
|
|
741
|
+
return light
|
|
742
|
+
return self._from_internal(WHITE._internal_value)
|
|
743
|
+
else:
|
|
744
|
+
if dark is not None:
|
|
745
|
+
return dark
|
|
746
|
+
return self._from_internal(BLACK._internal_value)
|
|
747
|
+
|
|
748
|
+
def opacity(self, opacity: float) -> Self:
|
|
749
|
+
"""Create a new :class:`ManimColor` with the given opacity and the same color
|
|
750
|
+
values as before.
|
|
751
|
+
|
|
752
|
+
Parameters
|
|
753
|
+
----------
|
|
754
|
+
opacity
|
|
755
|
+
The new opacity value to be used.
|
|
756
|
+
|
|
757
|
+
Returns
|
|
758
|
+
-------
|
|
759
|
+
ManimColor
|
|
760
|
+
The new :class:`ManimColor` with the same color values and the new opacity.
|
|
761
|
+
"""
|
|
762
|
+
tmp = self._internal_space.copy()
|
|
763
|
+
tmp[-1] = opacity
|
|
764
|
+
return self._construct_from_space(tmp)
|
|
765
|
+
|
|
766
|
+
def into(self, class_type: type[ManimColorT]) -> ManimColorT:
|
|
767
|
+
"""Convert the current color into a different colorspace given by ``class_type``,
|
|
768
|
+
without changing the :attr:`_internal_value`.
|
|
769
|
+
|
|
770
|
+
Parameters
|
|
771
|
+
----------
|
|
772
|
+
class_type
|
|
773
|
+
The class that is used for conversion. It must be a subclass of
|
|
774
|
+
:class:`ManimColor` which respects the specification HSV, RGBA, ...
|
|
775
|
+
|
|
776
|
+
Returns
|
|
777
|
+
-------
|
|
778
|
+
ManimColorT
|
|
779
|
+
A new color object of type ``class_type`` and the same
|
|
780
|
+
:attr:`_internal_value` as the original color.
|
|
781
|
+
"""
|
|
782
|
+
return class_type._from_internal(self._internal_value)
|
|
783
|
+
|
|
784
|
+
@classmethod
|
|
785
|
+
def _from_internal(cls, value: ManimColorInternal) -> Self:
|
|
786
|
+
"""This method is intended to be overwritten by custom color space classes
|
|
787
|
+
which are subtypes of :class:`ManimColor`.
|
|
788
|
+
|
|
789
|
+
The method constructs a new object of the given class by transforming the value
|
|
790
|
+
in the internal format ``[r,g,b,a]`` into a format which the constructor of the
|
|
791
|
+
custom class can understand. Look at :class:`.HSV` for an example.
|
|
792
|
+
"""
|
|
793
|
+
return cls(value)
|
|
794
|
+
|
|
541
795
|
@classmethod
|
|
542
796
|
def from_rgb(
|
|
543
797
|
cls,
|
|
544
798
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
545
799
|
alpha: float = 1.0,
|
|
546
800
|
) -> Self:
|
|
547
|
-
"""
|
|
801
|
+
"""Create a ManimColor from an RGB array. Automagically decides which type it
|
|
802
|
+
is: ``int`` or ``float``.
|
|
548
803
|
|
|
549
804
|
.. warning::
|
|
550
|
-
Please make sure that your elements are not floats if you want integers. A
|
|
551
|
-
being interpreted as if it was
|
|
805
|
+
Please make sure that your elements are not floats if you want integers. A
|
|
806
|
+
``5.0`` will result in the input being interpreted as if it was an RGB float
|
|
807
|
+
array with the value ``5.0`` and not the integer ``5``.
|
|
552
808
|
|
|
553
809
|
|
|
554
810
|
Parameters
|
|
555
811
|
----------
|
|
556
|
-
rgb
|
|
557
|
-
Any 3
|
|
558
|
-
alpha
|
|
559
|
-
|
|
812
|
+
rgb
|
|
813
|
+
Any iterable of 3 floats or 3 integers.
|
|
814
|
+
alpha
|
|
815
|
+
Alpha value to be used in the color. Default is 1.0.
|
|
560
816
|
|
|
561
817
|
Returns
|
|
562
818
|
-------
|
|
563
819
|
ManimColor
|
|
564
|
-
|
|
820
|
+
The :class:`ManimColor` which corresponds to the given ``rgb``.
|
|
565
821
|
"""
|
|
566
|
-
return cls(rgb, alpha)
|
|
822
|
+
return cls._from_internal(ManimColor(rgb, alpha)._internal_value)
|
|
567
823
|
|
|
568
824
|
@classmethod
|
|
569
825
|
def from_rgba(
|
|
570
826
|
cls, rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int
|
|
571
827
|
) -> Self:
|
|
572
|
-
"""
|
|
828
|
+
"""Create a ManimColor from an RGBA Array. Automagically decides which type it
|
|
829
|
+
is: ``int`` or ``float``.
|
|
573
830
|
|
|
574
831
|
.. warning::
|
|
575
|
-
Please make sure that your elements are not floats if you want integers. A
|
|
576
|
-
being interpreted as if it was a float
|
|
832
|
+
Please make sure that your elements are not floats if you want integers. A
|
|
833
|
+
``5.0`` will result in the input being interpreted as if it was a float RGB
|
|
834
|
+
array with the float ``5.0`` and not the integer ``5``.
|
|
577
835
|
|
|
578
836
|
Parameters
|
|
579
837
|
----------
|
|
580
|
-
rgba
|
|
581
|
-
Any 4
|
|
838
|
+
rgba
|
|
839
|
+
Any iterable of 4 floats or 4 integers.
|
|
582
840
|
|
|
583
841
|
Returns
|
|
584
842
|
-------
|
|
585
843
|
ManimColor
|
|
586
|
-
|
|
844
|
+
The :class:`ManimColor` corresponding to the given ``rgba``.
|
|
587
845
|
"""
|
|
588
846
|
return cls(rgba)
|
|
589
847
|
|
|
590
848
|
@classmethod
|
|
591
|
-
def from_hex(cls,
|
|
592
|
-
"""
|
|
849
|
+
def from_hex(cls, hex_str: str, alpha: float = 1.0) -> Self:
|
|
850
|
+
"""Create a :class:`ManimColor` from a hex string.
|
|
593
851
|
|
|
594
852
|
Parameters
|
|
595
853
|
----------
|
|
596
|
-
|
|
597
|
-
The hex string to be converted
|
|
598
|
-
|
|
599
|
-
|
|
854
|
+
hex_str
|
|
855
|
+
The hex string to be converted. The allowed prefixes for this string are
|
|
856
|
+
``#`` and ``0x``. Currently, this method only supports 6 nibbles, i.e. only
|
|
857
|
+
strings in the format ``#XXXXXX`` or ``0xXXXXXX``.
|
|
858
|
+
alpha
|
|
859
|
+
Alpha value to be used for the hex string. Default is 1.0.
|
|
600
860
|
|
|
601
861
|
Returns
|
|
602
862
|
-------
|
|
603
863
|
ManimColor
|
|
604
|
-
The ManimColor represented by the hex string
|
|
864
|
+
The :class:`ManimColor` represented by the hex string.
|
|
605
865
|
"""
|
|
606
|
-
return cls(
|
|
866
|
+
return cls._from_internal(ManimColor(hex_str, alpha)._internal_value)
|
|
607
867
|
|
|
608
868
|
@classmethod
|
|
609
869
|
def from_hsv(
|
|
610
870
|
cls, hsv: HSV_Array_Float | HSV_Tuple_Float, alpha: float = 1.0
|
|
611
871
|
) -> Self:
|
|
612
|
-
"""
|
|
872
|
+
"""Create a :class:`ManimColor` from an HSV array.
|
|
613
873
|
|
|
614
874
|
Parameters
|
|
615
875
|
----------
|
|
616
|
-
hsv
|
|
617
|
-
Any
|
|
618
|
-
alpha
|
|
619
|
-
|
|
876
|
+
hsv
|
|
877
|
+
Any iterable containing 3 floats from 0.0 to 1.0.
|
|
878
|
+
alpha
|
|
879
|
+
The alpha value to be used. Default is 1.0.
|
|
620
880
|
|
|
621
881
|
Returns
|
|
622
882
|
-------
|
|
623
883
|
ManimColor
|
|
624
|
-
The ManimColor with the corresponding RGB values to the HSV
|
|
884
|
+
The :class:`ManimColor` with the corresponding RGB values to the given HSV
|
|
885
|
+
array.
|
|
625
886
|
"""
|
|
626
887
|
rgb = colorsys.hsv_to_rgb(*hsv)
|
|
627
|
-
return cls(rgb, alpha)
|
|
888
|
+
return cls._from_internal(ManimColor(rgb, alpha)._internal_value)
|
|
889
|
+
|
|
890
|
+
@classmethod
|
|
891
|
+
def from_hsl(
|
|
892
|
+
cls, hsl: HSL_Array_Float | HSL_Tuple_Float, alpha: float = 1.0
|
|
893
|
+
) -> Self:
|
|
894
|
+
"""Create a :class:`ManimColor` from an HSL array.
|
|
895
|
+
|
|
896
|
+
Parameters
|
|
897
|
+
----------
|
|
898
|
+
hsl
|
|
899
|
+
Any iterable containing 3 floats from 0.0 to 1.0.
|
|
900
|
+
alpha
|
|
901
|
+
The alpha value to be used. Default is 1.0.
|
|
902
|
+
|
|
903
|
+
Returns
|
|
904
|
+
-------
|
|
905
|
+
ManimColor
|
|
906
|
+
The :class:`ManimColor` with the corresponding RGB values to the given HSL
|
|
907
|
+
array.
|
|
908
|
+
"""
|
|
909
|
+
rgb = colorsys.hls_to_rgb(*hsl)
|
|
910
|
+
return cls._from_internal(ManimColor(rgb, alpha)._internal_value)
|
|
628
911
|
|
|
629
912
|
@overload
|
|
630
913
|
@classmethod
|
|
@@ -645,31 +928,46 @@ class ManimColor:
|
|
|
645
928
|
@classmethod
|
|
646
929
|
def parse(
|
|
647
930
|
cls,
|
|
648
|
-
color: ParsableManimColor |
|
|
931
|
+
color: ParsableManimColor | Sequence[ParsableManimColor] | None,
|
|
649
932
|
alpha: float = 1.0,
|
|
650
933
|
) -> Self | list[Self]:
|
|
651
|
-
"""
|
|
652
|
-
|
|
934
|
+
"""Parse one color as a :class:`ManimColor` or a sequence of colors as a list of
|
|
935
|
+
:class:`ManimColor`'s.
|
|
653
936
|
|
|
654
937
|
Parameters
|
|
655
938
|
----------
|
|
656
939
|
color
|
|
657
|
-
The color or list of colors to parse. Note that this function can not accept
|
|
940
|
+
The color or list of colors to parse. Note that this function can not accept
|
|
941
|
+
tuples: it will assume that you mean ``Sequence[ParsableManimColor]`` and will
|
|
942
|
+
return a ``list[ManimColor]``.
|
|
658
943
|
alpha
|
|
659
|
-
The alpha value to use
|
|
944
|
+
The alpha (opacity) value to use for the passed color(s).
|
|
660
945
|
|
|
661
946
|
Returns
|
|
662
947
|
-------
|
|
663
|
-
ManimColor
|
|
664
|
-
Either a list of colors or a singular color depending on the input
|
|
948
|
+
ManimColor | list[ManimColor]
|
|
949
|
+
Either a list of colors or a singular color, depending on the input.
|
|
665
950
|
"""
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
951
|
+
|
|
952
|
+
def is_sequence(
|
|
953
|
+
color: ParsableManimColor | Sequence[ParsableManimColor] | None,
|
|
954
|
+
) -> TypeIs[Sequence[ParsableManimColor]]:
|
|
955
|
+
return isinstance(color, (list, tuple))
|
|
956
|
+
|
|
957
|
+
if is_sequence(color):
|
|
958
|
+
return [
|
|
959
|
+
cls._from_internal(ManimColor(c, alpha)._internal_value) for c in color
|
|
960
|
+
]
|
|
961
|
+
else:
|
|
962
|
+
return cls._from_internal(ManimColor(color, alpha)._internal_value)
|
|
669
963
|
|
|
670
964
|
@staticmethod
|
|
671
|
-
def gradient(
|
|
672
|
-
|
|
965
|
+
def gradient(
|
|
966
|
+
colors: list[ManimColor], length: int
|
|
967
|
+
) -> ManimColor | list[ManimColor]:
|
|
968
|
+
"""This method is currently not implemented. Refer to :func:`color_gradient` for
|
|
969
|
+
a working implementation for now.
|
|
970
|
+
"""
|
|
673
971
|
# TODO: implement proper gradient, research good implementation for this or look at 3b1b implementation
|
|
674
972
|
raise NotImplementedError
|
|
675
973
|
|
|
@@ -684,37 +982,240 @@ class ManimColor:
|
|
|
684
982
|
raise TypeError(
|
|
685
983
|
f"Cannot compare {self.__class__.__name__} with {other.__class__.__name__}"
|
|
686
984
|
)
|
|
687
|
-
|
|
985
|
+
are_equal: bool = np.allclose(self._internal_value, other._internal_value)
|
|
986
|
+
return are_equal
|
|
987
|
+
|
|
988
|
+
def __add__(self, other: int | float | Self) -> Self:
|
|
989
|
+
if isinstance(other, (int, float)):
|
|
990
|
+
return self._construct_from_space(self._internal_space + other)
|
|
991
|
+
else:
|
|
992
|
+
return self._construct_from_space(
|
|
993
|
+
self._internal_space + other._internal_space
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
def __radd__(self, other: int | float | Self) -> Self:
|
|
997
|
+
return self + other
|
|
998
|
+
|
|
999
|
+
def __sub__(self, other: int | float | Self) -> Self:
|
|
1000
|
+
if isinstance(other, (int, float)):
|
|
1001
|
+
return self._construct_from_space(self._internal_space - other)
|
|
1002
|
+
else:
|
|
1003
|
+
return self._construct_from_space(
|
|
1004
|
+
self._internal_space - other._internal_space
|
|
1005
|
+
)
|
|
1006
|
+
|
|
1007
|
+
def __rsub__(self, other: int | float | Self) -> Self:
|
|
1008
|
+
return self - other
|
|
1009
|
+
|
|
1010
|
+
def __mul__(self, other: int | float | Self) -> Self:
|
|
1011
|
+
if isinstance(other, (int, float)):
|
|
1012
|
+
return self._construct_from_space(self._internal_space * other)
|
|
1013
|
+
else:
|
|
1014
|
+
return self._construct_from_space(
|
|
1015
|
+
self._internal_space * other._internal_space
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
def __rmul__(self, other: int | float | Self) -> Self:
|
|
1019
|
+
return self * other
|
|
1020
|
+
|
|
1021
|
+
def __truediv__(self, other: int | float | Self) -> Self:
|
|
1022
|
+
if isinstance(other, (int, float)):
|
|
1023
|
+
return self._construct_from_space(self._internal_space / other)
|
|
1024
|
+
else:
|
|
1025
|
+
return self._construct_from_space(
|
|
1026
|
+
self._internal_space / other._internal_space
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
def __rtruediv__(self, other: int | float | Self) -> Self:
|
|
1030
|
+
return self / other
|
|
1031
|
+
|
|
1032
|
+
def __floordiv__(self, other: int | float | Self) -> Self:
|
|
1033
|
+
if isinstance(other, (int, float)):
|
|
1034
|
+
return self._construct_from_space(self._internal_space // other)
|
|
1035
|
+
else:
|
|
1036
|
+
return self._construct_from_space(
|
|
1037
|
+
self._internal_space // other._internal_space
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
def __rfloordiv__(self, other: int | float | Self) -> Self:
|
|
1041
|
+
return self // other
|
|
1042
|
+
|
|
1043
|
+
def __mod__(self, other: int | float | Self) -> Self:
|
|
1044
|
+
if isinstance(other, (int, float)):
|
|
1045
|
+
return self._construct_from_space(self._internal_space % other)
|
|
1046
|
+
else:
|
|
1047
|
+
return self._construct_from_space(
|
|
1048
|
+
self._internal_space % other._internal_space
|
|
1049
|
+
)
|
|
1050
|
+
|
|
1051
|
+
def __rmod__(self, other: int | float | Self) -> Self:
|
|
1052
|
+
return self % other
|
|
1053
|
+
|
|
1054
|
+
def __pow__(self, other: int | float | Self) -> Self:
|
|
1055
|
+
if isinstance(other, (int, float)):
|
|
1056
|
+
return self._construct_from_space(self._internal_space**other)
|
|
1057
|
+
else:
|
|
1058
|
+
return self._construct_from_space(
|
|
1059
|
+
self._internal_space**other._internal_space
|
|
1060
|
+
)
|
|
1061
|
+
|
|
1062
|
+
def __rpow__(self, other: int | float | Self) -> Self:
|
|
1063
|
+
return self**other
|
|
1064
|
+
|
|
1065
|
+
def __invert__(self) -> Self:
|
|
1066
|
+
return self.invert()
|
|
1067
|
+
|
|
1068
|
+
def __int__(self) -> int:
|
|
1069
|
+
return self.to_integer()
|
|
1070
|
+
|
|
1071
|
+
def __getitem__(self, index: int) -> float:
|
|
1072
|
+
item: float = self._internal_space[index]
|
|
1073
|
+
return item
|
|
1074
|
+
|
|
1075
|
+
def __and__(self, other: Self) -> Self:
|
|
1076
|
+
return self._construct_from_space(
|
|
1077
|
+
self._internal_from_integer(self.to_integer() & int(other), 1.0)
|
|
1078
|
+
)
|
|
688
1079
|
|
|
689
|
-
def
|
|
690
|
-
return
|
|
1080
|
+
def __or__(self, other: Self) -> Self:
|
|
1081
|
+
return self._construct_from_space(
|
|
1082
|
+
self._internal_from_integer(self.to_integer() | int(other), 1.0)
|
|
1083
|
+
)
|
|
691
1084
|
|
|
692
|
-
def
|
|
693
|
-
return
|
|
1085
|
+
def __xor__(self, other: Self) -> Self:
|
|
1086
|
+
return self._construct_from_space(
|
|
1087
|
+
self._internal_from_integer(self.to_integer() ^ int(other), 1.0)
|
|
1088
|
+
)
|
|
694
1089
|
|
|
695
|
-
def
|
|
696
|
-
return
|
|
1090
|
+
def __hash__(self) -> int:
|
|
1091
|
+
return hash(self.to_hex(with_alpha=True))
|
|
697
1092
|
|
|
698
|
-
def __truediv__(self, other: ManimColor) -> ManimColor:
|
|
699
|
-
return ManimColor(self._internal_value / other._internal_value)
|
|
700
1093
|
|
|
701
|
-
|
|
702
|
-
|
|
1094
|
+
RGBA = ManimColor
|
|
1095
|
+
"""RGBA Color Space"""
|
|
703
1096
|
|
|
704
|
-
def __mod__(self, other: ManimColor) -> ManimColor:
|
|
705
|
-
return ManimColor(self._internal_value % other._internal_value)
|
|
706
1097
|
|
|
707
|
-
|
|
708
|
-
|
|
1098
|
+
class HSV(ManimColor):
|
|
1099
|
+
"""HSV Color Space"""
|
|
709
1100
|
|
|
710
|
-
def
|
|
711
|
-
|
|
1101
|
+
def __init__(
|
|
1102
|
+
self,
|
|
1103
|
+
hsv: HSV_Array_Float | HSV_Tuple_Float | HSVA_Array_Float | HSVA_Tuple_Float,
|
|
1104
|
+
alpha: float = 1.0,
|
|
1105
|
+
) -> None:
|
|
1106
|
+
super().__init__(None)
|
|
1107
|
+
self.__hsv: HSVA_Array_Float
|
|
1108
|
+
if len(hsv) == 3:
|
|
1109
|
+
self.__hsv = np.asarray((*hsv, alpha))
|
|
1110
|
+
elif len(hsv) == 4:
|
|
1111
|
+
self.__hsv = np.asarray(hsv)
|
|
1112
|
+
else:
|
|
1113
|
+
raise ValueError("HSV Color must be an array of 3 values")
|
|
712
1114
|
|
|
713
|
-
|
|
714
|
-
|
|
1115
|
+
@classmethod
|
|
1116
|
+
@override
|
|
1117
|
+
def _from_internal(cls, value: ManimColorInternal) -> Self:
|
|
1118
|
+
hsv = colorsys.rgb_to_hsv(*value[:3])
|
|
1119
|
+
hsva = [*hsv, value[-1]]
|
|
1120
|
+
return cls(np.array(hsva))
|
|
715
1121
|
|
|
716
|
-
|
|
717
|
-
|
|
1122
|
+
@property
|
|
1123
|
+
def hue(self) -> float:
|
|
1124
|
+
hue: float = self.__hsv[0]
|
|
1125
|
+
return hue
|
|
1126
|
+
|
|
1127
|
+
@hue.setter
|
|
1128
|
+
def hue(self, hue: float) -> None:
|
|
1129
|
+
self.__hsv[0] = hue
|
|
1130
|
+
|
|
1131
|
+
@property
|
|
1132
|
+
def saturation(self) -> float:
|
|
1133
|
+
saturation: float = self.__hsv[1]
|
|
1134
|
+
return saturation
|
|
1135
|
+
|
|
1136
|
+
@saturation.setter
|
|
1137
|
+
def saturation(self, saturation: float) -> None:
|
|
1138
|
+
self.__hsv[1] = saturation
|
|
1139
|
+
|
|
1140
|
+
@property
|
|
1141
|
+
def value(self) -> float:
|
|
1142
|
+
value: float = self.__hsv[2]
|
|
1143
|
+
return value
|
|
1144
|
+
|
|
1145
|
+
@value.setter
|
|
1146
|
+
def value(self, value: float) -> None:
|
|
1147
|
+
self.__hsv[2] = value
|
|
1148
|
+
|
|
1149
|
+
@property
|
|
1150
|
+
def h(self) -> float:
|
|
1151
|
+
hue: float = self.__hsv[0]
|
|
1152
|
+
return hue
|
|
1153
|
+
|
|
1154
|
+
@h.setter
|
|
1155
|
+
def h(self, hue: float) -> None:
|
|
1156
|
+
self.__hsv[0] = hue
|
|
1157
|
+
|
|
1158
|
+
@property
|
|
1159
|
+
def s(self) -> float:
|
|
1160
|
+
saturation: float = self.__hsv[1]
|
|
1161
|
+
return saturation
|
|
1162
|
+
|
|
1163
|
+
@s.setter
|
|
1164
|
+
def s(self, saturation: float) -> None:
|
|
1165
|
+
self.__hsv[1] = saturation
|
|
1166
|
+
|
|
1167
|
+
@property
|
|
1168
|
+
def v(self) -> float:
|
|
1169
|
+
value: float = self.__hsv[2]
|
|
1170
|
+
return value
|
|
1171
|
+
|
|
1172
|
+
@v.setter
|
|
1173
|
+
def v(self, value: float) -> None:
|
|
1174
|
+
self.__hsv[2] = value
|
|
1175
|
+
|
|
1176
|
+
@property
|
|
1177
|
+
def _internal_space(self) -> npt.NDArray:
|
|
1178
|
+
return self.__hsv
|
|
1179
|
+
|
|
1180
|
+
@property
|
|
1181
|
+
def _internal_value(self) -> ManimColorInternal:
|
|
1182
|
+
"""Return the internal value of the current :class:`ManimColor` as an
|
|
1183
|
+
``[r,g,b,a]`` float array.
|
|
1184
|
+
|
|
1185
|
+
Returns
|
|
1186
|
+
-------
|
|
1187
|
+
ManimColorInternal
|
|
1188
|
+
Internal color representation.
|
|
1189
|
+
"""
|
|
1190
|
+
return np.array(
|
|
1191
|
+
[
|
|
1192
|
+
*colorsys.hsv_to_rgb(self.__hsv[0], self.__hsv[1], self.__hsv[2]),
|
|
1193
|
+
self.__alpha,
|
|
1194
|
+
],
|
|
1195
|
+
dtype=ManimColorDType,
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
@_internal_value.setter
|
|
1199
|
+
def _internal_value(self, value: ManimColorInternal) -> None:
|
|
1200
|
+
"""Overwrite the internal color value of this :class:`ManimColor`.
|
|
1201
|
+
|
|
1202
|
+
Parameters
|
|
1203
|
+
----------
|
|
1204
|
+
value
|
|
1205
|
+
The value which will overwrite the current color.
|
|
1206
|
+
|
|
1207
|
+
Raises
|
|
1208
|
+
------
|
|
1209
|
+
TypeError
|
|
1210
|
+
If an invalid array is passed.
|
|
1211
|
+
"""
|
|
1212
|
+
if not isinstance(value, np.ndarray):
|
|
1213
|
+
raise TypeError("Value must be a NumPy array.")
|
|
1214
|
+
if value.shape[0] != 4:
|
|
1215
|
+
raise TypeError("Array must have exactly 4 values.")
|
|
1216
|
+
tmp = colorsys.rgb_to_hsv(value[0], value[1], value[2])
|
|
1217
|
+
self.__hsv = np.array(tmp)
|
|
1218
|
+
self.__alpha = value[3]
|
|
718
1219
|
|
|
719
1220
|
|
|
720
1221
|
ParsableManimColor: TypeAlias = Union[
|
|
@@ -731,7 +1232,7 @@ ParsableManimColor: TypeAlias = Union[
|
|
|
731
1232
|
RGBA_Array_Float,
|
|
732
1233
|
]
|
|
733
1234
|
"""`ParsableManimColor` represents all the types which can be parsed
|
|
734
|
-
to a
|
|
1235
|
+
to a :class:`ManimColor` in Manim.
|
|
735
1236
|
"""
|
|
736
1237
|
|
|
737
1238
|
|
|
@@ -740,69 +1241,74 @@ ManimColorT = TypeVar("ManimColorT", bound=ManimColor)
|
|
|
740
1241
|
|
|
741
1242
|
def color_to_rgb(color: ParsableManimColor) -> RGB_Array_Float:
|
|
742
1243
|
"""Helper function for use in functional style programming.
|
|
743
|
-
Refer to :meth:`to_rgb
|
|
1244
|
+
Refer to :meth:`ManimColor.to_rgb`.
|
|
744
1245
|
|
|
745
1246
|
Parameters
|
|
746
1247
|
----------
|
|
747
|
-
color
|
|
748
|
-
A color
|
|
1248
|
+
color
|
|
1249
|
+
A color to convert to an RGB float array.
|
|
749
1250
|
|
|
750
1251
|
Returns
|
|
751
1252
|
-------
|
|
752
1253
|
RGB_Array_Float
|
|
753
|
-
|
|
1254
|
+
The corresponding RGB float array.
|
|
754
1255
|
"""
|
|
755
1256
|
return ManimColor(color).to_rgb()
|
|
756
1257
|
|
|
757
1258
|
|
|
758
|
-
def color_to_rgba(color: ParsableManimColor, alpha: float = 1) -> RGBA_Array_Float:
|
|
759
|
-
"""Helper function for use in functional style programming
|
|
1259
|
+
def color_to_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Array_Float:
|
|
1260
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1261
|
+
:meth:`ManimColor.to_rgba_with_alpha`.
|
|
760
1262
|
|
|
761
1263
|
Parameters
|
|
762
1264
|
----------
|
|
763
|
-
color
|
|
764
|
-
A color
|
|
765
|
-
alpha
|
|
766
|
-
alpha value to be used in the color
|
|
1265
|
+
color
|
|
1266
|
+
A color to convert to an RGBA float array.
|
|
1267
|
+
alpha
|
|
1268
|
+
An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is
|
|
1269
|
+
1.0.
|
|
767
1270
|
|
|
768
1271
|
Returns
|
|
769
1272
|
-------
|
|
770
1273
|
RGBA_Array_Float
|
|
771
|
-
|
|
1274
|
+
The corresponding RGBA float array.
|
|
772
1275
|
"""
|
|
773
1276
|
return ManimColor(color).to_rgba_with_alpha(alpha)
|
|
774
1277
|
|
|
775
1278
|
|
|
776
1279
|
def color_to_int_rgb(color: ParsableManimColor) -> RGB_Array_Int:
|
|
777
|
-
"""Helper function for use in functional style programming
|
|
1280
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1281
|
+
:meth:`ManimColor.to_int_rgb`.
|
|
778
1282
|
|
|
779
1283
|
Parameters
|
|
780
1284
|
----------
|
|
781
|
-
color
|
|
782
|
-
A color
|
|
1285
|
+
color
|
|
1286
|
+
A color to convert to an RGB integer array.
|
|
783
1287
|
|
|
784
1288
|
Returns
|
|
785
1289
|
-------
|
|
786
1290
|
RGB_Array_Int
|
|
787
|
-
|
|
1291
|
+
The corresponding RGB integer array.
|
|
788
1292
|
"""
|
|
789
1293
|
return ManimColor(color).to_int_rgb()
|
|
790
1294
|
|
|
791
1295
|
|
|
792
1296
|
def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Array_Int:
|
|
793
|
-
"""Helper function for use in functional style programming
|
|
1297
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1298
|
+
:meth:`ManimColor.to_int_rgba_with_alpha`.
|
|
794
1299
|
|
|
795
1300
|
Parameters
|
|
796
1301
|
----------
|
|
797
|
-
color
|
|
798
|
-
A color
|
|
799
|
-
alpha
|
|
800
|
-
alpha value to be used in the color
|
|
1302
|
+
color
|
|
1303
|
+
A color to convert to an RGBA integer array.
|
|
1304
|
+
alpha
|
|
1305
|
+
An alpha value between 0.0 and 1.0 to be used as opacity in the color. Default is
|
|
1306
|
+
1.0.
|
|
801
1307
|
|
|
802
1308
|
Returns
|
|
803
1309
|
-------
|
|
804
1310
|
RGBA_Array_Int
|
|
805
|
-
|
|
1311
|
+
The corresponding RGBA integer array.
|
|
806
1312
|
"""
|
|
807
1313
|
return ManimColor(color).to_int_rgba_with_alpha(alpha)
|
|
808
1314
|
|
|
@@ -810,17 +1316,18 @@ def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Arr
|
|
|
810
1316
|
def rgb_to_color(
|
|
811
1317
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
812
1318
|
) -> ManimColor:
|
|
813
|
-
"""Helper function for use in functional style programming
|
|
1319
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1320
|
+
:meth:`ManimColor.from_rgb`.
|
|
814
1321
|
|
|
815
1322
|
Parameters
|
|
816
1323
|
----------
|
|
817
|
-
rgb
|
|
818
|
-
A 3 element iterable
|
|
1324
|
+
rgb
|
|
1325
|
+
A 3 element iterable.
|
|
819
1326
|
|
|
820
1327
|
Returns
|
|
821
1328
|
-------
|
|
822
1329
|
ManimColor
|
|
823
|
-
A ManimColor with the corresponding value
|
|
1330
|
+
A ManimColor with the corresponding value.
|
|
824
1331
|
"""
|
|
825
1332
|
return ManimColor.from_rgb(rgb)
|
|
826
1333
|
|
|
@@ -828,12 +1335,13 @@ def rgb_to_color(
|
|
|
828
1335
|
def rgba_to_color(
|
|
829
1336
|
rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int,
|
|
830
1337
|
) -> ManimColor:
|
|
831
|
-
"""Helper function for use in functional style programming
|
|
1338
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1339
|
+
:meth:`ManimColor.from_rgba`.
|
|
832
1340
|
|
|
833
1341
|
Parameters
|
|
834
1342
|
----------
|
|
835
|
-
rgba
|
|
836
|
-
A 4 element iterable
|
|
1343
|
+
rgba
|
|
1344
|
+
A 4 element iterable.
|
|
837
1345
|
|
|
838
1346
|
Returns
|
|
839
1347
|
-------
|
|
@@ -846,92 +1354,74 @@ def rgba_to_color(
|
|
|
846
1354
|
def rgb_to_hex(
|
|
847
1355
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
848
1356
|
) -> str:
|
|
849
|
-
"""Helper function for use in functional style programming
|
|
1357
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1358
|
+
:meth:`ManimColor.from_rgb` and :meth:`ManimColor.to_hex`.
|
|
850
1359
|
|
|
851
1360
|
Parameters
|
|
852
1361
|
----------
|
|
853
|
-
rgb
|
|
854
|
-
A 3 element iterable
|
|
1362
|
+
rgb
|
|
1363
|
+
A 3 element iterable.
|
|
855
1364
|
|
|
856
1365
|
Returns
|
|
857
1366
|
-------
|
|
858
1367
|
str
|
|
859
|
-
A hex representation of the color
|
|
1368
|
+
A hex representation of the color.
|
|
860
1369
|
"""
|
|
861
1370
|
return ManimColor.from_rgb(rgb).to_hex()
|
|
862
1371
|
|
|
863
1372
|
|
|
864
1373
|
def hex_to_rgb(hex_code: str) -> RGB_Array_Float:
|
|
865
|
-
"""Helper function for use in functional style programming
|
|
1374
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1375
|
+
:meth:`ManimColor.to_rgb`.
|
|
866
1376
|
|
|
867
1377
|
Parameters
|
|
868
1378
|
----------
|
|
869
|
-
hex_code
|
|
870
|
-
A hex string representing a color
|
|
1379
|
+
hex_code
|
|
1380
|
+
A hex string representing a color.
|
|
871
1381
|
|
|
872
1382
|
Returns
|
|
873
1383
|
-------
|
|
874
1384
|
RGB_Array_Float
|
|
875
|
-
RGB array representing the color
|
|
1385
|
+
An RGB array representing the color.
|
|
876
1386
|
"""
|
|
877
1387
|
return ManimColor(hex_code).to_rgb()
|
|
878
1388
|
|
|
879
1389
|
|
|
880
1390
|
def invert_color(color: ManimColorT) -> ManimColorT:
|
|
881
|
-
"""Helper function for use in functional style programming
|
|
1391
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1392
|
+
:meth:`ManimColor.invert`
|
|
882
1393
|
|
|
883
1394
|
Parameters
|
|
884
1395
|
----------
|
|
885
|
-
color
|
|
886
|
-
|
|
1396
|
+
color
|
|
1397
|
+
The :class:`ManimColor` to invert.
|
|
887
1398
|
|
|
888
1399
|
Returns
|
|
889
1400
|
-------
|
|
890
1401
|
ManimColor
|
|
891
|
-
The linearly inverted ManimColor
|
|
1402
|
+
The linearly inverted :class:`ManimColor`.
|
|
892
1403
|
"""
|
|
893
1404
|
return color.invert()
|
|
894
1405
|
|
|
895
1406
|
|
|
896
|
-
def interpolate_arrays(
|
|
897
|
-
arr1: npt.NDArray[Any], arr2: npt.NDArray[Any], alpha: float
|
|
898
|
-
) -> np.ndarray:
|
|
899
|
-
"""Helper function used in Manim to fade between two objects smoothly
|
|
900
|
-
|
|
901
|
-
Parameters
|
|
902
|
-
----------
|
|
903
|
-
arr1 : npt.NDArray[Any]
|
|
904
|
-
The first array of colors
|
|
905
|
-
arr2 : npt.NDArray[Any]
|
|
906
|
-
The second array of colors
|
|
907
|
-
alpha : float
|
|
908
|
-
The alpha value corresponding to the interpolation point between the two inputs
|
|
909
|
-
|
|
910
|
-
Returns
|
|
911
|
-
-------
|
|
912
|
-
np.ndarray
|
|
913
|
-
The interpolated value of the to arrays
|
|
914
|
-
"""
|
|
915
|
-
return (1 - alpha) * arr1 + alpha * arr2
|
|
916
|
-
|
|
917
|
-
|
|
918
1407
|
def color_gradient(
|
|
919
1408
|
reference_colors: Sequence[ParsableManimColor],
|
|
920
1409
|
length_of_output: int,
|
|
921
1410
|
) -> list[ManimColor] | ManimColor:
|
|
922
|
-
"""
|
|
1411
|
+
"""Create a list of colors interpolated between the input array of colors with a
|
|
1412
|
+
specific number of colors.
|
|
923
1413
|
|
|
924
1414
|
Parameters
|
|
925
1415
|
----------
|
|
926
|
-
reference_colors
|
|
927
|
-
The colors to be interpolated between or spread apart
|
|
928
|
-
length_of_output
|
|
929
|
-
The number of colors that the output should have, ideally more than the input
|
|
1416
|
+
reference_colors
|
|
1417
|
+
The colors to be interpolated between or spread apart.
|
|
1418
|
+
length_of_output
|
|
1419
|
+
The number of colors that the output should have, ideally more than the input.
|
|
930
1420
|
|
|
931
1421
|
Returns
|
|
932
1422
|
-------
|
|
933
1423
|
list[ManimColor] | ManimColor
|
|
934
|
-
A list of ManimColor's
|
|
1424
|
+
A :class:`ManimColor` or a list of interpolated :class:`ManimColor`'s.
|
|
935
1425
|
"""
|
|
936
1426
|
if length_of_output == 0:
|
|
937
1427
|
return ManimColor(reference_colors[0])
|
|
@@ -951,34 +1441,39 @@ def color_gradient(
|
|
|
951
1441
|
|
|
952
1442
|
|
|
953
1443
|
def interpolate_color(
|
|
954
|
-
color1: ManimColorT, color2:
|
|
1444
|
+
color1: ManimColorT, color2: ManimColorT, alpha: float
|
|
955
1445
|
) -> ManimColorT:
|
|
956
|
-
"""Standalone function to interpolate two ManimColors and get the result
|
|
1446
|
+
"""Standalone function to interpolate two ManimColors and get the result. Refer to
|
|
1447
|
+
:meth:`ManimColor.interpolate`.
|
|
957
1448
|
|
|
958
1449
|
Parameters
|
|
959
1450
|
----------
|
|
960
|
-
color1
|
|
961
|
-
|
|
962
|
-
color2
|
|
963
|
-
|
|
964
|
-
alpha
|
|
965
|
-
The alpha value determining the point of interpolation between the colors
|
|
1451
|
+
color1
|
|
1452
|
+
The first :class:`ManimColor`.
|
|
1453
|
+
color2
|
|
1454
|
+
The second :class:`ManimColor`.
|
|
1455
|
+
alpha
|
|
1456
|
+
The alpha value determining the point of interpolation between the colors.
|
|
966
1457
|
|
|
967
1458
|
Returns
|
|
968
1459
|
-------
|
|
969
1460
|
ManimColor
|
|
970
|
-
The interpolated ManimColor
|
|
1461
|
+
The interpolated ManimColor.
|
|
971
1462
|
"""
|
|
972
1463
|
return color1.interpolate(color2, alpha)
|
|
973
1464
|
|
|
974
1465
|
|
|
975
1466
|
def average_color(*colors: ParsableManimColor) -> ManimColor:
|
|
976
|
-
"""
|
|
1467
|
+
"""Determine the average color between the given parameters.
|
|
1468
|
+
|
|
1469
|
+
.. note::
|
|
1470
|
+
This operation does not consider the alphas (opacities) of the colors. The
|
|
1471
|
+
generated color has an alpha or opacity of 1.0.
|
|
977
1472
|
|
|
978
1473
|
Returns
|
|
979
1474
|
-------
|
|
980
1475
|
ManimColor
|
|
981
|
-
The average color of the input
|
|
1476
|
+
The average color of the input.
|
|
982
1477
|
"""
|
|
983
1478
|
rgbs = np.array([color_to_rgb(color) for color in colors])
|
|
984
1479
|
mean_rgb = np.apply_along_axis(np.mean, 0, rgbs)
|
|
@@ -986,31 +1481,31 @@ def average_color(*colors: ParsableManimColor) -> ManimColor:
|
|
|
986
1481
|
|
|
987
1482
|
|
|
988
1483
|
def random_bright_color() -> ManimColor:
|
|
989
|
-
"""
|
|
1484
|
+
"""Return a random bright color: a random color averaged with ``WHITE``.
|
|
990
1485
|
|
|
991
1486
|
.. warning::
|
|
992
|
-
This operation is very expensive
|
|
1487
|
+
This operation is very expensive. Please keep in mind the performance loss.
|
|
993
1488
|
|
|
994
1489
|
Returns
|
|
995
1490
|
-------
|
|
996
1491
|
ManimColor
|
|
997
|
-
A bright ManimColor
|
|
1492
|
+
A random bright :class:`ManimColor`.
|
|
998
1493
|
"""
|
|
999
1494
|
curr_rgb = color_to_rgb(random_color())
|
|
1000
|
-
new_rgb =
|
|
1495
|
+
new_rgb = 0.5 * (curr_rgb + np.ones(3))
|
|
1001
1496
|
return ManimColor(new_rgb)
|
|
1002
1497
|
|
|
1003
1498
|
|
|
1004
1499
|
def random_color() -> ManimColor:
|
|
1005
|
-
"""Return
|
|
1500
|
+
"""Return a random :class:`ManimColor`.
|
|
1006
1501
|
|
|
1007
1502
|
.. warning::
|
|
1008
|
-
This operation is very expensive
|
|
1503
|
+
This operation is very expensive. Please keep in mind the performance loss.
|
|
1009
1504
|
|
|
1010
1505
|
Returns
|
|
1011
1506
|
-------
|
|
1012
1507
|
ManimColor
|
|
1013
|
-
|
|
1508
|
+
A random :class:`ManimColor`.
|
|
1014
1509
|
"""
|
|
1015
1510
|
import manim.utils.color.manim_colors as manim_colors
|
|
1016
1511
|
|
|
@@ -1018,17 +1513,38 @@ def random_color() -> ManimColor:
|
|
|
1018
1513
|
|
|
1019
1514
|
|
|
1020
1515
|
def get_shaded_rgb(
|
|
1021
|
-
rgb:
|
|
1022
|
-
point:
|
|
1023
|
-
unit_normal_vect:
|
|
1024
|
-
light_source:
|
|
1025
|
-
) ->
|
|
1516
|
+
rgb: RGB_Array_Float,
|
|
1517
|
+
point: Point3D,
|
|
1518
|
+
unit_normal_vect: Vector3D,
|
|
1519
|
+
light_source: Point3D,
|
|
1520
|
+
) -> RGB_Array_Float:
|
|
1521
|
+
"""Add light or shadow to the ``rgb`` color of some surface which is located at a
|
|
1522
|
+
given ``point`` in space and facing in the direction of ``unit_normal_vect``,
|
|
1523
|
+
depending on whether the surface is facing a ``light_source`` or away from it.
|
|
1524
|
+
|
|
1525
|
+
Parameters
|
|
1526
|
+
----------
|
|
1527
|
+
rgb
|
|
1528
|
+
An RGB array of floats.
|
|
1529
|
+
point
|
|
1530
|
+
The location of the colored surface.
|
|
1531
|
+
unit_normal_vect
|
|
1532
|
+
The direction in which the colored surface is facing.
|
|
1533
|
+
light_source
|
|
1534
|
+
The location of a light source which might illuminate the surface.
|
|
1535
|
+
|
|
1536
|
+
Returns
|
|
1537
|
+
-------
|
|
1538
|
+
RGB_Array_Float
|
|
1539
|
+
The color with added light or shadow, depending on the direction of the colored
|
|
1540
|
+
surface.
|
|
1541
|
+
"""
|
|
1026
1542
|
to_sun = normalize(light_source - point)
|
|
1027
|
-
|
|
1028
|
-
if
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
return
|
|
1543
|
+
light = 0.5 * np.dot(unit_normal_vect, to_sun) ** 3
|
|
1544
|
+
if light < 0:
|
|
1545
|
+
light *= 0.5
|
|
1546
|
+
shaded_rgb: RGB_Array_Float = rgb + light
|
|
1547
|
+
return shaded_rgb
|
|
1032
1548
|
|
|
1033
1549
|
|
|
1034
1550
|
__all__ = [
|
|
@@ -1044,11 +1560,12 @@ __all__ = [
|
|
|
1044
1560
|
"rgb_to_hex",
|
|
1045
1561
|
"hex_to_rgb",
|
|
1046
1562
|
"invert_color",
|
|
1047
|
-
"interpolate_arrays",
|
|
1048
1563
|
"color_gradient",
|
|
1049
1564
|
"interpolate_color",
|
|
1050
1565
|
"average_color",
|
|
1051
1566
|
"random_bright_color",
|
|
1052
1567
|
"random_color",
|
|
1053
1568
|
"get_shaded_rgb",
|
|
1569
|
+
"HSV",
|
|
1570
|
+
"RGBA",
|
|
1054
1571
|
]
|