manim

Posted on 2022-06-27 00:37  罗芭Remoo  阅读(405)  评论(0编辑  收藏  举报
from manim import *
#导入manim命名空间


#这是一个最基本的manim结构,类名叫做BaseFrame,传入一个场景Scene,并且包含一个construct方法,传入self
class BaseFrame(Scene):
    def construct(self):
        self.wait()


class CreateCircle(Scene):
    def construct(self):
        circle = Circle()  # 创建了一个Circle对象:circle
        circle.set_fill(PINK, opacity=0.5)  # set the color and transparency
        self.play(Create(circle))  # show the circle on screen



class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(PINK, opacity=0.5)  # set color and transparency

        square = Square()  # create a square
        square.rotate(PI / 4)  # rotate a certain amount

        self.play(Create(square))  # animate the creation of the square
        self.play(Transform(square, circle))  # interpolate the square into the circle
        self.play(FadeOut(square))  # fade out animation

class SquareAndCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(PINK, opacity=0.5)  # set the color and transparency

        square = Square()  # create a square
        square.set_fill(BLUE, opacity=0.5)  # set the color and transparency

        square.next_to(circle, RIGHT, buff=0.5)  # set the position
        self.play(Create(circle), Create(square))  # show the shapes on screen

class ThreePar(Scene):
    def construct(self):
        circle = Circle()
        circle.set_fill(RED, opacity=0.6)

        star = Star()
        star.set_fill(BLUE, opacity=0.4)
        
        square = Square()
        square.set_fill(BLUE, opacity=0.5)

        circle.next_to(star, LEFT, buff=0.5)
        square.next_to(star, RIGHT, buff=0.5)

        #占用1秒的时长,
        #如果你的Create方法是在play里面的,他就会占用一秒钟的时间去展示创建对象的过程
        self.add(star)
        self.add(circle)#无意义的,后面的Create(circle)会创建,系统会删除次代码
        self.play(Create(circle),Create(square))
        self.wait(1)
        self.remove(star)
        self.wait(1)

class AnimatedSquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        square = Square()  # create a square

#Play_Scripts_Start
        self.play(Create(square))  # show the square on screen
        self.play(square.animate.rotate(PI / 4))  # 旋转图形,参数是弧度制
        self.play(
            ReplacementTransform(square, circle)
        )  # transform the square into a circle
        self.play(
            circle.animate.set_fill(PINK, opacity=0.5)
        )  # color the circle on screen
#Play_Scripts_End

class DifferentRotations(Scene):
    def construct(self):
        left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT)
        right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT)
        self.play(
            left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2
        )
        self.wait()



#默认情况下,对象会生成在屏幕中心点
class Learn01_move(Scene):
    def construct(self):
        circle = Circle()
        triangle = Triangle()

        self.add(circle,triangle)
        print ("移动")
        self.wait(1)

        circle.shift(LEFT*3 + UP*2)
            #瞬间移动,LEFT,UP是单位方向向量
            #以自身为参考
        self.wait(1)

        triangle.next_to(circle,RIGHT)
            #瞬间移动
            #以传入对象为参考
        self.wait(1)

        circle.move_to(DOWN)
            #瞬间移动
            #以屏幕中心为参考
        self.wait(1)

        triangle.align_to(circle,DOWN)
            #瞬间移动
            #以传入对象的假想边界作为调整
            #传入DOWN(0,-1),那么物体的纵坐标就会"对其"对象的下边界
                #这个假想的边界一般以物体以中心为原点的第二象限区域
        self.wait(1)

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

        circle = Circle().shift(LEFT*2)
        star = Star().shift(RIGHT*2)
        self.play(Create(circle), Create(star))
        self.wait(1)

        #set_fill()  改变图形的内部
        #set_stroke()改变图形的边框
        star.set_stroke(color=YELLOW, width=20)
        circle.set_stroke(color=BLUE, width=20)
        star.set_fill(YELLOW, opacity=0.7)
        circle.set_fill(YELLOW, opacity=0.7)

        
        self.wait(1)
        
class Learn03_animations(Scene):
    def construct(self):
        star = Star()
        self.play(FadeIn(star))#渐入特效
        #self.play(FadeIn(star),run_time = 5)可以设置时间
        self.wait(1)
        self.play(Rotate(star, 2*PI))#旋转特效
        self.wait(1)
        self.play(FadeOut(star))#渐出特效

#animate方法
    #这样就可以
class Learn04_animateMethod(Scene):
    def construct(self):
        star = Star()
        self.play(star.animate.set_fill(YELLOW, opacity=0.4))
        self.wait(1)
        self.play(star.animate.set_fill(WHITE))
        self.wait(1)

        #也可以同时进行animate方法
        self.play(
            star.animate
            .shift(UP+LEFT)
            .rotate(2/3*PI)
            .set_fill(RED)
        )
        self.wait(1)

        #也可以在play中添加run_time参数,修改动画持续时间
        self.play(
            star.animate
            .shift(-UP-LEFT)
            .rotate(2/3*PI)
            .set_fill(BLUE)
            ,run_time = 5
        )
        self.wait(1)


#创建自定义动画
#重写interpolate_mobject()方法
class Countqq(Animation):
    #kwargs是可变参数,此处暂时用不上
    def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs):
        # Pass number as the mobject of the animation
        #这个是构造方法,使用到我们这个Countqq这个类的时候就会自动把参数传入此方法中
        #self在构造的时候不需要传递
        super().__init__(number, **kwargs)
        # Set start and end
        self.start = start
        self.end = end

    def interpolate_mobject(self, alpha: float):
        # Set value of DecimalNumber according to alpha
        #这一行是增长的 这个是manim系统内部调用的,我们就不管他了。
        value = self.start + (alpha * (self.end - self.start)) 
        self.mobject.set_value(value)
