Skip to content

ReplacementTransform leaves behind a “ghost” mobject when the target is already on‑screen #4238

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

Open
jaroslawjanas opened this issue May 4, 2025 · 1 comment · May be fixed by #4242

Comments

@jaroslawjanas
Copy link

Description of bug / unexpected behavior

After running two consecutive ReplacementTransform calls- first replacing a circle with a square, then that square with a triangle - the original circle and/or square sometimes remain in self.mobjects, resulting in extra, empty shapes (“ghosts”) being rendered alongside the intended transform.

Expected behavior

Only one triangle instance should remain on‑screen after the two ReplacementTransform calls, and self.mobjects should contain exactly that single triangle.

How to reproduce the issue

Code for reproducing the problem
from manim import Scene, Circle, Square, Triangle, ReplacementTransform, FadeIn, MoveAlongPath, Line
from manim.utils.color.manim_colors import PINK, LIGHTER_GRAY, RED
from manim import RIGHT, LEFT, UP

class Test(Scene):
    def construct(self):
        circle = Circle(color=PINK, radius=4, fill_opacity=0).shift(LEFT)
        square = Square(side_length=2, color=LIGHTER_GRAY).shift(UP)
        triangle = Triangle(radius=3, color=RED).shift(RIGHT)

        self.play(FadeIn(circle))
        self.play(FadeIn(square))
        self.play(FadeIn(triangle))
        
        self.play(ReplacementTransform(circle, square))
        self.play(ReplacementTransform(square, triangle))
        triangle.set_fill(RED, opacity=0.5)
        self.wait(2)

        path = Line(RIGHT, LEFT)
        self.play(MoveAlongPath(triangle, path))
        self.wait(2)
        
        # Inspect remaining mobjects
        for obj in self.mobjects:
            print(obj)
Triangle
Square
Triangle
Mobject
Mobject

Additional media files

Images/GIFs
Test.mp4

Logs

Terminal output
(manim) PS D:\Programming\manim-test> manim test.py Test -pql -v DEBUG
Manim Community v0.19.0

[05/04/25 22:19:22] DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.009381 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  1185818338_4190402543_223132457                            hashing.py:367
                    INFO     Animation 0 : Using cached data (hash :                                cairo_renderer.py:89
                             1185818338_4190402543_223132457)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457']
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.009456 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_537848572_4156405120                             hashing.py:367
                    INFO     Animation 1 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_537848572_4156405120)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120']
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.009287 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_2607346297_110000080                             hashing.py:367
                    INFO     Animation 2 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_2607346297_110000080)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080']
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.010183 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_289194527_836597036                              hashing.py:367
                    INFO     Animation 3 : Using cached data (hash : 624642324_289194527_836597036) cairo_renderer.py:89
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080', '624642324_289194527_836597036']
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.008176 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_3194600842_1010701616                            hashing.py:367
                    INFO     Animation 4 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_3194600842_1010701616)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080', '624642324_289194527_836597036',
                             '624642324_3194600842_1010701616']
                    DEBUG    Animation with empty mobject                                               animation.py:190
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.006768 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_2872842549_4071541655                            hashing.py:367
                    INFO     Animation 5 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_2872842549_4071541655)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080', '624642324_289194527_836597036',
                             '624642324_3194600842_1010701616']
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.010292 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_3653221575_1206155369                            hashing.py:367
                    INFO     Animation 6 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_3653221575_1206155369)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080', '624642324_289194527_836597036',
                             '624642324_3194600842_1010701616']
                    DEBUG    Animation with empty mobject                                               animation.py:190
                    DEBUG    Hashing ...                                                                  hashing.py:352
                    DEBUG    Hashing done in 0.008523 s.                                                  hashing.py:364
                    DEBUG    Hash generated :  624642324_2872842549_3178527957                            hashing.py:367
                    INFO     Animation 7 : Using cached data (hash :                                cairo_renderer.py:89
                             624642324_2872842549_3178527957)
                    DEBUG    List of the first few animation hashes of the scene:                   cairo_renderer.py:98
                             ['1185818338_4190402543_223132457', '624642324_537848572_4156405120',
                             '624642324_2607346297_110000080', '624642324_289194527_836597036',
                             '624642324_3194600842_1010701616']
