Added `colorscale` to `axes.plot()`
Overview: What does this pull request change?
Added colorscale and colorscale_axis to axes.plot() to allow for colorscales by value for line plots.
Motivation and Explanation: Why and how do your changes improve the library?
Adds functionality to the library consistent with Surface and OpenGLSurface.
Links to added or changed documentation pages
https://manimce--3148.org.readthedocs.build/en/3148/reference/manim.mobject.graphing.coordinate_systems.CoordinateSystem.html#manim.mobject.graphing.coordinate_systems.CoordinateSystem.plot
Further Information and Comments
Example code:
from manim import *
class PlotExample(Scene):
def construct(self):
# construct the axes
axes = Axes(
x_range=[0, 6],
y_range=[-2, 2],
tips=False,
)
curve = axes.plot(
lambda x: 2 * np.sin(x), x_range=(0.0, 6, 0.001), colorscale=[BLUE, GREEN, YELLOW, ORANGE, RED]
)
self.add(axes, curve)

Reviewer Checklist
- [ ] The PR title is descriptive enough for the changelog, and the PR is labeled correctly
- [ ] If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section
- [ ] If applicable: newly added functions and classes are tested
What about the pivots? To me those are key as I set values below 0 to be one color and above 0 to be another color. Is it possible to set pivots with the sheen direction?
What about the pivots? To me those are key as I set values below 0 to be one color and above 0 to be another color. Is it possible to set pivots with the sheen direction?
True! I don't think our current implementation of gradients allows to manually set pivots. Maybe this is something that we could consider after we have #3020 and implement our own ManimColorGradient class... Until then, your "manual" implementation might be a more suitable way to go.
Added a test to round out this PR.
@behackl is there anything else I need to do to get this PR in shape to be merged? Or are we waiting on #3020 to be merged so that we implement ManimColorGradient? If so, any idea on when that would happen?
It doesn't work with opengl renderer
CurvesAsSubmobjectsdoesn't seem to work in OpenGL
Can i just say this is hellishly slow ? I am trying to render this and it takes about a second on a good run i think that might be problematic for a lot of cases if people really wanted to use it
That is the output i can currently achieve when i use it with opengl. I am not quite sure how your solution works but there might still be something missing.
We basically spend 90% of the time just creating mobjects
In cairo this doesn't happen for some reason. But 6 seconds for a singular curve is pretty slow in my opinion.
It takes 155 seconds in cairo to draw this. I don't think this is acceptable tbh.
https://github.com/ManimCommunity/manim/assets/17803932/28b29753-4dd8-4ae4-9c67-8ad10504e16e
I would suggest a solution which somehow exploits curve.set_stroke([BLUE, RED, GREEN, YELLOW]) because that might be the faster way to change the colors without making thousands of little mobjects when it's not needed.
@MrDiver the number of sub-mobjects created is up to the user. It comes from x_range=(0.0, 6, 0.001) in axes.plot(). I choose 0.001 to ensure a nice smooth transition of colors. But changing it to 0.1 still results in a decent transition of colors and takes a fraction of the time:
Is that a reasonable solution? It still doesn't work in OpenGL, but that as you point out is because CurvesAsSubmobjects doesn't work in OpenGL and so the appropriate solution would be to get CurvesAsSubmobjects working in OpenGL in a separate PR.
As for using curve.set_stroke([BLUE, RED, GREEN, YELLOW]), I don't see how that can be done while allowing to set at least a mid-point for the colors. I say that as I often set certain colors for less than 0 and others for greater than 0. To me this is necessary and is already how Surface and OpenGLSurface work with colorscales (as well as other charting libraries like Plotly). I think it is worth it to discuss how colorscales should be implemented across all three, as there is some duplication of code. That is why I asked @behackl above about #3020 and implementing ManimColorGradient, as I would prefer that colorscales be implemented there and then each of these just use that implementation.
I already got the OpenGL thing to work, that's why i have the flamegraph for the 95 seconds. That's what it takes to render this I still think it is a little bit much to create so many mobjects for that. As far as i understand it colors may be applied independently of the number of mobjects.
@alembcke
class PlotExample(Scene):
def construct(self):
# construct the axes
axes = Axes(
x_range=[0, 6],
y_range=[-2, 2],
tips=False,
)
curve = axes.plot(
lambda x: 2 * np.sin(x), x_range=(0.0, 6), use_vectorized=True
)
colors = [
"#ff0000",
"#ffa500",
"#ffff00",
"#008000",
"#0000ff",
"#4b0082",
"#ee82ee",
]
# curve.set_stroke(colors)
curve.set_color(colors)
# curve.set_fill(colors, opacity=1)
self.play(Write(axes), Write(curve))
self.play(curve.animate.set_sheen_direction(UP))
self.play(curve.animate.set_sheen_direction(RIGHT))
self.play(curve.animate.set_sheen_direction(LEFT))
self.wait()
You might wanna take a look at this 👀 i just realized you can do that so it might make realizing the color stuff a lot easier because it is not dependend on the number of curves
https://github.com/ManimCommunity/manim/assets/17803932/fd0eb1b1-30f1-4cc6-ad4a-aaf2d8f96163
https://github.com/ManimCommunity/manim/assets/17803932/8cdf0038-ab4b-4f78-a19b-90e941f88f20
And you can scale the amount of colors without increasing the rendering time at all.
For 100 different colors the whole animation not just an image
Doing only an image:
So instead of generating all the curves and then iterating over them and setting all the fancy colors i would suggest just generating a color list and then setting the colors directly
Or we might just take a look at the implementation of that and see if we can borrow some color setting things such that you can get a custom pivot.
I added some changes to the PR, you can check if they have the same behavior that you intended. I just reused all of your code. I also added a test to check if the color axis parameter actually works so that it doesn't get missed in the graphical tests.
Just to reiterate here what was discussed on Discord, I rendered a bunch of videos I have that use this functionality and they all behave the same way as before but render much faster.
This is weird because the tests pass on my machine. I even deleted the folder with Manim in it and did a git clone and reran the tests - they still pass.
I double and triple checked that I am on the line_gradient branch and I ran poetry install and poetry run pytest. Am I doing anything wrong here?
I double and triple checked that I am on the
line_gradientbranch and I ranpoetry installandpoetry run pytest. Am I doing anything wrong here?
Maybe you also needed to run poetry shell to enter your environment :thinking:
As MrDiver said: the tests needed an update, because they stopped working after certain commit in main. Don't worry: I already updated the tests myself and your PR has passed all checks :wink: