Repository: ManimCommunity/manim
File: manim/animation/transform.py (Python)

Code before:
                "Functions passed to ApplyFunction must return object of type Mobject",
            )
        return target


class ApplyMatrix(ApplyPointwiseFunction):
    """Applies a matrix transform to an mobject.

    Parameters
    ----------
    matrix
        The transformation matrix.
    mobject
        The :class:`~.Mobject`.
    about_point
        The origin point for the transform. Defaults to ``ORIGIN``.
    kwargs
        Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`.

    Examples
    --------

    .. manim:: ApplyMatrix
        :quality: low

        class ApplyMatrix(Scene):
            def construct(self):
                matrix = [[1, 2], [3, 4]]
                self.play(ApplyMatrix(matrix, Text("Hello World!")))
    """

    def __init__(
        self,
        matrix: np.ndarray,
        mobject: Mobject,
        about_point: np.ndarray = ORIGIN,
        **kwargs,
    ) -> None:
        matrix = self.initialize_matrix(matrix)

        def func(p):
            return np.dot(p - about_point, matrix.T) + about_point

        super().__init__(func, mobject, **kwargs)

    def initialize_matrix(self, matrix: np.ndarray) -> np.ndarray:
        matrix = np.array(matrix)
        if matrix.shape == (2, 2):
            new_matrix = np.identity(3)
            new_matrix[:2, :2] = matrix
            matrix = new_matrix

Review comment (bug):
Circular reference for `ApplyMatrix` (the scene and the animation have the same name). Causes the docs to fail.
```suggestion
    .. manim:: ApplyMatrixExample
        :quality: low

        class ApplyMatrixExample(Scene):
```

Code after:
        class RestoreExample(Scene):
            def construct(self):
                s = Square()
                s.save_state()
                self.play(FadeIn(s))
                self.play(s.animate.set_color(PURPLE).set_opacity(0.5).shift(2*LEFT).scale(3))
                self.play(s.animate.shift(5*DOWN).rotate(PI/4))
                self.wait()
                self.play(Restore(s), run_time=2)

    """

    def __init__(self, mobject: Mobject, **kwargs) -> None:
        super().__init__(mobject.restore, **kwargs)


class ApplyFunction(Transform):
    def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None:
        self.function = function
        super().__init__(mobject, **kwargs)

    def create_target(self) -> Any:
        target = self.function(self.mobject.copy())
        if not isinstance(target, (Mobject, OpenGLMobject)):
            raise TypeError(
                "Functions passed to ApplyFunction must return object of type Mobject",
            )
        return target


class ApplyMatrix(ApplyPointwiseFunction):
    """Applies a matrix transform to an mobject.

    Parameters
    ----------
    matrix
        The transformation matrix.
    mobject
        The :class:`~.Mobject`.
    about_point
        The origin point for the transform. Defaults to ``ORIGIN``.
    kwargs
        Further keyword arguments that are passed to :class:`ApplyPointwiseFunction`.

    Examples
    --------

    .. manim:: ApplyMatrixExample

        class ApplyMatrixExample(Scene):
            def construct(self):