3b1b / manim

Animation engine for explanatory math videos
MIT License
68.01k stars 6.07k forks source link

How can I use three Scenes in one class? #1221

Closed Danny-Xiao closed 4 years ago

Danny-Xiao commented 4 years ago

Watching the tutorial of Theorem Of Beethoven,I knew that I can use "def setup(self):" to use two scenes in one chass.However,when trying to use three scenes in one class,I find it will raise an error:

Traceback (most recent call last): File "D:\Desktop\manim\manimlib\extract_scene.py", line 155, in main scene = SceneClass(**scene_kwargs) File "D:\Desktop\manim\manimlib\scene\scene.py", line 75, in init self.construct() File ".\ThreeDScene.py", line 13, in construct self.add_transformable_mobject(point,func) AttributeError: 'scene' object has no attribute 'add_transformable_mobject'

So is there anything wrong with my script,or it's couldn't be done in theory? 3Scenes.txt

NeoPlato commented 4 years ago

MovingCameraScene has an assert that collides with the others so there's that.

The last scene argument passed which in this case is ThreeDScene dominates the camera class making the other stuff like LinearTransformationScene and MovingCameraScene unusable.

Also, two things:

  1. It's better to learn how to make your own attributes to modify them to what you're making. This means actually learning Python otherwise you stick with the arbitrary decisions of others.

  2. I have tried this out before and it's really annoying. Needing to 3D transform something that isn't compatible with an animation before it e.g moving the camera so I usually opt to make two scenes where the second is a continuation of the first. Obvious disadvantage here is having to follow up results of animations in the second scene by copy pasting code.

Also, UpdateFromAlphaFunc does a better and less traumatizing job than a value tracker. I used it in my version of your code but I realized you were transforming the thing into an ellipse so I just made that happen. There's also other tricks you can find there such as defining class methods for specific scenes and using them kind of like functions which is more of a Python thing than a Manim thing.

Lastly, please use slightly deeper indentation. Makes code more readable.

class ExtractScene(MovingCameraScene):
    CONFIG = {
        "have_basis_vectors" : True 
    }
    def setup(self):
        MovingCameraScene.setup(self)
        self.add(
            NumberPlane(
                x_min = -10,
                x_max = 10,
                y_min = -7,
                y_max = 7
            )
        )
        if self.have_basis_vectors:
            self.add(
                self.get_basis_vectors())

    def construct(self):
        point = Dot(
            point = UP,
            color = YELLOW,
        )
        func = Circle(
            radius = 1,
            color = ORANGE,
            stroke_width = 2
        )
        self.play(
            ShowCreation(point),
            ShowCreation(func),
            run_time = 3
        )
        self.wait()
        matrix = np.array([[0, 1],[1, 0]]) 
        self.apply_matrix(
            matrix,
            run_time=3
        )
        self.wait()
        self.camera_frame.save_state()
        self.play(
            self.camera_frame.set_height, point.radius * 2 * 1.5,
            self.camera_frame.move_to, point.get_center(), 
            run_time = 3
        )
        self.wait(3)
        self.play(
            Restore(self.camera_frame) 
        )
        self.wait()
        self.play(
            self.turn_into_ellipse(func, 5),
            rate_func = there_and_back,
            run_time = 6
        )

    def get_basis_vectors(self):
        return VGroup(*[
            Vector(
                vect,
                color=color,
                stroke_width=6
            )
            for vect, color in [
                ([1, 0], RED),
                ([0, 1], GREEN)
            ]
        ])

    def apply_matrix(self, matrix, **kwargs):
        proper = matrix
        anims = [ApplyMatrix(
                matrix.T, mobject)
               for mobject in self.mobjects]
        self.play(*anims, **kwargs)

    def turn_into_ellipse(self, circle, new_width):
        anim = ApplyMatrix(
            matrix = np.array([[new_width, 0], [0,1]]),
            mobject = circle
        )
        return anim

class ExtractScene2(ThreeDScene):
    CONFIG = {
        "have_basis_vectors" : True
    }

    def setup(self):
        ThreeDScene.setup(self)
        self.add(
            NumberPlane(
                x_min = -10,
                x_max = 10,
                y_min = -7,
                y_max = 7
            )
        )
        if self.have_basis_vectors:
            self.add(
                self.get_basis_vectors())
        point = Dot(
            point = UP,
            color = YELLOW,
        )
        self.add(point)
        matrix = np.array([[0, 1],[1, 0]])
        for mob in self.get_mobjects():
            ApplyMatrix(matrix, mob)

    def construct(self):     
        func = Circle(
            radius = 1,
            color = ORANGE,
            stroke_width = 2
        )
        self.add(func)
        self.move_camera(
            phi = 75 * DEGREES,
            theta = -55 * DEGREES,
            run_time = 3
        )
        sph = Sphere(radius = 1)
        self.begin_ambient_camera_rotation(0.5) 
        self.play(
            ReplacementTransform(func, sph),
            run_time = 3
        )
        self.wait(4)
        self.play(*[FadeOut(mob) for mob in self.mobjects])

    def get_basis_vectors(self):
        return VGroup(*[
            Vector(
                vect,
                color=color,
                stroke_width=6
            )
            for vect, color in [
                ([1, 0], RED),
                ([0, 1], GREEN)
            ]
        ])

    def apply_matrix(self, matrix, **kwargs):
        anims = [ApplyMatrix(
                matrix.T, mobject)
               for mobject in self.mobjects]
        self.play(*anims, **kwargs)

