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.

Files changed (84) hide show
  1. manim/__init__.py +1 -0
  2. manim/__main__.py +2 -0
  3. manim/_config/__init__.py +0 -1
  4. manim/_config/logger_utils.py +1 -0
  5. manim/_config/utils.py +14 -5
  6. manim/animation/changing.py +9 -5
  7. manim/animation/creation.py +8 -3
  8. manim/animation/indication.py +4 -4
  9. manim/animation/speedmodifier.py +2 -4
  10. manim/animation/updaters/mobject_update_utils.py +134 -16
  11. manim/camera/camera.py +31 -17
  12. manim/cli/checkhealth/__init__.py +0 -0
  13. manim/cli/checkhealth/checks.py +173 -0
  14. manim/cli/checkhealth/commands.py +81 -0
  15. manim/cli/render/global_options.py +6 -0
  16. manim/constants.py +58 -54
  17. manim/mobject/geometry/__init__.py +1 -0
  18. manim/mobject/geometry/arc.py +126 -91
  19. manim/mobject/geometry/boolean_ops.py +6 -10
  20. manim/mobject/geometry/labeled.py +155 -0
  21. manim/mobject/geometry/line.py +66 -50
  22. manim/mobject/geometry/polygram.py +23 -15
  23. manim/mobject/geometry/shape_matchers.py +24 -15
  24. manim/mobject/geometry/tips.py +62 -40
  25. manim/mobject/graph.py +3 -4
  26. manim/mobject/graphing/coordinate_systems.py +190 -139
  27. manim/mobject/graphing/number_line.py +5 -2
  28. manim/mobject/graphing/probability.py +4 -3
  29. manim/mobject/graphing/scale.py +7 -7
  30. manim/mobject/logo.py +108 -22
  31. manim/mobject/matrix.py +33 -37
  32. manim/mobject/mobject.py +327 -260
  33. manim/mobject/opengl/opengl_image_mobject.py +1 -1
  34. manim/mobject/opengl/opengl_mobject.py +18 -12
  35. manim/mobject/opengl/opengl_point_cloud_mobject.py +1 -1
  36. manim/mobject/opengl/opengl_surface.py +1 -1
  37. manim/mobject/opengl/opengl_vectorized_mobject.py +21 -17
  38. manim/mobject/svg/brace.py +3 -1
  39. manim/mobject/svg/svg_mobject.py +9 -11
  40. manim/mobject/table.py +50 -54
  41. manim/mobject/text/numbers.py +48 -6
  42. manim/mobject/text/tex_mobject.py +8 -12
  43. manim/mobject/text/text_mobject.py +32 -24
  44. manim/mobject/three_d/three_d_utils.py +13 -8
  45. manim/mobject/three_d/three_dimensions.py +61 -43
  46. manim/mobject/types/image_mobject.py +5 -4
  47. manim/mobject/types/point_cloud_mobject.py +8 -6
  48. manim/mobject/types/vectorized_mobject.py +385 -258
  49. manim/mobject/vector_field.py +19 -11
  50. manim/plugins/import_plugins.py +1 -1
  51. manim/plugins/plugins_flags.py +1 -6
  52. manim/renderer/shader.py +2 -2
  53. manim/scene/scene.py +15 -7
  54. manim/scene/scene_file_writer.py +1 -2
  55. manim/scene/three_d_scene.py +1 -1
  56. manim/scene/vector_space_scene.py +17 -7
  57. manim/typing.py +133 -0
  58. manim/utils/bezier.py +267 -83
  59. manim/utils/color/AS2700.py +234 -0
  60. manim/utils/color/BS381.py +315 -0
  61. manim/utils/color/X11.py +530 -0
  62. manim/utils/color/XKCD.py +949 -0
  63. manim/utils/color/__init__.py +58 -0
  64. manim/utils/color/core.py +1036 -0
  65. manim/utils/color/manim_colors.py +220 -0
  66. manim/utils/docbuild/autocolor_directive.py +92 -0
  67. manim/utils/docbuild/manim_directive.py +40 -6
  68. manim/utils/file_ops.py +1 -1
  69. manim/utils/hashing.py +1 -1
  70. manim/utils/iterables.py +1 -1
  71. manim/utils/rate_functions.py +33 -0
  72. manim/utils/simple_functions.py +0 -18
  73. manim/utils/space_ops.py +55 -42
  74. manim/utils/testing/frames_comparison.py +9 -0
  75. manim/utils/tex.py +2 -0
  76. manim/utils/tex_file_writing.py +29 -2
  77. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/METADATA +14 -14
  78. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/RECORD +82 -71
  79. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/WHEEL +1 -1
  80. manim/communitycolors.py +0 -9
  81. manim/utils/color.py +0 -552
  82. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE +0 -0
  83. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE.community +0 -0
  84. {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
+ ]