class Learn05_CountingScene(Scene):
    def construct(self):
        #创建一个Decimal数字,设置颜色,缩放比
        number = DecimalNumber().set_color(BLUE).scale(5).move_to(LEFT)
        #添加一个定时更新器,ORIGIN相当于[0,0,0],移动到屏幕中心点
        #匿名函数lambda构建方法 lambda XXX:___
        number.add_updater(lambda number: number)

        self.add(number)

        self.wait(1)

        # Play the Count Animation to count from 0 to 314 in 4 seconds
        #Count传入数字范围从0到100,设置持续时间4秒,线性增长
        #play可以传递一个Animation类型的参数,用于动画的播放,参数可设置:run_time,rate_func there_and_back
        self.play(Countqq(number, 0, 100), run_time=4, rate_func=linear)
        
        self.wait(1)

class Learn06_MobjectExample(Scene):
    def construct(self):
        p1= [-1,-1,0]
        p2= [1,-1,0]
        p3= [1,1,0]
        p4= [-1,1,0]
        #append_points()方法是增加节点,连成折线。
            #方法中传入起点与终点的Line的points
        a = Line(p1,p2).append_points(Line(p2,p3).points).append_points(Line(p3,p4).points)
        #寻找线的开头&结尾&重心 get_start get_end get_center
        point_start= a.get_start()
        point_end  = a.get_end()
        point_center = a.get_center()
        #这个self.mobjects[-1]是指上一个add的对象
        #np是numpy的意思,manim中,numpy as np,即数学库
            #UR指的是UP+RIGHT,在边界的右上角
        self.add(Text(f"a.get_start() = {np.round(point_start,2).tolist()}", font_size=24).to_edge(UR).set_color(YELLOW))
        self.add(Text(f"a.get_end() = {np.round(point_end,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(RED))
        self.add(Text(f"a.get_center() = {np.round(point_center,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(BLUE))
        #还可以get各种位置 get_bottom get_center point_from_proportion是线的中点
        self.add(Dot(a.get_start()).set_color(YELLOW).scale(2))
        self.add(Dot(a.get_end()).set_color(RED).scale(2))
        self.add(Dot(a.get_top()).set_color(GREEN_A).scale(2))
        self.add(Dot(a.get_bottom()).set_color(GREEN_D).scale(2))
        self.add(Dot(a.get_center()).set_color(BLUE).scale(2))
        self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))
        self.add(*[Dot(x) for x in a.points])
        self.add(a)

#测试,不用管这里
class Learn07_MobjectTest(Scene):
    def construct(self):
        p1=[-1,-1,0]
        p2=[1,1,0]
        p3=[-1,1,0]

        a =Line(p1,p2).append_points(Line(p2,p3).points)
        self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))
        self.add(*[Dot(x) for x in a.points])
        self.add(a)


class Learn08_Transform(Scene):
    def construct(self):
        #设置摄像机的背景颜色,即屏幕背景
        self.camera.background_color = GREEN_A
        #创建一个正方形
        m1 = Circle().set_color(RED)
        #创建一个矩形,旋转一定角度
        m2 = Rectangle().set_color(RED).rotate(PI/6)
        #转变图形
        self.play(Transform(m1,m2))
        #会直接把m1变成m2的外观,m2不会显示


class Test_Transform(Scene):
    def construct(self):
        #渐变色
        mobj1 = Text(f"早上好,我是?", font_size=93,t2g={'[1:-1]': (RED,GREEN),}).shift(UP*2)
        self.play(FadeIn(mobj1),run_time=1)
        mobj2 = Text(f"傻逼!", font_size=256).next_to(self.mobjects[-1],DOWN).set_color(BLUE)
        self.play(Transform(mobj1,mobj2),run_time=2)

class Learn09_roll(Scene):
    def construct(self):
        self.camera.background_color = WHITE
        m1a = Square().set_color(RED).shift(LEFT)
        m1b = Circle().set_color(RED).shift(LEFT)
        m2a= Square().set_color(BLUE).shift(RIGHT)
        m2b= Circle().set_color(BLUE).shift(RIGHT)

        points = m2a.points
        points = np.roll(points, int(len(points)/4), axis=0)
        m2a.points = points

        self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1)


#隔离分组字串
class Learn10_HelloLaTeX(Scene):
    def construct(self):

        tex = MathTex(
            r"\sum_{i=0}^{n}{\frac{x^n}{n!}}"
        )
        text = Text('指数函数的泰勒展开.',font_size=32,
            t2c={"指数函数": BLUE, "泰勒": ORANGE}).next_to(tex,UP)
        #for x in text:
            #x.set_color(random_color())
            #x.set_color(random_bright_color())
        tex2 = MathTex(
            r"e^x = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots"
            ,substrings_to_isolate="x"#隔离x作为字串,后面就可以单独渲染它的颜色了
        ).next_to(tex,DOWN)
        tex2.set_color_by_tex("x", YELLOW)
        self.add(tex,text,tex2)


#坐标轴的显示
class Learn11_Plane(ThreeDScene):
    def construct(self):
        numberplane = NumberPlane(
        #关于直角坐标的一些相关设置
            #坐标偏移
#x_range The [x_min, x_max, x_step]-10 10 1
#y_range The [y_min, y_max, y_step]-10 10 1
            x_range=[-10,10,1],
            y_range=[-10,10,1],
            #坐标缩放边界,默认是20
            x_length=20,
            y_length=20,
            background_line_style={
                "stroke_color":RED,
                "stroke_width":4,
                "stroke_opacity":0.6
            },
            #坐标密度
            faded_line_ratio=1,

            ).add_coordinates([0,1,2,3],[-1,0,1,2,3])
            #展示部分坐标标签

        self.play(FadeIn(numberplane),run_time=2)
        self.play(FadeOut(numberplane),run_time=1.5)

        #添加默认的坐标轴标签
        numberplane = PolarPlane().add_coordinates()

        self.play(FadeIn(numberplane),run_time=2)
        self.play(FadeOut(numberplane),run_time=1.5)

        #如果要使用3维坐标,则需要使用3d scene
        ax = ThreeDAxes()
        lab = ax.get_z_axis_label(Tex("$z$-label"))
        self.set_camera_orientation(phi=2*PI/5, theta=-PI/5)
        self.add(ax, lab).wait(1)

