Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(vectorized_mobject,mobject): Removing explicit opacity attributes… #3862

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions manim/animation/rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

__all__ = ["Rotating", "Rotate"]

from collections.abc import Sequence
from typing import TYPE_CHECKING, Callable

import numpy as np
Expand All @@ -16,6 +15,7 @@

if TYPE_CHECKING:
from ..mobject.mobject import Mobject
from ..typing import Vector3D


class Rotating(Animation):
Expand Down Expand Up @@ -87,8 +87,8 @@ def __init__(
mobject: Mobject,
angle: float = PI,
axis: np.ndarray = OUT,
about_point: Sequence[float] | None = None,
about_edge: Sequence[float] | None = None,
about_point: Vector3D | None = None,
about_edge: Vector3D | None = None,
**kwargs,
) -> None:
if "path_arc" not in kwargs:
Expand Down
3 changes: 2 additions & 1 deletion manim/mobject/geometry/arc.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,10 +679,11 @@ def __init__(
point: Point3D = ORIGIN,
radius: float = DEFAULT_DOT_RADIUS,
stroke_width: float = 0,
fill_opacity: float = 1.0,
fill_opacity: float = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fill_opacity: float = None,
fill_opacity: float | None = None,

color: ParsableManimColor = WHITE,
**kwargs,
) -> None:
self.submobjects = []
super().__init__(
arc_center=point,
radius=radius,
Expand Down
7 changes: 2 additions & 5 deletions manim/mobject/geometry/shape_matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,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, ManimColor, ParsableManimColor
from manim.utils.color import BLACK, RED, YELLOW, ParsableManimColor


class SurroundingRectangle(RoundedRectangle):
Expand Down Expand Up @@ -107,7 +107,7 @@ def __init__(
buff=buff,
**kwargs,
)
self.original_fill_opacity: float = self.fill_opacity
self.original_fill_opacity: float = self.get_fill_opacities()

def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self:
self.set_fill(opacity=b * self.original_fill_opacity)
Expand All @@ -129,9 +129,6 @@ def set_style(self, fill_opacity: float, **kwargs) -> Self:
)
return self

def get_fill_color(self) -> ManimColor:
return self.color


class Cross(VGroup):
"""Creates a cross.
Expand Down
1 change: 1 addition & 0 deletions manim/mobject/graphing/probability.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class BarChart(Axes):
bar_names
A sequence of names for each bar. Does not have to match the length of ``values``.
y_range
Takes the form (min, max, stepsize)
The y_axis range of values. If ``None``, the range will be calculated based on the
min/max of ``values`` and the step will be calculated based on ``y_length``.
x_length
Expand Down
8 changes: 5 additions & 3 deletions manim/mobject/mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def __init_subclass__(cls, **kwargs) -> None:

def __init__(
self,
color: ParsableManimColor | list[ParsableManimColor] = WHITE,
color: ParsableManimColor | list[ParsableManimColor] | None = WHITE,
name: str | None = None,
dim: int = 3,
target=None,
Expand Down Expand Up @@ -400,13 +400,15 @@ def __deepcopy__(self, clone_from_id) -> Self:
return result

def __repr__(self) -> str:
return str(self.name)
if hasattr(self, "name"):
return str(self.name)
return str(self.__class__.__name__)

def reset_points(self) -> None:
"""Sets :attr:`points` to be an empty array."""
self.points = np.zeros((0, self.dim))

def init_colors(self) -> None:
def init_colors(self) -> Self:
"""Initializes the colors.

