From fd2a6a69e56f6e7a0069d0d395915ecbd7264ef0 Mon Sep 17 00:00:00 2001 From: Abdallah Soliman Date: Tue, 10 Jun 2025 16:15:55 +0100 Subject: [PATCH] Created a method ``remove_all_except()`` in scene.py and interactive_scene.py, and made default colors easily configurable. (#2346) * created a method remove_all_except() in scene.py and interactive_scene.py * Made it such that default mobject colors can be set through the yaml config file. * * Default color initialisation wasn't working. Changed conditional expression to `or` instead. * Added default values to yaml file. * added set_background_color() function to Scene class * Changed default font back to Consolas --- .gitignore | 1 + manimlib/constants.py | 9 +++++++++ manimlib/default_config.yml | 6 ++++++ manimlib/mobject/changing.py | 6 +++--- manimlib/mobject/coordinate_systems.py | 4 ++-- manimlib/mobject/geometry.py | 14 +++++++------- manimlib/mobject/interactive.py | 4 ++-- manimlib/mobject/mobject.py | 4 ++-- manimlib/mobject/number_line.py | 4 ++-- manimlib/mobject/numbers.py | 4 ++-- manimlib/mobject/shape_matchers.py | 4 ++-- manimlib/mobject/svg/old_tex_mobject.py | 6 +++--- manimlib/mobject/svg/special_tex.py | 4 ++-- manimlib/mobject/svg/string_mobject.py | 10 +++++----- manimlib/mobject/types/vectorized_mobject.py | 8 +++----- manimlib/mobject/vector_field.py | 4 ++-- manimlib/scene/interactive_scene.py | 4 ++++ manimlib/scene/scene.py | 11 +++++++++++ 18 files changed, 68 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 71be35c4..c8350ec3 100644 --- a/.gitignore +++ b/.gitignore @@ -151,3 +151,4 @@ dmypy.json # For manim /videos /custom_config.yml +test.py diff --git a/manimlib/constants.py b/manimlib/constants.py index f5ac8239..62192825 100644 --- a/manimlib/constants.py +++ b/manimlib/constants.py @@ -148,3 +148,12 @@ PURPLE: ManimColor = PURPLE_C GREY: ManimColor = GREY_C COLORMAP_3B1B: List[ManimColor] = [BLUE_E, GREEN, YELLOW, RED] + +# Default mobject colors should be configurable just like background color +# DEFAULT_MOBJECT_COLOR is mainly for text, tex, line, etc... mobjects. Default is WHITE +# DEFAULT_LIGHT_COLOR is mainly for things like axes, arrows, annulus and other lightly colored mobjects. Default is GREY_B +DEFAULT_MOBJECT_COLOR: ManimColor = manim_config.mobject.default_mobject_color or WHITE +DEFAULT_LIGHT_COLOR: ManimColor = manim_config.mobject.default_light_color or GREY_B + +DEFAULT_VMOBJECT_STROKE_COLOR : ManimColor = manim_config.vmobject.default_stroke_color or GREY_A +DEFAULT_VMOBJECT_FILL_COLOR : ManimColor = manim_config.vmobject.default_fill_color or GREY_C diff --git a/manimlib/default_config.yml b/manimlib/default_config.yml index ad84ccaa..098c6c45 100644 --- a/manimlib/default_config.yml +++ b/manimlib/default_config.yml @@ -71,10 +71,16 @@ scene: default_wait_time: 1.0 vmobject: default_stroke_width: 4.0 + default_stroke_color: "#DDDDDD" # Default is GREY_A + default_fill_color: "#888888" # Default is GREY_C +mobject: + default_mobject_color: "#FFFFFF" # Default is WHITE + default_light_color: "#BBBBBB" # Default is GREY_B tex: # See tex_templates.yml template: "default" text: + # font: "Cambria Math" font: "Consolas" alignment: "LEFT" embed: diff --git a/manimlib/mobject/changing.py b/manimlib/mobject/changing.py index 0c3c17f6..15c0b504 100644 --- a/manimlib/mobject/changing.py +++ b/manimlib/mobject/changing.py @@ -2,7 +2,7 @@ from __future__ import annotations import numpy as np -from manimlib.constants import BLUE_B, BLUE_D, BLUE_E, GREY_BROWN, WHITE +from manimlib.constants import BLUE_B, BLUE_D, BLUE_E, GREY_BROWN, DEFAULT_MOBJECT_COLOR from manimlib.mobject.mobject import Mobject from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.mobject.types.vectorized_mobject import VMobject @@ -102,7 +102,7 @@ class TracedPath(VMobject): time_traced: float = np.inf, time_per_anchor: float = 1.0 / 15, stroke_width: float | Iterable[float] = 2.0, - stroke_color: ManimColor = WHITE, + stroke_color: ManimColor = DEFAULT_MOBJECT_COLOR, **kwargs ): super().__init__(**kwargs) @@ -147,7 +147,7 @@ class TracingTail(TracedPath): time_traced: float = 1.0, stroke_width: float | Iterable[float] = (0, 3), stroke_opacity: float | Iterable[float] = (0, 1), - stroke_color: ManimColor = WHITE, + stroke_color: ManimColor = DEFAULT_MOBJECT_COLOR, **kwargs ): if isinstance(mobject_or_func, Mobject): diff --git a/manimlib/mobject/coordinate_systems.py b/manimlib/mobject/coordinate_systems.py index c51bf4cc..bb8b5aa1 100644 --- a/manimlib/mobject/coordinate_systems.py +++ b/manimlib/mobject/coordinate_systems.py @@ -6,7 +6,7 @@ import numbers import numpy as np import itertools as it -from manimlib.constants import BLACK, BLUE, BLUE_D, BLUE_E, GREEN, GREY_A, WHITE, RED +from manimlib.constants import BLACK, BLUE, BLUE_D, BLUE_E, GREEN, GREY_A, RED, DEFAULT_MOBJECT_COLOR from manimlib.constants import DEG, PI from manimlib.constants import DL, UL, DOWN, DR, LEFT, ORIGIN, OUT, RIGHT, UP from manimlib.constants import FRAME_X_RADIUS, FRAME_Y_RADIUS @@ -617,7 +617,7 @@ class ThreeDAxes(Axes): class NumberPlane(Axes): default_axis_config: dict = dict( - stroke_color=WHITE, + stroke_color=DEFAULT_MOBJECT_COLOR, stroke_width=2, include_ticks=False, include_tip=False, diff --git a/manimlib/mobject/geometry.py b/manimlib/mobject/geometry.py index 1ea875a8..4999b556 100644 --- a/manimlib/mobject/geometry.py +++ b/manimlib/mobject/geometry.py @@ -5,7 +5,7 @@ import math import numpy as np from manimlib.constants import DL, DOWN, DR, LEFT, ORIGIN, OUT, RIGHT, UL, UP, UR -from manimlib.constants import GREY_A, RED, WHITE, BLACK +from manimlib.constants import RED, BLACK, DEFAULT_MOBJECT_COLOR, DEFAULT_LIGHT_COLOR from manimlib.constants import MED_SMALL_BUFF, SMALL_BUFF from manimlib.constants import DEG, PI, TAU from manimlib.mobject.mobject import Mobject @@ -330,7 +330,7 @@ class Dot(Circle): stroke_color: ManimColor = BLACK, stroke_width: float = 0.0, fill_opacity: float = 1.0, - fill_color: ManimColor = WHITE, + fill_color: ManimColor = DEFAULT_MOBJECT_COLOR, **kwargs ): super().__init__( @@ -374,7 +374,7 @@ class AnnularSector(VMobject): inner_radius: float = 1.0, outer_radius: float = 2.0, arc_center: Vect3 = ORIGIN, - fill_color: ManimColor = GREY_A, + fill_color: ManimColor = DEFAULT_LIGHT_COLOR, fill_opacity: float = 1.0, stroke_width: float = 0.0, **kwargs, @@ -424,7 +424,7 @@ class Annulus(VMobject): outer_radius: float = 2.0, fill_opacity: float = 1.0, stroke_width: float = 0.0, - fill_color: ManimColor = GREY_A, + fill_color: ManimColor = DEFAULT_LIGHT_COLOR, center: Vect3 = ORIGIN, **kwargs, ): @@ -644,7 +644,7 @@ class StrokeArrow(Line): self, start: Vect3 | Mobject, end: Vect3 | Mobject, - stroke_color: ManimColor = GREY_A, + stroke_color: ManimColor = DEFAULT_LIGHT_COLOR, stroke_width: float = 5, buff: float = 0.25, tip_width_ratio: float = 5, @@ -744,7 +744,7 @@ class Arrow(Line): end: Vect3 | Mobject = LEFT, buff: float = MED_SMALL_BUFF, path_arc: float = 0, - fill_color: ManimColor = GREY_A, + fill_color: ManimColor = DEFAULT_LIGHT_COLOR, fill_opacity: float = 1.0, stroke_width: float = 0.0, thickness: float = 3.0, @@ -1008,7 +1008,7 @@ class ArrowTip(Triangle): width: float = DEFAULT_ARROW_TIP_WIDTH, length: float = DEFAULT_ARROW_TIP_LENGTH, fill_opacity: float = 1.0, - fill_color: ManimColor = WHITE, + fill_color: ManimColor = DEFAULT_MOBJECT_COLOR, stroke_width: float = 0.0, tip_style: int = 0, # triangle=0, inner_smooth=1, dot=2 **kwargs diff --git a/manimlib/mobject/interactive.py b/manimlib/mobject/interactive.py index 50bc87c5..aaadaeb3 100644 --- a/manimlib/mobject/interactive.py +++ b/manimlib/mobject/interactive.py @@ -6,7 +6,7 @@ from pyglet.window import key as PygletWindowKeys from manimlib.constants import FRAME_HEIGHT, FRAME_WIDTH from manimlib.constants import DOWN, LEFT, ORIGIN, RIGHT, UP from manimlib.constants import MED_LARGE_BUFF, MED_SMALL_BUFF, SMALL_BUFF -from manimlib.constants import BLACK, BLUE, GREEN, GREY_A, GREY_C, RED, WHITE +from manimlib.constants import BLACK, BLUE, GREEN, GREY_A, GREY_C, RED, WHITE, DEFAULT_MOBJECT_COLOR from manimlib.mobject.mobject import Group from manimlib.mobject.mobject import Mobject from manimlib.mobject.geometry import Circle @@ -387,7 +387,7 @@ class Textbox(ControlMobject): box_kwargs: dict = { "width": 2.0, "height": 1.0, - "fill_color": WHITE, + "fill_color": DEFAULT_MOBJECT_COLOR, "fill_opacity": 1.0, }, text_kwargs: dict = { diff --git a/manimlib/mobject/mobject.py b/manimlib/mobject/mobject.py index cdc4bfc2..6fc99055 100644 --- a/manimlib/mobject/mobject.py +++ b/manimlib/mobject/mobject.py @@ -18,7 +18,7 @@ from manimlib.constants import DOWN, IN, LEFT, ORIGIN, OUT, RIGHT, UP from manimlib.constants import FRAME_X_RADIUS, FRAME_Y_RADIUS from manimlib.constants import MED_SMALL_BUFF from manimlib.constants import TAU -from manimlib.constants import WHITE +from manimlib.constants import DEFAULT_MOBJECT_COLOR from manimlib.event_handler import EVENT_DISPATCHER from manimlib.event_handler.event_listner import EventListener from manimlib.event_handler.event_type import EventType @@ -78,7 +78,7 @@ class Mobject(object): def __init__( self, - color: ManimColor = WHITE, + color: ManimColor = DEFAULT_MOBJECT_COLOR, opacity: float = 1.0, shading: Tuple[float, float, float] = (0.0, 0.0, 0.0), # For shaders diff --git a/manimlib/mobject/number_line.py b/manimlib/mobject/number_line.py index 57456eff..eedbe7c3 100644 --- a/manimlib/mobject/number_line.py +++ b/manimlib/mobject/number_line.py @@ -3,7 +3,7 @@ from __future__ import annotations import numpy as np from manimlib.constants import DOWN, LEFT, RIGHT, UP -from manimlib.constants import GREY_B +from manimlib.constants import DEFAULT_LIGHT_COLOR from manimlib.constants import MED_SMALL_BUFF from manimlib.mobject.geometry import Line from manimlib.mobject.numbers import DecimalNumber @@ -24,7 +24,7 @@ class NumberLine(Line): def __init__( self, x_range: RangeSpecifier = (-8, 8, 1), - color: ManimColor = GREY_B, + color: ManimColor = DEFAULT_LIGHT_COLOR, stroke_width: float = 2.0, # How big is one one unit of this number line in terms of absolute spacial distance unit_size: float = 1.0, diff --git a/manimlib/mobject/numbers.py b/manimlib/mobject/numbers.py index 7009dee7..7fd8fe4d 100644 --- a/manimlib/mobject/numbers.py +++ b/manimlib/mobject/numbers.py @@ -4,7 +4,7 @@ from functools import lru_cache import numpy as np from manimlib.constants import DOWN, LEFT, RIGHT, UP -from manimlib.constants import WHITE +from manimlib.constants import DEFAULT_MOBJECT_COLOR from manimlib.mobject.svg.tex_mobject import Tex from manimlib.mobject.svg.text_mobject import Text from manimlib.mobject.types.vectorized_mobject import VMobject @@ -35,7 +35,7 @@ class DecimalNumber(VMobject): def __init__( self, number: float | complex = 0, - color: ManimColor = WHITE, + color: ManimColor = DEFAULT_MOBJECT_COLOR, stroke_width: float = 0, fill_opacity: float = 1.0, fill_border_width: float = 0.5, diff --git a/manimlib/mobject/shape_matchers.py b/manimlib/mobject/shape_matchers.py index 8faae9c5..123f717a 100644 --- a/manimlib/mobject/shape_matchers.py +++ b/manimlib/mobject/shape_matchers.py @@ -3,7 +3,7 @@ from __future__ import annotations from colour import Color from manimlib.config import manim_config -from manimlib.constants import BLACK, RED, YELLOW, WHITE +from manimlib.constants import BLACK, RED, YELLOW, DEFAULT_MOBJECT_COLOR from manimlib.constants import DL, DOWN, DR, LEFT, RIGHT, UL, UR from manimlib.constants import SMALL_BUFF from manimlib.mobject.geometry import Line @@ -118,7 +118,7 @@ class Underline(Line): self, mobject: Mobject, buff: float = SMALL_BUFF, - stroke_color=WHITE, + stroke_color=DEFAULT_MOBJECT_COLOR, stroke_width: float | Sequence[float] = [0, 3, 3, 0], stretch_factor=1.2, **kwargs diff --git a/manimlib/mobject/svg/old_tex_mobject.py b/manimlib/mobject/svg/old_tex_mobject.py index 7adc216e..56b5dd57 100644 --- a/manimlib/mobject/svg/old_tex_mobject.py +++ b/manimlib/mobject/svg/old_tex_mobject.py @@ -4,7 +4,7 @@ from functools import reduce import operator as op import re -from manimlib.constants import BLACK, WHITE +from manimlib.constants import BLACK, DEFAULT_MOBJECT_COLOR from manimlib.mobject.svg.svg_mobject import SVGMobject from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.utils.tex_file_writing import latex_to_svg @@ -26,10 +26,10 @@ class SingleStringTex(SVGMobject): self, tex_string: str, height: float | None = None, - fill_color: ManimColor = WHITE, + fill_color: ManimColor = DEFAULT_MOBJECT_COLOR, fill_opacity: float = 1.0, stroke_width: float = 0, - svg_default: dict = dict(fill_color=WHITE), + svg_default: dict = dict(fill_color=DEFAULT_MOBJECT_COLOR), path_string_config: dict = dict(), font_size: int = 48, alignment: str = R"\centering", diff --git a/manimlib/mobject/svg/special_tex.py b/manimlib/mobject/svg/special_tex.py index f933a11e..4dfa79e3 100644 --- a/manimlib/mobject/svg/special_tex.py +++ b/manimlib/mobject/svg/special_tex.py @@ -1,6 +1,6 @@ from __future__ import annotations -from manimlib.constants import MED_SMALL_BUFF, WHITE, GREY_C +from manimlib.constants import MED_SMALL_BUFF, DEFAULT_MOBJECT_COLOR, GREY_C from manimlib.constants import DOWN, LEFT, RIGHT, UP from manimlib.constants import FRAME_WIDTH from manimlib.constants import MED_LARGE_BUFF, SMALL_BUFF @@ -46,7 +46,7 @@ class BulletedList(VGroup): class TexTextFromPresetString(TexText): tex: str = "" - default_color: ManimColor = WHITE + default_color: ManimColor = DEFAULT_MOBJECT_COLOR def __init__(self, **kwargs): super().__init__( diff --git a/manimlib/mobject/svg/string_mobject.py b/manimlib/mobject/svg/string_mobject.py index 8e1631ba..660a6b32 100644 --- a/manimlib/mobject/svg/string_mobject.py +++ b/manimlib/mobject/svg/string_mobject.py @@ -6,7 +6,7 @@ import re from scipy.optimize import linear_sum_assignment from scipy.spatial.distance import cdist -from manimlib.constants import WHITE +from manimlib.constants import DEFAULT_MOBJECT_COLOR from manimlib.logger import log from manimlib.mobject.svg.svg_mobject import SVGMobject from manimlib.mobject.types.vectorized_mobject import VMobject @@ -46,11 +46,11 @@ class StringMobject(SVGMobject, ABC): def __init__( self, string: str, - fill_color: ManimColor = WHITE, + fill_color: ManimColor = DEFAULT_MOBJECT_COLOR, fill_border_width: float = 0.5, - stroke_color: ManimColor = WHITE, + stroke_color: ManimColor = DEFAULT_MOBJECT_COLOR, stroke_width: float = 0, - base_color: ManimColor = WHITE, + base_color: ManimColor = DEFAULT_MOBJECT_COLOR, isolate: Selector = (), protect: Selector = (), # When set to true, only the labelled svg is @@ -60,7 +60,7 @@ class StringMobject(SVGMobject, ABC): **kwargs ): self.string = string - self.base_color = base_color or WHITE + self.base_color = base_color or DEFAULT_MOBJECT_COLOR self.isolate = isolate self.protect = protect self.use_labelled_svg = use_labelled_svg diff --git a/manimlib/mobject/types/vectorized_mobject.py b/manimlib/mobject/types/vectorized_mobject.py index 1db4d9c8..912afe0c 100644 --- a/manimlib/mobject/types/vectorized_mobject.py +++ b/manimlib/mobject/types/vectorized_mobject.py @@ -5,6 +5,7 @@ from functools import wraps import numpy as np from manimlib.constants import GREY_A, GREY_C, GREY_E +from manimlib.constants import DEFAULT_VMOBJECT_FILL_COLOR, DEFAULT_VMOBJECT_STROKE_COLOR from manimlib.constants import BLACK from manimlib.constants import DEFAULT_STROKE_WIDTH from manimlib.constants import DEG @@ -53,9 +54,6 @@ if TYPE_CHECKING: from manimlib.typing import ManimColor, Vect3, Vect4, Vect3Array, Self from moderngl.context import Context -DEFAULT_STROKE_COLOR = GREY_A -DEFAULT_FILL_COLOR = GREY_C - class VMobject(Mobject): data_dtype: np.dtype = np.dtype([ @@ -99,9 +97,9 @@ class VMobject(Mobject): fill_border_width: float = 0.0, **kwargs ): - self.fill_color = fill_color or color or DEFAULT_FILL_COLOR + self.fill_color = fill_color or color or DEFAULT_VMOBJECT_FILL_COLOR self.fill_opacity = fill_opacity - self.stroke_color = stroke_color or color or DEFAULT_STROKE_COLOR + self.stroke_color = stroke_color or color or DEFAULT_VMOBJECT_STROKE_COLOR self.stroke_opacity = stroke_opacity self.stroke_width = stroke_width self.stroke_behind = stroke_behind diff --git a/manimlib/mobject/vector_field.py b/manimlib/mobject/vector_field.py index 0eda2c30..c1758d22 100644 --- a/manimlib/mobject/vector_field.py +++ b/manimlib/mobject/vector_field.py @@ -6,7 +6,7 @@ import numpy as np from scipy.integrate import solve_ivp from manimlib.constants import FRAME_HEIGHT, FRAME_WIDTH -from manimlib.constants import WHITE +from manimlib.constants import DEFAULT_MOBJECT_COLOR from manimlib.animation.indication import VShowPassingFlash from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.mobject.types.vectorized_mobject import VMobject @@ -351,7 +351,7 @@ class StreamLines(VGroup): cutoff_norm: float = 15, # Style info stroke_width: float = 1.0, - stroke_color: ManimColor = WHITE, + stroke_color: ManimColor = DEFAULT_MOBJECT_COLOR, stroke_opacity: float = 1, color_by_magnitude: bool = True, magnitude_range: Tuple[float, float] = (0, 2.0), diff --git a/manimlib/scene/interactive_scene.py b/manimlib/scene/interactive_scene.py index e54fa989..c4a4214f 100644 --- a/manimlib/scene/interactive_scene.py +++ b/manimlib/scene/interactive_scene.py @@ -245,6 +245,10 @@ class InteractiveScene(Scene): super().remove(*mobjects) self.regenerate_selection_search_set() + def remove_all_except(self, *mobjects_to_keep : Mobject): + super().remove_all_except(*mobjects_to_keep) + self.regenerate_selection_search_set() + # Related to selection def toggle_selection_mode(self): diff --git a/manimlib/scene/scene.py b/manimlib/scene/scene.py index c43be957..6ca06c3f 100644 --- a/manimlib/scene/scene.py +++ b/manimlib/scene/scene.py @@ -33,6 +33,7 @@ from manimlib.utils.family_ops import extract_mobject_family_members from manimlib.utils.family_ops import recursive_mobject_remove from manimlib.utils.iterables import batch_by_property from manimlib.utils.sounds import play_sound +from manimlib.utils.color import color_to_rgba from manimlib.window import Window from typing import TYPE_CHECKING @@ -380,6 +381,11 @@ class Scene(object): new_mobjects, _ = recursive_mobject_remove(self.mobjects, to_remove) self.mobjects = new_mobjects + @affects_mobject_list + def remove_all_except(self, *mobjects_to_keep : Mobject): + self.clear() + self.add(*mobjects_to_keep) + def bring_to_front(self, *mobjects: Mobject): self.add(*mobjects) return self @@ -867,6 +873,11 @@ class Scene(object): return self.window.focus() + def set_background_color(self, background_color, background_opacity=1) -> None: + self.camera.background_rgba = list(color_to_rgba( + background_color, background_opacity + )) + class SceneState(): def __init__(self, scene: Scene, ignore: list[Mobject] | None = None):