manim 0.18.0.post0__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/__init__.py +3 -6
- manim/__main__.py +61 -20
- manim/_config/__init__.py +6 -3
- manim/_config/cli_colors.py +16 -8
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +14 -8
- manim/_config/utils.py +651 -472
- manim/animation/animation.py +152 -5
- manim/animation/composition.py +80 -39
- manim/animation/creation.py +196 -14
- manim/animation/fading.py +5 -9
- manim/animation/indication.py +103 -47
- manim/animation/movement.py +22 -5
- manim/animation/rotation.py +3 -2
- manim/animation/specialized.py +4 -6
- manim/animation/speedmodifier.py +10 -5
- manim/animation/transform.py +4 -5
- manim/animation/transform_matching_parts.py +1 -1
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +15 -6
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +70 -44
- manim/cli/checkhealth/checks.py +93 -75
- manim/cli/checkhealth/commands.py +14 -5
- manim/cli/default_group.py +157 -25
- manim/cli/init/commands.py +32 -24
- 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 +51 -15
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +97 -32
- manim/constants.py +65 -19
- manim/gui/gui.py +2 -0
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +112 -78
- manim/mobject/geometry/boolean_ops.py +32 -25
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +132 -64
- manim/mobject/geometry/polygram.py +126 -30
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +38 -29
- manim/mobject/graph.py +414 -133
- manim/mobject/graphing/coordinate_systems.py +126 -64
- manim/mobject/graphing/functions.py +25 -15
- manim/mobject/graphing/number_line.py +24 -10
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +314 -165
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +30 -9
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +509 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
- manim/mobject/opengl/opengl_surface.py +3 -2
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
- manim/mobject/svg/brace.py +63 -13
- manim/mobject/svg/svg_mobject.py +4 -3
- manim/mobject/table.py +11 -13
- manim/mobject/text/code_mobject.py +186 -548
- manim/mobject/text/numbers.py +9 -7
- manim/mobject/text/tex_mobject.py +23 -14
- manim/mobject/text/text_mobject.py +70 -24
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +62 -34
- manim/mobject/types/image_mobject.py +42 -24
- manim/mobject/types/point_cloud_mobject.py +105 -67
- manim/mobject/types/vectorized_mobject.py +496 -228
- manim/mobject/value_tracker.py +5 -4
- manim/mobject/vector_field.py +5 -5
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +14 -8
- manim/renderer/cairo_renderer.py +20 -10
- manim/renderer/opengl_renderer.py +21 -23
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +5 -2
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +90 -43
- manim/scene/scene_file_writer.py +316 -165
- manim/scene/section.py +17 -15
- manim/scene/three_d_scene.py +13 -21
- manim/scene/vector_space_scene.py +22 -9
- manim/typing.py +830 -70
- manim/utils/bezier.py +1667 -399
- manim/utils/caching.py +13 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +3 -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 +3 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +844 -309
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +90 -40
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +234 -0
- manim/utils/docbuild/autocolor_directive.py +21 -17
- manim/utils/docbuild/manim_directive.py +50 -35
- 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 +26 -16
- manim/utils/hashing.py +9 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +14 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +57 -19
- manim/utils/opengl.py +83 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +21 -23
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +74 -39
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +125 -69
- 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 +33 -18
- manim/utils/testing/frames_comparison.py +27 -19
- manim/utils/tex.py +127 -197
- manim/utils/tex_file_writing.py +47 -45
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.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,48 +94,66 @@ 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
|
-
|
|
56
|
-
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{6,8}", re.IGNORECASE)
|
|
104
|
+
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{3,8}", re.IGNORECASE)
|
|
57
105
|
|
|
58
106
|
|
|
59
107
|
class ManimColor:
|
|
60
108
|
"""Internal representation of a color.
|
|
61
109
|
|
|
62
|
-
The ManimColor class is the main class for the representation of a color.
|
|
63
|
-
|
|
64
|
-
|
|
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.
|
|
65
113
|
|
|
66
|
-
This is done in order to reduce the amount of color
|
|
114
|
+
This is done in order to reduce the amount of color inconsistencies by constantly
|
|
67
115
|
casting between integers and floats which introduces errors.
|
|
68
116
|
|
|
69
117
|
The class can accept any value of type :class:`ParsableManimColor` i.e.
|
|
70
118
|
|
|
71
|
-
ManimColor, int, str, RGB_Tuple_Int, RGB_Tuple_Float, RGBA_Tuple_Int, RGBA_Tuple_Float, RGB_Array_Int,
|
|
72
|
-
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``
|
|
73
121
|
|
|
74
|
-
ManimColor itself only accepts singular values and will directly interpret
|
|
75
|
-
|
|
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.
|
|
76
125
|
|
|
77
|
-
If you want to parse a list of colors use the
|
|
78
|
-
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.
|
|
79
129
|
|
|
80
130
|
.. warning::
|
|
81
|
-
If you pass an array of numbers to :meth:`parse
|
|
82
|
-
|
|
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.
|
|
134
|
+
|
|
135
|
+
For conversion behaviors, see the ``_internal`` functions for further documentation.
|
|
136
|
+
|
|
137
|
+
You can create a :class:`ManimColor` instance via its classmethods. See the
|
|
138
|
+
respective methods for more info.
|
|
83
139
|
|
|
84
|
-
|
|
140
|
+
.. code-block:: python
|
|
141
|
+
|
|
142
|
+
mycolor = ManimColor.from_rgb((0, 1, 0.4, 0.5))
|
|
143
|
+
myothercolor = ManimColor.from_rgb((153, 255, 255))
|
|
144
|
+
|
|
145
|
+
You can also convert between different color spaces:
|
|
146
|
+
|
|
147
|
+
.. code-block:: python
|
|
148
|
+
|
|
149
|
+
mycolor_hex = mycolor.to_hex()
|
|
150
|
+
myoriginalcolor = ManimColor.from_hex(mycolor_hex).to_hsv()
|
|
85
151
|
|
|
86
152
|
Parameters
|
|
87
153
|
----------
|
|
88
154
|
value
|
|
89
155
|
Some representation of a color (e.g., a string or
|
|
90
|
-
a suitable tuple).
|
|
156
|
+
a suitable tuple). The default ``None`` is ``BLACK``.
|
|
91
157
|
alpha
|
|
92
158
|
The opacity of the color. By default, colors are
|
|
93
159
|
fully opaque (value 1.0).
|
|
@@ -118,14 +184,14 @@ class ManimColor:
|
|
|
118
184
|
# This is not expected to be called on module initialization time
|
|
119
185
|
# It can be horribly slow to convert a string to a color because
|
|
120
186
|
# it has to access the dictionary of colors and find the right color
|
|
121
|
-
self._internal_value = ManimColor._internal_from_string(value)
|
|
187
|
+
self._internal_value = ManimColor._internal_from_string(value, alpha)
|
|
122
188
|
elif isinstance(value, (list, tuple, np.ndarray)):
|
|
123
189
|
length = len(value)
|
|
124
190
|
if all(isinstance(x, float) for x in value):
|
|
125
191
|
if length == 3:
|
|
126
|
-
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]
|
|
127
193
|
elif length == 4:
|
|
128
|
-
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore
|
|
194
|
+
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore[arg-type]
|
|
129
195
|
else:
|
|
130
196
|
raise ValueError(
|
|
131
197
|
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
@@ -133,10 +199,11 @@ class ManimColor:
|
|
|
133
199
|
else:
|
|
134
200
|
if length == 3:
|
|
135
201
|
self._internal_value = ManimColor._internal_from_int_rgb(
|
|
136
|
-
value,
|
|
202
|
+
value, # type: ignore[arg-type]
|
|
203
|
+
alpha,
|
|
137
204
|
)
|
|
138
205
|
elif length == 4:
|
|
139
|
-
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]
|
|
140
207
|
else:
|
|
141
208
|
raise ValueError(
|
|
142
209
|
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
@@ -145,7 +212,6 @@ class ManimColor:
|
|
|
145
212
|
result = re_hex.search(value.get_hex())
|
|
146
213
|
if result is None:
|
|
147
214
|
raise ValueError(f"Failed to parse a color from {value}")
|
|
148
|
-
|
|
149
215
|
self._internal_value = ManimColor._internal_from_hex_string(
|
|
150
216
|
result.group(), alpha
|
|
151
217
|
)
|
|
@@ -157,37 +223,59 @@ class ManimColor:
|
|
|
157
223
|
f"list[float, float, float, float], not {type(value)}"
|
|
158
224
|
)
|
|
159
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
|
+
|
|
160
234
|
@property
|
|
161
235
|
def _internal_value(self) -> ManimColorInternal:
|
|
162
|
-
"""
|
|
236
|
+
"""Return the internal value of the current Manim color ``[r,g,b,a]`` float
|
|
237
|
+
array.
|
|
163
238
|
|
|
164
239
|
Returns
|
|
165
240
|
-------
|
|
166
241
|
ManimColorInternal
|
|
167
|
-
|
|
242
|
+
Internal color representation.
|
|
168
243
|
"""
|
|
169
244
|
return self.__value
|
|
170
245
|
|
|
171
246
|
@_internal_value.setter
|
|
172
247
|
def _internal_value(self, value: ManimColorInternal) -> None:
|
|
173
|
-
"""
|
|
248
|
+
"""Overwrite the internal color value of this :class:`ManimColor`.
|
|
174
249
|
|
|
175
250
|
Parameters
|
|
176
251
|
----------
|
|
177
|
-
value
|
|
178
|
-
The value which will overwrite the current color
|
|
252
|
+
value
|
|
253
|
+
The value which will overwrite the current color.
|
|
179
254
|
|
|
180
255
|
Raises
|
|
181
256
|
------
|
|
182
257
|
TypeError
|
|
183
|
-
|
|
258
|
+
If an invalid array is passed.
|
|
184
259
|
"""
|
|
185
260
|
if not isinstance(value, np.ndarray):
|
|
186
|
-
raise TypeError("
|
|
261
|
+
raise TypeError("Value must be a NumPy array.")
|
|
187
262
|
if value.shape[0] != 4:
|
|
188
|
-
raise TypeError("Array must have 4 values
|
|
263
|
+
raise TypeError("Array must have exactly 4 values.")
|
|
189
264
|
self.__value: ManimColorInternal = value
|
|
190
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
|
+
|
|
191
279
|
@staticmethod
|
|
192
280
|
def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal:
|
|
193
281
|
return np.asarray(
|
|
@@ -200,32 +288,41 @@ class ManimColor:
|
|
|
200
288
|
dtype=ManimColorDType,
|
|
201
289
|
)
|
|
202
290
|
|
|
203
|
-
# TODO: Maybe make 8 nibble hex also convertible ?
|
|
204
291
|
@staticmethod
|
|
205
|
-
def _internal_from_hex_string(
|
|
206
|
-
"""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`.
|
|
207
295
|
|
|
208
296
|
.. warning::
|
|
209
297
|
This does not accept any prefixes like # or similar in front of the hex string.
|
|
210
|
-
This is just intended for the raw hex part
|
|
298
|
+
This is just intended for the raw hex part.
|
|
211
299
|
|
|
212
300
|
*For internal use only*
|
|
213
301
|
|
|
214
302
|
Parameters
|
|
215
303
|
----------
|
|
216
|
-
hex
|
|
217
|
-
|
|
218
|
-
alpha
|
|
219
|
-
|
|
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.
|
|
220
309
|
|
|
221
310
|
Returns
|
|
222
311
|
-------
|
|
223
312
|
ManimColorInternal
|
|
224
313
|
Internal color representation
|
|
225
314
|
"""
|
|
226
|
-
if len(
|
|
227
|
-
|
|
228
|
-
|
|
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)
|
|
229
326
|
return np.asarray(
|
|
230
327
|
(
|
|
231
328
|
((tmp >> 24) & 0xFF) / 255,
|
|
@@ -240,22 +337,22 @@ class ManimColor:
|
|
|
240
337
|
def _internal_from_int_rgb(
|
|
241
338
|
rgb: RGB_Tuple_Int, alpha: float = 1.0
|
|
242
339
|
) -> ManimColorInternal:
|
|
243
|
-
"""Internal function for converting
|
|
340
|
+
"""Internal function for converting an RGB tuple of integers into the internal
|
|
341
|
+
representation of a :class:`ManimColor`.
|
|
244
342
|
|
|
245
343
|
*For internal use only*
|
|
246
344
|
|
|
247
345
|
Parameters
|
|
248
346
|
----------
|
|
249
|
-
rgb
|
|
250
|
-
|
|
251
|
-
alpha
|
|
252
|
-
|
|
347
|
+
rgb
|
|
348
|
+
Integer RGB tuple to be parsed
|
|
349
|
+
alpha
|
|
350
|
+
Optional alpha value. Default is 1.0.
|
|
253
351
|
|
|
254
352
|
Returns
|
|
255
353
|
-------
|
|
256
354
|
ManimColorInternal
|
|
257
|
-
Internal color representation
|
|
258
|
-
|
|
355
|
+
Internal color representation.
|
|
259
356
|
"""
|
|
260
357
|
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() / 255
|
|
261
358
|
value.resize(4, refcheck=False)
|
|
@@ -266,22 +363,22 @@ class ManimColor:
|
|
|
266
363
|
def _internal_from_rgb(
|
|
267
364
|
rgb: RGB_Tuple_Float, alpha: float = 1.0
|
|
268
365
|
) -> ManimColorInternal:
|
|
269
|
-
"""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`.
|
|
270
368
|
|
|
271
369
|
*For internal use only*
|
|
272
370
|
|
|
273
371
|
Parameters
|
|
274
372
|
----------
|
|
275
|
-
rgb
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
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.
|
|
280
377
|
|
|
281
378
|
Returns
|
|
282
379
|
-------
|
|
283
380
|
ManimColorInternal
|
|
284
|
-
Internal color representation
|
|
381
|
+
Internal color representation.
|
|
285
382
|
"""
|
|
286
383
|
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy()
|
|
287
384
|
value.resize(4, refcheck=False)
|
|
@@ -290,324 +387,527 @@ class ManimColor:
|
|
|
290
387
|
|
|
291
388
|
@staticmethod
|
|
292
389
|
def _internal_from_int_rgba(rgba: RGBA_Tuple_Int) -> ManimColorInternal:
|
|
293
|
-
"""Internal function for converting
|
|
390
|
+
"""Internal function for converting an RGBA tuple of integers into the internal
|
|
391
|
+
representation of a :class:`ManimColor`.
|
|
294
392
|
|
|
295
393
|
*For internal use only*
|
|
296
394
|
|
|
297
395
|
Parameters
|
|
298
396
|
----------
|
|
299
|
-
rgba
|
|
300
|
-
|
|
397
|
+
rgba
|
|
398
|
+
Int RGBA tuple to be parsed.
|
|
301
399
|
|
|
302
400
|
Returns
|
|
303
401
|
-------
|
|
304
402
|
ManimColorInternal
|
|
305
|
-
Internal color representation
|
|
403
|
+
Internal color representation.
|
|
306
404
|
"""
|
|
307
405
|
return np.asarray(rgba, dtype=ManimColorDType) / 255
|
|
308
406
|
|
|
309
407
|
@staticmethod
|
|
310
408
|
def _internal_from_rgba(rgba: RGBA_Tuple_Float) -> ManimColorInternal:
|
|
311
|
-
"""Internal function for converting
|
|
409
|
+
"""Internal function for converting an RGBA tuple of floats into the internal
|
|
410
|
+
representation of a :class:`ManimColor`.
|
|
312
411
|
|
|
313
412
|
*For internal use only*
|
|
314
413
|
|
|
315
414
|
Parameters
|
|
316
415
|
----------
|
|
317
|
-
rgba
|
|
318
|
-
|
|
416
|
+
rgba
|
|
417
|
+
Int RGBA tuple to be parsed.
|
|
319
418
|
|
|
320
419
|
Returns
|
|
321
420
|
-------
|
|
322
421
|
ManimColorInternal
|
|
323
|
-
Internal color representation
|
|
422
|
+
Internal color representation.
|
|
324
423
|
"""
|
|
325
424
|
return np.asarray(rgba, dtype=ManimColorDType)
|
|
326
425
|
|
|
327
426
|
@staticmethod
|
|
328
|
-
def _internal_from_string(name: str) -> ManimColorInternal:
|
|
329
|
-
"""Internal function for converting a string into the internal representation of
|
|
330
|
-
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.
|
|
331
431
|
|
|
332
432
|
*For internal use only*
|
|
333
433
|
|
|
334
434
|
Parameters
|
|
335
435
|
----------
|
|
336
|
-
name
|
|
337
|
-
The color name to be parsed into a color. Refer to the different color
|
|
338
|
-
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.
|
|
339
439
|
|
|
340
440
|
Returns
|
|
341
441
|
-------
|
|
342
442
|
ManimColorInternal
|
|
343
|
-
Internal color representation
|
|
443
|
+
Internal color representation.
|
|
344
444
|
|
|
345
445
|
Raises
|
|
346
446
|
------
|
|
347
447
|
ValueError
|
|
348
|
-
|
|
448
|
+
If the color name is not present in Manim.
|
|
349
449
|
"""
|
|
350
450
|
from . import _all_color_dict
|
|
351
451
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
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()
|
|
356
455
|
else:
|
|
357
456
|
raise ValueError(f"Color {name} not found")
|
|
358
457
|
|
|
359
458
|
def to_integer(self) -> int:
|
|
360
|
-
"""
|
|
459
|
+
"""Convert the current :class:`ManimColor` into an integer.
|
|
460
|
+
|
|
461
|
+
.. warning::
|
|
462
|
+
This will return only the RGB part of the color.
|
|
361
463
|
|
|
362
464
|
Returns
|
|
363
465
|
-------
|
|
364
466
|
int
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
.. warning::
|
|
368
|
-
This will return only the rgb part of the color
|
|
467
|
+
Integer representation of the color.
|
|
369
468
|
"""
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
)
|
|
469
|
+
tmp = (self._internal_value[:3] * 255).astype(dtype=np.byte).tobytes()
|
|
470
|
+
return int.from_bytes(tmp, "big")
|
|
373
471
|
|
|
374
472
|
def to_rgb(self) -> RGB_Array_Float:
|
|
375
|
-
"""
|
|
473
|
+
"""Convert the current :class:`ManimColor` into an RGB array of floats.
|
|
376
474
|
|
|
377
475
|
Returns
|
|
378
476
|
-------
|
|
379
477
|
RGB_Array_Float
|
|
380
|
-
|
|
478
|
+
RGB array of 3 floats from 0.0 to 1.0.
|
|
381
479
|
"""
|
|
382
480
|
return self._internal_value[:3]
|
|
383
481
|
|
|
384
482
|
def to_int_rgb(self) -> RGB_Array_Int:
|
|
385
|
-
"""
|
|
483
|
+
"""Convert the current :class:`ManimColor` into an RGB array of integers.
|
|
386
484
|
|
|
387
485
|
Returns
|
|
388
486
|
-------
|
|
389
487
|
RGB_Array_Int
|
|
390
|
-
|
|
488
|
+
RGB array of 3 integers from 0 to 255.
|
|
391
489
|
"""
|
|
392
490
|
return (self._internal_value[:3] * 255).astype(int)
|
|
393
491
|
|
|
394
492
|
def to_rgba(self) -> RGBA_Array_Float:
|
|
395
|
-
"""
|
|
493
|
+
"""Convert the current :class:`ManimColor` into an RGBA array of floats.
|
|
396
494
|
|
|
397
495
|
Returns
|
|
398
496
|
-------
|
|
399
497
|
RGBA_Array_Float
|
|
400
|
-
|
|
498
|
+
RGBA array of 4 floats from 0.0 to 1.0.
|
|
401
499
|
"""
|
|
402
500
|
return self._internal_value
|
|
403
501
|
|
|
404
502
|
def to_int_rgba(self) -> RGBA_Array_Int:
|
|
405
|
-
"""
|
|
503
|
+
"""Convert the current ManimColor into an RGBA array of integers.
|
|
406
504
|
|
|
407
505
|
|
|
408
506
|
Returns
|
|
409
507
|
-------
|
|
410
508
|
RGBA_Array_Int
|
|
411
|
-
|
|
509
|
+
RGBA array of 4 integers from 0 to 255.
|
|
412
510
|
"""
|
|
413
511
|
return (self._internal_value * 255).astype(int)
|
|
414
512
|
|
|
415
513
|
def to_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Float:
|
|
416
|
-
"""
|
|
417
|
-
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.
|
|
418
516
|
|
|
419
517
|
Parameters
|
|
420
518
|
----------
|
|
421
|
-
alpha
|
|
422
|
-
|
|
519
|
+
alpha
|
|
520
|
+
Alpha value to be used in the return value.
|
|
423
521
|
|
|
424
522
|
Returns
|
|
425
523
|
-------
|
|
426
524
|
RGBA_Array_Float
|
|
427
|
-
|
|
525
|
+
RGBA array of 4 floats from 0.0 to 1.0.
|
|
428
526
|
"""
|
|
429
527
|
return np.fromiter((*self._internal_value[:3], alpha), dtype=ManimColorDType)
|
|
430
528
|
|
|
431
529
|
def to_int_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Int:
|
|
432
|
-
"""
|
|
433
|
-
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.
|
|
434
532
|
|
|
435
533
|
Parameters
|
|
436
534
|
----------
|
|
437
|
-
alpha
|
|
438
|
-
|
|
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.
|
|
439
538
|
|
|
440
539
|
Returns
|
|
441
540
|
-------
|
|
442
541
|
RGBA_Array_Int
|
|
443
|
-
|
|
542
|
+
RGBA array of 4 integers from 0 to 255.
|
|
444
543
|
"""
|
|
445
544
|
tmp = self._internal_value * 255
|
|
446
545
|
tmp[3] = alpha * 255
|
|
447
546
|
return tmp.astype(int)
|
|
448
547
|
|
|
449
548
|
def to_hex(self, with_alpha: bool = False) -> str:
|
|
450
|
-
"""
|
|
549
|
+
"""Convert the :class:`ManimColor` to a hexadecimal representation of the color.
|
|
451
550
|
|
|
452
551
|
Parameters
|
|
453
552
|
----------
|
|
454
|
-
with_alpha
|
|
455
|
-
|
|
456
|
-
|
|
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``.
|
|
457
556
|
|
|
458
557
|
Returns
|
|
459
558
|
-------
|
|
460
559
|
str
|
|
461
|
-
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``.
|
|
462
562
|
"""
|
|
463
|
-
tmp =
|
|
563
|
+
tmp = (
|
|
564
|
+
f"#{int(self._internal_value[0] * 255):02X}"
|
|
565
|
+
f"{int(self._internal_value[1] * 255):02X}"
|
|
566
|
+
f"{int(self._internal_value[2] * 255):02X}"
|
|
567
|
+
)
|
|
464
568
|
if with_alpha:
|
|
465
|
-
tmp += f"{int(self._internal_value[3]*255):02X}"
|
|
569
|
+
tmp += f"{int(self._internal_value[3] * 255):02X}"
|
|
466
570
|
return tmp
|
|
467
571
|
|
|
468
572
|
def to_hsv(self) -> HSV_Array_Float:
|
|
469
|
-
"""
|
|
573
|
+
"""Convert the :class:`ManimColor` to an HSV array.
|
|
470
574
|
|
|
471
575
|
.. note::
|
|
472
|
-
Be careful this returns an array in the form
|
|
473
|
-
This might be confusing because
|
|
474
|
-
of
|
|
475
|
-
|
|
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.
|
|
476
581
|
|
|
477
582
|
Returns
|
|
478
583
|
-------
|
|
479
584
|
HSV_Array_Float
|
|
480
|
-
|
|
585
|
+
An HSV array of 3 floats from 0.0 to 1.0.
|
|
481
586
|
"""
|
|
482
|
-
return colorsys.rgb_to_hsv(*self.to_rgb())
|
|
587
|
+
return np.array(colorsys.rgb_to_hsv(*self.to_rgb()))
|
|
483
588
|
|
|
484
|
-
def
|
|
485
|
-
"""
|
|
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.
|
|
603
|
+
"""
|
|
604
|
+
return np.array(colorsys.rgb_to_hls(*self.to_rgb()))
|
|
605
|
+
|
|
606
|
+
def invert(self, with_alpha: bool = False) -> Self:
|
|
607
|
+
"""Return a new, linearly inverted version of this :class:`ManimColor` (no
|
|
608
|
+
inplace changes).
|
|
486
609
|
|
|
487
610
|
Parameters
|
|
488
611
|
----------
|
|
489
|
-
with_alpha
|
|
490
|
-
|
|
612
|
+
with_alpha
|
|
613
|
+
If ``True``, the alpha value will be inverted too. Default is ``False``.
|
|
491
614
|
|
|
492
615
|
.. note::
|
|
493
|
-
|
|
494
|
-
|
|
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.
|
|
495
619
|
|
|
496
620
|
Returns
|
|
497
621
|
-------
|
|
498
622
|
ManimColor
|
|
499
|
-
The linearly inverted ManimColor
|
|
623
|
+
The linearly inverted :class:`ManimColor`.
|
|
500
624
|
"""
|
|
501
|
-
|
|
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)
|
|
502
632
|
|
|
503
|
-
def interpolate(self, other:
|
|
504
|
-
"""
|
|
633
|
+
def interpolate(self, other: Self, alpha: float) -> Self:
|
|
634
|
+
"""Interpolate between the current and the given :class:`ManimColor`, and return
|
|
635
|
+
the result.
|
|
505
636
|
|
|
506
637
|
Parameters
|
|
507
638
|
----------
|
|
508
|
-
other
|
|
509
|
-
The other ManimColor to be used for interpolation
|
|
510
|
-
alpha
|
|
511
|
-
A point on the line in
|
|
512
|
-
|
|
513
|
-
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`.
|
|
514
645
|
|
|
515
646
|
Returns
|
|
516
647
|
-------
|
|
517
648
|
ManimColor
|
|
518
|
-
The interpolated ManimColor
|
|
649
|
+
The interpolated :class:`ManimColor`.
|
|
519
650
|
"""
|
|
520
|
-
return
|
|
521
|
-
self.
|
|
651
|
+
return self._construct_from_space(
|
|
652
|
+
self._internal_space * (1 - alpha) + other._internal_space * alpha
|
|
522
653
|
)
|
|
523
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
|
+
|
|
524
795
|
@classmethod
|
|
525
796
|
def from_rgb(
|
|
526
797
|
cls,
|
|
527
798
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
528
799
|
alpha: float = 1.0,
|
|
529
800
|
) -> Self:
|
|
530
|
-
"""
|
|
801
|
+
"""Create a ManimColor from an RGB array. Automagically decides which type it
|
|
802
|
+
is: ``int`` or ``float``.
|
|
531
803
|
|
|
532
804
|
.. warning::
|
|
533
|
-
Please make sure that your elements are not floats if you want integers. A
|
|
534
|
-
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``.
|
|
535
808
|
|
|
536
809
|
|
|
537
810
|
Parameters
|
|
538
811
|
----------
|
|
539
|
-
rgb
|
|
540
|
-
Any 3
|
|
541
|
-
alpha
|
|
542
|
-
|
|
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.
|
|
543
816
|
|
|
544
817
|
Returns
|
|
545
818
|
-------
|
|
546
819
|
ManimColor
|
|
547
|
-
|
|
820
|
+
The :class:`ManimColor` which corresponds to the given ``rgb``.
|
|
548
821
|
"""
|
|
549
|
-
return cls(rgb, alpha)
|
|
822
|
+
return cls._from_internal(ManimColor(rgb, alpha)._internal_value)
|
|
550
823
|
|
|
551
824
|
@classmethod
|
|
552
825
|
def from_rgba(
|
|
553
826
|
cls, rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int
|
|
554
827
|
) -> Self:
|
|
555
|
-
"""
|
|
828
|
+
"""Create a ManimColor from an RGBA Array. Automagically decides which type it
|
|
829
|
+
is: ``int`` or ``float``.
|
|
556
830
|
|
|
557
831
|
.. warning::
|
|
558
|
-
Please make sure that your elements are not floats if you want integers. A
|
|
559
|
-
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``.
|
|
560
835
|
|
|
561
836
|
Parameters
|
|
562
837
|
----------
|
|
563
|
-
rgba
|
|
564
|
-
Any 4
|
|
838
|
+
rgba
|
|
839
|
+
Any iterable of 4 floats or 4 integers.
|
|
565
840
|
|
|
566
841
|
Returns
|
|
567
842
|
-------
|
|
568
843
|
ManimColor
|
|
569
|
-
|
|
844
|
+
The :class:`ManimColor` corresponding to the given ``rgba``.
|
|
570
845
|
"""
|
|
571
846
|
return cls(rgba)
|
|
572
847
|
|
|
573
848
|
@classmethod
|
|
574
|
-
def from_hex(cls,
|
|
575
|
-
"""
|
|
849
|
+
def from_hex(cls, hex_str: str, alpha: float = 1.0) -> Self:
|
|
850
|
+
"""Create a :class:`ManimColor` from a hex string.
|
|
576
851
|
|
|
577
852
|
Parameters
|
|
578
853
|
----------
|
|
579
|
-
|
|
580
|
-
The hex string to be converted
|
|
581
|
-
|
|
582
|
-
|
|
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.
|
|
583
860
|
|
|
584
861
|
Returns
|
|
585
862
|
-------
|
|
586
863
|
ManimColor
|
|
587
|
-
The ManimColor represented by the hex string
|
|
864
|
+
The :class:`ManimColor` represented by the hex string.
|
|
588
865
|
"""
|
|
589
|
-
return cls(
|
|
866
|
+
return cls._from_internal(ManimColor(hex_str, alpha)._internal_value)
|
|
590
867
|
|
|
591
868
|
@classmethod
|
|
592
869
|
def from_hsv(
|
|
593
870
|
cls, hsv: HSV_Array_Float | HSV_Tuple_Float, alpha: float = 1.0
|
|
594
871
|
) -> Self:
|
|
595
|
-
"""
|
|
872
|
+
"""Create a :class:`ManimColor` from an HSV array.
|
|
596
873
|
|
|
597
874
|
Parameters
|
|
598
875
|
----------
|
|
599
|
-
hsv
|
|
600
|
-
Any
|
|
601
|
-
alpha
|
|
602
|
-
|
|
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.
|
|
603
880
|
|
|
604
881
|
Returns
|
|
605
882
|
-------
|
|
606
883
|
ManimColor
|
|
607
|
-
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.
|
|
608
886
|
"""
|
|
609
887
|
rgb = colorsys.hsv_to_rgb(*hsv)
|
|
610
|
-
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)
|
|
611
911
|
|
|
612
912
|
@overload
|
|
613
913
|
@classmethod
|
|
@@ -615,8 +915,7 @@ class ManimColor:
|
|
|
615
915
|
cls,
|
|
616
916
|
color: ParsableManimColor | None,
|
|
617
917
|
alpha: float = ...,
|
|
618
|
-
) -> Self:
|
|
619
|
-
...
|
|
918
|
+
) -> Self: ...
|
|
620
919
|
|
|
621
920
|
@overload
|
|
622
921
|
@classmethod
|
|
@@ -624,37 +923,51 @@ class ManimColor:
|
|
|
624
923
|
cls,
|
|
625
924
|
color: Sequence[ParsableManimColor],
|
|
626
925
|
alpha: float = ...,
|
|
627
|
-
) -> list[Self]:
|
|
628
|
-
...
|
|
926
|
+
) -> list[Self]: ...
|
|
629
927
|
|
|
630
928
|
@classmethod
|
|
631
929
|
def parse(
|
|
632
930
|
cls,
|
|
633
|
-
color: ParsableManimColor |
|
|
931
|
+
color: ParsableManimColor | Sequence[ParsableManimColor] | None,
|
|
634
932
|
alpha: float = 1.0,
|
|
635
933
|
) -> Self | list[Self]:
|
|
636
|
-
"""
|
|
637
|
-
|
|
934
|
+
"""Parse one color as a :class:`ManimColor` or a sequence of colors as a list of
|
|
935
|
+
:class:`ManimColor`'s.
|
|
638
936
|
|
|
639
937
|
Parameters
|
|
640
938
|
----------
|
|
641
939
|
color
|
|
642
|
-
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]``.
|
|
643
943
|
alpha
|
|
644
|
-
The alpha value to use
|
|
944
|
+
The alpha (opacity) value to use for the passed color(s).
|
|
645
945
|
|
|
646
946
|
Returns
|
|
647
947
|
-------
|
|
648
|
-
ManimColor
|
|
649
|
-
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.
|
|
650
950
|
"""
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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)
|
|
654
963
|
|
|
655
964
|
@staticmethod
|
|
656
|
-
def gradient(
|
|
657
|
-
|
|
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
|
+
"""
|
|
658
971
|
# TODO: implement proper gradient, research good implementation for this or look at 3b1b implementation
|
|
659
972
|
raise NotImplementedError
|
|
660
973
|
|
|
@@ -669,37 +982,240 @@ class ManimColor:
|
|
|
669
982
|
raise TypeError(
|
|
670
983
|
f"Cannot compare {self.__class__.__name__} with {other.__class__.__name__}"
|
|
671
984
|
)
|
|
672
|
-
|
|
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
|
+
)
|
|
1079
|
+
|
|
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
|
+
)
|
|
1084
|
+
|
|
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
|
+
)
|
|
1089
|
+
|
|
1090
|
+
def __hash__(self) -> int:
|
|
1091
|
+
return hash(self.to_hex(with_alpha=True))
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
RGBA = ManimColor
|
|
1095
|
+
"""RGBA Color Space"""
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
class HSV(ManimColor):
|
|
1099
|
+
"""HSV Color Space"""
|
|
1100
|
+
|
|
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")
|
|
1114
|
+
|
|
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))
|
|
1121
|
+
|
|
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
|
|
673
1139
|
|
|
674
|
-
|
|
675
|
-
|
|
1140
|
+
@property
|
|
1141
|
+
def value(self) -> float:
|
|
1142
|
+
value: float = self.__hsv[2]
|
|
1143
|
+
return value
|
|
676
1144
|
|
|
677
|
-
|
|
678
|
-
|
|
1145
|
+
@value.setter
|
|
1146
|
+
def value(self, value: float) -> None:
|
|
1147
|
+
self.__hsv[2] = value
|
|
679
1148
|
|
|
680
|
-
|
|
681
|
-
|
|
1149
|
+
@property
|
|
1150
|
+
def h(self) -> float:
|
|
1151
|
+
hue: float = self.__hsv[0]
|
|
1152
|
+
return hue
|
|
682
1153
|
|
|
683
|
-
|
|
684
|
-
|
|
1154
|
+
@h.setter
|
|
1155
|
+
def h(self, hue: float) -> None:
|
|
1156
|
+
self.__hsv[0] = hue
|
|
685
1157
|
|
|
686
|
-
|
|
687
|
-
|
|
1158
|
+
@property
|
|
1159
|
+
def s(self) -> float:
|
|
1160
|
+
saturation: float = self.__hsv[1]
|
|
1161
|
+
return saturation
|
|
688
1162
|
|
|
689
|
-
|
|
690
|
-
|
|
1163
|
+
@s.setter
|
|
1164
|
+
def s(self, saturation: float) -> None:
|
|
1165
|
+
self.__hsv[1] = saturation
|
|
691
1166
|
|
|
692
|
-
|
|
693
|
-
|
|
1167
|
+
@property
|
|
1168
|
+
def v(self) -> float:
|
|
1169
|
+
value: float = self.__hsv[2]
|
|
1170
|
+
return value
|
|
694
1171
|
|
|
695
|
-
|
|
696
|
-
|
|
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`.
|
|
697
1201
|
|
|
698
|
-
|
|
699
|
-
|
|
1202
|
+
Parameters
|
|
1203
|
+
----------
|
|
1204
|
+
value
|
|
1205
|
+
The value which will overwrite the current color.
|
|
700
1206
|
|
|
701
|
-
|
|
702
|
-
|
|
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]
|
|
703
1219
|
|
|
704
1220
|
|
|
705
1221
|
ParsableManimColor: TypeAlias = Union[
|
|
@@ -715,76 +1231,84 @@ ParsableManimColor: TypeAlias = Union[
|
|
|
715
1231
|
RGBA_Array_Int,
|
|
716
1232
|
RGBA_Array_Float,
|
|
717
1233
|
]
|
|
718
|
-
"""ParsableManimColor
|
|
1234
|
+
"""`ParsableManimColor` represents all the types which can be parsed
|
|
1235
|
+
to a :class:`ManimColor` in Manim.
|
|
1236
|
+
"""
|
|
719
1237
|
|
|
720
1238
|
|
|
721
1239
|
ManimColorT = TypeVar("ManimColorT", bound=ManimColor)
|
|
722
1240
|
|
|
723
1241
|
|
|
724
1242
|
def color_to_rgb(color: ParsableManimColor) -> RGB_Array_Float:
|
|
725
|
-
"""Helper function for use in functional style programming
|
|
1243
|
+
"""Helper function for use in functional style programming.
|
|
1244
|
+
Refer to :meth:`ManimColor.to_rgb`.
|
|
726
1245
|
|
|
727
1246
|
Parameters
|
|
728
1247
|
----------
|
|
729
|
-
color
|
|
730
|
-
A color
|
|
1248
|
+
color
|
|
1249
|
+
A color to convert to an RGB float array.
|
|
731
1250
|
|
|
732
1251
|
Returns
|
|
733
1252
|
-------
|
|
734
1253
|
RGB_Array_Float
|
|
735
|
-
|
|
1254
|
+
The corresponding RGB float array.
|
|
736
1255
|
"""
|
|
737
1256
|
return ManimColor(color).to_rgb()
|
|
738
1257
|
|
|
739
1258
|
|
|
740
|
-
def color_to_rgba(color: ParsableManimColor, alpha: float = 1) -> RGBA_Array_Float:
|
|
741
|
-
"""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`.
|
|
742
1262
|
|
|
743
1263
|
Parameters
|
|
744
1264
|
----------
|
|
745
|
-
color
|
|
746
|
-
A color
|
|
747
|
-
alpha
|
|
748
|
-
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.
|
|
749
1270
|
|
|
750
1271
|
Returns
|
|
751
1272
|
-------
|
|
752
1273
|
RGBA_Array_Float
|
|
753
|
-
|
|
1274
|
+
The corresponding RGBA float array.
|
|
754
1275
|
"""
|
|
755
1276
|
return ManimColor(color).to_rgba_with_alpha(alpha)
|
|
756
1277
|
|
|
757
1278
|
|
|
758
1279
|
def color_to_int_rgb(color: ParsableManimColor) -> RGB_Array_Int:
|
|
759
|
-
"""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`.
|
|
760
1282
|
|
|
761
1283
|
Parameters
|
|
762
1284
|
----------
|
|
763
|
-
color
|
|
764
|
-
A color
|
|
1285
|
+
color
|
|
1286
|
+
A color to convert to an RGB integer array.
|
|
765
1287
|
|
|
766
1288
|
Returns
|
|
767
1289
|
-------
|
|
768
1290
|
RGB_Array_Int
|
|
769
|
-
|
|
1291
|
+
The corresponding RGB integer array.
|
|
770
1292
|
"""
|
|
771
1293
|
return ManimColor(color).to_int_rgb()
|
|
772
1294
|
|
|
773
1295
|
|
|
774
1296
|
def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Array_Int:
|
|
775
|
-
"""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`.
|
|
776
1299
|
|
|
777
1300
|
Parameters
|
|
778
1301
|
----------
|
|
779
|
-
color
|
|
780
|
-
A color
|
|
781
|
-
alpha
|
|
782
|
-
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.
|
|
783
1307
|
|
|
784
1308
|
Returns
|
|
785
1309
|
-------
|
|
786
1310
|
RGBA_Array_Int
|
|
787
|
-
|
|
1311
|
+
The corresponding RGBA integer array.
|
|
788
1312
|
"""
|
|
789
1313
|
return ManimColor(color).to_int_rgba_with_alpha(alpha)
|
|
790
1314
|
|
|
@@ -792,17 +1316,18 @@ def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Arr
|
|
|
792
1316
|
def rgb_to_color(
|
|
793
1317
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
794
1318
|
) -> ManimColor:
|
|
795
|
-
"""Helper function for use in functional style programming
|
|
1319
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1320
|
+
:meth:`ManimColor.from_rgb`.
|
|
796
1321
|
|
|
797
1322
|
Parameters
|
|
798
1323
|
----------
|
|
799
|
-
rgb
|
|
800
|
-
A 3 element iterable
|
|
1324
|
+
rgb
|
|
1325
|
+
A 3 element iterable.
|
|
801
1326
|
|
|
802
1327
|
Returns
|
|
803
1328
|
-------
|
|
804
1329
|
ManimColor
|
|
805
|
-
A ManimColor with the corresponding value
|
|
1330
|
+
A ManimColor with the corresponding value.
|
|
806
1331
|
"""
|
|
807
1332
|
return ManimColor.from_rgb(rgb)
|
|
808
1333
|
|
|
@@ -810,12 +1335,13 @@ def rgb_to_color(
|
|
|
810
1335
|
def rgba_to_color(
|
|
811
1336
|
rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int,
|
|
812
1337
|
) -> ManimColor:
|
|
813
|
-
"""Helper function for use in functional style programming
|
|
1338
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1339
|
+
:meth:`ManimColor.from_rgba`.
|
|
814
1340
|
|
|
815
1341
|
Parameters
|
|
816
1342
|
----------
|
|
817
|
-
rgba
|
|
818
|
-
A 4 element iterable
|
|
1343
|
+
rgba
|
|
1344
|
+
A 4 element iterable.
|
|
819
1345
|
|
|
820
1346
|
Returns
|
|
821
1347
|
-------
|
|
@@ -828,92 +1354,74 @@ def rgba_to_color(
|
|
|
828
1354
|
def rgb_to_hex(
|
|
829
1355
|
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
830
1356
|
) -> str:
|
|
831
|
-
"""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`.
|
|
832
1359
|
|
|
833
1360
|
Parameters
|
|
834
1361
|
----------
|
|
835
|
-
rgb
|
|
836
|
-
A 3 element iterable
|
|
1362
|
+
rgb
|
|
1363
|
+
A 3 element iterable.
|
|
837
1364
|
|
|
838
1365
|
Returns
|
|
839
1366
|
-------
|
|
840
1367
|
str
|
|
841
|
-
A hex representation of the color
|
|
1368
|
+
A hex representation of the color.
|
|
842
1369
|
"""
|
|
843
1370
|
return ManimColor.from_rgb(rgb).to_hex()
|
|
844
1371
|
|
|
845
1372
|
|
|
846
1373
|
def hex_to_rgb(hex_code: str) -> RGB_Array_Float:
|
|
847
|
-
"""Helper function for use in functional style programming
|
|
1374
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1375
|
+
:meth:`ManimColor.to_rgb`.
|
|
848
1376
|
|
|
849
1377
|
Parameters
|
|
850
1378
|
----------
|
|
851
|
-
hex_code
|
|
852
|
-
A hex string representing a color
|
|
1379
|
+
hex_code
|
|
1380
|
+
A hex string representing a color.
|
|
853
1381
|
|
|
854
1382
|
Returns
|
|
855
1383
|
-------
|
|
856
1384
|
RGB_Array_Float
|
|
857
|
-
RGB array representing the color
|
|
1385
|
+
An RGB array representing the color.
|
|
858
1386
|
"""
|
|
859
1387
|
return ManimColor(hex_code).to_rgb()
|
|
860
1388
|
|
|
861
1389
|
|
|
862
1390
|
def invert_color(color: ManimColorT) -> ManimColorT:
|
|
863
|
-
"""Helper function for use in functional style programming
|
|
1391
|
+
"""Helper function for use in functional style programming. Refer to
|
|
1392
|
+
:meth:`ManimColor.invert`
|
|
864
1393
|
|
|
865
1394
|
Parameters
|
|
866
1395
|
----------
|
|
867
|
-
color
|
|
868
|
-
|
|
1396
|
+
color
|
|
1397
|
+
The :class:`ManimColor` to invert.
|
|
869
1398
|
|
|
870
1399
|
Returns
|
|
871
1400
|
-------
|
|
872
1401
|
ManimColor
|
|
873
|
-
The linearly inverted ManimColor
|
|
1402
|
+
The linearly inverted :class:`ManimColor`.
|
|
874
1403
|
"""
|
|
875
1404
|
return color.invert()
|
|
876
1405
|
|
|
877
1406
|
|
|
878
|
-
def interpolate_arrays(
|
|
879
|
-
arr1: npt.NDArray[Any], arr2: npt.NDArray[Any], alpha: float
|
|
880
|
-
) -> np.ndarray:
|
|
881
|
-
"""Helper function used in Manim to fade between two objects smoothly
|
|
882
|
-
|
|
883
|
-
Parameters
|
|
884
|
-
----------
|
|
885
|
-
arr1 : npt.NDArray[Any]
|
|
886
|
-
The first array of colors
|
|
887
|
-
arr2 : npt.NDArray[Any]
|
|
888
|
-
The second array of colors
|
|
889
|
-
alpha : float
|
|
890
|
-
The alpha value corresponding to the interpolation point between the two inputs
|
|
891
|
-
|
|
892
|
-
Returns
|
|
893
|
-
-------
|
|
894
|
-
np.ndarray
|
|
895
|
-
The interpolated value of the to arrays
|
|
896
|
-
"""
|
|
897
|
-
return (1 - alpha) * arr1 + alpha * arr2
|
|
898
|
-
|
|
899
|
-
|
|
900
1407
|
def color_gradient(
|
|
901
1408
|
reference_colors: Sequence[ParsableManimColor],
|
|
902
1409
|
length_of_output: int,
|
|
903
1410
|
) -> list[ManimColor] | ManimColor:
|
|
904
|
-
"""
|
|
1411
|
+
"""Create a list of colors interpolated between the input array of colors with a
|
|
1412
|
+
specific number of colors.
|
|
905
1413
|
|
|
906
1414
|
Parameters
|
|
907
1415
|
----------
|
|
908
|
-
reference_colors
|
|
909
|
-
The colors to be interpolated between or spread apart
|
|
910
|
-
length_of_output
|
|
911
|
-
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.
|
|
912
1420
|
|
|
913
1421
|
Returns
|
|
914
1422
|
-------
|
|
915
1423
|
list[ManimColor] | ManimColor
|
|
916
|
-
A list of ManimColor's
|
|
1424
|
+
A :class:`ManimColor` or a list of interpolated :class:`ManimColor`'s.
|
|
917
1425
|
"""
|
|
918
1426
|
if length_of_output == 0:
|
|
919
1427
|
return ManimColor(reference_colors[0])
|
|
@@ -933,34 +1441,39 @@ def color_gradient(
|
|
|
933
1441
|
|
|
934
1442
|
|
|
935
1443
|
def interpolate_color(
|
|
936
|
-
color1: ManimColorT, color2:
|
|
1444
|
+
color1: ManimColorT, color2: ManimColorT, alpha: float
|
|
937
1445
|
) -> ManimColorT:
|
|
938
|
-
"""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`.
|
|
939
1448
|
|
|
940
1449
|
Parameters
|
|
941
1450
|
----------
|
|
942
|
-
color1
|
|
943
|
-
|
|
944
|
-
color2
|
|
945
|
-
|
|
946
|
-
alpha
|
|
947
|
-
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.
|
|
948
1457
|
|
|
949
1458
|
Returns
|
|
950
1459
|
-------
|
|
951
1460
|
ManimColor
|
|
952
|
-
The interpolated ManimColor
|
|
1461
|
+
The interpolated ManimColor.
|
|
953
1462
|
"""
|
|
954
1463
|
return color1.interpolate(color2, alpha)
|
|
955
1464
|
|
|
956
1465
|
|
|
957
1466
|
def average_color(*colors: ParsableManimColor) -> ManimColor:
|
|
958
|
-
"""
|
|
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.
|
|
959
1472
|
|
|
960
1473
|
Returns
|
|
961
1474
|
-------
|
|
962
1475
|
ManimColor
|
|
963
|
-
The average color of the input
|
|
1476
|
+
The average color of the input.
|
|
964
1477
|
"""
|
|
965
1478
|
rgbs = np.array([color_to_rgb(color) for color in colors])
|
|
966
1479
|
mean_rgb = np.apply_along_axis(np.mean, 0, rgbs)
|
|
@@ -968,31 +1481,31 @@ def average_color(*colors: ParsableManimColor) -> ManimColor:
|
|
|
968
1481
|
|
|
969
1482
|
|
|
970
1483
|
def random_bright_color() -> ManimColor:
|
|
971
|
-
"""
|
|
1484
|
+
"""Return a random bright color: a random color averaged with ``WHITE``.
|
|
972
1485
|
|
|
973
1486
|
.. warning::
|
|
974
|
-
This operation is very expensive
|
|
1487
|
+
This operation is very expensive. Please keep in mind the performance loss.
|
|
975
1488
|
|
|
976
1489
|
Returns
|
|
977
1490
|
-------
|
|
978
1491
|
ManimColor
|
|
979
|
-
A bright ManimColor
|
|
1492
|
+
A random bright :class:`ManimColor`.
|
|
980
1493
|
"""
|
|
981
1494
|
curr_rgb = color_to_rgb(random_color())
|
|
982
|
-
new_rgb =
|
|
1495
|
+
new_rgb = 0.5 * (curr_rgb + np.ones(3))
|
|
983
1496
|
return ManimColor(new_rgb)
|
|
984
1497
|
|
|
985
1498
|
|
|
986
1499
|
def random_color() -> ManimColor:
|
|
987
|
-
"""Return
|
|
1500
|
+
"""Return a random :class:`ManimColor`.
|
|
988
1501
|
|
|
989
1502
|
.. warning::
|
|
990
|
-
This operation is very expensive
|
|
1503
|
+
This operation is very expensive. Please keep in mind the performance loss.
|
|
991
1504
|
|
|
992
1505
|
Returns
|
|
993
1506
|
-------
|
|
994
1507
|
ManimColor
|
|
995
|
-
|
|
1508
|
+
A random :class:`ManimColor`.
|
|
996
1509
|
"""
|
|
997
1510
|
import manim.utils.color.manim_colors as manim_colors
|
|
998
1511
|
|
|
@@ -1000,17 +1513,38 @@ def random_color() -> ManimColor:
|
|
|
1000
1513
|
|
|
1001
1514
|
|
|
1002
1515
|
def get_shaded_rgb(
|
|
1003
|
-
rgb:
|
|
1004
|
-
point:
|
|
1005
|
-
unit_normal_vect:
|
|
1006
|
-
light_source:
|
|
1007
|
-
) ->
|
|
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
|
+
"""
|
|
1008
1542
|
to_sun = normalize(light_source - point)
|
|
1009
|
-
|
|
1010
|
-
if
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
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
|
|
1014
1548
|
|
|
1015
1549
|
|
|
1016
1550
|
__all__ = [
|
|
@@ -1026,11 +1560,12 @@ __all__ = [
|
|
|
1026
1560
|
"rgb_to_hex",
|
|
1027
1561
|
"hex_to_rgb",
|
|
1028
1562
|
"invert_color",
|
|
1029
|
-
"interpolate_arrays",
|
|
1030
1563
|
"color_gradient",
|
|
1031
1564
|
"interpolate_color",
|
|
1032
1565
|
"average_color",
|
|
1033
1566
|
"random_bright_color",
|
|
1034
1567
|
"random_color",
|
|
1035
1568
|
"get_shaded_rgb",
|
|
1569
|
+
"HSV",
|
|
1570
|
+
"RGBA",
|
|
1036
1571
|
]
|