class Learn12_indication(Scene):
    def construct(self):
        #波浪文字
        testStr = MathTex(r"WaveWavexxxxyyyyzzzz").scale(2)
        #ApplyWave
        self.play(ApplyWave(testStr))
        self.play(ApplyWave(
            testStr,
            direction=RIGHT,
            time_width=0.5,
            amplitude=0.3
        ))
        self.play(ApplyWave(
            testStr,
            rate_func=linear,
            ripples=4
        ))
        #强调,划重点
        self.play(Circumscribe(testStr))
        self.play(Circumscribe(testStr, Circle))
        self.play(Circumscribe(testStr, fade_out=True))
        self.play(Circumscribe(testStr, time_width=2))
        self.play(Circumscribe(testStr, Circle, True))
        #高亮 Indicate
        self.play(Indicate(tex))
        self.wait()
        #放大、摇晃Wiggle
        self.play(Wiggle(tex))
        self.wait()



#实际例子1--Logo图案设计--#mathbb mathscr mathtt
class RemooLogo(Scene):
    def construct(self):
        self.add(NumberPlane())
        self.camera.background_color='#758a99'
        logo_green = "#87c2a5"
        logo_blue = "#525893"
        logo_red = "#e07a5f"
        logo_black = "#343434"
        MT_R = MathTex(r"\mathscr{R}", fill_color=logo_black)\
            .scale(7)\
            .shift(LEFT+UP)
        MT_ee = MathTex(r"\mathtt{E}", fill_color=logo_blue)\
            .scale(4)
        circle0 = Circle(color=GREEN_A, fill_opacity=0.7).shift(RIGHT)
        circle1 = Circle(color=logo_green, fill_opacity=1).shift(RIGHT*2)
        square = Square(color=YELLOW, fill_opacity=1)
        triangle = Triangle(color=logo_red, fill_opacity=1).shift(LEFT)
        logo = VGroup(triangle,square,circle0,circle1,MT_ee,MT_R)#order matters~
        logo.move_to(ORIGIN).scale(2)
        self.add(logo)

#实际例子2--微分、斜率示意
class DyAndDx(Scene):
    def construct(self):
        dot = Dot([-2, -1,0])
        dot2 = Dot([2, 1, 0])
        dot3 = Dot([2,-1,0])
        line = Line(dot.get_center(), dot2.get_center()).set_color(ORANGE)

        #线变成括号{ -- Brace
        b1 = Brace(line)
        b1text = b1.get_tex("x_0+dx")
        b2 = Brace(line, direction=line.copy().rotate(PI / 2).get_unit_vector())
        b2text = b2.get_tex(r"\sqrt{(dx)^2+(dy)^2}")
        b3 = Brace(line,direction=[1,0,0])
        b3text = b3.get_tex("y_0+dy")
        #self.add(line, dot, dot2, b1, b2, b3, b1text, b2text, b3text)
        sets = VGroup( dot, dot2, b1, b2, b3, b1text, b2text, b3text)
        self.play(FadeIn(line,shift=DOWN))
        for mobj in sets:
            self.play(Write(mobj),run_time=0.2)
        self.wait(1)
        
        
#实际例子3--向量-基础
class VectorArrow(Scene):
    def construct(self):
        numberplane = NumberPlane()
        dot = Dot([0,0,0])
        arrow = Arrow([0,0,0],[2,2,0],buff = 0)
        origin_text = Text('(0.0,0.0)').next_to(dot,DOWN+RIGHT)
        tip_text = Text(f'({np.round(arrow.get_vector()[0])},{np.round(arrow.get_vector()[1])})').next_to(arrow,UP+RIGHT)
        self.add(numberplane, dot, arrow, origin_text, tip_text)

#实际例子4-方框文字颜色
class RectangleSelected(Scene):
    def construct(self):
        rectangle = Rectangle(color = RED)
        text=Text("你好,我是remoo\n这里是manim学习笔记",
            t2c={"我是remoo":BLUE,"manim学习笔记":GREEN,},
            line_spacing=2)
        selectText = "remoo"
        print(selectText)
        rectangle.surround(text)
        group1 = VGroup(rectangle,text)
        self.play(Write(text))
        self.play(FadeIn(rectangle))
        self.wait(0.3)
        self.play(ApplyMethod(group1.scale,2))
        self.wait(0.2)
        self.play(ApplyMethod(group1.scale,0.5))
        self.wait(1)

class BooleanDevice(Scene):
    def construct(self):
        circle1 = Circle(
            radius=2,fill_opacity=0.5,color=BLUE,stroke_width=10
        ).move_to(LEFT*2.5)
        circle2 = Circle(
            radius=2,fill_opacity=0.5,color=YELLOW,stroke_width=10
        ).move_to(LEFT*0.5)
        group1 = VGroup(circle1,circle2)
        self.play(GrowFromCenter(group1))
        self.play(group1.animate.shift(LEFT))

        #求交集
        intersection = Intersection(circle1,circle2,color=GREEN,fill_opacity=0.8)
        Text_inter = Text("交集")
        self.play(intersection.animate.scale(0.25).move_to(RIGHT * 5 + UP * 2.5),
            Text_inter.animate.move_to(RIGHT * 3 + UP * 2.5))
            
        #求并集
        union = Union(circle1, circle2, color=ORANGE, fill_opacity=0.8)
        Text_uni = Text("并集")
        self.play(union.animate.scale(0.25).move_to(RIGHT * 5 + UP),
            Text_uni.animate.move_to(RIGHT * 3 + UP))

        #求容斥
        union = Exclusion(circle1, circle2, color=PINK, fill_opacity=0.8)
        Text_uni = Text("容斥")
        self.play(union.animate.scale(0.25).move_to(RIGHT * 5 - UP),
            Text_uni.animate.move_to(RIGHT * 3 - UP))

        #求异
        union = Difference(circle1, circle2, color=RED, fill_opacity=0.8)
        Text_uni = Text("求异")
        self.play(union.animate.scale(0.25).move_to(RIGHT * 5 - UP * 2.5),
            Text_uni.animate.move_to(RIGHT * 3 - UP * 2.5))

class PointMovingOnShapes(Scene):
    def construct(self):
        circle = Circle(radius=1, color=BLUE)
        dot = Dot()
        dot2 = dot.copy().shift(RIGHT)
        self.add(dot)

        line = Line([1, 0, 0], [7, 0, 0])
        self.add(line)

        self.play(GrowFromCenter(circle))
        self.play(Transform(dot, dot2))
        self.play(MoveAlongPath(dot, circle), run_time=2, rate_func=there_and_back)
        self.play(MoveAlongPath(dot, circle), run_time=1, rate_func=linear)
        #根据某一点旋转
        self.play(Rotating(dot, about_point=[4, 0, 0]), run_time=1.5)
        self.wait(1)


class MovingFrameBox(Scene):
    def construct(self):
        text=MathTex(
            "\\frac{d}{dx}f(x)g(x)=","f(x)\\frac{d}{dx}g(x)","+",
            "g(x)\\frac{d}{dx}f(x)"
        )
        self.play(Write(text))
        framebox1 = SurroundingRectangle(text[1], buff = .1)
        framebox2 = SurroundingRectangle(text[3], buff = .1)
        self.play(
            Create(framebox1),
        )
        self.wait()
        self.play(
            ReplacementTransform(framebox1,framebox2),
        )
        self.wait()




class ArrangeSumobjectsExample(Scene):
    def construct(self):
        s= VGroup(*[Dot().shift(i*0.1*RIGHT+UP) for i in range(0,15)])
        s.shift(UP).set_color(BLUE)
        s2= s.copy().set_color(RED)
        s2.arrange_submobjects()
        s2.shift(DOWN)
        self.add(s,s2)



class InvertSumobjectsExample(Scene):
    def construct(self):
        s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])
        s2 = s.copy()
        s2.invert()
        s2.shift(DOWN)
        self.play(Write(s), Write(s2))



class BooleanOperations(Scene):
    def construct(self):
        ellipse1 = Ellipse(
            width=4.0, height=5.0, fill_opacity=0.5, color=BLUE, stroke_width=10
        ).move_to(LEFT)
        ellipse2 = ellipse1.copy().set_color(color=RED).move_to(RIGHT)
        bool_ops_text = MarkupText("<u>Boolean Operation</u>").next_to(ellipse1, UP * 3)
        ellipse_group = Group(bool_ops_text, ellipse1, ellipse2).move_to(LEFT * 3)
        self.play(FadeIn(ellipse_group))

        i = Intersection(ellipse1, ellipse2, color=GREEN, fill_opacity=0.5)
        self.play(i.animate.scale(0.25).move_to(RIGHT * 5 + UP * 2.5))
        intersection_text = Text("Intersection", font_size=23).next_to(i, UP)
        self.play(FadeIn(intersection_text))

        u = Union(ellipse1, ellipse2, color=ORANGE, fill_opacity=0.5)
        union_text = Text("Union", font_size=23)
        self.play(u.animate.scale(0.3).next_to(i, DOWN, buff=union_text.height * 3))
        union_text.next_to(u, UP)
        self.play(FadeIn(union_text))

        e = Exclusion(ellipse1, ellipse2, color=YELLOW, fill_opacity=0.5)
        exclusion_text = Text("Exclusion", font_size=23)
        self.play(e.animate.scale(0.3).next_to(u, DOWN, buff=exclusion_text.height * 3.5))
        exclusion_text.next_to(e, UP)
        self.play(FadeIn(exclusion_text))

        d = Difference(ellipse1, ellipse2, color=PINK, fill_opacity=0.5)
        difference_text = Text("Difference", font_size=23)
        self.play(d.animate.scale(0.3).next_to(u, LEFT, buff=difference_text.height * 3.5))
        difference_text.next_to(d, UP)
        self.play(FadeIn(difference_text))



class SumFuncG_p1(Scene):
    def construct(self):
        P1Group = VGroup()
        axes = Axes(
            x_range=[-1.2, 1.2, .5],
            y_range=[-0.3, 10, 1],
            x_length=10,
            axis_config={"color": GREEN},
            x_axis_config={
                "numbers_to_include": np.arange(-1, 1.2, .5),
                "numbers_with_elongated_ticks": np.arange(-0.3, 3, 1),
            },
        )
        Background_Frame = SurroundingRectangle(axes,color=ORANGE)

        labels = axes.get_axis_labels(x_label="", y_label="")
        Tex01 = MathTex(
            r"\sum_{n=0}^{\infty}\frac{4n^2+4n+3}{2n+1}x^{2n}").shift(UP*1.6)
        S_Tex01 = SurroundingRectangle(Tex01,color=GREEN_A,fill_color=PINK,fill_opacity=0.3)
        self.play(Write(axes),FadeIn(labels),Write(Tex01),FadeIn(S_Tex01),GrowFromCenter(Background_Frame))
        
        #原本是x: (4*n**2+4*n+3)/(2*n+1)*x**(2*n)
        #但是指数增长过快,所以造了个假!!~~(2*n)*x**(2*n)
        sum_func = lambda x: x**(2*n)

        for n in range(1,16):
            text = Text(f"n = {n}")
            sum_graph = axes.plot(
                sum_func,
                discontinuities=[-1.1, 1.1],
                dt=0.0001
            , color=random_bright_color())
            self.add(text)
            self.play(Write(sum_graph),run_time=0.5,rate_func=there_and_back)
            self.remove(text)

        #dot1_axes = Dot(axes.coords_to_point(1, 0))
        #dot2_axes = Dot(axes.coords_to_point(-1, 0))
        line1_graph = axes.get_lines_to_point(axes.c2p(1,10.16))
        line2_graph = axes.get_lines_to_point(axes.c2p(-1,10.17))
        Tex = MathTex(f"\\frac{{4\\cdot{n}^2+4\\cdot{n}+3}}{{2\\cdot{n}+1}}x^{{2\\cdot{n}}}")
        st = SurroundingRectangle(Tex,color=GREEN_A,fill_color=GREEN_C,fill_opacity=0.3)
        self.play(Write(line1_graph),Write(line2_graph),GrowFromCenter(st))


        for n in range(1,20):
            Tex = MathTex(f"\\frac{{4\\cdot{n}^2+4\\cdot{n}+3}}{{2\\cdot{n}+1}}x^{{2\\cdot{n}}}")

            sum_graph = axes.plot(
                sum_func,
                discontinuities=[-1.1, 1.1],
                dt=0.0001
            , color=random_bright_color())
            P1Group.add(sum_graph)
            self.add(Tex,st)
            self.play(Write(sum_graph),run_time=0.2,rate_func=linear)
            self.remove(Tex)
        P1Group.add(Background_Frame,axes,labels,Tex01,S_Tex01,line1_graph,line2_graph,Tex,st)



