Welcome to Manim's documentation!¶

About¶
Manim 是Grant Sanderson (3Blue1Brown) 开发的Python库,旨在制作数学动画. Sanderson最早开发该库用于自己在可汗学院教授微积分等数学课程时使用,现在Manim仍是一个在发展中的项目!如果你看过3Blue1Brown频道的数学视频,一定领略到了Manim的强大,虽然还有很多不完善的地方,但瑕不掩瑜!
本中文文档是本人业余所为,所以不能保证更新的进度.如果你想要提前了解更多,可以参考 Theorem of Beethoven 编写的 英文文档 (但也不完善).另外推荐YouTube频道上的Theorem of Beethoven频道,其专门制作Manim教程,比较系统;Bilibili上有搬运教程,但由于版权问题,就不在这里给出链接.本文档有很多地方也都是参考Theorem of Beethoven的视频资料和文档.
Theorem of Beethoven的 Github 上有很多有趣的projects,可供大家参考!
关于Manim,Bilibili和YouTube上都有很多有趣的资源可供参考与学习,但都比较杂,没有形成社区生态.故本文档参考资料比较杂烩,会在相关之处一一列明,如果侵权了您的权益,请与我联系!
Happy maniming!
Windows¶
本节主要参考 Manim Github 的README.
Manim的安装有两种方式,第一种是安装发布的manimlib,第二种是克隆Github上的repo,在本地直接与repo中的manimlib的文件挂钩进行编译.
个人推荐第二种安装方式,因为发布的manimlib比较老了,有些功能没有更新;其次方便自己二次开发,并与自己fork的repo同步;最后是安装比较简单.这里只介绍第二种安装方式,基于Window系统,其他平台本人不熟悉,故暂不予以详细介绍,请参考Github上的README.
警告
如果你选择直接安装manimlib的话,需要把电脑的编码改成UTF-8(自行百度一下),否则可能会出现一片红的报错,但是这会对一些软件造成影响!
安装Python¶
官网 直接下载安装即可.个人建议安装 Anaconda ,方便一些!
重要
安装Python的时候要把添加到环境变量的选项勾选上.如果安装Anaconda,也要添加到环境变量(一般默认添加).
安装相关的依赖¶
小技巧
使用pip进行安装相关的包时,可以更换为国内的镜像源(自行百度一下)!
安装Cairo¶
这个包是manim的基本图形包,直接通过pip安装会出问题,建议直接手动安装.在 这里 下载对应你的python和操作系统位数版本的Cairo.然后在 cmd
中输入
pip install <Cairo的路径>(比如 C:/path/to/wheel/pycairo‑1.18.0‑cp37‑cp37m‑win32.whl)
重要
如果你安装的是Anaconda,需要先启动Anaconda的环境,在命令行中输入 conda activate <环境名称>
如果省略 环境名称
则默认启动 root
环境.后续的命令行操作也都如此.
安装LaTex¶
如果你没有使用LaTex的话,可以在网上查找相关的资料快速上手.Manim中的文字和数学公式都是通过Latex编译,然后生成SVG图片插入的.推荐下载 MiKTeX ,包管理比较方便.
重要
同样要把相关的路径添加到环境变量,但一般默认会添加.如果编译出现问题再检查一下.
安装Sox¶
Sox是音频处理包.可以直接通过 pip install sox
安装.
克隆repo并安装其他依赖¶
克隆repo¶
在电脑上选个好地方,打开 Git Bash
,输入
git clone https://github.com/3b1b/manim.git
如果你有二次开发的需求,可以先fork再clone.如果你不了解Git的使用,可以参考廖雪峰的 教程.
安装其他Python依赖¶
打开 cmd
命令行,进入到manim repo的本地主目录中,输入
pip install -r requirements.txt
requirement.txt
文件内容如下
argparse==1.4.0
colour==0.1.5
numpy==1.16.4
Pillow==5.2.0
progressbar==2.5
scipy==1.3.0
tqdm==4.24.0
opencv-python==3.4.2.17
pycairo==1.17.1; sys_platform == 'linux'
pycairo>=1.18.1; sys_platform == 'win32'
pydub==0.23.0
pyreadline==2.1; sys_platform == 'win32'
如果你本地已经安装了其中的一些包,但版本高于上面所列的版本号,如果不想降低版本的话,可以把上面的 ==
都改为 >=
,但本人不晓得会不会出现什么问题.你也可以用Anaconda创建一个新的虚拟环境后再安装.
测试¶
在 cmd
中,进入manim的repo本地主目录,输入:
python manim.py example_scenes.py SquareToCircle -pl
python
代表启动python, manim.py
是编译脚本, example_scenes.py
是包含你的动画代码的文件, SquareToCircle
是你要编译的动画类, -pl
是编译选项,后面会有详细介绍.第一和第二个是必不可少的.
如果最后出现动画了,那恭喜你,你已经基本完成了安装!
你也可以选择Live Sreaming模式,但我觉得挺鸡肋的.
> python -m manim --livestream
Writing to media/videos/scene/scene/1080p30/LiveStreamTemp.mp4
Manim is now running in streaming mode. Stream animations by passing
them to manim.play(), e.g.
>>> c = Circle()
>>> manim.play(ShowCreation(c))
>>>
如果你安装的是manimlib库,应该输入
manim my_project.py MyScene
manim
是直接启动manim, my_project.py
就是包含你的动画代码的文件, MyScene
是你要编译的动画类.可以附加编译选项,这里没有加.
再次不推荐你安装manimlib!
FAQ¶
注意
此节不仅包含了安装时出现的问题,也包含了各种其他问题,若暂时没有遇到或不需要则不必要看.
LaTex问题¶
如果你尝试编译 example_scenes.py
中的其他动画类,出现报错 Latex error converting to dvi
的话,那就对了.
LaTex是非常折腾的东西,但如果你熟悉了的话也就那样吧.这里报错最大的问题其实是LaTex的一些宏包没有安装好,而很多MiKTeX宏包安装是连接到国外的服务器.如果你科学上网的话,这里应该不成问题,因为Latex会自动安装缺失的宏包.如果没有的话,因为连接超时下载不到宏包无法正确编译而报错.
解决方案一:科学上网!这是最佳方案,因为可以持续更新宏包!
解决方案二:手动安装或者更换镜像源! 这里 有一些解决方案!
Manim编译需要的LaTex宏包你可以在 /manimlib/tex_template.tex
和 /manimlib/ctex_template.tex
中找到;前者是英文模板,后者是中文模板.怎么使manim支持中文,后面会讲到.
你可以打开电脑中的MiKTeX Console:

