From 16ae32044c9cca5389ec3af43fc1a639614f9dde Mon Sep 17 00:00:00 2001 From: Ludwig Johansson Date: Mon, 7 Mar 2022 11:42:13 +0100 Subject: [PATCH 1/9] =?UTF-8?q?Removed=20enum=20from=20color=20class=20and?= =?UTF-8?q?=20temporary=20fix=20to=20access=20constant=20fro=E2=80=A6=20(#?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removed enum from color class and temporar fix to access constant from text_mobjects, fix #2 * Removed color class and improved safety on how constant are accessed, fix #2 --- manim/mobject/geometry/shape_matchers.py | 4 +- manim/mobject/mobject.py | 3 +- manim/mobject/opengl/opengl_mobject.py | 3 +- manim/mobject/text/text_mobject.py | 10 +- manim/utils/color.py | 263 +---------------------- 5 files changed, 18 insertions(+), 265 deletions(-) diff --git a/manim/mobject/geometry/shape_matchers.py b/manim/mobject/geometry/shape_matchers.py index 5aad303090..ad52402979 100644 --- a/manim/mobject/geometry/shape_matchers.py +++ b/manim/mobject/geometry/shape_matchers.py @@ -10,7 +10,7 @@ from manim.mobject.geometry.polygram import RoundedRectangle from manim.mobject.mobject import Mobject from manim.mobject.types.vectorized_mobject import VGroup -from manim.utils.color import BLACK, RED, YELLOW, Color, Colors +from manim.utils.color import BLACK, RED, YELLOW, Color class SurroundingRectangle(RoundedRectangle): @@ -79,7 +79,7 @@ def construct(self): def __init__( self, mobject, - color: Colors | None = None, + color: str | None = None, stroke_width: float = 0, stroke_opacity: float = 0, fill_opacity: float = 0.75, diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index b2ababb994..f45d288934 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -39,7 +39,6 @@ BLACK, WHITE, YELLOW_C, - Colors, color_gradient, interpolate_color, ) @@ -1646,7 +1645,7 @@ def put_start_and_end_on(self, start, end): # Background rectangle def add_background_rectangle( - self, color: Optional[Colors] = None, opacity: float = 0.75, **kwargs + self, color: str = None, opacity: float = 0.75, **kwargs ): """Add a BackgroundRectangle as submobject. diff --git a/manim/mobject/opengl/opengl_mobject.py b/manim/mobject/opengl/opengl_mobject.py index 9aae1a5765..71eb3e9e73 100644 --- a/manim/mobject/opengl/opengl_mobject.py +++ b/manim/mobject/opengl/opengl_mobject.py @@ -16,7 +16,6 @@ from manim.constants import * from manim.utils.bezier import integer_interpolate, interpolate from manim.utils.color import * -from manim.utils.color import Colors from manim.utils.config_ops import _Data, _Uniforms # from ..utils.iterables import batch_by_property @@ -1983,7 +1982,7 @@ def set_shadow(self, shadow, recurse=True): # Background rectangle def add_background_rectangle( - self, color: Colors | None = None, opacity: float = 0.75, **kwargs + self, color: str | None = None, opacity: float = 0.75, **kwargs ): # TODO, this does not behave well when the mobject has points, # since it gets displayed on top diff --git a/manim/mobject/text/text_mobject.py b/manim/mobject/text/text_mobject.py index f01a88c551..cde309babe 100644 --- a/manim/mobject/text/text_mobject.py +++ b/manim/mobject/text/text_mobject.py @@ -49,6 +49,8 @@ def construct(self): from __future__ import annotations +from manim.utils.color import get_all_colors + __all__ = ["Text", "Paragraph", "MarkupText", "register_font"] @@ -71,7 +73,7 @@ def construct(self): from manim.mobject.geometry.arc import Dot from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject -from manim.utils.color import Colors, color_gradient +from manim.utils.color import * from manim.utils.deprecation import deprecated TEXT_MOB_SCALE_FACTOR = 0.05 @@ -1331,7 +1333,11 @@ def _parse_color(self, col): if re.match("#[0-9a-f]{6}", col): return col else: - return Colors[col.lower()].value + # lookup in COLOR_VALUES + colorDict = get_all_colors() + return colorDict[col] + + def _extract_color_tags(self): """Used to determine which parts (if any) of the string should be formatted diff --git a/manim/utils/color.py b/manim/utils/color.py index 6356fb3f04..a53cd0a4d4 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -21,7 +21,6 @@ ] import random -from enum import Enum from typing import Iterable import numpy as np @@ -30,260 +29,6 @@ from ..utils.bezier import interpolate from ..utils.space_ops import normalize - -class Colors(Enum): - """A list of pre-defined colors. - - Examples - -------- - - .. manim:: ColorsOverview - :save_last_frame: - :hide_source: - - from manim.utils.color import Colors - class ColorsOverview(Scene): - def construct(self): - def color_group(color): - group = VGroup( - *[ - Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=Colors[name].value) - for name in subnames(color) - ] - ).arrange_submobjects(buff=0.4, direction=DOWN) - - name = Text(color).scale(0.6).next_to(group, UP, buff=0.3) - if any(decender in color for decender in "gjpqy"): - name.shift(DOWN * 0.08) - group.add(name) - return group - - def subnames(name): - return [name + "_" + char for char in "abcde"] - - color_groups = VGroup( - *[ - color_group(color) - for color in [ - "blue", - "teal", - "green", - "yellow", - "gold", - "red", - "maroon", - "purple", - ] - ] - ).arrange_submobjects(buff=0.2, aligned_edge=DOWN) - - for line, char in zip(color_groups[0], "abcde"): - color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2)) - - def named_lines_group(length, colors, names, text_colors, align_to_block): - lines = VGroup( - *[ - Line( - ORIGIN, - RIGHT * length, - stroke_width=55, - color=Colors[color].value, - ) - for color in colors - ] - ).arrange_submobjects(buff=0.6, direction=DOWN) - - for line, name, color in zip(lines, names, text_colors): - line.add(Text(name, color=color).scale(0.6).move_to(line)) - lines.next_to(color_groups, DOWN, buff=0.5).align_to( - color_groups[align_to_block], LEFT - ) - return lines - - other_colors = ( - "pink", - "light_pink", - "orange", - "light_brown", - "dark_brown", - "gray_brown", - ) - - other_lines = named_lines_group( - 3.2, - other_colors, - other_colors, - [BLACK] * 4 + [WHITE] * 2, - 0, - ) - - gray_lines = named_lines_group( - 6.6, - ["white"] + subnames("gray") + ["black"], - [ - "white", - "lighter_gray / gray_a", - "light_gray / gray_b", - "gray / gray_c", - "dark_gray / gray_d", - "darker_gray / gray_e", - "black", - ], - [BLACK] * 3 + [WHITE] * 4, - 2, - ) - - pure_colors = ( - "pure_red", - "pure_green", - "pure_blue", - ) - - pure_lines = named_lines_group( - 3.2, - pure_colors, - pure_colors, - [BLACK, BLACK, WHITE], - 6, - ) - - self.add(color_groups, other_lines, gray_lines, pure_lines) - - VGroup(*self.mobjects).move_to(ORIGIN) - - - The preferred way of using these colors is by importing their constants from manim: - - .. code-block:: pycon - - >>> from manim import RED, GREEN, BLUE - >>> RED - '#FC6255' - - Note this way uses the name of the colors in UPPERCASE. - - Alternatively, you can also import this Enum directly and use its members - directly, through the use of :code:`color.value`. Note this way uses the - name of the colors in lowercase. - - .. code-block:: pycon - - >>> from manim.utils.color import Colors - >>> Colors.red.value - '#FC6255' - - .. note:: - - The colors of type "C" have an alias equal to the colorname without a letter, - e.g. GREEN = GREEN_C - - """ - - white: str = "#FFFFFF" - gray_a: str = "#DDDDDD" - gray_b: str = "#BBBBBB" - gray_c: str = "#888888" - gray_d: str = "#444444" - gray_e: str = "#222222" - black: str = "#000000" - lighter_gray: str = gray_a - light_gray: str = gray_b - gray: str = gray_c - dark_gray: str = gray_d - darker_gray: str = gray_e - - blue_a: str = "#C7E9F1" - blue_b: str = "#9CDCEB" - blue_c: str = "#58C4DD" - blue_d: str = "#29ABCA" - blue_e: str = "#236B8E" - pure_blue: str = "#0000FF" - blue: str = blue_c - dark_blue: str = blue_e - - teal_a: str = "#ACEAD7" - teal_b: str = "#76DDC0" - teal_c: str = "#5CD0B3" - teal_d: str = "#55C1A7" - teal_e: str = "#49A88F" - teal: str = teal_c - - green_a: str = "#C9E2AE" - green_b: str = "#A6CF8C" - green_c: str = "#83C167" - green_d: str = "#77B05D" - green_e: str = "#699C52" - pure_green: str = "#00FF00" - green: str = green_c - - yellow_a: str = "#FFF1B6" - yellow_b: str = "#FFEA94" - yellow_c: str = "#FFFF00" - yellow_d: str = "#F4D345" - yellow_e: str = "#E8C11C" - yellow: str = yellow_c - - gold_a: str = "#F7C797" - gold_b: str = "#F9B775" - gold_c: str = "#F0AC5F" - gold_d: str = "#E1A158" - gold_e: str = "#C78D46" - gold: str = gold_c - - red_a: str = "#F7A1A3" - red_b: str = "#FF8080" - red_c: str = "#FC6255" - red_d: str = "#E65A4C" - red_e: str = "#CF5044" - pure_red: str = "#FF0000" - red: str = red_c - - maroon_a: str = "#ECABC1" - maroon_b: str = "#EC92AB" - maroon_c: str = "#C55F73" - maroon_d: str = "#A24D61" - maroon_e: str = "#94424F" - maroon: str = maroon_c - - purple_a: str = "#CAA3E8" - purple_b: str = "#B189C6" - purple_c: str = "#9A72AC" - purple_d: str = "#715582" - purple_e: str = "#644172" - purple: str = purple_c - - pink: str = "#D147BD" - light_pink: str = "#DC75CD" - - orange: str = "#FF862F" - light_brown: str = "#CD853F" - dark_brown: str = "#8B4513" - gray_brown: str = "#736357" - - -def print_constant_definitions(): - """ - A simple function used to generate the constant values below. To run it - paste this function and the Colors class into a file and run them. - """ - constants_names: list[str] = [] - for name in Colors.__members__.keys(): - name_upper = name.upper() - - constants_names.append(name_upper) - print(f"{name_upper} = Colors.{name}") - - if "GRAY" in name_upper: - name_upper = name_upper.replace("GRAY", "GREY") - - constants_names.append(name_upper) - print(f"{name_upper} = Colors.{name}") - - constants_names_repr = '[\n "' + '",\n "'.join(constants_names) + '",\n]' - - print(f"\n__all__ += {constants_names_repr}") - - WHITE: str = "#FFFFFF" GRAY_A: str = "#DDDDDD" GREY_A: str = "#DDDDDD" @@ -450,6 +195,11 @@ def print_constant_definitions(): "GREY_BROWN", ] +color_map = dict(((colorName, value) for colorName, value in locals().items() if str(value).startswith("#"))) +all_colors = [c for colors, c in locals().items() if str(c).startswith("#")] + +def get_all_colors(): + return color_map def color_to_rgb(color: Color | str) -> np.ndarray: if isinstance(color, str): @@ -535,8 +285,7 @@ def random_bright_color() -> Color: def random_color() -> Color: - return random.choice([c.value for c in list(Colors)]) - + return random.choice(all_colors) def get_shaded_rgb( rgb: np.ndarray, From 63ed75f834021b0d055633ca63f23788c460a421 Mon Sep 17 00:00:00 2001 From: Amanda Krohn <33667375+amandakrohn@users.noreply.github.com> Date: Mon, 7 Mar 2022 14:16:33 +0100 Subject: [PATCH 2/9] Makes color constants instances of Color-class (#9) * Converts values in setting_args dict in _get_settings_from_t2xs to string to make sure that all values are of type string. * Makes color constants instances of Color-class from colour-module and updates color_gradient to handle gradient with one color, fixes #7. --- manim/mobject/text/text_mobject.py | 13 +- manim/utils/color.py | 259 +++++++++++++++++++---------- 2 files changed, 176 insertions(+), 96 deletions(-) diff --git a/manim/mobject/text/text_mobject.py b/manim/mobject/text/text_mobject.py index cde309babe..8423077805 100644 --- a/manim/mobject/text/text_mobject.py +++ b/manim/mobject/text/text_mobject.py @@ -49,8 +49,6 @@ def construct(self): from __future__ import annotations -from manim.utils.color import get_all_colors - __all__ = ["Text", "Paragraph", "MarkupText", "register_font"] @@ -73,7 +71,9 @@ def construct(self): from manim.mobject.geometry.arc import Dot from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject -from manim.utils.color import * + +# from manim.utils.color import * +from manim.utils.color import ALL_COLORS from manim.utils.deprecation import deprecated TEXT_MOB_SCALE_FACTOR = 0.05 @@ -646,7 +646,7 @@ def _get_settings_from_t2xs( t2xwords = set(chain(*([*t2x.keys()] for t2x, _ in t2xs))) for word in t2xwords: setting_args = { - arg: t2x[word] if word in t2x else default_args[arg] + arg: str(t2x[word]) if word in t2x else str(default_args[arg]) for t2x, arg in t2xs } @@ -1334,10 +1334,7 @@ def _parse_color(self, col): return col else: # lookup in COLOR_VALUES - colorDict = get_all_colors() - return colorDict[col] - - + return ALL_COLORS[col] def _extract_color_tags(self): """Used to determine which parts (if any) of the string should be formatted diff --git a/manim/utils/color.py b/manim/utils/color.py index a53cd0a4d4..478f221164 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -29,87 +29,171 @@ from ..utils.bezier import interpolate from ..utils.space_ops import normalize -WHITE: str = "#FFFFFF" -GRAY_A: str = "#DDDDDD" -GREY_A: str = "#DDDDDD" -GRAY_B: str = "#BBBBBB" -GREY_B: str = "#BBBBBB" -GRAY_C: str = "#888888" -GREY_C: str = "#888888" -GRAY_D: str = "#444444" -GREY_D: str = "#444444" -GRAY_E: str = "#222222" -GREY_E: str = "#222222" -BLACK: str = "#000000" -LIGHTER_GRAY: str = "#DDDDDD" -LIGHTER_GREY: str = "#DDDDDD" -LIGHT_GRAY: str = "#BBBBBB" -LIGHT_GREY: str = "#BBBBBB" -GRAY: str = "#888888" -GREY: str = "#888888" -DARK_GRAY: str = "#444444" -DARK_GREY: str = "#444444" -DARKER_GRAY: str = "#222222" -DARKER_GREY: str = "#222222" -BLUE_A: str = "#C7E9F1" -BLUE_B: str = "#9CDCEB" -BLUE_C: str = "#58C4DD" -BLUE_D: str = "#29ABCA" -BLUE_E: str = "#236B8E" -PURE_BLUE: str = "#0000FF" -BLUE: str = "#58C4DD" -DARK_BLUE: str = "#236B8E" -TEAL_A: str = "#ACEAD7" -TEAL_B: str = "#76DDC0" -TEAL_C: str = "#5CD0B3" -TEAL_D: str = "#55C1A7" -TEAL_E: str = "#49A88F" -TEAL: str = "#5CD0B3" -GREEN_A: str = "#C9E2AE" -GREEN_B: str = "#A6CF8C" -GREEN_C: str = "#83C167" -GREEN_D: str = "#77B05D" -GREEN_E: str = "#699C52" -PURE_GREEN: str = "#00FF00" -GREEN: str = "#83C167" -YELLOW_A: str = "#FFF1B6" -YELLOW_B: str = "#FFEA94" -YELLOW_C: str = "#FFFF00" -YELLOW_D: str = "#F4D345" -YELLOW_E: str = "#E8C11C" -YELLOW: str = "#FFFF00" -GOLD_A: str = "#F7C797" -GOLD_B: str = "#F9B775" -GOLD_C: str = "#F0AC5F" -GOLD_D: str = "#E1A158" -GOLD_E: str = "#C78D46" -GOLD: str = "#F0AC5F" -RED_A: str = "#F7A1A3" -RED_B: str = "#FF8080" -RED_C: str = "#FC6255" -RED_D: str = "#E65A4C" -RED_E: str = "#CF5044" -PURE_RED: str = "#FF0000" -RED: str = "#FC6255" -MAROON_A: str = "#ECABC1" -MAROON_B: str = "#EC92AB" -MAROON_C: str = "#C55F73" -MAROON_D: str = "#A24D61" -MAROON_E: str = "#94424F" -MAROON: str = "#C55F73" -PURPLE_A: str = "#CAA3E8" -PURPLE_B: str = "#B189C6" -PURPLE_C: str = "#9A72AC" -PURPLE_D: str = "#715582" -PURPLE_E: str = "#644172" -PURPLE: str = "#9A72AC" -PINK: str = "#D147BD" -LIGHT_PINK: str = "#DC75CD" -ORANGE: str = "#FF862F" -LIGHT_BROWN: str = "#CD853F" -DARK_BROWN: str = "#8B4513" -GRAY_BROWN: str = "#736357" -GREY_BROWN: str = "#736357" +WHITE: Color = Color("#FFFFFF") +GRAY_A: Color = Color("#DDDDDD") +GREY_A: Color = Color("#DDDDDD") +GRAY_B: Color = Color("#BBBBBB") +GREY_B: Color = Color("#BBBBBB") +GRAY_C: Color = Color("#888888") +GREY_C: Color = Color("#888888") +GRAY_D: Color = Color("#444444") +GREY_D: Color = Color("#444444") +GRAY_E: Color = Color("#222222") +GREY_E: Color = Color("#222222") +BLACK: Color = Color("#000000") +LIGHTER_GRAY: Color = Color("#DDDDDD") +LIGHTER_GREY: Color = Color("#DDDDDD") +LIGHT_GRAY: Color = Color("#BBBBBB") +LIGHT_GREY: Color = Color("#BBBBBB") +GRAY: Color = Color("#888888") +GREY: Color = Color("#888888") +DARK_GRAY: Color = Color("#444444") +DARK_GREY: Color = Color("#444444") +DARKER_GRAY: Color = Color("#222222") +DARKER_GREY: Color = Color("#222222") +BLUE_A: Color = Color("#C7E9F1") +BLUE_B: Color = Color("#9CDCEB") +BLUE_C: Color = Color("#58C4DD") +BLUE_D: Color = Color("#29ABCA") +BLUE_E: Color = Color("#236B8E") +PURE_BLUE: Color = Color("#0000FF") +BLUE: Color = Color("#58C4DD") +DARK_BLUE: Color = Color("#236B8E") +TEAL_A: Color = Color("#ACEAD7") +TEAL_B: Color = Color("#76DDC0") +TEAL_C: Color = Color("#5CD0B3") +TEAL_D: Color = Color("#55C1A7") +TEAL_E: Color = Color("#49A88F") +TEAL: Color = Color("#5CD0B3") +GREEN_A: Color = Color("#C9E2AE") +GREEN_B: Color = Color("#A6CF8C") +GREEN_C: Color = Color("#83C167") +GREEN_D: Color = Color("#77B05D") +GREEN_E: Color = Color("#699C52") +PURE_GREEN: Color = Color("#00FF00") +GREEN: Color = Color("#83C167") +YELLOW_A: Color = Color("#FFF1B6") +YELLOW_B: Color = Color("#FFEA94") +YELLOW_C: Color = Color("#FFFF00") +YELLOW_D: Color = Color("#F4D345") +YELLOW_E: Color = Color("#E8C11C") +YELLOW: Color = Color("#FFFF00") +GOLD_A: Color = Color("#F7C797") +GOLD_B: Color = Color("#F9B775") +GOLD_C: Color = Color("#F0AC5F") +GOLD_D: Color = Color("#E1A158") +GOLD_E: Color = Color("#C78D46") +GOLD: Color = Color("#F0AC5F") +RED_A: Color = Color("#F7A1A3") +RED_B: Color = Color("#FF8080") +RED_C: Color = Color("#FC6255") +RED_D: Color = Color("#E65A4C") +RED_E: Color = Color("#CF5044") +PURE_RED: Color = Color("#FF0000") +RED: Color = Color("#FC6255") +MAROON_A: Color = Color("#ECABC1") +MAROON_B: Color = Color("#EC92AB") +MAROON_C: Color = Color("#C55F73") +MAROON_D: Color = Color("#A24D61") +MAROON_E: Color = Color("#94424F") +MAROON: Color = Color("#C55F73") +PURPLE_A: Color = Color("#CAA3E8") +PURPLE_B: Color = Color("#B189C6") +PURPLE_C: Color = Color("#9A72AC") +PURPLE_D: Color = Color("#715582") +PURPLE_E: Color = Color("#644172") +PURPLE: Color = Color("#9A72AC") +PINK: Color = Color("#D147BD") +LIGHT_PINK: Color = Color("#DC75CD") +ORANGE: Color = Color("#FF862F") +LIGHT_BROWN: Color = Color("#CD853F") +DARK_BROWN: Color = Color("#8B4513") +GRAY_BROWN: Color = Color("#736357") +GREY_BROWN: Color = Color("#736357") + +ALL_COLORS = { + "WHITE": WHITE, + "GRAY_A": GRAY_A, + "GREY_A": GREY_B, + "GRAY_B": GRAY_B, + "GREY_B": GREY_B, + "GRAY_C": GRAY_C, + "GREY_C": GREY_C, + "GRAY_D": GRAY_D, + "GREY_D": GREY_D, + "GRAY_E": GRAY_E, + "GREY_E": GREY_E, + "BLACK": BLACK, + "LIGHTER_GRAY": LIGHTER_GRAY, + "LIGHTER_GREY": LIGHTER_GREY, + "LIGHT_GRAY": LIGHT_GRAY, + "LIGHT_GREY": LIGHT_GREY, + "GRAY": GRAY, + "GREY": GREY, + "DARK_GRAY": DARK_GRAY, + "DARK_GREY": DARK_GREY, + "DARKER_GRAY": DARKER_GRAY, + "DARKER_GREY": DARKER_GREY, + "BLUE_A": BLUE_A, + "BLUE_B": BLUE_B, + "BLUE_C": BLUE_C, + "BLUE_D": BLUE_D, + "BLUE_E": BLUE_E, + "PURE_BLUE": PURE_BLUE, + "BLUE": BLUE, + "DARK_BLUE": DARK_BLUE, + "TEAL_A": TEAL_A, + "TEAL_B": TEAL_B, + "TEAL_C": TEAL_C, + "TEAL_D": TEAL_D, + "TEAL_E": TEAL_E, + "TEAL": TEAL, + "GREEN_A": GREEN_A, + "GREEN_B": GREEN_B, + "GREEN_C": GREEN_C, + "GREEN_D": GREEN_D, + "GREEN_E": GREEN_E, + "PURE_GREEN": PURE_GREEN, + "GREEN": GREEN, + "YELLOW_A": YELLOW_A, + "YELLOW_B": YELLOW_B, + "YELLOW_C": YELLOW_C, + "YELLOW_D": YELLOW_D, + "YELLOW_E": YELLOW_E, + "YELLOW": YELLOW, + "GOLD_A": GOLD_A, + "GOLD_B": GOLD_B, + "GOLD_C": GOLD_C, + "GOLD_D": GOLD_D, + "GOLD_E": GOLD_E, + "GOLD": GOLD, + "RED_A": RED_A, + "RED_B": RED_B, + "RED_C": RED_C, + "RED_D": RED_D, + "RED_E": RED_E, + "PURE_RED": PURE_RED, + "RED": RED, + "MAROON_A": MAROON_A, + "MAROON_B": MAROON_B, + "MAROON_C": MAROON_C, + "MAROON_D": MAROON_D, + "MAROON_E": MAROON_E, + "MAROON": MAROON, + "PURPLE_A": PURPLE_A, + "PURPLE_B": PURPLE_B, + "PURPLE_C": PURPLE_C, + "PURPLE_D": PURPLE_D, + "PURPLE_E": PURPLE_E, + "PURPLE": PURPLE, + "PINK": PINK, + "LIGHT_PINK": LIGHT_PINK, + "ORANGE": ORANGE, + "LIGHT_BROWN": LIGHT_BROWN, + "DARK_BROWN": DARK_BROWN, + "GRAY_BROWN": GRAY_BROWN, + "GREY_BROWN": GREY_BROWN, +} __all__ += [ "WHITE", @@ -193,13 +277,9 @@ "DARK_BROWN", "GRAY_BROWN", "GREY_BROWN", + "ALL_COLORS", ] -color_map = dict(((colorName, value) for colorName, value in locals().items() if str(value).startswith("#"))) -all_colors = [c for colors, c in locals().items() if str(c).startswith("#")] - -def get_all_colors(): - return color_map def color_to_rgb(color: Color | str) -> np.ndarray: if isinstance(color, str): @@ -248,11 +328,13 @@ def color_to_int_rgba(color: Color, opacity: float = 1.0) -> np.ndarray: def color_gradient( - reference_colors: Iterable[Color], + reference_colors: Color | Iterable[Color], length_of_output: int, ) -> list[Color]: if length_of_output == 0: return reference_colors[0] + if isinstance(reference_colors, Color): + return list(reference_colors.range_to(reference_colors, length_of_output)) rgbs = list(map(color_to_rgb, reference_colors)) alphas = np.linspace(0, (len(rgbs) - 1), length_of_output) floors = alphas.astype("int") @@ -285,7 +367,8 @@ def random_bright_color() -> Color: def random_color() -> Color: - return random.choice(all_colors) + return random.choice(list(ALL_COLORS.values())) + def get_shaded_rgb( rgb: np.ndarray, From 707ce2b0d960ef9aeafee803444c9dabef422371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bror=20Sebastian=20Sj=C3=B6vald?= <49447840+BrorSebastianSjovald@users.noreply.github.com> Date: Mon, 7 Mar 2022 16:11:35 +0100 Subject: [PATCH 3/9] Add deprecation warnings for duplicate color functions (#10) * Added deprecation warnings for color conversions, feat #1 * Update and remove unecessary warnings, fix #1 * Added more specific deprecation warnings * Removed warnings from functions that are not in `colour` module * Fixed deprecation warning in `color_to_rgb`, fix #1 --- manim/utils/color.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/manim/utils/color.py b/manim/utils/color.py index 478f221164..ca5ac210fe 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -21,6 +21,7 @@ ] import random +import warnings from typing import Iterable import numpy as np @@ -281,7 +282,14 @@ ] + def color_to_rgb(color: Color | str) -> np.ndarray: + warnings.warn( + "This method is not guaranteed to stay around. " + "Please refer to colour module `Color.get_rgb` for Color to rgb conversion", + DeprecationWarning, + stacklevel=2, + ) if isinstance(color, str): return hex_to_rgb(color) elif isinstance(color, Color): @@ -303,10 +311,22 @@ def rgba_to_color(rgba: Iterable[float]) -> Color: def rgb_to_hex(rgb: Iterable[float]) -> str: + warnings.warn( + "This method is not guaranteed to stay around. " + "Please refer to colour module `rgb2hex` for rgb to hex conversion", + DeprecationWarning, + stacklevel=2, + ) return "#" + "".join("%02x" % round(255 * x) for x in rgb) def hex_to_rgb(hex_code: str) -> np.ndarray: + warnings.warn( + "This method is not guaranteed to stay around. " + "Please refer to colour module `hex2rgb` for hex to rgb conversion", + DeprecationWarning, + stacklevel=2, + ) hex_part = hex_code[1:] if len(hex_part) == 3: hex_part = "".join([2 * c for c in hex_part]) @@ -322,6 +342,7 @@ def color_to_int_rgb(color: Color) -> np.ndarray: def color_to_int_rgba(color: Color, opacity: float = 1.0) -> np.ndarray: + alpha_multiplier = np.vectorize(lambda x: int(x * opacity)) return alpha_multiplier(np.append(color_to_int_rgb(color), 255)) @@ -370,6 +391,7 @@ def random_color() -> Color: return random.choice(list(ALL_COLORS.values())) + def get_shaded_rgb( rgb: np.ndarray, point: np.ndarray, From be0efb7a664a3f2fbdb4ff5415ff1e034a17c652 Mon Sep 17 00:00:00 2001 From: Ludwig Johansson Date: Mon, 7 Mar 2022 16:37:11 +0100 Subject: [PATCH 4/9] 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 --- manim/utils/color.py | 339 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 337 insertions(+), 2 deletions(-) diff --git a/manim/utils/color.py b/manim/utils/color.py index ca5ac210fe..7d886cc26d 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -22,6 +22,7 @@ import random import warnings +from enum import Enum, EnumMeta from typing import Iterable import numpy as np @@ -30,6 +31,342 @@ from ..utils.bezier import interpolate from ..utils.space_ops import normalize + +class ColorsMeta(EnumMeta): + def __getattribute__(self, colorName): + colors = [ + "white", + "gray_a", + "gray_b", + "gray_c", + "gray_d", + "gray_e", + "black", + "lighter_gray", + "gray", + "darker_gray", + "blue_a", + "blue_b", + "blue_c", + "blue_d", + "blue_e", + "pure_blue", + "blue", + "dark_blue", + "teal_a", + "teal_b", + "teal_c", + "teal_d", + "teal_e", + "teal", + "green_a", + "green_b", + "green_c", + "green_d", + "green_e", + "pure_green", + "green", + "yellow_a", + "yellow_b", + "yellow_c", + "yellow_d", + "yellow_e", + "yellow", + "gold_a", + "gold_b", + "gold_c", + "gold_d", + "gold_e", + "gold", + "red_a", + "red_b", + "red_c", + "red_d", + "red_e", + "pure_red", + "red", + "maroon_a", + "maroon_b", + "maroon_c", + "maroon_d", + "maroon_e", + "maroon", + "purple_a", + "purple_b", + "purple_c", + "purple_d", + "purple_e", + "purple", + "pink", + "light_pink", + "orange", + "light_brown", + "dark_brown", + "gray_brown", + ] + if colorName in colors: + warnings.warn( + "Color enums is deprecated in favor of the constants. " + "The constants can be accessed by importing manim.utils.color", + DeprecationWarning, + stacklevel=2, + ) + return EnumMeta.__getattribute__(self, colorName) + + +class Colors(Enum, metaclass=ColorsMeta): + """A list of pre-defined colors. + + Examples + -------- + + .. manim:: ColorsOverview + :save_last_frame: + :hide_source: + + from manim.utils.color import Colors + class ColorsOverview(Scene): + def construct(self): + def color_group(color): + group = VGroup( + *[ + Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=Colors[name].value) + for name in subnames(color) + ] + ).arrange_submobjects(buff=0.4, direction=DOWN) + + name = Text(color).scale(0.6).next_to(group, UP, buff=0.3) + if any(decender in color for decender in "gjpqy"): + name.shift(DOWN * 0.08) + group.add(name) + return group + + def subnames(name): + return [name + "_" + char for char in "abcde"] + + color_groups = VGroup( + *[ + color_group(color) + for color in [ + "blue", + "teal", + "green", + "yellow", + "gold", + "red", + "maroon", + "purple", + ] + ] + ).arrange_submobjects(buff=0.2, aligned_edge=DOWN) + + for line, char in zip(color_groups[0], "abcde"): + color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2)) + + def named_lines_group(length, colors, names, text_colors, align_to_block): + lines = VGroup( + *[ + Line( + ORIGIN, + RIGHT * length, + stroke_width=55, + color=Colors[color].value, + ) + for color in colors + ] + ).arrange_submobjects(buff=0.6, direction=DOWN) + + for line, name, color in zip(lines, names, text_colors): + line.add(Text(name, color=color).scale(0.6).move_to(line)) + lines.next_to(color_groups, DOWN, buff=0.5).align_to( + color_groups[align_to_block], LEFT + ) + return lines + + other_colors = ( + "pink", + "light_pink", + "orange", + "light_brown", + "dark_brown", + "gray_brown", + ) + + other_lines = named_lines_group( + 3.2, + other_colors, + other_colors, + [BLACK] * 4 + [WHITE] * 2, + 0, + ) + + gray_lines = named_lines_group( + 6.6, + ["white"] + subnames("gray") + ["black"], + [ + "white", + "lighter_gray / gray_a", + "light_gray / gray_b", + "gray / gray_c", + "dark_gray / gray_d", + "darker_gray / gray_e", + "black", + ], + [BLACK] * 3 + [WHITE] * 4, + 2, + ) + + pure_colors = ( + "pure_red", + "pure_green", + "pure_blue", + ) + + pure_lines = named_lines_group( + 3.2, + pure_colors, + pure_colors, + [BLACK, BLACK, WHITE], + 6, + ) + + self.add(color_groups, other_lines, gray_lines, pure_lines) + + VGroup(*self.mobjects).move_to(ORIGIN) + + + The preferred way of using these colors is by importing their constants from manim: + + .. code-block:: pycon + + >>> from manim import RED, GREEN, BLUE + >>> RED + '#FC6255' + + Note this way uses the name of the colors in UPPERCASE. + + Alternatively, you can also import this Enum directly and use its members + directly, through the use of :code:`color.value`. Note this way uses the + name of the colors in lowercase. + + .. code-block:: pycon + + >>> from manim.utils.color import Colors + >>> Colors.red.value + '#FC6255' + + .. note:: + + The colors of type "C" have an alias equal to the colorname without a letter, + e.g. GREEN = GREEN_C + + """ + + white: str = "#FFFFFF" + gray_a: str = "#DDDDDD" + gray_b: str = "#BBBBBB" + gray_c: str = "#888888" + gray_d: str = "#444444" + gray_e: str = "#222222" + black: str = "#000000" + lighter_gray: str = gray_a + light_gray: str = gray_b + gray: str = gray_c + dark_gray: str = gray_d + darker_gray: str = gray_e + + blue_a: str = "#C7E9F1" + blue_b: str = "#9CDCEB" + blue_c: str = "#58C4DD" + blue_d: str = "#29ABCA" + blue_e: str = "#236B8E" + pure_blue: str = "#0000FF" + blue: str = blue_c + dark_blue: str = blue_e + + teal_a: str = "#ACEAD7" + teal_b: str = "#76DDC0" + teal_c: str = "#5CD0B3" + teal_d: str = "#55C1A7" + teal_e: str = "#49A88F" + teal: str = teal_c + + green_a: str = "#C9E2AE" + green_b: str = "#A6CF8C" + green_c: str = "#83C167" + green_d: str = "#77B05D" + green_e: str = "#699C52" + pure_green: str = "#00FF00" + green: str = green_c + + yellow_a: str = "#FFF1B6" + yellow_b: str = "#FFEA94" + yellow_c: str = "#FFFF00" + yellow_d: str = "#F4D345" + yellow_e: str = "#E8C11C" + yellow: str = yellow_c + + gold_a: str = "#F7C797" + gold_b: str = "#F9B775" + gold_c: str = "#F0AC5F" + gold_d: str = "#E1A158" + gold_e: str = "#C78D46" + gold: str = gold_c + + red_a: str = "#F7A1A3" + red_b: str = "#FF8080" + red_c: str = "#FC6255" + red_d: str = "#E65A4C" + red_e: str = "#CF5044" + pure_red: str = "#FF0000" + red: str = red_c + + maroon_a: str = "#ECABC1" + maroon_b: str = "#EC92AB" + maroon_c: str = "#C55F73" + maroon_d: str = "#A24D61" + maroon_e: str = "#94424F" + maroon: str = maroon_c + + purple_a: str = "#CAA3E8" + purple_b: str = "#B189C6" + purple_c: str = "#9A72AC" + purple_d: str = "#715582" + purple_e: str = "#644172" + purple: str = purple_c + + pink: str = "#D147BD" + light_pink: str = "#DC75CD" + + orange: str = "#FF862F" + light_brown: str = "#CD853F" + dark_brown: str = "#8B4513" + gray_brown: str = "#736357" + + +def print_constant_definitions(): + """ + A simple function used to generate the constant values below. To run it + paste this function and the Colors class into a file and run them. + """ + constants_names: list[str] = [] + for name in Colors.__members__.keys(): + name_upper = name.upper() + + constants_names.append(name_upper) + print(f"{name_upper} = Colors.{name}") + + if "GRAY" in name_upper: + name_upper = name_upper.replace("GRAY", "GREY") + + constants_names.append(name_upper) + print(f"{name_upper} = Colors.{name}") + + constants_names_repr = '[\n "' + '",\n "'.join(constants_names) + '",\n]' + + print(f"\n__all__ += {constants_names_repr}") + + WHITE: Color = Color("#FFFFFF") GRAY_A: Color = Color("#DDDDDD") GREY_A: Color = Color("#DDDDDD") @@ -282,7 +619,6 @@ ] - def color_to_rgb(color: Color | str) -> np.ndarray: warnings.warn( "This method is not guaranteed to stay around. " @@ -391,7 +727,6 @@ def random_color() -> Color: return random.choice(list(ALL_COLORS.values())) - def get_shaded_rgb( rgb: np.ndarray, point: np.ndarray, From fd261774494323e216a86d70093ddcb0def60f09 Mon Sep 17 00:00:00 2001 From: BrorSebastianSjovald Date: Wed, 9 Mar 2022 14:06:12 +0100 Subject: [PATCH 5/9] Changed `warnings` to `deprecated` decorations --- manim/utils/color.py | 106 ++----------------------------------------- 1 file changed, 4 insertions(+), 102 deletions(-) diff --git a/manim/utils/color.py b/manim/utils/color.py index 7d886cc26d..7eba30272b 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -22,99 +22,19 @@ import random import warnings -from enum import Enum, EnumMeta +from enum import Enum from typing import Iterable import numpy as np from colour import Color from ..utils.bezier import interpolate +from ..utils.deprecation import deprecated from ..utils.space_ops import normalize -class ColorsMeta(EnumMeta): - def __getattribute__(self, colorName): - colors = [ - "white", - "gray_a", - "gray_b", - "gray_c", - "gray_d", - "gray_e", - "black", - "lighter_gray", - "gray", - "darker_gray", - "blue_a", - "blue_b", - "blue_c", - "blue_d", - "blue_e", - "pure_blue", - "blue", - "dark_blue", - "teal_a", - "teal_b", - "teal_c", - "teal_d", - "teal_e", - "teal", - "green_a", - "green_b", - "green_c", - "green_d", - "green_e", - "pure_green", - "green", - "yellow_a", - "yellow_b", - "yellow_c", - "yellow_d", - "yellow_e", - "yellow", - "gold_a", - "gold_b", - "gold_c", - "gold_d", - "gold_e", - "gold", - "red_a", - "red_b", - "red_c", - "red_d", - "red_e", - "pure_red", - "red", - "maroon_a", - "maroon_b", - "maroon_c", - "maroon_d", - "maroon_e", - "maroon", - "purple_a", - "purple_b", - "purple_c", - "purple_d", - "purple_e", - "purple", - "pink", - "light_pink", - "orange", - "light_brown", - "dark_brown", - "gray_brown", - ] - if colorName in colors: - warnings.warn( - "Color enums is deprecated in favor of the constants. " - "The constants can be accessed by importing manim.utils.color", - DeprecationWarning, - stacklevel=2, - ) - return EnumMeta.__getattribute__(self, colorName) - - -class Colors(Enum, metaclass=ColorsMeta): +@deprecated(replacement="constants") +class Colors(Enum): """A list of pre-defined colors. Examples @@ -620,12 +540,6 @@ def print_constant_definitions(): def color_to_rgb(color: Color | str) -> np.ndarray: - warnings.warn( - "This method is not guaranteed to stay around. " - "Please refer to colour module `Color.get_rgb` for Color to rgb conversion", - DeprecationWarning, - stacklevel=2, - ) if isinstance(color, str): return hex_to_rgb(color) elif isinstance(color, Color): @@ -647,22 +561,10 @@ def rgba_to_color(rgba: Iterable[float]) -> Color: def rgb_to_hex(rgb: Iterable[float]) -> str: - warnings.warn( - "This method is not guaranteed to stay around. " - "Please refer to colour module `rgb2hex` for rgb to hex conversion", - DeprecationWarning, - stacklevel=2, - ) return "#" + "".join("%02x" % round(255 * x) for x in rgb) def hex_to_rgb(hex_code: str) -> np.ndarray: - warnings.warn( - "This method is not guaranteed to stay around. " - "Please refer to colour module `hex2rgb` for hex to rgb conversion", - DeprecationWarning, - stacklevel=2, - ) hex_part = hex_code[1:] if len(hex_part) == 3: hex_part = "".join([2 * c for c in hex_part]) From 6698ec276f52181f5880d20e44a2b11ab30efcbd Mon Sep 17 00:00:00 2001 From: BrorSebastianSjovald Date: Wed, 9 Mar 2022 14:12:00 +0100 Subject: [PATCH 6/9] Fixed doctest to new type of constants --- manim/utils/color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/utils/color.py b/manim/utils/color.py index 7eba30272b..80981bcda9 100644 --- a/manim/utils/color.py +++ b/manim/utils/color.py @@ -161,7 +161,7 @@ def named_lines_group(length, colors, names, text_colors, align_to_block): >>> from manim import RED, GREEN, BLUE >>> RED - '#FC6255' + Note this way uses the name of the colors in UPPERCASE. From 254a5269147b838aa4b51d0264db5f880155ec7f Mon Sep 17 00:00:00 2001 From: BrorSebastianSjovald Date: Wed, 9 Mar 2022 14:13:16 +0100 Subject: [PATCH 7/9] Fixed pre-commit issues --- manim/mobject/mobject.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index f45d288934..d28a772710 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -35,13 +35,7 @@ from .. import config from ..constants import * -from ..utils.color import ( - BLACK, - WHITE, - YELLOW_C, - color_gradient, - interpolate_color, -) +from ..utils.color import BLACK, WHITE, YELLOW_C, color_gradient, interpolate_color from ..utils.exceptions import MultiAnimationOverrideException from ..utils.iterables import list_update, remove_list_redundancies from ..utils.paths import straight_path From 863333532f0f4c7b63515f31fa1e3fd8eb2d6951 Mon Sep 17 00:00:00 2001 From: BrorSebastianSjovald Date: Wed, 9 Mar 2022 14:14:12 +0100 Subject: [PATCH 8/9] Removed uneccessary comment in imports --- manim/mobject/text/text_mobject.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/manim/mobject/text/text_mobject.py b/manim/mobject/text/text_mobject.py index 8423077805..415c8e3ea0 100644 --- a/manim/mobject/text/text_mobject.py +++ b/manim/mobject/text/text_mobject.py @@ -71,8 +71,6 @@ def construct(self): from manim.mobject.geometry.arc import Dot from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject - -# from manim.utils.color import * from manim.utils.color import ALL_COLORS from manim.utils.deprecation import deprecated From 5334848a6b283ef4cca693ed238c087c81b47b2a Mon Sep 17 00:00:00 2001 From: BrorSebastianSjovald Date: Wed, 9 Mar 2022 14:40:09 +0100 Subject: [PATCH 9/9] Added missing import for example --- manim/mobject/text/text_mobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/mobject/text/text_mobject.py b/manim/mobject/text/text_mobject.py index 415c8e3ea0..e98d850a6d 100644 --- a/manim/mobject/text/text_mobject.py +++ b/manim/mobject/text/text_mobject.py @@ -71,7 +71,7 @@ def construct(self): from manim.mobject.geometry.arc import Dot from manim.mobject.svg.svg_mobject import SVGMobject from manim.mobject.types.vectorized_mobject import VGroup, VMobject -from manim.utils.color import ALL_COLORS +from manim.utils.color import ALL_COLORS, color_gradient from manim.utils.deprecation import deprecated TEXT_MOB_SCALE_FACTOR = 0.05