A ValueTracker in Manim tracks a value of some sort of a number. You can’t show the actual value tracker on the screen because it works in the background.
A value tracker is used to increase or decrease a value while an animation is playing.
You can attach the ValueTracker to another mobject and then animate that mobject based on how the value tracker changes.
Let’s look at an example:
How to animate a number increasing in Manim using a ValueTracker
A perfect example to illustrate how a value tracker works in Manim is to animate a number increasing (or decreasing) on the screen.
Example:
from manim import *
class valuetracker(Scene):
def construct(self):
t1 = ValueTracker(10)
number = always_redraw(lambda: DecimalNumber(t1.get_value(), num_decimal_places = 0))
self.play(Write(number))
self.play(t1.animate.set_value(30))
self.wait()
Output:
I wanted to animate the number 10 going to the number 30 on the screen.
Here’s the code explanation:
Line 1: I imported the Manim library into VS Code so that it understands Manim code syntax.
Lines 3 and 4: I created a new Manim scene and named it “valuetrakcer”.
Line 5: I created the value tracker, assigned it to a new variable that I decided to name t1, and assigned 10 as the initial value to the ValueTracker. I will be able to change this value later when I animate the value tracker changing from 10 to 30.
Line 6:
This one will need some space for explaining.
For now let’s skip the always_redraw(lambda: ) part and let’s look at the line of code without it.
number = DecimalNumber(t1.get_value(), num_decimal_places = 0)
Immediately less scary.
Since I can’t put the actual ValueTracker() on the screen I had to create a new variable with the number that I’ll show on the screen. I decided to name it number and assigned a DecimalNumber() to it.
DecimalNumber() basically lets me assign a number to a variable. If I were to say numbers = DecimalNumber(69), that would mean that my variable number = 69.00.
But in this case, I wanted to animate this number changing from 10 to 30. That’s why I set the initial value of this number to be equal to whatever number I put in the value tracker. t1.get_value() grabs the value from the ValueTracker(). I set the initial value of the value tracker to 10 so now the DecimalNumber() will become the value 10. I want to do this because I can animate the value inside of the ValueTracker() changing which will also change my number variable to that value and I can show that happening on the screen later.
If I stopped here and played my number on the screen I would see the number 10.00.
By default, DecimalNumber() has two decimal places after the number (for example, 10.00). I didn’t want to show the decimal numbers so I added num_decimal_places = 0 parameter to it.
Before we get to the always_redraw(lambda: ) part let’s explore the other lines of code which will make it easier to understand what it’s for.
Line 7: I animated the number on the screen using the Write() animation type. This wrote it on the screen.
Line 8: I animated the value of the ValueTracker() changing from its original value (which was 10) to a 30.
Line 9: I paused the animation for 1 second on the screen.
Now what the hell is the always_redraw(lambda: ) part?
This is an updater function. If you wrap your code with it then the object that’s wrapped will be redrawn on the screen for every new frame.
Why did I need an updater in this example?
If I were to run the code without it I would only see a static number 10 on the screen.
Since I’m animating the ValueTracker changing (line 8) and not the number itself I need to also update the number to change on the screen based on the new value of the value tracker.
The value of the number is attached to the value of the ValueTracker() but they’re separate things. Remember I mentioned before that you can’t show the ValueTracker() on the screen. You can only show things that are attached to the ValueTracker().
That’s why, as the value inside of the ValueTracker() changes you want to see those changes happening to the mobject that the ValueTracker() is attached to. And to do that you can use an updater function.
To always redraw or update something on the screen surround the thing that you want to update like this:
always_redraw(lambda: the_thing_you_want_updated)
You can see this in the 6th line of code of the example:
number = always_redraw(lambda: DecimalNumber(t1.get_value(), num_decimal_places = 0))
I surrounded the DecimalNumber() with an updater function so that for every frame that plays, this number is updated on the screen to be redrawn to have the value of the ValueTracker() and to always have 0 decimal places.
Let me help you learn Manim
If you want to skip the headache of trying to learn Manim from a bunch of scattered information, I put together a comprehensive 3-hour Manim course for complete beginners.
It will give you all the foundational skills you need to start creating stunning animations with code.
Enroll In Manim Course For Beginners