Skip to content

Commit b69e1d7

Browse files
Adding the ability to pass lists and generators to .play() (#3365)
* adding the ability to pass lists and generators to .play() * fix for _AnimationBuilder * Changed handling of generators to accept lists of generators and normal arguments at the same time * Animation group handles generators * Refactored into own function for reusability * Fix typing * Fix typing --------- Co-authored-by: Jason Grace <[email protected]>
1 parent fc42710 commit b69e1d7

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

manim/animation/composition.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
from __future__ import annotations
55

6-
from typing import TYPE_CHECKING, Callable, Sequence
6+
import types
7+
from typing import TYPE_CHECKING, Callable, Iterable, Sequence
78

89
import numpy as np
910

1011
from manim.mobject.opengl.opengl_mobject import OpenGLGroup
12+
from manim.utils.parameter_parsing import flatten_iterable_parameters
1113

1214
from .._config import config
1315
from ..animation.animation import Animation, prepare_animation
@@ -54,14 +56,15 @@ class AnimationGroup(Animation):
5456

5557
def __init__(
5658
self,
57-
*animations: Animation,
59+
*animations: Animation | Iterable[Animation] | types.GeneratorType[Animation],
5860
group: Group | VGroup | OpenGLGroup | OpenGLVGroup = None,
5961
run_time: float | None = None,
6062
rate_func: Callable[[float], float] = linear,
6163
lag_ratio: float = 0,
6264
**kwargs,
6365
) -> None:
64-
self.animations = [prepare_animation(anim) for anim in animations]
66+
arg_anim = flatten_iterable_parameters(animations)
67+
self.animations = [prepare_animation(anim) for anim in arg_anim]
6568
self.rate_func = rate_func
6669
self.group = group
6770
if self.group is None:

manim/renderer/cairo_renderer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import typing
4-
from typing import Any
54

65
import numpy as np
76

@@ -15,6 +14,10 @@
1514
from ..utils.iterables import list_update
1615

1716
if typing.TYPE_CHECKING:
17+
import types
18+
from typing import Any, Iterable
19+
20+
from manim.animation.animation import Animation
1821
from manim.scene.scene import Scene
1922

2023

@@ -51,7 +54,12 @@ def init_scene(self, scene):
5154
scene.__class__.__name__,
5255
)
5356

54-
def play(self, scene, *args, **kwargs):
57+
def play(
58+
self,
59+
scene: Scene,
60+
*args: Animation | Iterable[Animation] | types.GeneratorType[Animation],
61+
**kwargs,
62+
):
5563
# Reset skip_animations to the original state.
5664
# Needed when rendering only some animations, and skipping others.
5765
self.skip_animations = self._original_skipping_status

manim/scene/scene.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from manim.utils.parameter_parsing import flatten_iterable_parameters
6+
57
__all__ = ["Scene"]
68

79
import copy
@@ -13,7 +15,6 @@
1315
import time
1416
import types
1517
from queue import Queue
16-
from typing import Callable
1718

1819
import srt
1920

@@ -25,6 +26,8 @@
2526
dearpygui_imported = True
2627
except ImportError:
2728
dearpygui_imported = False
29+
from typing import TYPE_CHECKING
30+
2831
import numpy as np
2932
from tqdm import tqdm
3033
from watchdog.events import FileSystemEventHandler
@@ -48,6 +51,9 @@
4851
from ..utils.file_ops import open_media_file
4952
from ..utils.iterables import list_difference_update, list_update
5053

54+
if TYPE_CHECKING:
55+
from typing import Callable, Iterable
56+
5157

5258
class RerunSceneHandler(FileSystemEventHandler):
5359
"""A class to handle rerunning a Scene after the input file is modified."""
@@ -865,7 +871,11 @@ def get_moving_and_static_mobjects(self, animations):
865871
)
866872
return all_moving_mobject_families, static_mobjects
867873

868-
def compile_animations(self, *args: Animation, **kwargs):
874+
def compile_animations(
875+
self,
876+
*args: Animation | Iterable[Animation] | types.GeneratorType[Animation],
877+
**kwargs,
878+
):
869879
"""
870880
Creates _MethodAnimations from any _AnimationBuilders and updates animation
871881
kwargs with kwargs passed to play().
@@ -883,7 +893,9 @@ def compile_animations(self, *args: Animation, **kwargs):
883893
Animations to be played.
884894
"""
885895
animations = []
886-
for arg in args:
896+
arg_anims = flatten_iterable_parameters(args)
897+
# Allow passing a generator to self.play instead of comma separated arguments
898+
for arg in arg_anims:
887899
try:
888900
animations.append(prepare_animation(arg))
889901
except TypeError:
@@ -1027,7 +1039,7 @@ def get_run_time(self, animations: list[Animation]):
10271039

10281040
def play(
10291041
self,
1030-
*args,
1042+
*args: Animation | Iterable[Animation] | types.GeneratorType[Animation],
10311043
subcaption=None,
10321044
subcaption_duration=None,
10331045
subcaption_offset=0,
@@ -1157,7 +1169,11 @@ def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60):
11571169
"""
11581170
self.wait(max_time, stop_condition=stop_condition)
11591171

1160-
def compile_animation_data(self, *animations: Animation, **play_kwargs):
1172+
def compile_animation_data(
1173+
self,
1174+
*animations: Animation | Iterable[Animation] | types.GeneratorType[Animation],
1175+
**play_kwargs,
1176+
):
11611177
"""Given a list of animations, compile the corresponding
11621178
static and moving mobjects, and gather the animation durations.
11631179

manim/utils/parameter_parsing.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
from types import GeneratorType
4+
from typing import Iterable, TypeVar
5+
6+
T = TypeVar("T")
7+
8+
9+
def flatten_iterable_parameters(
10+
args: Iterable[T | Iterable[T] | GeneratorType],
11+
) -> list[T]:
12+
"""Flattens an iterable of parameters into a list of parameters.
13+
14+
Parameters
15+
----------
16+
args
17+
The iterable of parameters to flatten.
18+
[(generator), [], (), ...]
19+
20+
Returns
21+
-------
22+
:class:`list`
23+
The flattened list of parameters.
24+
"""
25+
flattened_parameters = []
26+
for arg in args:
27+
if isinstance(arg, (Iterable, GeneratorType)):
28+
flattened_parameters.extend(arg)
29+
else:
30+
flattened_parameters.append(arg)
31+
return flattened_parameters

0 commit comments

Comments
 (0)