0
# Value Tracking
1
2
ManimGL's value tracking system provides powerful tools for managing numeric parameters that change over time during animations. Value trackers are invisible mobjects that store numeric data and integrate seamlessly with the animation system, enabling complex parameter-dependent animations and interactive controls.
3
4
## Capabilities
5
6
### Basic Value Tracking
7
8
Store and animate numeric values that can drive parameter-dependent animations and link multiple objects to shared data sources.
9
10
```python { .api }
11
class ValueTracker(Mobject):
12
value_type: type = np.float64
13
14
def __init__(self, value: float | complex | np.ndarray = 0, **kwargs):
15
"""
16
Initialize a value tracker with a numeric value.
17
18
Parameters:
19
- value: Initial numeric value (scalar, complex, or array)
20
- kwargs: Additional Mobject keyword arguments
21
"""
22
23
def get_value(self) -> float | complex | np.ndarray:
24
"""
25
Retrieve the current tracked value.
26
27
Returns:
28
Current value (scalar if single value, array if multiple values)
29
"""
30
31
def set_value(self, value: float | complex | np.ndarray) -> Self:
32
"""
33
Update the tracked value.
34
35
Parameters:
36
- value: New numeric value to store
37
38
Returns:
39
Self for method chaining
40
"""
41
42
def increment_value(self, d_value: float | complex) -> None:
43
"""
44
Add the specified amount to the current value.
45
46
Parameters:
47
- d_value: Amount to add to current value
48
"""
49
50
def init_uniforms(self) -> None:
51
"""Initialize internal uniform data structure for GPU integration."""
52
```
53
54
### Exponential Value Tracking
55
56
Specialized tracker for exponential interpolation, storing values in logarithmic space for natural exponential animation behavior.
57
58
```python { .api }
59
class ExponentialValueTracker(ValueTracker):
60
def __init__(self, value: float | complex = 1, **kwargs):
61
"""
62
Initialize tracker for exponential value changes.
63
64
Parameters:
65
- value: Initial value (stored as log internally)
66
- kwargs: Additional ValueTracker arguments
67
"""
68
69
def get_value(self) -> float | complex:
70
"""
71
Get the exponential of the stored value.
72
73
Returns:
74
np.exp(internal_value) - the actual exponential value
75
"""
76
77
def set_value(self, value: float | complex):
78
"""
79
Set value by storing its logarithm internally.
80
81
Parameters:
82
- value: Actual value to represent (stored as log)
83
"""
84
```
85
86
### Complex Number Tracking
87
88
Optimized tracker for complex number values with high-precision complex number operations.
89
90
```python { .api }
91
class ComplexValueTracker(ValueTracker):
92
value_type: type = np.complex128
93
94
def __init__(self, value: complex = 0+0j, **kwargs):
95
"""
96
Initialize tracker for complex number values.
97
98
Parameters:
99
- value: Initial complex number value
100
- kwargs: Additional ValueTracker arguments
101
"""
102
```
103
104
## Usage Examples
105
106
### Basic Parameter Animation
107
108
```python
109
from manimlib import *
110
111
class BasicValueTracking(Scene):
112
def construct(self):
113
# Create a value tracker for controlling opacity
114
opacity_tracker = ValueTracker(0)
115
116
# Create objects that respond to the tracker
117
circle = Circle(radius=2, color=BLUE, fill_opacity=1)
118
square = Square(side_length=3, color=RED, fill_opacity=1)
119
120
# Link objects to the tracker value
121
circle.add_updater(
122
lambda c: c.set_fill_opacity(opacity_tracker.get_value())
123
)
124
square.add_updater(
125
lambda s: s.set_fill_opacity(1 - opacity_tracker.get_value())
126
)
127
128
self.add(circle, square)
129
130
# Animate the tracked value
131
self.play(opacity_tracker.animate.set_value(1), run_time=3)
132
self.play(opacity_tracker.animate.set_value(0.5), run_time=2)
133
self.play(opacity_tracker.animate.set_value(0), run_time=3)
134
```
135
136
### Function Plotting with Value Tracking
137
138
```python
139
class DynamicFunctionPlot(Scene):
140
def construct(self):
141
# Create coordinate system
142
axes = Axes(x_range=[-3, 3], y_range=[-2, 2])
143
self.add(axes)
144
145
# Create value trackers for function parameters
146
amplitude = ValueTracker(1)
147
frequency = ValueTracker(1)
148
phase = ValueTracker(0)
149
150
# Create function that depends on trackers
151
def get_sine_graph():
152
return axes.plot(
153
lambda x: (
154
amplitude.get_value() *
155
np.sin(frequency.get_value() * x + phase.get_value())
156
),
157
color=YELLOW
158
)
159
160
# Create initial graph
161
graph = get_sine_graph()
162
163
# Add updater to redraw graph when parameters change
164
graph.add_updater(lambda g: g.become(get_sine_graph()))
165
166
self.add(graph)
167
168
# Animate parameters
169
self.play(amplitude.animate.set_value(1.5), run_time=2)
170
self.play(frequency.animate.set_value(2), run_time=2)
171
self.play(phase.animate.set_value(PI/2), run_time=2)
172
173
# Multiple parameters simultaneously
174
self.play(
175
amplitude.animate.set_value(0.5),
176
frequency.animate.set_value(3),
177
phase.animate.set_value(0),
178
run_time=3
179
)
180
```
181
182
### Exponential Growth Animation
183
184
```python
185
class ExponentialAnimation(Scene):
186
def construct(self):
187
# Create exponential value tracker for smooth exponential growth
188
scale_tracker = ExponentialValueTracker(1)
189
190
# Create object that will grow exponentially
191
circle = Circle(radius=0.5, color=BLUE, fill_opacity=0.7)
192
193
# Link circle size to exponential tracker
194
def update_circle(c):
195
scale_factor = scale_tracker.get_value()
196
c.set_width(scale_factor)
197
c.set_height(scale_factor)
198
# Color intensity based on size
199
opacity = min(1, scale_factor / 5)
200
c.set_fill_opacity(opacity)
201
202
circle.add_updater(update_circle)
203
self.add(circle)
204
205
# Animate exponential growth (linear interpolation in log space)
206
self.play(scale_tracker.animate.set_value(10), run_time=4)
207
self.wait()
208
209
# Exponential decay
210
self.play(scale_tracker.animate.set_value(0.1), run_time=3)
211
```
212
213
### Complex Parameter Control
214
215
```python
216
class ComplexValueDemo(Scene):
217
def construct(self):
218
# Use complex tracker for rotation and scaling combined
219
complex_tracker = ComplexValueTracker(1+0j)
220
221
# Create shape to transform
222
arrow = Arrow(ORIGIN, RIGHT, color=RED, buff=0)
223
224
# Transform arrow based on complex number
225
def update_arrow(a):
226
complex_val = complex_tracker.get_value()
227
# Complex multiplication = rotation + scaling
228
magnitude = abs(complex_val)
229
angle = np.angle(complex_val)
230
231
a.become(Arrow(ORIGIN, RIGHT, buff=0, color=RED))
232
a.scale(magnitude)
233
a.rotate(angle)
234
235
arrow.add_updater(update_arrow)
236
self.add(arrow)
237
238
# Animate in complex plane
239
self.play(
240
complex_tracker.animate.set_value(2 * np.exp(1j * PI/4)),
241
run_time=2
242
)
243
self.play(
244
complex_tracker.animate.set_value(3 * np.exp(1j * PI)),
245
run_time=2
246
)
247
self.play(
248
complex_tracker.animate.set_value(0.5 * np.exp(1j * 2*PI)),
249
run_time=3
250
)
251
```
252
253
### Multi-Parameter Coordination
254
255
```python
256
class CoordinatedParameters(Scene):
257
def construct(self):
258
# Create multiple coordinated trackers
259
x_pos = ValueTracker(-3)
260
y_pos = ValueTracker(0)
261
size = ValueTracker(0.5)
262
hue = ValueTracker(0)
263
264
# Create object that depends on all parameters
265
circle = Circle(radius=0.5, fill_opacity=0.8)
266
267
def update_circle(c):
268
# Position
269
c.move_to([x_pos.get_value(), y_pos.get_value(), 0])
270
271
# Size
272
c.set_width(2 * size.get_value())
273
c.set_height(2 * size.get_value())
274
275
# Color based on hue value
276
import colorsys
277
rgb = colorsys.hsv_to_rgb(hue.get_value(), 1, 1)
278
c.set_fill(rgb_to_color(rgb))
279
280
circle.add_updater(update_circle)
281
self.add(circle)
282
283
# Coordinate multiple parameter changes
284
self.play(
285
x_pos.animate.set_value(3),
286
y_pos.animate.set_value(2),
287
size.animate.set_value(1.5),
288
hue.animate.set_value(0.3),
289
run_time=4
290
)
291
292
# Create circular motion with changing properties
293
self.play(
294
x_pos.animate.set_value(-3),
295
y_pos.animate.set_value(-2),
296
size.animate.set_value(0.3),
297
hue.animate.set_value(0.8),
298
run_time=3
299
)
300
```
301
302
### Interactive Parameter Control
303
304
```python
305
from manimlib.mobject.interactive import LinearNumberSlider
306
307
class InteractiveValueTracking(Scene):
308
def setup(self):
309
# Create sliders that are themselves value trackers
310
self.amplitude_slider = LinearNumberSlider(
311
value=1, min_value=0, max_value=3, step=0.1
312
)
313
self.frequency_slider = LinearNumberSlider(
314
value=1, min_value=0.1, max_value=5, step=0.1
315
)
316
317
# Position sliders
318
self.amplitude_slider.to_edge(DOWN).shift(UP * 0.5)
319
self.frequency_slider.to_edge(DOWN)
320
321
self.add(self.amplitude_slider, self.frequency_slider)
322
323
def construct(self):
324
# Create responsive visualization
325
axes = Axes(x_range=[-3, 3], y_range=[-3, 3])
326
327
def get_wave():
328
return axes.plot(
329
lambda x: (
330
self.amplitude_slider.get_value() *
331
np.sin(self.frequency_slider.get_value() * x)
332
),
333
color=YELLOW
334
)
335
336
wave = get_wave()
337
wave.add_updater(lambda w: w.become(get_wave()))
338
339
self.add(axes, wave)
340
341
# Create labels that show current values
342
amplitude_label = Text("Amplitude: 1.0", font_size=24)
343
frequency_label = Text("Frequency: 1.0", font_size=24)
344
345
amplitude_label.to_edge(UP).shift(DOWN * 0.5)
346
frequency_label.to_edge(UP)
347
348
def update_amp_label(label):
349
val = self.amplitude_slider.get_value()
350
label.become(Text(f"Amplitude: {val:.1f}", font_size=24))
351
label.to_edge(UP).shift(DOWN * 0.5)
352
353
def update_freq_label(label):
354
val = self.frequency_slider.get_value()
355
label.become(Text(f"Frequency: {val:.1f}", font_size=24))
356
label.to_edge(UP)
357
358
amplitude_label.add_updater(update_amp_label)
359
frequency_label.add_updater(update_freq_label)
360
361
self.add(amplitude_label, frequency_label)
362
363
# Interactive exploration time
364
self.wait(10)
365
```
366
367
## Integration with Animation System
368
369
### Chaining Operations
370
371
```python
372
# Value trackers support method chaining
373
tracker = ValueTracker(0)
374
tracker.set_value(5).increment_value(2) # Final value: 7
375
376
# Animation chaining
377
self.play(
378
tracker.animate.set_value(10),
379
other_object.animate.shift(UP)
380
)
381
```
382
383
### Updater Patterns
384
385
```python
386
# Time-based updaters (receive dt parameter)
387
def time_updater(mob, dt):
388
mob.rotate(dt * tracker.get_value())
389
390
mob.add_updater(time_updater)
391
392
# Non-time-based updaters (called every frame)
393
def position_updater(mob):
394
mob.move_to([tracker.get_value(), 0, 0])
395
396
mob.add_updater(position_updater, call_updater=True)
397
```
398
399
### Advanced Animation Patterns
400
401
```python
402
# Multiple trackers with different rate functions
403
self.play(
404
tracker1.animate.set_value(5).set_rate_func(smooth),
405
tracker2.animate.set_value(10).set_rate_func(linear),
406
tracker3.animate.set_value(2).set_rate_func(there_and_back),
407
run_time=3
408
)
409
410
# Staggered animations
411
self.play(
412
AnimationGroup(
413
tracker1.animate.set_value(5),
414
tracker2.animate.set_value(3),
415
tracker3.animate.set_value(8),
416
lag_ratio=0.3
417
),
418
run_time=4
419
)
420
```
421
422
## Technical Implementation
423
424
### Data Storage Architecture
425
426
Value trackers store data in `self.uniforms["value"]` as numpy arrays, enabling:
427
- GPU shader integration for advanced rendering
428
- Consistent handling of scalar and array values
429
- Efficient memory management and updates
430
431
### Animation Integration
432
433
- Inherits full animation capabilities from Mobject base class
434
- Compatible with `.animate` syntax for smooth transitions
435
- Supports all interpolation and transformation methods
436
- Integrates with rate functions and animation timing
437
438
### Performance Considerations
439
440
- Value trackers are lightweight and efficient for real-time updates
441
- Updater functions are called every frame - keep them optimized
442
- Use `clear_updaters()` when no longer needed to prevent memory leaks
443
- For complex calculations, consider caching results when tracker values haven't changed
444
445
The value tracking system provides the foundation for sophisticated parameter-dependent animations in ManimGL, enabling smooth interpolation of any numeric parameter while maintaining full integration with the animation and rendering pipeline.