Gets called upon creation. This is an empty method that can be implemented by
Expand Down
5 changes: 2 additions & 3 deletions manim/mobject/text/numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def __init__(
fill_opacity: float = 1.0,
**kwargs,
):
super().__init__(**kwargs, stroke_width=stroke_width)
super().__init__(**kwargs, stroke_width=stroke_width, fill_opacity=fill_opacity)
self.number = number
self.num_decimal_places = num_decimal_places
self.include_sign = include_sign
Expand All @@ -112,7 +112,7 @@ def __init__(
self.include_background_rectangle = include_background_rectangle
self.edge_to_fix = edge_to_fix
self._font_size = font_size
self.fill_opacity = fill_opacity
self.set_fill_opacity(fill_opacity)

self.initial_config = kwargs.copy()
self.initial_config.update(
Expand All @@ -133,7 +133,6 @@ def __init__(
)

self._set_submobjects_from_number(number)
self.init_colors()

@property
def font_size(self):
Expand Down
117 changes: 63 additions & 54 deletions manim/mobject/types/vectorized_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import itertools as it
import sys
from collections.abc import Generator, Hashable, Iterable, Mapping, Sequence
from typing import TYPE_CHECKING, Callable, Literal
from typing import TYPE_CHECKING, Callable, Literal, cast

import numpy as np
from PIL.Image import Image
Expand All @@ -39,6 +39,7 @@
)
from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor
from manim.utils.iterables import (
listify,
make_even,
resize_array,
stretch_array_to_length,
Expand Down Expand Up @@ -112,13 +113,14 @@

def __init__(
self,
color: ParsableManimColor | list[ParsableManimColor] | None = None,
fill_color: ParsableManimColor | None = None,
fill_opacity: float = 0.0,
fill_opacity: float | None = None,
stroke_color: ParsableManimColor | None = None,
stroke_opacity: float = 1.0,
stroke_opacity: float | None = None,
stroke_width: float = DEFAULT_STROKE_WIDTH,
background_stroke_color: ParsableManimColor | None = BLACK,
background_stroke_opacity: float = 1.0,
background_stroke_opacity: float | None = None,
background_stroke_width: float = 0,
sheen_factor: float = 0.0,
joint_type: LineJointType | None = None,
Expand All @@ -134,14 +136,7 @@
cap_style: CapStyleType = CapStyleType.AUTO,
**kwargs,
):
self.fill_opacity = fill_opacity
self.stroke_opacity = stroke_opacity
self.stroke_width = stroke_width
if background_stroke_color is not None:
self.background_stroke_color: ManimColor = ManimColor(
background_stroke_color
)
self.background_stroke_opacity: float = background_stroke_opacity
self.background_stroke_width: float = background_stroke_width
self.sheen_factor: float = sheen_factor
self.joint_type: LineJointType = (
Expand All @@ -163,17 +158,35 @@
0, 1, n_points_per_cubic_curve
)
self.cap_style: CapStyleType = cap_style
super().__init__(**kwargs)

# TODO: Refactor color initialization
# This must be after init

self.submobjects: list[VMobject]
# if fill_color is not None or stroke_color is not None:
# color = None
Comment on lines +166 to +167

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

if background_stroke_color is not None:
self.background_stroke_color: ManimColor | list[ManimColor] = (
ManimColor.parse(background_stroke_color)
)
if background_stroke_opacity is not None:
self.background_stroke_color = self.background_stroke_color.opacity(
background_stroke_opacity
)

print("Before", color, fill_color, stroke_color)
super().__init__(color=color, **kwargs)
print("After", self.color, self.fill_color, self.stroke_color)

# TODO: Find where color overwrites are happening and remove the color doubling
# if "color" in kwargs:
# fill_color = kwargs["color"]
# stroke_color = kwargs["color"]
if fill_color is not None:
self.fill_color = ManimColor.parse(fill_color)
if fill_opacity is not None:
self.fill_color = self.fill_color.opacity(fill_opacity)
if stroke_color is not None:
self.stroke_color = ManimColor.parse(stroke_color)
if stroke_opacity is not None:
self.stroke_color = self.stroke_color.opacity(stroke_opacity)

def _assert_valid_submobjects(self, submobjects: Iterable[VMobject]) -> Self:
return self._assert_valid_submobjects_internal(submobjects, VMobject)
Expand All @@ -192,21 +205,9 @@

# Colors
def init_colors(self, propagate_colors: bool = True) -> Self:
self.set_fill(
color=self.fill_color,
opacity=self.fill_opacity,
family=propagate_colors,
)
self.set_stroke(
color=self.stroke_color,
width=self.stroke_width,
opacity=self.stroke_opacity,
family=propagate_colors,
)
self.set_background_stroke(
color=self.background_stroke_color,
width=self.background_stroke_width,
opacity=self.background_stroke_opacity,
family=propagate_colors,
)
self.set_sheen(
Expand All @@ -222,7 +223,7 @@
return self

def generate_rgbas_array(
self, color: ManimColor | list[ManimColor], opacity: float | Iterable[float]
self, color: ManimColor | list[ManimColor]
) -> RGBA_Array_Float:
"""
First arg can be either a color, or a tuple/list of colors.
Expand All @@ -232,14 +233,10 @@
will automatically be added for the gradient
"""
colors: list[ManimColor] = [
ManimColor(c) if (c is not None) else BLACK for c in tuplify(color)
ManimColor(c) if (c is not None) else BLACK
for c in cast(tuple[ManimColor], tuplify(color))
]
opacities: list[float] = [
o if (o is not None) else 0.0 for o in tuplify(opacity)
]
rgbas: npt.NDArray[RGBA_Array_Float] = np.array(
[c.to_rgba_with_alpha(o) for c, o in zip(*make_even(colors, opacities))],
)
rgbas = np.array([c.to_rgba() for c in colors])

sheen_factor = self.get_sheen_factor()
if sheen_factor != 0 and len(rgbas) == 1:
Expand All @@ -252,10 +249,11 @@
def update_rgbas_array(
self,
array_name: str,
color: ManimColor | None = None,
opacity: float | None = None,
color: ManimColor | list[ManimColor] | None,
) -> Self:
rgbas = self.generate_rgbas_array(color, opacity)
if color is None:
return self
rgbas = self.generate_rgbas_array(color)
if not hasattr(self, array_name):
setattr(self, array_name, rgbas)
return self
Expand All @@ -269,15 +267,14 @@
rgbas = stretch_array_to_length(rgbas, len(curr_rgbas))
# Only update rgb if color was not None, and only
# update alpha channel if opacity was passed in
if color is not None:
curr_rgbas[:, :3] = rgbas[:, :3]
if opacity is not None:
curr_rgbas[:, 3] = rgbas[:, 3]
curr_rgbas[:, :4] = rgbas[:, :4]
print(array_name, curr_rgbas)
setattr(self, array_name, curr_rgbas)
return self

def set_fill(
self,
color: ParsableManimColor | None = None,
color: ParsableManimColor | list[ParsableManimColor] | None = None,
opacity: float | None = None,
family: bool = True,
) -> Self:
Expand Down Expand Up @@ -316,23 +313,33 @@
--------
:meth:`~.VMobject.set_style`
"""
new_color: list[ManimColor] = listify(self.get_fill_color())
if color is not None:
new_color: list[ManimColor] = listify(ManimColor.parse(color))
if opacity is not None:
new_color = [c.opacity(opacity) for c in new_color]

if family:
for submobject in self.submobjects:
submobject.set_fill(color, opacity, family)
self.update_rgbas_array("fill_rgbas", color, opacity)
self.update_rgbas_array("fill_rgbas", new_color)
self.fill_rgbas: RGBA_Array_Float
if opacity is not None:
self.fill_opacity = opacity
return self

def set_stroke(
self,
color: ParsableManimColor = None,
color: ParsableManimColor | list[ParsableManimColor] | None = None,
width: float | None = None,
opacity: float | None = None,
background=False,
family: bool = True,
) -> Self:
new_color: list[ManimColor] = listify(self.get_fill_color())
if color is not None:
new_color: list[ManimColor] = listify(ManimColor.parse(color))
if opacity is not None:
new_color = [c.opacity(opacity) for c in new_color]

if family:
for submobject in self.submobjects:
submobject.set_stroke(color, width, opacity, background, family)
Expand All @@ -344,16 +351,14 @@
array_name = "stroke_rgbas"
width_name = "stroke_width"
opacity_name = "stroke_opacity"
self.update_rgbas_array(array_name, color, opacity)

self.update_rgbas_array(array_name, new_color)
if width is not None:
setattr(self, width_name, width)
if opacity is not None:
setattr(self, opacity_name, opacity)
if color is not None and background:
if isinstance(color, (list, tuple)):
self.background_stroke_color = ManimColor.parse(color)
else:
self.background_stroke_color = ManimColor(color)
self.background_stroke_color = ManimColor.parse(color)
return self

def set_cap_style(self, cap_style: CapStyleType) -> Self:
Expand Down Expand Up @@ -510,6 +515,10 @@
"""
return self.get_fill_opacities()[0]

def set_fill_opacity(self, opacity: float):
self.fill_color = [x.opacity(opacity) for x in tuplify(self.fill_color)]
return self

# TODO: Does this just do a copy?
# TODO: I have the feeling that this function should not return None, does that have any usage ?
def get_fill_colors(self) -> list[ManimColor | None]:
Expand All @@ -527,8 +536,8 @@
self.background_stroke_rgbas: RGBA_Array_Float
rgbas = self.background_stroke_rgbas
else:
self.stroke_rgbas: RGBA_Array_Float
rgbas = self.stroke_rgbas
self.stroke_rgbas: RGBA_Array_Float
return rgbas
except AttributeError:
return np.zeros((1, 4))
Expand Down
Loading
Loading