Skip to content

Preserve user-specified gradient order for VMobject.set_color #4227

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

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
24 changes: 24 additions & 0 deletions color_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

import numpy as np

from manim import *


class ColorTest(Scene):
def construct(self):
line1 = Line(
np.array([-1, 0, 0]), np.array([0, 1, 0]), stroke_width=20
).set_color(color=["#7301FF", "#EDCD00"])
line2 = Line(
np.array([-1, 0, 0]), np.array([1, 0, 0]), stroke_width=20
).set_color(color=["#7301FF", "#EDCD00"])
line3 = Line(
np.array([-1, 0, 0]), np.array([0, -1, 0]), stroke_width=20
).set_color(color=["#7301FF", "#EDCD00"])
line4 = Line(
np.array([-1, 0, 0]), np.array([-1, 1, 0]), stroke_width=20
).set_color(color=["#7301FF", "#EDCD00"])

self.play(Create(line1), Create(line2), Create(line3), Create(line4))
self.wait(2)
26 changes: 26 additions & 0 deletions gradient_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from __future__ import annotations

from manim import BLUE, GREEN, RED, WHITE, DashedLine, Line, Scene
from manim.constants import DOWN, LEFT, RIGHT, UP


class GradientDemo(Scene):
"""
Quick visual sanity-check: one solid and one dashed line showing that
the first colour in the list is always mapped to the start anchor.
"""

def construct(self):
# ── Solid 2-stop gradient ───────────────────────────────────────────────
solid = Line(LEFT * 4 + UP * 2, RIGHT * 4 + UP * 2, stroke_width=24).set_stroke(
[BLUE, RED]
)

# ── Dashed 2-stop gradient (let Manim pick dash count) ─────────────────
dashed = DashedLine(
LEFT * 4 + DOWN * 2,
RIGHT * 4 + DOWN * 2,
stroke_width=24,
).set_stroke([GREEN, WHITE])

self.add(solid, dashed)
33 changes: 26 additions & 7 deletions manim/mobject/types/vectorized_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,27 +247,46 @@ def generate_rgbas_array(
def update_rgbas_array(
self,
array_name: str,
color: ManimColor | None = None,
opacity: float | None = None,
color: ManimColor | list[ParsableManimColor] | None = None,
opacity: float | Iterable[float] | None = None,
) -> Self:
rgbas = self.generate_rgbas_array(color, opacity)
if isinstance(color, (list, tuple)) and len(color) > 1:
if opacity is None:
opacities = it.repeat(1.0)
elif isinstance(opacity, (int, float)):
opacities = it.repeat(float(opacity))
else:
if len(opacity) != len(color):
raise ValueError(
"When passing multiple colours, 'opacity' must be a "
"scalar or have the same length as 'color' "
f"(got {len(opacity)} vs {len(color)})"
)
opacities = opacity

rgba_list = [
ManimColor(c).to_rgba_with_alpha(a) for c, a in zip(color, opacities)
]
rgbas = np.asarray(rgba_list, dtype=float)
else:
rgbas = self.generate_rgbas_array(color, opacity)

if not hasattr(self, array_name):
setattr(self, array_name, rgbas)
return self
# Match up current rgbas array with the newly calculated
# one. 99% of the time they'll be the same.

curr_rgbas = getattr(self, array_name)
if len(curr_rgbas) < len(rgbas):
curr_rgbas = stretch_array_to_length(curr_rgbas, len(rgbas))
setattr(self, array_name, curr_rgbas)
elif len(rgbas) < len(curr_rgbas):
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]

return self

def set_fill(
Expand Down
Loading