选择 Switch to MiKTeX Console administrator mode
进入管理员模式,点击左手边的 Package
.

在上面的方框中输入宏包名称来检查该宏包是否安装.
使LaTex支持更多的Latex宏包/字体¶
参考 Manim fast tutorial - How to add more LaTeX packages?
更改 /manimlib/tex_template.tex
或者 /manimlib/ctex_template.tex
模板即可.但如果你不熟悉LaTex请不要随便更改!
以我的LaTex模板为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /documentclass[preview]{standalone}
/usepackage[english]{babel}
/usepackage{amsmath}
/usepackage{amssymb}
/usepackage{dsfont}
/usepackage{setspace}
/usepackage{tipa}
/usepackage{relsize}
/usepackage{textcomp}
/usepackage{mathrsfs}
/usepackage{wasysym}
/usepackage{ragged2e}
/usepackage{physics}
/usepackage{listings}
/usepackage{xcolor}
% /usepackage{microtype}
%% 字体设置
/usepackage[T1,OT1]{fontenc}
/usepackage{palatino} % english defalut font
/usepackage{calligra} % hand-writing /calligra
/newcommand{/sz}[1]{/fontencoding{OT1}/fontfamily{pplj}/fontseries{m}/selectfont #1} % non-aligned number
/newcommand{/gt}[1]{/fontencoding{OT1}/fontfamily{pgoth}/fontseries{m}/selectfont #1} % Gothic font
%% xelatex font
/usepackage{fontspec}
/usepackage{xeCJK}
/setCJKmainfont[BoldFont={Noto Sans S Chinese}]{Noto Serif CJK SC}
/setCJKmonofont{Noto Serif CJK SC}
/setCJKsansfont{Noto Serif CJK SC SemiBold} % /sf Chinese title font
/setmainfont{Palatino-Roman} % /sf English hand-writing font
/setsansfont{Zapfino}
%% 绘图工具
/usepackage[siunitx,RPvoltages,european]{circuitikz}
/usepackage{tikz}
% /DisableLigatures{encoding = *, family = * }
/linespread{1}
/begin{document}
YourTextHere
/end{document}
|
字体设置 :这里可以自定义字体,不详细展开.
绘图工具 :如果要使Tikz或者CircuiTikz的绘图正确显示,需要更改绘图的填充,否则不能在manim编译的动画中正确显示,因为manim会自动滤除颜色.对于一些LaTex自带的符号也是如此!如果你发现LaTex编译没有问题,那很大程度上的问题就是填充透明度等有问题.
有兴趣的可以尝试一下:
警告
需要在英文模式下,也就是 TEX_USE_CTEX=False
的情况下编译!因为中文情况下的处理会出现问题!
class TikzMobject(TextMobject):
CONFIG = {
"stroke_width": 1,
"fill_opacity": 1,
"stroke_opacity": 1,
}
class ExampleTikz(Scene):
def construct(self):
circuit = TikzMobject(r"""
/begin{circuitikz}[american voltages]
/draw
(0,0) to [short, *-] (6,0)
to [V, l_=$/mathrm{j}{/omega}_m /underline{/psi}^s_R$] (6,2)
to [R, l_=$R_R$] (6,4)
to [short, i_=$/underline{i}^s_R$] (5,4)
(0,0) to [open,v^>=$/underline{u}^s_s$] (0,4)
to [short, *- ,i=$/underline{i}^s_s$] (1,4)
to [R, l=$R_s$] (3,4)
to [L, l=$L_{/sigma}$] (5,4)
to [short, i_=$/underline{i}^s_M$] (5,3)
to [L, l_=$L_M$] (5,0);
/end{circuitikz}
""")
self.play(Write(circuit))
self.wait()

中文支持问题¶
首先要确保你的LaTex能够正常编译!在 manimlib/constants.py
找到 TEX_USE_CTEX
设置为 True
.
如果你的LaTex在英文模式下能够正常编译的话,这里应该问题就不大了.如果出现 xeLatex error converting to dvi
报错,很大程度上还是宏包问题.这里中文使用的是 ctex
宏包,要注意有没有安装.
LaTex实在有很多可以讲的,这一块都能单独写好几本书了,我们放到后面.网上有很多资料和书籍,需要大家多多学习和折腾!
编译过慢问题¶
Manim编译有时候会很慢,如果你的电脑上有GPU的话,那恭喜你!你可用GPU来加速!在你的文件中添加如下代码:
import os
def set_gpus(gpu_index):
if type(gpu_index) == list:
gpu_index = ','.join(str(_) for _ in gpu_index)
if type(gpu_index) ==int:
gpu_index = str(gpu_index)
os.environ["CUDA_VISIBLE_DEVICES"] = gpu_index
然后在你的动画类的 def construct(self):
下面写一行代码: set_gpus(0)
或者 set_gpus([0,1])
如果你是土豪有两块GPU的话!
有了GPU的加持,你会体验到编译速度的飞跃,但对于大规模的计算场景,如多个对象淡出、Update动画等,速度会回归龟速.
编译动态条问题¶
如果你不喜欢编译时的动态条,可以参考 Manim tutorial | Settings - Leave the progress bars by default 去除.
# TODO:完善细节.
如何改变视频输出地址¶
个人不建议更改!默认就好,方便管理. 如果要更改,可以参考 Manim tutorial | Settings - Change media directory 设置.
# TODO:完善细节.
如何在终端中设置输出的帧率¶
参考 Manim tutorial | Settings - Render faster, set FPS via terminal 进行设置.
# TODO:完善细节.
添加声音、SVG和图像¶
参考 Manim tutorial | 7 - Add sounds, svgs and images 进行设置.
添加声音¶
# TODO: 完善细节
添加SVG¶
# TODO: 完善细节
添加图像¶
# TODO: 完善细节
如何改变背景颜色 1¶
class ChangeBackgroundColor(Scene):
CONFIG={
"camera_config":{"background_color":RED}, # 改变背景色
"text":TexMobject(r"/frac{d}{dx}/Bigr|_{y=2}").scale(5)
}
def construct(self):
self.add(self.text)

VS Code配置¶
此节基于Bilibili Up主 pdcxs 的文章: 配置Manim自动编译环境(仅限VS Code Win) 进行改进.
如果你使用的是Visual Studio Code的话,可以配置自动编译,而不需要每一次手动输入 python manim.py example_scenes.py SquareToCircle -pl
这样一长串的代码.
配置tasks.json¶
在工作目录下的 .vscode
中(如果没有就创建一个)创建一个 tasks.json
文件(如果已经有了,直接修改即可).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | {
"version": "2.0.0",
"tasks": [
{
"label": "l",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}\\compile_shell.py",
"${relativeFile}",
"${lineNumber}",
"-pl"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "best",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}\\compile_shell.py",
"${relativeFile}",
"${lineNumber}",
"-p"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "m",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}\\compile_shell.py",
"${relativeFile}",
"${lineNumber}",
"-pm"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "s",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}\\compile_shell.py",
"${relativeFile}",
"${lineNumber}",
"-s"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
"label": "i",
"type": "shell",
"command": "python",
"args": [
"${workspaceFolder}\\compile_shell.py",
"${relativeFile}",
"${lineNumber}",
"-il"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
]
}
|
每一个任务都有一个标签(可以自定义修改),与其任务的输出格式是相对应的;如第 5
行的 l
代表的是低分辨率输出,相应的 第 12
行 -pl
代表低分辨率渲染,并用默认播放器打开;其他任务同理.
l
:低分辨渲染m
:中分辨渲染b
:最高分辨渲染,输出品质i
:输出gif格式s
:低分辨率保存最后一帧
可以自定义添加更多的指令.渲染指令请参考渲染设置.
配置compile_shell.py¶
在主工作目录下,添加 compile_shell.py
文件.这个文件是用于寻找当前要编译的动画类的名称.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import sys
import os
import linecache
file_relative_dir=sys.argv[1]
linenumber=int(sys.argv[2])
setting=sys.argv[3]
while linenumber:
text=linecache.getline(file_relative_dir,linenumber)
if 'class' in text:
escape_index=text.find(' ')
brackets_index=text.find('(')
class_name=text[escape_index:brackets_index]
linecache.clearcache()
break
else:
linenumber-=1
commands=[
'D:\Anaconda3\python.exe', # my anaconda dir -> to replace it with yours
'manim.py',
file_relative_dir,
class_name,
setting
]
os.system(' '.join(commands))
|
第 20-26
行是编译的命令,第 21
行是指定的编译器,由于我的电脑同时安装了Anaconda和Python,为了避免冲突,这里可以自行指定编译器;你需要自行替换一下.如果选择使用默认的Python,把第 21
行改为 python
即可.
这里的机制是在你的鼠标所在行向上搜索类的名称,然后放入命令行进行自动编译.原参考的解决方案是使用Poweshell,这对于非Windows平台是不支持的,这里改成Python脚本.理论上来说,只要能装上VS Code,都能实现这样的自动编译.
编译选项¶
用法¶
对于安装manimlib的情况:
manim [-h] [-p] [-w] [-s] [-l] [-m] [--high_quality] [-g] [-i] [-f]
[-t] [-q] [-a] [-o FILE_NAME] [-n START_AT_ANIMATION_NUMBER]
[-r RESOLUTION] [-c COLOR] [--sound] [--leave_progress_bars]
[--media_dir MEDIA_DIR]
[--video_dir VIDEO_DIR | --video_output_dir VIDEO_OUTPUT_DIR]
[--tex_dir TEX_DIR] [--livestream] [--to-twitch]
[--with-key TWITCH_KEY]
[file] [scene_names [scene_names ...]]
对于克隆repo直接挂钩编译则只需把上面的 manim
改为 python manim.py
就可以了.
选项详解¶
文件参数¶
- file
代码路径
- scene_names
需要编译的代码类
可选参数¶
- -h, --help
显示帮助信息
- -p, --preview
编译完成后自动播放
- -w, --write_to_movie
将场景作为媒体文件渲染为电影文件
- -s, --save_last_frame
输出最后一帧
- -l, --low_quality
低分辨率渲染
- -m, --medium_quality
中分辨率渲染
- --high_quality
高分辨率渲染
- -g, --save_pngs
保存每一帧为png图片
- -i, --save_as_gif
保存为gif图片
- -f, --show_file_in_finder
渲染完成后,打开文件所在文件夹
- -t, --transparent
在透明通道渲染
- -q, --quiet
#TODO
- -a, --write_all
编译文件中的所有动画类
- -o FILE_NAME, --file_name FILE_NAME
重新命名动画类名称
- -n START_AT_ANIMATION_NUMBER, --start_at_animation_number START_AT_ANIMATION_NUMBER
不从第一个动画开始渲染,如果输入两个参数,例如"3,6",就只渲染第3到第6个动画
- -r RESOLUTION, --resolution RESOLUTION
重设分辨率,输入形式为
高度,宽度
- -c COLOR, --color COLOR
设置背景颜色
- --sound
编译成/失败提示音
- --leave_progress_bars
隐藏终端中的编译条
- --media_dir MEDIA_DIR
设置存放媒体文件的目录
- --video_dir VIDEO_DIR
设置存放输出视频的目录
- --video_output_dir VIDEO_OUTPUT_DIR
设置输出视频的目录
- --tex_dir TEX_DIR
设置存放
.tex
文件的目录- --livestream
进入livestream模式
- --to-twitch
#TODO
- --with-key TWITCH_KEY
#TODO
Hello World¶
Manimlib架构¶
.
├── manim.py
├── stage_scenes.py
├── manimlib
│ ├── animation
│ │ ├── animation.py
│ │ ├── composition.py
│ │ ├── creation.py
│ │ ├── fading.py
│ │ ├── growing.py
│ │ ├── indication.py
│ │ ├── movement.py
│ │ ├── numbers.py
│ │ ├── rotation.py
│ │ ├── specialized.py
│ │ ├── transform.py
│ │ └── update.py
│ ├── camera
│ │ ├── camera.py
│ │ ├── mapping_camera.py
│ │ ├── moving_camera.py
│ │ ├── multi_camera.py
│ │ └── three_d_camera.py
│ ├── config.py
│ ├── constants.py
│ ├── container
│ │ └── container.py
│ ├── ctex_template.tex
│ ├── extract_scene.py
│ ├── files
│ │ ├── Bubbles_speech.svg
│ │ ├── Bubbles_thought.svg
│ │ └── PiCreatures_plain.svg
│ ├── for_3b1b_videos
│ │ ├── common_scenes.py
│ │ ├── pi_class.py
│ │ ├── pi_creature_animations.py
│ │ ├── pi_creature.py
│ │ └── pi_creature_scene.py
│ ├── mobject
│ │ ├── changing.py
│ │ ├── coordinate_systems.py
│ │ ├── frame.py
│ │ ├── functions.py
│ │ ├── geometry.py
│ │ ├── matrix.py
│ │ ├── mobject.py
│ │ ├── mobject_update_utils.py
│ │ ├── number_line.py
│ │ ├── numbers.py
│ │ ├── probability.py
│ │ ├── shape_matchers.py
│ │ ├── svg
│ │ │ ├── brace.py
│ │ │ ├── drawings.py
│ │ │ ├── svg_mobject.py
│ │ │ └── tex_mobject.py
│ │ │ └── text_mobject.py
│ │ ├── three_dimensions.py
│ │ ├── three_d_shading_utils.py
│ │ ├── three_d_utils.py
│ │ ├── types
│ │ │ ├── image_mobject.py
│ │ │ ├── point_cloud_mobject.py
│ │ │ └── vectorized_mobject.py
│ │ ├── value_tracker.py
│ │ └── vector_field.py
│ ├── once_useful_constructs
│ │ ├── arithmetic.py
│ │ ├── combinatorics.py
│ │ ├── complex_transformation_scene.py
│ │ ├── counting.py
│ │ ├── fractals.py
│ │ ├── graph_theory.py
│ │ ├── light.py
│ │ ├── matrix_multiplication.py
│ │ ├── NOTE.md
│ │ └── region.py
│ ├── scene
│ │ ├── graph_scene.py
│ │ ├── moving_camera_scene.py
│ │ ├── reconfigurable_scene.py
│ │ ├── sample_space_scene.py
│ │ ├── scene_file_writer.py
│ │ ├── scene_from_video.py
│ │ ├── scene.py
│ │ ├── three_d_scene.py
│ │ ├── vector_space_scene.py
│ │ └── zoomed_scene.py
│ ├── stream_starter.py
│ ├── tex_template.tex
│ └── utils
│ ├── bezier.py
│ ├── color.py
│ ├── config_ops.py
│ ├── file_ops.py
│ ├── images.py
│ ├── iterables.py
│ ├── paths.py
│ ├── rate_functions.py
│ ├── simple_functions.py
│ ├── sounds.py
│ ├── space_ops.py
│ ├── strings.py
│ └── tex_file_writing.py
├── README.md
├── requirements.txt
├── Dockerfile
├── example_scenes.py
└── LICENSE
基于Theorem of Beethoven编写的 Doc 进行修改.
- manim.py
编译启动文件.
- stage_scenes.py
# TODO
- example_scenes.py
示例文件.
- manimlib.config.py
设定编译指令,如输出的分辨率、输出格式、帧率、路径、背景颜色等命令.
- manimlib.stream_starter
Livestream模式的启动设置.
- manimlib.extract_scene.py
场景解析文件,在编译过程中会使用到.
- manimlib.imports.py
模块导入文件.如果你自主开发了一些功能,添加在库中,为了方便调用,你可以在这里文件里面添加相应的模块.
- manimlib.media_dir.txt
媒体文件路径.正常情况下,媒体文件都会储存在你的终端运行的主目录下的
/media
中,你可以自定义修改.- manimlib.tex_template.tex
默认LaTex模板.
- manimlib.ctex_template.tex
使用中文时的LaTex模板.
- manimlib.constants.py
基本参数,将在基本参数中介绍.
基本参数¶
本节主要参考 Constants.
路径¶
当你第一次运行动画编译的时候,终端会出现这样的提示:
Media will be stored in media/. You can change this behavior by writing a different directory to media_dir.txt.
这是因为动画文件会被存放在在 media
路径中,在你终端运行的主目录下,会出现新的文件
.
├── manim.py
├── stage_scenes.py
├── media # <- 新目录
└── manimlib
└── media_dir.txt # <- 新文件
└── scene
└── media_dir.txt # <- 新文件
如果你不更改媒体路径的话,后面不会再出现这个提示.可以通过更改 media_dir.txt
来更改媒体保存路径,这会导致 manimlib/constants.py
第 14
行的改变.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | MEDIA_DIR = ""
VIDEO_DIR = ""
VIDEO_OUTPUT_DIR = ""
TEX_DIR = ""
TEXT_DIR = ""
def initialize_directories(config):
global MEDIA_DIR
global VIDEO_DIR
global VIDEO_OUTPUT_DIR
global TEX_DIR
global TEXT_DIR
video_path_specified = config["video_dir"] or config["video_output_dir"]
if not (video_path_specified and config["tex_dir"]):
if config["media_dir"]:
MEDIA_DIR = config["media_dir"]
else:
MEDIA_DIR = os.path.join(
os.path.expanduser('~'),
"Dropbox (3Blue1Brown)/3Blue1Brown Team Folder"
)
if not os.path.isdir(MEDIA_DIR):
MEDIA_DIR = "./media"
print(
f"Media will be written to {MEDIA_DIR + os.sep}. You can change "
"this behavior with the --media_dir flag."
)
else:
if config["media_dir"]:
print(
"Ignoring --media_dir, since both --tex_dir and a video "
"directory were both passed"
)
TEX_DIR = config["tex_dir"] or os.path.join(MEDIA_DIR, "Tex")
TEXT_DIR = os.path.join(MEDIA_DIR, "texts")
if not video_path_specified:
VIDEO_DIR = os.path.join(MEDIA_DIR, "videos")
VIDEO_OUTPUT_DIR = os.path.join(MEDIA_DIR, "videos")
elif config["video_output_dir"]:
VIDEO_OUTPUT_DIR = config["video_output_dir"]
else:
VIDEO_DIR = config["video_dir"]
for folder in [VIDEO_DIR, VIDEO_OUTPUT_DIR, TEX_DIR, TEXT_DIR]:
if folder != "" and not os.path.exists(folder):
os.makedirs(folder)
|
更多细节请参考 FAQ 2.7.
Text设置¶
Text
类的设置.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | NOT_SETTING_FONT_MSG='''
Warning:
You haven't set font.
If you are not using English, this may cause text rendering problem.
You set font like:
text = Text('your text', font='your font')
or:
class MyText(Text):
CONFIG = {
'font': 'My Font'
}
'''
START_X = 30
START_Y = 20
NORMAL = 'NORMAL'
ITALIC = 'ITALIC'
OBLIQUE = 'OBLIQUE'
BOLD = 'BOLD'
|
LaTex编译设置¶
74 75 76 77 78 79 80 81 82 83 84 85 | TEX_USE_CTEX = True
TEX_TEXT_TO_REPLACE = "YourTextHere"
TEMPLATE_TEX_FILE = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"tex_template.tex" if not TEX_USE_CTEX else "ctex_template.tex"
)
with open(TEMPLATE_TEX_FILE, "r") as infile:
TEMPLATE_TEXT_FILE_BODY = infile.read()
TEMPLATE_TEX_FILE_BODY = TEMPLATE_TEXT_FILE_BODY.replace(
TEX_TEXT_TO_REPLACE,
"\\begin{align*}\n" + TEX_TEXT_TO_REPLACE + "\n\\end{align*}",
)
|
帮助与报错信息¶
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | HELP_MESSAGE = """
Usage:
python extract_scene.py <module> [<scene name>]
-p preview in low quality
-s show and save picture of last frame
-w write result to file [this is default if nothing else is stated]
-o <file_name> write to a different file_name
-l use low quality
-m use medium quality
-a run and save every scene in the script, or all args for the given scene
-q don't print progress
-f when writing to a movie file, export the frames in png sequence
-t use transperency when exporting images
-n specify the number of the animation to start from
-r specify a resolution
-c specify a background color
"""
SCENE_NOT_FOUND_MESSAGE = """
{} is not in the script
"""
CHOOSE_NUMBER_MESSAGE = """
Choose number corresponding to desired scene/arguments.
(Use comma separated list for multiple entries)
Choice(s): """
INVALID_NUMBER_MESSAGE = "Fine then, if you don't want to give a valid number I'll just quit"
NO_SCENE_MESSAGE = """
There are no scenes inside that module
"""
|
分辨率¶
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | # There might be other configuration than pixel shape later...
PRODUCTION_QUALITY_CAMERA_CONFIG = {
"pixel_height": 1440,
"pixel_width": 2560,
"frame_rate": 60,
}
HIGH_QUALITY_CAMERA_CONFIG = {
"pixel_height": 1080,
"pixel_width": 1920,
"frame_rate": 60,
}
MEDIUM_QUALITY_CAMERA_CONFIG = {
"pixel_height": 720,
"pixel_width": 1280,
"frame_rate": 30,
}
LOW_QUALITY_CAMERA_CONFIG = {
"pixel_height": 480,
"pixel_width": 854,
"frame_rate": 15,
}
|
画面尺寸¶
142 143 144 145 146 147 148 149 150 151 152 153 154 | DEFAULT_PIXEL_HEIGHT = PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_height"]
DEFAULT_PIXEL_WIDTH = PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_width"]
DEFAULT_FRAME_RATE = 60
DEFAULT_POINT_DENSITY_2D = 25
DEFAULT_POINT_DENSITY_1D = 250
DEFAULT_STROKE_WIDTH = 4
FRAME_HEIGHT = 8.0
FRAME_WIDTH = FRAME_HEIGHT * DEFAULT_PIXEL_WIDTH / DEFAULT_PIXEL_HEIGHT
FRAME_Y_RADIUS = FRAME_HEIGHT / 2
FRAME_X_RADIUS = FRAME_WIDTH / 2
|
间距¶
156 157 158 159 160 161 162 | SMALL_BUFF = 0.1
MED_SMALL_BUFF = 0.25
MED_LARGE_BUFF = 0.5
LARGE_BUFF = 1
DEFAULT_MOBJECT_TO_EDGE_BUFFER = MED_LARGE_BUFF
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF
|
时间¶
165 166 167 | # All in seconds
DEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0
DEFAULT_WAIT_TIME = 1.0
|
向量¶
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | ORIGIN = np.array((0., 0., 0.))
UP = np.array((0., 1., 0.))
DOWN = np.array((0., -1., 0.))
RIGHT = np.array((1., 0., 0.))
LEFT = np.array((-1., 0., 0.))
IN = np.array((0., 0., -1.))
OUT = np.array((0., 0., 1.))
X_AXIS = np.array((1., 0., 0.))
Y_AXIS = np.array((0., 1., 0.))
Z_AXIS = np.array((0., 0., 1.))
# Useful abbreviations for diagonals
UL = UP + LEFT
UR = UP + RIGHT
DL = DOWN + LEFT
DR = DOWN + RIGHT
TOP = FRAME_Y_RADIUS * UP
BOTTOM = FRAME_Y_RADIUS * DOWN
LEFT_SIDE = FRAME_X_RADIUS * LEFT
RIGHT_SIDE = FRAME_X_RADIUS * RIGHT
|
角度¶
192 193 194 | PI = np.pi
TAU = 2 * PI
DEGREES = TAU / 360
|
颜色¶
颜色盘展示注解
默认 COLOR = COLOR_C
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | # Colors
COLOR_MAP = {
"DARK_BLUE": "#236B8E",
"DARK_BROWN": "#8B4513",
"LIGHT_BROWN": "#CD853F",
"BLUE_E": "#1C758A",
"BLUE_D": "#29ABCA",
"BLUE_C": "#58C4DD",
"BLUE_B": "#9CDCEB",
"BLUE_A": "#C7E9F1",
"TEAL_E": "#49A88F",
"TEAL_D": "#55C1A7",
"TEAL_C": "#5CD0B3",
"TEAL_B": "#76DDC0",
"TEAL_A": "#ACEAD7",
"GREEN_E": "#699C52",
"GREEN_D": "#77B05D",
"GREEN_C": "#83C167",
"GREEN_B": "#A6CF8C",
"GREEN_A": "#C9E2AE",
"YELLOW_E": "#E8C11C",
"YELLOW_D": "#F4D345",
"YELLOW_C": "#FFFF00",
"YELLOW_B": "#FFEA94",
"YELLOW_A": "#FFF1B6",
"GOLD_E": "#C78D46",
"GOLD_D": "#E1A158",
"GOLD_C": "#F0AC5F",
"GOLD_B": "#F9B775",
"GOLD_A": "#F7C797",
"RED_E": "#CF5044",
"RED_D": "#E65A4C",
"RED_C": "#FC6255",
"RED_B": "#FF8080",
"RED_A": "#F7A1A3",
"MAROON_E": "#94424F",
"MAROON_D": "#A24D61",
"MAROON_C": "#C55F73",
"MAROON_B": "#EC92AB",
"MAROON_A": "#ECABC1",
"PURPLE_E": "#644172",
"PURPLE_D": "#715582",
"PURPLE_C": "#9A72AC",
"PURPLE_B": "#B189C6",
"PURPLE_A": "#CAA3E8",
"WHITE": "#FFFFFF",
"BLACK": "#000000",
"LIGHT_GRAY": "#BBBBBB",
"LIGHT_GREY": "#BBBBBB",
"GRAY": "#888888",
"GREY": "#888888",
"DARK_GREY": "#444444",
"DARK_GRAY": "#444444",
"DARKER_GREY": "#222222",
"DARKER_GRAY": "#222222",
"GREY_BROWN": "#736357",
"PINK": "#D147BD",
"LIGHT_PINK": "#DC75CD",
"GREEN_SCREEN": "#00FF00",
"ORANGE": "#FF862F",
}
PALETTE = list(COLOR_MAP.values())
locals().update(COLOR_MAP)
for name in [s for s in list(COLOR_MAP.keys()) if s.endswith("_C")]:
locals()[name.replace("_C", "")] = locals()[name]
|
Mobject¶
-
class
manimlib.mobject.mobject.
Mobject
(**kwargs)¶ 数学对象
-
align_on_border
(direction, buff=0.5)¶ Direction just needs to be a vector pointing towards side or corner in the 2d plane.
-
align_to
(mobject_or_point, direction=array([0.0, 0.0, 0.0]), alignment_vect=array([0.0, 1.0, 0.0]))¶ Examples: mob1.align_to(mob2, UP) moves mob1 vertically so that its top edge lines ups with mob2's top edge.
mob1.align_to(mob2, alignment_vect = RIGHT) moves mob1 horizontally so that it's center is directly above/below the center of mob2
-
become
(mobject, copy_submobjects=True)¶ Edit points, colors and submobjects to be idential to another mobject
-
become_partial
(mobject, a, b)¶ Set points in such a way as to become only part of mobject. Inputs 0 <= a < b <= 1 determine what portion of mobject to become.
-
digest_mobject_attrs
()¶ Ensures all attributes which are mobjects are included in the submobjects list.
-
get_coord
(dim, direction=array([0.0, 0.0, 0.0]))¶ Meant to generalize get_x, get_y, get_z
-
get_critical_point
(direction)¶ Picture a box bounding the mobject. Such a box has 9 'critical points': 4 corners, 4 edge center, the center. This returns one of them.
-
get_point_mobject
(center=None)¶ The simplest mobject to be transformed to or from self. Should by a point of the appropriate type
-
interpolate
(mobject1, mobject2, alpha, path_func=<function straight_path>)¶ Turns self into an interpolation between mobject1 and mobject2.
-
null_point_align
(mobject)¶ If a mobject with points is being aligned to one without, treat both as groups, and push the one with points into its own submobjects list.
-
repeat
(count)¶ This can make transition animations nicer
-
scale
(scale_factor, **kwargs)¶ Default behavior is to scale about the center of the mobject. The argument about_edge can be a vector, indicating which side of the mobject to scale about, e.g., mob.scale(about_edge = RIGHT) scales about mob.get_right().
Otherwise, if about_point is given a value, scaling is done with respect to that point.
-
set_color
(color='#FFFF00', family=True)¶ Condition is function which takes in one arguments, (x, y, z). Here it just recurses to submobjects, but in subclasses this should be further implemented based on the the inner workings of color
-
-
class
manimlib.mobject.mobject.
Group
(*mobjects, **kwargs)¶