Replace one mobject in the scene with another, preserving draw order. If ``old_mobject`` is a submobject of some other Mobject (e.g. a :class:`.Group`), the new_mobject will replace it inside the group, without otherwise changing the parent mobject. Parameters
(self, old_mobject: Mobject, new_mobject: Mobject)
| 571 | return self |
| 572 | |
| 573 | def replace(self, old_mobject: Mobject, new_mobject: Mobject) -> None: |
| 574 | """Replace one mobject in the scene with another, preserving draw order. |
| 575 | |
| 576 | If ``old_mobject`` is a submobject of some other Mobject (e.g. a |
| 577 | :class:`.Group`), the new_mobject will replace it inside the group, |
| 578 | without otherwise changing the parent mobject. |
| 579 | |
| 580 | Parameters |
| 581 | ---------- |
| 582 | old_mobject |
| 583 | The mobject to be replaced. Must be present in the scene. |
| 584 | new_mobject |
| 585 | A mobject which must not already be in the scene. |
| 586 | |
| 587 | """ |
| 588 | if old_mobject is None or new_mobject is None: |
| 589 | raise ValueError("Specified mobjects cannot be None") |
| 590 | |
| 591 | def replace_in_list( |
| 592 | mobj_list: list[Mobject], old_m: Mobject, new_m: Mobject |
| 593 | ) -> bool: |
| 594 | # Avoid duplicate references to the same object in self.mobjects |
| 595 | if new_m in mobj_list: |
| 596 | if old_m is new_m: |
| 597 | # In this case, one could say that the old Mobject was already found. |
| 598 | # No replacement is needed, since old_m is new_m, so no action is required. |
| 599 | # This might be unexpected, so raise a warning. |
| 600 | logger.warning( |
| 601 | f"Attempted to replace {type(old_m).__name__} " |
| 602 | "with itself in Scene.mobjects." |
| 603 | ) |
| 604 | return True |
| 605 | mobj_list.remove(new_m) |
| 606 | |
| 607 | # We use breadth-first search because some Mobjects get very deep and |
| 608 | # we expect top-level elements to be the most common targets for replace. |
| 609 | for i in range(0, len(mobj_list)): |
| 610 | # Is this the old mobject? |
| 611 | if mobj_list[i] == old_m: |
| 612 | # If so, write the new object to the same spot and stop looking. |
| 613 | mobj_list[i] = new_m |
| 614 | return True |
| 615 | # Now check all the children of all these mobs. |
| 616 | for mob in mobj_list: # noqa: SIM110 |
| 617 | if replace_in_list(mob.submobjects, old_m, new_m): |
| 618 | # If we found it in a submobject, stop looking. |
| 619 | return True |
| 620 | # If we did not find the mobject in the mobject list or any submobjects, |
| 621 | # (or the list was empty), indicate we did not make the replacement. |
| 622 | return False |
| 623 | |
| 624 | # Make use of short-circuiting conditionals to check mobjects and then |
| 625 | # foreground_mobjects |
| 626 | replaced = replace_in_list( |
| 627 | self.mobjects, old_mobject, new_mobject |
| 628 | ) or replace_in_list(self.foreground_mobjects, old_mobject, new_mobject) |
| 629 | |
| 630 | if not replaced: |
no outgoing calls