class SumFuncShow001(Scene):
    def construct(self):
        text01 = Text("今天来看一道2012年数学3的考研题\n颇有技巧~Remoo",t2c={"数学3":RED,"~Remoo":BLUE})
        self.play(Write(text01),run_time=2)
        self.play(text01.animate.shift(LEFT*2+UP*3.2))

        #题目
        Qs01_p1 = Text("求幂级数").align_to(text01,DL).shift(DOWN)
        Tex01 = MathTex(
            r"\sum_{n=0}^{\infty}\frac{4n^2+4n+3}{2n+1}x^{","2n","}").next_to(Qs01_p1,RIGHT)
        Qs01_p2 = Text("的收敛半径与和函数",t2c={"收敛半径":RED,"和函数":RED}).next_to(Tex01,RIGHT)
        group01 = VGroup (Qs01_p1,Tex01,Qs01_p2)
        self.play(GrowFromCenter(group01))
        self.wait(2)
        #此时题目已经展示出来了,需要把废话弄掉。
        text02 = Text("2012数三").scale(0.5).move_to(text01,UL)
        for letter in text02:
            letter.set_color(random_bright_color())
        self.play(Transform(text01,text02),group01.animate.move_to(text01,DL).shift(DOWN*0.4))

        text02 = Text("解:",font_size=84,t2c={"解:":PINK})
        self.play(text02.animate.move_to(group01,DL*2).shift(DOWN))

        #缺奇次幂,直接用比值审敛法

        mk_Rectangle_01 = Rectangle(color=RED, fill_opacity=0)
        mk_Rectangle_01.surround(Tex01[1])
        self.play(FadeOut(mk_Rectangle_01),run_time=0.5)
        for x in range(2):
            self.play(FadeOut(mk_Rectangle_01),run_time=0.5)
            self.play(FadeIn(mk_Rectangle_01),run_time=0.5)

        text03 = Text("由于这里是缺奇次幂,直接用比值审敛法",
            t2c={"比值审敛法":RED,"缺奇次幂":RED,}).next_to(text02,RIGHT)
        self.play(ReplacementTransform(Tex01[1].copy(),text03),FadeOut(mk_Rectangle_01),run_time=1)

        Tex02 = MathTex(
            r"\lim _{n \rightarrow \infty}\frac{\left|\frac{4(n+1)^{2}+4(n+1)+3}{2(n+1)+1} x^{2(n+1)}\right|}{\left|\frac{4 n^{2}+4 n+3}{2 n+1} x^{2 n}\right| } ",r"="
            ,font_size=64)
        self.wait(1)
        Tex02.move_to(ORIGIN)
        self.play(Write(Tex02))
        self.wait(1)

        ##代入比值审敛法公式
        #高亮题目Un部分
        Tex1_temp = Tex01[0][5:18].copy()
        self.add(Tex1_temp)
        for x in range(2):
            self.play(Tex1_temp.animate.set_fill(BLUE),run_time=0.8,rate_func=there_and_back)
        #传给分子
        self.play(ReplacementTransform(Tex1_temp,Tex02[0][6:44]))
        #高亮题目Un部分
        Tex1_temp = Tex01[0][5:18].copy()
        self.add(Tex1_temp)
        for x in range(1):
            self.play(Tex1_temp.animate.set_fill(BLUE),run_time=0.8,rate_func=there_and_back)
        #传给分母
        self.play(ReplacementTransform(Tex1_temp,Tex02[0][45:80]))
        self.wait(1)

        #self.play(Write(Tex02))

        ##式子往左边移动一点
        self.play(Tex02.animate.align_to(text02,LEFT))
        self.wait(1.5)

        ##式子化简
        #高亮化简部分
        Tex1_temp = Tex02[0][6:44].copy()
        Tex2_temp = Tex02[0][45:80].copy()
        self.add(Tex1_temp)
        for x in range(2):
            self.play(
                Tex1_temp.animate.set_fill(BLUE),
                Tex2_temp.animate.set_fill(BLUE),
                run_time=0.4,rate_func=there_and_back)

        ##化简结果展示
        #Tex03放在Tex02的右边
        Tex03 = MathTex(
            r"\lim _{n \rightarrow \infty} \frac{\left|x^{2(n+1)}\right|}{\left|x^{2 n}\right|}", r"=")\
            .next_to(Tex02,RIGHT)
        
        self.play(
            ReplacementTransform(Tex1_temp,Tex03),
            ReplacementTransform(Tex2_temp,Tex03),
            )

        ##把 解:XXX 隐去
        self.play(
            FadeOut(text02),FadeOut(text03),
            Tex02.animate.shift(UP*0.8),Tex03.animate.shift(UP*0.8))

        self.wait(2)

        ##把Tex02隐去,得出收敛半径
        self.play(FadeOut(Tex02),Tex03.animate.align_to(text02,LEFT))


        Tex04 = MathTex(
            r" =\left | x^2 \right | "
            ,font_size=64)\
            .next_to(Tex03,RIGHT).shift(LEFT*0.5)

        self.play(ReplacementTransform(Tex03[1],Tex04))

        self.wait(2)

        Tex05 = MathTex(
            r" =\left | x^2 \right |< 1 "
            ,font_size=64)\
            .next_to(Tex03,RIGHT).shift(LEFT*2)
        self.play(ReplacementTransform(Tex04,Tex05))

        self.wait(2)

        text04 = Text(",于是,收敛半径 R=1 ",t2c={"收敛半径":RED})
        text04.next_to(Tex05,RIGHT)

        self.play(Write(text04))
        
        self.wait(2)


        ##代入端点验算
        text05 = Text("当x = ±1时,",t2c={"±1":RED}).next_to(Tex03,DOWN).shift(DOWN)
        Tex06 = MathTex(r"\pm 1").next_to(Tex03,DOWN).shift(DOWN)
        Tex07 = MathTex(r"\sum_{n=1}^{\infty} \frac{4 n^{2}+4 n+3}{2 n+1}(\pm 1)^{2 n}").next_to(text05,RIGHT)
        Tex07[0][19:21].set_color(RED)


        self.play(Write(text05))
        self.wait(1)
        self.play(Transform(Tex06,Tex01))
        self.play(Transform(Tex06,Tex07))
        #化简
        Tex08 = MathTex(r"=\sum_{n=1}^{\infty} \frac{4 n^{2}+4 n+3}{2 n+1}").next_to(Tex06,RIGHT)
        self.play(Write(Tex08))

        text06 = Text("显然,该级数发散,故收敛域:(-1,1)",t2c={"收敛域:(-1,1)":PINK}).next_to(text05,DOWN).align_to(text05,LEFT).shift(DOWN*0.8)
        self.play(Write(text06))


