manim 0.18.1__py3-none-any.whl → 0.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__main__.py +45 -12
- manim/_config/__init__.py +2 -2
- manim/_config/cli_colors.py +8 -4
- manim/_config/default.cfg +0 -2
- manim/_config/logger_utils.py +5 -0
- manim/_config/utils.py +29 -38
- manim/animation/animation.py +148 -8
- manim/animation/composition.py +16 -13
- manim/animation/creation.py +184 -8
- manim/animation/fading.py +5 -8
- manim/animation/indication.py +93 -26
- manim/animation/movement.py +21 -3
- manim/animation/rotation.py +2 -1
- manim/animation/specialized.py +3 -5
- manim/animation/speedmodifier.py +3 -3
- manim/animation/transform.py +4 -5
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +2 -2
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +52 -36
- manim/cli/checkhealth/checks.py +92 -76
- manim/cli/checkhealth/commands.py +12 -5
- manim/cli/default_group.py +148 -24
- manim/cli/init/commands.py +28 -23
- manim/cli/plugins/commands.py +13 -3
- manim/cli/render/commands.py +47 -42
- manim/cli/render/global_options.py +43 -9
- manim/cli/render/render_options.py +84 -19
- manim/constants.py +11 -4
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +109 -75
- manim/mobject/geometry/boolean_ops.py +20 -17
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +120 -60
- manim/mobject/geometry/polygram.py +109 -25
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +36 -27
- manim/mobject/graph.py +48 -40
- manim/mobject/graphing/coordinate_systems.py +110 -45
- manim/mobject/graphing/functions.py +16 -10
- manim/mobject/graphing/number_line.py +23 -9
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +149 -103
- manim/mobject/opengl/opengl_geometry.py +4 -8
- manim/mobject/opengl/opengl_mobject.py +506 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
- manim/mobject/opengl/opengl_surface.py +1 -2
- manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
- manim/mobject/svg/brace.py +61 -13
- manim/mobject/svg/svg_mobject.py +2 -1
- manim/mobject/table.py +11 -12
- manim/mobject/text/code_mobject.py +186 -550
- manim/mobject/text/numbers.py +7 -7
- manim/mobject/text/tex_mobject.py +22 -13
- manim/mobject/text/text_mobject.py +29 -20
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_dimensions.py +59 -31
- manim/mobject/types/image_mobject.py +37 -23
- manim/mobject/types/point_cloud_mobject.py +103 -67
- manim/mobject/types/vectorized_mobject.py +387 -214
- manim/mobject/value_tracker.py +2 -1
- manim/mobject/vector_field.py +2 -4
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +2 -3
- manim/plugins/plugins_flags.py +3 -3
- manim/renderer/cairo_renderer.py +11 -11
- manim/renderer/opengl_renderer.py +19 -20
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +3 -2
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +72 -41
- manim/scene/scene_file_writer.py +313 -164
- manim/scene/section.py +15 -15
- manim/scene/three_d_scene.py +8 -15
- manim/scene/vector_space_scene.py +3 -6
- manim/typing.py +326 -66
- manim/utils/bezier.py +1658 -381
- manim/utils/caching.py +11 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +2 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +2 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +818 -301
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +40 -19
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -6
- manim/utils/deprecation.py +92 -43
- manim/utils/docbuild/autoaliasattr_directive.py +45 -8
- manim/utils/docbuild/autocolor_directive.py +12 -13
- manim/utils/docbuild/manim_directive.py +35 -29
- manim/utils/docbuild/module_parsing.py +74 -27
- manim/utils/family.py +3 -3
- manim/utils/family_ops.py +12 -4
- manim/utils/file_ops.py +22 -16
- manim/utils/hashing.py +7 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +12 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +55 -19
- manim/utils/opengl.py +68 -23
- manim/utils/parameter_parsing.py +3 -2
- manim/utils/paths.py +11 -5
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +69 -32
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +48 -37
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +20 -14
- manim/utils/tex.py +4 -2
- manim/utils/tex_file_writing.py +45 -45
- manim/utils/tex_templates.py +1 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim-0.18.1.dist-info/RECORD +0 -217
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Callable
|
|
3
|
+
from typing import Any, Callable
|
|
4
4
|
|
|
5
|
+
from manim.renderer.cairo_renderer import CairoRenderer
|
|
6
|
+
from manim.renderer.opengl_renderer import OpenGLRenderer
|
|
5
7
|
from manim.scene.scene import Scene
|
|
6
8
|
from manim.scene.scene_file_writer import SceneFileWriter
|
|
9
|
+
from manim.typing import PixelArray, StrPath
|
|
7
10
|
|
|
8
11
|
from ._frames_testers import _FramesTester
|
|
9
12
|
|
|
@@ -11,13 +14,14 @@ from ._frames_testers import _FramesTester
|
|
|
11
14
|
def _make_test_scene_class(
|
|
12
15
|
base_scene: type[Scene],
|
|
13
16
|
construct_test: Callable[[Scene], None],
|
|
14
|
-
test_renderer,
|
|
17
|
+
test_renderer: CairoRenderer | OpenGLRenderer | None,
|
|
15
18
|
) -> type[Scene]:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
# TODO: Get the type annotation right for the base_scene argument.
|
|
20
|
+
class _TestedScene(base_scene): # type: ignore[valid-type, misc]
|
|
21
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
22
|
+
super().__init__(*args, renderer=test_renderer, **kwargs)
|
|
19
23
|
|
|
20
|
-
def construct(self):
|
|
24
|
+
def construct(self) -> None:
|
|
21
25
|
construct_test(self)
|
|
22
26
|
|
|
23
27
|
# Manim hack to render the very last frame (normally the last frame is not the very end of the animation)
|
|
@@ -28,7 +32,7 @@ def _make_test_scene_class(
|
|
|
28
32
|
return _TestedScene
|
|
29
33
|
|
|
30
34
|
|
|
31
|
-
def _make_test_renderer_class(from_renderer):
|
|
35
|
+
def _make_test_renderer_class(from_renderer: type) -> Any:
|
|
32
36
|
# Just for inheritance.
|
|
33
37
|
class _TestRenderer(from_renderer):
|
|
34
38
|
pass
|
|
@@ -39,39 +43,50 @@ def _make_test_renderer_class(from_renderer):
|
|
|
39
43
|
class DummySceneFileWriter(SceneFileWriter):
|
|
40
44
|
"""Delegate of SceneFileWriter used to test the frames."""
|
|
41
45
|
|
|
42
|
-
def __init__(
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
renderer: CairoRenderer | OpenGLRenderer,
|
|
49
|
+
scene_name: StrPath,
|
|
50
|
+
**kwargs: Any,
|
|
51
|
+
) -> None:
|
|
43
52
|
super().__init__(renderer, scene_name, **kwargs)
|
|
44
53
|
self.i = 0
|
|
45
54
|
|
|
46
|
-
def init_output_directories(self, scene_name):
|
|
55
|
+
def init_output_directories(self, scene_name: StrPath) -> None:
|
|
47
56
|
pass
|
|
48
57
|
|
|
49
|
-
def add_partial_movie_file(self, hash_animation):
|
|
58
|
+
def add_partial_movie_file(self, hash_animation: str) -> None:
|
|
50
59
|
pass
|
|
51
60
|
|
|
52
|
-
def begin_animation(
|
|
61
|
+
def begin_animation(
|
|
62
|
+
self, allow_write: bool = True, file_path: StrPath | None = None
|
|
63
|
+
) -> Any:
|
|
53
64
|
pass
|
|
54
65
|
|
|
55
|
-
def end_animation(self, allow_write):
|
|
66
|
+
def end_animation(self, allow_write: bool = False) -> None:
|
|
56
67
|
pass
|
|
57
68
|
|
|
58
|
-
def combine_to_movie(self):
|
|
69
|
+
def combine_to_movie(self) -> None:
|
|
59
70
|
pass
|
|
60
71
|
|
|
61
|
-
def combine_to_section_videos(self):
|
|
72
|
+
def combine_to_section_videos(self) -> None:
|
|
62
73
|
pass
|
|
63
74
|
|
|
64
|
-
def clean_cache(self):
|
|
75
|
+
def clean_cache(self) -> None:
|
|
65
76
|
pass
|
|
66
77
|
|
|
67
|
-
def write_frame(
|
|
78
|
+
def write_frame(
|
|
79
|
+
self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1
|
|
80
|
+
) -> None:
|
|
68
81
|
self.i += 1
|
|
69
82
|
|
|
70
83
|
|
|
71
84
|
def _make_scene_file_writer_class(tester: _FramesTester) -> type[SceneFileWriter]:
|
|
72
85
|
class TestSceneFileWriter(DummySceneFileWriter):
|
|
73
|
-
def write_frame(
|
|
86
|
+
def write_frame(
|
|
87
|
+
self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1
|
|
88
|
+
) -> None:
|
|
74
89
|
tester.check_frame(self.i, frame_or_renderer)
|
|
75
|
-
super().write_frame(frame_or_renderer)
|
|
90
|
+
super().write_frame(frame_or_renderer, num_frames=num_frames)
|
|
76
91
|
|
|
77
92
|
return TestSceneFileWriter
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import functools
|
|
4
4
|
import inspect
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Callable
|
|
6
|
+
from typing import Any, Callable
|
|
7
7
|
|
|
8
8
|
import cairo
|
|
9
9
|
import pytest
|
|
@@ -14,7 +14,9 @@ from manim._config import tempconfig
|
|
|
14
14
|
from manim._config.utils import ManimConfig
|
|
15
15
|
from manim.camera.three_d_camera import ThreeDCamera
|
|
16
16
|
from manim.renderer.cairo_renderer import CairoRenderer
|
|
17
|
+
from manim.renderer.opengl_renderer import OpenGLRenderer
|
|
17
18
|
from manim.scene.three_d_scene import ThreeDScene
|
|
19
|
+
from manim.typing import StrPath
|
|
18
20
|
|
|
19
21
|
from ._frames_testers import _ControlDataWriter, _FramesTester
|
|
20
22
|
from ._test_class_makers import (
|
|
@@ -31,13 +33,13 @@ MIN_CAIRO_VERSION = 11800
|
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
def frames_comparison(
|
|
34
|
-
func=None,
|
|
36
|
+
func: Callable | None = None,
|
|
35
37
|
*,
|
|
36
38
|
last_frame: bool = True,
|
|
37
|
-
renderer_class=CairoRenderer,
|
|
38
|
-
base_scene=Scene,
|
|
39
|
-
**custom_config,
|
|
40
|
-
):
|
|
39
|
+
renderer_class: type[CairoRenderer | OpenGLRenderer] = CairoRenderer,
|
|
40
|
+
base_scene: type[Scene] = Scene,
|
|
41
|
+
**custom_config: Any,
|
|
42
|
+
) -> Callable:
|
|
41
43
|
"""Compares the frames generated by the test with control frames previously registered.
|
|
42
44
|
|
|
43
45
|
If there is no control frames for this test, the test will fail. To generate
|
|
@@ -60,7 +62,7 @@ def frames_comparison(
|
|
|
60
62
|
If the scene has a moving animation, then the test must set last_frame to False.
|
|
61
63
|
"""
|
|
62
64
|
|
|
63
|
-
def decorator_maker(tested_scene_construct):
|
|
65
|
+
def decorator_maker(tested_scene_construct: Callable) -> Callable:
|
|
64
66
|
if (
|
|
65
67
|
SCENE_PARAMETER_NAME
|
|
66
68
|
not in inspect.getfullargspec(tested_scene_construct).args
|
|
@@ -79,11 +81,14 @@ def frames_comparison(
|
|
|
79
81
|
"There is no module test name indicated for the graphical unit test. You have to declare __module_test__ in the test file.",
|
|
80
82
|
)
|
|
81
83
|
module_name = tested_scene_construct.__globals__.get("__module_test__")
|
|
84
|
+
assert isinstance(module_name, str)
|
|
82
85
|
test_name = tested_scene_construct.__name__[len("test_") :]
|
|
83
86
|
|
|
84
87
|
@functools.wraps(tested_scene_construct)
|
|
85
88
|
# The "request" parameter is meant to be used as a fixture by pytest. See below.
|
|
86
|
-
def wrapper(
|
|
89
|
+
def wrapper(
|
|
90
|
+
*args: Any, request: FixtureRequest, tmp_path: StrPath, **kwargs: Any
|
|
91
|
+
) -> None:
|
|
87
92
|
# check for cairo version
|
|
88
93
|
if (
|
|
89
94
|
renderer_class is CairoRenderer
|
|
@@ -146,13 +151,13 @@ def frames_comparison(
|
|
|
146
151
|
inspect.Parameter("tmp_path", inspect.Parameter.KEYWORD_ONLY),
|
|
147
152
|
]
|
|
148
153
|
new_sig = old_sig.replace(parameters=parameters)
|
|
149
|
-
wrapper.__signature__ = new_sig
|
|
154
|
+
wrapper.__signature__ = new_sig # type: ignore[attr-defined]
|
|
150
155
|
|
|
151
156
|
# Reach a bit into pytest internals to hoist the marks from our wrapped
|
|
152
157
|
# function.
|
|
153
|
-
|
|
158
|
+
wrapper.pytestmark = [] # type: ignore[attr-defined]
|
|
154
159
|
new_marks = getattr(tested_scene_construct, "pytestmark", [])
|
|
155
|
-
wrapper.pytestmark = new_marks
|
|
160
|
+
wrapper.pytestmark = new_marks # type: ignore[attr-defined]
|
|
156
161
|
return wrapper
|
|
157
162
|
|
|
158
163
|
# Case where the decorator is called with and without parentheses.
|
|
@@ -192,9 +197,10 @@ def _make_test_comparing_frames(
|
|
|
192
197
|
Callable[[], None]
|
|
193
198
|
The pytest test.
|
|
194
199
|
"""
|
|
195
|
-
|
|
196
200
|
if is_set_test_data_test:
|
|
197
|
-
frames_tester = _ControlDataWriter(
|
|
201
|
+
frames_tester: _FramesTester = _ControlDataWriter(
|
|
202
|
+
file_path, size_frame=size_frame
|
|
203
|
+
)
|
|
198
204
|
else:
|
|
199
205
|
frames_tester = _FramesTester(file_path, show_diff=show_diff)
|
|
200
206
|
|
|
@@ -205,7 +211,7 @@ def _make_test_comparing_frames(
|
|
|
205
211
|
)
|
|
206
212
|
testRenderer = _make_test_renderer_class(renderer_class)
|
|
207
213
|
|
|
208
|
-
def real_test():
|
|
214
|
+
def real_test() -> None:
|
|
209
215
|
with frames_tester.testing():
|
|
210
216
|
sceneTested = _make_test_scene_class(
|
|
211
217
|
base_scene=base_scene,
|
manim/utils/tex.py
CHANGED
|
@@ -36,6 +36,9 @@ class TexTemplate:
|
|
|
36
36
|
tex_compiler: str = "latex"
|
|
37
37
|
"""The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``."""
|
|
38
38
|
|
|
39
|
+
description: str = ""
|
|
40
|
+
"""A description of the template"""
|
|
41
|
+
|
|
39
42
|
output_format: str = ".dvi"
|
|
40
43
|
"""The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``."""
|
|
41
44
|
|
|
@@ -181,7 +184,6 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]:
|
|
|
181
184
|
A pair of strings representing the opening and closing of the tex environment, e.g.
|
|
182
185
|
``\begin{tabular}{cccl}`` and ``\end{tabular}``
|
|
183
186
|
"""
|
|
184
|
-
|
|
185
187
|
environment.removeprefix(r"\begin").removeprefix("{")
|
|
186
188
|
|
|
187
189
|
# The \begin command takes everything and closes with a brace
|
|
@@ -191,7 +193,7 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]:
|
|
|
191
193
|
begin += "}"
|
|
192
194
|
|
|
193
195
|
# While the \end command terminates at the first closing brace
|
|
194
|
-
split_at_brace = re.split("}", environment, 1)
|
|
196
|
+
split_at_brace = re.split("}", environment, maxsplit=1)
|
|
195
197
|
end = r"\end{" + split_at_brace[0] + "}"
|
|
196
198
|
|
|
197
199
|
return begin, end
|
manim/utils/tex_file_writing.py
CHANGED
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import hashlib
|
|
12
|
-
import os
|
|
13
12
|
import re
|
|
13
|
+
import subprocess
|
|
14
14
|
import unicodedata
|
|
15
|
+
from collections.abc import Generator, Iterable, Sequence
|
|
15
16
|
from pathlib import Path
|
|
16
|
-
from
|
|
17
|
+
from re import Match
|
|
18
|
+
from typing import Any
|
|
17
19
|
|
|
18
20
|
from manim.utils.tex import TexTemplate
|
|
19
21
|
|
|
@@ -22,7 +24,7 @@ from .. import config, logger
|
|
|
22
24
|
__all__ = ["tex_to_svg_file"]
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
def tex_hash(expression):
|
|
27
|
+
def tex_hash(expression: Any) -> str:
|
|
26
28
|
id_str = str(expression)
|
|
27
29
|
hasher = hashlib.sha256()
|
|
28
30
|
hasher.update(id_str.encode())
|
|
@@ -34,8 +36,8 @@ def tex_to_svg_file(
|
|
|
34
36
|
expression: str,
|
|
35
37
|
environment: str | None = None,
|
|
36
38
|
tex_template: TexTemplate | None = None,
|
|
37
|
-
):
|
|
38
|
-
"""Takes a tex expression and returns the svg version of the compiled tex
|
|
39
|
+
) -> Path:
|
|
40
|
+
r"""Takes a tex expression and returns the svg version of the compiled tex
|
|
39
41
|
|
|
40
42
|
Parameters
|
|
41
43
|
----------
|
|
@@ -76,7 +78,7 @@ def generate_tex_file(
|
|
|
76
78
|
environment: str | None = None,
|
|
77
79
|
tex_template: TexTemplate | None = None,
|
|
78
80
|
) -> Path:
|
|
79
|
-
"""Takes a tex expression (and an optional tex environment),
|
|
81
|
+
r"""Takes a tex expression (and an optional tex environment),
|
|
80
82
|
and returns a fully formed tex file ready for compilation.
|
|
81
83
|
|
|
82
84
|
Parameters
|
|
@@ -114,10 +116,11 @@ def generate_tex_file(
|
|
|
114
116
|
return result
|
|
115
117
|
|
|
116
118
|
|
|
117
|
-
def
|
|
119
|
+
def make_tex_compilation_command(
|
|
118
120
|
tex_compiler: str, output_format: str, tex_file: Path, tex_dir: Path
|
|
119
|
-
) -> str:
|
|
120
|
-
"""Prepares the
|
|
121
|
+
) -> list[str]:
|
|
122
|
+
"""Prepares the TeX compilation command, i.e. the TeX compiler name
|
|
123
|
+
and all necessary CLI flags.
|
|
121
124
|
|
|
122
125
|
Parameters
|
|
123
126
|
----------
|
|
@@ -132,50 +135,46 @@ def tex_compilation_command(
|
|
|
132
135
|
|
|
133
136
|
Returns
|
|
134
137
|
-------
|
|
135
|
-
:class:`str`
|
|
138
|
+
:class:`list[str]`
|
|
136
139
|
Compilation command according to given parameters
|
|
137
140
|
"""
|
|
138
141
|
if tex_compiler in {"latex", "pdflatex", "luatex", "lualatex"}:
|
|
139
|
-
|
|
142
|
+
command = [
|
|
140
143
|
tex_compiler,
|
|
141
144
|
"-interaction=batchmode",
|
|
142
|
-
f
|
|
145
|
+
f"-output-format={output_format[1:]}",
|
|
143
146
|
"-halt-on-error",
|
|
144
|
-
f
|
|
145
|
-
f
|
|
146
|
-
">",
|
|
147
|
-
os.devnull,
|
|
147
|
+
f"-output-directory={tex_dir.as_posix()}",
|
|
148
|
+
f"{tex_file.as_posix()}",
|
|
148
149
|
]
|
|
149
150
|
elif tex_compiler == "xelatex":
|
|
150
151
|
if output_format == ".xdv":
|
|
151
|
-
outflag = "-no-pdf"
|
|
152
|
+
outflag = ["-no-pdf"]
|
|
152
153
|
elif output_format == ".pdf":
|
|
153
|
-
outflag =
|
|
154
|
+
outflag = []
|
|
154
155
|
else:
|
|
155
156
|
raise ValueError("xelatex output is either pdf or xdv")
|
|
156
|
-
|
|
157
|
+
command = [
|
|
157
158
|
"xelatex",
|
|
158
|
-
outflag,
|
|
159
|
+
*outflag,
|
|
159
160
|
"-interaction=batchmode",
|
|
160
161
|
"-halt-on-error",
|
|
161
|
-
f
|
|
162
|
-
f
|
|
163
|
-
">",
|
|
164
|
-
os.devnull,
|
|
162
|
+
f"-output-directory={tex_dir.as_posix()}",
|
|
163
|
+
f"{tex_file.as_posix()}",
|
|
165
164
|
]
|
|
166
165
|
else:
|
|
167
166
|
raise ValueError(f"Tex compiler {tex_compiler} unknown.")
|
|
168
|
-
return
|
|
167
|
+
return command
|
|
169
168
|
|
|
170
169
|
|
|
171
|
-
def insight_inputenc_error(matching):
|
|
170
|
+
def insight_inputenc_error(matching: Match[str]) -> Generator[str]:
|
|
172
171
|
code_point = chr(int(matching[1], 16))
|
|
173
172
|
name = unicodedata.name(code_point)
|
|
174
173
|
yield f"TexTemplate does not support character '{name}' (U+{matching[1]})."
|
|
175
174
|
yield "See the documentation for manim.mobject.svg.tex_mobject for details on using a custom TexTemplate."
|
|
176
175
|
|
|
177
176
|
|
|
178
|
-
def insight_package_not_found_error(matching):
|
|
177
|
+
def insight_package_not_found_error(matching: Match[str]) -> Generator[str]:
|
|
179
178
|
yield f"You do not have package {matching[1]} installed."
|
|
180
179
|
yield f"Install {matching[1]} it using your LaTeX package manager, or check for typos."
|
|
181
180
|
|
|
@@ -200,14 +199,14 @@ def compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path:
|
|
|
200
199
|
result = tex_file.with_suffix(output_format)
|
|
201
200
|
tex_dir = config.get_dir("tex_dir")
|
|
202
201
|
if not result.exists():
|
|
203
|
-
command =
|
|
202
|
+
command = make_tex_compilation_command(
|
|
204
203
|
tex_compiler,
|
|
205
204
|
output_format,
|
|
206
205
|
tex_file,
|
|
207
206
|
tex_dir,
|
|
208
207
|
)
|
|
209
|
-
|
|
210
|
-
if
|
|
208
|
+
cp = subprocess.run(command, stdout=subprocess.DEVNULL)
|
|
209
|
+
if cp.returncode != 0:
|
|
211
210
|
log_file = tex_file.with_suffix(".log")
|
|
212
211
|
print_all_tex_errors(log_file, tex_compiler, tex_file)
|
|
213
212
|
raise ValueError(
|
|
@@ -218,7 +217,7 @@ def compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path:
|
|
|
218
217
|
return result
|
|
219
218
|
|
|
220
219
|
|
|
221
|
-
def convert_to_svg(dvi_file: Path, extension: str, page: int = 1):
|
|
220
|
+
def convert_to_svg(dvi_file: Path, extension: str, page: int = 1) -> Path:
|
|
222
221
|
"""Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm.
|
|
223
222
|
|
|
224
223
|
Parameters
|
|
@@ -237,18 +236,16 @@ def convert_to_svg(dvi_file: Path, extension: str, page: int = 1):
|
|
|
237
236
|
"""
|
|
238
237
|
result = dvi_file.with_suffix(".svg")
|
|
239
238
|
if not result.exists():
|
|
240
|
-
|
|
239
|
+
command = [
|
|
241
240
|
"dvisvgm",
|
|
242
|
-
"--pdf" if extension == ".pdf" else
|
|
243
|
-
"
|
|
244
|
-
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
|
|
248
|
-
">",
|
|
249
|
-
os.devnull,
|
|
241
|
+
*(["--pdf"] if extension == ".pdf" else []),
|
|
242
|
+
f"--page={page}",
|
|
243
|
+
"--no-fonts",
|
|
244
|
+
"--verbosity=0",
|
|
245
|
+
f"--output={result.as_posix()}",
|
|
246
|
+
f"{dvi_file.as_posix()}",
|
|
250
247
|
]
|
|
251
|
-
|
|
248
|
+
subprocess.run(command, stdout=subprocess.DEVNULL)
|
|
252
249
|
|
|
253
250
|
# if the file does not exist now, this means conversion failed
|
|
254
251
|
if not result.exists():
|
|
@@ -271,7 +268,6 @@ def delete_nonsvg_files(additional_endings: Iterable[str] = ()) -> None:
|
|
|
271
268
|
additional_endings
|
|
272
269
|
Additional endings to whitelist
|
|
273
270
|
"""
|
|
274
|
-
|
|
275
271
|
tex_dir = config.get_dir("tex_dir")
|
|
276
272
|
file_suffix_whitelist = {".svg", ".tex", *additional_endings}
|
|
277
273
|
|
|
@@ -310,7 +306,11 @@ LATEX_ERROR_INSIGHTS = [
|
|
|
310
306
|
]
|
|
311
307
|
|
|
312
308
|
|
|
313
|
-
def print_tex_error(
|
|
309
|
+
def print_tex_error(
|
|
310
|
+
tex_compilation_log: Sequence[str],
|
|
311
|
+
error_start_index: int,
|
|
312
|
+
tex_source: Sequence[str],
|
|
313
|
+
) -> None:
|
|
314
314
|
logger.error(
|
|
315
315
|
f"LaTeX compilation error: {tex_compilation_log[error_start_index][2:]}",
|
|
316
316
|
)
|
|
@@ -344,8 +344,8 @@ def print_tex_error(tex_compilation_log, error_start_index, tex_source):
|
|
|
344
344
|
context += tex_source[line_of_tex_error - 3 : line_of_tex_error + 3]
|
|
345
345
|
context[-4] = "-> " + context[-4]
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
logger.error(
|
|
347
|
+
context_joined = "".join(context)
|
|
348
|
+
logger.error(context_joined)
|
|
349
349
|
|
|
350
350
|
for insights in LATEX_ERROR_INSIGHTS:
|
|
351
351
|
prob, get_insight = insights
|
manim/utils/tex_templates.py
CHANGED
|
@@ -12,7 +12,7 @@ from .tex import *
|
|
|
12
12
|
# This file makes TexTemplateLibrary and TexFontTemplates available for use in manim Tex and MathTex objects.
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def _new_ams_template():
|
|
15
|
+
def _new_ams_template() -> TexTemplate:
|
|
16
16
|
"""Returns a simple Tex Template with only basic AMS packages"""
|
|
17
17
|
preamble = r"""
|
|
18
18
|
\usepackage[english]{babel}
|
manim/utils/unit.py
CHANGED
|
@@ -5,20 +5,21 @@ from __future__ import annotations
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
7
7
|
from .. import config, constants
|
|
8
|
+
from ..typing import Vector3D
|
|
8
9
|
|
|
9
10
|
__all__ = ["Pixels", "Degrees", "Munits", "Percent"]
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class _PixelUnits:
|
|
13
|
-
def __mul__(self, val):
|
|
14
|
+
def __mul__(self, val: float) -> float:
|
|
14
15
|
return val * config.frame_width / config.pixel_width
|
|
15
16
|
|
|
16
|
-
def __rmul__(self, val):
|
|
17
|
+
def __rmul__(self, val: float) -> float:
|
|
17
18
|
return val * config.frame_width / config.pixel_width
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class Percent:
|
|
21
|
-
def __init__(self, axis):
|
|
22
|
+
def __init__(self, axis: Vector3D) -> None:
|
|
22
23
|
if np.array_equal(axis, constants.X_AXIS):
|
|
23
24
|
self.length = config.frame_width
|
|
24
25
|
if np.array_equal(axis, constants.Y_AXIS):
|
|
@@ -26,10 +27,10 @@ class Percent:
|
|
|
26
27
|
if np.array_equal(axis, constants.Z_AXIS):
|
|
27
28
|
raise NotImplementedError("length of Z axis is undefined")
|
|
28
29
|
|
|
29
|
-
def __mul__(self, val):
|
|
30
|
+
def __mul__(self, val: float) -> float:
|
|
30
31
|
return val / 100 * self.length
|
|
31
32
|
|
|
32
|
-
def __rmul__(self, val):
|
|
33
|
+
def __rmul__(self, val: float) -> float:
|
|
33
34
|
return val / 100 * self.length
|
|
34
35
|
|
|
35
36
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: manim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: Animation engine for explanatory math videos.
|
|
5
|
-
Home-page: https://www.manim.community/
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: The Manim Community Developers
|
|
8
7
|
Author-email: contact@manim.community
|
|
9
|
-
Requires-Python: >=3.9
|
|
8
|
+
Requires-Python: >=3.9
|
|
10
9
|
Classifier: Development Status :: 4 - Beta
|
|
11
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Natural Language :: English
|
|
@@ -15,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Topic :: Multimedia :: Graphics
|
|
20
19
|
Classifier: Topic :: Multimedia :: Video
|
|
21
20
|
Classifier: Topic :: Scientific/Engineering
|
|
@@ -23,6 +22,9 @@ Provides-Extra: gui
|
|
|
23
22
|
Provides-Extra: jupyterlab
|
|
24
23
|
Requires-Dist: Pillow (>=9.1)
|
|
25
24
|
Requires-Dist: Pygments (>=2.0.0)
|
|
25
|
+
Requires-Dist: audioop-lts (>=0.2.0) ; python_version >= "3.13"
|
|
26
|
+
Requires-Dist: av (>=9.0.0,<14.0.0)
|
|
27
|
+
Requires-Dist: beautifulsoup4 (>=4.12)
|
|
26
28
|
Requires-Dist: click (>=8.0)
|
|
27
29
|
Requires-Dist: cloup (>=2.0.0)
|
|
28
30
|
Requires-Dist: dearpygui (>=1.0.0) ; extra == "gui"
|
|
@@ -36,11 +38,13 @@ Requires-Dist: moderngl (>=5.0.0,<6.0.0)
|
|
|
36
38
|
Requires-Dist: moderngl-window (>=2.0.0)
|
|
37
39
|
Requires-Dist: networkx (>=2.6)
|
|
38
40
|
Requires-Dist: notebook (>=6.0.0) ; extra == "jupyterlab"
|
|
39
|
-
Requires-Dist: numpy (>=
|
|
41
|
+
Requires-Dist: numpy (>=2.0) ; python_version < "3.10"
|
|
42
|
+
Requires-Dist: numpy (>=2.1) ; python_version >= "3.10"
|
|
40
43
|
Requires-Dist: pycairo (>=1.13,<2.0.0)
|
|
41
44
|
Requires-Dist: pydub (>=0.20.0)
|
|
42
45
|
Requires-Dist: rich (>=12.0.0)
|
|
43
|
-
Requires-Dist: scipy (>=1.
|
|
46
|
+
Requires-Dist: scipy (>=1.13.0) ; python_version < "3.13"
|
|
47
|
+
Requires-Dist: scipy (>=1.14.0) ; python_version >= "3.13"
|
|
44
48
|
Requires-Dist: screeninfo (>=0.7)
|
|
45
49
|
Requires-Dist: skia-pathops (>=0.7.0)
|
|
46
50
|
Requires-Dist: srt (>=3.0.0)
|
|
@@ -52,6 +56,7 @@ Project-URL: Bug Tracker, https://github.com/ManimCommunity/manim/issues
|
|
|
52
56
|
Project-URL: Changelog, https://docs.manim.community/en/stable/changelog.html
|
|
53
57
|
Project-URL: Documentation, https://docs.manim.community/
|
|
54
58
|
Project-URL: Discord, https://www.manim.community/discord/
|
|
59
|
+
Project-URL: Homepage, https://www.manim.community/
|
|
55
60
|
Project-URL: Repository, https://github.com/manimcommunity/manim
|
|
56
61
|
Project-URL: Twitter, https://twitter.com/manim_community
|
|
57
62
|
Description-Content-Type: text/markdown
|
|
@@ -79,7 +84,8 @@ Description-Content-Type: text/markdown
|
|
|
79
84
|
|
|
80
85
|
Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as demonstrated in the videos of [3Blue1Brown](https://www.3blue1brown.com/).
|
|
81
86
|
|
|
82
|
-
> NOTE
|
|
87
|
+
> [!NOTE]
|
|
88
|
+
> The community edition of Manim has been forked from 3b1b/manim, a tool originally created and open-sourced by Grant Sanderson, also creator of the 3Blue1Brown educational math videos. While Grant Sanderson’s repository continues to be maintained separately by him, he is not among the maintainers of the community edition. We recommend this version for its continued development, improved features, enhanced documentation, and more active community-driven maintenance. If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)).
|
|
83
89
|
|
|
84
90
|
## Table of Contents:
|
|
85
91
|
|
|
@@ -93,7 +99,8 @@ Manim is an animation engine for explanatory math videos. It's used to create pr
|
|
|
93
99
|
|
|
94
100
|
## Installation
|
|
95
101
|
|
|
96
|
-
>
|
|
102
|
+
> [!CAUTION]
|
|
103
|
+
> These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version.
|
|
97
104
|
|
|
98
105
|
Manim requires a few dependencies that must be installed prior to using it. If you
|
|
99
106
|
want to try it out first before installing it locally, you can do so
|