If you want something done in Manim you do it yourself

  • Someone with a lot of PTSD working with Manim

Oh try this link. See if the video can load

Danny-Xiao commented 4 years ago

MovingCameraScene has an assert that collides with the others so there's that.

The last scene argument passed which in this case is ThreeDScene dominates the camera class making the other stuff like LinearTransformationScene and MovingCameraScene unusable.

Also, two things:

  1. It's better to learn how to make your own attributes to modify them to what you're making. This means actually learning Python otherwise you stick with the arbitrary decisions of others.
  2. I have tried this out before and it's really annoying. Needing to 3D transform something that isn't compatible with an animation before it e.g moving the camera so I usually opt to make two scenes where the second is a continuation of the first. Obvious disadvantage here is having to follow up results of animations in the second scene by copy pasting code.

Also, UpdateFromAlphaFunc does a better and less traumatizing job than a value tracker. I used it in my version of your code but I realized you were transforming the thing into an ellipse so I just made that happen. There's also other tricks you can find there such as defining class methods for specific scenes and using them kind of like functions which is more of a Python thing than a Manim thing.

Lastly, please use slightly deeper indentation. Makes code more readable.

class ExtractScene(MovingCameraScene):
    CONFIG = {
        "have_basis_vectors" : True 
    }
    def setup(self):
        MovingCameraScene.setup(self)
        self.add(
            NumberPlane(
                x_min = -10,
                x_max = 10,
                y_min = -7,
                y_max = 7
            )
        )
        if self.have_basis_vectors:
            self.add(
                self.get_basis_vectors())

    def construct(self):
        point = Dot(
            point = UP,
            color = YELLOW,
        )
        func = Circle(
            radius = 1,
            color = ORANGE,
            stroke_width = 2
        )
        self.play(
            ShowCreation(point),
            ShowCreation(func),
            run_time = 3
        )
        self.wait()
        matrix = np.array([[0, 1],[1, 0]]) 
        self.apply_matrix(
            matrix,
            run_time=3
        )
        self.wait()
        self.camera_frame.save_state()
        self.play(
            self.camera_frame.set_height, point.radius * 2 * 1.5,
            self.camera_frame.move_to, point.get_center(), 
            run_time = 3
        )
        self.wait(3)
        self.play(
            Restore(self.camera_frame) 
        )
        self.wait()
        self.play(
            self.turn_into_ellipse(func, 5),
            rate_func = there_and_back,
            run_time = 6
        )

    def get_basis_vectors(self):
        return VGroup(*[
            Vector(
                vect,
                color=color,
                stroke_width=6
            )
            for vect, color in [
                ([1, 0], RED),
                ([0, 1], GREEN)
            ]
        ])

    def apply_matrix(self, matrix, **kwargs):
        proper = matrix
        anims = [ApplyMatrix(
                matrix.T, mobject)
               for mobject in self.mobjects]
        self.play(*anims, **kwargs)

    def turn_into_ellipse(self, circle, new_width):
        anim = ApplyMatrix(
            matrix = np.array([[new_width, 0], [0,1]]),
            mobject = circle
        )
        return anim

class ExtractScene2(ThreeDScene):
    CONFIG = {
        "have_basis_vectors" : True
    }

    def setup(self):
        ThreeDScene.setup(self)
        self.add(
            NumberPlane(
                x_min = -10,
                x_max = 10,
                y_min = -7,
                y_max = 7
            )
        )
        if self.have_basis_vectors:
            self.add(
                self.get_basis_vectors())
        point = Dot(
            point = UP,
            color = YELLOW,
        )
        self.add(point)
        matrix = np.array([[0, 1],[1, 0]])
        for mob in self.get_mobjects():
            ApplyMatrix(matrix, mob)

    def construct(self):     
        func = Circle(
            radius = 1,
            color = ORANGE,
            stroke_width = 2
        )
        self.add(func)
        self.move_camera(
            phi = 75 * DEGREES,
            theta = -55 * DEGREES,
            run_time = 3
        )
        sph = Sphere(radius = 1)
        self.begin_ambient_camera_rotation(0.5) 
        self.play(
            ReplacementTransform(func, sph),
            run_time = 3
        )
        self.wait(4)
        self.play(*[FadeOut(mob) for mob in self.mobjects])

    def get_basis_vectors(self):
        return VGroup(*[
            Vector(
                vect,
                color=color,
                stroke_width=6
            )
            for vect, color in [
                ([1, 0], RED),
                ([0, 1], GREEN)
            ]
        ])

    def apply_matrix(self, matrix, **kwargs):
        anims = [ApplyMatrix(
                matrix.T, mobject)
               for mobject in self.mobjects]
        self.play(*anims, **kwargs)

If you want something done in Manim you do it yourself

  • Someone with a lot of PTSD working with Manim

Thanks for your help and advice,well appreciated.I'll try to learn writing attributes myself as you suggested.