class SumFuncPart2(Scene):
    def construct(self):
        #题目
        text01 = Text("2012数三").scale(0.5).to_edge(UL)
        for letter in text01:
            letter.set_color(random_bright_color())
        Qs01_p1 = Text("求幂级数").align_to(text01,DL).shift(DOWN)
        Tex01 = MathTex(
            r"\sum_{n=0}^{\infty}\frac{4n^2+4n+3}{2n+1}x^{","2n","}").next_to(Qs01_p1,RIGHT)
        Qs01_p2 = Text("的收敛半径与和函数",t2c={"收敛半径":GREEN,"和函数":RED}).next_to(Tex01,RIGHT)

        group01 = VGroup (Qs01_p1,Tex01,Qs01_p2,text01)
        self.add(group01)

        ##开始求和函数
        Tex02 = MathTex(r"let:s(x)=\sum_{n=0}^{\infty} \frac{4 n^{2}+4 n+3}{2 n+1} x^{2 n} \quad(|x|<1)")\
            .align_to(text01,LEFT)
        Tex03 = MathTex(r"=\sum_{n=0}^{\infty} \frac{(2 n+1)^{2}+2}{2 n+1} x^{2 n}")
        #14 21
        self.play(ReplacementTransform(Tex02[0][14:21]))






        
















#实际例子40--灰阶显示
class GradientImageFromArray(Scene):
    def construct(self):
        n = 256
        imageArray = np.uint8(
            [[i * 256 / n for i in range(0, n)] for _ in range(0, n)]
        )
        image = ImageMobject(imageArray).scale(2)
        image.background_rectangle = SurroundingRectangle(image, GREEN)
        self.add(image, image.background_rectangle)


#MathTex公式在内存中的存储方式!!
class MathTexTest(Scene):
    def construct(self):
        Tex02_p1 = MathTex(
            "\\lim _{n \\rightarrow \\infty}"
            ,font_size=64)
        Tex02_p2 = MathTex(
            r"\lim _{n \rightarrow \infty}\frac{\left|\frac{4(n+1)^{2}+4(n+1)+3}{2(n+1)+1} x^{2(n+1)}\right|}{\left|\frac{4 n^{2}+4 n+3}{2 n+1} x^{2 n}\right|}"
            ,font_size=64)
        self.play(GrowFromCenter(Tex02_p2))
        self.wait(2)
        #for x in range(60):
            #self.play(Tex02_p2[0][x].copy().animate.shift(DOWN*2))
        self.play(Tex02_p2[0][6:44].copy().animate.shift(DOWN*2))





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

        lines1 = MathTex(r'\frac{1}{2}', r'\divisionsymbol', r'\frac{2}{3}')
        lines2 = MathTex(r'2 \divisionsymbol 3')
        lines3 = MathTex(r'\frac{2}{1} \times \frac{1}{3}')

        lines2.move_to(lines1[2], RIGHT)
        lines2.shift(RIGHT)
        lines3.move_to(lines2)
        self.play(Write(lines1))
        self.play(ReplacementTransform(lines1[2], lines2))
        self.wait(1)
        self.play(ReplacementTransform(lines2, lines3))
        self.wait(3)



