Manim:使用Python绘制数学动画

Manim是一个由3Blue1Brown的Grant Sanderson开发的开源框架,用户可以通过编写Python代码来创建数学动画,适用于教学、科研和科普宣传等多个领域。

Manim的核心功能之一是动画效果的创建和控制。它提供了多种动画效果,如创建、变换、淡入淡出等,用户可以通过简单的代码实现复杂的动画效果,此外还支持自定义动画效果,以满足用户的特定需求。

Manim官网:Manim Community

在安装Manim前需要先安装ffmpeg和MikTeX。

ffmpeg下载网址:Download FFmpeg

 MikTeX下载网址:Getting MiKTeX

下载完成后需要配置下Path环境 

 我为Manim使用Anaconda创建了一个3.10版本的Python虚拟环境,随后在虚拟环境中直接安装Manim:

pip install manim

有些时候运行Manim脚本会产生报错,只要在 MikTeX Console 中安装相应的宏包即可

接下来整三段官方教学代码和一段我写的Jumping第一定律教学动画

代码一: 绘制文本

 这里先创建一个BraceAnnotation类,它继承自 Scene 类,这是 Manim 中用于构建动画场景的基础类。随后创建场景construct,将对象添加到场景中即可:

python">from manim import *

class BraceAnnotation(Scene):
    def construct(self):
        dot = Dot([-2, -1, 0])
        dot2 = Dot([2, 1, 0])
        line = Line(dot.get_center(), dot2.get_center()).set_color(ORANGE)
        b1 = Brace(line)
        b1text = b1.get_text("Horizontal distance")
        b2 = Brace(line, direction=line.copy().rotate(PI / 2).get_unit_vector())
        b2text = b2.get_tex("x-x_1")
        self.add(line, dot, dot2, b1, b2, b1text, b2text)

 运行效果如下:

输入命令可以将脚本转换为动画:

python">manim test.py BraceAnnotation # 类名

 脚本运行后,会生成一系列文件夹,在video文件夹中可以找到生成的动画

 代码二:图形动画

这里展示了两个椭圆之间的布尔运算。先创建两个不同颜色的椭圆,并添加了标题文本,接着依次通过动画展示了这两个椭圆的交集、并集、排除和差集,同时为每种运算结果添加了相应的文本标签。

python">from manim import *

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))

代码三:动态展示角度

python">from manim import *

class MovingAngle(Scene):
    def construct(self):
        rotation_center = LEFT

        theta_tracker = ValueTracker(110)
        line1 = Line(LEFT, RIGHT)
        line_moving = Line(LEFT, RIGHT)
        line_ref = line_moving.copy()
        line_moving.rotate(
            theta_tracker.get_value() * DEGREES, about_point=rotation_center
        )
        a = Angle(line1, line_moving, radius=0.5, other_angle=False)
        tex = MathTex(r"\theta").move_to(
            Angle(
                line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False
            ).point_from_proportion(0.5)
        )

        self.add(line1, line_moving, a, tex)
        self.wait()

        line_moving.add_updater(
            lambda x: x.become(line_ref.copy()).rotate(
                theta_tracker.get_value() * DEGREES, about_point=rotation_center
            )
        )

        a.add_updater(
            lambda x: x.become(Angle(line1, line_moving, radius=0.5, other_angle=False))
        )
        tex.add_updater(
            lambda x: x.move_to(
                Angle(
                    line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False
                ).point_from_proportion(0.5)
            )
        )

        self.play(theta_tracker.animate.set_value(40))
        self.play(theta_tracker.animate.increment_value(140))
        self.play(tex.animate.set_color(RED), run_time=0.5)
        self.play(theta_tracker.animate.set_value(350))

代码四:Jumping第一定律

python">from manim import Scene, ImageMobject, ORIGIN, FadeIn, FadeOut, Text, config  
from manim import *  
  
