Skip to content

Bug: Gradient color mapping fails on symmetric ParametricFunctions (Parabolas) #4573

@miltonlin103111-create

Description

@miltonlin103111-create

Description of bug / unexpected behavior

When applying a color list (gradient) to a non-monotonic function (like a parabola y = ax^2), the color rendering fails during or after the Create animation.Specifically, the right-hand side of the symmetric curve (where t > 0) loses its assigned gradient and becomes a solid single color (usually the last or first color of the list), even when the curve is split into two separate ParametricFunction objects. This issue persists despite having FFmpeg correctly installed and trying multiple coloring methods.

Expected behavior

The curve should maintain a symmetric gradient (e.g., Red at the ends, Blue at the vertex) throughout the animation and after it finishes.

How to reproduce the issue

The following code demonstrates that even after splitting the parabola into two branches and manually assigning colors to each, the right branch fails to render the gradient correctly.

from manim import *
import numpy as np

class test(MovingCameraScene):
    def construct(self):

        # create two seperate function
        def func2_l(t):
            x = t 
            y = 0.8 * t**2  
            return np.array([x, y, 0])
        def func2_r(t):
            x = t 
            y = 0.8 * t**2  
            return np.array([x, y, 0])

        path2_left= ParametricFunction(func2_l, t_range=[-1.3, 0], stroke_width=5)
        path2_right= ParametricFunction(func2_r, t_range=[0, 1.3], stroke_width=5)
        path2_left.move_to([3, 0, 0], aligned_edge=DR)
        path2_right.move_to([3, 0, 0], aligned_edge=DL)

       # Assign colors to the left branch (Red to Blue)
        num_points_left= len(path2_left.points)
        new_colors_left = []
        for i in range(num_points_left):
            alpha_l = i / (num_points_left - 1) 
            color_l = interpolate_color(BLUE, RED, alpha_l)
            new_colors_left.append(color_l)
        path2_left.set_color(new_colors_left) 
        # Assign colors to the left branch (Blue to Red)
        num_points_right= len(path2_right.points)
        new_colors_right = []
        for i in range(num_points_right):
            alpha_r = i / (num_points_right - 1) 
            color_r = interpolate_color(RED, BLUE, alpha_r)
            new_colors_right.append(color_r)
        path2_right.set_color(new_colors_right) 

        # The bug: path2_right often renders as a solid color instead of a gradient
        self.play(Create(path2_left), run_time=1)
        self.play(Create(path2_right), run_time=1)
        self.wait(3)

        # In order to make a contrast, I create a monotonic function (exponantial)
        def func1(t):
            x = t 
            y = 0.5* np.exp(t)  
            return np.array([x, y, 0])

        path1 = ParametricFunction(func1, t_range=[-1.8, 1.4], stroke_width=5)
        path1.move_to([-3, 0, 0])

        # The same color method 
        num_points = len(path1.points)
        new_colors = []
        for i in range(num_points):
            alpha = i / (num_points - 1)              
            color = interpolate_color(RED, BLUE, alpha)            
            new_colors.append(color)
        path1.set_color(new_colors)

        # A normal gradient color with no bug
        self.play(Create(path1), run_time=1)

Additional media files

Images/GIFs Image
test.mp4

Logs

Terminal output

C:\manim_projects\manim_video_3_laplace_operator>manim -v DEBUG test.py test
Manim Community v0.19.2