class SineCurveUnitCircle(Scene):
    # contributed by heejin_park, https://infograph.tistory.com/230
    #remoo注释

    def construct(self):
        self.show_axis()
        self.show_circle()
        self.move_dot_and_draw_curve()
        self.wait()

    def show_axis(self):
        x_start = np.array([-6,0,0])
        x_end = np.array([6,0,0])

        y_start = np.array([-4,-2,0])
        y_end = np.array([-4,2,0])

        x_axis = Line(x_start, x_end)
        y_axis = Line(y_start, y_end)

        self.add(x_axis, y_axis)
        self.add_x_labels()

        self.origin_point = np.array([-4,0,0])
        self.curve_start = np.array([-3,0,0])

    def add_x_labels(self):
        x_labels = [
            MathTex("\pi"), MathTex("2 \pi"),
            MathTex("3 \pi"), MathTex("4 \pi"),
        ]

        for i in range(len(x_labels)):
            x_labels[i].next_to(np.array([-1 + 2*i, 0, 0]), DOWN)
            self.add(x_labels[i])

    def show_circle(self):
        circle = Circle(radius=1)
        circle.move_to(self.origin_point)
        self.add(circle)
        self.circle = circle

    def move_dot_and_draw_curve(self):
        orbit = self.circle
        origin_point = self.origin_point

        dot = Dot(radius=0.08, color=YELLOW)
        dot.move_to(orbit.point_from_proportion(0))
        self.t_offset = 0
        rate = 0.25

        def go_around_circle(mob, dt):
            self.t_offset += (dt * rate)
            # print(self.t_offset)
            mob.move_to(orbit.point_from_proportion(self.t_offset % 1))

        def get_line_to_circle():
            return Line(origin_point, dot.get_center(), color=BLUE)

        def get_line_to_curve():
            x = self.curve_start[0] + self.t_offset * 4
            y = dot.get_center()[1]
            return Line(dot.get_center(), np.array([x,y,0]), color=YELLOW_A, stroke_width=2 )


        self.curve = VGroup()
        self.curve.add(Line(self.curve_start,self.curve_start))
        def get_curve():
            last_line = self.curve[-1]
            x = self.curve_start[0] + self.t_offset * 4
            y = dot.get_center()[1]
            new_line = Line(last_line.get_end(),np.array([x,y,0]), color=YELLOW_D)
            self.curve.add(new_line)

            return self.curve

        dot.add_updater(go_around_circle)

        origin_to_circle_line = always_redraw(get_line_to_circle)
        dot_to_curve_line = always_redraw(get_line_to_curve)
        sine_curve_line = always_redraw(get_curve)

        self.add(dot)
        self.add(orbit, origin_to_circle_line, dot_to_curve_line, sine_curve_line)
        self.wait(8.5)

        dot.remove_updater(go_around_circle)
from manim import *
#导入manim命名空间

#这是一个最基本的manim结构,类名叫做BaseFrame,传入一个场景Scene,并且包含一个construct方法,传入self
class BaseFrame(Scene):
    def construct(self):
        self.wait()


class CreateCircle(Scene):
    def construct(self):
        circle = Circle()  # 创建了一个Circle对象:circle
        circle.set_fill(PINK, opacity=0.5)  # set the color and transparency
        self.play(Create(circle))  # show the circle on screen



class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(PINK, opacity=0.5)  # set color and transparency

        square = Square()  # create a square
        square.rotate(PI / 4)  # rotate a certain amount

        self.play(Create(square))  # animate the creation of the square
        self.play(Transform(square, circle))  # interpolate the square into the circle
        self.play(FadeOut(square))  # fade out animation

class SquareAndCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(PINK, opacity=0.5)  # set the color and transparency

        square = Square()  # create a square
        square.set_fill(BLUE, opacity=0.5)  # set the color and transparency

        square.next_to(circle, RIGHT, buff=0.5)  # set the position
        self.play(Create(circle), Create(square))  # show the shapes on screen

class ThreePar(Scene):
    def construct(self):
        circle = Circle()
        circle.set_fill(RED, opacity=0.6)

        star = Star()
        star.set_fill(BLUE, opacity=0.4)
        
        square = Square()
        square.set_fill(BLUE, opacity=0.5)

        circle.next_to(star, LEFT, buff=0.5)
        square.next_to(star, RIGHT, buff=0.5)

        #占用1秒的时长,
        #如果你的Create方法是在play里面的,他就会占用一秒钟的时间去展示创建对象的过程
        self.add(star)
        self.add(circle)#无意义的,后面的Create(circle)会创建,系统会删除次代码
        self.play(Create(circle),Create(square))
        self.wait(1)
        self.remove(star)
        self.wait(1)

class AnimatedSquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        square = Square()  # create a square

#Play_Scripts_Start
        self.play(Create(square))  # show the square on screen
        self.play(square.animate.rotate(PI / 4))  # 旋转图形,参数是弧度制
        self.play(
            ReplacementTransform(square, circle)
        )  # transform the square into a circle
        self.play(
            circle.animate.set_fill(PINK, opacity=0.5)
        )  # color the circle on screen
#Play_Scripts_End

class DifferentRotations(Scene):
    def construct(self):
        left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT)
        right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT)
        self.play(
            left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2
        )
        self.wait()



#默认情况下,对象会生成在屏幕中心点
class Learn01_move(Scene):
    def construct(self):
        circle = Circle()
        triangle = Triangle()

        self.add(circle,triangle)
        print ("移动")
        self.wait(1)

        circle.shift(LEFT*3 + UP*2)
            #瞬间移动,LEFT,UP是单位方向向量
            #以自身为参考
        self.wait(1)

        triangle.next_to(circle,RIGHT)
            #瞬间移动
            #以传入对象为参考
        self.wait(1)

        circle.move_to(DOWN)
            #瞬间移动
            #以屏幕中心为参考
        self.wait(1)

        triangle.align_to(circle,DOWN)
            #瞬间移动
            #以传入对象的假想边界作为调整
            #传入DOWN(0,-1),那么物体的纵坐标就会"对其"对象的下边界
                #这个假想的边界一般以物体以中心为原点的第二象限区域
        self.wait(1)

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

        circle = Circle().shift(LEFT*2)
        star = Star().shift(RIGHT*2)
        self.play(Create(circle), Create(star))
        self.wait(1)

        #set_fill()  改变图形的内部
        #set_stroke()改变图形的边框
        star.set_stroke(color=YELLOW, width=20)
        circle.set_stroke(color=BLUE, width=20)
        star.set_fill(YELLOW, opacity=0.7)
        circle.set_fill(YELLOW, opacity=0.7)

        
        self.wait(1)
        
class Learn03_animations(Scene):
    def construct(self):
        star = Star()
        self.play(FadeIn(star))#渐入特效
        #self.play(FadeIn(star),run_time = 5)可以设置时间
        self.wait(1)
        self.play(Rotate(star, 2*PI))#旋转特效
        self.wait(1)
        self.play(FadeOut(star))#渐出特效

#animate方法
    #这样就可以
