Repository: ManimCommunity/manim
File: manim/mobject/graph.py (Python)

Code before:
                label_fill_color=label_fill_color,
                vertex_type=vertex_type,
                vertex_config=vertex_config,
                vertex_mobjects=vertex_mobjects,
            )
        ]

    class _AddVerticesAnimation(AnimationGroup):
        def __init__(
            self,
            *args,
            graph: GenericGraph,
            vertex_mobjects: Iterable,
            **kwargs,
        ):
            super().__init__(*args, introducer=True, **kwargs)
            self._vertex_mobjects = vertex_mobjects
            self._graph = graph

        def finish(self):
            super().finish()
            for v in self._vertex_mobjects:
                self.buffer.remove(v[-1])
                vertex = self._graph._add_created_vertex(*v)
                self.buffer.add(vertex)
            self.apply_buffer = True

    @override_animate(add_vertices)
    def _add_vertices_animation(self, *args, anim_args=None, **kwargs):
        if anim_args is None:
            anim_args = {}

        animation = anim_args.pop("animation", Create)

        vertex_mobjects = self._create_vertices(*args, **kwargs)

        return self._AddVerticesAnimation(
            *(animation(v[-1], **anim_args) for v in vertex_mobjects),
            group=self,
            graph=self,
            vertex_mobjects=vertex_mobjects,
        )

    def _remove_vertex(self, vertex):
        """Remove a vertex (as well as all incident edges) from the graph.

        Parameters
        ----------

        vertex
            The identifier of a vertex to be removed.

Review comment (suggestion):
An issue with doing `.buffer.remove()` is that it disbands the original graph, adding its submobjects separately into the scene instead. This seems to cause the issue you described: since the actual graph mobject is no longer in the scene, the vertices we just added into the graph have no reason to continue showing up in the scene after the animation finishes.

I made some tests and it seems to be enough to simply add the new graph again into the scene in order to have it reflect its changes, so let me suggest the following code for `.finish()`:
```suggestion
        def finish(self):
            super().finish()
            for v in self._vertex_mobjects:
                self._graph._add_created_vertex(*v)
            self.buffer.add(self._graph)
```

Notes:
- Although the animation is an introducer (which adds the `_vertex_mobjects` _at the beginning_ of the animation), we currently need to readd the `_graph` _at the end_ of the animation, which is why `self.buffer.add(self._graph)` is needed for that. Not doing that means that the new vertices are added independently as standalone mobjects in the scene (and also the `__repr__()` of the graph now counts the newly added vertices, which is awkward).

- I also suggest removing the `self.apply_buffer = True` line. According to the documentation, the buffer is already applied at the beginning and end of an animation: we only need to set `apply_buffer = True` if we want to add/remove/replace mobjects in the middle of an animation, i.e. inside `interpolate()`. I tested removing it and the animation still works.

Code after:
                label_fill_color=label_fill_color,
                vertex_type=vertex_type,
                vertex_config=vertex_config,
                vertex_mobjects=vertex_mobjects,
            )
        ]

    @override_animate(add_vertices)
    def _add_vertices_animation(
        self,
        *vertices: Hashable,
        anim_args: dict[str, Any] | None = None,
        **kwargs: Any,
    ) -> AnimationGroup:
        vertex_mobjects = self.add_vertices(*vertices, **kwargs)

        base_anim_args = {"animation": Create, "introducer": False}
        if anim_args is not None:
            base_anim_args.update(anim_args)
        animation = base_anim_args.pop("animation")

        return AnimationGroup(
            animation(vertex_mobject, **base_anim_args)
            for vertex_mobject in vertex_mobjects
        )

    def _remove_vertex(self, vertex):
        """Remove a vertex (as well as all incident edges) from the graph.

        Parameters
        ----------

        vertex
            The identifier of a vertex to be removed.

        Returns
        -------

        Group
            A mobject containing all removed objects.

        """
        if vertex not in self.vertices:
            raise ValueError(
                f"The graph does not contain a vertex with identifier '{vertex}'",
            )

        self._graph.remove_node(vertex)
        self._layout.pop(vertex)
        if vertex in self._labels:
            self._labels.pop(vertex)