class JumpingLaw(Scene):  
    def construct(self):  
        config.tex_template.add_to_preamble(r'\usepackage[utf8]{inputenc}')  
        config.tex_template.add_to_preamble(r'\usepackage{amsmath}')  
        config.tex_template.add_to_preamble(r'\usepackage{amssymb}')  
        config.tex_template.add_to_preamble(r'\usepackage{unicode-math}')  
        config.tex_template.add_to_preamble(r'\setmainfont{SimHei}')  # 使用黑体字体  
  
        mathematician_image = ImageMobject("jumping.png").scale(1)  
        mathematician_image.move_to(ORIGIN)  
        text = Text("Jumping第一定律").scale(0.75).next_to(mathematician_image, DOWN)  
   
        formula1 = Text("宇宙最终答案 = 42").scale(0.75)  
        formula2 = Text("一周有 7 天").scale(0.75)  
        formula3 = Text("42 ÷ 7 = 6").scale(0.75)  
        formula4 = Text("主 = 6").scale(0.75)  
        formula1.move_to(3 * LEFT + 2 * UP)  
        formula2.move_to(3 * LEFT + UP)  
        formula3.move_to(3 * LEFT)  
        formula4.move_to(3 * LEFT + DOWN)  
  
        self.play(FadeIn(mathematician_image), FadeIn(text))  
        self.wait()  
        self.play(  
            mathematician_image.animate.move_to(np.array([3, 1.5, 0])),  # 用3D坐标,z坐标设为0  
            text.animate.move_to(np.array([3, -2, 0])) 
        )  
        self.wait()  
  
        self.play(FadeIn(formula1))  
        self.wait()  
        self.play(FadeIn(formula2))  
        self.wait()  
        self.play(FadeIn(formula3))  
        self.wait()  
        self.play(FadeIn(formula4))  
        self.wait(2)  
        self.play(  
            FadeOut(mathematician_image),  
            FadeOut(text),  
            FadeOut(formula1),  
            FadeOut(formula2),  
            FadeOut(formula3)  
        )  
        self.wait()  
        formula4.scale(2) 
        formula4.move_to(ORIGIN) 
        self.play(formula4.animate.scale(2).move_to(ORIGIN))  
        self.wait(2) 

运行后效果如下:


http://www.niftyadmin.cn/n/5689282.html

相关文章

69 BERT预训练_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录NLP里的迁移学习Bert的动机Bert架构对输入的修改五、预训练任务1、2、3、 六、1、2、3、 七、1、2、3、 八、1、2、3、 NLP里的迁移学习 之前是使用预训练好的模型来抽取词、句子的特征&#xff0c;例如 word2vec 或语言模型这种非深度学习…

C++《string》

在之前的C语言学习当中我们已经了解了一系列的字符以及字符串函数&#xff0c;虽然这些函数也能实现对字符串进行求长度、拷贝、追加等操作&#xff0c;但是C语言当中的这些函数是与字符串分离的&#xff0c;并且最主要的是在使用这些函数时原字符串的底层空间是需要我们自己来…

代码随想录:105、有向图的完全可达性

105. 有向图的完全可达性 这道题属于简单搜索题&#xff0c;采用bfs即可&#xff0c;也可用dfs但注意要回溯 1、条件准备 graph数组存图&#xff0c;visit数组判断结点是否走过。 #include <bits/stdc.h> #define rep(i, l, r) for (int i l; i < r; i) using na…

leetcode35--搜索插入位置--二分查找刷题

搜索插入位置 一共会出现下面四种情况&#xff1a; 目标值在数组所有元素之前 目标值等于数组中某一个元素 目标值插入数组中的位置 目标值在数组所有元素之后 首先在二分查找的代码之前处理掉目标值在数组所有元素之前和之后的情况如果目标值在数组中的某个位置&#xff0c…

25货拉拉校园招聘面试经验 面试最常见问题总结

货拉拉校园招聘面试经验 目录 【面试经历】 问题+详细答案 面试全流程 【面试经历】 发面经,攒人品。 项目问题: 1.AOP日志落库到数据库,为什么不用一些现成的方案? 2.邀请链接的id怎么用redis生成的? 3.乐观锁保证了奖励的正确发放,请你说说乐观锁的原理。 4.奖…

【BUUCTF N1BOOK】[第一章 web入门]

常见的搜集 这里提示敏感文件 可以想到敏感文件的类型 1.gedit备份文件 格式&#xff1a;filename~ ex.index.php~ 2.vim备份文件 格式&#xff1a;.filename.swap *.swo *.swn ex.index.php.swp 3.robots.txt 可以通过访问每个目录得到flag 也可以使用扫描软件 扫描目录 …

Linux查看触摸坐标点的方法,触觉智能RK3562开发板,瑞芯微、全志等通用

平时遇到键盘、鼠标、触摸板等输入设备无响应等异常情况时&#xff0c;一般通过更换设备判断异常。但在遇到更换正常设备后&#xff0c;输入仍然异常的情况下&#xff0c;可以借助evtest工具查看内核的上报事件信息&#xff0c;协助定位问题所在。 本次使用的是触觉智能EVB356…

win10装机 vs+qt+cuda

1.QT QT插件 Index of /official_releases/vsaddin QT软件 Index of /archive/qt 2. vs vs2019 Visual Studio 2019 生成号和发布日期 | Microsoft Learn vs2022 Visual Studio 2022 IDE - 适用于软件开发人员的编程工具 3.cuda https://developer.nvidia.com/cuda-1…