mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Add caching functionality, and have Tex and Text both use it for saved svg strings
This commit is contained in:
parent
88370d4d5d
commit
129e512b0c
7 changed files with 64 additions and 46 deletions
|
@ -61,6 +61,7 @@ from manimlib.scene.interactive_scene import *
|
||||||
from manimlib.scene.scene import *
|
from manimlib.scene.scene import *
|
||||||
|
|
||||||
from manimlib.utils.bezier import *
|
from manimlib.utils.bezier import *
|
||||||
|
from manimlib.utils.cache import *
|
||||||
from manimlib.utils.color import *
|
from manimlib.utils.color import *
|
||||||
from manimlib.utils.dict_ops import *
|
from manimlib.utils.dict_ops import *
|
||||||
from manimlib.utils.customization import *
|
from manimlib.utils.customization import *
|
||||||
|
|
|
@ -7,7 +7,7 @@ import re
|
||||||
from manimlib.constants import BLACK, WHITE
|
from manimlib.constants import BLACK, WHITE
|
||||||
from manimlib.mobject.svg.svg_mobject import SVGMobject
|
from manimlib.mobject.svg.svg_mobject import SVGMobject
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||||
from manimlib.utils.tex_file_writing import tex_content_to_svg_file
|
from manimlib.utils.tex_file_writing import tex_to_svg
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
@ -76,12 +76,12 @@ class SingleStringTex(SVGMobject):
|
||||||
self.additional_preamble
|
self.additional_preamble
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_file_path(self) -> str:
|
def get_svg_string_by_content(self, content: str) -> str:
|
||||||
content = self.get_tex_file_body(self.tex_string)
|
return get_cached_value(
|
||||||
file_path = tex_content_to_svg_file(
|
key=hash_string(str((content, self.template, self.additional_preamble))),
|
||||||
content, self.template, self.additional_preamble, self.tex_string
|
value_func=lambda: tex_to_svg(content, self.template, self.additional_preamble),
|
||||||
|
message=f"Writing {self.tex_string}..."
|
||||||
)
|
)
|
||||||
return file_path
|
|
||||||
|
|
||||||
def get_tex_file_body(self, tex_string: str) -> str:
|
def get_tex_file_body(self, tex_string: str) -> str:
|
||||||
new_tex = self.get_modified_expression(tex_string)
|
new_tex = self.get_modified_expression(tex_string)
|
||||||
|
|
|
@ -20,7 +20,6 @@ from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||||
from manimlib.utils.directories import get_mobject_data_dir
|
from manimlib.utils.directories import get_mobject_data_dir
|
||||||
from manimlib.utils.images import get_full_vector_image_path
|
from manimlib.utils.images import get_full_vector_image_path
|
||||||
from manimlib.utils.iterables import hash_obj
|
from manimlib.utils.iterables import hash_obj
|
||||||
from manimlib.utils.simple_functions import hash_string
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
|
@ -6,10 +6,12 @@ from pathlib import Path
|
||||||
from manimlib.mobject.svg.string_mobject import StringMobject
|
from manimlib.mobject.svg.string_mobject import StringMobject
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||||
|
from manimlib.utils.cache import get_cached_value
|
||||||
from manimlib.utils.color import color_to_hex
|
from manimlib.utils.color import color_to_hex
|
||||||
from manimlib.utils.color import hex_to_int
|
from manimlib.utils.color import hex_to_int
|
||||||
from manimlib.utils.tex_file_writing import tex_content_to_svg_file
|
from manimlib.utils.tex_file_writing import tex_to_svg
|
||||||
from manimlib.utils.tex import num_tex_symbols
|
from manimlib.utils.tex import num_tex_symbols
|
||||||
|
from manimlib.utils.simple_functions import hash_string
|
||||||
from manimlib.logger import log
|
from manimlib.logger import log
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
@ -84,11 +86,11 @@ class Tex(StringMobject):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_svg_string_by_content(self, content: str) -> str:
|
def get_svg_string_by_content(self, content: str) -> str:
|
||||||
# TODO, implement this without writing to a file
|
return get_cached_value(
|
||||||
file_path = tex_content_to_svg_file(
|
key=hash_string(str((content, self.template, self.additional_preamble))),
|
||||||
content, self.template, self.additional_preamble, self.tex_string
|
value_func=lambda: tex_to_svg(content, self.template, self.additional_preamble),
|
||||||
|
message=f"Writing {self.tex_string}..."
|
||||||
)
|
)
|
||||||
return Path(file_path).read_text()
|
|
||||||
|
|
||||||
def _handle_scale_side_effects(self, scale_factor: float) -> Self:
|
def _handle_scale_side_effects(self, scale_factor: float) -> Self:
|
||||||
self.font_size *= scale_factor
|
self.font_size *= scale_factor
|
||||||
|
|
|
@ -16,9 +16,10 @@ from manimlib.constants import DEFAULT_PIXEL_WIDTH, FRAME_WIDTH
|
||||||
from manimlib.constants import NORMAL
|
from manimlib.constants import NORMAL
|
||||||
from manimlib.logger import log
|
from manimlib.logger import log
|
||||||
from manimlib.mobject.svg.string_mobject import StringMobject
|
from manimlib.mobject.svg.string_mobject import StringMobject
|
||||||
from manimlib.utils.customization import get_customization
|
from manimlib.utils.cache import get_cached_value
|
||||||
from manimlib.utils.color import color_to_hex
|
from manimlib.utils.color import color_to_hex
|
||||||
from manimlib.utils.color import int_to_hex
|
from manimlib.utils.color import int_to_hex
|
||||||
|
from manimlib.utils.customization import get_customization
|
||||||
from manimlib.utils.directories import get_downloads_dir
|
from manimlib.utils.directories import get_downloads_dir
|
||||||
from manimlib.utils.directories import get_text_dir
|
from manimlib.utils.directories import get_text_dir
|
||||||
from manimlib.utils.simple_functions import hash_string
|
from manimlib.utils.simple_functions import hash_string
|
||||||
|
@ -172,17 +173,14 @@ class MarkupText(StringMobject):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_svg_string_by_content(self, content: str) -> str:
|
def get_svg_string_by_content(self, content: str) -> str:
|
||||||
# TODO, check the cache
|
key = hash_string(str((
|
||||||
hash_content = str((
|
|
||||||
content,
|
content,
|
||||||
self.justify,
|
self.justify,
|
||||||
self.indent,
|
self.indent,
|
||||||
self.alignment,
|
self.alignment,
|
||||||
self.line_width
|
self.line_width
|
||||||
))
|
)))
|
||||||
# hash_string(hash_content)
|
return get_cached_value(key, lambda: self.markup_to_svg_string(content))
|
||||||
key = hashlib.sha256(hash_content.encode()).hexdigest()
|
|
||||||
return self.markup_to_svg_string(content)
|
|
||||||
|
|
||||||
def markup_to_svg_string(self, markup_str: str) -> str:
|
def markup_to_svg_string(self, markup_str: str) -> str:
|
||||||
self.validate_markup_string(markup_str)
|
self.validate_markup_string(markup_str)
|
||||||
|
|
33
manimlib/utils/cache.py
Normal file
33
manimlib/utils/cache.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import appdirs
|
||||||
|
import os
|
||||||
|
from diskcache import Cache
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
|
CACHE_SIZE = 1e9 # 1 Gig
|
||||||
|
|
||||||
|
|
||||||
|
def get_cached_value(key, value_func, message=""):
|
||||||
|
cache_dir = appdirs.user_cache_dir("manim")
|
||||||
|
cache = Cache(cache_dir, size_limit=CACHE_SIZE)
|
||||||
|
|
||||||
|
value = cache.get(key)
|
||||||
|
if value is None:
|
||||||
|
with display_during_execution(message):
|
||||||
|
value = value_func()
|
||||||
|
cache.set(key, value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def display_during_execution(message: str):
|
||||||
|
# Merge into a single line
|
||||||
|
to_print = message.replace("\n", " ")
|
||||||
|
max_characters = os.get_terminal_size().columns - 1
|
||||||
|
if len(to_print) > max_characters:
|
||||||
|
to_print = to_print[:max_characters - 3] + "..."
|
||||||
|
try:
|
||||||
|
print(to_print, end="\r")
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
print(" " * len(to_print), end="\r")
|
|
@ -1,10 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from contextlib import contextmanager
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from manimlib.config import get_custom_config
|
from manimlib.config import get_custom_config
|
||||||
from manimlib.config import get_manim_dir
|
from manimlib.config import get_manim_dir
|
||||||
from manimlib.logger import log
|
from manimlib.logger import log
|
||||||
|
@ -51,9 +53,10 @@ def get_tex_config() -> dict[str, str]:
|
||||||
return SAVED_TEX_CONFIG
|
return SAVED_TEX_CONFIG
|
||||||
|
|
||||||
|
|
||||||
def tex_content_to_svg_file(
|
def tex_to_svg(
|
||||||
content: str, template: str, additional_preamble: str,
|
content: str,
|
||||||
short_tex: str
|
template: str,
|
||||||
|
additional_preamble: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
tex_config = get_tex_config()
|
tex_config = get_tex_config()
|
||||||
if not template or template == tex_config["template"]:
|
if not template or template == tex_config["template"]:
|
||||||
|
@ -74,14 +77,11 @@ def tex_content_to_svg_file(
|
||||||
"\\end{document}"
|
"\\end{document}"
|
||||||
)) + "\n"
|
)) + "\n"
|
||||||
|
|
||||||
svg_file = os.path.join(
|
with tempfile.NamedTemporaryFile(suffix='.svg', mode='r+') as tmp:
|
||||||
get_tex_dir(), hash_string(full_tex) + ".svg"
|
create_tex_svg(full_tex, tmp.name, compiler)
|
||||||
)
|
# Read the contents
|
||||||
if not os.path.exists(svg_file):
|
tmp.seek(0)
|
||||||
# If svg doesn't exist, create it
|
return tmp.read()
|
||||||
with display_during_execution("Writing " + short_tex):
|
|
||||||
create_tex_svg(full_tex, svg_file, compiler)
|
|
||||||
return svg_file
|
|
||||||
|
|
||||||
|
|
||||||
def create_tex_svg(full_tex: str, svg_file: str, compiler: str) -> None:
|
def create_tex_svg(full_tex: str, svg_file: str, compiler: str) -> None:
|
||||||
|
@ -145,20 +145,5 @@ def create_tex_svg(full_tex: str, svg_file: str, compiler: str) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# TODO, perhaps this should live elsewhere
|
|
||||||
@contextmanager
|
|
||||||
def display_during_execution(message: str):
|
|
||||||
# Merge into a single line
|
|
||||||
to_print = message.replace("\n", " ")
|
|
||||||
max_characters = os.get_terminal_size().columns - 1
|
|
||||||
if len(to_print) > max_characters:
|
|
||||||
to_print = to_print[:max_characters - 3] + "..."
|
|
||||||
try:
|
|
||||||
print(to_print, end="\r")
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
print(" " * len(to_print), end="\r")
|
|
||||||
|
|
||||||
|
|
||||||
class LatexError(Exception):
|
class LatexError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Add table
Reference in a new issue