Skip to content

Commit 08e06e1

Browse files
sparshgjsonvillanuevabehackl
authored
Render image automatically if no animation is played in a scene (#1261)
* Display image instead if attempting to make movie file with no animations * update * logging warnings added * small fixes * Fix broken test, add suggestions * ignore skipping if scene finished * fixes + replace self.play(Anim.. with self.add() * dummy commit * explicitly set write_to_movie in manim_directive Co-authored-by: Jason Villanueva <[email protected]> Co-authored-by: Benjamin Hackl <[email protected]>
1 parent 2b6b2cd commit 08e06e1

File tree

13 files changed

+62
-55
lines changed

13 files changed

+62
-55
lines changed

docs/source/manim_directive.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def run(self):
221221
f'config["pixel_width"] = {pixel_width}',
222222
f'config["save_last_frame"] = {save_last_frame}',
223223
f'config["save_as_gif"] = {save_as_gif}',
224+
f'config["write_to_movie"] = {not save_last_frame}',
224225
f'config["output_file"] = r"{output_file}"',
225226
]
226227

manim/renderer/cairo_renderer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,15 @@ def update_skipping_status(self):
266266
raise EndSceneEarlyException()
267267

268268
def scene_finished(self, scene):
269-
self.file_writer.finish()
269+
# If no animations in scene, render an image instead
270+
if self.num_plays:
271+
self.file_writer.finish()
272+
elif config.write_to_movie:
273+
config.save_last_frame = True
274+
config.write_to_movie = False
275+
else:
276+
self.update_frame(scene)
277+
270278
if config["save_last_frame"]:
271-
self.update_frame(scene, ignore_skipping=False)
279+
self.update_frame(scene)
272280
self.file_writer.save_final_image(self.camera.get_image())

manim/scene/scene.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,11 @@ def render(self, preview=False):
187187
# We have to reset these settings in case of multiple renders.
188188
self.renderer.scene_finished(self)
189189

190-
logger.info(
191-
f"Rendered {str(self)}\nPlayed {self.renderer.num_plays} animations"
192-
)
190+
# Show info only if animations are rendered or to get image
191+
if self.renderer.num_plays or config["save_last_frame"] or config["save_pngs"]:
192+
logger.info(
193+
f"Rendered {str(self)}\nPlayed {self.renderer.num_plays} animations"
194+
)
193195

194196
# If preview open up the render after rendering.
195197
if preview:

manim/scene/scene_file_writer.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,13 @@ def init_output_directories(self, scene_name):
7878
else:
7979
default_name = Path(scene_name)
8080

81-
if config["save_last_frame"] or config["save_pngs"]:
82-
if config["media_dir"]:
83-
image_dir = guarantee_existence(
84-
config.get_dir("images_dir", module_name=module_name)
85-
)
86-
self.image_file_path = os.path.join(
87-
image_dir, add_extension_if_not_present(default_name, ".png")
81+
if config["media_dir"]:
82+
image_dir = guarantee_existence(
83+
config.get_dir("images_dir", module_name=module_name)
8884
)
85+
self.image_file_path = os.path.join(
86+
image_dir, add_extension_if_not_present(default_name, ".png")
87+
)
8988

9089
if config["write_to_movie"]:
9190
movie_dir = guarantee_existence(
Binary file not shown.

tests/test_graphical_units/test_coordinate_systems.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def construct(self):
1717
y_axis_config={"x_max": 5, "width": 6, "label_direction": UL},
1818
center_point=2 * DL,
1919
)
20-
self.play(Animation(plane))
20+
self.add(plane)
2121

2222

2323
MODULE_NAME = "coordinate_systems"

tests/test_graphical_units/test_functions.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ def construct(self):
1313
lambda x: 2 * np.cos(0.5 * x), x_min=-PI, x_max=PI, color=BLUE
1414
)
1515
self.add(graph)
16-
self.wait()
1716

1817

1918
MODULE_NAME = "functions"

tests/test_graphical_units/test_geometry.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,25 @@
99
class CoordinatesTest(Scene):
1010
def construct(self):
1111
dots = [Dot(np.array([x, y, 0])) for x in range(-7, 8) for y in range(-4, 5)]
12-
self.play(Animation(VGroup(*dots)))
12+
self.add(VGroup(*dots))
1313

1414

1515
class ArcTest(Scene):
1616
def construct(self):
1717
a = Arc(PI)
18-
self.play(Animation(a))
18+
self.add(a)
1919

2020

2121
class ArcBetweenPointsTest(Scene):
2222
def construct(self):
2323
a = ArcBetweenPoints(np.array([1, 1, 0]), np.array([2, 2, 0]))
24-
self.play(Animation(a))
24+
self.add(a)
2525

2626

2727
class CurvedArrowTest(Scene):
2828
def construct(self):
2929
a = CurvedArrow(np.array([1, 1, 0]), np.array([2, 2, 0]))
30-
self.play(Animation(a))
30+
self.add(a)
3131

3232

3333
class CustomDoubleArrowTest(Scene):
@@ -40,91 +40,91 @@ def construct(self):
4040
tip_shape_start=ArrowCircleTip,
4141
tip_shape_end=ArrowSquareFilledTip,
4242
)
43-
self.play(Animation(a))
43+
self.add(a)
4444

