TexTemplates without CONFIG + all Font Examples

This commit is contained in:
Aron Fischer 2020-10-08 23:42:01 +02:00
commit 85aa5dece4
8 changed files with 262 additions and 137 deletions

View file

@ -1,11 +1,11 @@
from manim import *
# French Cursive LaTeX font examples from http://jf.burnol.free.fr/showcase.html
class TexTemplateFrenchCursive(TexTemplate):
def prepare_template_body(self):
# For more LaTeX font examples from http://jf.burnol.free.fr/showcase.html
self.body = r"""
\documentclass[preview]{standalone}
# Example 1 Manually creating a Template
TemplateForFrenchCursive = TexTemplate(
preamble=r"""
\usepackage[english]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
@ -13,23 +13,16 @@ class TexTemplateFrenchCursive(TexTemplate):
\usepackage[default]{frcursive}
\usepackage[eulergreek,noplusnominus,noequal,nohbar,%
nolessnomore,noasterisk]{mathastext}
\begin{document}
YourTextHere
\end{document}
"""
)
class FrenchCursive(Tex):
def __init__(self, *tex_strings, **kwargs):
super().__init__(
*tex_strings, tex_template=TexTemplateFrenchCursive(), **kwargs
)
def FrenchCursive(*tex_strings, **kwargs):
template = kwargs.pop("tex_template", TemplateForFrenchCursive)
return Tex(*tex_strings, tex_template=template, **kwargs)
class AdvancedTexFontExample(Scene):
class TexFontTemplateManual(Scene):
def construct(self):
self.add(Tex("Tex Font Example").to_edge(UL))
self.play(ShowCreation(FrenchCursive("$f: A \\longrightarrow B$").shift(UP)))
@ -45,3 +38,90 @@ class AdvancedTexFontExample(Scene):
)
)
self.wait(2)
# Example 2, using a Template from the collection
class TexFontTemplateLibrary(Scene):
def construct(self):
def write_one_line(template):
x = Tex(template.description, tex_template=template).shift(UP)
self.play(ShowCreation(x))
self.wait(1)
self.play(FadeOut(x))
# Please Note: The entries that are commented out
# require that the fonts in question are installed on your local machine.
# For example, choosing the template TexFontTemplates.chalkduster will
# not compile if the chalkduster font is not installed.
examples = [
# TexFontTemplates.american_typewriter, # "American Typewriter"
# TexFontTemplates.antykwa, # "Antykwa Półtawskiego (TX Fonts for Greek and math symbols)"
# TexFontTemplates.apple_chancery, # "Apple Chancery"
TexFontTemplates.auriocus_kalligraphicus, # "Auriocus Kalligraphicus (Symbol Greek)"
TexFontTemplates.baskervald_adf_fourier, # "Baskervald ADF with Fourier"
# TexFontTemplates.baskerville_it, # "Baskerville (Italic)"
TexFontTemplates.biolinum, # "Biolinum"
# TexFontTemplates.brushscriptx, # "BrushScriptX-Italic (PX math and Greek)"
# TexFontTemplates.chalkboard_se, # "Chalkboard SE"
# TexFontTemplates.chalkduster, # "Chalkduster"
TexFontTemplates.comfortaa, # "Comfortaa"
TexFontTemplates.comic_sans, # "Comic Sans MS"
TexFontTemplates.droid_sans, # "Droid Sans"
TexFontTemplates.droid_sans_it, # "Droid Sans (Italic)"
TexFontTemplates.droid_serif, # "Droid Serif"
TexFontTemplates.droid_serif_px_it, # "Droid Serif (PX math symbols) (Italic)"
TexFontTemplates.ecf_augie, # "ECF Augie (Euler Greek)"
TexFontTemplates.ecf_jd, # "ECF JD (with TX fonts)"
TexFontTemplates.ecf_skeetch, # "ECF Skeetch (CM Greek)"
TexFontTemplates.ecf_tall_paul, # "ECF Tall Paul (with Symbol font)"
TexFontTemplates.ecf_webster, # "ECF Webster (with TX fonts)"
TexFontTemplates.electrum_adf, # "Electrum ADF (CM Greek)"
TexFontTemplates.epigrafica, # Epigrafica
TexFontTemplates.fourier_utopia, # "Fourier Utopia (Fourier upright Greek)"
TexFontTemplates.french_cursive, # "French Cursive (Euler Greek)"
TexFontTemplates.gfs_bodoni, # "GFS Bodoni"
TexFontTemplates.gfs_didot, # "GFS Didot (Italic)"
TexFontTemplates.gfs_neoHellenic, # "GFS NeoHellenic"
TexFontTemplates.gnu_freesans_tx, # "GNU FreeSerif (and TX fonts symbols)"
TexFontTemplates.gnu_freeserif_freesans, # "GNU FreeSerif and FreeSans"
TexFontTemplates.helvetica_fourier_it, # "Helvetica with Fourier (Italic)"
TexFontTemplates.latin_modern_tw_it, # "Latin Modern Typewriter Proportional (CM Greek) (Italic)"
TexFontTemplates.latin_modern_tw, # "Latin Modern Typewriter Proportional"
TexFontTemplates.libertine, # "Libertine"
TexFontTemplates.libris_adf_fourier, # "Libris ADF with Fourier"
# TexFontTemplates.minion_pro_myriad_pro, # "Minion Pro and Myriad Pro (and TX fonts symbols)"
# TexFontTemplates.minion_pro_tx, # "Minion Pro (and TX fonts symbols)"
TexFontTemplates.new_century_schoolbook, # "New Century Schoolbook (Symbol Greek)"
TexFontTemplates.new_century_schoolbook_px, # "New Century Schoolbook (Symbol Greek, PX math symbols)"
# TexFontTemplates.noteworthy_light, # "Noteworthy Light"
TexFontTemplates.palatino, # "Palatino (Symbol Greek)"
# TexFontTemplates.papyrus, # "Papyrus"
TexFontTemplates.romande_adf_fourier_it, # "Romande ADF with Fourier (Italic)"
TexFontTemplates.slitex, # "SliTeX (Euler Greek)"
TexFontTemplates.times_fourier_it, # "Times with Fourier (Italic)"
TexFontTemplates.urw_avant_garde, # "URW Avant Garde (Symbol Greek)"
TexFontTemplates.urw_zapf_chancery, # "URW Zapf Chancery (CM Greek)"
TexFontTemplates.venturis_adf_fourier_it, # "Venturis ADF with Fourier (Italic)"
TexFontTemplates.verdana_it, # "Verdana (Italic)"
# TexFontTemplates.vollkorn_fourier_it, # "Vollkorn with Fourier (Italic)"
# TexFontTemplates.vollkorn, # "Vollkorn (TX fonts for Greek and math symbols)"
TexFontTemplates.zapf_chancery, # "Zapf Chancery"
]
self.add(Tex("Tex Font Template Example").to_edge(UL))
for font in examples:
print("Compiling tex for: ", font.description)
write_one_line(font)
self.play(
ShowCreation(
Tex(
"See more font templates at \\\\ http://jf.burnol.free.fr/showcase.html"
).shift(2 * DOWN)
)
)
self.wait(2)

View file

@ -22,29 +22,23 @@ class InCodeTexTemplate(Scene):
"""
def construct(self):
# Create a template
# Create a new template
template = TexTemplate()
# Other options include
# BasicTexTemplate()
# ThreeBlueOneBrownTexTemplate()
# ThreeBlueOneBrownCTEXTemplate()
# Add packages to the template
template.add_to_preamble(r"\usepackage{esvect}")
# Set the compiler and output format (default: latex and .dvi)
# possible tex compilers: "latex", "pdflatex", "xelatex", "lualatex", "luatex"
# possible output formats: ".dvi", ".pdf", and ".xdv"
template.tex_compiler = "pdflatex"
# Alternatives are "latex", "pdflatex", "xelatex", "lualatex", "luatex"
template.output_format = ".pdf"
# alternatives are ".dvi", ".pdf", and ".xdv"
# To use this as the default template for all Tex:
config["tex_template"] = template
# config["tex_template"] = template
# To use this template only for specific Tex() objects
# use the keyword argument tex_template
text = MathTex(r"\vv{vb}")
text = MathTex(r"f:A\rightarrow B", tex_template=template)
text.shift(DOWN)
self.play(Write(text))
# To use this template for a single Tex() or MathTex() object only
text2 = MathTex(r"f:A\rightarrow B", tex_template=template)
text2.shift(DOWN)
self.play(Write(text2))

