Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ManimCE Doesn't Recognize Text Object's changes When Rerunning The Scene Due to Old Cache #4096

Open
OdyAsh opened this issue Jan 9, 2025 · 6 comments

Comments

@OdyAsh
Copy link

OdyAsh commented Jan 9, 2025

Description of bug / unexpected behavior

Given the below code [1] , I rerun manim src\manim_odyash_playground\scene.py -> 1 command after changing gradient to (GREEN, ...) instead of (RED, ...), yet the scene gets rendered with RED color [2].

Note: This always happens, but if I change text, font, or apparently any other str-related argument ---> the issue gets fixed! --> I.e., the scene gets rendered with GREEN color!

(so changing width doesn't fix the issue either)

[1]:

class SceneTest(Scene):
    def construct(self):
        oa_txt = Text(text="Hello Amazing World!", font="", width=6.5, gradient=(RED, WHITE, BLUE))
        self.play(Write(oa_txt))

[2]:

image

Expected behavior

Any update that I do in any argument of Text Mobject should make it refreshed (i.e., updated) when I rerun the script!

How to reproduce the issue

Provided in [1] above.

Also, these are the project's requirements till now [3]:

manim==0.18.1
python3-pip-autoremove==0.9.1
ffmpeg-python==0.2.0
Code for reproducing the problem

Provided in [1] above.

Additional media files

Images/GIFs

Provided in [2] above.

Logs

Terminal output

This is the log (after changing RED to GREEN):

[01/09/25 08:21:42] DEBUG    Hashing ...                                                                                                                                                hashing.py:352
[01/09/25 08:21:43] DEBUG    Hashing done in 0.173308 s.                                                                                                                                hashing.py:364
                    DEBUG    Hash generated :  3977891868_4229486692_223132457                                                                                                          hashing.py:367
                    INFO     Animation 0 : Using cached data (hash : 3977891868_4229486692_223132457)                                                                             cairo_renderer.py:88
                    DEBUG    List of the first few animation hashes of the scene: ['3977891868_4229486692_223132457']                                                             cairo_renderer.py:97
                    INFO     Combining to Movie file.                                                                                                                         scene_file_writer.py:617
                    DEBUG    Partial movie files to combine (1 files):                                                                                                        scene_file_writer.py:561
                             ['D:\\CS\\projects\\manim-odyash-playground\\media\\videos\\scene\\1080p60\\partial_movie_files\\SceneTest\\3977891868_4229486692_223132457.mp4'                         
                             ]                                                                                                                                                                        
                    INFO                                                                                                                                                      scene_file_writer.py:737
                             File ready at 'D:\CS\projects\manim-odyash-playground\media\videos\scene\1080p60\SceneTest.mp4'                                                                          
                                                                                                                                                                                                      
                    INFO     Rendered SceneTest                                                                                                                                           scene.py:247
                             Played 1 animations 

System specifications

System Details
  • OS: Windows 11 Version 24H2 (OS Build 26100.2605)
  • RAM: 16GB
  • Python version (python/py/python3 --version): 3.11
  • Installed modules (provide output from pip list): provided in [3] above, I just pip installed those
LaTeX details

Note: I don't think this section is relevant, as the code doesn't use latex.

  • LaTeX distribution (e.g. TeX Live 2020): MiKTeX 23.5 (I figured it out by running pdftex --version command.
  • Installed LaTeX packages: I get tlmgr : The term 'tlmgr' is not recognized error when running tlmgr list --only-installed

Additional comments

None.

@uwezi
Copy link
Contributor

uwezi commented Jan 9, 2025

The problem is easily reproducible with the following compact snippet. The problem must be that the color gradient= (I did not even know such an option existed) is handled by Pango, but not part of the hash.

class SceneTest(Scene):
    def construct(self):
        oa_txt = Text(text="Hello Amazing World!", font="", width=6.5, gradient=[RED, WHITE, BLUE])
        ob_txt = Text(text="Hello Amazing World!", font="", width=6.5, gradient=[GREEN, WHITE, BLUE])
        ob_txt.next_to(oa_txt,DOWN)
        self.add(oa_txt,ob_txt)

image

I would suggest to deprecate the use of gradient= and let Manim do the coloring

class SceneTest2(Scene):
    def construct(self):
        oa_txt = Text(text="Hello Amazing World!", font="", width=6.5)
        ob_txt = Text(text="Hello Amazing World!", font="", width=6.5)
        ob_txt.next_to(oa_txt,DOWN)
        oa_txt = Union(*oa_txt).set_fill(opacity=1,color=[RED,WHITE,BLUE]).set_stroke(width=0)
        ob_txt = Union(*ob_txt).set_fill(opacity=1,color=[GREEN,WHITE,BLUE]).set_stroke(width=0)
        self.add(oa_txt,ob_txt)

image

@OdyAsh
Copy link
Author

OdyAsh commented Jan 9, 2025

Thanks for the quick reply!!

Regarding the "pango, not hash" part of your reply ... Is there a way that I can know this in the code?

Let me rephrase my question: what's the internal manim code/class/method/etc. that I have to check , in order to deduce that something is implemented using pango vs hashing?

I'm asking this to know a way for me to mentally-connect future errors like this with the pango/hash issue.

Regarding your actual code snippet workaround, I honestly don't understand how it achieves the same result, but probably that's due to my limited experience in manim (I'm on mobile now so hard to search) ...

Thanks again for the help! 🙌

@uwezi
Copy link
Contributor

uwezi commented Jan 9, 2025

Text() objects are handled by the Python Pango library, and obviously gradient= coloring is handled by this library as well. The resulting rendered outlines of your text are then cached in the media/texts sub-folder of your project. In order to determine if something is cached or not, Manim uses a calculated "hash" from some properties of the Text() object itself - this is used as the filename for the rendered .svg file in the cache. If the file already exists, Manim uses the existing file.

Something similar is done with Tex() and MathTex() objects, which are rendered by the external LaTeX software. Here also the filename of the rendered result is the calculated hash from the Tex() object itself.

Both of these caching methods are not affected by the commandline switch --disable_caching either, probably because it was considered to always be beneficial to use already existing text-objects over re-rendering them every single time.

In my snippet, both oa_txt and ob_txt generate the same hash information, therefore Manim uses the same pre-rendered .svg file for the resulting display, completely ignoring the different coloring. The identity of the object is not in the variable name, but in the actual text it contains (plus font, scaling,...). This you can see in the following slight modification: giving both Text() objects a different font_size= makes them into unique objects:

class SceneTest(Scene):
    def construct(self):
        oa_txt = Text(text="Hello Amazing World!", font="", font_size=30, width=6.5, gradient=[RED, WHITE, BLUE])
        ob_txt = Text(text="Hello Amazing World!", font="", font_size=31, width=6.5, gradient=[GREEN, WHITE, BLUE])
        ob_txt.next_to(oa_txt,DOWN)
        self.add(oa_txt,ob_txt)

image

image

778d2f328f8be69f
396ce2b99f60d1e2

@uwezi
Copy link
Contributor

uwezi commented Jan 9, 2025

Here is the relevant part of the code, generating the unique filename - as you can see all different attributes are considered, but not the color gradient...

image

The fix is actually quite simple, and thanks to the nature of Python you could monkey-patch your own Manim quite easily:

import hashlib
def _text2hash(self, color: ManimColor):
    """Generates ``sha256`` hash for file name."""
    settings = (
        "PANGO" + self.font + self.slant + self.weight + str(color)
    )  # to differentiate Text and CairoText
    settings += str(self.t2f) + str(self.t2s) + str(self.t2w) + str(self.t2c)
    settings += str(self.line_spacing) + str(self._font_size)
    settings += str(self.disable_ligatures)
    settings += str(self.gradient) # add gradient to hashed properties
    id_str = self.text + settings
    hasher = hashlib.sha256()
    hasher.update(id_str.encode())
    return hasher.hexdigest()[:16]
Text._text2hash = _text2hash

class SceneTest3(Scene):
    def construct(self):
        oa_txt = Text(text="Hello Amazing World!", font="", font_size=30, width=6.5, gradient=[RED, WHITE, BLUE])
        ob_txt = Text(text="Hello Amazing World!", font="", font_size=30, width=6.5, gradient=[GREEN, WHITE, BLUE])
        ob_txt.next_to(oa_txt,DOWN)
        self.add(oa_txt,ob_txt)

image

@OdyAsh
Copy link
Author

OdyAsh commented Jan 9, 2025

This was probably the most comprehensive/thorough reply I've received on GitHub 😅

I've understood everything, and have nothing else to say (I was going to suggest adding this final monkey-patch fix to manim's actual codebase, but I think this issue is so obscure no one else will care if it's added or not XD)

Thank you so much for your time/explanations!

@uwezi
Copy link
Contributor

uwezi commented Jan 9, 2025

I agree that this should be added to the code base and I would have done so, if I currently had a development environment on my computer... I hope some of the other developers will pick up this solution, we also should check if there are other attributes which should be included...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants