From f158d3e75120d4ac92dbccceadf23224e3554011 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 14:41:06 -0800 Subject: [PATCH 01/12] Give unit_normal refreshing the same behavior as triangulation That is, don't actually compute it until it needs to be. This is necessary so that VMobject.append_points can refresh both of those, without effecting SVG initialization. --- manimlib/mobject/types/vectorized_mobject.py | 24 ++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/manimlib/mobject/types/vectorized_mobject.py b/manimlib/mobject/types/vectorized_mobject.py index e57dfdef..44b15e4d 100644 --- a/manimlib/mobject/types/vectorized_mobject.py +++ b/manimlib/mobject/types/vectorized_mobject.py @@ -100,6 +100,7 @@ class VMobject(Mobject): self.flat_stroke = flat_stroke self.needs_new_triangulation = True + self.needs_new_unit_normal = True self.triangulation = np.zeros(0, dtype='i4') super().__init__(**kwargs) @@ -114,7 +115,7 @@ class VMobject(Mobject): "fill_rgba": np.zeros((1, 4)), "stroke_rgba": np.zeros((1, 4)), "stroke_width": np.zeros((1, 1)), - "unit_normal": np.zeros((1, 3)) + "unit_normal": np.array(OUT, ndmin=2), }) # These are here just to make type checkers happy @@ -771,7 +772,7 @@ class VMobject(Mobject): ]) def get_unit_normal(self, recompute: bool = False) -> Vect3: - if not recompute: + if not self.needs_new_unit_normal and not recompute: return self.data["unit_normal"][0] if self.get_num_points() < 3: @@ -788,17 +789,12 @@ class VMobject(Mobject): points[2] - points[1], ) self.data["unit_normal"][:] = normal + self.needs_new_unit_normal = False return normal def refresh_unit_normal(self): for mob in self.get_family(): - mob.get_unit_normal(recompute=True) - return self - - def reverse_points(self): - super().reverse_points() - self.refresh_unit_normal() - self.refresh_triangulation() + mob.needs_new_unit_normal = True return self # Alignment @@ -1030,6 +1026,16 @@ class VMobject(Mobject): super().set_points(points) return self + @triggers_refreshed_triangulation + def append_points(self, points: Vect3Array): + super().append_points(points) + return self + + @triggers_refreshed_triangulation + def reverse_points(self): + super().reverse_points() + return self + @triggers_refreshed_triangulation def set_data(self, data: dict): super().set_data(data) From ef64b90ed358bc6d0d31bac0e00b1ca3e60b152d Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 14:42:04 -0800 Subject: [PATCH 02/12] Allow for default height/width of SVGMobject specified as class variables --- manimlib/mobject/svg/svg_mobject.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/manimlib/mobject/svg/svg_mobject.py b/manimlib/mobject/svg/svg_mobject.py index 1248456e..6476cd95 100644 --- a/manimlib/mobject/svg/svg_mobject.py +++ b/manimlib/mobject/svg/svg_mobject.py @@ -35,12 +35,14 @@ def _convert_point_to_3d(x: float, y: float) -> np.ndarray: class SVGMobject(VMobject): file_name: str = "" + height: float | None = 2.0 + width: float | None = None def __init__( self, file_name: str = "", should_center: bool = True, - height: float | None = 2.0, + height: float | None = None, width: float | None = None, # Style that overrides the original svg color: ManimColor = None, @@ -66,7 +68,6 @@ class SVGMobject(VMobject): self.file_name = file_name or self.file_name self.svg_default = dict(svg_default) self.path_string_config = dict(path_string_config) - self.height = height super().__init__(**kwargs ) self.init_svg_mobject() @@ -82,6 +83,9 @@ class SVGMobject(VMobject): ) # Initialize position + height = height or self.height + width = width or self.width + if should_center: self.center() if height is not None: From 2c20a1509e9fe5ec83de01215bc2c00be1f63a44 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 14:43:10 -0800 Subject: [PATCH 03/12] Remoe height defaults form __init__args of SingleStringTex and String --- manimlib/mobject/svg/string_mobject.py | 4 ++-- manimlib/mobject/svg/tex_mobject.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/manimlib/mobject/svg/string_mobject.py b/manimlib/mobject/svg/string_mobject.py index 8c70b442..7cde9240 100644 --- a/manimlib/mobject/svg/string_mobject.py +++ b/manimlib/mobject/svg/string_mobject.py @@ -51,10 +51,11 @@ class StringMobject(SVGMobject, ABC): so that each submobject of the original `SVGMobject` will be labelled by the color of its paired submobject from the additional `SVGMobject`. """ + height = None + def __init__( self, string: str, - height: float | None = None, fill_color: ManimColor = WHITE, stroke_color: ManimColor = WHITE, stroke_width: float = 0, @@ -75,7 +76,6 @@ class StringMobject(SVGMobject, ABC): self.parse() super().__init__( - height=height, stroke_color=stroke_color, fill_color=fill_color, stroke_width=stroke_width, diff --git a/manimlib/mobject/svg/tex_mobject.py b/manimlib/mobject/svg/tex_mobject.py index 366e659f..8883edd0 100644 --- a/manimlib/mobject/svg/tex_mobject.py +++ b/manimlib/mobject/svg/tex_mobject.py @@ -25,6 +25,8 @@ SCALE_FACTOR_PER_FONT_POINT = 0.001 class SingleStringTex(SVGMobject): + height: float | None = None + def __init__( self, tex_string: str, @@ -60,6 +62,7 @@ class SingleStringTex(SVGMobject): fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, + path_string_config=path_string_config, **kwargs ) From 96d9e41a3519b3f9584d78d5c26a721c2a81576a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 14:43:27 -0800 Subject: [PATCH 04/12] Refresh unit normal on init of brace --- manimlib/mobject/svg/brace.py | 1 + 1 file changed, 1 insertion(+) diff --git a/manimlib/mobject/svg/brace.py b/manimlib/mobject/svg/brace.py index 8ea55047..53c84a7e 100644 --- a/manimlib/mobject/svg/brace.py +++ b/manimlib/mobject/svg/brace.py @@ -52,6 +52,7 @@ class Brace(SingleStringTex): self.shift(left - self.get_corner(UL) + buff * DOWN) for mob in mobject, self: mob.rotate(angle, about_point=ORIGIN) + self.refresh_unit_normal() def set_initial_width(self, width: float): width_diff = width - self.get_width() From 8d05431b7bd4b6a98639d39494a2f289788b59c9 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 14:43:57 -0800 Subject: [PATCH 05/12] Add points in reverse order to AngularSector --- manimlib/mobject/geometry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/manimlib/mobject/geometry.py b/manimlib/mobject/geometry.py index bf6229fc..98081998 100644 --- a/manimlib/mobject/geometry.py +++ b/manimlib/mobject/geometry.py @@ -405,6 +405,7 @@ class AnnularSector(VMobject): fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, + **kwargs, ) # Initialize points @@ -417,11 +418,10 @@ class AnnularSector(VMobject): ) for radius in (inner_radius, outer_radius) ] - outer_arc.reverse_points() - self.append_points(inner_arc.get_points()) + self.append_points(inner_arc.get_points()[::-1]) # Reverse self.add_line_to(outer_arc.get_points()[0]) self.append_points(outer_arc.get_points()) - self.add_line_to(inner_arc.get_points()[0]) + self.add_line_to(inner_arc.get_points()[-1]) class Sector(AnnularSector): @@ -454,6 +454,7 @@ class Annulus(VMobject): fill_color=fill_color, fill_opacity=fill_opacity, stroke_width=stroke_width, + **kwargs, ) self.radius = outer_radius From 71c9144952bb17002aad879987871eb8c4eadb69 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:03:16 -0800 Subject: [PATCH 06/12] Use io.BytesIO rather than writing to a temp file --- manimlib/mobject/svg/svg_mobject.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/manimlib/mobject/svg/svg_mobject.py b/manimlib/mobject/svg/svg_mobject.py index 6476cd95..fa2286cf 100644 --- a/manimlib/mobject/svg/svg_mobject.py +++ b/manimlib/mobject/svg/svg_mobject.py @@ -5,6 +5,7 @@ from xml.etree import ElementTree as ET import numpy as np import svgelements as se +import io from manimlib.constants import RIGHT from manimlib.logger import log @@ -118,13 +119,13 @@ class SVGMobject(VMobject): file_path = self.get_file_path() element_tree = ET.parse(file_path) new_tree = self.modify_xml_tree(element_tree) - # Create a temporary svg file to dump modified svg to be parsed - root, ext = os.path.splitext(file_path) - modified_file_path = root + "_" + ext - new_tree.write(modified_file_path) - svg = se.SVG.parse(modified_file_path) - os.remove(modified_file_path) + # New svg based on tree contents + data_stream = io.BytesIO() + new_tree.write(data_stream) + data_stream.seek(0) + svg = se.SVG.parse(data_stream) + data_stream.close() mobjects = self.get_mobjects_from(svg) self.add(*mobjects) From ab470c3ee598e335c4f2252a8802d71a8cc59e93 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:19:43 -0800 Subject: [PATCH 07/12] Move display_during_exection associated with Latex rendering Only have it display when a new SVG is being written --- manimlib/mobject/svg/mtex_mobject.py | 8 +++----- manimlib/mobject/svg/tex_mobject.py | 8 +++----- manimlib/utils/tex_file_writing.py | 3 ++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/manimlib/mobject/svg/mtex_mobject.py b/manimlib/mobject/svg/mtex_mobject.py index fdf33663..dda35e9b 100644 --- a/manimlib/mobject/svg/mtex_mobject.py +++ b/manimlib/mobject/svg/mtex_mobject.py @@ -3,7 +3,6 @@ from __future__ import annotations import re from manimlib.mobject.svg.string_mobject import StringMobject -from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -79,10 +78,9 @@ class MTex(StringMobject): ) def get_file_path_by_content(self, content: str) -> str: - with display_during_execution(f"Writing \"{self.tex_string}\""): - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble + ) return file_path # Parsing diff --git a/manimlib/mobject/svg/tex_mobject.py b/manimlib/mobject/svg/tex_mobject.py index 8883edd0..2101163c 100644 --- a/manimlib/mobject/svg/tex_mobject.py +++ b/manimlib/mobject/svg/tex_mobject.py @@ -11,7 +11,6 @@ from manimlib.constants import MED_LARGE_BUFF, SMALL_BUFF from manimlib.mobject.geometry import Line from manimlib.mobject.svg.svg_mobject import SVGMobject from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -86,10 +85,9 @@ class SingleStringTex(SVGMobject): def get_file_path(self) -> str: content = self.get_tex_file_body(self.tex_string) - with display_during_execution(f"Writing \"{self.tex_string}\""): - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble + ) return file_path def get_tex_file_body(self, tex_string: str) -> str: diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index 35304b9e..fd45262a 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -78,7 +78,8 @@ def tex_content_to_svg_file( ) if not os.path.exists(svg_file): # If svg doesn't exist, create it - create_tex_svg(full_tex, svg_file, compiler) + with display_during_execution(f"Writing \"{content}\""): + create_tex_svg(full_tex, svg_file, compiler) return svg_file From 5c0232a5e0581c613cbb7fd34577ffa302d838f5 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:20:19 -0800 Subject: [PATCH 08/12] Have LatexError show line of error and the next line This is where undefined control sequence errors will show up. --- manimlib/utils/tex_file_writing.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index fd45262a..a6473572 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -113,14 +113,15 @@ def create_tex_svg(full_tex: str, svg_file: str, compiler: str) -> None: log.error( "LaTeX Error! Not a worry, it happens to the best of us." ) + error_str = "" with open(root + ".log", "r", encoding="utf-8") as log_file: - error_match_obj = re.search(r"(?<=\n! ).*", log_file.read()) + error_match_obj = re.search(r"(?<=\n! ).*\n.*\n", log_file.read()) if error_match_obj: + error_str = error_match_obj.group() log.debug( - "The error could be: `%s`", - error_match_obj.group() + f"The error could be:\n`{error_str}`", ) - raise LatexError() + raise LatexError(error_str) # dvi to svg os.system(" ".join(( From b2fd22c53928667010928fbb95a006fcd144b882 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:21:40 -0800 Subject: [PATCH 09/12] Small cleanups --- manimlib/mobject/svg/string_mobject.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/manimlib/mobject/svg/string_mobject.py b/manimlib/mobject/svg/string_mobject.py index 7cde9240..0bda1488 100644 --- a/manimlib/mobject/svg/string_mobject.py +++ b/manimlib/mobject/svg/string_mobject.py @@ -69,7 +69,6 @@ class StringMobject(SVGMobject, ABC): **kwargs ): self.string = string - self.path_string_config = dict(path_string_config) self.base_color = base_color or WHITE self.isolate = isolate self.protect = protect @@ -79,6 +78,7 @@ class StringMobject(SVGMobject, ABC): stroke_color=stroke_color, fill_color=fill_color, stroke_width=stroke_width, + path_string_config=path_string_config, **kwargs ) self.labels = [submob.label for submob in self.submobjects] @@ -105,7 +105,7 @@ class StringMobject(SVGMobject, ABC): labelled_svg = SVGMobject(file_path) if len(self.submobjects) != len(labelled_svg.submobjects): log.warning( - "Cannot align submobjects of the labelled svg " + "Cannot align submobjects of the labelled svg " + \ "to the original svg. Skip the labelling process." ) for submob in self.submobjects: @@ -126,7 +126,7 @@ class StringMobject(SVGMobject, ABC): submob.label = label if unrecognizable_colors: log.warning( - "Unrecognizable color labels detected (%s). " + "Unrecognizable color labels detected (%s). " + \ "The result could be unexpected.", ", ".join( self.int_to_hex(color) @@ -144,11 +144,7 @@ class StringMobject(SVGMobject, ABC): if not labelled_svg.submobjects: return - bb_0 = self.get_bounding_box() - bb_1 = labelled_svg.get_bounding_box() - scale_factor = abs((bb_0[2] - bb_0[0]) / (bb_1[2] - bb_1[0])) - labelled_svg.move_to(self).scale(scale_factor) - + labelled_svg.replace(self) distance_matrix = cdist( [submob.get_center() for submob in self.submobjects], [submob.get_center() for submob in labelled_svg.submobjects] From a53867d8a16326945699f7d5a962eb395799f79a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:54:44 -0800 Subject: [PATCH 10/12] Fix TexText bug --- manimlib/mobject/svg/tex_mobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manimlib/mobject/svg/tex_mobject.py b/manimlib/mobject/svg/tex_mobject.py index 2101163c..64788d03 100644 --- a/manimlib/mobject/svg/tex_mobject.py +++ b/manimlib/mobject/svg/tex_mobject.py @@ -247,7 +247,7 @@ class Tex(SingleStringTex): tex_string = tex_string.strip() if len(tex_string) == 0: continue - sub_tex_mob = SingleStringTex(tex_string) + sub_tex_mob = SingleStringTex(tex_string, math_mode=self.math_mode) num_submobs = len(sub_tex_mob) if num_submobs == 0: continue From c2c8149627773c0654fe155f080fb9c7e52dcd35 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 16:54:55 -0800 Subject: [PATCH 11/12] Revert "Move display_during_exection associated with Latex rendering" This reverts commit ab470c3ee598e335c4f2252a8802d71a8cc59e93. --- manimlib/mobject/svg/mtex_mobject.py | 8 +++++--- manimlib/mobject/svg/tex_mobject.py | 8 +++++--- manimlib/utils/tex_file_writing.py | 3 +-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/manimlib/mobject/svg/mtex_mobject.py b/manimlib/mobject/svg/mtex_mobject.py index dda35e9b..fdf33663 100644 --- a/manimlib/mobject/svg/mtex_mobject.py +++ b/manimlib/mobject/svg/mtex_mobject.py @@ -3,6 +3,7 @@ from __future__ import annotations import re from manimlib.mobject.svg.string_mobject import StringMobject +from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -78,9 +79,10 @@ class MTex(StringMobject): ) def get_file_path_by_content(self, content: str) -> str: - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + with display_during_execution(f"Writing \"{self.tex_string}\""): + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble + ) return file_path # Parsing diff --git a/manimlib/mobject/svg/tex_mobject.py b/manimlib/mobject/svg/tex_mobject.py index 64788d03..549ccfe9 100644 --- a/manimlib/mobject/svg/tex_mobject.py +++ b/manimlib/mobject/svg/tex_mobject.py @@ -11,6 +11,7 @@ from manimlib.constants import MED_LARGE_BUFF, SMALL_BUFF from manimlib.mobject.geometry import Line from manimlib.mobject.svg.svg_mobject import SVGMobject from manimlib.mobject.types.vectorized_mobject import VGroup +from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -85,9 +86,10 @@ class SingleStringTex(SVGMobject): def get_file_path(self) -> str: content = self.get_tex_file_body(self.tex_string) - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + with display_during_execution(f"Writing \"{self.tex_string}\""): + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble + ) return file_path def get_tex_file_body(self, tex_string: str) -> str: diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index a6473572..14ce8403 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -78,8 +78,7 @@ def tex_content_to_svg_file( ) if not os.path.exists(svg_file): # If svg doesn't exist, create it - with display_during_execution(f"Writing \"{content}\""): - create_tex_svg(full_tex, svg_file, compiler) + create_tex_svg(full_tex, svg_file, compiler) return svg_file From e0e7e24351f433e981464194fb66cacbfed449e0 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 19 Dec 2022 17:01:06 -0800 Subject: [PATCH 12/12] Move display_during_execturion call Such that it only gets called when a new svg needs to be written --- manimlib/mobject/svg/mtex_mobject.py | 8 +++----- manimlib/mobject/svg/tex_mobject.py | 8 +++----- manimlib/utils/tex_file_writing.py | 6 ++++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/manimlib/mobject/svg/mtex_mobject.py b/manimlib/mobject/svg/mtex_mobject.py index fdf33663..fdb40cd3 100644 --- a/manimlib/mobject/svg/mtex_mobject.py +++ b/manimlib/mobject/svg/mtex_mobject.py @@ -3,7 +3,6 @@ from __future__ import annotations import re from manimlib.mobject.svg.string_mobject import StringMobject -from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -79,10 +78,9 @@ class MTex(StringMobject): ) def get_file_path_by_content(self, content: str) -> str: - with display_during_execution(f"Writing \"{self.tex_string}\""): - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble, self.tex_string + ) return file_path # Parsing diff --git a/manimlib/mobject/svg/tex_mobject.py b/manimlib/mobject/svg/tex_mobject.py index 549ccfe9..2b5b38bc 100644 --- a/manimlib/mobject/svg/tex_mobject.py +++ b/manimlib/mobject/svg/tex_mobject.py @@ -11,7 +11,6 @@ from manimlib.constants import MED_LARGE_BUFF, SMALL_BUFF from manimlib.mobject.geometry import Line from manimlib.mobject.svg.svg_mobject import SVGMobject from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.utils.tex_file_writing import display_during_execution from manimlib.utils.tex_file_writing import tex_content_to_svg_file from typing import TYPE_CHECKING @@ -86,10 +85,9 @@ class SingleStringTex(SVGMobject): def get_file_path(self) -> str: content = self.get_tex_file_body(self.tex_string) - with display_during_execution(f"Writing \"{self.tex_string}\""): - file_path = tex_content_to_svg_file( - content, self.template, self.additional_preamble - ) + file_path = tex_content_to_svg_file( + content, self.template, self.additional_preamble, self.tex_string + ) return file_path def get_tex_file_body(self, tex_string: str) -> str: diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index 14ce8403..6538adc9 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -52,7 +52,8 @@ def get_tex_config() -> dict[str, str]: def tex_content_to_svg_file( - content: str, template: str, additional_preamble: str + content: str, template: str, additional_preamble: str, + short_tex: str ) -> str: tex_config = get_tex_config() if not template or template == tex_config["template"]: @@ -78,7 +79,8 @@ def tex_content_to_svg_file( ) if not os.path.exists(svg_file): # If svg doesn't exist, create it - create_tex_svg(full_tex, svg_file, compiler) + with display_during_execution("Writing " + short_tex): + create_tex_svg(full_tex, svg_file, compiler) return svg_file