4545

4646
class CircleTest(Scene):
4747
def construct(self):
4848
circle = Circle()
49-
self.play(Animation(circle))
49+
self.add(circle)
5050

5151

5252
class DotTest(Scene):
5353
def construct(self):
5454
dot = Dot()
55-
self.play(Animation(dot))
55+
self.add(dot)
5656

5757

5858
class AnnotationDotTest(Scene):
5959
def construct(self):
6060
adot = AnnotationDot()
61-
self.play(Animation(adot))
61+
self.add(adot)
6262

6363

6464
class EllipseTest(Scene):
6565
def construct(self):
6666
e = Ellipse()
67-
self.play(Animation(e))
67+
self.add(e)
6868

6969

7070
class SectorTest(Scene):
7171
def construct(self):
7272
e = Sector()
73-
self.play(Animation(e))
73+
self.add(e)
7474

7575

7676
class AnnulusTest(Scene):
7777
def construct(self):
7878
a = Annulus()
79-
self.play(Animation(a))
79+
self.add(a)
8080

8181

8282
class AnnularSectorTest(Scene):
8383
def construct(self):
8484
a = AnnularSector()
85-
self.play(Animation(a))
85+
self.add(a)
8686

8787

8888
class LineTest(Scene):
8989
def construct(self):
9090
a = Line(np.array([1, 1, 0]), np.array([2, 2, 0]))
91-
self.play(Animation(a))
91+
self.add(a)
9292

9393

9494
class ElbowTest(Scene):
9595
def construct(self):
9696
a = Elbow()
97-
self.play(Animation(a))
97+
self.add(a)
9898

9999

100100
class DoubleArrowTest(Scene):
101101
def construct(self):
102102
a = DoubleArrow()
103-
self.play(Animation(a))
103+
self.add(a)
104104

105105

106106
class VectorTest(Scene):
107107
def construct(self):
108108
a = Vector(UP)
109-
self.play(Animation(a))
109+
self.add(a)
110110

111111

112112
class PolygonTest(Scene):
113113
def construct(self):
114114
a = Polygon(*[np.array([1, 1, 0]), np.array([2, 2, 0]), np.array([2, 3, 0])])
115-
self.play(Animation(a))
115+
self.add(a)
116116

117117

118118
class RectangleTest(Scene):
119119
def construct(self):
120120
a = Rectangle()
121-
self.play(Animation(a))
121+
self.add(a)
122122

123123

124124
class RoundedRectangleTest(Scene):
125125
def construct(self):
126126
a = RoundedRectangle()
127-
self.play(Animation(a))
127+
self.add(a)
128128

129129

130130
class ArrangeTest(Scene):
@@ -133,7 +133,6 @@ def construct(self):
133133
s2 = Square()
134134
x = VGroup(s1, s2).set_x(0).arrange(buff=1.4)
135135
self.add(x)
136-
self.wait()
137136

138137

139138
class ZIndexTest(Scene):
@@ -148,23 +147,22 @@ def construct(self):
148147
self.play(FadeIn(VGroup(circle, square, triangle)))
149148
self.play(ApplyMethod(circle.shift, UP))
150149
self.play(ApplyMethod(triangle.shift, 2 * UP))
151-
self.wait(1)
152150

153151

154152
class AngleTest(Scene):
155153
def construct(self):
156154
l1 = Line(ORIGIN, RIGHT)
157155
l2 = Line(ORIGIN, UP)
158156
a = Angle(l1, l2)
159-
self.play(Animation(a))
157+
self.add(a)
160158

161159

162160
class RightAngleTest(Scene):
163161
def construct(self):
164162
l1 = Line(ORIGIN, RIGHT)
165163
l2 = Line(ORIGIN, UP)
166164
a = RightAngle(l1, l2)
167-
self.play(Animation(a))
165+
self.add(a)
168166

169167

170168
MODULE_NAME = "geometry"

tests/test_graphical_units/test_graphscene.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def construct(self):
2727
self.setup_axes()
2828
f = self.get_graph(lambda x: x ** 2)
2929

30-
self.play(Animation(f))
30+
self.add(f)
3131

3232

3333
MODULE_NAME = "plot"

tests/test_graphical_units/test_mobjects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class PointCloudDotTest(ThreeDScene):
1010
def construct(self):
1111
p = PointCloudDot()
12-
self.play(Animation(p))
12+
self.add(p)
1313

1414

1515
MODULE_NAME = "mobjects"

0 commit comments

Comments
 (0)