manim icon indicating copy to clipboard operation
manim copied to clipboard

Hallucinated or dropped edges in Transform of Graph

Open niplav opened this issue 1 year ago • 3 comments

Description of bug / unexpected behavior

When Transforming a Graph into another graph with a different number of edges, the resulting animated graph has the same number of edges as the original graph.

For example, when transforming the graph Graph(["A", "B", "C"], [("A", "B"), ("A", "C")]) to Graph(["A", "B", "C"], [("A", "B"), ("A", "C"), ("B", "C")]), the resulting graph should be a triangle, but one edge is dropped.

Expected behavior

The graph that is the result of a transformation has the number of edges that is specified in the code, not the number of edges the predecessor had.

How to reproduce the issue

Code for reproducing the problem
from manim import *

class BugDemo(Scene):
    def construct(self):
        # Create a graph with two edges
        graph1 = Graph(["A", "B", "C"], [("A", "B"), ("A", "C")])

        # Create another graph with three edges
        graph2 = Graph(["A", "B", "C"], [("A", "B"), ("A", "C"), ("B", "C")])

        # Display the first graph
        self.play(Create(graph1))
        self.wait(1)

        # Attempt to transform graph1 into graph2
        self.play(Transform(graph1, graph2))
        self.wait(1)

Additional media files

Images/GIFs

https://github.com/user-attachments/assets/f54ab219-5e51-4817-beb3-ec9b262329c0

Logs

Terminal output
Manim Community v0.18.1

[10/05/24 20:26:24] DEBUG    Hashing ...                                                                                        hashing.py:352
                    DEBUG    Hashing done in 0.006551 s.                                                                        hashing.py:364
                    DEBUG    Hash generated :  1185818338_2661024192_223132457                                                  hashing.py:367
                    DEBUG    List of the first few animation hashes of the scene: ['1185818338_2661024192_223132457']     cairo_renderer.py:97
                    INFO     Animation 0 : Partial movie file written in                                              scene_file_writer.py:527
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /1185818338_2661024192_223132457.mp4'                                                                            
                    DEBUG    Animation with empty mobject                                                                     animation.py:175
                    DEBUG    Hashing ...                                                                                        hashing.py:352
                    DEBUG    Hashing done in 0.005637 s.                                                                        hashing.py:364
                    DEBUG    Hash generated :  624642324_3890345977_2618601865                                                  hashing.py:367
                    DEBUG    List of the first few animation hashes of the scene: ['1185818338_2661024192_223132457',     cairo_renderer.py:97
                             '624642324_3890345977_2618601865']                                                                               