[02/08/26 19:07:47] DEBUG Hashing ... hashing.py:360
DEBUG Hashing done in 0.005994 s. hashing.py:372
DEBUG Hash generated : 4260039051_1344388235_223132457 hashing.py:375
DEBUG List of the first few animation hashes of the scene: cairo_renderer.py:103
['4260039051_1344388235_223132457']
[02/08/26 19:07:49] INFO Animation 0 : Partial movie file written in scene_file_writer.py:590
'C:\manim_projects\manim_video_3_laplace_operator\media\videos\tes
t\1080p60\partial_movie_files\test\4260039051_1344388235_223132457
.mp4'
DEBUG Hashing ... hashing.py:360
DEBUG Hashing done in 0.008145 s. hashing.py:372
DEBUG Hash generated : 3275331699_1167032440_1761094800 hashing.py:375
DEBUG List of the first few animation hashes of the scene: cairo_renderer.py:103
['4260039051_1344388235_223132457',
'3275331699_1167032440_1761094800']
[02/08/26 19:07:50] INFO Animation 1 : Partial movie file written in scene_file_writer.py:590
'C:\manim_projects\manim_video_3_laplace_operator\media\videos\tes
t\1080p60\partial_movie_files\test\3275331699_1167032440_176109480
0.mp4'
DEBUG Hashing ... hashing.py:360
DEBUG Hashing done in 0.008245 s. hashing.py:372
DEBUG Hash generated : 3275331699_3511709901_1014563049 hashing.py:375
DEBUG List of the first few animation hashes of the scene: cairo_renderer.py:103
['4260039051_1344388235_223132457',
'3275331699_1167032440_1761094800',
'3275331699_3511709901_1014563049']
[02/08/26 19:07:51] INFO Animation 2 : Partial movie file written in scene_file_writer.py:590
'C:\manim_projects\manim_video_3_laplace_operator\media\videos\tes
t\1080p60\partial_movie_files\test\3275331699_3511709901_101456304
9.mp4'
DEBUG Animation with empty mobject animation.py:185
DEBUG Hashing ... hashing.py:360
DEBUG Hashing done in 0.007494 s. hashing.py:372
DEBUG Hash generated : 3275331699_1135141467_2383492836 hashing.py:375
DEBUG List of the first few animation hashes of the scene: cairo_renderer.py:103
['4260039051_1344388235_223132457',
'3275331699_1167032440_1761094800',
'3275331699_3511709901_1014563049',
'3275331699_1135141467_2383492836']
[02/08/26 19:07:54] INFO Animation 3 : Partial movie file written in scene_file_writer.py:590
'C:\manim_projects\manim_video_3_laplace_operator\media\videos\tes
t\1080p60\partial_movie_files\test\3275331699_1135141467_238349283
6.mp4'
INFO Combining to Movie file. scene_file_writer.py:742
DEBUG Partial movie files to combine (4 files): scene_file_writer.py:624
['C:\manim_projects\manim_video_3_laplace_operator\media\video
s\test\1080p60\partial_movie_files\test\4260039051_1344388235
223132457.mp4',
'C:\manim_projects\manim_video_3_laplace_operator\media\videos
\test\1080p60\partial_movie_files\test\3275331699_1167032440

1761094800.mp4',
'C:\manim_projects\manim_video_3_laplace_operator\media\videos
\test\1080p60\partial_movie_files\test\3275331699_3511709901_
1014563049.mp4',
'C:\manim_projects\manim_video_3_laplace_operator\media\videos
\test\1080p60\partial_movie_files\test\3275331699_1135141467_
2383492836.mp4']
[02/08/26 19:07:55] INFO scene_file_writer.py:893
File ready at
'C:\manim_projects\manim_video_3_laplace_operator\media\videos\tes
t\1080p60\test.mp4'

                INFO     Rendered test                                                                  scene.py:278
                         Played 4 animations

</details>


## System specifications

<details><summary>System Details</summary>

- OS : Microsoft Windows [version 10.0.26100.7623]
- RAM: 14.0/31.4GB
- Python version (`python/py/python3 --version`): Python 3.11.9
- Installed modules (provide output from `pip list`):

Package Version


av 16.1.0
beautifulsoup4 4.14.3
click 8.3.1
cloup 3.0.8
colorama 0.4.6
decorator 5.2.1
glcontext 3.0.0
isosurfaces 0.1.2
manim 0.19.2
ManimPango 0.6.1
mapbox_earcut 2.0.0
markdown-it-py 4.0.0
mdurl 0.1.2
moderngl 5.12.0
moderngl-window 3.1.1
networkx 3.6.1
numpy 2.4.1
pillow 12.1.0
pip 24.0
pycairo 1.29.0
pydub 0.25.1
pyglet 2.1.12
pyglm 2.8.3
Pygments 2.19.2
rich 14.2.0
scipy 1.17.0
screeninfo 0.8.1
setuptools 65.5.0
skia-pathops 0.9.1
soupsieve 2.8.2
srt 3.5.3
svgelements 1.9.6
tqdm 4.67.1
typing_extensions 4.15.0
watchdog 6.0.0

[notice] A new release of pip is available: 24.0 -> 26.0.1
[notice] To update, run: python.exe -m pip install --upgrade pip

</details>

<details><summary>LaTeX details</summary>

+ LaTeX distribution (e.g. TeX Live 2020): MiKTeX
+ Installed LaTeX packages:
Basic MiKTeX installation, packages managed automatically.
</details>

## Additional comments

We have tried several workarounds, all of which failed to solve the "solid color" issue on the right branch: set_color_by_gradient(RED, BLUE): The right side remains a solid color. Splitting the curve: Created two separate ParametricFunction objects for t < 0 and t > 0. Manual color list injection: Manually calculating colors based on points coordinates. Installing/Reinstalling FFmpeg: Verified with ffmpeg -version, but the rendering issue persists. Chain method vs Separate calls: Tried set_color().move_to() vs calling them on separate lines. It seems like Manim is either caching the color attributes incorrectly for symmetric points or failing to map the color list to the right-side points of the parametric path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions