Skip to content

Commit 0261b83

Browse files
authored
Merge pull request #131 from PhilippImhof/customtex
Complete rewrite of TeX template management
2 parents 4614496 + 59fa6c5 commit 0261b83

File tree

9 files changed

+415
-42
lines changed

9 files changed

+415
-42
lines changed

example_scenes/custom_template.tex

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
\documentclass[preview]{standalone}
2+
3+
\usepackage[english]{babel}
4+
\usepackage{amsmath}
5+
\usepackage{amssymb}
6+
\usepackage[f]{esvect}
7+
\usepackage{dsfont}
8+
\usepackage{setspace}
9+
\usepackage{tipa}
10+
\usepackage{relsize}
11+
\usepackage{textcomp}
12+
\usepackage{mathrsfs}
13+
\usepackage{calligra}
14+
\usepackage{wasysym}
15+
\usepackage{ragged2e}
16+
\usepackage{physics}
17+
\usepackage{xcolor}
18+
\usepackage{microtype}
19+
\DisableLigatures{encoding = *, family = * }
20+
%\usepackage[UTF8]{ctex}
21+
\linespread{1}
22+
23+
\begin{document}
24+
25+
YourTextHere
26+
27+
\end{document}

example_scenes/customtex.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from manim import *
2+
3+
# Test cases:
4+
# 1. manim customtex.py ExampleFileScene -pl
5+
# --> should fail, because \vv is not defined
6+
#
7+
# 2. manim customtex.py ExampleFileScene --tex_template custom_template.tex -pl
8+
# --> should succeed as custom template includes package esvect (which defines \vv)
9+
#
10+
# 3. manim customtex.py ExampleClassScene -pl
11+
# --> should succeed as the package esvect is included in template object
12+
13+
class ExampleFileScene(Scene):
14+
def construct(self):
15+
text=TexMobject(r"\vv{vb}")
16+
#text=TextMobject(r"$\vv{vb}$")
17+
self.play(Write(text))
18+
19+
class ExampleClassScene(Scene):
20+
def construct(self):
21+
tpl=TexTemplate()
22+
tpl.append_package(["esvect",["f"]])
23+
config.register_tex_template(tpl)
24+
25+
#text=TextMobject(r"$\vv{vb}$")
26+
text=TexMobject(r"\vv{vb}")
27+
self.play(Write(text))

manim/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,4 @@
6868
from .utils.sounds import *
6969
from .utils.space_ops import *
7070
from .utils.strings import *
71+
from .utils.tex import *

manim/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def main():
77
args = config.parse_cli()
88
cfg = config.get_configuration(args)
99
config.initialize_directories(cfg)
10+
config.initialize_tex(cfg)
1011
extract_scene.main(cfg)
1112

1213

manim/config.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import sys
55
import types
66

7+
from .utils.tex import *
78
from . import constants
89
from . import dirs
910
from .logger import logger
1011

11-
__all__ = ["parse_cli", "get_configuration", "initialize_directories"]
12+
__all__ = ["parse_cli", "get_configuration", "initialize_directories","register_tex_template","initialize_tex"]
1213

1314

1415
def parse_cli():
@@ -140,7 +141,12 @@ def parse_cli():
140141
"--text_dir",
141142
help="Directory to write text",
142143
)
144+
parser.add_argument(
145+
"--tex_template",
146+
help="Specify a custom TeX template file",
147+
)
143148
return parser.parse_args()
149+
144150
except argparse.ArgumentError as err:
145151
logger.error(str(err))
146152
sys.exit(2)
@@ -176,6 +182,7 @@ def get_configuration(args):
176182
"video_dir": args.video_dir,
177183
"tex_dir": args.tex_dir,
178184
"text_dir": args.text_dir,
185+
"tex_template": args.tex_template,
179186
}
180187

181188
# Camera configuration
@@ -281,3 +288,39 @@ def initialize_directories(config):
281288
dirs.VIDEO_DIR = dir_config["video_dir"]
282289
dirs.TEX_DIR = dir_config["tex_dir"]
283290
dirs.TEXT_DIR = dir_config["text_dir"]
291+
292+
def register_tex_template(tpl):
293+
"""Register the given LaTeX template for later use.
294+
295+
Parameters
296+
----------
297+
tpl : :class:`~.TexTemplate`
298+
The LaTeX template to register.
299+
"""
300+
constants.TEX_TEMPLATE = tpl
301+
302+
def initialize_tex(config):
303+
"""Safely create a LaTeX template object from a file.
304+
If file is not readable, the default template file is used.
305+
306+
Parameters
307+
----------
308+
filename : :class:`str`
309+
The name of the file with the LaTeX template.
310+
"""
311+
filename=""
312+
if config["tex_template"]:
313+
filename = os.path.expanduser(config["tex_template"])
314+
if filename and not os.access(filename, os.R_OK):
315+
# custom template not available, fallback to default
316+
logger.warning(
317+
f"Custom TeX template {filename} not found or not readable. "
318+
"Falling back to the default template."
319+
)
320+
filename = ""
321+
if filename:
322+
# still having a filename -> use the file
323+
constants.TEX_TEMPLATE = TexTemplateFromFile(filename=filename)
324+
else:
325+
# use the default template
326+
constants.TEX_TEMPLATE = TexTemplate()

manim/constants.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,7 @@ class MyText(Text):
2020
OBLIQUE = 'OBLIQUE'
2121
BOLD = 'BOLD'
2222

23-
TEX_USE_CTEX = False
24-
TEX_TEXT_TO_REPLACE = "YourTextHere"
25-
TEMPLATE_TEX_FILE = os.path.join(
26-
os.path.dirname(os.path.realpath(__file__)),
27-
"tex_template.tex" if not TEX_USE_CTEX else "ctex_template.tex"
28-
)
29-
with open(TEMPLATE_TEX_FILE, "r") as infile:
30-
TEMPLATE_TEXT_FILE_BODY = infile.read()
31-
TEMPLATE_TEX_FILE_BODY = TEMPLATE_TEXT_FILE_BODY.replace(
32-
TEX_TEXT_TO_REPLACE,
33-
"\\begin{align*}\n" + TEX_TEXT_TO_REPLACE + "\n\\end{align*}",
34-
)
23+
TEX_TEMPLATE = None
3524

3625
SCENE_NOT_FOUND_MESSAGE = """
3726
{} is not in the script

manim/mobject/svg/tex_mobject.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from ...utils.strings import split_string_list_to_isolate_substrings
1212
from ...utils.tex_file_writing import tex_to_svg_file
1313

14-
1514
TEX_MOB_SCALE_FACTOR = 0.05
1615

1716

@@ -21,10 +20,8 @@ class TexSymbol(VMobjectFromSVGPathstring):
2120
"""
2221
pass
2322

24-
2523
class SingleStringTexMobject(SVGMobject):
2624
CONFIG = {
27-
"template_tex_file_body": TEMPLATE_TEX_FILE_BODY,
2825
"stroke_width": 0,
2926
"fill_opacity": 1.0,
3027
"background_stroke_width": 1,
@@ -33,6 +30,7 @@ class SingleStringTexMobject(SVGMobject):
3330
"height": None,
3431
"organize_left_to_right": False,
3532
"alignment": "",
33+
"type": "tex",
3634
}
3735

3836
def __init__(self, tex_string, **kwargs):
@@ -41,7 +39,7 @@ def __init__(self, tex_string, **kwargs):
4139
self.tex_string = tex_string
4240
file_name = tex_to_svg_file(
4341
self.get_modified_expression(tex_string),
44-
self.template_tex_file_body
42+
self.type
4543
)
4644
SVGMobject.__init__(self, file_name=file_name, **kwargs)
4745
if self.height is None:
@@ -247,9 +245,9 @@ def sort_alphabetically(self):
247245

248246
class TextMobject(TexMobject):
249247
CONFIG = {
250-
"template_tex_file_body": TEMPLATE_TEXT_FILE_BODY,
251248
"alignment": "\\centering",
252249
"arg_separator": "",
250+
"type": "text",
253251
}
254252

255253

@@ -258,7 +256,6 @@ class BulletedList(TextMobject):
258256
"buff": MED_LARGE_BUFF,
259257
"dot_scale_factor": 2,
260258
# Have to include because of handle_multiple_args implementation
261-
"template_tex_file_body": TEMPLATE_TEXT_FILE_BODY,
262259
"alignment": "",
263260
}
264261

@@ -325,4 +322,4 @@ def __init__(self, *text_parts, **kwargs):
325322
else:
326323
underline.set_width(self.underline_width)
327324
self.add(underline)
328-
self.underline = underline
325+
self.underline = underline

0 commit comments

Comments
 (0)