class Learn04_animateMethod(Scene):
    def construct(self):
        star = Star()
        self.play(star.animate.set_fill(YELLOW, opacity=0.4))
        self.wait(1)
        self.play(star.animate.set_fill(WHITE))
        self.wait(1)

        #也可以同时进行animate方法
        self.play(
            star.animate
            .shift(UP+LEFT)
            .rotate(2/3*PI)
            .set_fill(RED)
        )
        self.wait(1)

        #也可以在play中添加run_time参数,修改动画持续时间
        self.play(
            star.animate
            .shift(-UP-LEFT)
            .rotate(2/3*PI)
            .set_fill(BLUE)
            ,run_time = 5
        )
        self.wait(1)


#创建自定义动画
#重写interpolate_mobject()方法
class Countqq(Animation):
    #kwargs是可变参数,此处暂时用不上
    def __init__(self, number: DecimalNumber, start: float, end: float, **kwargs):
        # Pass number as the mobject of the animation
        #这个是构造方法,使用到我们这个Countqq这个类的时候就会自动把参数传入此方法中
        #self在构造的时候不需要传递
        super().__init__(number, **kwargs)
        # Set start and end
        self.start = start
        self.end = end

    def interpolate_mobject(self, alpha: float):
        # Set value of DecimalNumber according to alpha
        #这一行是增长的 这个是manim系统内部调用的,我们就不管他了。
        value = self.start + (alpha * (self.end - self.start)) 
        self.mobject.set_value(value)
class Learn05_CountingScene(Scene):
    def construct(self):
        #创建一个Decimal数字,设置颜色,缩放比
        number = DecimalNumber().set_color(BLUE).scale(5).move_to(LEFT)
        #添加一个定时更新器,ORIGIN相当于[0,0,0],移动到屏幕中心点
        #匿名函数lambda构建方法 lambda XXX:___
        number.add_updater(lambda number: number)

        self.add(number)

        self.wait(1)

        # Play the Count Animation to count from 0 to 314 in 4 seconds
        #Count传入数字范围从0到100,设置持续时间4秒,线性增长
        #play可以传递一个Animation类型的参数,用于动画的播放,参数可设置:run_time,rate_func there_and_back
        self.play(Countqq(number, 0, 100), run_time=4, rate_func=linear)
        
        self.wait(1)

class Learn06_MobjectExample(Scene):
    def construct(self):
        p1= [-1,-1,0]
        p2= [1,-1,0]
        p3= [1,1,0]
        p4= [-1,1,0]
        #append_points()方法是增加节点,连成折线。
            #方法中传入起点与终点的Line的points
        a = Line(p1,p2).append_points(Line(p2,p3).points).append_points(Line(p3,p4).points)
        #寻找线的开头&结尾&重心 get_start get_end get_center
        point_start= a.get_start()
        point_end  = a.get_end()
        point_center = a.get_center()
        #这个self.mobjects[-1]是指上一个add的对象
        #np是numpy的意思,manim中,numpy as np,即数学库
            #UR指的是UP+RIGHT,在边界的右上角
        self.add(Text(f"a.get_start() = {np.round(point_start,2).tolist()}", font_size=24).to_edge(UR).set_color(YELLOW))
        self.add(Text(f"a.get_end() = {np.round(point_end,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(RED))
        self.add(Text(f"a.get_center() = {np.round(point_center,2).tolist()}", font_size=24).next_to(self.mobjects[-1],DOWN).set_color(BLUE))
        #还可以get各种位置 get_bottom get_center point_from_proportion是线的中点
        self.add(Dot(a.get_start()).set_color(YELLOW).scale(2))
        self.add(Dot(a.get_end()).set_color(RED).scale(2))
        self.add(Dot(a.get_top()).set_color(GREEN_A).scale(2))
        self.add(Dot(a.get_bottom()).set_color(GREEN_D).scale(2))
        self.add(Dot(a.get_center()).set_color(BLUE).scale(2))
        self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))
        self.add(*[Dot(x) for x in a.points])
        self.add(a)

#测试,不用管这里
class Learn07_MobjectTest(Scene):
    def construct(self):
        p1=[-1,-1,0]
        p2=[1,1,0]
        p3=[-1,1,0]

        a =Line(p1,p2).append_points(Line(p2,p3).points)
        self.add(Dot(a.point_from_proportion(0.5)).set_color(ORANGE).scale(2))
        self.add(*[Dot(x) for x in a.points])
        self.add(a)


class Learn08_Transform(Scene):
    def construct(self):
        #设置摄像机的背景颜色,即屏幕背景
        self.camera.background_color = GREEN_A
        #创建一个正方形
        m1 = Circle().set_color(RED)
        #创建一个矩形,旋转一定角度
        m2 = Rectangle().set_color(RED).rotate(PI/6)
        #转变图形
        self.play(Transform(m1,m2))
        #会直接把m1变成m2的外观,m2不会显示


class Test_Transform(Scene):
    def construct(self):
        #渐变色
        mobj1 = Text(f"早上好,我是?", font_size=93,t2g={'[1:-1]': (RED,GREEN),}).shift(UP*2)
        self.play(FadeIn(mobj1),run_time=1)
        mobj2 = Text(f"傻逼!", font_size=256).next_to(self.mobjects[-1],DOWN).set_color(BLUE)
        self.play(Transform(mobj1,mobj2),run_time=2)

class Learn09_roll(Scene):
    def construct(self):
        self.camera.background_color = WHITE
        m1a = Square().set_color(RED).shift(LEFT)
        m1b = Circle().set_color(RED).shift(LEFT)
        m2a= Square().set_color(BLUE).shift(RIGHT)
        m2b= Circle().set_color(BLUE).shift(RIGHT)

        points = m2a.points
        points = np.roll(points, int(len(points)/4), axis=0)
        m2a.points = points

        self.play(Transform(m1a,m1b),Transform(m2a,m2b), run_time=1)



class Learn10_HelloLaTeX(Scene):
    def construct(self):
        tex = MathTex(
            r"\sum_{i=1}^{n}{X_i}"
        )
        tex2 = MathTex(
            r"e^x = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots"
            ,substrings_to_isolate="x"#隔离x作为字串,后面就可以单独渲染它的颜色了
        ).next_to(tex,DOWN)
        tex2.set_color_by_tex("x", YELLOW)
        self.add(tex,tex2)