From ef941b4040d91866f9d847ed097ae01e06ed5cd9 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 20 Dec 2022 22:35:41 -0800 Subject: [PATCH] Factor out num_tex_symbols --- manimlib/__init__.py | 1 + manimlib/mobject/svg/mtex_mobject.py | 44 ++++++++++++---------------- manimlib/utils/tex.py | 27 +++++++++++++++++ 3 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 manimlib/utils/tex.py diff --git a/manimlib/__init__.py b/manimlib/__init__.py index 7704b352..520d4825 100644 --- a/manimlib/__init__.py +++ b/manimlib/__init__.py @@ -75,3 +75,4 @@ from manimlib.utils.rate_functions import * from manimlib.utils.simple_functions import * from manimlib.utils.sounds import * from manimlib.utils.space_ops import * +from manimlib.utils.tex import * diff --git a/manimlib/mobject/svg/mtex_mobject.py b/manimlib/mobject/svg/mtex_mobject.py index b7adf2c4..5698dcfa 100644 --- a/manimlib/mobject/svg/mtex_mobject.py +++ b/manimlib/mobject/svg/mtex_mobject.py @@ -3,14 +3,17 @@ from __future__ import annotations import re from manimlib.mobject.svg.string_mobject import StringMobject +from manimlib.mobject.types.vectorized_mobject import VGroup +from manimlib.mobject.types.vectorized_mobject import VMobject from manimlib.utils.color import color_to_hex from manimlib.utils.color import hex_to_int from manimlib.utils.tex_file_writing import tex_content_to_svg_file +from manimlib.utils.tex import num_tex_symbols +from manimlib.logger import log from typing import TYPE_CHECKING if TYPE_CHECKING: - from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.typing import ManimColor, Span, Selector @@ -209,36 +212,27 @@ class MTex(StringMobject): ): return self.set_parts_color_by_dict(color_map) - @staticmethod - def n_symbols(tex) -> int: - """ - This function attempts to estimate the number of symbols that - a given string of tex would produce. - - No guarantees this is accurate. - """ - count_to_subtrs = [ - (0, ["emph", "textbf", "big", "Big", "small", "Small"]), - (2, ["sqrt", "ne"]), - (6, ["underbrace"]), - # Replace all other \expressions (like "\pi") with a single character - # Deliberately put this last. - (1, ["[a-zA-Z]+"]) - ] - for count, substrs in count_to_subtrs: - # Replace occurances of the given substrings with `count` characters - pattern = "|".join((R"\\" + s for s in substrs )) - tex = re.sub(pattern, "X" * count, tex) - # Ignore various control characters - return len(list(filter(lambda c: c not in "^{} \n\t_", tex))) def dirty_select(self, substr: str) -> VGroup: + """ + Tries to pull out substrings based on guessing how + many symbols are associated with a given tex string. + + This can fail in cases where the order of symbols does + not match the order in which they're drawn by latex. + For example, `\\underbrace{text}' orders the brace + after the text. + """ tex = self.get_tex() result = [] + if len(self) != num_tex_symbols(tex): + log.warning( + f"Estimated size of {tex} does not match true size", + ) for match in re.finditer(substr.replace("\\", R"\\"), tex): index = match.start() - start = self.n_symbols(tex[:index]) - end = start + self.n_symbols(substr) + start = num_tex_symbols(tex[:index]) + end = start + num_tex_symbols(substr) result.append(self[start:end]) return VGroup(*result) diff --git a/manimlib/utils/tex.py b/manimlib/utils/tex.py new file mode 100644 index 00000000..2d454731 --- /dev/null +++ b/manimlib/utils/tex.py @@ -0,0 +1,27 @@ +import re + +def num_tex_symbols(tex: str) -> int: + """ + This function attempts to estimate the number of symbols that + a given string of tex would produce. + + No guarantees this is accurate. + """ + count_to_subtrs = [ + (0, [ + "emph", "textbf", "big", "Big", "small", "Small", + "quad", "qquad", ",", ";", "ghost", + *"^{} \n\t_", + ]), + (2, ["sqrt", "ne"]), + (6, ["underbrace"]), + # Replace all other \expressions (like "\pi") with a single character + # Deliberately put this last. + (1, ["[a-zA-Z]+"]) + ] + for count, substrs in count_to_subtrs: + # Replace occurances of the given substrings with `count` characters + pattern = "|".join((R"\\" + s for s in substrs )) + tex = re.sub(pattern, "X" * count, tex) + # Ignore various control characters + return sum(map(lambda c: c not in "^{} \n\t_", tex))