manim 0.17.3__py3-none-any.whl → 0.18.0.post0__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 +1 -0
- manim/__main__.py +2 -0
- manim/_config/__init__.py +0 -1
- manim/_config/logger_utils.py +1 -0
- manim/_config/utils.py +14 -5
- manim/animation/changing.py +9 -5
- manim/animation/creation.py +8 -3
- manim/animation/indication.py +4 -4
- manim/animation/speedmodifier.py +2 -4
- manim/animation/updaters/mobject_update_utils.py +134 -16
- manim/camera/camera.py +31 -17
- manim/cli/checkhealth/__init__.py +0 -0
- manim/cli/checkhealth/checks.py +173 -0
- manim/cli/checkhealth/commands.py +81 -0
- manim/cli/render/global_options.py +6 -0
- manim/constants.py +58 -54
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +126 -91
- manim/mobject/geometry/boolean_ops.py +6 -10
- manim/mobject/geometry/labeled.py +155 -0
- manim/mobject/geometry/line.py +66 -50
- manim/mobject/geometry/polygram.py +23 -15
- manim/mobject/geometry/shape_matchers.py +24 -15
- manim/mobject/geometry/tips.py +62 -40
- manim/mobject/graph.py +3 -4
- manim/mobject/graphing/coordinate_systems.py +190 -139
- manim/mobject/graphing/number_line.py +5 -2
- manim/mobject/graphing/probability.py +4 -3
- manim/mobject/graphing/scale.py +7 -7
- manim/mobject/logo.py +108 -22
- manim/mobject/matrix.py +33 -37
- manim/mobject/mobject.py +327 -260
- manim/mobject/opengl/opengl_image_mobject.py +1 -1
- manim/mobject/opengl/opengl_mobject.py +18 -12
- manim/mobject/opengl/opengl_point_cloud_mobject.py +1 -1
- manim/mobject/opengl/opengl_surface.py +1 -1
- manim/mobject/opengl/opengl_vectorized_mobject.py +21 -17
- manim/mobject/svg/brace.py +3 -1
- manim/mobject/svg/svg_mobject.py +9 -11
- manim/mobject/table.py +50 -54
- manim/mobject/text/numbers.py +48 -6
- manim/mobject/text/tex_mobject.py +8 -12
- manim/mobject/text/text_mobject.py +32 -24
- manim/mobject/three_d/three_d_utils.py +13 -8
- manim/mobject/three_d/three_dimensions.py +61 -43
- manim/mobject/types/image_mobject.py +5 -4
- manim/mobject/types/point_cloud_mobject.py +8 -6
- manim/mobject/types/vectorized_mobject.py +385 -258
- manim/mobject/vector_field.py +19 -11
- manim/plugins/import_plugins.py +1 -1
- manim/plugins/plugins_flags.py +1 -6
- manim/renderer/shader.py +2 -2
- manim/scene/scene.py +15 -7
- manim/scene/scene_file_writer.py +1 -2
- manim/scene/three_d_scene.py +1 -1
- manim/scene/vector_space_scene.py +17 -7
- manim/typing.py +133 -0
- manim/utils/bezier.py +267 -83
- manim/utils/color/AS2700.py +234 -0
- manim/utils/color/BS381.py +315 -0
- manim/utils/color/X11.py +530 -0
- manim/utils/color/XKCD.py +949 -0
- manim/utils/color/__init__.py +58 -0
- manim/utils/color/core.py +1036 -0
- manim/utils/color/manim_colors.py +220 -0
- manim/utils/docbuild/autocolor_directive.py +92 -0
- manim/utils/docbuild/manim_directive.py +40 -6
- manim/utils/file_ops.py +1 -1
- manim/utils/hashing.py +1 -1
- manim/utils/iterables.py +1 -1
- manim/utils/rate_functions.py +33 -0
- manim/utils/simple_functions.py +0 -18
- manim/utils/space_ops.py +55 -42
- manim/utils/testing/frames_comparison.py +9 -0
- manim/utils/tex.py +2 -0
- manim/utils/tex_file_writing.py +29 -2
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/METADATA +14 -14
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/RECORD +82 -71
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/WHEEL +1 -1
- manim/communitycolors.py +0 -9
- manim/utils/color.py +0 -552
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE +0 -0
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE.community +0 -0
- {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,1036 @@
|
|
|
1
|
+
"""Manim's (internal) color data structure and some utilities for
|
|
2
|
+
color conversion.
|
|
3
|
+
|
|
4
|
+
This module contains the implementation of :class:`.ManimColor`,
|
|
5
|
+
the data structure internally used to represent colors.
|
|
6
|
+
|
|
7
|
+
The preferred way of using these colors is by importing their constants from manim:
|
|
8
|
+
|
|
9
|
+
.. code-block:: pycon
|
|
10
|
+
|
|
11
|
+
>>> from manim import RED, GREEN, BLUE
|
|
12
|
+
>>> print(RED)
|
|
13
|
+
#FC6255
|
|
14
|
+
|
|
15
|
+
Note this way uses the name of the colors in UPPERCASE.
|
|
16
|
+
|
|
17
|
+
.. note::
|
|
18
|
+
|
|
19
|
+
The colors of type "C" have an alias equal to the colorname without a letter,
|
|
20
|
+
e.g. GREEN = GREEN_C
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import colorsys
|
|
26
|
+
|
|
27
|
+
# logger = _config.logger
|
|
28
|
+
import random
|
|
29
|
+
import re
|
|
30
|
+
from typing import Any, Sequence, TypeVar, Union, overload
|
|
31
|
+
|
|
32
|
+
import numpy as np
|
|
33
|
+
import numpy.typing as npt
|
|
34
|
+
from typing_extensions import Self, TypeAlias
|
|
35
|
+
|
|
36
|
+
from manim.typing import (
|
|
37
|
+
HSV_Array_Float,
|
|
38
|
+
HSV_Tuple_Float,
|
|
39
|
+
ManimColorDType,
|
|
40
|
+
ManimColorInternal,
|
|
41
|
+
RGB_Array_Float,
|
|
42
|
+
RGB_Array_Int,
|
|
43
|
+
RGB_Tuple_Float,
|
|
44
|
+
RGB_Tuple_Int,
|
|
45
|
+
RGBA_Array_Float,
|
|
46
|
+
RGBA_Array_Int,
|
|
47
|
+
RGBA_Tuple_Float,
|
|
48
|
+
RGBA_Tuple_Int,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from ...utils.space_ops import normalize
|
|
52
|
+
|
|
53
|
+
# import manim._config as _config
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{6,8}", re.IGNORECASE)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ManimColor:
|
|
60
|
+
"""Internal representation of a color.
|
|
61
|
+
|
|
62
|
+
The ManimColor class is the main class for the representation of a color.
|
|
63
|
+
It's internal representation is a 4 element array of floats corresponding
|
|
64
|
+
to a [r,g,b,a] value where r,g,b,a can be between 0 to 1.
|
|
65
|
+
|
|
66
|
+
This is done in order to reduce the amount of color inconsitencies by constantly
|
|
67
|
+
casting between integers and floats which introduces errors.
|
|
68
|
+
|
|
69
|
+
The class can accept any value of type :class:`ParsableManimColor` i.e.
|
|
70
|
+
|
|
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
|
|
73
|
+
|
|
74
|
+
ManimColor itself only accepts singular values and will directly interpret them into a single color if possible
|
|
75
|
+
Be careful when passing strings to ManimColor it can create a big overhead for the color processing.
|
|
76
|
+
|
|
77
|
+
If you want to parse a list of colors use the function :meth:`parse` in :class:`ManimColor` which assumes that
|
|
78
|
+
you are going to pass a list of color so arrays will not bei interpreted as a single color.
|
|
79
|
+
|
|
80
|
+
.. warning::
|
|
81
|
+
If you pass an array of numbers to :meth:`parse` it will interpret the r,g,b,a numbers in that array as colors
|
|
82
|
+
so instead of the expect singular color you get and array with 4 colors.
|
|
83
|
+
|
|
84
|
+
For conversion behaviors see the _internal functions for further documentation
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
value
|
|
89
|
+
Some representation of a color (e.g., a string or
|
|
90
|
+
a suitable tuple).
|
|
91
|
+
alpha
|
|
92
|
+
The opacity of the color. By default, colors are
|
|
93
|
+
fully opaque (value 1.0).
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def __init__(
|
|
97
|
+
self,
|
|
98
|
+
value: ParsableManimColor | None,
|
|
99
|
+
alpha: float = 1.0,
|
|
100
|
+
) -> None:
|
|
101
|
+
if value is None:
|
|
102
|
+
self._internal_value = np.array((0, 0, 0, alpha), dtype=ManimColorDType)
|
|
103
|
+
elif isinstance(value, ManimColor):
|
|
104
|
+
# logger.info(
|
|
105
|
+
# "ManimColor was passed another ManimColor. This is probably not what "
|
|
106
|
+
# "you want. Created a copy of the passed ManimColor instead."
|
|
107
|
+
# )
|
|
108
|
+
self._internal_value = value._internal_value
|
|
109
|
+
elif isinstance(value, int):
|
|
110
|
+
self._internal_value = ManimColor._internal_from_integer(value, alpha)
|
|
111
|
+
elif isinstance(value, str):
|
|
112
|
+
result = re_hex.search(value)
|
|
113
|
+
if result is not None:
|
|
114
|
+
self._internal_value = ManimColor._internal_from_hex_string(
|
|
115
|
+
result.group(), alpha
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
# This is not expected to be called on module initialization time
|
|
119
|
+
# It can be horribly slow to convert a string to a color because
|
|
120
|
+
# it has to access the dictionary of colors and find the right color
|
|
121
|
+
self._internal_value = ManimColor._internal_from_string(value)
|
|
122
|
+
elif isinstance(value, (list, tuple, np.ndarray)):
|
|
123
|
+
length = len(value)
|
|
124
|
+
if all(isinstance(x, float) for x in value):
|
|
125
|
+
if length == 3:
|
|
126
|
+
self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore
|
|
127
|
+
elif length == 4:
|
|
128
|
+
self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore
|
|
129
|
+
else:
|
|
130
|
+
raise ValueError(
|
|
131
|
+
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
if length == 3:
|
|
135
|
+
self._internal_value = ManimColor._internal_from_int_rgb(
|
|
136
|
+
value, alpha # type: ignore
|
|
137
|
+
)
|
|
138
|
+
elif length == 4:
|
|
139
|
+
self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore
|
|
140
|
+
else:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}"
|
|
143
|
+
)
|
|
144
|
+
elif hasattr(value, "get_hex") and callable(value.get_hex):
|
|
145
|
+
result = re_hex.search(value.get_hex())
|
|
146
|
+
if result is None:
|
|
147
|
+
raise ValueError(f"Failed to parse a color from {value}")
|
|
148
|
+
|
|
149
|
+
self._internal_value = ManimColor._internal_from_hex_string(
|
|
150
|
+
result.group(), alpha
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
# logger.error(f"Invalid color value: {value}")
|
|
154
|
+
raise TypeError(
|
|
155
|
+
"ManimColor only accepts int, str, list[int, int, int], "
|
|
156
|
+
"list[int, int, int, int], list[float, float, float], "
|
|
157
|
+
f"list[float, float, float, float], not {type(value)}"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def _internal_value(self) -> ManimColorInternal:
|
|
162
|
+
"""Returns the internal value of the current Manim color [r,g,b,a] float array
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
ManimColorInternal
|
|
167
|
+
internal color representation
|
|
168
|
+
"""
|
|
169
|
+
return self.__value
|
|
170
|
+
|
|
171
|
+
@_internal_value.setter
|
|
172
|
+
def _internal_value(self, value: ManimColorInternal) -> None:
|
|
173
|
+
"""Overwrites the internal color value of the ManimColor object
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
value : ManimColorInternal
|
|
178
|
+
The value which will overwrite the current color
|
|
179
|
+
|
|
180
|
+
Raises
|
|
181
|
+
------
|
|
182
|
+
TypeError
|
|
183
|
+
Raises a TypeError if an invalid array is passed
|
|
184
|
+
"""
|
|
185
|
+
if not isinstance(value, np.ndarray):
|
|
186
|
+
raise TypeError("value must be a numpy array")
|
|
187
|
+
if value.shape[0] != 4:
|
|
188
|
+
raise TypeError("Array must have 4 values exactly")
|
|
189
|
+
self.__value: ManimColorInternal = value
|
|
190
|
+
|
|
191
|
+
@staticmethod
|
|
192
|
+
def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal:
|
|
193
|
+
return np.asarray(
|
|
194
|
+
(
|
|
195
|
+
((value >> 16) & 0xFF) / 255,
|
|
196
|
+
((value >> 8) & 0xFF) / 255,
|
|
197
|
+
((value >> 0) & 0xFF) / 255,
|
|
198
|
+
alpha,
|
|
199
|
+
),
|
|
200
|
+
dtype=ManimColorDType,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# TODO: Maybe make 8 nibble hex also convertible ?
|
|
204
|
+
@staticmethod
|
|
205
|
+
def _internal_from_hex_string(hex: str, alpha: float) -> ManimColorInternal:
|
|
206
|
+
"""Internal function for converting a hex string into the internal representation of a ManimColor.
|
|
207
|
+
|
|
208
|
+
.. warning::
|
|
209
|
+
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
|
|
211
|
+
|
|
212
|
+
*For internal use only*
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
hex : str
|
|
217
|
+
hex string to be parsed
|
|
218
|
+
alpha : float
|
|
219
|
+
alpha value used for the color
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
ManimColorInternal
|
|
224
|
+
Internal color representation
|
|
225
|
+
"""
|
|
226
|
+
if len(hex) == 6:
|
|
227
|
+
hex += "00"
|
|
228
|
+
tmp = int(hex, 16)
|
|
229
|
+
return np.asarray(
|
|
230
|
+
(
|
|
231
|
+
((tmp >> 24) & 0xFF) / 255,
|
|
232
|
+
((tmp >> 16) & 0xFF) / 255,
|
|
233
|
+
((tmp >> 8) & 0xFF) / 255,
|
|
234
|
+
alpha,
|
|
235
|
+
),
|
|
236
|
+
dtype=ManimColorDType,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
@staticmethod
|
|
240
|
+
def _internal_from_int_rgb(
|
|
241
|
+
rgb: RGB_Tuple_Int, alpha: float = 1.0
|
|
242
|
+
) -> ManimColorInternal:
|
|
243
|
+
"""Internal function for converting a rgb tuple of integers into the internal representation of a ManimColor.
|
|
244
|
+
|
|
245
|
+
*For internal use only*
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
rgb : RGB_Tuple_Int
|
|
250
|
+
integer rgb tuple to be parsed
|
|
251
|
+
alpha : float, optional
|
|
252
|
+
optional alpha value, by default 1.0
|
|
253
|
+
|
|
254
|
+
Returns
|
|
255
|
+
-------
|
|
256
|
+
ManimColorInternal
|
|
257
|
+
Internal color representation
|
|
258
|
+
|
|
259
|
+
"""
|
|
260
|
+
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy() / 255
|
|
261
|
+
value.resize(4, refcheck=False)
|
|
262
|
+
value[3] = alpha
|
|
263
|
+
return value
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def _internal_from_rgb(
|
|
267
|
+
rgb: RGB_Tuple_Float, alpha: float = 1.0
|
|
268
|
+
) -> ManimColorInternal:
|
|
269
|
+
"""Internal function for converting a rgb tuple of floats into the internal representation of a ManimColor.
|
|
270
|
+
|
|
271
|
+
*For internal use only*
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
rgb : RGB_Tuple_Float
|
|
276
|
+
float rgb tuple to be parsed
|
|
277
|
+
|
|
278
|
+
alpha : float, optional
|
|
279
|
+
optional alpha value, by default 1.0
|
|
280
|
+
|
|
281
|
+
Returns
|
|
282
|
+
-------
|
|
283
|
+
ManimColorInternal
|
|
284
|
+
Internal color representation
|
|
285
|
+
"""
|
|
286
|
+
value: np.ndarray = np.asarray(rgb, dtype=ManimColorDType).copy()
|
|
287
|
+
value.resize(4, refcheck=False)
|
|
288
|
+
value[3] = alpha
|
|
289
|
+
return value
|
|
290
|
+
|
|
291
|
+
@staticmethod
|
|
292
|
+
def _internal_from_int_rgba(rgba: RGBA_Tuple_Int) -> ManimColorInternal:
|
|
293
|
+
"""Internal function for converting a rgba tuple of integers into the internal representation of a ManimColor.
|
|
294
|
+
|
|
295
|
+
*For internal use only*
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
rgba : RGBA_Tuple_Int
|
|
300
|
+
int rgba tuple to be parsed
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
ManimColorInternal
|
|
305
|
+
Internal color representation
|
|
306
|
+
"""
|
|
307
|
+
return np.asarray(rgba, dtype=ManimColorDType) / 255
|
|
308
|
+
|
|
309
|
+
@staticmethod
|
|
310
|
+
def _internal_from_rgba(rgba: RGBA_Tuple_Float) -> ManimColorInternal:
|
|
311
|
+
"""Internal function for converting a rgba tuple of floats into the internal representation of a ManimColor.
|
|
312
|
+
|
|
313
|
+
*For internal use only*
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
rgba : RGBA_Tuple_Float
|
|
318
|
+
int rgba tuple to be parsed
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
ManimColorInternal
|
|
323
|
+
Internal color representation
|
|
324
|
+
"""
|
|
325
|
+
return np.asarray(rgba, dtype=ManimColorDType)
|
|
326
|
+
|
|
327
|
+
@staticmethod
|
|
328
|
+
def _internal_from_string(name: str) -> ManimColorInternal:
|
|
329
|
+
"""Internal function for converting a string into the internal representation of a ManimColor.
|
|
330
|
+
This is not used for hex strings, please refer to :meth:`_internal_from_hex` for this functionality.
|
|
331
|
+
|
|
332
|
+
*For internal use only*
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
name : str
|
|
337
|
+
The color name to be parsed into a color. Refer to the different color Modules in the documentation Page to
|
|
338
|
+
find the corresponding Color names.
|
|
339
|
+
|
|
340
|
+
Returns
|
|
341
|
+
-------
|
|
342
|
+
ManimColorInternal
|
|
343
|
+
Internal color representation
|
|
344
|
+
|
|
345
|
+
Raises
|
|
346
|
+
------
|
|
347
|
+
ValueError
|
|
348
|
+
Raises a ValueError if the color name is not present with manim
|
|
349
|
+
"""
|
|
350
|
+
from . import _all_color_dict
|
|
351
|
+
|
|
352
|
+
upper_name = name.upper()
|
|
353
|
+
|
|
354
|
+
if upper_name in _all_color_dict:
|
|
355
|
+
return _all_color_dict[upper_name]._internal_value
|
|
356
|
+
else:
|
|
357
|
+
raise ValueError(f"Color {name} not found")
|
|
358
|
+
|
|
359
|
+
def to_integer(self) -> int:
|
|
360
|
+
"""Converts the current ManimColor into an integer
|
|
361
|
+
|
|
362
|
+
Returns
|
|
363
|
+
-------
|
|
364
|
+
int
|
|
365
|
+
integer representation of the color
|
|
366
|
+
|
|
367
|
+
.. warning::
|
|
368
|
+
This will return only the rgb part of the color
|
|
369
|
+
"""
|
|
370
|
+
return int.from_bytes(
|
|
371
|
+
(self._internal_value[:3] * 255).astype(int).tobytes(), "big"
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def to_rgb(self) -> RGB_Array_Float:
|
|
375
|
+
"""Converts the current ManimColor into a rgb array of floats
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
RGB_Array_Float
|
|
380
|
+
rgb array with 3 elements of type float
|
|
381
|
+
"""
|
|
382
|
+
return self._internal_value[:3]
|
|
383
|
+
|
|
384
|
+
def to_int_rgb(self) -> RGB_Array_Int:
|
|
385
|
+
"""Converts the current ManimColor into a rgb array of int
|
|
386
|
+
|
|
387
|
+
Returns
|
|
388
|
+
-------
|
|
389
|
+
RGB_Array_Int
|
|
390
|
+
rgb array with 3 elements of type int
|
|
391
|
+
"""
|
|
392
|
+
return (self._internal_value[:3] * 255).astype(int)
|
|
393
|
+
|
|
394
|
+
def to_rgba(self) -> RGBA_Array_Float:
|
|
395
|
+
"""Converts the current ManimColor into a rgba array of floats
|
|
396
|
+
|
|
397
|
+
Returns
|
|
398
|
+
-------
|
|
399
|
+
RGBA_Array_Float
|
|
400
|
+
rgba array with 4 elements of type float
|
|
401
|
+
"""
|
|
402
|
+
return self._internal_value
|
|
403
|
+
|
|
404
|
+
def to_int_rgba(self) -> RGBA_Array_Int:
|
|
405
|
+
"""Converts the current ManimColor into a rgba array of int
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
Returns
|
|
409
|
+
-------
|
|
410
|
+
RGBA_Array_Int
|
|
411
|
+
rgba array with 4 elements of type int
|
|
412
|
+
"""
|
|
413
|
+
return (self._internal_value * 255).astype(int)
|
|
414
|
+
|
|
415
|
+
def to_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Float:
|
|
416
|
+
"""Converts the current ManimColor into a rgba array of float as :meth:`to_rgba` but you can change the alpha
|
|
417
|
+
value.
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
alpha : float
|
|
422
|
+
alpha value to be used in the return value
|
|
423
|
+
|
|
424
|
+
Returns
|
|
425
|
+
-------
|
|
426
|
+
RGBA_Array_Float
|
|
427
|
+
rgba array with 4 elements of type float
|
|
428
|
+
"""
|
|
429
|
+
return np.fromiter((*self._internal_value[:3], alpha), dtype=ManimColorDType)
|
|
430
|
+
|
|
431
|
+
def to_int_rgba_with_alpha(self, alpha: float) -> RGBA_Array_Int:
|
|
432
|
+
"""Converts the current ManimColor into a rgba array of integers as :meth:`to_int_rgba` but you can change the alpha
|
|
433
|
+
value.
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
alpha : float
|
|
438
|
+
alpha value to be used for the return value. (Will automatically be scaled from 0-1 to 0-255 so just pass 0-1)
|
|
439
|
+
|
|
440
|
+
Returns
|
|
441
|
+
-------
|
|
442
|
+
RGBA_Array_Int
|
|
443
|
+
rgba array with 4 elements of type int
|
|
444
|
+
"""
|
|
445
|
+
tmp = self._internal_value * 255
|
|
446
|
+
tmp[3] = alpha * 255
|
|
447
|
+
return tmp.astype(int)
|
|
448
|
+
|
|
449
|
+
def to_hex(self, with_alpha: bool = False) -> str:
|
|
450
|
+
"""Converts the manim color to a hexadecimal representation of the color
|
|
451
|
+
|
|
452
|
+
Parameters
|
|
453
|
+
----------
|
|
454
|
+
with_alpha : bool, optional
|
|
455
|
+
Changes the result from 6 to 8 values where the last 2 nibbles represent the alpha value of 0-255,
|
|
456
|
+
by default False
|
|
457
|
+
|
|
458
|
+
Returns
|
|
459
|
+
-------
|
|
460
|
+
str
|
|
461
|
+
A hex string starting with a # with either 6 or 8 nibbles depending on your input, by default 6 i.e #XXXXXX
|
|
462
|
+
"""
|
|
463
|
+
tmp = f"#{int(self._internal_value[0]*255):02X}{int(self._internal_value[1]*255):02X}{int(self._internal_value[2]*255):02X}"
|
|
464
|
+
if with_alpha:
|
|
465
|
+
tmp += f"{int(self._internal_value[3]*255):02X}"
|
|
466
|
+
return tmp
|
|
467
|
+
|
|
468
|
+
def to_hsv(self) -> HSV_Array_Float:
|
|
469
|
+
"""Converts the Manim Color to HSV array.
|
|
470
|
+
|
|
471
|
+
.. note::
|
|
472
|
+
Be careful this returns an array in the form `[h, s, v]` where the elements are floats.
|
|
473
|
+
This might be confusing because rgb can also be an array of floats so you might want to annotate the usage
|
|
474
|
+
of this function in your code by typing the variables with :class:`HSV_Array_Float` in order to differentiate
|
|
475
|
+
between rgb arrays and hsv arrays
|
|
476
|
+
|
|
477
|
+
Returns
|
|
478
|
+
-------
|
|
479
|
+
HSV_Array_Float
|
|
480
|
+
A hsv array containing 3 elements of type float ranging from 0 to 1
|
|
481
|
+
"""
|
|
482
|
+
return colorsys.rgb_to_hsv(*self.to_rgb())
|
|
483
|
+
|
|
484
|
+
def invert(self, with_alpha=False) -> ManimColor:
|
|
485
|
+
"""Returns an linearly inverted version of the color (no inplace changes)
|
|
486
|
+
|
|
487
|
+
Parameters
|
|
488
|
+
----------
|
|
489
|
+
with_alpha : bool, optional
|
|
490
|
+
if true the alpha value will be inverted too, by default False
|
|
491
|
+
|
|
492
|
+
.. note::
|
|
493
|
+
This can result in unintended behavior where objects are not displayed because their alpha
|
|
494
|
+
value is suddenly 0 or very low. Please keep that in mind when setting this to true
|
|
495
|
+
|
|
496
|
+
Returns
|
|
497
|
+
-------
|
|
498
|
+
ManimColor
|
|
499
|
+
The linearly inverted ManimColor
|
|
500
|
+
"""
|
|
501
|
+
return ManimColor(1.0 - self._internal_value, with_alpha)
|
|
502
|
+
|
|
503
|
+
def interpolate(self, other: ManimColor, alpha: float) -> ManimColor:
|
|
504
|
+
"""Interpolates between the current and the given ManimColor an returns the interpolated color
|
|
505
|
+
|
|
506
|
+
Parameters
|
|
507
|
+
----------
|
|
508
|
+
other : ManimColor
|
|
509
|
+
The other ManimColor to be used for interpolation
|
|
510
|
+
alpha : float
|
|
511
|
+
A point on the line in rgba colorspace connecting the two colors i.e. the interpolation point
|
|
512
|
+
|
|
513
|
+
0 corresponds to the current ManimColor and 1 corresponds to the other ManimColor
|
|
514
|
+
|
|
515
|
+
Returns
|
|
516
|
+
-------
|
|
517
|
+
ManimColor
|
|
518
|
+
The interpolated ManimColor
|
|
519
|
+
"""
|
|
520
|
+
return ManimColor(
|
|
521
|
+
self._internal_value * (1 - alpha) + other._internal_value * alpha
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
@classmethod
|
|
525
|
+
def from_rgb(
|
|
526
|
+
cls,
|
|
527
|
+
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
528
|
+
alpha: float = 1.0,
|
|
529
|
+
) -> Self:
|
|
530
|
+
"""Creates a ManimColor from an RGB Array. Automagically decides which type it is int/float
|
|
531
|
+
|
|
532
|
+
.. warning::
|
|
533
|
+
Please make sure that your elements are not floats if you want integers. A 5.0 will result in the input
|
|
534
|
+
being interpreted as if it was a float rgb array with the value 5.0 and not the integer 5
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
Parameters
|
|
538
|
+
----------
|
|
539
|
+
rgb : RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int
|
|
540
|
+
Any 3 Element Iterable
|
|
541
|
+
alpha : float, optional
|
|
542
|
+
alpha value to be used in the color, by default 1.0
|
|
543
|
+
|
|
544
|
+
Returns
|
|
545
|
+
-------
|
|
546
|
+
ManimColor
|
|
547
|
+
Returns the ManimColor object
|
|
548
|
+
"""
|
|
549
|
+
return cls(rgb, alpha)
|
|
550
|
+
|
|
551
|
+
@classmethod
|
|
552
|
+
def from_rgba(
|
|
553
|
+
cls, rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int
|
|
554
|
+
) -> Self:
|
|
555
|
+
"""Creates a ManimColor from an RGBA Array. Automagically decides which type it is int/float
|
|
556
|
+
|
|
557
|
+
.. warning::
|
|
558
|
+
Please make sure that your elements are not floats if you want integers. A 5.0 will result in the input
|
|
559
|
+
being interpreted as if it was a float rgb array with the value 5.0 and not the integer 5
|
|
560
|
+
|
|
561
|
+
Parameters
|
|
562
|
+
----------
|
|
563
|
+
rgba : RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int
|
|
564
|
+
Any 4 Element Iterable
|
|
565
|
+
|
|
566
|
+
Returns
|
|
567
|
+
-------
|
|
568
|
+
ManimColor
|
|
569
|
+
Returns the ManimColor object
|
|
570
|
+
"""
|
|
571
|
+
return cls(rgba)
|
|
572
|
+
|
|
573
|
+
@classmethod
|
|
574
|
+
def from_hex(cls, hex: str, alpha: float = 1.0) -> Self:
|
|
575
|
+
"""Creates a Manim Color from a hex string, prefixes allowed # and 0x
|
|
576
|
+
|
|
577
|
+
Parameters
|
|
578
|
+
----------
|
|
579
|
+
hex : str
|
|
580
|
+
The hex string to be converted (currently only supports 6 nibbles)
|
|
581
|
+
alpha : float, optional
|
|
582
|
+
alpha value to be used for the hex string, by default 1.0
|
|
583
|
+
|
|
584
|
+
Returns
|
|
585
|
+
-------
|
|
586
|
+
ManimColor
|
|
587
|
+
The ManimColor represented by the hex string
|
|
588
|
+
"""
|
|
589
|
+
return cls(hex, alpha)
|
|
590
|
+
|
|
591
|
+
@classmethod
|
|
592
|
+
def from_hsv(
|
|
593
|
+
cls, hsv: HSV_Array_Float | HSV_Tuple_Float, alpha: float = 1.0
|
|
594
|
+
) -> Self:
|
|
595
|
+
"""Creates a ManimColor from an HSV Array
|
|
596
|
+
|
|
597
|
+
Parameters
|
|
598
|
+
----------
|
|
599
|
+
hsv : HSV_Array_Float | HSV_Tuple_Float
|
|
600
|
+
Any 3 Element Iterable containing floats from 0-1
|
|
601
|
+
alpha : float, optional
|
|
602
|
+
the alpha value to be used, by default 1.0
|
|
603
|
+
|
|
604
|
+
Returns
|
|
605
|
+
-------
|
|
606
|
+
ManimColor
|
|
607
|
+
The ManimColor with the corresponding RGB values to the HSV
|
|
608
|
+
"""
|
|
609
|
+
rgb = colorsys.hsv_to_rgb(*hsv)
|
|
610
|
+
return cls(rgb, alpha)
|
|
611
|
+
|
|
612
|
+
@overload
|
|
613
|
+
@classmethod
|
|
614
|
+
def parse(
|
|
615
|
+
cls,
|
|
616
|
+
color: ParsableManimColor | None,
|
|
617
|
+
alpha: float = ...,
|
|
618
|
+
) -> Self:
|
|
619
|
+
...
|
|
620
|
+
|
|
621
|
+
@overload
|
|
622
|
+
@classmethod
|
|
623
|
+
def parse(
|
|
624
|
+
cls,
|
|
625
|
+
color: Sequence[ParsableManimColor],
|
|
626
|
+
alpha: float = ...,
|
|
627
|
+
) -> list[Self]:
|
|
628
|
+
...
|
|
629
|
+
|
|
630
|
+
@classmethod
|
|
631
|
+
def parse(
|
|
632
|
+
cls,
|
|
633
|
+
color: ParsableManimColor | list[ParsableManimColor] | None,
|
|
634
|
+
alpha: float = 1.0,
|
|
635
|
+
) -> Self | list[Self]:
|
|
636
|
+
"""
|
|
637
|
+
Handles the parsing of a list of colors or a single color.
|
|
638
|
+
|
|
639
|
+
Parameters
|
|
640
|
+
----------
|
|
641
|
+
color
|
|
642
|
+
The color or list of colors to parse. Note that this function can not accept rgba tuples. It will assume that you mean list[ManimColor] and will return a list of ManimColors.
|
|
643
|
+
alpha
|
|
644
|
+
The alpha value to use if a single color is passed. or if a list of colors is passed to set the value of all colors.
|
|
645
|
+
|
|
646
|
+
Returns
|
|
647
|
+
-------
|
|
648
|
+
ManimColor
|
|
649
|
+
Either a list of colors or a singular color depending on the input
|
|
650
|
+
"""
|
|
651
|
+
if isinstance(color, (list, tuple)):
|
|
652
|
+
return [cls(c, alpha) for c in color] # type: ignore
|
|
653
|
+
return cls(color, alpha) # type: ignore
|
|
654
|
+
|
|
655
|
+
@staticmethod
|
|
656
|
+
def gradient(colors: list[ManimColor], length: int):
|
|
657
|
+
"""This is not implemented by now refer to :func:`color_gradient` for a working implementation for now"""
|
|
658
|
+
# TODO: implement proper gradient, research good implementation for this or look at 3b1b implementation
|
|
659
|
+
raise NotImplementedError
|
|
660
|
+
|
|
661
|
+
def __repr__(self) -> str:
|
|
662
|
+
return f"{self.__class__.__name__}('{self.to_hex()}')"
|
|
663
|
+
|
|
664
|
+
def __str__(self) -> str:
|
|
665
|
+
return f"{self.to_hex()}"
|
|
666
|
+
|
|
667
|
+
def __eq__(self, other: object) -> bool:
|
|
668
|
+
if not isinstance(other, ManimColor):
|
|
669
|
+
raise TypeError(
|
|
670
|
+
f"Cannot compare {self.__class__.__name__} with {other.__class__.__name__}"
|
|
671
|
+
)
|
|
672
|
+
return np.allclose(self._internal_value, other._internal_value)
|
|
673
|
+
|
|
674
|
+
def __add__(self, other: ManimColor) -> ManimColor:
|
|
675
|
+
return ManimColor(self._internal_value + other._internal_value)
|
|
676
|
+
|
|
677
|
+
def __sub__(self, other: ManimColor) -> ManimColor:
|
|
678
|
+
return ManimColor(self._internal_value - other._internal_value)
|
|
679
|
+
|
|
680
|
+
def __mul__(self, other: ManimColor) -> ManimColor:
|
|
681
|
+
return ManimColor(self._internal_value * other._internal_value)
|
|
682
|
+
|
|
683
|
+
def __truediv__(self, other: ManimColor) -> ManimColor:
|
|
684
|
+
return ManimColor(self._internal_value / other._internal_value)
|
|
685
|
+
|
|
686
|
+
def __floordiv__(self, other: ManimColor) -> ManimColor:
|
|
687
|
+
return ManimColor(self._internal_value // other._internal_value)
|
|
688
|
+
|
|
689
|
+
def __mod__(self, other: ManimColor) -> ManimColor:
|
|
690
|
+
return ManimColor(self._internal_value % other._internal_value)
|
|
691
|
+
|
|
692
|
+
def __pow__(self, other: ManimColor) -> ManimColor:
|
|
693
|
+
return ManimColor(self._internal_value**other._internal_value)
|
|
694
|
+
|
|
695
|
+
def __and__(self, other: ManimColor) -> ManimColor:
|
|
696
|
+
return ManimColor(self.to_integer() & other.to_integer())
|
|
697
|
+
|
|
698
|
+
def __or__(self, other: ManimColor) -> ManimColor:
|
|
699
|
+
return ManimColor(self.to_integer() | other.to_integer())
|
|
700
|
+
|
|
701
|
+
def __xor__(self, other: ManimColor) -> ManimColor:
|
|
702
|
+
return ManimColor(self.to_integer() ^ other.to_integer())
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
ParsableManimColor: TypeAlias = Union[
|
|
706
|
+
ManimColor,
|
|
707
|
+
int,
|
|
708
|
+
str,
|
|
709
|
+
RGB_Tuple_Int,
|
|
710
|
+
RGB_Tuple_Float,
|
|
711
|
+
RGBA_Tuple_Int,
|
|
712
|
+
RGBA_Tuple_Float,
|
|
713
|
+
RGB_Array_Int,
|
|
714
|
+
RGB_Array_Float,
|
|
715
|
+
RGBA_Array_Int,
|
|
716
|
+
RGBA_Array_Float,
|
|
717
|
+
]
|
|
718
|
+
"""ParsableManimColor is the representation for all types that are parsable to a color in manim"""
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
ManimColorT = TypeVar("ManimColorT", bound=ManimColor)
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
def color_to_rgb(color: ParsableManimColor) -> RGB_Array_Float:
|
|
725
|
+
"""Helper function for use in functional style programming refer to :meth:`to_rgb` in :class:`ManimColor`
|
|
726
|
+
|
|
727
|
+
Parameters
|
|
728
|
+
----------
|
|
729
|
+
color : ParsableManimColor
|
|
730
|
+
A color
|
|
731
|
+
|
|
732
|
+
Returns
|
|
733
|
+
-------
|
|
734
|
+
RGB_Array_Float
|
|
735
|
+
the corresponding rgb array
|
|
736
|
+
"""
|
|
737
|
+
return ManimColor(color).to_rgb()
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
def color_to_rgba(color: ParsableManimColor, alpha: float = 1) -> RGBA_Array_Float:
|
|
741
|
+
"""Helper function for use in functional style programming refer to :meth:`to_rgba_with_alpha` in :class:`ManimColor`
|
|
742
|
+
|
|
743
|
+
Parameters
|
|
744
|
+
----------
|
|
745
|
+
color : ParsableManimColor
|
|
746
|
+
A color
|
|
747
|
+
alpha : float, optional
|
|
748
|
+
alpha value to be used in the color, by default 1
|
|
749
|
+
|
|
750
|
+
Returns
|
|
751
|
+
-------
|
|
752
|
+
RGBA_Array_Float
|
|
753
|
+
the corresponding rgba array
|
|
754
|
+
"""
|
|
755
|
+
return ManimColor(color).to_rgba_with_alpha(alpha)
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
def color_to_int_rgb(color: ParsableManimColor) -> RGB_Array_Int:
|
|
759
|
+
"""Helper function for use in functional style programming refer to :meth:`to_int_rgb` in :class:`ManimColor`
|
|
760
|
+
|
|
761
|
+
Parameters
|
|
762
|
+
----------
|
|
763
|
+
color : ParsableManimColor
|
|
764
|
+
A color
|
|
765
|
+
|
|
766
|
+
Returns
|
|
767
|
+
-------
|
|
768
|
+
RGB_Array_Int
|
|
769
|
+
the corresponding int rgb array
|
|
770
|
+
"""
|
|
771
|
+
return ManimColor(color).to_int_rgb()
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
def color_to_int_rgba(color: ParsableManimColor, alpha: float = 1.0) -> RGBA_Array_Int:
|
|
775
|
+
"""Helper function for use in functional style programming refer to :meth:`to_int_rgba_with_alpha` in :class:`ManimColor`
|
|
776
|
+
|
|
777
|
+
Parameters
|
|
778
|
+
----------
|
|
779
|
+
color : ParsableManimColor
|
|
780
|
+
A color
|
|
781
|
+
alpha : float, optional
|
|
782
|
+
alpha value to be used in the color, by default 1.0
|
|
783
|
+
|
|
784
|
+
Returns
|
|
785
|
+
-------
|
|
786
|
+
RGBA_Array_Int
|
|
787
|
+
the corresponding int rgba array
|
|
788
|
+
"""
|
|
789
|
+
return ManimColor(color).to_int_rgba_with_alpha(alpha)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def rgb_to_color(
|
|
793
|
+
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
794
|
+
) -> ManimColor:
|
|
795
|
+
"""Helper function for use in functional style programming refer to :meth:`from_rgb` in :class:`ManimColor`
|
|
796
|
+
|
|
797
|
+
Parameters
|
|
798
|
+
----------
|
|
799
|
+
rgb : RGB_Array_Float | RGB_Tuple_Float
|
|
800
|
+
A 3 element iterable
|
|
801
|
+
|
|
802
|
+
Returns
|
|
803
|
+
-------
|
|
804
|
+
ManimColor
|
|
805
|
+
A ManimColor with the corresponding value
|
|
806
|
+
"""
|
|
807
|
+
return ManimColor.from_rgb(rgb)
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
def rgba_to_color(
|
|
811
|
+
rgba: RGBA_Array_Float | RGBA_Tuple_Float | RGBA_Array_Int | RGBA_Tuple_Int,
|
|
812
|
+
) -> ManimColor:
|
|
813
|
+
"""Helper function for use in functional style programming refer to :meth:`from_rgba` in :class:`ManimColor`
|
|
814
|
+
|
|
815
|
+
Parameters
|
|
816
|
+
----------
|
|
817
|
+
rgba : RGBA_Array_Float | RGBA_Tuple_Float
|
|
818
|
+
A 4 element iterable
|
|
819
|
+
|
|
820
|
+
Returns
|
|
821
|
+
-------
|
|
822
|
+
ManimColor
|
|
823
|
+
A ManimColor with the corresponding value
|
|
824
|
+
"""
|
|
825
|
+
return ManimColor.from_rgba(rgba)
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
def rgb_to_hex(
|
|
829
|
+
rgb: RGB_Array_Float | RGB_Tuple_Float | RGB_Array_Int | RGB_Tuple_Int,
|
|
830
|
+
) -> str:
|
|
831
|
+
"""Helper function for use in functional style programming refer to :meth:`from_rgb` in :class:`ManimColor`
|
|
832
|
+
|
|
833
|
+
Parameters
|
|
834
|
+
----------
|
|
835
|
+
rgb : RGB_Array_Float | RGB_Tuple_Float
|
|
836
|
+
A 3 element iterable
|
|
837
|
+
|
|
838
|
+
Returns
|
|
839
|
+
-------
|
|
840
|
+
str
|
|
841
|
+
A hex representation of the color, refer to :meth:`to_hex` in :class:`ManimColor`
|
|
842
|
+
"""
|
|
843
|
+
return ManimColor.from_rgb(rgb).to_hex()
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
def hex_to_rgb(hex_code: str) -> RGB_Array_Float:
|
|
847
|
+
"""Helper function for use in functional style programming refer to :meth:`to_hex` in :class:`ManimColor`
|
|
848
|
+
|
|
849
|
+
Parameters
|
|
850
|
+
----------
|
|
851
|
+
hex_code : str
|
|
852
|
+
A hex string representing a color
|
|
853
|
+
|
|
854
|
+
Returns
|
|
855
|
+
-------
|
|
856
|
+
RGB_Array_Float
|
|
857
|
+
RGB array representing the color
|
|
858
|
+
"""
|
|
859
|
+
return ManimColor(hex_code).to_rgb()
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
def invert_color(color: ManimColorT) -> ManimColorT:
|
|
863
|
+
"""Helper function for use in functional style programming refer to :meth:`invert` in :class:`ManimColor`
|
|
864
|
+
|
|
865
|
+
Parameters
|
|
866
|
+
----------
|
|
867
|
+
color : ManimColor
|
|
868
|
+
A ManimColor
|
|
869
|
+
|
|
870
|
+
Returns
|
|
871
|
+
-------
|
|
872
|
+
ManimColor
|
|
873
|
+
The linearly inverted ManimColor
|
|
874
|
+
"""
|
|
875
|
+
return color.invert()
|
|
876
|
+
|
|
877
|
+
|
|
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
|
+
def color_gradient(
|
|
901
|
+
reference_colors: Sequence[ParsableManimColor],
|
|
902
|
+
length_of_output: int,
|
|
903
|
+
) -> list[ManimColor] | ManimColor:
|
|
904
|
+
"""Creates a list of colors interpolated between the input array of colors with a specific number of colors
|
|
905
|
+
|
|
906
|
+
Parameters
|
|
907
|
+
----------
|
|
908
|
+
reference_colors : Sequence[ParsableManimColor]
|
|
909
|
+
The colors to be interpolated between or spread apart
|
|
910
|
+
length_of_output : int
|
|
911
|
+
The number of colors that the output should have, ideally more than the input
|
|
912
|
+
|
|
913
|
+
Returns
|
|
914
|
+
-------
|
|
915
|
+
list[ManimColor] | ManimColor
|
|
916
|
+
A list of ManimColor's which has the interpolated colors
|
|
917
|
+
"""
|
|
918
|
+
if length_of_output == 0:
|
|
919
|
+
return ManimColor(reference_colors[0])
|
|
920
|
+
if len(reference_colors) == 1:
|
|
921
|
+
return [ManimColor(reference_colors[0])] * length_of_output
|
|
922
|
+
rgbs = [color_to_rgb(color) for color in reference_colors]
|
|
923
|
+
alphas = np.linspace(0, (len(rgbs) - 1), length_of_output)
|
|
924
|
+
floors = alphas.astype("int")
|
|
925
|
+
alphas_mod1 = alphas % 1
|
|
926
|
+
# End edge case
|
|
927
|
+
alphas_mod1[-1] = 1
|
|
928
|
+
floors[-1] = len(rgbs) - 2
|
|
929
|
+
return [
|
|
930
|
+
rgb_to_color((rgbs[i] * (1 - alpha)) + (rgbs[i + 1] * alpha))
|
|
931
|
+
for i, alpha in zip(floors, alphas_mod1)
|
|
932
|
+
]
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
def interpolate_color(
|
|
936
|
+
color1: ManimColorT, color2: ManimColor, alpha: float
|
|
937
|
+
) -> ManimColorT:
|
|
938
|
+
"""Standalone function to interpolate two ManimColors and get the result refer to :meth:`interpolate` in :class:`ManimColor`
|
|
939
|
+
|
|
940
|
+
Parameters
|
|
941
|
+
----------
|
|
942
|
+
color1 : ManimColor
|
|
943
|
+
First ManimColor
|
|
944
|
+
color2 : ManimColor
|
|
945
|
+
Second ManimColor
|
|
946
|
+
alpha : float
|
|
947
|
+
The alpha value determining the point of interpolation between the colors
|
|
948
|
+
|
|
949
|
+
Returns
|
|
950
|
+
-------
|
|
951
|
+
ManimColor
|
|
952
|
+
The interpolated ManimColor
|
|
953
|
+
"""
|
|
954
|
+
return color1.interpolate(color2, alpha)
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
def average_color(*colors: ParsableManimColor) -> ManimColor:
|
|
958
|
+
"""Determines the Average color of the given parameters
|
|
959
|
+
|
|
960
|
+
Returns
|
|
961
|
+
-------
|
|
962
|
+
ManimColor
|
|
963
|
+
The average color of the input
|
|
964
|
+
"""
|
|
965
|
+
rgbs = np.array([color_to_rgb(color) for color in colors])
|
|
966
|
+
mean_rgb = np.apply_along_axis(np.mean, 0, rgbs)
|
|
967
|
+
return rgb_to_color(mean_rgb)
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def random_bright_color() -> ManimColor:
|
|
971
|
+
"""Returns you a random bright color
|
|
972
|
+
|
|
973
|
+
.. warning::
|
|
974
|
+
This operation is very expensive please keep in mind the performance loss.
|
|
975
|
+
|
|
976
|
+
Returns
|
|
977
|
+
-------
|
|
978
|
+
ManimColor
|
|
979
|
+
A bright ManimColor
|
|
980
|
+
"""
|
|
981
|
+
curr_rgb = color_to_rgb(random_color())
|
|
982
|
+
new_rgb = interpolate_arrays(curr_rgb, np.ones(len(curr_rgb)), 0.5)
|
|
983
|
+
return ManimColor(new_rgb)
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
def random_color() -> ManimColor:
|
|
987
|
+
"""Return you a random ManimColor
|
|
988
|
+
|
|
989
|
+
.. warning::
|
|
990
|
+
This operation is very expensive please keep in mind the performance loss.
|
|
991
|
+
|
|
992
|
+
Returns
|
|
993
|
+
-------
|
|
994
|
+
ManimColor
|
|
995
|
+
_description_
|
|
996
|
+
"""
|
|
997
|
+
import manim.utils.color.manim_colors as manim_colors
|
|
998
|
+
|
|
999
|
+
return random.choice(manim_colors._all_manim_colors)
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
def get_shaded_rgb(
|
|
1003
|
+
rgb: npt.NDArray[Any],
|
|
1004
|
+
point: npt.NDArray[Any],
|
|
1005
|
+
unit_normal_vect: npt.NDArray[Any],
|
|
1006
|
+
light_source: npt.NDArray[Any],
|
|
1007
|
+
) -> RGBA_Array_Float:
|
|
1008
|
+
to_sun = normalize(light_source - point)
|
|
1009
|
+
factor = 0.5 * np.dot(unit_normal_vect, to_sun) ** 3
|
|
1010
|
+
if factor < 0:
|
|
1011
|
+
factor *= 0.5
|
|
1012
|
+
result = rgb + factor
|
|
1013
|
+
return result
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
__all__ = [
|
|
1017
|
+
"ManimColor",
|
|
1018
|
+
"ManimColorDType",
|
|
1019
|
+
"ParsableManimColor",
|
|
1020
|
+
"color_to_rgb",
|
|
1021
|
+
"color_to_rgba",
|
|
1022
|
+
"color_to_int_rgb",
|
|
1023
|
+
"color_to_int_rgba",
|
|
1024
|
+
"rgb_to_color",
|
|
1025
|
+
"rgba_to_color",
|
|
1026
|
+
"rgb_to_hex",
|
|
1027
|
+
"hex_to_rgb",
|
|
1028
|
+
"invert_color",
|
|
1029
|
+
"interpolate_arrays",
|
|
1030
|
+
"color_gradient",
|
|
1031
|
+
"interpolate_color",
|
|
1032
|
+
"average_color",
|
|
1033
|
+
"random_bright_color",
|
|
1034
|
+
"random_color",
|
|
1035
|
+
"get_shaded_rgb",
|
|
1036
|
+
]
|