[10/05/24 20:26:25] INFO     Animation 1 : Partial movie file written in                                              scene_file_writer.py:527
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_3890345977_2618601865.mp4'                                                                            
                    DEBUG    Hashing ...                                                                                        hashing.py:352
                    DEBUG    Hashing done in 0.011324 s.                                                                        hashing.py:364
                    DEBUG    Hash generated :  624642324_2810248401_2118276392                                                  hashing.py:367
                    DEBUG    List of the first few animation hashes of the scene: ['1185818338_2661024192_223132457',     cairo_renderer.py:97
                             '624642324_3890345977_2618601865', '624642324_2810248401_2118276392']                                            
                    INFO     Animation 2 : Partial movie file written in                                              scene_file_writer.py:527
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_2810248401_2118276392.mp4'                                                                            
                    DEBUG    Animation with empty mobject                                                                     animation.py:175
                    DEBUG    Hashing ...                                                                                        hashing.py:352
                    DEBUG    Hashing done in 0.006592 s.                                                                        hashing.py:364
                    DEBUG    Hash generated :  624642324_3890345977_3537993160                                                  hashing.py:367
                    DEBUG    List of the first few animation hashes of the scene: ['1185818338_2661024192_223132457',     cairo_renderer.py:97
                             '624642324_3890345977_2618601865', '624642324_2810248401_2118276392',                                            
                             '624642324_3890345977_3537993160']                                                                               
                    INFO     Animation 3 : Partial movie file written in                                              scene_file_writer.py:527
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_3890345977_3537993160.mp4'                                                                            
                    INFO     Combining to Movie file.                                                                 scene_file_writer.py:617
                    DEBUG    Partial movie files to combine (4 files):                                                scene_file_writer.py:561
                             ['/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDem                         
                             o/1185818338_2661024192_223132457.mp4',                                                                          
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_3890345977_2618601865.mp4',                                                                           
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_2810248401_2118276392.mp4',                                                                           
                             '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/partial_movie_files/BugDemo                         
                             /624642324_3890345977_3537993160.mp4']                                                                           
                    INFO                                                                                              scene_file_writer.py:737
                             File ready at '/home/niplav/proj/site/anim/turning/media/videos/bug/480p15/BugDemo.mp4'                          
                                                                                                                                              
                    INFO     Rendered BugDemo                                                                                     scene.py:247
                             Played 4 animations                                                                                              

System specifications

System Details
  • OS Void Linux:
› uname -a                                                                                                                                                                                                   (manim)
Linux REDACTED 6.6.52_1 #1 SMP PREEMPT_DYNAMIC Sat Sep 21 15:47:36 UTC 2024 x86_64 GNU/Linux
› cat /etc/os-release                                                                                                                                                                                        (manim)
NAME="Void"
ID="void"
PRETTY_NAME="Void Linux"
HOME_URL="https://voidlinux.org/"
DOCUMENTATION_URL="https://docs.voidlinux.org/"
LOGO="void-logo"
ANSI_COLOR="0;38;2;71;128;97"

DISTRIB_ID="void"
  • RAM: 16GB
  • Python version (python/py/python3 --version):
python3 --version                                                                                                                                                                                          (manim)
Python 3.12.5
  • Installed modules (provide output from pip list):
Package              Version
-------------------- -----------
Brotli               1.1.0
build                1.2.1
CacheControl         0.14.0
certifi              2024.7.4
cffi                 1.17.0
charset-normalizer   3.3.2
cleo                 2.1.0
click                8.1.7
click-default-group  1.2.4
cloup                3.0.5
colorama             0.4.6
crashtest            0.4.1
cryptography         43.0.0
decorator            5.1.1
distlib              0.3.8
dulwich              0.21.7
fastjsonschema       2.20.0
filelock             3.15.4
future               1.0.0
glcontext            2.5.0
h2                   4.1.0
hpack                4.0.0
hyperframe           6.0.1
idna                 3.7
importlib_metadata   8.2.0
installer            0.7.0
isosurfaces          0.1.2
jaraco.classes       3.4.0
jeepney              0.8.0
keyring              24.3.1
manim                0.18.1
ManimPango           0.5.0
mapbox_earcut        1.0.1
markdown-it-py       3.0.0
mdurl                0.1.2
moderngl             5.10.0
moderngl-window      2.4.1
more-itertools       10.4.0
msgpack              1.0.8
multipledispatch     0.6.0
networkx             3.3
numpy                1.26.4
packaging            24.1
pexpect              4.9.0
pillow               10.4.0
pip                  24.2
pkginfo              1.11.1
platformdirs         4.2.2
poetry               1.8.3
poetry-core          1.9.0
poetry-plugin-export 1.8.0
ptyprocess           0.7.0
pycairo              1.26.1
pycparser            2.22
pydub                0.25.1
pyglet               1.5.27
Pygments             2.18.0
pyproject_hooks      1.1.0
pyrr                 0.10.3
PySocks              1.7.1
PyYAML               6.0.2
rapidfuzz            3.9.6
requests             2.32.3
requests-toolbelt    1.0.0
rich                 13.7.1
scipy                1.14.0
screeninfo           0.8.1
SecretStorage        3.3.3
setuptools           72.1.0
shellingham          1.5.4
six                  1.16.0
skia-pathops         0.8.0.post1
srt                  3.5.3
svgelements          1.9.6
tomli                2.0.1
tomlkit              0.13.0
tqdm                 4.66.5
trove-classifiers    2024.7.2
typing_extensions    4.12.2
urllib3              2.2.2
virtualenv           20.26.3
watchdog             4.0.1
wheel                0.44.0
zipp                 3.19.2
zstandard            0.23.0

Additional comments

niplav avatar Oct 05 '24 18:10 niplav

After self.play(Transform(graph1, graph2)) you see graph1 left on the screen with 4 dots dots and 2 lines as submobjects. It's rather strange to see. Just print graph1.submobjects out.

Using ReplacementTransform results in graph2 left on the screen with all vertices and edges as expected.

0x13b avatar Oct 08 '24 21:10 0x13b

Yes, but when I tried that with a directed graph I got a different error.

niplav avatar Oct 14 '24 08:10 niplav

* graph1 before: 
  * Family:[Undirected graph on 3 vertices and 2 edges, Dot, Dot, Dot, Line, Line] 
  * sub: [Dot, Dot, Dot, Line, Line]
* graph2 
  * Family: [Undirected graph on 3 vertices and 4 edges, Dot, Dot, Dot, Line, Line, Line, Line] 
  * sub: [Dot, Dot, Dot, Line, Line]
* graph1 after Transform.
  * Family: [Undirected graph on 3 vertices and 2 edges, Dot, Dot, Dot, Dot, Dot, Line, Line] 
  * sub: [Dot, Dot, Dot, Dot, Dot, Line, Line]

Observations:

  • There is some problems with submobject and cloning those in Transform
  • Self-closing graphs seems to produce two lines in in some point and that most likely is the culprit
  • I quess Transform automatic submobject fitting does not like that and fail (end product has two Point models with line- points)
from manim import *
config.disable_caching = True

class BugDemo(Scene):

   def construct(self):
       def break_model(models:Mobject, where, color):
           for i, model in enumerate(models):
               self.play(model.animate.move_to(model.get_center()+where * (i+1)).set_color(color))
       # Create a graph with two edges
       graph1 = Graph(["A", "B", "C"], [("A", "B"), ("A", "C")])
       # Create another graph with three edges
       graph2 = Graph(["A", "B", "C"], [("A", "B"), ("A", "C"), ("B", "C"), ("C", "A")]).move_to(DL*2 +LEFT)

       # Display the first graph
       self.add(graph2)
       self.play(Create(graph1))

       # Attempt to transform graph1 into graph2
       print("graph1 before:", graph1.get_family(),"sub:", graph1.submobjects)
       t_family = graph2.get_family()
       print("target",t_family ,"sub:", graph1.submobjects)
       
       self.play(Transform(graph1, graph2))
       g1_after = graph1.get_family()
       print("after", g1_after,"sub:", graph1.submobjects)
       graph2.clear_updaters()
       graph1.clear_updaters()


       self.play(graph1.animate.move_to(UL*2 +LEFT))
       break_model(t_family[1:], RIGHT, YELLOW)
       break_model(g1_after[1:],  RIGHT, RED)
       self.wait(1)

https://github.com/user-attachments/assets/d74c1327-0c0b-4aa7-b7e6-8ebe00667044

OliverStrait avatar Nov 07 '24 21:11 OliverStrait