View file

@ -79,4 +79,4 @@ from .utils.sounds import *
from .utils.space_ops import *
from .utils.strings import *
from .utils.tex import *
from .utils.tex_templates import *
from .utils.tex_templates import TexFontTemplates

View file

@ -49,19 +49,20 @@ class SingleStringMathTex(SVGMobject):
"organize_left_to_right": False,
"alignment": "",
"tex_environment": "align*",
"template": None,
"tex_template": None,
}
def __init__(self, tex_string, **kwargs):
digest_config(self, kwargs)
if self.template is None:
self.template = kwargs.get("tex_template", config["tex_template"])
if self.tex_template is None:
self.tex_template = kwargs.get("tex_template", config["tex_template"])
assert isinstance(tex_string, str)
self.tex_string = tex_string
file_name = tex_to_svg_file(
self.get_modified_expression(tex_string),
environment=self.tex_environment,
tex_template=self.template,
tex_template=self.tex_template,
)
SVGMobject.__init__(self, file_name=file_name, **kwargs)
if self.height is None:

View file

@ -6,6 +6,7 @@ import inspect
import os
import sys
import types
import re
def get_module(file_name):

View file

@ -5,15 +5,20 @@ __all__ = [
"TexTemplateFromFile",
"BasicTexTemplate",
"ThreeBlueOneBrownTexTemplate",
"ThreeBlueOneBrownCTEXTemplate",
"CTEXTemplate",
]
import os
threeblueonebrown_tex_template_body = r"""
\documentclass[preview]{standalone}
class TexTemplate:
"""
Class representing a TeX template to be used for creating Tex() and MathTex() objects.
"""
default_documentclass = r"\documentclass[preview]{standalone}"
default_preamble = r"""
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
@ -33,73 +38,105 @@ threeblueonebrown_tex_template_body = r"""
\usepackage{microtype}
\DisableLigatures{encoding = *, family = * }
\linespread{1}
\begin{document}
YourTextHere
\end{document}
"""
default_placeholder_text = "YourTextHere"
default_tex_compiler = "latex"
default_output_format = ".dvi"
default_post_doc_commands = ""
def __init__(
self,
tex_compiler=None,
output_format=None,
documentclass=None,
preamble=None,
placeholder_text=None,
post_doc_commands=None,
**kwargs
):
self.tex_compiler = (
tex_compiler
if tex_compiler is not None
else TexTemplate.default_tex_compiler
)
self.output_format = (
output_format
if output_format is not None
else TexTemplate.default_output_format
)
self.documentclass = (
documentclass
if documentclass is not None
else TexTemplate.default_documentclass
)
self.preamble = (
preamble if preamble is not None else TexTemplate.default_preamble
)
self.placeholder_text = (
placeholder_text
if placeholder_text is not None
else TexTemplate.default_placeholder_text
)
self.post_doc_commands = (
post_doc_commands
if post_doc_commands is not None
else TexTemplate.default_post_doc_commands
)
self.rebuild()
class TexTemplate:
"""
Class representing a TeX template to be used for creating Tex() and MathTex() objects.
"""
def rebuild(self):
self.body = (
self.documentclass
+ "\n"
+ self.preamble
+ "\n"
+ r"\begin{document}"
+ "\n"
+ self.post_doc_commands
+ "\n"
+ self.placeholder_text
+ "\n"
+ r"\end{document}"
+ "\n"
)
tex_compiler = None
output_format = None
body = None
has_environment = False
def __init__(self, **kwargs):
if self.tex_compiler is None:
self.tex_compiler = kwargs.pop("tex_compiler", "latex")
if self.output_format is None:
self.output_format = kwargs.pop("output_format", ".dvi")
self.prepare_template_body()
def prepare_template_body(self):
self.body = threeblueonebrown_tex_template_body
def prepend_to_preamble(self, txt):
# Adds txt to the TeX template preamble just after the \documentclass
self.preamble = txt + "\n" + self.preamble
self.rebuild()
def add_to_preamble(self, txt):
# Adds txt to the TeX template preamble just before \begin{document}
self.body = self.body.replace("\\begin{document}", txt + "\n\\begin{document}")
self.preamble += "\n" + txt
self.rebuild()
def add_to_document(self, txt):
# Adds txt to the TeX template just after \begin{document}
self.body = self.body.replace(
"\\begin{document}", "\\begin{document}\n" + txt + "\n"
)
self.post_doc_commands += "\n" + txt + "\n"
self.rebuild()
def get_texcode_for_expression(self, expression):
# Inserts expression verbatim into TeX template.
return self.body.replace("YourTextHere", expression)
return self.body.replace(self.placeholder_text, expression)
def get_texcode_for_expression_in_env(self, expression, environment):
# Inserts expression into TeX template wrapped in \begin{environemnt} and \end{environment}
begin = r"\begin{" + environment + "}"
end = r"\end{" + environment + "}"
return self.body.replace(
"YourTextHere", "{0}\n{1}\n{2}".format(begin, expression, end)
self.placeholder_text, "{0}\n{1}\n{2}".format(begin, expression, end)
)
class BasicTexTemplate(TexTemplate):
def prepare_template_body(self):
self.body = r"""
\documentclass[preview]{standalone}
def __init__(self, *args, **kwargs):
basic_headers = r"""
\usepackage[english]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\begin{document}
YourTextHere
\end{document}
\usepackage{amssymb}
"""
preamble = kwargs.pop("preamble", basic_headers)
super().__init__(*args, preamble=preamble, **kwargs)
class ThreeBlueOneBrownTexTemplate(TexTemplate):
@ -107,31 +144,49 @@ class ThreeBlueOneBrownTexTemplate(TexTemplate):
The default TeX template from the 3b1b version of manim
"""
def prepare_template_body(self):
self.body = threeblueonebrown_tex_template_body
pass
class ThreeBlueOneBrownCTEXTemplate(ThreeBlueOneBrownTexTemplate):
class CTEXTemplate(TexTemplate):
"""
The default TeX template from the 3b1b version of manim with the use_ctex option
"""
def __init__(self, **kwargs):
self.tex_compiler = kwargs.pop("tex_compiler", "xelatex")
self.output_format = kwargs.pop("output_format", ".xdv")
super().__init__(**kwargs)
def prepare_template_body(self):
self.body = threeblueonebrown_tex_template_body.replace(
tex_compiler = kwargs.pop("tex_compiler", "xelatex")
output_format = kwargs.pop("output_format", ".xdv")
preamble = TexTemplate.default_preamble.replace(
r"\DisableLigatures{encoding = *, family = * }", r"\usepackage[UTF8]{ctex}"
)
super().__init__(
tex_compiler=tex_compiler,
output_format=output_format,
preamble=preamble,
**kwargs
)
class TexTemplateFromFile(TexTemplate):
"""
A TexTemplate object created from a template file (default: tex_template.tex)
"""
def __init__(self, **kwargs):
self.template_file = kwargs.pop("filename", "tex_template.tex")
super().__init__(**kwargs)
def prepare_template_body(self):
def rebuild(self):
with open(self.template_file, "r") as infile:
self.body = infile.read()
def file_not_mutable():
raise Exception("Cannot modify TexTemplate when using a template file.")
def prepend_to_preamble(self, txt):
self.file_not_mutable()
def add_to_preamble(self, txt):
self.file_not_mutable()
def add_to_document(self, txt):
self.file_not_mutable()

View file

@ -21,21 +21,21 @@ def tex_hash(expression):
return hasher.hexdigest()[:16]
def tex_to_svg_file(expression, source_type, tex_template=None):
def tex_to_svg_file(expression, environment=None, tex_template=None):
if tex_template is None:
tex_template = config["tex_template"]
tex_file = generate_tex_file(expression, tex_template, source_type)
dvi_file = tex_to_dvi(tex_file, tex_template.use_ctex, tex_template.tex_compiler)
return dvi_to_svg(
dvi_file, use_ctex=tex_template.use_ctex, tex_compiler=tex_template.tex_compiler
tex_file = generate_tex_file(expression, environment, tex_template)
dvi_file = tex_to_dvi(
tex_file, tex_template.tex_compiler, tex_template.output_format
)
return dvi_to_svg(dvi_file, tex_template.output_format)
def generate_tex_file(expression, tex_template, source_type):
if source_type == "text":
output = tex_template.get_text_for_text_mode(expression)
elif source_type == "tex":
output = tex_template.get_text_for_tex_mode(expression)
def generate_tex_file(expression, environment, tex_template):
if environment is not None:
output = tex_template.get_texcode_for_expression_in_env(expression, environment)
else:
output = tex_template.get_texcode_for_expression(expression)
result = os.path.join(file_writer_config["tex_dir"], tex_hash(output)) + ".tex"
if not os.path.exists(result):
@ -45,22 +45,22 @@ def generate_tex_file(expression, tex_template, source_type):
return result
def tex_compilation_command(compiler, tex_file, tex_dir):
if compiler["command"] in {"latex", "pdflatex", "luatex", "lualatex"}:
def tex_compilation_command(tex_compiler, output_format, tex_file, tex_dir):
if tex_compiler in {"latex", "pdflatex", "luatex", "lualatex"}:
commands = [
compiler["command"],
tex_compiler,
"-interaction=batchmode",
f'-output-format="{compiler["output_format"][1:]}"',
f'-output-format="{output_format[1:]}"',
"-halt-on-error",
f'-output-directory="{tex_dir}"',
f'"{tex_file}"',
">",
os.devnull,
]
elif compiler["command"] == "xelatex":
if compiler["output_format"] == ".xdv":
elif tex_compiler == "xelatex":
if output_format == ".xdv":
outflag = "-no-pdf"
elif compiler["output_format"] == ".pdf":
elif output_format == ".pdf":
outflag = ""
else:
raise ValueError("xelatex output is either pdf or xdv")
@ -75,53 +75,41 @@ def tex_compilation_command(compiler, tex_file, tex_dir):
os.devnull,
]
else:
raise ValueError(f"Tex compiler {compiler['command']} unknown.")
raise ValueError(f"Tex compiler {tex_compiler} unknown.")
return " ".join(commands)
def tex_to_dvi(tex_file, use_ctex=False, tex_compiler=None):
if tex_compiler is None:
tex_compiler = (
{"command": "xelatex", "output_format": ".xdv"}
if use_ctex
else {"command": "latex", "output_format": ".dvi"}
)
result = tex_file.replace(".tex", tex_compiler["output_format"])
def tex_to_dvi(tex_file, tex_compiler, output_format):
result = tex_file.replace(".tex", output_format)
result = Path(result).as_posix()
tex_file = Path(tex_file).as_posix()
tex_dir = Path(file_writer_config["tex_dir"]).as_posix()
if not os.path.exists(result):
command = tex_compilation_command(tex_compiler, tex_file, tex_dir)
command = tex_compilation_command(
tex_compiler, output_format, tex_file, tex_dir
)
exit_code = os.system(command)
if exit_code != 0:
log_file = tex_file.replace(".tex", ".log")
raise ValueError(
f"{tex_compiler['command']} error converting to"
f" {tex_compiler['output_format'][1:]}. See log output above or"
f"{tex_compiler} error converting to"
f" {output_format[1:]}. See log output above or"
f" the log file: {log_file}"
)
return result
def dvi_to_svg(
dvi_file, use_ctex=False, tex_compiler=None, regen_if_exists=False, page=1
):
def dvi_to_svg(dvi_file, extension, regen_if_exists=False, page=1):
"""
Converts a dvi, xdv, or pdf file into an svg using dvisvgm.
"""
if tex_compiler is None:
tex_compiler = (
{"command": "xelatex", "output_format": ".xdv"}
if use_ctex
else {"command": "latex", "output_format": ".dvi"}
)
result = dvi_file.replace(tex_compiler["output_format"], ".svg")
result = dvi_file.replace(extension, ".svg")
result = Path(result).as_posix()
dvi_file = Path(dvi_file).as_posix()
if not os.path.exists(result):
commands = [
"dvisvgm",
"--pdf" if tex_compiler["output_format"] == ".pdf" else "",
"--pdf" if extension == ".pdf" else "",
"-p " + str(page),
'"{}"'.format(dvi_file),
"-n",

View file

@ -242,7 +242,7 @@ americantypewriter.add_to_preamble(
"""
)
americantypewriter.tex_compiler = "xelatex"
americantypewriter.output_format = ".xdv"
# Minion Pro and Myriad Pro (and TX fonts symbols)
mpmptx = BasicTexTemplate()
@ -260,6 +260,7 @@ mpmptx.add_to_preamble(
"""
)
mpmptx.tex_compiler = "xelatex"
mpmptx.output_format = ".xdv"
# New Century Schoolbook (Symbol Greek, PX math symbols)
@ -362,6 +363,7 @@ applechancery.add_to_preamble(
"""
)
applechancery.tex_compiler = "xelatex"
applechancery.output_format = ".xdv"
# Zapf Chancery
@ -392,6 +394,7 @@ italicverdana.add_to_preamble(
"""
)
italicverdana.tex_compiler = "xelatex"
italicverdana.output_format = ".xdv"
# URW Zapf Chancery (CM Greek)
@ -428,6 +431,7 @@ comicsansms.add_to_preamble(
"""
)
comicsansms.tex_compiler = "xelatex"
comicsansms.output_format = ".xdv"
# GFS Didot (Italic)
@ -469,6 +473,7 @@ mptx.add_to_preamble(
"""
)
mptx.tex_compiler = "xelatex"
mptx.output_format = ".xdv"
# GNU FreeSerif and FreeSans
@ -553,6 +558,7 @@ italicbaskerville.add_to_preamble(
"""
)
italicbaskerville.tex_compiler = "xelatex"
italicbaskerville.output_format = ".xdv"
# ECF JD (with TX fonts)
@ -597,6 +603,7 @@ papyrus.add_to_preamble(
"""
)
papyrus.tex_compiler = "xelatex"
papyrus.output_format = ".xdv"
# GNU FreeSerif (and TX fonts symbols)
@ -710,6 +717,7 @@ chalkboardse.add_to_preamble(
"""
)
chalkboardse.tex_compiler = "xelatex"
chalkboardse.output_format = ".xdv"
# Noteworthy Light
@ -797,6 +805,7 @@ brushscriptxpx.add_to_document(
"""
)
brushscriptxpx.tex_compiler = "xelatex"
brushscriptxpx.output_format = ".xdv"
# URW Avant Garde (Symbol Greek)
@ -838,7 +847,7 @@ italichelveticaf.add_to_preamble(
)
class TexFontTemplateCollection(object):
class TexFontTemplates(object):
"""A list of Tex templates for the fonts described at http://jf.burnol.free.fr/showcase.html"""
american_typewriter = americantypewriter # "American Typewriter"
@ -897,6 +906,3 @@ class TexFontTemplateCollection(object):
vollkorn_fourier_it = italicvollkornf # "Vollkorn with Fourier (Italic)"
vollkorn = vollkorntx # "Vollkorn (TX fonts for Greek and math symbols)"
zapf_chancery = zapfchancery # "Zapf Chancery"
TexFontTemplates = TexFontTemplateCollection()