Skip to content

Commit 63ff45d

Browse files
authored
Added deprecation warnings when accessing color enums, fix #8 (#11)
* Added deprecation warnings when accessing color enums, fix #8 * Simplified import statement for warnings, fix #8
1 parent 288951b commit 63ff45d

File tree

1 file changed

+337
-2
lines changed

1 file changed

+337
-2
lines changed

manim/utils/color.py

Lines changed: 337 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import random
2424
import warnings
25+
from enum import Enum, EnumMeta
2526
from typing import Iterable
2627

2728
import numpy as np
@@ -30,6 +31,342 @@
3031
from ..utils.bezier import interpolate
3132
from ..utils.space_ops import normalize
3233

34+
35+
class ColorsMeta(EnumMeta):
36+
def __getattribute__(self, colorName):
37+
colors = [
38+
"white",
39+
"gray_a",
40+
"gray_b",
41+
"gray_c",
42+
"gray_d",
43+
"gray_e",
44+
"black",
45+
"lighter_gray",
46+
"gray",
47+
"darker_gray",
48+
"blue_a",
49+
"blue_b",
50+
"blue_c",
51+
"blue_d",
52+
"blue_e",
53+
"pure_blue",
54+
"blue",
55+
"dark_blue",
56+
"teal_a",
57+
"teal_b",
58+
"teal_c",
59+
"teal_d",
60+
"teal_e",
61+
"teal",
62+
"green_a",
63+
"green_b",
64+
"green_c",
65+
"green_d",
66+
"green_e",
67+
"pure_green",
68+
"green",
69+
"yellow_a",
70+
"yellow_b",
71+
"yellow_c",
72+
"yellow_d",
73+
"yellow_e",
74+
"yellow",
75+
"gold_a",
76+
"gold_b",
77+
"gold_c",
78+
"gold_d",
79+
"gold_e",
80+
"gold",
81+
"red_a",
82+
"red_b",
83+
"red_c",
84+
"red_d",
85+
"red_e",
86+
"pure_red",
87+
"red",
88+
"maroon_a",
89+
"maroon_b",
90+
"maroon_c",
91+
"maroon_d",
92+
"maroon_e",
93+
"maroon",
94+
"purple_a",
95+
"purple_b",
96+
"purple_c",
97+
"purple_d",
98+
"purple_e",
99+
"purple",
100+
"pink",
101+
"light_pink",
102+
"orange",
103+
"light_brown",
104+
"dark_brown",
105+
"gray_brown",
106+
]
107+
if colorName in colors:
108+
warnings.warn(
109+
"Color enums is deprecated in favor of the constants. "
110+
"The constants can be accessed by importing manim.utils.color",
111+
DeprecationWarning,
112+
stacklevel=2,
113+
)
114+
return EnumMeta.__getattribute__(self, colorName)
115+
116+
117+
class Colors(Enum, metaclass=ColorsMeta):
118+
"""A list of pre-defined colors.
119+
120+
Examples
121+
--------
122+
123+
.. manim:: ColorsOverview
124+
:save_last_frame:
125+
:hide_source:
126+
127+
from manim.utils.color import Colors
128+
class ColorsOverview(Scene):
129+
def construct(self):
130+
def color_group(color):
131+
group = VGroup(
132+
*[
133+
Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=Colors[name].value)
134+
for name in subnames(color)
135+
]
136+
).arrange_submobjects(buff=0.4, direction=DOWN)
137+
138+
name = Text(color).scale(0.6).next_to(group, UP, buff=0.3)
139+
if any(decender in color for decender in "gjpqy"):
140+
name.shift(DOWN * 0.08)
141+
group.add(name)
142+
return group
143+
144+
def subnames(name):
145+
return [name + "_" + char for char in "abcde"]
146+
147+
color_groups = VGroup(
148+
*[
149+
color_group(color)
150+
for color in [
151+
"blue",
152+
"teal",
153+
"green",
154+
"yellow",
155+
"gold",
156+
"red",
157+
"maroon",
158+
"purple",
159+
]
160+
]
161+
).arrange_submobjects(buff=0.2, aligned_edge=DOWN)
162+
163+
for line, char in zip(color_groups[0], "abcde"):
164+
color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2))
165+
166+
def named_lines_group(length, colors, names, text_colors, align_to_block):
167+
lines = VGroup(
168+
*[
169+
Line(
170+
ORIGIN,
171+
RIGHT * length,
172+
stroke_width=55,
173+
color=Colors[color].value,
174+
)
175+
for color in colors
176+
]
177+
).arrange_submobjects(buff=0.6, direction=DOWN)
178+
179+
for line, name, color in zip(lines, names, text_colors):
180+
line.add(Text(name, color=color).scale(0.6).move_to(line))
181+
lines.next_to(color_groups, DOWN, buff=0.5).align_to(
182+
color_groups[align_to_block], LEFT
183+
)
184+
return lines
185+
186+
other_colors = (
187+
"pink",
188+
"light_pink",
189+
"orange",
190+
"light_brown",
191+
"dark_brown",
192+
"gray_brown",
193+
)
194+
195+
other_lines = named_lines_group(
196+
3.2,
197+
other_colors,
198+
other_colors,
199+
[BLACK] * 4 + [WHITE] * 2,
200+
0,
201+
)
202+
203+
gray_lines = named_lines_group(
204+
6.6,
205+
["white"] + subnames("gray") + ["black"],
206+
[
207+
"white",
208+
"lighter_gray / gray_a",
209+
"light_gray / gray_b",
210+
"gray / gray_c",
211+
"dark_gray / gray_d",
212+
"darker_gray / gray_e",
213+
"black",
214+
],
215+
[BLACK] * 3 + [WHITE] * 4,
216+
2,
217+
)
218+
219+
pure_colors = (
220+
"pure_red",
221+
"pure_green",
222+
"pure_blue",
223+
)
224+
225+
pure_lines = named_lines_group(
226+
3.2,
227+
pure_colors,
228+
pure_colors,
229+
[BLACK, BLACK, WHITE],
230+
6,
231+
)
232+
233+
self.add(color_groups, other_lines, gray_lines, pure_lines)
234+
235+
VGroup(*self.mobjects).move_to(ORIGIN)
236+
237+
238+
The preferred way of using these colors is by importing their constants from manim:
239+
240+
.. code-block:: pycon
241+
242+
>>> from manim import RED, GREEN, BLUE
243+
>>> RED
244+
'#FC6255'
245+
246+
Note this way uses the name of the colors in UPPERCASE.
247+
248+
Alternatively, you can also import this Enum directly and use its members
249+
directly, through the use of :code:`color.value`. Note this way uses the
250+
name of the colors in lowercase.
251+
252+
.. code-block:: pycon
253+
254+
>>> from manim.utils.color import Colors
255+
>>> Colors.red.value
256+
'#FC6255'
257+
258+
.. note::
259+
260+
The colors of type "C" have an alias equal to the colorname without a letter,
261+
e.g. GREEN = GREEN_C
262+
263+
"""
264+
265+
white: str = "#FFFFFF"
266+
gray_a: str = "#DDDDDD"
267+
gray_b: str = "#BBBBBB"
268+
gray_c: str = "#888888"
269+
gray_d: str = "#444444"
270+
gray_e: str = "#222222"
271+
black: str = "#000000"
272+
lighter_gray: str = gray_a
273+
light_gray: str = gray_b
274+
gray: str = gray_c
275+
dark_gray: str = gray_d
276+
darker_gray: str = gray_e
277+
278+
blue_a: str = "#C7E9F1"
279+
blue_b: str = "#9CDCEB"
280+
blue_c: str = "#58C4DD"
281+
blue_d: str = "#29ABCA"
282+
blue_e: str = "#236B8E"
283+
pure_blue: str = "#0000FF"
284+
blue: str = blue_c
285+
dark_blue: str = blue_e
286+
287+
teal_a: str = "#ACEAD7"
288+
teal_b: str = "#76DDC0"
289+
teal_c: str = "#5CD0B3"
290+
teal_d: str = "#55C1A7"
291+
teal_e: str = "#49A88F"
292+
teal: str = teal_c
293+
294+
green_a: str = "#C9E2AE"
295+
green_b: str = "#A6CF8C"
296+
green_c: str = "#83C167"
297+
green_d: str = "#77B05D"
298+
green_e: str = "#699C52"
299+
pure_green: str = "#00FF00"
300+
green: str = green_c
301+
302+
yellow_a: str = "#FFF1B6"
303+
yellow_b: str = "#FFEA94"
304+
yellow_c: str = "#FFFF00"
305+
yellow_d: str = "#F4D345"
306+
yellow_e: str = "#E8C11C"
307+
yellow: str = yellow_c
308+
309+
gold_a: str = "#F7C797"
310+
gold_b: str = "#F9B775"
311+
gold_c: str = "#F0AC5F"
312+
gold_d: str = "#E1A158"
313+
gold_e: str = "#C78D46"
314+
gold: str = gold_c
315+
316+
red_a: str = "#F7A1A3"
317+
red_b: str = "#FF8080"
318+
red_c: str = "#FC6255"
319+
red_d: str = "#E65A4C"
320+
red_e: str = "#CF5044"
321+
pure_red: str = "#FF0000"
322+
red: str = red_c
323+
324+
maroon_a: str = "#ECABC1"
325+
maroon_b: str = "#EC92AB"
326+
maroon_c: str = "#C55F73"
327+
maroon_d: str = "#A24D61"
328+
maroon_e: str = "#94424F"
329+
maroon: str = maroon_c
330+
331+
purple_a: str = "#CAA3E8"
332+
purple_b: str = "#B189C6"
333+
purple_c: str = "#9A72AC"
334+
purple_d: str = "#715582"
335+
purple_e: str = "#644172"
336+
purple: str = purple_c
337+
338+
pink: str = "#D147BD"
339+
light_pink: str = "#DC75CD"
340+
341+
orange: str = "#FF862F"
342+
light_brown: str = "#CD853F"
343+
dark_brown: str = "#8B4513"
344+
gray_brown: str = "#736357"
345+
346+
347+
def print_constant_definitions():
348+
"""
349+
A simple function used to generate the constant values below. To run it
350+
paste this function and the Colors class into a file and run them.
351+
"""
352+
constants_names: list[str] = []
353+
for name in Colors.__members__.keys():
354+
name_upper = name.upper()
355+
356+
constants_names.append(name_upper)
357+
print(f"{name_upper} = Colors.{name}")
358+
359+
if "GRAY" in name_upper:
360+
name_upper = name_upper.replace("GRAY", "GREY")
361+
362+
constants_names.append(name_upper)
363+
print(f"{name_upper} = Colors.{name}")
364+
365+
constants_names_repr = '[\n "' + '",\n "'.join(constants_names) + '",\n]'
366+
367+
print(f"\n__all__ += {constants_names_repr}")
368+
369+
33370
WHITE: Color = Color("#FFFFFF")
34371
GRAY_A: Color = Color("#DDDDDD")
35372
GREY_A: Color = Color("#DDDDDD")
@@ -282,7 +619,6 @@
282619
]
283620

284621

285-
286622
def color_to_rgb(color: Color | str) -> np.ndarray:
287623
warnings.warn(
288624
"This method is not guaranteed to stay around. "
@@ -391,7 +727,6 @@ def random_color() -> Color:
391727
return random.choice(list(ALL_COLORS.values()))
392728

393729

394-
395730
def get_shaded_rgb(
396731
rgb: np.ndarray,
397732
point: np.ndarray,

0 commit comments

Comments
 (0)