Triangle
Square
Triangle
Mobject
Mobject
                    INFO     Combining to Movie file.                                           scene_file_writer.py:739
                    DEBUG    Partial movie files to combine (8 files):                          scene_file_writer.py:622
                             ['D:\\Programming\\manim-test\\media\\videos\\test\\480p15\\partia
                             l_movie_files\\Test\\1185818338_4190402543_223132457.mp4',
                             'D:\\Programming\\manim-test\\media\\videos\\test\\480p15\\partial
                             _movie_files\\Test\\624642324_537848572_4156405120.mp4',
                             'D:\\Programming\\manim-test\\media\\videos\\test\\480p15\\partial
                             _movie_files\\Test\\624642324_2607346297_110000080.mp4',
                             'D:\\Programming\\manim-test\\media\\videos\\test\\480p15\\partial
                             _movie_files\\Test\\624642324_289194527_836597036.mp4',
                             'D:\\Programming\\manim-test\\media\\videos\\test\\480p15\\partial
                             _movie_files\\Test\\624642324_3194600842_1010701616.mp4']
                    INFO                                                                        scene_file_writer.py:886
                             File ready at
                             'D:\Programming\manim-test\media\videos\test\480p15\Test.mp4'

                    INFO     Rendered Test                                                                  scene.py:255
                             Played 8 animations
[05/04/25 22:19:23] INFO     Previewed File at:                                                          file_ops.py:237
                             'D:\Programming\manim-test\media\videos\test\480p15\Test.mp4'

System specifications

System Details
  • OS: Windows 10 Education (10.0.19045 Build 19045)
  • RAM: 16GB
  • Python version (python/py/python3 --version): 3.12.10
  • Installed modules (conda list):
# Name                    Version                   Build  Channel
_openmp_mutex             4.5                       2_gnu    conda-forge
anyio                     4.9.0              pyh29332c3_0    conda-forge
aom                       3.9.1                he0c23c2_0    conda-forge
av                        13.1.0          py312he67cb50_0    conda-forge
backports                 1.0                pyhd8ed1ab_5    conda-forge
backports.tarfile         1.2.0              pyhd8ed1ab_1    conda-forge
beautifulsoup4            4.13.4             pyha770c72_0    conda-forge
brotli-python             1.1.0           py312h275cf98_2    conda-forge
bzip2                     1.0.8                h2466b09_7    conda-forge
ca-certificates           2025.4.26            h4c7d964_0    conda-forge
cachecontrol              0.14.3             pyha770c72_0    conda-forge
cachecontrol-with-filecache 0.14.3             pyhd8ed1ab_0    conda-forge
cairo                     1.18.4               h5782bbf_0    conda-forge
certifi                   2025.1.31          pyhd8ed1ab_0    conda-forge
cffi                      1.17.1          py312h4389bb4_0    conda-forge
charset-normalizer        3.4.2              pyhd8ed1ab_0    conda-forge
cleo                      2.1.0              pyhd8ed1ab_1    conda-forge
click                     8.1.8              pyh7428d3b_0    conda-forge
cloup                     3.0.7              pyhd8ed1ab_0    conda-forge
colorama                  0.4.6              pyhd8ed1ab_1    conda-forge
crashtest                 0.4.1              pyhd8ed1ab_1    conda-forge
dav1d                     1.2.1                hcfcfb64_0    conda-forge
decorator                 5.2.1              pyhd8ed1ab_0    conda-forge
distlib                   0.3.9              pyhd8ed1ab_1    conda-forge
dulwich                   0.22.8          py312h2615798_0    conda-forge
exceptiongroup            1.2.2              pyhd8ed1ab_1    conda-forge
ffmpeg                    7.1.1           gpl_hc27df84_704    conda-forge
filelock                  3.18.0             pyhd8ed1ab_0    conda-forge
findpython                0.6.3              pyhff2d567_0    conda-forge
font-ttf-dejavu-sans-mono 2.37                 hab24e00_0    conda-forge
font-ttf-inconsolata      3.000                h77eed37_0    conda-forge
font-ttf-source-code-pro  2.038                h77eed37_0    conda-forge
font-ttf-ubuntu           0.83                 h77eed37_3    conda-forge
fontconfig                2.15.0               h765892d_1    conda-forge
fonts-conda-ecosystem     1                             0    conda-forge
fonts-conda-forge         1                             0    conda-forge
freetype                  2.13.3               h57928b3_1    conda-forge
fribidi                   1.0.10               h8d14728_0    conda-forge
gdk-pixbuf                2.42.12              hed59a49_0    conda-forge
glcontext                 3.0.0           py312h275cf98_1    conda-forge
glib                      2.84.1               he8f994d_1    conda-forge
glib-tools                2.84.1               h4394cf3_1    conda-forge
graphite2                 1.3.13            h63175ca_1003    conda-forge
h11                       0.16.0             pyhd8ed1ab_0    conda-forge
h2                        4.2.0              pyhd8ed1ab_0    conda-forge
harfbuzz                  11.1.0               h8796e6f_0    conda-forge
hpack                     4.1.0              pyhd8ed1ab_0    conda-forge
httpcore                  1.0.9              pyh29332c3_0    conda-forge
httpx                     0.28.1             pyhd8ed1ab_0    conda-forge
hyperframe                6.1.0              pyhd8ed1ab_0    conda-forge
icu                       75.1                 he0c23c2_0    conda-forge
idna                      3.10               pyhd8ed1ab_1    conda-forge
importlib-metadata        8.6.1              pyha770c72_0    conda-forge
importlib_resources       6.5.2              pyhd8ed1ab_0    conda-forge
intel-openmp              2024.2.1          h57928b3_1083    conda-forge
isosurfaces               0.1.2              pyhd8ed1ab_0    conda-forge
jaraco.classes            3.4.0              pyhd8ed1ab_2    conda-forge
jaraco.context            6.0.1              pyhd8ed1ab_0    conda-forge
jaraco.functools          4.1.0              pyhd8ed1ab_0    conda-forge
keyring                   25.6.0             pyh7428d3b_0    conda-forge
lame                      3.100             hcfcfb64_1003    conda-forge
lcms2                     2.17                 hbcf6048_0    conda-forge
lerc                      4.0.0                h6470a55_1    conda-forge
libblas                   3.9.0           31_h641d27c_mkl    conda-forge
libcblas                  3.9.0           31_h5e41251_mkl    conda-forge
libdeflate                1.23                 h76ddb4d_0    conda-forge
libexpat                  2.7.0                he0c23c2_0    conda-forge
libffi                    3.4.6                h537db12_1    conda-forge
libfreetype               2.13.3               h57928b3_1    conda-forge
libfreetype6              2.13.3               h0b5ce68_1    conda-forge
libgcc                    14.2.0               h1383e82_2    conda-forge
libgd                     2.3.3               h7208af6_11    conda-forge
libglib                   2.84.1               hbc94333_1    conda-forge
libgomp                   14.2.0               h1383e82_2    conda-forge
libhwloc                  2.11.2          default_ha69328c_1001    conda-forge
libiconv                  1.18                 h135ad9c_1    conda-forge
libintl                   0.22.5               h5728263_3    conda-forge
libintl-devel             0.22.5               h5728263_3    conda-forge
libjpeg-turbo             3.1.0                h2466b09_0    conda-forge
liblapack                 3.9.0           31_h1aa476e_mkl    conda-forge
liblzma                   5.8.1                h2466b09_0    conda-forge
libogg                    1.3.5                h2466b09_1    conda-forge
libopus                   1.5.2                h2466b09_0    conda-forge
libpng                    1.6.47               h7a4582a_0    conda-forge
librsvg                   2.58.4               h5ce5fed_3    conda-forge
libsqlite                 3.49.1               h67fdade_2    conda-forge
libtiff                   4.7.0                h797046b_4    conda-forge
libusb                    1.0.28               h2466b09_0    conda-forge
libvorbis                 1.3.7                h0e60522_0    conda-forge
libwebp-base              1.5.0                h3b0e114_0    conda-forge
libwinpthread             12.0.0.r4.gg4f2fc60ca      h57928b3_9    conda-forge
libxcb                    1.17.0               h0e4246c_0    conda-forge
libxml2                   2.13.7               h442d1da_1    conda-forge
libzlib                   1.3.1                h2466b09_2    conda-forge
manim                     0.19.0             pyh29332c3_0    conda-forge
manimpango                0.6.0           py312hd5ffd92_0    conda-forge
mapbox_earcut             1.0.3           py312hbaa7e33_1    conda-forge
markdown-it-py            3.0.0              pyhd8ed1ab_1    conda-forge
mdurl                     0.1.2              pyhd8ed1ab_1    conda-forge
mkl                       2024.2.2            h66d3029_15    conda-forge
moderngl                  5.11.1          py312h72972c8_0    conda-forge
moderngl-window           3.1.1              pyh29332c3_1    conda-forge
more-itertools            10.7.0             pyhd8ed1ab_0    conda-forge
msgpack-python            1.1.0           py312hd5eb7cc_0    conda-forge
networkx                  3.4.2              pyh267e887_2    conda-forge
numpy                     2.2.5           py312h3150e54_0    conda-forge
openh264                  2.6.0                hb17fa0b_0    conda-forge
openjpeg                  2.5.3                h4d64b90_0    conda-forge
openssl                   3.5.0                ha4e3fda_1    conda-forge
packaging                 25.0               pyh29332c3_1    conda-forge
pango                     1.56.3               h0c53d3b_1    conda-forge
pbs-installer             2025.4.9           pyhd8ed1ab_0    conda-forge
pcre2                     10.45                h99c9b8b_0    conda-forge
pillow                    11.1.0          py312h078707f_0    conda-forge
pip                       25.1.1             pyh8b19718_0    conda-forge
pixman                    0.46.0               had0cd8c_0    conda-forge
pkginfo                   1.12.1.2           pyhd8ed1ab_0    conda-forge
platformdirs              4.3.7              pyh29332c3_0    conda-forge
poetry                    2.1.2              pyh7428d3b_0    conda-forge
poetry-core               2.1.2              pyhd8ed1ab_0    conda-forge
pthread-stubs             0.4               h0e40799_1002    conda-forge
pycairo                   1.28.0          py312h0cc4484_0    conda-forge
pycparser                 2.22               pyh29332c3_1    conda-forge
pydub                     0.25.1             pyhd8ed1ab_1    conda-forge
pyglet                    2.1.6              pyhd8ed1ab_0    conda-forge
pyglm                     2.8.2           py312hd5eb7cc_0    conda-forge
pygments                  2.19.1             pyhd8ed1ab_0    conda-forge
pyproject_hooks           1.2.0              pyhd8ed1ab_1    conda-forge
pysocks                   1.7.1              pyh09c184e_7    conda-forge
python                    3.12.10         h3f84c4b_0_cpython    conda-forge
python-build              1.2.2.post1        pyhff2d567_1    conda-forge
python-fastjsonschema     2.21.1             pyhd8ed1ab_0    conda-forge
python-installer          0.7.0              pyhff2d567_1    conda-forge
python_abi                3.12                    7_cp312    conda-forge
pywin32-ctypes            0.2.3           py312h2e8e312_1    conda-forge
pyyaml                    6.0.2           py312h31fea79_2    conda-forge
rapidfuzz                 3.13.0          py312h275cf98_0    conda-forge
requests                  2.32.3             pyhd8ed1ab_1    conda-forge
requests-toolbelt         1.0.0              pyhd8ed1ab_1    conda-forge
rich                      14.0.0             pyh29332c3_0    conda-forge
scipy                     1.15.2          py312h451d5c4_0    conda-forge
screeninfo                0.8.1           py312h2e8e312_2    conda-forge
sdl2                      2.32.54              he0c23c2_0    conda-forge
sdl3                      3.2.10               he0c23c2_1    conda-forge
setuptools                80.1.0             pyhff2d567_0    conda-forge
shellingham               1.5.4              pyhd8ed1ab_1    conda-forge
skia-pathops              0.8.0.post2     py312hd5eb7cc_0    conda-forge
sniffio                   1.3.1              pyhd8ed1ab_1    conda-forge
soupsieve                 2.5                pyhd8ed1ab_1    conda-forge
srt                       3.5.3           py312h2e8e312_0    conda-forge
svgelements               1.9.6              pyhd8ed1ab_0    conda-forge
svt-av1                   3.0.2                he0c23c2_0    conda-forge
tbb                       2021.13.0            h62715c5_1    conda-forge
tk                        8.6.13               h5226925_1    conda-forge
tomli                     2.2.1              pyhd8ed1ab_1    conda-forge
tomlkit                   0.13.2             pyha770c72_1    conda-forge
tqdm                      4.67.1             pyhd8ed1ab_1    conda-forge
trove-classifiers         2025.5.1.12        pyhd8ed1ab_0    conda-forge
typing-extensions         4.13.2               h0e9735f_0    conda-forge
typing_extensions         4.13.2             pyh29332c3_0    conda-forge
tzdata                    2025b                h78e105d_0    conda-forge
ucrt                      10.0.22621.0         h57928b3_1    conda-forge
urllib3                   2.4.0              pyhd8ed1ab_0    conda-forge
vc                        14.3                h2b53caa_26    conda-forge
vc14_runtime              14.42.34438         hfd919c2_26    conda-forge
virtualenv                20.30.0            pyhd8ed1ab_0    conda-forge
vs2015_runtime            14.42.34438         h7142326_26    conda-forge
watchdog                  6.0.0           py312h2e8e312_0    conda-forge
wheel                     0.45.1             pyhd8ed1ab_1    conda-forge
win_inet_pton             1.1.0              pyh7428d3b_8    conda-forge
x264                      1!164.3095           h8ffe710_2    conda-forge
x265                      3.5                  h2d74725_3    conda-forge
xorg-libice               1.1.2                h0e40799_0    conda-forge
xorg-libsm                1.2.6                h0e40799_0    conda-forge
xorg-libx11               1.8.12               hf48077a_0    conda-forge
xorg-libxau               1.0.12               h0e40799_0    conda-forge
xorg-libxdmcp             1.1.5                h0e40799_0    conda-forge
xorg-libxext              1.3.6                h0e40799_0    conda-forge
xorg-libxpm               3.5.17               h0e40799_1    conda-forge
xorg-libxt                1.3.1                h0e40799_0    conda-forge
yaml                      0.2.5                h8ffe710_2    conda-forge
zipp                      3.21.0             pyhd8ed1ab_1    conda-forge
zstandard                 0.23.0          py312h4389bb4_2    conda-forge
zstd                      1.5.7                hbeecb71_2    conda-forge

Additional comments

Discord help link

Suggestions:

To the best of my knowledge, the issue arises because ReplacementTransform always invokes the scene’s replace logic, which unconditionally inserts the target mobject at the source’s position - even if that target is already present - then removes only the source. This can leave behind a duplicate reference or the original target, producing “ghost” shapes after the animation .

A straightforward remedy would be to adjust ReplacementTransform so that it:

  1. Detects Existing Targets
    Before performing any insertion, check whether target_mobject is already in scene.mobjects.
  2. Skips Redundant Inserts
    If the target is present, only removes the source_mobject from the scene, rather than inserting the target again.
  3. Falls Back Gracefully
    If the target isn’t yet on-screen, proceed with the normal replace behaviour (insert + remove) so nothing else changes.

By doing this, after the transform finishes there will only ever be one instance of the target - no leftover “ghost” copies remain.

@jaroslawjanas
Copy link
Author

@uwezi Hey, can you have a look and check if this is adequately described?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🆕 New
1 participant