mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Merge remote-tracking branch 'upstream/master' into shaders
This commit is contained in:
commit
1f6e911d60
469 changed files with 10334 additions and 298791 deletions
14
.github/ISSUE_TEMPLATE.md
vendored
14
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,14 +0,0 @@
|
|||
### If this is a support request:
|
||||
|
||||
**Please attempt to solve the problem on your own before opening an issue.**
|
||||
Between old issues, StackOverflow, and Google, you should be able to find
|
||||
solutions to most of the common problems.
|
||||
|
||||
Include at least:
|
||||
1. Steps to reproduce the issue (e.g. the command you ran)
|
||||
2. The unexpected behavior that occurred (e.g. error messages or screenshots)
|
||||
3. The environment (e.g. operating system and version of manim)
|
||||
|
||||
|
||||
### If this is a feature request:
|
||||
Include the motivation for making this change.
|
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the bug
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**Code**:
|
||||
<!-- The code you run which reflect the bug. -->
|
||||
|
||||
**Wrong display or Error traceback**:
|
||||
<!-- the wrong display result of the code you run, or the error Traceback -->
|
||||
|
||||
### Additional context
|
||||
<!-- Add any other context about the problem here. -->
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ask A Question
|
||||
url: https://github.com/3b1b/manim/discussions/categories/q-a
|
||||
about: Please ask questions you encountered here.
|
23
.github/ISSUE_TEMPLATE/error-when-using.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/error-when-using.md
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
name: Error when using
|
||||
about: The error you encountered while using manim
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the error
|
||||
<!-- A clear and concise description of what you want to make. -->
|
||||
|
||||
### Code and Error
|
||||
**Code**:
|
||||
<!-- The code you run -->
|
||||
|
||||
**Error**:
|
||||
<!-- The error traceback you get when run your code -->
|
||||
|
||||
### Environment
|
||||
**OS System**:
|
||||
**manim version**: master <!-- make sure you are using the latest version of master branch -->
|
||||
**python version**:
|
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,9 +1,18 @@
|
|||
Thanks for contributing to manim!
|
||||
<!-- Thanks for contributing to manim!
|
||||
Please ensure that your pull request works with the latest version of manim.
|
||||
-->
|
||||
|
||||
**Please ensure that your pull request works with the latest version of manim.**
|
||||
You should also include:
|
||||
## Motivation
|
||||
<!-- Outline your motivation: In what way do your changes improve the library? -->
|
||||
|
||||
1. The motivation for making this change (or link the relevant issues)
|
||||
2. How you tested the new behavior (e.g. a minimal working example, before/after
|
||||
screenshots, gifs, commands, etc.) This is rather informal at the moment, but
|
||||
the goal is to show us how you know the pull request works as intended.
|
||||
## Proposed changes
|
||||
<!-- What you changed in those files -->
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
## Test
|
||||
<!-- How do you test your changes -->
|
||||
**Code**:
|
||||
|
||||
**Result**:
|
40
.github/workflows/docs.yml
vendored
Normal file
40
.github/workflows/docs.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
name: docs
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
name: build up document and deploy
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Install sphinx and manim env
|
||||
run: |
|
||||
pip3 install --upgrade pip
|
||||
sudo apt install python3-setuptools
|
||||
pip3 install -r docs/requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
- name: Build document with Sphinx
|
||||
run: |
|
||||
cd docs
|
||||
export PATH="$PATH:/home/runner/.local/bin"
|
||||
export SPHINXBUILD="python3 -m sphinx"
|
||||
make html
|
||||
|
||||
- name: Deploy to GitHub pages
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
with:
|
||||
ACCESS_TOKEN: ${{ secrets.DOC_DEPLOY_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: docs/build/html
|
30
.github/workflows/publish.yml
vendored
Normal file
30
.github/workflows/publish.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
name: Upload Python Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.8'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel twine
|
||||
|
||||
- name: Build and publish
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/*
|
170
.gitignore
vendored
170
.gitignore
vendored
|
@ -1,28 +1,154 @@
|
|||
*.pyc
|
||||
*.bak
|
||||
.DS_Store
|
||||
homeless.py
|
||||
playground.py
|
||||
cairo_test.py
|
||||
mayavi_test.py
|
||||
random_scenes/
|
||||
files/
|
||||
assets/
|
||||
ben_playground.py
|
||||
ben_cairo_test.py
|
||||
.floo
|
||||
.flooignore
|
||||
.vscode
|
||||
.vs
|
||||
*.xml
|
||||
*.iml
|
||||
media
|
||||
manim.sublime-project
|
||||
manim.sublime-workspace
|
||||
.eggs/
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
manimlib.egg-info/
|
||||
|
||||
primes.py
|
||||
/media_dir.txt
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
pytestdebug.log
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
doc/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
pythonenv*
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# profiling data
|
||||
.prof
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
# Custom exclusions:
|
||||
.DS_Store
|
||||
|
||||
# For manim
|
||||
/videos
|
||||
/custom_config.yml
|
||||
|
|
30
.travis.yml
30
.travis.yml
|
@ -1,30 +0,0 @@
|
|||
language: python
|
||||
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
|
||||
python: "3.7"
|
||||
cache: pip
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
install:
|
||||
- pip install --upgrade pip
|
||||
- pip install -r requirements.txt
|
||||
- pip install flake8
|
||||
before_script:
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
- flake8 manimlib/ --count --select=E9,F63,F72,F82 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
- flake8 manimlib/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
script:
|
||||
- python setup.py test
|
||||
- python setup.py bdist_wheel
|
||||
after_success:
|
||||
- test $TRAVIS_BRANCH = "master" && test $TRAVIS_PULL_REQUEST = "false" && travis/build_docs.sh
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: eulertour
|
||||
on:
|
||||
tags: true
|
||||
password:
|
||||
secure: j5M2hiJo9kDWJhl0/iSuIQmfd2G2O1Qoc455AkUPMCheAcALnX9xJgFsYBmqfgOXTCtUCQf52XGdOIG4o4s5TY340NZ9eLKI9cWae+sTeSrDCkdwChUilm3D0jQf1FWPUf9ywScwGi20m0sRtzxEJyTuX+JMFd7PIa8bFoDXWPtEjoFOOJrfBusMsANzrI+j+vIMdJ48lc1J8UsQdZapwusTrYU9s12JLhKBPLavmaDKf0HDAJdEhFQ9SaINdkiW/QY8qbfJ/MVu5jHai168zXjD/IaswxoKqCO1G+fWlOq3KwVhG7gI7rwhnnuF+wcA7yLAaMdo0CjO2V7z15S6cG721V2Il2IIh1jq0F8irSH1ZOLOkv/fFk9hkSUQyEU0i8k4m1wE9L47a6GP/66+b+gI91PGfxBOqq4gE/1BdZJqceh0qc13KpcehtYrQwR05bSw0Ye5OoTkqAnCeON0B0Ur4ejfHd3TzkjgB06fw76cZtjAK8f/YjB3KyNCvysOixgzE4tRxlY92yX/tAKZ3iX3yD0MjsinSfwo52N5sIEaCS/FmPRMhJOQBa6ftkfbcUNQBTG9G3b134XXF/LbC4vBloCaTm5VSXagta+oY3SFKQxPAZXx7X+wcFGjqxDjZXG1e66QnA2JJH4aBDsRfSXmUtD8MblwFYdcCJWz+Ck=
|
19
Dockerfile
19
Dockerfile
|
@ -1,19 +0,0 @@
|
|||
FROM python:3.7
|
||||
RUN apt-get update \
|
||||
&& apt-get install -qqy --no-install-recommends \
|
||||
apt-utils \
|
||||
ffmpeg \
|
||||
sox \
|
||||
libcairo2-dev \
|
||||
texlive \
|
||||
texlive-fonts-extra \
|
||||
texlive-latex-extra \
|
||||
texlive-latex-recommended \
|
||||
texlive-science \
|
||||
tipa \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY . /manim
|
||||
RUN cd /manim \
|
||||
&& python setup.py sdist \
|
||||
&& python -m pip install dist/manimlib*
|
||||
ENTRYPOINT ["/bin/bash"]
|
|
@ -1,10 +1,6 @@
|
|||
All files of this project under the directory "from_3b1b" are copyright 3Blue1Brown LLC and used by permission for this project only.
|
||||
|
||||
Any other file of this project is available under the MIT license as follow:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 3Blue1Brown LLC
|
||||
Copyright (c) 2020 3Blue1Brown LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
171
README.md
171
README.md
|
@ -1,155 +1,114 @@
|
|||

|
||||
<p align="center">
|
||||
<a href="https://github.com/3b1b/manim">
|
||||
<img src="https://raw.githubusercontent.com/3b1b/manim/master/logo/cropped.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[](https://travis-ci.org/3b1b/manim)
|
||||
[](https://www.eulertour.com/learn/manim/)
|
||||
[](https://pypi.org/project/manimgl/)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
[](https://www.reddit.com/r/manim/)
|
||||
[](https://discord.gg/mMRrZQW)
|
||||
[](https://www.reddit.com/r/manim/)
|
||||
[](https://discord.gg/mMRrZQW)
|
||||
[](https://3b1b.github.io/manim/)
|
||||
|
||||
Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as seen in the videos at [3Blue1Brown](https://www.3blue1brown.com/).
|
||||
Manim is an engine for precise programatic animations, designed for creating explanatory math videos.
|
||||
|
||||
Note, there are two versions of manim. This repository began as a personal project by the author of [3Blue1Brown](https://www.3blue1brown.com/) for the purpose of animating those videos, with video-specific code available [here](https://github.com/3b1b/videos). In 2020 a group of developers forked it into what is now the [community edition](https://github.com/ManimCommunity/manim/), with a goal of being more stable, better tested, quicker to respond to community contributions, and all around friendlier to get started with. You can engage with that community by joining the discord.
|
||||
|
||||
Since the fork, this version has evolved to work on top of OpenGL, and allows real-time rendering to an interactive window before scenes are finalized and written to a file.
|
||||
|
||||
## Installation
|
||||
Manim runs on Python 3.7. You can install it from PyPI via pip:
|
||||
Manim runs on Python 3.6 or higher (Python 3.8 is recommended).
|
||||
|
||||
System requirements are [FFmpeg](https://ffmpeg.org/), [OpenGL](https://www.opengl.org/) and [LaTeX](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
For Linux, [Pango](https://pango.gnome.org) along with it's developerment headers are required. See instruction [here](https://github.com/ManimCommunity/ManimPango#building).
|
||||
|
||||
### Directly
|
||||
|
||||
```sh
|
||||
pip3 install manimlib
|
||||
```
|
||||
# Install manimgl
|
||||
pip install manimgl
|
||||
|
||||
System requirements are [cairo](https://www.cairographics.org), [ffmpeg](https://www.ffmpeg.org), [sox](http://sox.sourceforge.net), [latex](https://www.latex-project.org) (optional, if you want to use LaTeX).
|
||||
|
||||
You can now use it via the `manim` command. For example:
|
||||
|
||||
```sh
|
||||
manim my_project.py MyScene
|
||||
# Try it out
|
||||
manimgl
|
||||
```
|
||||
|
||||
For more options, take a look at the [Using manim](#using-manim) sections further below.
|
||||
|
||||
### Directly
|
||||
|
||||
If you want to hack on manimlib itself, clone this repository and in that directory execute:
|
||||
|
||||
```sh
|
||||
# Install python requirements
|
||||
python3 -m pip install -r requirements.txt
|
||||
# Install manimgl
|
||||
pip install -e .
|
||||
|
||||
# Try it out
|
||||
python3 ./manim.py example_scenes.py SquareToCircle -pl
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
# or
|
||||
manim-render example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
### Directly (Windows)
|
||||
|
||||
1. [Install FFmpeg](https://www.wikihow.com/Install-FFmpeg-on-Windows).
|
||||
2. [Install Cairo](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo). For most users, ``pycairo‑1.18.0‑cp37‑cp37m‑win32.whl`` will do fine.
|
||||
```sh
|
||||
pip3 install C:\path\to\wheel\pycairo‑1.18.0‑cp37‑cp37m‑win32.whl
|
||||
```
|
||||
3. Install a LaTeX distribution. [MiKTeX](https://miktex.org/download) is recommended.
|
||||
|
||||
4. [Install SoX](https://sourceforge.net/projects/sox/files/sox/).
|
||||
|
||||
5. Install the remaining Python packages. Make sure that ``pycairo==1.17.1`` is changed to ``pycairo==1.18.0`` in requirements.txt.
|
||||
2. Install a LaTeX distribution. [MiKTeX](https://miktex.org/download) is recommended.
|
||||
3. Install the remaining Python packages.
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
pip3 install -r requirements.txt
|
||||
python3 manim.py example_scenes.py SquareToCircle -pl
|
||||
pip install -e .
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
### Mac OSX
|
||||
|
||||
1. Install FFmpeg, LaTeX in terminal using homebrew.
|
||||
```sh
|
||||
brew install ffmpeg mactex
|
||||
```
|
||||
|
||||
2. Install latest version of manim using these command.
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
pip install -e .
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
|
||||
## Anaconda Install
|
||||
|
||||
* Install sox and latex as above.
|
||||
* Create a conda environment using `conda env create -f environment.yml`
|
||||
* **WINDOWS ONLY** Install `pyreadline` via `pip install pyreadline`.
|
||||
1. Install LaTeX as above.
|
||||
2. Create a conda environment using `conda create -n manim python=3.8`.
|
||||
3. Activate the environment using `conda activate manim`.
|
||||
4. Install manimgl using `pip install -e .`.
|
||||
|
||||
|
||||
### Using `virtualenv` and `virtualenvwrapper`
|
||||
After installing `virtualenv` and `virtualenvwrapper`
|
||||
```sh
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
mkvirtualenv -a manim -r requirements.txt manim
|
||||
python3 -m manim example_scenes.py SquareToCircle -pl
|
||||
```
|
||||
|
||||
### Using Docker
|
||||
Since it's a bit tricky to get all the dependencies set up just right, there is a Dockerfile and Compose file provided in this repo as well as [a premade image on Docker Hub](https://hub.docker.com/r/eulertour/manim/tags/). The Dockerfile contains instructions on how to build a manim image, while the Compose file contains instructions on how to run the image.
|
||||
|
||||
The prebuilt container image has manim repository included.
|
||||
`INPUT_PATH` is where the container looks for scene files. You must set the `INPUT_PATH`
|
||||
environment variable to the absolute path containing your scene file and the
|
||||
`OUTPUT_PATH` environment variable to the directory where you want media to be written.
|
||||
|
||||
1. [Install Docker](https://docs.docker.com)
|
||||
2. [Install Docker Compose](https://docs.docker.com/compose/install/)
|
||||
3. Render an animation:
|
||||
```sh
|
||||
INPUT_PATH=/path/to/dir/containing/source/code \
|
||||
OUTPUT_PATH=/path/to/output/ \
|
||||
docker-compose run manim example_scenes.py SquareToCircle -l
|
||||
```
|
||||
The command needs to be run as root if your username is not in the docker group.
|
||||
|
||||
You can replace `example.scenes.py` with any relative path from your `INPUT_PATH`.
|
||||
|
||||

|
||||
|
||||
After running the output will say files ready at `/tmp/output/`, which refers to path inside the container. Your `OUTPUT_PATH` is bind mounted to this `/tmp/output` so any changes made by the container to `/tmp/output` will be mirrored on your `OUTPUT_PATH`. `/media/` will be created in `OUTPUT_PATH`.
|
||||
|
||||
`-p` won't work as manim would look for video player in the container system, which it does not have.
|
||||
|
||||
The first time you execute the above command, Docker will pull the image from Docker Hub and cache it. Any subsequent runs until the image is evicted will use the cached image.
|
||||
Note that the image doesn't have any development tools installed and can't preview animations. Its purpose is building and testing only.
|
||||
|
||||
## Using manim
|
||||
Try running the following:
|
||||
```sh
|
||||
python3 -m manim example_scenes.py SquareToCircle -pl
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
```
|
||||
The `-p` flag in the command above is for previewing, meaning the video file will automatically open when it is done rendering. The `-l` flag is for a faster rendering at a lower quality.
|
||||
This should pop up a window playing a simple scene.
|
||||
|
||||
Some other useful flags include:
|
||||
Some useful flags include:
|
||||
* `-w` to write the scene to a file
|
||||
* `-o` to write the scene to a file and open the result
|
||||
* `-s` to skip to the end and just show the final frame.
|
||||
* `-so` will save the final frame to an image and show it
|
||||
* `-n <number>` to skip ahead to the `n`'th animation of a scene.
|
||||
* `-f` to show the file in finder (for OSX).
|
||||
* `-f` to make the playback window fullscreen
|
||||
|
||||
Set `MEDIA_DIR` environment variable to specify where the image and animation files will be written.
|
||||
Take a look at custom_config.yml for further configuration. To add your customization, you can either edit this file, or add another file by the same name "custom_config.yml" to whatever directory you are running manim from. For example [this is the one](https://github.com/3b1b/videos/blob/master/custom_config.yml) for 3blue1brown videos. There you can specify where videos should be output to, where manim should look for image files and sounds you want to read in, and other defaults regarding style and video quality.
|
||||
|
||||
Look through the `old_projects` folder to see the code for previous 3b1b videos. Note, however, that developments are often made to the library without considering backwards compatibility with those old projects. To run an old project with a guarantee that it will work, you will have to go back to the commit which completed that project.
|
||||
|
||||
While developing a scene, the `-sp` flags are helpful to just see what things look like at the end without having to generate the full animation. It can also be helpful to use the `-n` flag to skip over some number of animations.
|
||||
Look through the [example scenes](https://3b1b.github.io/manim/getting_started/example_scenes.html) to get a sense of how it is used, and feel free to look through the code behind [3blue1brown videos](https://github.com/3b1b/videos) for a much larger set of example. Note, however, that developments are often made to the library without considering backwards compatibility with those old videos. To run an old project with a guarantee that it will work, you will have to go back to the commit which completed that project.
|
||||
|
||||
### Documentation
|
||||
Documentation is in progress at [eulertour.com/learn/manim](https://www.eulertour.com/learn/manim/).
|
||||
Documentation is in progress at [3b1b.github.io/manim](https://3b1b.github.io/manim/). And there is also a Chinese version maintained by **@manim-kindergarten**: [manim.ml](https://manim.ml/) (in Chinese).
|
||||
|
||||
### Walkthrough
|
||||
Todd Zimmerman put together a [tutorial](https://talkingphysics.wordpress.com/2019/01/08/getting-started-animating-with-manim-and-python-3-7/) on getting started with manim, which has been updated to run on Python 3.7.
|
||||
|
||||
### Live Streaming
|
||||
To live stream your animations, simply run manim with the `--livestream` option.
|
||||
|
||||
```sh
|
||||
> 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))
|
||||
|
||||
>>>
|
||||
```
|
||||
|
||||
It is also possible to stream directly to Twitch. To do that simply pass
|
||||
`--livestream` and `--to-twitch to manim` and specify the stream key with
|
||||
`--with-key`. Then when you follow the above example the stream will directly
|
||||
start on your Twitch channel (with no audio support).
|
||||
[manim-kindergarten](https://github.com/manim-kindergarten/) wrote and collected some useful extra classes and some codes of videos in [manim_sandbox repo](https://github.com/manim-kindergarten/manim_sandbox).
|
||||
|
||||
|
||||
## Contributing
|
||||
Is always welcome. In particular, there is a dire need for tests and documentation.
|
||||
Is always welcome. As mentioned above, the [community edition](https://github.com/ManimCommunity/manim) has the most active ecosystem for contributions, with testing and continuous integration, but pull requests are welcome here too. Please explain the motivation for a given change and examples of its effect.
|
||||
|
||||
|
||||
## License
|
||||
All files in the directory `from_3b1b`, which by and large generate the visuals for 3b1b videos, are copyright 3Blue1Brown.
|
||||
|
||||
The general purpose animation code found in the remainder of the repository, on the other hand, is under the MIT license.
|
||||
This project falls under the MIT license.
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
version: '3.1'
|
||||
|
||||
services:
|
||||
manim:
|
||||
# comment this line if you build the image to prevent overwriting the tag
|
||||
image: eulertour/manim:latest
|
||||
# uncomment this line to build rather than pull the image
|
||||
# build: .
|
||||
entrypoint:
|
||||
- manim
|
||||
- --media_dir=/tmp/output
|
||||
volumes:
|
||||
- ${INPUT_PATH:?INPUT_PATH environment variable isn't set}:/tmp/input
|
||||
- ${OUTPUT_PATH:?OUTPUT_PATH environment variable isn't set}:/tmp/output
|
||||
working_dir: /tmp/input
|
||||
network_mode: "none"
|
|
@ -1,9 +1,10 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
|
@ -16,4 +17,4 @@ help:
|
|||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
|
37
docs/example.py
Normal file
37
docs/example.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
square = Square()
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.wait()
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
self.wait()
|
||||
# Try typing the following lines
|
||||
# self.play(circle.animate.stretch(4, dim=0))
|
||||
# self.play(Rotate(circle, TAU / 4))
|
||||
# self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
|
||||
# circle.insert_n_curves(10)
|
||||
# self.play(circle.animate.apply_complex_function(lambda z: z**2))
|
||||
|
||||
class SquareToCircleEmbed(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
|
||||
self.add(circle)
|
||||
self.wait()
|
||||
self.play(circle.animate.stretch(4, dim=0))
|
||||
self.wait(1.5)
|
||||
self.play(Rotate(circle, TAU / 4))
|
||||
self.wait(1.5)
|
||||
self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
|
||||
self.wait(1.5)
|
||||
circle.insert_n_curves(10)
|
||||
self.play(circle.animate.apply_complex_function(lambda z: z**2))
|
||||
self.wait(2)
|
|
@ -1,35 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
|
4
docs/requirements.txt
Normal file
4
docs/requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
Sphinx==3.0.3
|
||||
sphinx-copybutton
|
||||
furo==2020.10.5b9
|
||||
Jinja2
|
293
docs/source/_static/colors.css
Normal file
293
docs/source/_static/colors.css
Normal file
|
@ -0,0 +1,293 @@
|
|||
p.color-text {
|
||||
font-size: inherit;
|
||||
font-family: var(--font-stack--monospace);
|
||||
margin-top: 25px;
|
||||
color: WHITE;
|
||||
}
|
||||
|
||||
p.color-text-small {
|
||||
font-size: small;
|
||||
font-family: var(--font-stack--monospace);
|
||||
margin-top: 28px;
|
||||
color: WHITE;
|
||||
}
|
||||
|
||||
.colors {
|
||||
float: left;
|
||||
padding: 10px;
|
||||
border: 10px;
|
||||
margin: 0;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.BLUE_A {
|
||||
background: #C7E9F1;
|
||||
color:#C7E9F1;
|
||||
}
|
||||
|
||||
.BLUE_B {
|
||||
background: #9CDCEB;
|
||||
color:#9CDCEB;
|
||||
}
|
||||
|
||||
.BLUE_C {
|
||||
background: #58C4DD;
|
||||
color:#58C4DD;
|
||||
}
|
||||
|
||||
.BLUE_D {
|
||||
background: #29ABCA;
|
||||
color:#29ABCA;
|
||||
}
|
||||
|
||||
.BLUE_E {
|
||||
background: #1C758A;
|
||||
color:#1C758A;
|
||||
}
|
||||
|
||||
.TEAL_A {
|
||||
background: #ACEAD7;
|
||||
color:#ACEAD7 ;
|
||||
}
|
||||
|
||||
.TEAL_B {
|
||||
background: #76DDC0;
|
||||
color: #76DDC0;
|
||||
}
|
||||
|
||||
.TEAL_C {
|
||||
background: #5CD0B3;
|
||||
color: #5CD0B3;
|
||||
}
|
||||
|
||||
.TEAL_D {
|
||||
background: #55C1A7;
|
||||
color: #55C1A7;
|
||||
}
|
||||
|
||||
.TEAL_E {
|
||||
background: #49A88F;
|
||||
color: #49A88F;
|
||||
}
|
||||
|
||||
.GREEN_A {
|
||||
background: #C9E2AE;
|
||||
color: #C9E2AE;
|
||||
}
|
||||
|
||||
.GREEN_B {
|
||||
background: #A6CF8C;
|
||||
color: #A6CF8C;
|
||||
}
|
||||
|
||||
.GREEN_C {
|
||||
background: #83C167;
|
||||
color: #83C167;
|
||||
}
|
||||
|
||||
.GREEN_D {
|
||||
background: #77B05D;
|
||||
color: #77B05D;
|
||||
}
|
||||
|
||||
.GREEN_E {
|
||||
background: #699C52;
|
||||
color: #699C52;
|
||||
}
|
||||
|
||||
.YELLOW_A {
|
||||
background: #FFF1B6;
|
||||
color: #FFF1B6;
|
||||
}
|
||||
|
||||
.YELLOW_B {
|
||||
background: #FFEA94;
|
||||
color:#FFEA94 ;
|
||||
}
|
||||
|
||||
.YELLOW_C {
|
||||
background: #FFFF00;
|
||||
color: #FFFF00;
|
||||
}
|
||||
|
||||
.YELLOW_D {
|
||||
background: #F4D345;
|
||||
color: #F4D345;
|
||||
}
|
||||
|
||||
.YELLOW_E {
|
||||
background: #E8C11C;
|
||||
color: #E8C11C;
|
||||
}
|
||||
|
||||
.GOLD_A {
|
||||
background: #F7C797;
|
||||
color:#F7C797;
|
||||
}
|
||||
|
||||
.GOLD_B {
|
||||
background: #F9B775;
|
||||
color:#F9B775;
|
||||
}
|
||||
|
||||
.GOLD_C {
|
||||
background: #F0AC5F;
|
||||
color:#F0AC5F;
|
||||
}
|
||||
|
||||
.GOLD_D {
|
||||
background: #E1A158;
|
||||
color:#E1A158;
|
||||
}
|
||||
|
||||
.GOLD_E {
|
||||
background: #C78D46;
|
||||
color:#C78D46;
|
||||
}
|
||||
|
||||
.RED_A {
|
||||
background: #F7A1A3;
|
||||
color:#F7A1A3;
|
||||
}
|
||||
|
||||
.RED_B {
|
||||
background: #FF8080;
|
||||
color:#FF8080;
|
||||
}
|
||||
|
||||
.RED_C {
|
||||
background: #FC6255;
|
||||
color:#FC6255;
|
||||
}
|
||||
|
||||
.RED_D {
|
||||
background: #E65A4C;
|
||||
color:#E65A4C;
|
||||
}
|
||||
|
||||
.RED_E {
|
||||
background: #CF5044;
|
||||
color:#CF5044;
|
||||
}
|
||||
|
||||
.MAROON_A {
|
||||
background: #ECABC1;
|
||||
color: #ECABC1;
|
||||
}
|
||||
|
||||
.MAROON_B {
|
||||
background: #EC92AB;
|
||||
color: #EC92AB;
|
||||
}
|
||||
|
||||
.MAROON_C {
|
||||
background: #C55F73;
|
||||
color: #C55F73;
|
||||
}
|
||||
|
||||
.MAROON_D {
|
||||
background: #A24D61;
|
||||
color: #A24D61;
|
||||
}
|
||||
|
||||
.MAROON_E {
|
||||
background: #94424F;
|
||||
color: #94424F;
|
||||
}
|
||||
|
||||
.PURPLE_A {
|
||||
background: #CAA3E8;
|
||||
color: #CAA3E8;
|
||||
}
|
||||
|
||||
.PURPLE_B {
|
||||
background: #B189C6;
|
||||
color: #B189C6;
|
||||
}
|
||||
|
||||
.PURPLE_C {
|
||||
background: #9A72AC;
|
||||
color: #9A72AC;
|
||||
}
|
||||
|
||||
.PURPLE_D {
|
||||
background: #715582;
|
||||
color: #715582;
|
||||
}
|
||||
|
||||
.PURPLE_E {
|
||||
background: #644172;
|
||||
color: #644172;
|
||||
}
|
||||
|
||||
.GREY_A {
|
||||
background: #DDDDDD;
|
||||
color: #DDDDDD;
|
||||
}
|
||||
|
||||
.GREY_B {
|
||||
background: #BBBBBB;
|
||||
color: #BBBBBB;
|
||||
}
|
||||
|
||||
.GREY_C {
|
||||
background: #888888;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.GREY_D {
|
||||
background: #444444;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.GREY_E {
|
||||
background: #222222;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.WHITE {
|
||||
background: #FFFFFF;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.BLACK {
|
||||
background: #000000;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.GREY_BROWN {
|
||||
background: #736357;
|
||||
color: #736357;
|
||||
}
|
||||
|
||||
.DARK_BROWN {
|
||||
background: #8B4513;
|
||||
color: #8B4513;
|
||||
}
|
||||
|
||||
.LIGHT_BROWN {
|
||||
background: #CD853F;
|
||||
color: #CD853F;
|
||||
}
|
||||
|
||||
.PINK {
|
||||
background: #D147BD;
|
||||
color: #D147BD;
|
||||
}
|
||||
|
||||
.LIGHT_PINK {
|
||||
background: #DC75CD;
|
||||
color: #DC75CD;
|
||||
}
|
||||
|
||||
.GREEN_SCREEN {
|
||||
background: #00FF00;
|
||||
color: #00FF00;
|
||||
}
|
||||
|
||||
.ORANGE {
|
||||
background: #FF862F;
|
||||
color: #FF862F;
|
||||
}
|
62
docs/source/_static/custom.css
Normal file
62
docs/source/_static/custom.css
Normal file
|
@ -0,0 +1,62 @@
|
|||
p {
|
||||
font-size: initial;
|
||||
}
|
||||
|
||||
span.caption-text {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
span.pre {
|
||||
font-size: initial;
|
||||
}
|
||||
|
||||
.highlight-python.notranslate {
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
.manim-video {
|
||||
width: 99.9%;
|
||||
padding: 8px 0;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.manim-example {
|
||||
background-color: #333333;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 2px 2px 4px #ddd;
|
||||
}
|
||||
|
||||
.manim-example .manim-video {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.manim-example img {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h5.example-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
padding: 8px 16px;
|
||||
color: white;
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
text-transform: none;
|
||||
margin-top: -0.4em;
|
||||
margin-bottom: -0.2em;
|
||||
}
|
||||
|
||||
.manim-example .highlight {
|
||||
background-color: #fafafa;
|
||||
border: 2px solid #333333;
|
||||
padding: 8px 8px 10px 8px;
|
||||
font-size: large;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.manim-example .highlight pre {
|
||||
background-color: inherit;
|
||||
border-left: none;
|
||||
margin: 0;
|
||||
padding: 0 6px 0 6px;
|
||||
}
|
BIN
docs/source/_static/example_scenes/AnimatingMethods.mp4
Normal file
BIN
docs/source/_static/example_scenes/AnimatingMethods.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/CoordinateSystemExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/CoordinateSystemExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/GraphExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/GraphExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/InteractiveDevlopment.mp4
Normal file
BIN
docs/source/_static/example_scenes/InteractiveDevlopment.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/OpeningManimExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/OpeningManimExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/SquareToCircle.mp4
Normal file
BIN
docs/source/_static/example_scenes/SquareToCircle.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/SurfaceExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/SurfaceExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/TexTransformExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/TexTransformExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/TextExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/TextExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/example_scenes/UpdatersExample.mp4
Normal file
BIN
docs/source/_static/example_scenes/UpdatersExample.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/icon.png
Normal file
BIN
docs/source/_static/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 KiB |
BIN
docs/source/_static/manim_shaders_process_en.png
Normal file
BIN
docs/source/_static/manim_shaders_process_en.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 603 KiB |
BIN
docs/source/_static/manim_shaders_structure.png
Normal file
BIN
docs/source/_static/manim_shaders_structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/source/_static/quickstart/SquareToCircle.mp4
Normal file
BIN
docs/source/_static/quickstart/SquareToCircle.mp4
Normal file
Binary file not shown.
BIN
docs/source/_static/quickstart/SquareToCircle.png
Normal file
BIN
docs/source/_static/quickstart/SquareToCircle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
docs/source/_static/quickstart/SquareToCircleEmbed.mp4
Normal file
BIN
docs/source/_static/quickstart/SquareToCircleEmbed.mp4
Normal file
Binary file not shown.
|
@ -1,11 +0,0 @@
|
|||
About
|
||||
=====
|
||||
|
||||
Animating technical concepts is traditionally pretty tedious, since it can be
|
||||
difficult to make the animations precise enough to convey them accurately.
|
||||
``Manim`` uses Python to generate animations programmatically, which makes it
|
||||
possible to specify exactly how each one should run.
|
||||
|
||||
This project is still very much a work in progress, but I hope that the
|
||||
information here will make it easier for newcomers to get started using
|
||||
``Manim``.
|
|
@ -1,210 +0,0 @@
|
|||
Animation
|
||||
=========
|
||||
|
||||
|
||||
|
||||
The simplest of which is ``Scene.add``. The object appears on the first frame
|
||||
without any animation::
|
||||
|
||||
class NoAnimation(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
self.add(square))
|
||||
|
||||
Animation are used in conjunction with ``scene.Play``
|
||||
|
||||
Fade
|
||||
----
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeIn.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeIn(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Fade In")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.play(FadeIn(square))
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeOut.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeOut(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Fade Out")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.add(square)
|
||||
self.play(FadeOut(square))
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFrom.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFrom(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Fade In from {label}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeInFrom(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeOutAndShift.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeOutAndShift(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Fade Out and shift {label}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeOutAndShift(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromLarge.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromLarge(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
for factor in [0.1, 0.5, 0.8, 1, 2, 5]:
|
||||
anno = TextMobject(f"Fade In from large scale\_factor={factor}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(FadeInFromLarge(square, scale_factor=factor))
|
||||
self.remove(anno, square)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromPoint.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromPoint(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for i in range(-6, 7, 2):
|
||||
anno = TextMobject(f"Fade In from point {i}")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
self.play(FadeInFromPoint(square, point=i))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
Grow
|
||||
----
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationGrowFromEdge.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationGrowFromEdge(Scene):
|
||||
def construct(self):
|
||||
|
||||
for label, edge in zip(
|
||||
["LEFT", "RIGHT", "UP", "DOWN"], [LEFT, RIGHT, UP, DOWN]
|
||||
):
|
||||
anno = TextMobject(f"Grow from {label} edge")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
square = Square()
|
||||
self.play(GrowFromEdge(square, edge))
|
||||
self.remove(anno, square)
|
||||
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationGrowFromCenter.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationGrowFromCenter(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
|
||||
anno = TextMobject("Grow from center")
|
||||
anno.shift(2 * DOWN)
|
||||
self.add(anno)
|
||||
|
||||
self.play(GrowFromCenter(square))
|
||||
|
||||
|
||||
|
||||
|
||||
Diagonal Directions
|
||||
-------------------
|
||||
|
||||
You can combine cardinal directions to form diagonal animations
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="_static/AnimationFadeInFromDiagonal.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AnimationFadeInFromDiagonal(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
for diag in [UP + LEFT, UP + RIGHT, DOWN + LEFT, DOWN + RIGHT]:
|
||||
self.play(FadeInFrom(square, diag))
|
||||
|
||||
.. note::
|
||||
You can also use the abbreviated forms like ``UL, UR, DL, DR``.
|
||||
See :ref:`ref-directions`.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
@ -1,53 +1,40 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath("."))
|
||||
sys.path.insert(0, os.path.abspath('../../'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
project = 'manim'
|
||||
copyright = '- This document has been placed in the public domain.'
|
||||
author = 'TonyCrane'
|
||||
|
||||
project = 'Manim'
|
||||
copyright = '2019, EulerTour'
|
||||
author = 'EulerTour'
|
||||
release = ''
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
master_doc = 'index'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.githubpages',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx_copybutton',
|
||||
'manim_example_ext'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
autoclass_content = 'both'
|
||||
mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
|
||||
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
pygments_style = 'default'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['assets']
|
||||
html_static_path = ["_static"]
|
||||
html_css_files = ["custom.css", "colors.css"]
|
||||
html_theme = 'furo' # pip install furo==2020.10.5b9
|
||||
html_favicon = '_static/icon.png'
|
||||
html_logo = '../../logo/transparent_graph.png'
|
||||
html_theme_options = {
|
||||
"sidebar_hide_name": True,
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
Manim Constants
|
||||
===============
|
||||
|
||||
The ``constants.py`` under ``manimlib/`` contains variables that are used
|
||||
during setup and running manim. Some variables are not documented here as they are
|
||||
only used internally by manim.
|
||||
|
||||
Directories
|
||||
-----------
|
||||
|
||||
MEDIA_DIR
|
||||
The directory where ``VIDEO_DIR`` and ``TEX_DIR`` will be created,
|
||||
if they aren't specified via flags.
|
||||
VIDEO_DIR
|
||||
Used to store the scenes rendered by Manim. When a scene is
|
||||
finished rendering, it will be stored under
|
||||
``VIDEO_DIR/module_name/scene_name/quality/scene_name.mp4``.
|
||||
Created under ``MEDIA_DIR`` by default.
|
||||
TEX_DIR
|
||||
Files written by Latex are stored here. It also acts as a cache
|
||||
so that the files aren't rewritten each time Latex is needed.
|
||||
|
||||
Those directories are created if they don't exist.
|
||||
|
||||
Tex
|
||||
---
|
||||
TEX_USE_CTEX
|
||||
A boolean value. Change it to True if you need to use Chinese typesetting.
|
||||
TEX_TEXT_TO_REPLACE
|
||||
Placeholder text used by manim when generating tex files
|
||||
TEMPLATE_TEX_FILE
|
||||
By default ``manimlib/tex_template.tex`` is used. If ``TEX_USE_CTEX``
|
||||
is set to True then ``manimlib/ctex_template.tex`` is used.
|
||||
|
||||
Numerical Constants
|
||||
-------------------
|
||||
|
||||
PI
|
||||
alias to ``numpy.pi``
|
||||
TAU
|
||||
PI * 2
|
||||
|
||||
DEGREES
|
||||
TAU / 360
|
||||
|
||||
Camera Configuration
|
||||
--------------------
|
||||
|
||||
Render setting presets
|
||||
|
||||
PRODUCTION_QUALITY_CAMERA_CONFIG
|
||||
2560x1440 @ 60fps # This is the default when rendering a scene
|
||||
HIGH_QUALITY_CAMERA_CONFIG
|
||||
1920x1080 @ 60fps. # Used when the ``-h`` or ``--high_quality`` flag
|
||||
is passed.
|
||||
MEDIUM_QUALITY_CAMERA_CONFIG
|
||||
1280x720 @ 30fps. # Used when the ``-m`` or ``--medium_quality``
|
||||
flag is passed.
|
||||
LOW_QUALITY_CAMERA_CONFIG
|
||||
854x480 @ 15fps. # Used when the ``-l`` or ``--low_quality`` flag is
|
||||
passed.
|
||||
|
||||
.. _ref-directions:
|
||||
|
||||
Coordinates
|
||||
-----------
|
||||
|
||||
Used for 2d/3d animations and placements::
|
||||
|
||||
ORIGIN
|
||||
UP
|
||||
DOWN
|
||||
RIGHT
|
||||
LEFT
|
||||
IN # 3d camera only, away from camera
|
||||
OUT # 3d camera only, close to camera
|
||||
|
||||
UL = UP + LEFT # diagonal abbreviations. You can use either one
|
||||
UR = UP + RIGHT
|
||||
DL = DOWN + LEFT
|
||||
DR = DOWN + RIGHT
|
||||
|
||||
TOP
|
||||
BOTTOM
|
||||
LEFT_SIDE
|
||||
RIGHT_SIDE``
|
||||
|
||||
Colors
|
||||
------
|
||||
|
||||
COLOR_MAP
|
||||
A predefined color maps
|
||||
PALETTE
|
||||
A list of color hex strings, derived from COLOR_MAP
|
|
@ -1,178 +0,0 @@
|
|||
Coordinate
|
||||
==========
|
||||
|
||||
By default, the scene in manim is made up by 8 x 14 grid. The grid is addressed using a numpy
|
||||
array in the form of [x, y, z]. For 2D animations only the x and y axes are used.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class DotMap(Scene):
|
||||
def construct(self):
|
||||
dots = dict()
|
||||
annos = dict()
|
||||
var_index = 0
|
||||
for x in range(-7, 8):
|
||||
for y in range(-4, 5):
|
||||
annos[f"{x}{y}"] = TexMobject(f"({x}, {y})")
|
||||
dots[f"{var_index}"] = Dot(np.array([x, y, 0]))
|
||||
var_index = var_index + 1
|
||||
for anno, dot in zip(annos.values(), dots.values()):
|
||||
self.add(anno)
|
||||
self.add(dot)
|
||||
self.wait(0.2)
|
||||
self.remove(anno)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="700" height="394" controls>
|
||||
<source src="_static/coordinate/DotMap.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
.. note::
|
||||
You can place objects outside this boundary, but it won't show up in the render.
|
||||
|
||||
Using Coordinates
|
||||
-----------------
|
||||
|
||||
Coordinates are used for creating geometries (`VMobject` in manim) and animations.
|
||||
|
||||
Here coordinates are used to create this Polygon
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class CoorPolygon(Scene):
|
||||
def construct(self):
|
||||
for x in range(-7, 8):
|
||||
for y in range(-4, 5):
|
||||
self.add(Dot(np.array([x, y, 0]), color=DARK_GREY))
|
||||
polygon = Polygon(
|
||||
np.array([3, 2, 0]),
|
||||
np.array([1, -1, 0]),
|
||||
np.array([-5, -4, 0]),
|
||||
np.array([-4, 4, 0]))
|
||||
self.add(polygon)
|
||||
|
||||
|
||||
.. Image:: assets/coordinate/CoorPolygon.png
|
||||
:width: 700px
|
||||
|
||||
Coordinate Aliasing
|
||||
-------------------
|
||||
|
||||
From some animations typing a ``np.array`` everytime you need a coordinate can be tedious.
|
||||
Manim provides aliases to the most common coordinates::
|
||||
|
||||
UP == np.array([0, 1, 0])
|
||||
DOWN == np.array([0, -1, 0])
|
||||
LEFT == np.array([-1, 0, 0])
|
||||
RIGHT == np.array([1, 0, 0])
|
||||
UL == np.array([-1, 1, 0])
|
||||
DL == np.array([-1, -1, 0])
|
||||
UR == np.array([1, 1, 0])
|
||||
DR == np.array([1, -1, 0])
|
||||
|
||||
Here coordinates are used for animations
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class CoorAlias(Scene):
|
||||
def construct(self):
|
||||
for x in range(-7, 8):
|
||||
for y in range(-4, 5):
|
||||
self.add(Dot(np.array([x, y, 0]), color=DARK_GREY))
|
||||
|
||||
aliases = {
|
||||
"UP": UP,
|
||||
"np.array([0,1,0])": np.array([0, 1, 0]),
|
||||
"DOWN": DOWN,
|
||||
"np.array([0,-1,0])": np.array([0, -1, 0]),
|
||||
"LEFT": LEFT,
|
||||
"np.array([-1,0,0])": np.array([-1, 0, 0]),
|
||||
"RIGHT": RIGHT,
|
||||
"np.array([1,0,0])": np.array([1, 0, 0]),
|
||||
"UL": UL,
|
||||
"np.array([-1,1,0])": np.array([-1, 1, 0]),
|
||||
"DL": DL,
|
||||
"np.array([-1,-1,0])": np.array([-1, -1, 0]),
|
||||
"UR": UR,
|
||||
"np.array([1,1,0])": np.array([1, 1, 0]),
|
||||
"DR": DR,
|
||||
"np.array([1,-1,0])": np.array([1, -1, 0])}
|
||||
circle = Circle(color=RED, radius=0.5)
|
||||
self.add(circle)
|
||||
self.wait(0.5)
|
||||
|
||||
for text, aliase in aliases.items():
|
||||
anno = TexMobject(f"\\texttt{{{text}}}")
|
||||
self.play(Write(anno, run_time=0.2))
|
||||
self.play(ApplyMethod(circle.shift, aliase))
|
||||
self.wait(0.2)
|
||||
self.play(FadeOut(anno, run_time=0.2))
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="700" height="394" controls>
|
||||
<source src="_static/coordinate/CoorAlias.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
Coordinate Arithmetic
|
||||
---------------------
|
||||
|
||||
Numpy array allows arithmetic operations::
|
||||
|
||||
>>> numpy.array([2,2,0]) + 4
|
||||
array([6, 6, 4])
|
||||
|
||||
>>> np.array([1, -3, 0]) + np.array([-4, 2, 0])
|
||||
array([-3, -1, 0])
|
||||
|
||||
>>> np.array([2, 2, 0]) - np.array([3,6, 0])
|
||||
array([-1, -4, 0])
|
||||
|
||||
>>> numpy.array([2,2,0]) - 3
|
||||
array([-1, -1, -3])
|
||||
|
||||
>>> np.array([1, -3, 0]) * 3
|
||||
array([ 3, -9, 0])
|
||||
|
||||
>>> numpy.array([2,2,0]) / 2
|
||||
array([1., 1., 0.])
|
||||
|
||||
>>> numpy.array([2,2,0]) / numpy.array([1, 4, 0])
|
||||
__main__:1: RuntimeWarning: invalid value encountered in true_divide
|
||||
array([2. , 0.5, nan])
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class CoorArithmetic(Scene):
|
||||
def construct(self):
|
||||
for x in range(-7, 8):
|
||||
for y in range(-4, 5):
|
||||
self.add(Dot(np.array([x, y, 0]), color=DARK_GREY))
|
||||
|
||||
circle = Circle(color=RED, radius=0.5)
|
||||
self.add(circle)
|
||||
self.wait(0.5)
|
||||
|
||||
aliases = {
|
||||
"LEFT * 3": LEFT * 3,
|
||||
"UP + RIGHT / 2": UP + RIGHT / 2,
|
||||
"DOWN + LEFT * 2": DOWN + LEFT * 2,
|
||||
"RIGHT * 3.75 * DOWN": RIGHT * 3.75 * DOWN,
|
||||
# certain arithmetic won't work as you expected
|
||||
# In [4]: RIGHT * 3.75 * DOWN
|
||||
# Out[4]: array([ 0., -0., 0.])
|
||||
"RIGHT * 3.75 + DOWN": RIGHT * 3.75 + DOWN}
|
||||
|
||||
for text, aliase in aliases.items():
|
||||
anno = TexMobject(f"\\texttt{{{text}}}")
|
||||
self.play(Write(anno, run_time=0.2))
|
||||
self.play(ApplyMethod(circle.shift, aliase))
|
||||
self.wait(0.2)
|
||||
self.play(FadeOut(anno, run_time=0.2))
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="700" height="394" controls>
|
||||
<source src="_static/coordinate/CoorArithmetic.mp4" type="video/mp4">
|
||||
</video>
|
31
docs/source/development/about.rst
Normal file
31
docs/source/development/about.rst
Normal file
|
@ -0,0 +1,31 @@
|
|||
About
|
||||
=====
|
||||
|
||||
About Manim
|
||||
-----------
|
||||
|
||||
Manim is an animation engine for explanatory math videos.
|
||||
You can use it to make math videos (or other fields) like 3Blue1Brown.
|
||||
|
||||
There are mainly two versions here:
|
||||
|
||||
- `3b1b/manim <https://github.com/3b1b/manim>`_ : Maintained by Grant Sanderson of 3Blue1Brown.
|
||||
|
||||
Using OpenGL and its GLSL language to use GPU for rendering. It has higher efficiency,
|
||||
faster rendering speed, and supports real-time rendering and interaction.
|
||||
|
||||
- `ManimCommunity/manim <https://github.com/ManimCommunity/manim>`_ : Maintained by Manim Community Dev Team.
|
||||
|
||||
Using multiple backend rendering. There is better documentation and
|
||||
a more open contribution community.
|
||||
|
||||
About this documentation
|
||||
------------------------
|
||||
|
||||
This documentation is based on the version in `3b1b/manim <https://github.com/3b1b/manim>`_.
|
||||
Created by `TonyCrane <https://github.com/TonyCrane>`_ ("鹤翔万里" in Chinese) and in production.
|
||||
|
||||
Among them, the ``manim_example_ext`` extension for Sphinx refers to
|
||||
`the documentation of ManimCommunity <https://docs.manim.community/>`_.
|
||||
|
||||
If you want to contribute to manim or this document, please see: :doc:`contributing`
|
4
docs/source/development/changelog.rst
Normal file
4
docs/source/development/changelog.rst
Normal file
|
@ -0,0 +1,4 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
No changes now.
|
59
docs/source/development/contributing.rst
Normal file
59
docs/source/development/contributing.rst
Normal file
|
@ -0,0 +1,59 @@
|
|||
Contributing
|
||||
============
|
||||
|
||||
Accept any contribution you make :)
|
||||
|
||||
- **Contribute to the manim source code**:
|
||||
|
||||
Please fork to your own repository and make changes, submit a pull request, and fill in
|
||||
the motivation for the change following the instructions in the template. We will check
|
||||
your pull request in detail (this usually takes a while, please be patient)
|
||||
|
||||
- **Contribute to the documentation**:
|
||||
|
||||
Also submit a pull request and write down the main changes.
|
||||
|
||||
- **If you find a bug in the code**:
|
||||
|
||||
Please open an issue and fill in the found problem and your environment according
|
||||
to the template. (But please note that if you think this problem is just a problem
|
||||
of yourself, rather than a problem of source code, it is recommended that you ask a
|
||||
question in the `Q&A category <https://github.com/3b1b/manim/discussions/categories/q-a>`_
|
||||
of the discussion page)
|
||||
|
||||
- **You are welcome to share the content you made with manim**:
|
||||
|
||||
Post it in the `show and tell category <https://github.com/3b1b/manim/discussions/categories/show-and-tell>`_
|
||||
of the discussion page.
|
||||
|
||||
- **You are also welcome to share some of your suggestions and ideas**:
|
||||
|
||||
Post them in the `ideas category <https://github.com/3b1b/manim/discussions/categories/ideas>`_
|
||||
of the discussion page.
|
||||
|
||||
How to build this documentation
|
||||
-------------------------------
|
||||
|
||||
- Clone the 3b1b/manim repository
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
# or your own repo
|
||||
# git clone https://github.com/<your user name>/manim.git
|
||||
cd manim
|
||||
|
||||
- Install python package dependencies
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install -r docs/requirements.txt
|
||||
|
||||
- Go to the ``docs/`` folder and build
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
cd docs/
|
||||
make html
|
||||
|
||||
- The output document is located in ``docs/build/html/``
|
2
docs/source/documentation/animation/index.rst
Normal file
2
docs/source/documentation/animation/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Animation (TODO)
|
||||
================
|
2
docs/source/documentation/camera/index.rst
Normal file
2
docs/source/documentation/camera/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Camera (TODO)
|
||||
=============
|
192
docs/source/documentation/constants.rst
Normal file
192
docs/source/documentation/constants.rst
Normal file
|
@ -0,0 +1,192 @@
|
|||
constants
|
||||
=========
|
||||
|
||||
The ``constants.py`` in the ``manimlib`` folder defines the constants
|
||||
needed when running manim. Some constants are not explained here because
|
||||
they are only used inside manim.
|
||||
|
||||
Frame and pixel shape
|
||||
---------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ASPECT_RATIO = 16.0 / 9.0
|
||||
FRAME_HEIGHT = 8.0
|
||||
FRAME_WIDTH = FRAME_HEIGHT * ASPECT_RATIO
|
||||
FRAME_Y_RADIUS = FRAME_HEIGHT / 2
|
||||
FRAME_X_RADIUS = FRAME_WIDTH / 2
|
||||
|
||||
DEFAULT_PIXEL_HEIGHT = 1080
|
||||
DEFAULT_PIXEL_WIDTH = 1920
|
||||
DEFAULT_FRAME_RATE = 30
|
||||
|
||||
Buffs
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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 # Distance between object and edge
|
||||
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER = MED_SMALL_BUFF # Distance between objects
|
||||
|
||||
Run times
|
||||
---------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
DEFAULT_POINTWISE_FUNCTION_RUN_TIME = 3.0
|
||||
DEFAULT_WAIT_TIME = 1.0
|
||||
|
||||
Coordinates
|
||||
-----------
|
||||
|
||||
manim uses three-dimensional coordinates and uses the type of ``ndarray``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
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
|
||||
|
||||
Mathematical constant
|
||||
---------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
PI = np.pi
|
||||
TAU = 2 * PI
|
||||
DEGREES = TAU / 360
|
||||
|
||||
Text
|
||||
----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
START_X = 30
|
||||
START_Y = 20
|
||||
NORMAL = "NORMAL"
|
||||
ITALIC = "ITALIC"
|
||||
OBLIQUE = "OBLIQUE"
|
||||
BOLD = "BOLD"
|
||||
|
||||
Stroke width
|
||||
------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
DEFAULT_STROKE_WIDTH = 4
|
||||
|
||||
Colours
|
||||
-------
|
||||
|
||||
Here are the preview of default colours. (Modified from
|
||||
`elteoremadebeethoven <https://elteoremadebeethoven.github.io/manim_3feb_docs.github.io/html/_static/colors/colors.html>`_)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div style="float: left;">
|
||||
<h3>BLUE</h3>
|
||||
<div class="colors BLUE_E"><p class="color-text">BLUE_E</p></div>
|
||||
<div class="colors BLUE_D"><p class="color-text">BLUE_D</p></div>
|
||||
<div class="colors BLUE_C"><p class="color-text">BLUE_C</p></div>
|
||||
<div class="colors BLUE_B"><p class="color-text">BLUE_B</p></div>
|
||||
<div class="colors BLUE_A"><p class="color-text">BLUE_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>TEAL</h3>
|
||||
<div class="colors TEAL_E"><p class="color-text">TEAL_E</p></div>
|
||||
<div class="colors TEAL_D"><p class="color-text">TEAL_D</p></div>
|
||||
<div class="colors TEAL_C"><p class="color-text">TEAL_C</p></div>
|
||||
<div class="colors TEAL_B"><p class="color-text">TEAL_B</p></div>
|
||||
<div class="colors TEAL_A"><p class="color-text">TEAL_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>GREEN</h3>
|
||||
<div class="colors GREEN_E"><p class="color-text">GREEN_E</p></div>
|
||||
<div class="colors GREEN_D"><p class="color-text">GREEN_D</p></div>
|
||||
<div class="colors GREEN_C"><p class="color-text">GREEN_C</p></div>
|
||||
<div class="colors GREEN_B"><p class="color-text">GREEN_B</p></div>
|
||||
<div class="colors GREEN_A"><p class="color-text">GREEN_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>YELLOW</h3>
|
||||
<div class="colors YELLOW_E"><p class="color-text">YELLOW_E</p></div>
|
||||
<div class="colors YELLOW_D"><p class="color-text">YELLOW_D</p></div>
|
||||
<div class="colors YELLOW_C"><p class="color-text">YELLOW_C</p></div>
|
||||
<div class="colors YELLOW_B"><p class="color-text">YELLOW_B</p></div>
|
||||
<div class="colors YELLOW_A"><p class="color-text">YELLOW_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>GOLD</h3>
|
||||
<div class="colors GOLD_E"><p class="color-text">GOLD_E</p></div>
|
||||
<div class="colors GOLD_D"><p class="color-text">GOLD_D</p></div>
|
||||
<div class="colors GOLD_C"><p class="color-text">GOLD_C</p></div>
|
||||
<div class="colors GOLD_B"><p class="color-text">GOLD_B</p></div>
|
||||
<div class="colors GOLD_A"><p class="color-text">GOLD_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>RED</h3>
|
||||
<div class="colors RED_E"><p class="color-text">RED_E</p></div>
|
||||
<div class="colors RED_D"><p class="color-text">RED_D</p></div>
|
||||
<div class="colors RED_C"><p class="color-text">RED_C</p></div>
|
||||
<div class="colors RED_B"><p class="color-text">RED_B</p></div>
|
||||
<div class="colors RED_A"><p class="color-text">RED_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>MAROON</h3>
|
||||
<div class="colors MAROON_E"><p class="color-text">MAROON_E</p></div>
|
||||
<div class="colors MAROON_D"><p class="color-text">MAROON_D</p></div>
|
||||
<div class="colors MAROON_C"><p class="color-text">MAROON_C</p></div>
|
||||
<div class="colors MAROON_B"><p class="color-text">MAROON_B</p></div>
|
||||
<div class="colors MAROON_A"><p class="color-text">MAROON_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>PURPLE</h3>
|
||||
<div class="colors PURPLE_E"><p class="color-text">PURPLE_E</p></div>
|
||||
<div class="colors PURPLE_D"><p class="color-text">PURPLE_D</p></div>
|
||||
<div class="colors PURPLE_C"><p class="color-text">PURPLE_C</p></div>
|
||||
<div class="colors PURPLE_B"><p class="color-text">PURPLE_B</p></div>
|
||||
<div class="colors PURPLE_A"><p class="color-text">PURPLE_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>GREY</h3>
|
||||
<div class="colors GREY_E"><p class="color-text">GREY_E</p></div>
|
||||
<div class="colors GREY_D"><p class="color-text">GREY_D</p></div>
|
||||
<div class="colors GREY_C"><p class="color-text">GREY_C</p></div>
|
||||
<div class="colors GREY_B"><p class="color-text">GREY_B</p></div>
|
||||
<div class="colors GREY_A"><p class="color-text">GREY_A</p></div>
|
||||
</div>
|
||||
<div style="float: left;">
|
||||
<h3>Others</h3>
|
||||
<div class="colors WHITE"><p class="color-text" style="color: BLACK">WHITE</p></div>
|
||||
<div class="colors BLACK"><p class="color-text">BLACK</p></div>
|
||||
<div class="colors GREY_BROWN"><p class="color-text-small">GREY_BROWN</p></div>
|
||||
<div class="colors DARK_BROWN"><p class="color-text-small">DARK_BROWN</p></div>
|
||||
<div class="colors LIGHT_BROWN"><p class="color-text-small">LIGHT_BROWN</p></div>
|
||||
<div class="colors PINK"><p class="color-text">PINK</p></div>
|
||||
<div class="colors LIGHT_PINK"><p class="color-text-small">LIGHT_PINK</p></div>
|
||||
<div class="colors GREEN_SCREEN"><p class="color-text-small">GREEN_SCREEN</p></div>
|
||||
<div class="colors ORANGE"><p class="color-text">ORANGE</p></div>
|
||||
</div>
|
139
docs/source/documentation/custom_config.rst
Normal file
139
docs/source/documentation/custom_config.rst
Normal file
|
@ -0,0 +1,139 @@
|
|||
custom_config
|
||||
==============
|
||||
|
||||
``directories``
|
||||
---------------
|
||||
|
||||
- ``mirror_module_path``
|
||||
(``True`` or ``False``) Whether to create a folder named the name of the
|
||||
running file under the ``output`` path, and save the output (``images/``
|
||||
or ``videos/``) in it.
|
||||
|
||||
- ``output``
|
||||
Output file path, the videos will be saved in the ``videos/`` folder under it,
|
||||
and the pictures will be saved in the ``images/`` folder under it.
|
||||
|
||||
For example, if you set ``output`` to ``"/.../manim/output"`` and
|
||||
``mirror_module_path`` to ``False``, then you exported ``Scene1`` in the code
|
||||
file and saved the last frame, then the final directory structure will be like:
|
||||
|
||||
.. code-block:: text
|
||||
:emphasize-lines: 9, 11
|
||||
|
||||
manim/
|
||||
├── manimlib/
|
||||
│ ├── animation/
|
||||
│ ├── ...
|
||||
│ ├── default_config.yml
|
||||
│ └── window.py
|
||||
├── output/
|
||||
│ ├── images
|
||||
│ │ └── Scene1.png
|
||||
│ └── videos
|
||||
│ └── Scene1.mp4
|
||||
├── code.py
|
||||
└── custom_config.yml
|
||||
|
||||
But if you set ``mirror_module_path`` to ``True``, the directory structure will be:
|
||||
|
||||
.. code-block:: text
|
||||
:emphasize-lines: 8
|
||||
|
||||
manim/
|
||||
├── manimlib/
|
||||
│ ├── animation/
|
||||
│ ├── ...
|
||||
│ ├── default_config.yml
|
||||
│ └── window.py
|
||||
├── output/
|
||||
│ └── code/
|
||||
│ ├── images
|
||||
│ │ └── Scene1.png
|
||||
│ └── videos
|
||||
│ └── Scene1.mp4
|
||||
├── code.py
|
||||
└── custom_config.yml
|
||||
|
||||
- ``raster_images``
|
||||
The directory for storing raster images to be used in the code (including
|
||||
``.jpg``, ``.png`` and ``.gif``), which will be read by ``ImageMobject``.
|
||||
|
||||
- ``vector_images``
|
||||
The directory for storing vector images to be used in the code (including
|
||||
``.svg`` and ``.xdv``), which will be read by ``SVGMobject``.
|
||||
|
||||
- ``sounds``
|
||||
The directory for storing sound files to be used in ``Scene.add_sound()`` (
|
||||
including ``.wav`` and ``.mp3``).
|
||||
|
||||
- ``temporary_storage``
|
||||
The directory for storing temporarily generated cache files, including
|
||||
``Tex`` cache, ``Text`` cache and storage of object points.
|
||||
|
||||
``tex``
|
||||
-------
|
||||
|
||||
- ``executable``
|
||||
The executable program used to compile LaTeX (``latex`` or ``xelatex -no-pdf``
|
||||
is recommended)
|
||||
|
||||
- ``template_file``
|
||||
LaTeX template used, in ``manimlib/tex_templates``
|
||||
|
||||
- ``intermediate_filetype``
|
||||
The type of intermediate vector file generated after compilation (``dvi`` if
|
||||
``latex`` is used, ``xdv`` if ``xelatex`` is used)
|
||||
|
||||
- ``text_to_replace``
|
||||
The text to be replaced in the template (needn't to change)
|
||||
|
||||
``universal_import_line``
|
||||
-------------------------
|
||||
|
||||
Import line that need to execute when entering interactive mode directly.
|
||||
|
||||
``style``
|
||||
---------
|
||||
|
||||
- ``font``
|
||||
Default font of Text
|
||||
|
||||
- ``background_color``
|
||||
Default background color
|
||||
|
||||
``window_position``
|
||||
-------------------
|
||||
|
||||
The relative position of the playback window on the display (two characters,
|
||||
the first character means upper(U) / middle(O) / lower(D), the second character
|
||||
means left(L) / middle(O) / right(R)).
|
||||
|
||||
``break_into_partial_movies``
|
||||
-----------------------------
|
||||
|
||||
If this is set to ``True``, then many small files will be written corresponding
|
||||
to each ``Scene.play`` and ``Scene.wait`` call, and these files will then be combined
|
||||
to form the full scene.
|
||||
|
||||
Sometimes video-editing is made easier when working with the broken up scene, which
|
||||
effectively has cuts at all the places you might want.
|
||||
|
||||
``camera_qualities``
|
||||
--------------------
|
||||
|
||||
Export quality
|
||||
|
||||
- ``low``
|
||||
Low quality (default is 480p15)
|
||||
|
||||
- ``medium``
|
||||
Medium quality (default is 720p30)
|
||||
|
||||
- ``high``
|
||||
High quality (default is 1080p30)
|
||||
|
||||
- ``ultra_high``
|
||||
Ultra high quality (default is 4K60)
|
||||
|
||||
- ``default_quality``
|
||||
Default quality (one of the above four)
|
2
docs/source/documentation/mobject/index.rst
Normal file
2
docs/source/documentation/mobject/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Mobject (TODO)
|
||||
==============
|
2
docs/source/documentation/scene/index.rst
Normal file
2
docs/source/documentation/scene/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Scene (TODO)
|
||||
============
|
2
docs/source/documentation/shaders/index.rst
Normal file
2
docs/source/documentation/shaders/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Shaders (TODO)
|
||||
==============
|
2
docs/source/documentation/utils/index.rst
Normal file
2
docs/source/documentation/utils/index.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Utils (TODO)
|
||||
============
|
|
@ -1,4 +0,0 @@
|
|||
Animating Mobjects
|
||||
==================
|
||||
|
||||
Learn about animations.
|
104
docs/source/getting_started/config.rst
Normal file
104
docs/source/getting_started/config.rst
Normal file
|
@ -0,0 +1,104 @@
|
|||
CONFIG dictionary
|
||||
=================
|
||||
|
||||
What's CONFIG
|
||||
-------------
|
||||
|
||||
``CONFIG`` dictionary is a feature of manim, which facilitates the inheritance
|
||||
and modification of parameters between parent and child classes.
|
||||
|
||||
| ``CONFIG`` dictionary 's processing is in ``manimlib/utils/config_ops.py``
|
||||
| It can convert the key-value pairs in the ``CONFIG`` dictionary into class attributes and values
|
||||
|
||||
Generally, the first line of the ``.__init__()`` method in some basic class (``Mobject``, ``Animation``,
|
||||
etc.) will call this function ``digest_config(self, kwargs)`` to convert both
|
||||
the ``CONFIG`` dictionary and ``kwargs`` into attributes. Then it can be accessed
|
||||
directly through ``self.``, which simplifies the handling of inheritance between classes.
|
||||
|
||||
**An example**:
|
||||
|
||||
There are many class inheritance relationships in ``manimlib/mobject/geometry.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Line 279
|
||||
class Circle(Arc):
|
||||
CONFIG = {
|
||||
"color": RED,
|
||||
"close_new_points": True,
|
||||
"anchors_span_full_range": False
|
||||
}
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Line 304
|
||||
class Dot(Circle):
|
||||
CONFIG = {
|
||||
"radius": DEFAULT_DOT_RADIUS,
|
||||
"stroke_width": 0,
|
||||
"fill_opacity": 1.0,
|
||||
"color": WHITE
|
||||
}
|
||||
|
||||
The ``Circle`` class uses the key-value pair ``"color": RED`` in the ``CONFIG``
|
||||
dictionary to add the attribute ``self.color``.
|
||||
|
||||
At the same time, the ``Dot`` class also contains the key ``color`` in the
|
||||
``CONFIG`` dictionary, but the value is different. At this time, the priority will
|
||||
modify the attribute ``self.color`` to ``WHITE``.
|
||||
|
||||
CONFIG nesting
|
||||
--------------
|
||||
|
||||
The ``CONFIG`` dictionary supports nesting, that is, the value of the key is also
|
||||
a dictionary, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Camera(object):
|
||||
CONFIG = {
|
||||
# configs
|
||||
}
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Scene(object):
|
||||
CONFIG = {
|
||||
"window_config": {},
|
||||
"camera_class": Camera,
|
||||
"camera_config": {},
|
||||
"file_writer_config": {},
|
||||
# other configs
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
# some lines
|
||||
self.camera = self.camera_class(**self.camera_config)
|
||||
|
||||
The ``CONFIG`` dictionary of the ``Camera`` class contains many key-value pairs,
|
||||
and this class needs to be instantiated in the ``Scene`` class. For more convenient
|
||||
control, there is a special key-value pair in the Scene class ``"camera_config": {}``,
|
||||
Its value is a dictionary, passed in as ``kwargs`` when initializing the ``Camera`` class
|
||||
to modify the value of the properties of the ``Camera`` class.
|
||||
|
||||
So the nesting of the ``CONFIG`` dictionary **essentially** passes in the value as ``kwargs``.
|
||||
|
||||
Common usage
|
||||
------------
|
||||
|
||||
When writing a class by yourself, you can add attributes or modify the attributes
|
||||
of the parent class through ``CONFIG``.
|
||||
|
||||
The most commonly used is to modify the properties of the camera when writing a ``Scene``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class YourScene(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"background_color": WHITE,
|
||||
},
|
||||
}
|
||||
|
||||
For example, the above dictionary will change the background color to white, etc.
|
89
docs/source/getting_started/configuration.rst
Normal file
89
docs/source/getting_started/configuration.rst
Normal file
|
@ -0,0 +1,89 @@
|
|||
CLI flags and configuration
|
||||
===========================
|
||||
|
||||
Command Line Interface
|
||||
----------------------
|
||||
|
||||
To run manim, you need to enter the directory at the same level as ``manimlib/``
|
||||
and enter the command in the following format into terminal:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl <code>.py <Scene> <flags>
|
||||
# or
|
||||
manim-render <code>.py <Scene> <flags>
|
||||
|
||||
- ``<code>.py`` : The python file you wrote. Needs to be at the same level as ``manimlib/``, otherwise you need to use an absolute path or a relative path.
|
||||
- ``<Scene>`` : The scene you want to render here. If it is not written or written incorrectly, it will list all for you to choose. And if there is only one ``Scene`` in the file, this class will be rendered directly.
|
||||
- ``<flags>`` : CLI flags.
|
||||
|
||||
Some useful flags
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
- ``-w`` to write the scene to a file.
|
||||
- ``-o`` to write the scene to a file and open the result.
|
||||
- ``-s`` to skip to the end and just show the final frame.
|
||||
|
||||
- ``-so`` will save the final frame to an image and show it.
|
||||
|
||||
- ``-n <number>`` to skip ahead to the ``n``\ ’th animation of a scene.
|
||||
- ``-f`` to make the playback window fullscreen.
|
||||
|
||||
All supported flags
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
========================================================== ====== =================================================================================================================================================================================================
|
||||
flag abbr function
|
||||
========================================================== ====== =================================================================================================================================================================================================
|
||||
``--help`` ``-h`` Show the help message and exit
|
||||
``--write_file`` ``-w`` Render the scene as a movie file
|
||||
``--skip_animations`` ``-s`` Skip to the last frame
|
||||
``--low_quality`` ``-l`` Render at a low quality (for faster rendering)
|
||||
``--medium_quality`` ``-m`` Render at a medium quality
|
||||
``--hd`` Render at a 1080p quality
|
||||
``--uhd`` Render at a 4k quality
|
||||
``--full_screen`` ``-f`` Show window in full screen
|
||||
``--save_pngs`` ``-g`` Save each frame as a png
|
||||
``--save_as_gif`` ``-i`` Save the video as gif
|
||||
``--transparent`` ``-t`` Render to a movie file with an alpha channel
|
||||
``--quiet`` ``-q``
|
||||
``--write_all`` ``-a`` Write all the scenes from a file
|
||||
``--open`` ``-o`` Automatically open the saved file once its done
|
||||
``--finder`` Show the output file in finder
|
||||
``--config`` Guide for automatic configuration
|
||||
``--file_name FILE_NAME`` Name for the movie or image file
|
||||
``--start_at_animation_number START_AT_ANIMATION_NUMBER`` ``-n`` Start rendering not from the first animation, but from another, specified by its index. If you passin two comma separated values, e.g. "3,6", it will end the rendering at the second value.
|
||||
``--resolution RESOLUTION`` ``-r`` Resolution, passed as "WxH", e.g. "1920x1080"
|
||||
``--frame_rate FRAME_RATE`` Frame rate, as an integer
|
||||
``--color COLOR`` ``-c`` Background color
|
||||
``--leave_progress_bars`` Leave progress bars displayed in terminal
|
||||
``--video_dir VIDEO_DIR`` directory to write video
|
||||
========================================================== ====== =================================================================================================================================================================================================
|
||||
|
||||
custom_config
|
||||
--------------
|
||||
|
||||
In order to perform more configuration (about directories, etc.) and permanently
|
||||
change the default value (you don't have to add flags to the command every time),
|
||||
you can modify ``custom_config.yml``. The meaning of each option is in
|
||||
page :doc:`../documentation/custom_config`.
|
||||
|
||||
You can also use different ``custom_config.yml`` for different directories, such as
|
||||
following the directory structure:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
manim/
|
||||
├── manimlib/
|
||||
│ ├── animation/
|
||||
│ ├── ...
|
||||
│ ├── default_config.yml
|
||||
│ └── window.py
|
||||
├── project/
|
||||
│ ├── code.py
|
||||
│ └── custom_config.yml
|
||||
└── custom_config.yml
|
||||
|
||||
When you enter the ``project/`` folder and run ``manimgl code.py <Scene>``,
|
||||
it will overwrite ``manim/custom_config.yml`` with ``custom_config.yml``
|
||||
in the ``project`` folder.
|
719
docs/source/getting_started/example_scenes.rst
Normal file
719
docs/source/getting_started/example_scenes.rst
Normal file
|
@ -0,0 +1,719 @@
|
|||
Example Scenes
|
||||
==============
|
||||
|
||||
After understanding the previous knowledge, we can understand more scenes.
|
||||
Many example scenes are given in ``example_scenes.py``, let's start with
|
||||
the simplest and one by one.
|
||||
|
||||
InteractiveDevlopment
|
||||
---------------------
|
||||
|
||||
.. manim-example:: InteractiveDevlopment
|
||||
:media: ../_static/example_scenes/InteractiveDevlopment.mp4
|
||||
|
||||
from manimlib import *
|
||||
|
||||
class InteractiveDevlopment(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
square = Square()
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.wait()
|
||||
|
||||
# This opens an iPython termnial where you can keep writing
|
||||
# lines as if they were part of this construct method.
|
||||
# In particular, 'square', 'circle' and 'self' will all be
|
||||
# part of the local namespace in that terminal.
|
||||
self.embed()
|
||||
|
||||
# Try copying and pasting some of the lines below into
|
||||
# the interactive shell
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
self.wait()
|
||||
self.play(circle.animate.stretch(4, 0))
|
||||
self.play(Rotate(circle, 90 * DEGREES))
|
||||
self.play(circle.animate.shift(2 * RIGHT).scale(0.25))
|
||||
|
||||
text = Text("""
|
||||
In general, using the interactive shell
|
||||
is very helpful when developing new scenes
|
||||
""")
|
||||
self.play(Write(text))
|
||||
|
||||
# In the interactive shell, you can just type
|
||||
# play, add, remove, clear, wait, save_state and restore,
|
||||
# instead of self.play, self.add, self.remove, etc.
|
||||
|
||||
# To interact with the window, type touch(). You can then
|
||||
# scroll in the window, or zoom by holding down 'z' while scrolling,
|
||||
# and change camera perspective by holding down 'd' while moving
|
||||
# the mouse. Press 'r' to reset to the standard camera position.
|
||||
# Press 'q' to stop interacting with the window and go back to
|
||||
# typing new commands into the shell.
|
||||
|
||||
# In principle you can customize a scene to be responsive to
|
||||
# mouse and keyboard interactions
|
||||
always(circle.move_to, self.mouse_point)
|
||||
|
||||
This scene is similar to what we wrote in :doc:`quickstart`.
|
||||
And how to interact has been written in the comments.
|
||||
No more explanation here.
|
||||
|
||||
AnimatingMethods
|
||||
----------------
|
||||
|
||||
.. manim-example:: AnimatingMethods
|
||||
:media: ../_static/example_scenes/AnimatingMethods.mp4
|
||||
|
||||
class AnimatingMethods(Scene):
|
||||
def construct(self):
|
||||
grid = Tex(r"\pi").get_grid(10, 10, height=4)
|
||||
self.add(grid)
|
||||
|
||||
# You can animate the application of mobject methods with the
|
||||
# ".animate" syntax:
|
||||
self.play(grid.animate.shift(LEFT))
|
||||
|
||||
# Alternatively, you can use the older syntax by passing the
|
||||
# method and then the arguments to the scene's "play" function:
|
||||
self.play(grid.shift, LEFT)
|
||||
|
||||
# Both of those will interpolate between the mobject's initial
|
||||
# state and whatever happens when you apply that method.
|
||||
# For this example, calling grid.shift(LEFT) would shift the
|
||||
# grid one unit to the left, but both of the previous calls to
|
||||
# "self.play" animate that motion.
|
||||
|
||||
# The same applies for any method, including those setting colors.
|
||||
self.play(grid.animate.set_color(YELLOW))
|
||||
self.wait()
|
||||
self.play(grid.animate.set_submobject_colors_by_gradient(BLUE, GREEN))
|
||||
self.wait()
|
||||
self.play(grid.animate.set_height(TAU - MED_SMALL_BUFF))
|
||||
self.wait()
|
||||
|
||||
# The method Mobject.apply_complex_function lets you apply arbitrary
|
||||
# complex functions, treating the points defining the mobject as
|
||||
# complex numbers.
|
||||
self.play(grid.animate.apply_complex_function(np.exp), run_time=5)
|
||||
self.wait()
|
||||
|
||||
# Even more generally, you could apply Mobject.apply_function,
|
||||
# which takes in functions form R^3 to R^3
|
||||
self.play(
|
||||
grid.animate.apply_function(
|
||||
lambda p: [
|
||||
p[0] + 0.5 * math.sin(p[1]),
|
||||
p[1] + 0.5 * math.sin(p[0]),
|
||||
p[2]
|
||||
]
|
||||
),
|
||||
run_time=5,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
The new usage in this scene is ``.get_grid()`` and ``self.play(mob.animate.method(args))``.
|
||||
|
||||
- ``.get_grid()`` method will return a new mobject containing multiple copies of this one arranged in a grid.
|
||||
- ``self.play(mob.animate.method(args))`` animates the method, and the details are in the comments above.
|
||||
|
||||
TextExample
|
||||
-----------
|
||||
|
||||
.. manim-example:: TextExample
|
||||
:media: ../_static/example_scenes/TextExample.mp4
|
||||
|
||||
class TextExample(Scene):
|
||||
def construct(self):
|
||||
text = Text("Here is a text", font="Consolas", font_size=90)
|
||||
difference = Text(
|
||||
"""
|
||||
The most important difference between Text and TexText is that\n
|
||||
you can change the font more easily, but can't use the LaTeX grammar
|
||||
""",
|
||||
font="Arial", font_size=24,
|
||||
t2c={"Text": BLUE, "TexText": BLUE, "LaTeX": ORANGE}
|
||||
)
|
||||
VGroup(text, difference).arrange(DOWN, buff=1)
|
||||
self.play(Write(text))
|
||||
self.play(FadeIn(difference, UP))
|
||||
self.wait(3)
|
||||
|
||||
fonts = Text(
|
||||
"And you can also set the font according to different words",
|
||||
font="Arial",
|
||||
t2f={"font": "Consolas", "words": "Consolas"},
|
||||
t2c={"font": BLUE, "words": GREEN}
|
||||
)
|
||||
slant = Text(
|
||||
"And the same as slant and weight",
|
||||
font="Consolas",
|
||||
t2s={"slant": ITALIC},
|
||||
t2w={"weight": BOLD},
|
||||
t2c={"slant": ORANGE, "weight": RED}
|
||||
)
|
||||
VGroup(fonts, slant).arrange(DOWN, buff=0.8)
|
||||
self.play(FadeOut(text), FadeOut(difference, shift=DOWN))
|
||||
self.play(Write(fonts))
|
||||
self.wait()
|
||||
self.play(Write(slant))
|
||||
self.wait()
|
||||
|
||||
The new classes in this scene are ``Text``, ``VGroup``, ``Write``, ``FadeIn`` and ``FadeOut``.
|
||||
|
||||
- ``Text`` can create text, define fonts, etc. The usage ais clearly reflected in the above examples.
|
||||
- ``VGroup`` can put multiple ``VMobject`` together as a whole. In the example, the ``.arrange()`` method is called to arrange the sub-mobjects in sequence downward (``DOWN``), and the spacing is ``buff``.
|
||||
- ``Write`` is an animation that shows similar writing effects.
|
||||
- ``FadeIn`` fades the object in, the second parameter indicates the direction of the fade in.
|
||||
- ``FadeOut`` fades out the object, the second parameter indicates the direction of the fade out.
|
||||
|
||||
TexTransformExample
|
||||
-------------------
|
||||
|
||||
.. manim-example:: TexTransformExample
|
||||
:media: ../_static/example_scenes/TexTransformExample.mp4
|
||||
|
||||
class TexTransformExample(Scene):
|
||||
def construct(self):
|
||||
to_isolate = ["B", "C", "=", "(", ")"]
|
||||
lines = VGroup(
|
||||
# Surrounding substrings with double braces
|
||||
# will ensure that those parts are separated
|
||||
# out in the Tex. For example, here the
|
||||
# Tex will have 5 submobjects, corresponding
|
||||
# to the strings [A^2, +, B^2, =, C^2]
|
||||
Tex("{{A^2}} + {{B^2}} = {{C^2}}"),
|
||||
Tex("{{A^2}} = {{C^2}} - {{B^2}}"),
|
||||
# Alternatively, you can pass in the keyword argument
|
||||
# "isolate" with a list of strings that should be out as
|
||||
# their own submobject. So both lines below are equivalent
|
||||
# to what you'd get by wrapping every instance of "B", "C"
|
||||
# "=", "(" and ")" with double braces
|
||||
Tex("{{A^2}} = (C + B)(C - B)", isolate=to_isolate),
|
||||
Tex("A = \\sqrt{(C + B)(C - B)}", isolate=to_isolate)
|
||||
)
|
||||
lines.arrange(DOWN, buff=LARGE_BUFF)
|
||||
for line in lines:
|
||||
line.set_color_by_tex_to_color_map({
|
||||
"A": BLUE,
|
||||
"B": TEAL,
|
||||
"C": GREEN,
|
||||
})
|
||||
|
||||
play_kw = {"run_time": 2}
|
||||
self.add(lines[0])
|
||||
# The animation TransformMatchingTex will line up parts
|
||||
# of the source and target which have matching tex strings.
|
||||
# Here, giving it a little path_arc makes each part sort of
|
||||
# rotate into their final positions, which feels appropriate
|
||||
# for the idea of rearranging an equation
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
lines[0].copy(), lines[1],
|
||||
path_arc=90 * DEGREES,
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Now, we could try this again on the next line...
|
||||
self.play(
|
||||
TransformMatchingTex(lines[1].copy(), lines[2]),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
# ...and this looks nice enough, but since there's no tex
|
||||
# in lines[2] which matches "C^2" or "B^2", those terms fade
|
||||
# out to nothing while the C and B terms fade in from nothing.
|
||||
# If, however, we want the C^2 to go to C, and B^2 to go to B,
|
||||
# we can specify that with a key map.
|
||||
self.play(FadeOut(lines[2]))
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
lines[1].copy(), lines[2],
|
||||
key_map={
|
||||
"C^2": "C",
|
||||
"B^2": "B",
|
||||
}
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# And to finish off, a simple TransformMatchingShapes would work
|
||||
# just fine. But perhaps we want that exponent on A^2 to transform into
|
||||
# the square root symbol. At the moment, lines[2] treats the expression
|
||||
# A^2 as a unit, so we might create a new version of the same line which
|
||||
# separates out just the A. This way, when TransformMatchingTex lines up
|
||||
# all matching parts, the only mismatch will be between the "^2" from
|
||||
# new_line2 and the "\sqrt" from the final line. By passing in,
|
||||
# transform_mismatches=True, it will transform this "^2" part into
|
||||
# the "\sqrt" part.
|
||||
new_line2 = Tex("{{A}}^2 = (C + B)(C - B)", isolate=to_isolate)
|
||||
new_line2.replace(lines[2])
|
||||
new_line2.match_style(lines[2])
|
||||
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
new_line2, lines[3],
|
||||
transform_mismatches=True,
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeOut(lines, RIGHT))
|
||||
|
||||
# Alternatively, if you don't want to think about breaking up
|
||||
# the tex strings deliberately, you can TransformMatchingShapes,
|
||||
# which will try to line up all pieces of a source mobject with
|
||||
# those of a target, regardless of the submobject hierarchy in
|
||||
# each one, according to whether those pieces have the same
|
||||
# shape (as best it can).
|
||||
source = Text("the morse code", height=1)
|
||||
target = Text("here come dots", height=1)
|
||||
|
||||
self.play(Write(source))
|
||||
self.wait()
|
||||
kw = {"run_time": 3, "path_arc": PI / 2}
|
||||
self.play(TransformMatchingShapes(source, target, **kw))
|
||||
self.wait()
|
||||
self.play(TransformMatchingShapes(target, source, **kw))
|
||||
self.wait()
|
||||
|
||||
The new classes in this scene are ``Tex``, ``TexText``, ``TransformMatchingTex``
|
||||
and ``TransformMatchingShapes``.
|
||||
|
||||
- ``Tex`` uses LaTeX to create mathematical formulas.
|
||||
- ``TexText`` uses LaTeX to create text.
|
||||
- ``TransformMatchingTeX`` automatically transforms sub-objects according to the similarities and differences of tex in ``Tex``.
|
||||
- ``TransformMatchingShapes`` automatically transform sub-objects directly based on the similarities and differences of the object point sets.
|
||||
|
||||
UpdatersExample
|
||||
---------------
|
||||
|
||||
.. manim-example:: UpdatersExample
|
||||
:media: ../_static/example_scenes/UpdatersExample.mp4
|
||||
|
||||
class UpdatersExample(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
square.set_fill(BLUE_E, 1)
|
||||
|
||||
# On all all frames, the constructor Brace(square, UP) will
|
||||
# be called, and the mobject brace will set its data to match
|
||||
# that of the newly constructed object
|
||||
brace = always_redraw(Brace, square, UP)
|
||||
|
||||
text, number = label = VGroup(
|
||||
Text("Width = "),
|
||||
DecimalNumber(
|
||||
0,
|
||||
show_ellipsis=True,
|
||||
num_decimal_places=2,
|
||||
include_sign=True,
|
||||
)
|
||||
)
|
||||
label.arrange(RIGHT)
|
||||
|
||||
# This ensures that the method deicmal.next_to(square)
|
||||
# is called on every frame
|
||||
always(label.next_to, brace, UP)
|
||||
# You could also write the following equivalent line
|
||||
# label.add_updater(lambda m: m.next_to(brace, UP))
|
||||
|
||||
# If the argument itself might change, you can use f_always,
|
||||
# for which the arguments following the initial Mobject method
|
||||
# should be functions returning arguments to that method.
|
||||
# The following line ensures thst decimal.set_value(square.get_y())
|
||||
# is called every frame
|
||||
f_always(number.set_value, square.get_width)
|
||||
# You could also write the following equivalent line
|
||||
# number.add_updater(lambda m: m.set_value(square.get_width()))
|
||||
|
||||
self.add(square, brace, label)
|
||||
|
||||
# Notice that the brace and label track with the square
|
||||
self.play(
|
||||
square.animate.scale(2),
|
||||
rate_func=there_and_back,
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
square.set_width(5, stretch=True),
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
square.animate.set_width(2),
|
||||
run_time=3
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# In general, you can alway call Mobject.add_updater, and pass in
|
||||
# a function that you want to be called on every frame. The function
|
||||
# should take in either one argument, the mobject, or two arguments,
|
||||
# the mobject and the amount of time since the last frame.
|
||||
now = self.time
|
||||
w0 = square.get_width()
|
||||
square.add_updater(
|
||||
lambda m: m.set_width(w0 * math.cos(self.time - now))
|
||||
)
|
||||
self.wait(4 * PI)
|
||||
|
||||
The new classes and usage in this scene are ``always_redraw()``, ``DecimalNumber``, ``.to_edge()``,
|
||||
``.center()``, ``always()``, ``f_always()``, ``.set_y()`` and ``.add_updater()``.
|
||||
|
||||
- ``always_redraw()`` function create a new mobject every frame.
|
||||
- ``DecimalNumber`` is a variable number, speed it up by breaking it into ``Text`` characters.
|
||||
- ``.to_edge()`` means to place the object on the edge of the screen.
|
||||
- ``.center()`` means to place the object in the center of the screen.
|
||||
- ``always(f, x)`` means that a certain function (``f(x)``) is executed every frame.
|
||||
- ``f_always(f, g)`` is similar to ``always``, executed ``f(g())`` every frame.
|
||||
- ``.set_y()`` means to set the ordinate of the object on the screen.
|
||||
- ``.add_updater()`` sets an update function for the object. For example: ``mob1.add_updater(lambda mob: mob.next_to(mob2))`` means ``mob1.next_to(mob2)`` is executed every frame.
|
||||
|
||||
CoordinateSystemExample
|
||||
-----------------------
|
||||
|
||||
.. manim-example:: CoordinateSystemExample
|
||||
:media: ../_static/example_scenes/CoordinateSystemExample.mp4
|
||||
|
||||
class CoordinateSystemExample(Scene):
|
||||
def construct(self):
|
||||
axes = Axes(
|
||||
# x-axis ranges from -1 to 10, with a default step size of 1
|
||||
x_range=(-1, 10),
|
||||
# y-axis ranges from -2 to 10 with a step size of 0.5
|
||||
y_range=(-2, 2, 0.5),
|
||||
# The axes will be stretched so as to match the specified
|
||||
# height and width
|
||||
height=6,
|
||||
width=10,
|
||||
# Axes is made of two NumberLine mobjects. You can specify
|
||||
# their configuration with axis_config
|
||||
axis_config={
|
||||
"stroke_color": GREY_A,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
# Alternatively, you can specify configuration for just one
|
||||
# of them, like this.
|
||||
y_axis_config={
|
||||
"include_tip": False,
|
||||
}
|
||||
)
|
||||
# Keyword arguments of add_coordinate_labels can be used to
|
||||
# configure the DecimalNumber mobjects which it creates and
|
||||
# adds to the axes
|
||||
axes.add_coordinate_labels(
|
||||
font_size=20,
|
||||
num_decimal_places=1,
|
||||
)
|
||||
self.add(axes)
|
||||
|
||||
# Axes descends from the CoordinateSystem class, meaning
|
||||
# you can call call axes.coords_to_point, abbreviated to
|
||||
# axes.c2p, to associate a set of coordinates with a point,
|
||||
# like so:
|
||||
dot = Dot(color=RED)
|
||||
dot.move_to(axes.c2p(0, 0))
|
||||
self.play(FadeIn(dot, scale=0.5))
|
||||
self.play(dot.animate.move_to(axes.c2p(3, 2)))
|
||||
self.wait()
|
||||
self.play(dot.animate.move_to(axes.c2p(5, 0.5)))
|
||||
self.wait()
|
||||
|
||||
# Similarly, you can call axes.point_to_coords, or axes.p2c
|
||||
# print(axes.p2c(dot.get_center()))
|
||||
|
||||
# We can draw lines from the axes to better mark the coordinates
|
||||
# of a given point.
|
||||
# Here, the always_redraw command means that on each new frame
|
||||
# the lines will be redrawn
|
||||
h_line = always_redraw(lambda: axes.get_h_line(dot.get_left()))
|
||||
v_line = always_redraw(lambda: axes.get_v_line(dot.get_bottom()))
|
||||
|
||||
self.play(
|
||||
ShowCreation(h_line),
|
||||
ShowCreation(v_line),
|
||||
)
|
||||
self.play(dot.animate.move_to(axes.c2p(3, -2)))
|
||||
self.wait()
|
||||
self.play(dot.animate.move_to(axes.c2p(1, 1)))
|
||||
self.wait()
|
||||
|
||||
# If we tie the dot to a particular set of coordinates, notice
|
||||
# that as we move the axes around it respects the coordinate
|
||||
# system defined by them.
|
||||
f_always(dot.move_to, lambda: axes.c2p(1, 1))
|
||||
self.play(
|
||||
axes.animate.scale(0.75),
|
||||
axes.animate.to_corner(UL),
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOut(VGroup(axes, dot, h_line, v_line)))
|
||||
|
||||
# Other coordinate systems you can play around with include
|
||||
# ThreeDAxes, NumberPlane, and ComplexPlane.
|
||||
|
||||
|
||||
GraphExample
|
||||
------------
|
||||
|
||||
.. manim-example:: GraphExample
|
||||
:media: ../_static/example_scenes/GraphExample.mp4
|
||||
|
||||
class GraphExample(Scene):
|
||||
def construct(self):
|
||||
axes = Axes((-3, 10), (-1, 8))
|
||||
axes.add_coordinate_labels()
|
||||
|
||||
self.play(Write(axes, lag_ratio=0.01, run_time=1))
|
||||
|
||||
# Axes.get_graph will return the graph of a function
|
||||
sin_graph = axes.get_graph(
|
||||
lambda x: 2 * math.sin(x),
|
||||
color=BLUE,
|
||||
)
|
||||
# By default, it draws it so as to somewhat smoothly interpolate
|
||||
# between sampled points (x, f(x)). If the graph is meant to have
|
||||
# a corner, though, you can set use_smoothing to False
|
||||
relu_graph = axes.get_graph(
|
||||
lambda x: max(x, 0),
|
||||
use_smoothing=False,
|
||||
color=YELLOW,
|
||||
)
|
||||
# For discontinuous functions, you can specify the point of
|
||||
# discontinuity so that it does not try to draw over the gap.
|
||||
step_graph = axes.get_graph(
|
||||
lambda x: 2.0 if x > 3 else 1.0,
|
||||
discontinuities=[3],
|
||||
color=GREEN,
|
||||
)
|
||||
|
||||
# Axes.get_graph_label takes in either a string or a mobject.
|
||||
# If it's a string, it treats it as a LaTeX expression. By default
|
||||
# it places the label next to the graph near the right side, and
|
||||
# has it match the color of the graph
|
||||
sin_label = axes.get_graph_label(sin_graph, "\\sin(x)")
|
||||
relu_label = axes.get_graph_label(relu_graph, Text("ReLU"))
|
||||
step_label = axes.get_graph_label(step_graph, Text("Step"), x=4)
|
||||
|
||||
self.play(
|
||||
ShowCreation(sin_graph),
|
||||
FadeIn(sin_label, RIGHT),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ReplacementTransform(sin_graph, relu_graph),
|
||||
FadeTransform(sin_label, relu_label),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(relu_graph, step_graph),
|
||||
FadeTransform(relu_label, step_label),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
parabola = axes.get_graph(lambda x: 0.25 * x**2)
|
||||
parabola.set_stroke(BLUE)
|
||||
self.play(
|
||||
FadeOut(step_graph),
|
||||
FadeOut(step_label),
|
||||
ShowCreation(parabola)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# You can use axes.input_to_graph_point, abbreviated
|
||||
# to axes.i2gp, to find a particular point on a graph
|
||||
dot = Dot(color=RED)
|
||||
dot.move_to(axes.i2gp(2, parabola))
|
||||
self.play(FadeIn(dot, scale=0.5))
|
||||
|
||||
# A value tracker lets us animate a parameter, usually
|
||||
# with the intent of having other mobjects update based
|
||||
# on the parameter
|
||||
x_tracker = ValueTracker(2)
|
||||
f_always(
|
||||
dot.move_to,
|
||||
lambda: axes.i2gp(x_tracker.get_value(), parabola)
|
||||
)
|
||||
|
||||
self.play(x_tracker.animate.set_value(4), run_time=3)
|
||||
self.play(x_tracker.animate.set_value(-2), run_time=3)
|
||||
self.wait()
|
||||
|
||||
SurfaceExample
|
||||
--------------
|
||||
|
||||
.. manim-example:: SurfaceExample
|
||||
:media: ../_static/example_scenes/SurfaceExample.mp4
|
||||
|
||||
class SurfaceExample(Scene):
|
||||
CONFIG = {
|
||||
"camera_class": ThreeDCamera,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
surface_text = Text("For 3d scenes, try using surfaces")
|
||||
surface_text.fix_in_frame()
|
||||
surface_text.to_edge(UP)
|
||||
self.add(surface_text)
|
||||
self.wait(0.1)
|
||||
|
||||
torus1 = Torus(r1=1, r2=1)
|
||||
torus2 = Torus(r1=3, r2=1)
|
||||
sphere = Sphere(radius=3, resolution=torus1.resolution)
|
||||
# You can texture a surface with up to two images, which will
|
||||
# be interpreted as the side towards the light, and away from
|
||||
# the light. These can be either urls, or paths to a local file
|
||||
# in whatever you've set as the image directory in
|
||||
# the custom_config.yml file
|
||||
|
||||
# day_texture = "EarthTextureMap"
|
||||
# night_texture = "NightEarthTextureMap"
|
||||
day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
|
||||
night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg"
|
||||
|
||||
surfaces = [
|
||||
TexturedSurface(surface, day_texture, night_texture)
|
||||
for surface in [sphere, torus1, torus2]
|
||||
]
|
||||
|
||||
for mob in surfaces:
|
||||
mob.shift(IN)
|
||||
mob.mesh = SurfaceMesh(mob)
|
||||
mob.mesh.set_stroke(BLUE, 1, opacity=0.5)
|
||||
|
||||
# Set perspective
|
||||
frame = self.camera.frame
|
||||
frame.set_euler_angles(
|
||||
theta=-30 * DEGREES,
|
||||
phi=70 * DEGREES,
|
||||
)
|
||||
|
||||
surface = surfaces[0]
|
||||
|
||||
self.play(
|
||||
FadeIn(surface),
|
||||
ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
|
||||
)
|
||||
for mob in surfaces:
|
||||
mob.add(mob.mesh)
|
||||
surface.save_state()
|
||||
self.play(Rotate(surface, PI / 2), run_time=2)
|
||||
for mob in surfaces[1:]:
|
||||
mob.rotate(PI / 2)
|
||||
|
||||
self.play(
|
||||
Transform(surface, surfaces[1]),
|
||||
run_time=3
|
||||
)
|
||||
|
||||
self.play(
|
||||
Transform(surface, surfaces[2]),
|
||||
# Move camera frame during the transition
|
||||
frame.animate.increment_phi(-10 * DEGREES),
|
||||
frame.animate.increment_theta(-20 * DEGREES),
|
||||
run_time=3
|
||||
)
|
||||
# Add ambient rotation
|
||||
frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))
|
||||
|
||||
# Play around with where the light is
|
||||
light_text = Text("You can move around the light source")
|
||||
light_text.move_to(surface_text)
|
||||
light_text.fix_in_frame()
|
||||
|
||||
self.play(FadeTransform(surface_text, light_text))
|
||||
light = self.camera.light_source
|
||||
self.add(light)
|
||||
light.save_state()
|
||||
self.play(light.animate.move_to(3 * IN), run_time=5)
|
||||
self.play(light.animate.shift(10 * OUT), run_time=5)
|
||||
|
||||
drag_text = Text("Try moving the mouse while pressing d or s")
|
||||
drag_text.move_to(light_text)
|
||||
drag_text.fix_in_frame()
|
||||
|
||||
self.play(FadeTransform(light_text, drag_text))
|
||||
self.wait()
|
||||
|
||||
This scene shows an example of using a three-dimensional surface, and
|
||||
the related usage has been briefly described in the notes.
|
||||
|
||||
- ``.fix_in_frame()`` makes the object not change with the view angle of the screen, and is always displayed at a fixed position on the screen.
|
||||
|
||||
OpeningManimExample
|
||||
-------------------
|
||||
|
||||
.. manim-example:: OpeningManimExample
|
||||
:media: ../_static/example_scenes/OpeningManimExample.mp4
|
||||
|
||||
|
||||
class OpeningManimExample(Scene):
|
||||
def construct(self):
|
||||
intro_words = Text("""
|
||||
The original motivation for manim was to
|
||||
better illustrate mathematical functions
|
||||
as transformations.
|
||||
""")
|
||||
intro_words.to_edge(UP)
|
||||
|
||||
self.play(Write(intro_words))
|
||||
self.wait(2)
|
||||
|
||||
# Linear transform
|
||||
grid = NumberPlane((-10, 10), (-5, 5))
|
||||
matrix = [[1, 1], [0, 1]]
|
||||
linear_transform_words = VGroup(
|
||||
Text("This is what the matrix"),
|
||||
IntegerMatrix(matrix, include_background_rectangle=True),
|
||||
Text("looks like")
|
||||
)
|
||||
linear_transform_words.arrange(RIGHT)
|
||||
linear_transform_words.to_edge(UP)
|
||||
linear_transform_words.set_stroke(BLACK, 10, background=True)
|
||||
|
||||
self.play(
|
||||
ShowCreation(grid),
|
||||
FadeTransform(intro_words, linear_transform_words)
|
||||
)
|
||||
self.wait()
|
||||
self.play(grid.animate.apply_matrix(matrix), run_time=3)
|
||||
self.wait()
|
||||
|
||||
# Complex map
|
||||
c_grid = ComplexPlane()
|
||||
moving_c_grid = c_grid.copy()
|
||||
moving_c_grid.prepare_for_nonlinear_transform()
|
||||
c_grid.set_stroke(BLUE_E, 1)
|
||||
c_grid.add_coordinate_labels(font_size=24)
|
||||
complex_map_words = TexText("""
|
||||
Or thinking of the plane as $\\mathds{C}$,\\\\
|
||||
this is the map $z \\rightarrow z^2$
|
||||
""")
|
||||
complex_map_words.to_corner(UR)
|
||||
complex_map_words.set_stroke(BLACK, 5, background=True)
|
||||
|
||||
self.play(
|
||||
FadeOut(grid),
|
||||
Write(c_grid, run_time=3),
|
||||
FadeIn(moving_c_grid),
|
||||
FadeTransform(linear_transform_words, complex_map_words),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
moving_c_grid.animate.apply_complex_function(lambda z: z**2),
|
||||
run_time=6,
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
This scene is a comprehensive application of a two-dimensional scene.
|
||||
|
||||
After seeing these scenes, you have already understood part of the
|
||||
usage of manim. For more examples, see `the video code of 3b1b <https://github.com/3b1b/videos>`_.
|
|
@ -1,18 +0,0 @@
|
|||
Getting Started
|
||||
===============
|
||||
|
||||
Todd Zimmerman put together `a very nice tutorial`_ on getting started with
|
||||
``manim``, which has been updated to run on python 3.7. Note that you'll want
|
||||
to change `from big_ol_pile_of_manim_imports import *` to `from
|
||||
manimlib.imports import *` to work with the current codebase.
|
||||
|
||||
.. _a very nice tutorial: https://talkingphysics.wordpress.com/2019/01/08/getting-started-animating-with-manim-and-python-3-7/
|
||||
|
||||
.. toctree::
|
||||
:caption: Contents
|
||||
:maxdepth: 2
|
||||
|
||||
learning_by_example
|
||||
mathematical_objects
|
||||
animating_mobjects
|
||||
making_a_scene
|
69
docs/source/getting_started/installation.rst
Normal file
69
docs/source/getting_started/installation.rst
Normal file
|
@ -0,0 +1,69 @@
|
|||
Installation
|
||||
============
|
||||
|
||||
Manim runs on Python 3.6 or higher (Python 3.8 is recommended).
|
||||
|
||||
System requirements are:
|
||||
|
||||
- `FFmpeg <https://ffmpeg.org/>`__
|
||||
- `OpenGL <https://www.opengl.org//>`__ (included in python package ``PyOpenGL``)
|
||||
- `LaTeX <https://www.latex-project.org>`__ (optional, if you want to use LaTeX)
|
||||
- `Pango <https://pango.org>`__ (only for Linux)
|
||||
|
||||
|
||||
Directly
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Install manimgl
|
||||
pip install manimgl
|
||||
|
||||
# Try it out
|
||||
manimgl
|
||||
|
||||
If you want to hack on manimlib itself, clone this repository and in
|
||||
that directory execute:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Install python requirements
|
||||
pip install -e .
|
||||
|
||||
# Try it out
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
# or
|
||||
manim-render example_scenes.py OpeningManimExample
|
||||
|
||||
If you run the above command and no error message appears,
|
||||
then you have successfully installed all the environments required by manim.
|
||||
|
||||
Directly (Windows)
|
||||
------------------
|
||||
|
||||
1. `Install
|
||||
FFmpeg <https://www.wikihow.com/Install-FFmpeg-on-Windows>`__, and make sure that its path is in the PATH environment variable.
|
||||
2. Install a LaTeX distribution.
|
||||
`TeXLive-full <http://tug.org/texlive/>`__ is recommended.
|
||||
3. Install the remaining Python packages.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
pip install -e .
|
||||
manimgl example_scenes.py OpeningManimExample
|
||||
|
||||
For Anaconda
|
||||
------------
|
||||
|
||||
- Install FFmpeg and LaTeX as above.
|
||||
- Create a conda environment using
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://github.com/3b1b/manim.git
|
||||
cd manim
|
||||
conda create -n manim python=3.8
|
||||
conda activate manim
|
||||
pip install -e .
|
|
@ -1,131 +0,0 @@
|
|||
Learning by Example
|
||||
===================
|
||||
|
||||
SquareToCircle
|
||||
--------------
|
||||
|
||||
``example_scenes.py`` contains simple examples that we can use to learn about manim.
|
||||
|
||||
Go ahead and try out the ``SquareToCircle`` scene by running it with ``$ manim example_scenes.py SquareToCircle -p``
|
||||
in manim directory.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
square = Square()
|
||||
square.flip(RIGHT)
|
||||
square.rotate(-3 * TAU / 8)
|
||||
circle.set_fill(PINK, opacity=0.5)
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.play(Transform(square, circle))
|
||||
self.play(FadeOut(square))
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video width="560" height="315" controls>
|
||||
<source src="../_static/SquareToCircle.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The flag ``-p`` plays the rendered video with default video player.
|
||||
|
||||
Other frequently used flags are:
|
||||
|
||||
* ``-l`` for rendering video in lower resolution (which renders faster)
|
||||
* ``-s`` to show the last frame of the video.
|
||||
|
||||
Run ``manim -h`` all the available flags (``python -m manim -h`` if you installed it to a venv)
|
||||
|
||||
|
||||
Let's step through each line of ``SquareToCircle``
|
||||
|
||||
.. code-block:: python
|
||||
:lineno-start: 3
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
|
||||
You create videos in manim by writing :class:`~scene.scene.Scene` classes.
|
||||
|
||||
Each :class:`~scene.scene.Scene` in manim is self-contained. That means everything
|
||||
you created under this scene does not exist outside the class.
|
||||
|
||||
.. code-block:: python
|
||||
:lineno-start: 4
|
||||
|
||||
def construct(self):
|
||||
|
||||
:meth:`~scene.scene.Scene.construct` specifies what is displayed on the screen
|
||||
when the :class:`~scene.scene.Scene` is rendered to video.
|
||||
|
||||
.. code-block:: python
|
||||
:lineno-start: 5
|
||||
|
||||
circle = Circle()
|
||||
square = Square()
|
||||
|
||||
``Circle()`` and ``Square()`` create :class:`~mobject.geometry.Circle` and :class:`~mobject.geometry.Square`.
|
||||
|
||||
Both of these are instances of :class:`~mobject.mobject.Mobject` subclasses, the base class for objects in manim. Note
|
||||
that instantiating a :class:`~mobject.mobject.Mobject` does not add it to the
|
||||
:class:`~scene.scene.Scene`, so you wouldn't see anything if you were to render
|
||||
the :class:`~scene.scene.Scene` at this point.
|
||||
|
||||
.. code-block:: python
|
||||
:lineno-start: 7
|
||||
|
||||
square.flip(RIGHT)
|
||||
square.rotate(-3 * TAU / 8)
|
||||
circle.set_fill(PINK, opacity=0.5)
|
||||
|
||||
``flip()`` ``rotate()`` ``set_fill()`` apply various modifications to the mobjects before animating
|
||||
them. The call to :meth:`~mobject.mobject.Mobject.flip` flips the
|
||||
:class:`~mobject.geometry.Square` across the RIGHT vector. This is equivalent
|
||||
to a refection across the x-axis.
|
||||
|
||||
The call to :meth:`~mobject.mobject.Mobject.rotate` rotates the
|
||||
:class:`~mobject.geometry.Square` 3/8ths of a full rotation counterclockwise.
|
||||
|
||||
The call to :meth:`~mobject.mobject.Mobject.set_fill` sets
|
||||
the fill color for the :class:`~mobject.geometry.Circle` to pink, and its opacity to 0.5.
|
||||
|
||||
.. code-block:: python
|
||||
:lineno-start: 11
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.play(Transform(square, circle))
|
||||
self.play(FadeOut(square))
|
||||
|
||||
To generated animation, :class:`~animation.animation.Animation` classes are used.
|
||||
|
||||
Each :class:`~animation.animation.Animation` takes one or more :class:`~mobject.mobject.Mobject` instances as arguments, which it animates
|
||||
when passed to :meth:`~scene.scene.Scene.play`. This is how video is typically
|
||||
created in manim.
|
||||
|
||||
:class:`~mobject.mobject.Mobject` instances are automatically
|
||||
added to the :class:`~scene.scene.Scene` when they are animated. You can add a
|
||||
:class:`~mobject.mobject.Mobject` to the :class:`~scene.scene.Scene` manually
|
||||
by passing it as an argument to :meth:`~scene.scene.Scene.add`.
|
||||
|
||||
|
||||
:class:`~animation.creation.ShowCreation` draws a :class:`~mobject.mobject.Mobject` to the screen.
|
||||
|
||||
:class:`~animation.transform.Transform` morphs one :class:`~mobject.mobject.Mobject` into another.
|
||||
|
||||
:class:`~animation.creation.FadeOut` fades a :class:`~mobject.mobject.Mobject` out of the :class:`~scene.scene.Scene`.
|
||||
|
||||
.. note::
|
||||
|
||||
Only the first argument to :class:`~animation.transform.Transform` is modified,
|
||||
the second is not added to the :class:`~scene.scene.Scene`. :class:`~animation.tranform.Transform`
|
||||
only changes the appearance but not the underlying properties.
|
||||
|
||||
After the call to ``transform()`` ``square`` is still a :class:`~mobject.geometry.Square` instance
|
||||
but with the shape of :class:`~mobject.geometry.Circle`.
|
|
@ -1,15 +0,0 @@
|
|||
Making a Scene
|
||||
==============
|
||||
|
||||
A scene is what renders when manim is executed. Each scene contains mobjects, which can then be animated as
|
||||
previously explained. In code, a scene is a class that extends ``Scene`` and implements the ``construct``
|
||||
function, like so. Manim will execute this function to render the scene.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from manimlib.imports import *
|
||||
|
||||
class ExampleScene(Scene):
|
||||
def construct(self):
|
||||
# Add and animate mobjects here
|
|
@ -1,13 +0,0 @@
|
|||
Mathematical Objects
|
||||
====================
|
||||
|
||||
Everything that appears on screen in a manim video is a
|
||||
:class:`~mobject.mobject.Mobject`, or Mathematical Object. A
|
||||
:class:`~mobject.mobject.Mobject`'s appearance is determined by 3
|
||||
factors:
|
||||
|
||||
* ``m.points``, an Nx3 ``numpy.array`` specifying how to draw ``m``
|
||||
* ``m``'s style attributes, such as ``m.color``, ``m.stroke_width``, and
|
||||
``m.fill_opacity``
|
||||
* ``m.submobjects``, a list of :class:`~mobject.mobject.Mobject` instances that
|
||||
are considered part of ``m``
|
256
docs/source/getting_started/quickstart.rst
Normal file
256
docs/source/getting_started/quickstart.rst
Normal file
|
@ -0,0 +1,256 @@
|
|||
Quick Start
|
||||
===========
|
||||
|
||||
After installing the manim environment according to the instructions on the
|
||||
:doc:`installation` page, you can try to make a scene yourself from scratch.
|
||||
|
||||
First, create a new ``.py`` file (such as ``start.py``) according to the following
|
||||
directory structure:
|
||||
|
||||
.. code-block:: text
|
||||
:emphasize-lines: 8
|
||||
|
||||
manim/
|
||||
├── manimlib/
|
||||
│ ├── animation/
|
||||
│ ├── ...
|
||||
│ ├── default_config.yml
|
||||
│ └── window.py
|
||||
├── custom_config.yml
|
||||
└── start.py
|
||||
|
||||
And paste the following code (I will explain the function of each line in detail later):
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from manimlib import *
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
|
||||
self.add(circle)
|
||||
|
||||
And run this command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl start.py SquareToCircle
|
||||
|
||||
A window will pop up on the screen. And then you can :
|
||||
|
||||
- scroll the middle mouse button to move the screen up and down
|
||||
- hold down the :kbd:`z` on the keyboard while scrolling the middle mouse button to zoom the screen
|
||||
- hold down the :kbd:`s` key on the keyboard and move the mouse to pan the screen
|
||||
- hold down the :kbd:`d` key on the keyboard and move the mouse to change the three-dimensional perspective.
|
||||
|
||||
Finally, you can close the window and exit the program by pressing :kbd:`q`.
|
||||
|
||||
Run this command again:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl start.py SquareToCircle -os
|
||||
|
||||
At this time, no window will pop up. When the program is finished, this rendered
|
||||
image will be automatically opened (saved in the subdirectory ``images/`` of the same
|
||||
level directory of ``start.py`` by default):
|
||||
|
||||
.. image:: ../_static/quickstart/SquareToCircle.png
|
||||
:align: center
|
||||
|
||||
Make an image
|
||||
-------------
|
||||
|
||||
Next, let's take a detailed look at what each row does.
|
||||
|
||||
**Line 1**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from manimlib import *
|
||||
|
||||
This will import all the classes that may be used when using manim.
|
||||
|
||||
**Line 3**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
|
||||
Create a :class:`Scene` subclass ``SquareToCircle``, which will be
|
||||
the scene you write and render.
|
||||
|
||||
**Line 4**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def construct(self):
|
||||
|
||||
Write the ``construct()`` method, the content of which will determine
|
||||
how to create the mobjects in the screen and what operations need to be performed.
|
||||
|
||||
**Line 5**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
circle = Circle()
|
||||
|
||||
Create a circle (an instance of the :class:`Circle` class), called ``circle``
|
||||
|
||||
**Line 6~7**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
|
||||
Set the circle style by calling the circle's method.
|
||||
|
||||
- The ``.set_fill()`` method sets the fill color of this circle to blue (``BLUE``, defined in :doc:`../documentation/constants`), and the fill transparency to 0.5.
|
||||
- The ``.set_stroke()`` method sets the stroke color of this circle to dark blue (``BLUE_E``, defined in :doc:`../documentation/constants`), and the stroke width to 4.
|
||||
|
||||
**Line 9**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
self.add(circle)
|
||||
|
||||
Add this circle to the screen through the ``.add()`` method of :class:`Scene`.
|
||||
|
||||
Add animations
|
||||
--------------
|
||||
|
||||
Let's change some codes and add some animations to make videos instead of just pictures.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
from manimlib import *
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
square = Square()
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.wait()
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
self.wait()
|
||||
|
||||
Run this command this time:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl start.py SquareToCircle
|
||||
|
||||
The pop-up window will play animations of drawing a square and transforming
|
||||
it into a circle. If you want to save this video, run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl start.py SquareToCircle -o
|
||||
|
||||
This time there will be no pop-up window, but the video file (saved in the subdirectory
|
||||
``videos/`` of the same level directory of ``start.py`` by default) will be automatically
|
||||
opened after the operation is over:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video class="manim-video" controls loop autoplay src="../_static/quickstart/SquareToCircle.mp4"></video>
|
||||
|
||||
Let's take a look at the code this time. The first 7 lines are the same as the previous
|
||||
ones, and the 8th line is similar to the 5th line, which creates an instance of the
|
||||
:class:`Square` class and named it ``square``.
|
||||
|
||||
**Line 10**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
|
||||
An animation is played through :class:`Scene`'s ``.play()`` method. :class:`ShowCreation`
|
||||
is an animation that shows the process of creating a given mobject.
|
||||
``self.play(ShowCreation(square))`` is to play the animation of creating ``square``.
|
||||
|
||||
**Line 11**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
self.wait()
|
||||
|
||||
Use :class:`Scene`'s ``.wait()`` method to pause (default 1s), you can pass in
|
||||
parameters to indicate the pause time (for example, ``self.wait(3)`` means pause for 3s).
|
||||
|
||||
**Line 12**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
|
||||
Play the animation that transforms ``square`` into ``circle``.
|
||||
``ReplacementTransform(A, B)`` means to transform A into B's pattern and replace A with B.
|
||||
|
||||
**Line 13**: Same as line 11, pause for 1s.
|
||||
|
||||
|
||||
Enable interaction
|
||||
------------------
|
||||
|
||||
Interaction is a new feature of the new version. You can add the following line
|
||||
at the end of the code to enable interaction:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
self.embed()
|
||||
|
||||
Then run ``manimgl start.py SquareToCircle``.
|
||||
|
||||
After the previous animation is executed, the ipython terminal will be opened on
|
||||
the command line. After that, you can continue to write code in it, and the statement
|
||||
you entered will be executed immediately after pressing :kbd:`Enter`.
|
||||
|
||||
For example: input the following lines (without comment lines) into it respectively
|
||||
(``self.play`` can be abbreviated as ``play`` in this mode):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Stretched 4 times in the vertical direction
|
||||
play(circle.animate.stretch(4, dim=0}))
|
||||
# Rotate the ellipse 90°
|
||||
play(Rotate(circle, TAU / 4))
|
||||
# Move 2 units to the right and shrink to 1/4 of the original
|
||||
play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
|
||||
# Insert 10 curves into circle for non-linear transformation (no animation will play)
|
||||
circle.insert_n_curves(10)
|
||||
# Apply a complex transformation of f(z)=z^2 to all points on the circle
|
||||
play(circle.animate.apply_complex_function(lambda z: z**2))
|
||||
# Close the window and exit the program
|
||||
exit()
|
||||
|
||||
You will get an animation similar to the following:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<video class="manim-video" controls loop autoplay src="../_static/quickstart/SquareToCircleEmbed.mp4"></video>
|
||||
|
||||
If you want to enter the interactive mode directly, you don't have to write an
|
||||
empty scene containing only ``self.embed()``, you can directly run the following command
|
||||
(this will enter the ipython terminal while the window pops up):
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
manimgl
|
||||
|
||||
You succeeded!
|
||||
--------------
|
||||
|
||||
After reading the above content, you already know how to use manim.
|
||||
Below you can see some examples, in the :doc:`example_scenes` page.
|
||||
But before that, you'd better have a look at the :doc:`configuration` of manim.
|
||||
|
127
docs/source/getting_started/structure.rst
Normal file
127
docs/source/getting_started/structure.rst
Normal file
|
@ -0,0 +1,127 @@
|
|||
Manim's structure
|
||||
=================
|
||||
|
||||
|
||||
Manim's directory structure
|
||||
---------------------------
|
||||
|
||||
The manim directory looks very complicated, with a lot of files,
|
||||
but the structure is clear.
|
||||
|
||||
Below is the directory structure of manim:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
manimlib/ # manim library
|
||||
├── __init__.py
|
||||
├── __main__.py
|
||||
├── default_config.yml # Default configuration file
|
||||
├── config.py # Process CLI flags
|
||||
├── constants.py # Defined some constants
|
||||
├── extract_scene.py # Extract and run the scene
|
||||
├── shader_wrapper.py # Shaders' Wrapper for convenient control
|
||||
├── window.py # Playback window
|
||||
├── tex_templates/ # Templates preset for LaTeX
|
||||
│ ├── tex_templates.tex # Tex template (will be compiled with latex, default)
|
||||
│ └── ctex_templates.tex # Tex template that support Chinese (will be compiled with xelatex)
|
||||
├── camera/
|
||||
│ └── camera.py # Including Camera and CameraFrame
|
||||
├── scene/
|
||||
│ ├── scene_file_writer.py # Used to write scene to video file
|
||||
│ ├── scene.py # The basic Scene class
|
||||
│ ├── three_d_scene.py # Three-dimensional scene
|
||||
│ ├── sample_space_scene.py # Probability related sample space scene
|
||||
│ └── vector_space_scene.py # Vector field scene
|
||||
├── animation/
|
||||
│ ├── animation.py # The basic class of animation
|
||||
│ ├── composition.py # Animation group
|
||||
│ ├── creation.py # Animation related to Create
|
||||
│ ├── fading.py # Fade related animation
|
||||
│ ├── growing.py # Animation related to Grow
|
||||
│ ├── indication.py # Some animations for emphasis
|
||||
│ ├── movement.py # Animation related to movement
|
||||
│ ├── numbers.py # Realize changes to DecimalNumber
|
||||
│ ├── rotation.py # Animation related to rotation
|
||||
│ ├── specialized.py # Some uncommon animations for special projects
|
||||
│ ├── transform_matching_parts.py # Transform which can automatically match parts
|
||||
│ ├── transform.py # Some Transforms
|
||||
│ └── update.py # Realize update from function
|
||||
├── mobject/
|
||||
│ ├── mobject.py # The basic class of all math object
|
||||
│ ├── types/ # 4 types of mobject
|
||||
│ │ ├── dot_cloud.py # Dot cloud (an subclass of PMobject)
|
||||
│ │ ├── image_mobject.py # Insert pictures
|
||||
│ │ ├── point_cloud_mobject.py # PMobject (mobject composed of points)
|
||||
│ │ ├── surface.py # ParametricSurface
|
||||
│ │ └── vectorized_mobject.py # VMobject (vectorized mobject)
|
||||
│ ├── svg/ # mobject related to svg
|
||||
│ │ ├── svg_mobject.py # SVGMobject
|
||||
│ │ ├── brace.py # Brace
|
||||
│ │ ├── drawings.py # Some special mobject of svg image
|
||||
│ │ ├── tex_mobject.py # Tex and TexText implemented by LaTeX
|
||||
│ │ └── text_mobject.py # Text implemented by manimpango
|
||||
│ ├── changing.py # Dynamically changing mobject
|
||||
│ ├── coordinate_systems.py # coordinate system
|
||||
│ ├── frame.py # mobject related to frame
|
||||
│ ├── functions.py # ParametricFunction
|
||||
│ ├── geometry.py # geometry mobjects
|
||||
│ ├── matrix.py # matrix
|
||||
│ ├── mobject_update_utils.py # some defined updater
|
||||
│ ├── number_line.py # Number line
|
||||
│ ├── numbers.py # Numbers that can be changed
|
||||
│ ├── probability.py # mobject related to probability
|
||||
│ ├── shape_matchers.py # mobject adapted to the size of other objects
|
||||
│ ├── three_dimensions.py # Three-dimensional objects
|
||||
│ ├── value_tracker.py # ValueTracker which storage number
|
||||
│ └── vector_field.py # VectorField
|
||||
├── once_useful_constructs/ # 3b1b's Common scenes written for some videos
|
||||
│ └── ...
|
||||
├── shaders/ # GLSL scripts for rendering
|
||||
│ ├── simple_vert.glsl # a simple glsl script for position
|
||||
│ ├── insert/ # glsl scripts to be inserted in other glsl scripts
|
||||
│ │ ├── NOTE.md # explain how to insert glsl scripts
|
||||
│ │ └── ... # useful scripts
|
||||
│ ├── image/ # glsl for images
|
||||
│ │ └── ... # containing shaders for vertex and fragment
|
||||
│ ├── quadratic_bezier_fill/ # glsl for the fill of quadratic bezier curve
|
||||
│ │ └── ... # containing shaders for vertex, fragment and geometry
|
||||
│ ├── quadratic_bezier_stroke/ # glsl for the stroke of quadratic bezier curve
|
||||
│ │ └── ... # containing shaders for vertex, fragment and geometry
|
||||
│ ├── surface/ # glsl for surfaces
|
||||
│ │ └── ... # containing shaders for vertex and fragment
|
||||
│ ├── textured_surface/ # glsl for textured_surface
|
||||
│ │ └── ... # containing shaders for vertex and fragment
|
||||
│ └── true_dot/ # glsl for a dot
|
||||
│ └── ... # containing shaders for vertex, fragment and geometry
|
||||
└── utils/ # Some useful utility functions
|
||||
├── bezier.py # For bezier curve
|
||||
├── color.py # For color
|
||||
├── config_ops.py # Process CONFIG
|
||||
├── customization.py # Read from custom_config.yml
|
||||
├── debug.py # Utilities for debugging in program
|
||||
├── family_ops.py # Process family members
|
||||
├── file_ops.py # Process files and directories
|
||||
├── images.py # Read image
|
||||
├── init_config.py # Configuration guide
|
||||
├── iterables.py # Functions related to list/dictionary processing
|
||||
├── paths.py # Curve path
|
||||
├── rate_functions.py # Some defined rate_functions
|
||||
├── simple_functions.py # Some commonly used functions
|
||||
├── sounds.py # Process sounds
|
||||
├── space_ops.py # Space coordinate calculation
|
||||
├── strings.py # Process strings
|
||||
└── tex_file_writing.py # Use LaTeX to write strings as svg
|
||||
|
||||
Inheritance structure of manim's classes
|
||||
----------------------------------------
|
||||
|
||||
`Here <https://github.com/3b1b/manim/files/5824383/manim_shaders_structure.pdf>`_
|
||||
is a pdf showed inheritance structure of manim's classes, large,
|
||||
but basically all classes have included:
|
||||
|
||||
.. image:: ../_static/manim_shaders_structure.png
|
||||
|
||||
Manim execution process
|
||||
-----------------------
|
||||
|
||||
.. image:: ../_static/manim_shaders_process_en.png
|
144
docs/source/getting_started/whatsnew.rst
Normal file
144
docs/source/getting_started/whatsnew.rst
Normal file
|
@ -0,0 +1,144 @@
|
|||
What's new
|
||||
==========
|
||||
|
||||
Usage changes of new version manim
|
||||
----------------------------------
|
||||
|
||||
There are many changes in the new version of manim, and here are only the changes that
|
||||
may have an impact at the code writing level.
|
||||
|
||||
Some of the changes here may not have any major impact on the use, and some changes
|
||||
that affect the use are not mentioned below.
|
||||
|
||||
This document is for reference only, see the source code for details.
|
||||
|
||||
- ``Animation``
|
||||
|
||||
- Added ``Fade`` as the parent class of ``FadeIn`` and ``FadeOut``
|
||||
- ``FadeIn`` and ``FadeOut`` can be passed in ``shift`` and ``scale`` parameters
|
||||
- Deleted ``FadeInFrom, FadeInFromDown, FadeOutAndShift, FadeOutAndShiftDown, FadeInFromLarge``, these can be used ``FadeIn, FadeOut`` to achieve the same effect more easily
|
||||
- Added ``FadeTransform`` to cross fade between two objects, and subclass ``FadeTransformPieces``
|
||||
- Added ``CountInFrom(decimal_mob, source_number=0)`` to count ``decimal_mob`` from ``source_number`` to the current value
|
||||
- ``Rotating`` can directly pass in ``angle`` and ``axis`` without writing keywords ``angle=, axis=``
|
||||
- ``Rotate`` has become a subclass of ``Rotating``, and the distortion effect in ``Transform`` will not appear
|
||||
- Removed ``MoveCar`` animation
|
||||
- Added ``TransformMatchingShapes(mobject, target_mobject)`` and ``TransformMatchingTex(mobject, target_mobject)``
|
||||
|
||||
- ``Camera``
|
||||
|
||||
- Removed all camera classes except ``Camera`` (``MappingCamera``, ``MovingCamera``, ``MultiCamera``) and all functions in ``ThreeDCamera``
|
||||
- Implemented ``CameraFrame`` (as a ``Mobject``)
|
||||
|
||||
- Can be called by ``self.camera.frame`` in ``Scene``
|
||||
- All methods of ``Mobject`` can be used, such as ``.shift()``, ``.scale()``, etc.
|
||||
- Call ``.to_default_state()`` to place in the default position
|
||||
- Set the Euler angles of the camera by ``.set_euler_angles(theta, phi, gamma)``
|
||||
- Set three single Euler angles by ``.set_theta(theta)``, ``.set_phi(phi)``, ``.set_gamma(gamma)``
|
||||
- Use ``.increment_theta(dtheta)``, ``.increment_phi(dphi)``, ``.increment_gamma(gamma)`` to increase the three Euler angles by a certain value. Can be used to realize automatic rotation ``self.camera.frame.add_updater(lambda mob, dt: mob.increment_theta(0.1 * dt))``
|
||||
|
||||
- ``Camera`` adds a light source, which is a ``Point``, which can be called by ``self.camera.light_source`` in ``Scene`` to move and so on. The default position is ``(- 10, 10, 10)``
|
||||
|
||||
- Delete ``Container``
|
||||
- ``Mobject``
|
||||
|
||||
- ``svg`` related
|
||||
|
||||
- Added ``Checkmark`` and ``Exmark``
|
||||
- Some unnecessary classes have been removed from ``drawings.py``
|
||||
- Removed ``Code`` and ``Paragraph`` (by mistake)
|
||||
- ``TexMobject`` is renamed to ``Tex``, ``TextMobject`` is renamed to ``TexText``
|
||||
- ``font_size`` has been added to ``Tex``, ``TexText`` and ``Text``
|
||||
- ``Tex`` and ``TexText`` added ``isolate``, which is a list, which will be automatically split
|
||||
|
||||
- Mobject ``types``
|
||||
|
||||
- Added a new class ``Surface``, which is the parent class of ``ParametricSurface`` and ``TexturedSurface``.
|
||||
- Added the group ``SGroup`` for ``Surface``
|
||||
- Added ``TexturedSurface(uv_surface, image_file, dark_image_file=None)``, where ``uv_surface`` is a ``Surface``, ``image_file`` is the image to be posted, and ``dark_image_file`` is the image to be posted in the dark (default and ``image_file`` is the same)
|
||||
- Deleted ``Mobject1D``, ``Mobject2D``, ``PointCloudDot``
|
||||
- Added ``DotCloud`` (a ``PMobject``), which has been greatly optimized
|
||||
- Removed ``AbstractImageMobject``, ``ImageMobjectFromCamera``
|
||||
- Removed ``sheen`` from ``VMobject``
|
||||
|
||||
- ``Mobject``
|
||||
|
||||
- Added ``gloss`` and ``shadow``, which are the numbers between ``[0, 1]`` respectively. There are four methods of ``.get_gloss()``, ``.set_gloss(gloss)``, ``.get_shadow()``, ``.set_shadow(shadow)``
|
||||
- Added ``.get_grid(n_rows, n_cols)`` to copy into grid
|
||||
- Added ``.set_color_by_code(glsl_code)`` to use GLSL code to change the color
|
||||
- Added ``.set_color_by_xyz_func(glsl_snippet, min_value=-5.0, max_value=5.0, colormap="viridis")`` to pass in GLSL expression in the form of ``x,y,z``, the return value should be a floating point number
|
||||
|
||||
- Coordinate system (including ``Axes``, ``ThreeDAxes``, ``NumberPlane``, ``ComplexPlane``)
|
||||
|
||||
- No longer use ``x_min``, ``x_max``, ``y_min``, ``y_max``, but use ``x_range``, ``y_range`` as a ``np.array()``, containing three numbers ``np.array([ Minimum, maximum, step size])``
|
||||
- Added the abbreviation ``.i2gp(x, graph)`` of ``.input_to_graph_point(x, graph)``
|
||||
- Added some functions of the original ``GraphScene``
|
||||
|
||||
- Added ``.get_v_line(point)``, ``.get_h_line(point)`` to return the line from ``point`` to the two coordinate axes, and specify the line type through the keyword argument of ``line_func`` (default ``DashedLine``)
|
||||
- Added ``.get_graph_label(graph, label, x, direction, buff, color)`` to return the label added to the image
|
||||
- Added ``.get_v_line_to_graph(x, graph)``, ``.get_h_line_to_graph(x, graph)`` to return the line from the point with the abscissa of ``x`` on the ``graph`` to the two- axis line
|
||||
- Added ``.angle_of_tangent(x, graph, dx=EPSILON)``, returns the inclination angle of ``graph`` at ``x``
|
||||
- Added ``.slope_of_tangent(x, graph, dx=EPSILON)``, returns the slope of tangent line of ``graph`` at ``x``
|
||||
- Added ``.get_tangent_line(x, graph, length=5)`` to return the tangent line of ``graph`` at ``x``
|
||||
- Added ``.get_riemann_rectangles(graph, x_range, dx, input_sample_type, ...)`` to return Riemann rectangles (a ``VGroup``)
|
||||
|
||||
- The attribute ``number_line_config`` of ``Axes`` is renamed to ``axis_config``
|
||||
- ``Axes`` original ``.get_coordinate_labels(x_values, y_values)`` method was renamed to ``.add_coordinate_labels(x_values, y_values)`` (but it is not added to the screen)
|
||||
- ``.add_coordinate_labels(numbers)`` of ``ComplexPlane`` will directly add the coordinates to the screen
|
||||
|
||||
- ``NumberLine``
|
||||
|
||||
- No longer use ``x_min``, ``x_max``, ``tick_frequency``, but use ``x_range``, which is an array containing three numbers ``[min, max, step]``
|
||||
- The original ``label_direction`` attribute changed to the ``line_to_number_direction`` attribute
|
||||
- Replace ``tip_width`` and ``tip_height`` with ``tip_config`` (dictionary) attributes
|
||||
- The original ``exclude_zero_from_default`` attribute is modified to the ``numbers_to_exclude`` attribute (default is None)
|
||||
- The original ``.add_tick_marks()`` method was changed to the ``.add_ticks()`` method
|
||||
- Delete the ``.get_number_mobjects(*numbers)`` method, only use the ``.add_numbers(x_values=None, excluding=None)`` method
|
||||
|
||||
- Three-dimensional objects
|
||||
|
||||
- Added ``SurfaceMesh(uv_surface)``, pass in a ``Surface`` to generate its uv mesh
|
||||
- ``ParametricSurface`` no longer uses ``u_min, u_max, v_min, v_max``, but instead uses ``u_range, v_range``, which is a tuple (``(min, max)``), and ``resolution`` can be set larger, don’t worry Speed issue
|
||||
- Added ``Torus``, controlled by ``r1, r2`` keyword parameters
|
||||
- Added ``Cylinder``, controlled by ``height, radius`` keyword parameters
|
||||
- Added ``Line3D`` (extremely thin cylinder), controlled by the ``width`` keyword parameter
|
||||
- Added ``Disk3D``, controlled by ``radius`` keyword parameter
|
||||
- Add ``Square3D``, controlled by ``side_length`` keyword parameter
|
||||
- Improved ``Cube`` and ``Prism``, the usage remains unchanged
|
||||
|
||||
- Other objects
|
||||
|
||||
- ``ParametricFunction`` is renamed to ``ParametricCurve``. Instead of using ``t_min, t_max, step_size``, use ``t_range``, which is an array of three numbers (``[t_min, t_max, step_size]``). ``dt`` was renamed to ``epsilon``. Other usage remains unchanged
|
||||
- All ``TipableVMobject`` can pass in ``tip_length`` to control the style of ``tip``
|
||||
- ``Line`` adds ``.set_points_by_ends(start, end, buff=0, path_arc=0)`` method
|
||||
- ``Line`` added ``.get_projection(point)`` to return the projection position of ``point`` on a straight line
|
||||
- ``Arrow`` adds three attributes of ``thickness, tip_width_ratio, tip_angle``
|
||||
- ``CubicBezier`` is changed to ``a0, h0, h1, a1``, that is, only a third-order Bezier curve is supported
|
||||
- ``Square`` can be initialized directly by passing in ``side_length`` instead of using the keyword ``side_length=``
|
||||
- ``always_redraw(func, *args, **kwargs)`` supports incoming parameters ``*args, **kwargs``
|
||||
- The ``digit_to_digit_buff`` property of ``DecimalNumber`` has been renamed to ``digit_buff_per_font_unit``, and the ``.scale()`` method has been improved
|
||||
- ``ValueTracker`` adds ``value_type`` attribute, the default is ``np.float64``
|
||||
|
||||
- ``Scene``
|
||||
|
||||
- Removed all functions of ``GraphScene`` (moved to ``once_useful_constructs``), ``MovingCameraScene``, ``ReconfigurableScene``, ``SceneFromVideo``, ``ZoomedScene``, and ``ThreeDScene``. Because these can basically be achieved by adjusting ``CameraFrame`` (``self.camera.frame``)
|
||||
- Currently ``SampleSpaceScene`` and ``VectorScene`` have not been changed for the new version, so it is not recommended to use (only ``Scene`` is recommended)
|
||||
- Fix the export of gif, just use the ``-i`` option directly
|
||||
- Added the ``.interact()`` method, during which the mouse and keyboard can be used to continue the interaction, which will be executed by default after the scene ends
|
||||
- Added ``.embed()`` method, open iPython terminal to enter interactive mode
|
||||
- Added ``.save_state()`` method to save the current state of the scene
|
||||
- Added ``.restore()`` method to restore the entire scene to the saved state
|
||||
|
||||
- ``utils``
|
||||
|
||||
- A series of functions related to second-order Bezier have been added to ``utils/bezier.py``
|
||||
- Added a function to read color map from ``matplotlib`` in ``utils/color.py``
|
||||
- Added a series of related functions for processing folders/custom styles/object families
|
||||
- ``resize_array``, ``resize_preserving_order``, ``resize_with_interpolation`` three functions have been added to ``utils/iterables.py``
|
||||
- The definition of ``smooth`` is updated in ``utils/rate_functions.py``
|
||||
- ``clip(a, min_a, max_a)`` function has been added to ``utils/simple_functions.py``
|
||||
- Some functions have been improved in ``utils/space_ops.py``, some functions for space calculation, and functions for processing triangulation have been added
|
||||
|
||||
- ``constants``
|
||||
|
||||
- Fixed the aspect ratio of the screen to 16:9
|
||||
- Deleted the old gray series (``LIGHT_GREY``, ``GREY``, ``DARK_GREY``, ``DARKER_GREY``), added a new series of gray ``GREY_A`` ~ ``GREY_E``
|
|
@ -1,30 +1,36 @@
|
|||
.. Manim documentation master file, created by
|
||||
sphinx-quickstart on Mon May 27 14:19:19 2019.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
Manim's documentation
|
||||
=====================
|
||||
|
||||
Welcome to Manim's documentation!
|
||||
=================================
|
||||
.. image:: ../../logo/white_with_name.png
|
||||
|
||||
These docs are generated from the master branch of the
|
||||
`Manim repo <https://github.com/3b1b/manim>`_. You can contribute by submitting
|
||||
a pull request there.
|
||||
Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as seen in the videos
|
||||
at `3Blue1Brown <https://www.3blue1brown.com/>`_.
|
||||
|
||||
And here is a Chinese version of this documentation: https://manim.ml/shaders
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents
|
||||
:maxdepth: 2
|
||||
:caption: Getting Started
|
||||
|
||||
about
|
||||
installation/index
|
||||
getting_started/index
|
||||
coordinate
|
||||
animation
|
||||
constants
|
||||
getting_started/installation
|
||||
getting_started/quickstart
|
||||
getting_started/configuration
|
||||
getting_started/example_scenes
|
||||
getting_started/config
|
||||
getting_started/structure
|
||||
getting_started/whatsnew
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Documentation
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
documentation/constants
|
||||
documentation/custom_config
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Development
|
||||
|
||||
development/changelog
|
||||
development/contributing
|
||||
development/about
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
Installation
|
||||
============
|
||||
|
||||
Instructions on installing Manim
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents
|
||||
|
||||
linux
|
||||
mac
|
||||
windows
|
|
@ -1,64 +0,0 @@
|
|||
Linux
|
||||
=====
|
||||
|
||||
Ubuntu
|
||||
------
|
||||
|
||||
Install system libraries::
|
||||
|
||||
# apt install sox ffmpeg libcairo2 libcairo2-dev
|
||||
|
||||
Install Latex distribution::
|
||||
|
||||
# apt install texlive-full
|
||||
|
||||
Install manim via pypi::
|
||||
|
||||
# pip3 install manimlib
|
||||
|
||||
OR Install manim via the git repository with venv::
|
||||
|
||||
$ git clone https://github.com/3b1b/manim
|
||||
$ cd manim
|
||||
$ python3 -m venv ./
|
||||
$ source bin/activate
|
||||
$ pip3 install -r requirement.txt
|
||||
|
||||
To use manim in virtual environment you need to activate the environment with
|
||||
the ``activate`` binary by doing ``source bin/activate``, to exit use the ``deactivate`` command.
|
||||
|
||||
.. note:: The git repository is updated first before the one on pypi. The git repository also
|
||||
includes project files used to produce 3b1b videos. Some of the old projects might not
|
||||
work as due to api changes.
|
||||
|
||||
|
||||
.. note:: The required latex packages are dictated by
|
||||
``manimlib/tex_template.tex`` which ``texlive-full`` will satisfy. The download size
|
||||
can be quite large. If you wish to install only the packages required to use
|
||||
manim, substitude ``texlive-full`` with::
|
||||
|
||||
texlive texlive-latex-extra texlive-fonts-extra
|
||||
texlive-latex-recommended texlive-science texlive-fonts-extra tipa
|
||||
|
||||
Arch Linux
|
||||
----------
|
||||
Install system libraries::
|
||||
|
||||
# pacman -S cairo ffmpeg opencv sox
|
||||
|
||||
Install Latex distribution::
|
||||
|
||||
# pacman -S texlive-most
|
||||
|
||||
OR install python-manimlib_:sup:`AUR` package::
|
||||
|
||||
$ git clone https://aur.archlinux.org/python-manimlib.git
|
||||
$ cd python-manimlib
|
||||
$ makepkg -si
|
||||
|
||||
You can use AUR helpers such as yay_:sup:`AUR`::
|
||||
|
||||
$ yay -S python-manimlib
|
||||
|
||||
.. _python-manimlib: https://aur.archlinux.org/packages/python-manimlib/
|
||||
.. _yay: https://aur.archlinux.org/packages/yay/
|
|
@ -1,12 +0,0 @@
|
|||
Mac
|
||||
===
|
||||
|
||||
The simplest way to install the system dependencies on Mac OS X is with Homebrew.
|
||||
Mac come preinstalled with python2, but to use manim, python3 is required
|
||||
|
||||
1. Install python3 https://docs.python.org/3/using/mac.html
|
||||
2. Install Cairo: ``brew install cairo``
|
||||
3. Install Sox: ``brew install sox``
|
||||
4. Install ffmpeg: ``brew install ffmpeg``
|
||||
5. Install latex (MacTeX): ``brew cask install mactex``
|
||||
6. Install manimlib ``pip install manimlib`` (or ``pip install --user manimlib`` to just yourself)
|
|
@ -1,60 +0,0 @@
|
|||
Windows
|
||||
=======
|
||||
|
||||
Install System Libraries
|
||||
------------------------
|
||||
|
||||
Make sure you have *Python 3* for Windows installed first:
|
||||
|
||||
https://www.python.org/downloads/windows/
|
||||
|
||||
Install ffmpeg:
|
||||
|
||||
https://ffmpeg.org/download.html#build-windows
|
||||
|
||||
Install sox:
|
||||
|
||||
http://sox.sourceforge.net/Main/HomePage
|
||||
|
||||
Install a latex distribution. On Windows MikTex is commonly used:
|
||||
|
||||
https://miktex.org/howto/install-miktex
|
||||
|
||||
Path configuration
|
||||
------------------
|
||||
|
||||
To invoke commandline without supplying path to the binary
|
||||
the PATH environment needs to be configured. Below are template examples, please change
|
||||
the path according to your username and specific python version. Assuming all the
|
||||
softwares are installed with no alteration to the installation paths::
|
||||
|
||||
C:\Users\$username\AppData\local\Programs\Python\Python$version\
|
||||
C:\Users\$username\AppData\local\Programs\Python\Python$version\Scripts\
|
||||
C:\MikTex\miktex\bin\x64\
|
||||
C:\ffmpeg\bin\
|
||||
|
||||
The path entries should be separated by semicolon.
|
||||
|
||||
Installing python packages and manim
|
||||
------------------------------------
|
||||
|
||||
Make sure you can start pip using ``pip`` in your commandline. Then do
|
||||
``pip install pyreadline`` for the ``readline`` package.
|
||||
|
||||
Grab the pycairo wheel binary ``pycairo‑1.18.0‑cp37‑cp37m‑win32.whl`` from https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycairo
|
||||
and install it via ``python -m pip install C:\absolute\path\to\the\whl\file``
|
||||
|
||||
clone the manim repository if you have git ``git clone https://github.com/3b1b/manim`` or download the zip file from
|
||||
the repository page with ``Clone or download`` button and unzip it.
|
||||
|
||||
Open the commandline within the manim directory with ``Shift + Right click`` on an empty space in the folder and select ``open command window here``
|
||||
|
||||
Install manim python dependencies with ``pip install -r requirements.txt``
|
||||
|
||||
Test the installation
|
||||
---------------------
|
||||
|
||||
Type in ``python -m manim -h`` and if nothing went wrong during the installation process you should see the help text.
|
||||
|
||||
Use ``python -m manim example_scenes.py SquareToCircle -pl`` to render the example scene and the file should play after rendering. The movie file should be
|
||||
in ``media/videos/example_scenes/480p15``
|
108
docs/source/manim_example_ext.py
Normal file
108
docs/source/manim_example_ext.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
|
||||
|
||||
class skip_manim_node(nodes.Admonition, nodes.Element):
|
||||
pass
|
||||
|
||||
|
||||
def visit(self, node, name=""):
|
||||
self.visit_admonition(node, name)
|
||||
|
||||
|
||||
def depart(self, node):
|
||||
self.depart_admonition(node)
|
||||
|
||||
|
||||
class ManimExampleDirective(Directive):
|
||||
has_content = True
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
option_spec = {
|
||||
"hide_code": bool,
|
||||
"media": str,
|
||||
}
|
||||
final_argument_whitespace = True
|
||||
|
||||
def run(self):
|
||||
hide_code = "hide_code" in self.options
|
||||
scene_name = self.arguments[0]
|
||||
media_file_name = self.options["media"]
|
||||
|
||||
source_block = [
|
||||
".. code-block:: python",
|
||||
"",
|
||||
*[" " + line for line in self.content],
|
||||
]
|
||||
source_block = "\n".join(source_block)
|
||||
|
||||
state_machine = self.state_machine
|
||||
document = state_machine.document
|
||||
|
||||
if any(media_file_name.endswith(ext) for ext in [".png", ".jpg", ".gif"]):
|
||||
is_video = False
|
||||
else:
|
||||
is_video = True
|
||||
|
||||
rendered_template = jinja2.Template(TEMPLATE).render(
|
||||
scene_name=scene_name,
|
||||
scene_name_lowercase=scene_name.lower(),
|
||||
hide_code=hide_code,
|
||||
is_video=is_video,
|
||||
media_file_name=media_file_name,
|
||||
source_block=source_block,
|
||||
)
|
||||
state_machine.insert_input(
|
||||
rendered_template.split("\n"), source=document.attributes["source"]
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_node(skip_manim_node, html=(visit, depart))
|
||||
|
||||
setup.app = app
|
||||
setup.config = app.config
|
||||
setup.confdir = app.confdir
|
||||
|
||||
app.add_directive("manim-example", ManimExampleDirective)
|
||||
|
||||
metadata = {"parallel_read_safe": False, "parallel_write_safe": True}
|
||||
return metadata
|
||||
|
||||
|
||||
TEMPLATE = r"""
|
||||
{% if not hide_code %}
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div class="manim-example">
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if is_video %}
|
||||
.. raw:: html
|
||||
|
||||
<video id="{{ scene_name_lowercase }}" class="manim-video" controls loop autoplay src="{{ media_file_name }}"></video>
|
||||
{% else %}
|
||||
.. image:: {{ media_file_name }}
|
||||
:align: center
|
||||
:name: {{ scene_name_lowercase }}
|
||||
{% endif %}
|
||||
|
||||
{% if not hide_code %}
|
||||
.. raw:: html
|
||||
|
||||
<h5 class="example-header">{{ scene_name }}<a class="headerlink" href="#{{ scene_name_lowercase }}">¶</a></h5>
|
||||
|
||||
{{ source_block }}
|
||||
{% endif %}
|
||||
|
||||
.. raw:: html
|
||||
|
||||
</div>
|
||||
"""
|
|
@ -1,19 +0,0 @@
|
|||
name: manim
|
||||
channels:
|
||||
- defaults
|
||||
- conda-forge
|
||||
dependencies:
|
||||
- python=3.7
|
||||
- cairo
|
||||
- ffmpeg
|
||||
- colour==0.1.5
|
||||
- numpy==1.15.0
|
||||
- pillow==5.2.0
|
||||
- scipy==1.1.0
|
||||
- tqdm==4.24.0
|
||||
- opencv==3.4.2
|
||||
- pycairo==1.18.0
|
||||
- pydub==0.23.0
|
||||
- ffmpeg
|
||||
- pip:
|
||||
- pyreadline
|
|
@ -1,136 +1,674 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from manimlib.imports import *
|
||||
from manimlib import *
|
||||
import numpy as np
|
||||
|
||||
# To watch one of these scenes, run the following:
|
||||
# python -m manim example_scenes.py SquareToCircle -pl
|
||||
#
|
||||
# Use the flat -l for a faster rendering at a lower
|
||||
# quality.
|
||||
# python -m manim example_scenes.py SquareToCircle
|
||||
# Use -s to skip to the end and just save the final frame
|
||||
# Use the -p to have the animation (or image, if -s was
|
||||
# used) pop up once done.
|
||||
# Use -w to write the animation to a file
|
||||
# Use -o to write it to a file and open it once done
|
||||
# Use -n <number> to skip ahead to the n'th animation of a scene.
|
||||
# Use -r <number> to specify a resolution (for example, -r 1080
|
||||
# for a 1920x1080 video)
|
||||
|
||||
|
||||
class OpeningManimExample(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("This is some \\LaTeX")
|
||||
basel = TexMobject(
|
||||
"\\sum_{n=1}^\\infty "
|
||||
"\\frac{1}{n^2} = \\frac{\\pi^2}{6}"
|
||||
intro_words = Text("""
|
||||
The original motivation for manim was to
|
||||
better illustrate mathematical functions
|
||||
as transformations.
|
||||
""")
|
||||
intro_words.to_edge(UP)
|
||||
|
||||
self.play(Write(intro_words))
|
||||
self.wait(2)
|
||||
|
||||
# Linear transform
|
||||
grid = NumberPlane((-10, 10), (-5, 5))
|
||||
matrix = [[1, 1], [0, 1]]
|
||||
linear_transform_words = VGroup(
|
||||
Text("This is what the matrix"),
|
||||
IntegerMatrix(matrix, include_background_rectangle=True),
|
||||
Text("looks like")
|
||||
)
|
||||
VGroup(title, basel).arrange(DOWN)
|
||||
linear_transform_words.arrange(RIGHT)
|
||||
linear_transform_words.to_edge(UP)
|
||||
linear_transform_words.set_stroke(BLACK, 10, background=True)
|
||||
|
||||
self.play(
|
||||
Write(title),
|
||||
FadeInFrom(basel, UP),
|
||||
ShowCreation(grid),
|
||||
FadeTransform(intro_words, linear_transform_words)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
transform_title = TextMobject("That was a transform")
|
||||
transform_title.to_corner(UP + LEFT)
|
||||
self.play(
|
||||
Transform(title, transform_title),
|
||||
LaggedStart(*map(FadeOutAndShiftDown, basel)),
|
||||
)
|
||||
self.play(grid.animate.apply_matrix(matrix), run_time=3)
|
||||
self.wait()
|
||||
|
||||
grid = NumberPlane()
|
||||
grid_title = TextMobject("This is a grid")
|
||||
grid_title.scale(1.5)
|
||||
grid_title.move_to(transform_title)
|
||||
# Complex map
|
||||
c_grid = ComplexPlane()
|
||||
moving_c_grid = c_grid.copy()
|
||||
moving_c_grid.prepare_for_nonlinear_transform()
|
||||
c_grid.set_stroke(BLUE_E, 1)
|
||||
c_grid.add_coordinate_labels(font_size=24)
|
||||
complex_map_words = TexText("""
|
||||
Or thinking of the plane as $\\mathds{C}$,\\\\
|
||||
this is the map $z \\rightarrow z^2$
|
||||
""")
|
||||
complex_map_words.to_corner(UR)
|
||||
complex_map_words.set_stroke(BLACK, 5, background=True)
|
||||
|
||||
self.add(grid, grid_title) # Make sure title is on top of grid
|
||||
self.play(
|
||||
FadeOut(title),
|
||||
FadeInFromDown(grid_title),
|
||||
ShowCreation(grid, run_time=3, lag_ratio=0.1),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
grid_transform_title = TextMobject(
|
||||
"That was a non-linear function \\\\"
|
||||
"applied to the grid"
|
||||
)
|
||||
grid_transform_title.move_to(grid_title, UL)
|
||||
grid.prepare_for_nonlinear_transform()
|
||||
self.play(
|
||||
grid.apply_function,
|
||||
lambda p: p + np.array([
|
||||
np.sin(p[1]),
|
||||
np.sin(p[0]),
|
||||
0,
|
||||
]),
|
||||
run_time=3,
|
||||
FadeOut(grid),
|
||||
Write(c_grid, run_time=3),
|
||||
FadeIn(moving_c_grid),
|
||||
FadeTransform(linear_transform_words, complex_map_words),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Transform(grid_title, grid_transform_title)
|
||||
moving_c_grid.animate.apply_complex_function(lambda z: z**2),
|
||||
run_time=6,
|
||||
)
|
||||
self.wait()
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class SquareToCircle(Scene):
|
||||
class AnimatingMethods(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
square = Square()
|
||||
square.flip(RIGHT)
|
||||
square.rotate(-3 * TAU / 8)
|
||||
circle.set_fill(PINK, opacity=0.5)
|
||||
grid = Tex(r"\pi").get_grid(10, 10, height=4)
|
||||
self.add(grid)
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.play(Transform(square, circle))
|
||||
self.play(FadeOut(square))
|
||||
# You can animate the application of mobject methods with the
|
||||
# ".animate" syntax:
|
||||
self.play(grid.animate.shift(LEFT))
|
||||
|
||||
# Alternatively, you can use the older syntax by passing the
|
||||
# method and then the arguments to the scene's "play" function:
|
||||
self.play(grid.shift, LEFT)
|
||||
|
||||
class WarpSquare(Scene):
|
||||
def construct(self):
|
||||
square = Square()
|
||||
self.play(ApplyPointwiseFunction(
|
||||
lambda point: complex_to_R3(np.exp(R3_to_complex(point))),
|
||||
square
|
||||
))
|
||||
# Both of those will interpolate between the mobject's initial
|
||||
# state and whatever happens when you apply that method.
|
||||
# For this example, calling grid.shift(LEFT) would shift the
|
||||
# grid one unit to the left, but both of the previous calls to
|
||||
# "self.play" animate that motion.
|
||||
|
||||
# The same applies for any method, including those setting colors.
|
||||
self.play(grid.animate.set_color(YELLOW))
|
||||
self.wait()
|
||||
self.play(grid.animate.set_submobject_colors_by_gradient(BLUE, GREEN))
|
||||
self.wait()
|
||||
self.play(grid.animate.set_height(TAU - MED_SMALL_BUFF))
|
||||
self.wait()
|
||||
|
||||
# The method Mobject.apply_complex_function lets you apply arbitrary
|
||||
# complex functions, treating the points defining the mobject as
|
||||
# complex numbers.
|
||||
self.play(grid.animate.apply_complex_function(np.exp), run_time=5)
|
||||
self.wait()
|
||||
|
||||
# Even more generally, you could apply Mobject.apply_function,
|
||||
# which takes in functions form R^3 to R^3
|
||||
self.play(
|
||||
grid.animate.apply_function(
|
||||
lambda p: [
|
||||
p[0] + 0.5 * math.sin(p[1]),
|
||||
p[1] + 0.5 * math.sin(p[0]),
|
||||
p[2]
|
||||
]
|
||||
),
|
||||
run_time=5,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WriteStuff(Scene):
|
||||
class TextExample(Scene):
|
||||
def construct(self):
|
||||
example_text = TextMobject(
|
||||
"This is a some text",
|
||||
tex_to_color_map={"text": YELLOW}
|
||||
# To run this scene properly, you should have "Consolas" font in your computer
|
||||
# for full usage, you can see https://github.com/3b1b/manim/pull/680
|
||||
text = Text("Here is a text", font="Consolas", font_size=90)
|
||||
difference = Text(
|
||||
"""
|
||||
The most important difference between Text and TexText is that\n
|
||||
you can change the font more easily, but can't use the LaTeX grammar
|
||||
""",
|
||||
font="Arial", font_size=24,
|
||||
# t2c is a dict that you can choose color for different text
|
||||
t2c={"Text": BLUE, "TexText": BLUE, "LaTeX": ORANGE}
|
||||
)
|
||||
example_tex = TexMobject(
|
||||
"\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}",
|
||||
)
|
||||
group = VGroup(example_text, example_tex)
|
||||
group.arrange(DOWN)
|
||||
group.set_width(FRAME_WIDTH - 2 * LARGE_BUFF)
|
||||
VGroup(text, difference).arrange(DOWN, buff=1)
|
||||
self.play(Write(text))
|
||||
self.play(FadeIn(difference, UP))
|
||||
self.wait(3)
|
||||
|
||||
self.play(Write(example_text))
|
||||
self.play(Write(example_tex))
|
||||
fonts = Text(
|
||||
"And you can also set the font according to different words",
|
||||
font="Arial",
|
||||
t2f={"font": "Consolas", "words": "Consolas"},
|
||||
t2c={"font": BLUE, "words": GREEN}
|
||||
)
|
||||
fonts.set_width(FRAME_WIDTH - 1)
|
||||
slant = Text(
|
||||
"And the same as slant and weight",
|
||||
font="Consolas",
|
||||
t2s={"slant": ITALIC},
|
||||
t2w={"weight": BOLD},
|
||||
t2c={"slant": ORANGE, "weight": RED}
|
||||
)
|
||||
VGroup(fonts, slant).arrange(DOWN, buff=0.8)
|
||||
self.play(FadeOut(text), FadeOut(difference, shift=DOWN))
|
||||
self.play(Write(fonts))
|
||||
self.wait()
|
||||
self.play(Write(slant))
|
||||
self.wait()
|
||||
|
||||
|
||||
class TexTransformExample(Scene):
|
||||
def construct(self):
|
||||
to_isolate = ["B", "C", "=", "(", ")"]
|
||||
lines = VGroup(
|
||||
# Passing in muliple arguments to Tex will result
|
||||
# in the same expression as if those arguments had
|
||||
# been joined together, except that the submobject
|
||||
# heirarchy of the resulting mobject ensure that the
|
||||
# Tex mobject has a subject corresponding to
|
||||
# each of these strings. For example, the Tex mobject
|
||||
# below will have 5 subjects, corresponding to the
|
||||
# expressions [A^2, +, B^2, =, C^2]
|
||||
Tex("A^2", "+", "B^2", "=", "C^2"),
|
||||
# Likewise here
|
||||
Tex("A^2", "=", "C^2", "-", "B^2"),
|
||||
# Alternatively, you can pass in the keyword argument
|
||||
# "isolate" with a list of strings that should be out as
|
||||
# their own submobject. So the line below is equivalent
|
||||
# to the commented out line below it.
|
||||
Tex("A^2 = (C + B)(C - B)", isolate=["A^2", *to_isolate]),
|
||||
# Tex("A^2", "=", "(", "C", "+", "B", ")", "(", "C", "-", "B", ")"),
|
||||
Tex("A = \\sqrt{(C + B)(C - B)}", isolate=["A", *to_isolate])
|
||||
)
|
||||
lines.arrange(DOWN, buff=LARGE_BUFF)
|
||||
for line in lines:
|
||||
line.set_color_by_tex_to_color_map({
|
||||
"A": BLUE,
|
||||
"B": TEAL,
|
||||
"C": GREEN,
|
||||
})
|
||||
|
||||
play_kw = {"run_time": 2}
|
||||
self.add(lines[0])
|
||||
# The animation TransformMatchingTex will line up parts
|
||||
# of the source and target which have matching tex strings.
|
||||
# Here, giving it a little path_arc makes each part sort of
|
||||
# rotate into their final positions, which feels appropriate
|
||||
# for the idea of rearranging an equation
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
lines[0].copy(), lines[1],
|
||||
path_arc=90 * DEGREES,
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Now, we could try this again on the next line...
|
||||
self.play(
|
||||
TransformMatchingTex(lines[1].copy(), lines[2]),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
# ...and this looks nice enough, but since there's no tex
|
||||
# in lines[2] which matches "C^2" or "B^2", those terms fade
|
||||
# out to nothing while the C and B terms fade in from nothing.
|
||||
# If, however, we want the C^2 to go to C, and B^2 to go to B,
|
||||
# we can specify that with a key map.
|
||||
self.play(FadeOut(lines[2]))
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
lines[1].copy(), lines[2],
|
||||
key_map={
|
||||
"C^2": "C",
|
||||
"B^2": "B",
|
||||
}
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# And to finish off, a simple TransformMatchingShapes would work
|
||||
# just fine. But perhaps we want that exponent on A^2 to transform into
|
||||
# the square root symbol. At the moment, lines[2] treats the expression
|
||||
# A^2 as a unit, so we might create a new version of the same line which
|
||||
# separates out just the A. This way, when TransformMatchingTex lines up
|
||||
# all matching parts, the only mismatch will be between the "^2" from
|
||||
# new_line2 and the "\sqrt" from the final line. By passing in,
|
||||
# transform_mismatches=True, it will transform this "^2" part into
|
||||
# the "\sqrt" part.
|
||||
new_line2 = Tex("A^2 = (C + B)(C - B)", isolate=["A", *to_isolate])
|
||||
new_line2.replace(lines[2])
|
||||
new_line2.match_style(lines[2])
|
||||
|
||||
self.play(
|
||||
TransformMatchingTex(
|
||||
new_line2, lines[3],
|
||||
transform_mismatches=True,
|
||||
),
|
||||
**play_kw
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeOut(lines, RIGHT))
|
||||
|
||||
# Alternatively, if you don't want to think about breaking up
|
||||
# the tex strings deliberately, you can TransformMatchingShapes,
|
||||
# which will try to line up all pieces of a source mobject with
|
||||
# those of a target, regardless of the submobject hierarchy in
|
||||
# each one, according to whether those pieces have the same
|
||||
# shape (as best it can).
|
||||
source = Text("the morse code", height=1)
|
||||
target = Text("here come dots", height=1)
|
||||
|
||||
self.play(Write(source))
|
||||
self.wait()
|
||||
kw = {"run_time": 3, "path_arc": PI / 2}
|
||||
self.play(TransformMatchingShapes(source, target, **kw))
|
||||
self.wait()
|
||||
self.play(TransformMatchingShapes(target, source, **kw))
|
||||
self.wait()
|
||||
|
||||
|
||||
class UpdatersExample(Scene):
|
||||
def construct(self):
|
||||
decimal = DecimalNumber(
|
||||
0,
|
||||
show_ellipsis=True,
|
||||
num_decimal_places=3,
|
||||
include_sign=True,
|
||||
)
|
||||
square = Square().to_edge(UP)
|
||||
square = Square()
|
||||
square.set_fill(BLUE_E, 1)
|
||||
|
||||
decimal.add_updater(lambda d: d.next_to(square, RIGHT))
|
||||
decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))
|
||||
self.add(square, decimal)
|
||||
# On all all frames, the constructor Brace(square, UP) will
|
||||
# be called, and the mobject brace will set its data to match
|
||||
# that of the newly constructed object
|
||||
brace = always_redraw(Brace, square, UP)
|
||||
|
||||
text, number = label = VGroup(
|
||||
Text("Width = "),
|
||||
DecimalNumber(
|
||||
0,
|
||||
show_ellipsis=True,
|
||||
num_decimal_places=2,
|
||||
include_sign=True,
|
||||
)
|
||||
)
|
||||
label.arrange(RIGHT)
|
||||
|
||||
# This ensures that the method deicmal.next_to(square)
|
||||
# is called on every frame
|
||||
always(label.next_to, brace, UP)
|
||||
# You could also write the following equivalent line
|
||||
# label.add_updater(lambda m: m.next_to(brace, UP))
|
||||
|
||||
# If the argument itself might change, you can use f_always,
|
||||
# for which the arguments following the initial Mobject method
|
||||
# should be functions returning arguments to that method.
|
||||
# The following line ensures thst decimal.set_value(square.get_y())
|
||||
# is called every frame
|
||||
f_always(number.set_value, square.get_width)
|
||||
# You could also write the following equivalent line
|
||||
# number.add_updater(lambda m: m.set_value(square.get_width()))
|
||||
|
||||
self.add(square, brace, label)
|
||||
|
||||
# Notice that the brace and label track with the square
|
||||
self.play(
|
||||
square.to_edge, DOWN,
|
||||
square.animate.scale(2),
|
||||
rate_func=there_and_back,
|
||||
run_time=5,
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
square.animate.set_width(5, stretch=True),
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
square.animate.set_width(2),
|
||||
run_time=3
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# See old_projects folder for many, many more
|
||||
# In general, you can alway call Mobject.add_updater, and pass in
|
||||
# a function that you want to be called on every frame. The function
|
||||
# should take in either one argument, the mobject, or two arguments,
|
||||
# the mobject and the amount of time since the last frame.
|
||||
now = self.time
|
||||
w0 = square.get_width()
|
||||
square.add_updater(
|
||||
lambda m: m.set_width(w0 * math.cos(self.time - now))
|
||||
)
|
||||
self.wait(4 * PI)
|
||||
|
||||
|
||||
class CoordinateSystemExample(Scene):
|
||||
def construct(self):
|
||||
axes = Axes(
|
||||
# x-axis ranges from -1 to 10, with a default step size of 1
|
||||
x_range=(-1, 10),
|
||||
# y-axis ranges from -2 to 10 with a step size of 0.5
|
||||
y_range=(-2, 2, 0.5),
|
||||
# The axes will be stretched so as to match the specified
|
||||
# height and width
|
||||
height=6,
|
||||
width=10,
|
||||
# Axes is made of two NumberLine mobjects. You can specify
|
||||
# their configuration with axis_config
|
||||
axis_config={
|
||||
"stroke_color": GREY_A,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
# Alternatively, you can specify configuration for just one
|
||||
# of them, like this.
|
||||
y_axis_config={
|
||||
"include_tip": False,
|
||||
}
|
||||
)
|
||||
# Keyword arguments of add_coordinate_labels can be used to
|
||||
# configure the DecimalNumber mobjects which it creates and
|
||||
# adds to the axes
|
||||
axes.add_coordinate_labels(
|
||||
font_size=20,
|
||||
num_decimal_places=1,
|
||||
)
|
||||
self.add(axes)
|
||||
|
||||
# Axes descends from the CoordinateSystem class, meaning
|
||||
# you can call call axes.coords_to_point, abbreviated to
|
||||
# axes.c2p, to associate a set of coordinates with a point,
|
||||
# like so:
|
||||
dot = Dot(color=RED)
|
||||
dot.move_to(axes.c2p(0, 0))
|
||||
self.play(FadeIn(dot, scale=0.5))
|
||||
self.play(dot.animate.move_to(axes.c2p(3, 2)))
|
||||
self.wait()
|
||||
self.play(dot.animate.move_to(axes.c2p(5, 0.5)))
|
||||
self.wait()
|
||||
|
||||
# Similarly, you can call axes.point_to_coords, or axes.p2c
|
||||
# print(axes.p2c(dot.get_center()))
|
||||
|
||||
# We can draw lines from the axes to better mark the coordinates
|
||||
# of a given point.
|
||||
# Here, the always_redraw command means that on each new frame
|
||||
# the lines will be redrawn
|
||||
h_line = always_redraw(lambda: axes.get_h_line(dot.get_left()))
|
||||
v_line = always_redraw(lambda: axes.get_v_line(dot.get_bottom()))
|
||||
|
||||
self.play(
|
||||
ShowCreation(h_line),
|
||||
ShowCreation(v_line),
|
||||
)
|
||||
self.play(dot.animate.move_to(axes.c2p(3, -2)))
|
||||
self.wait()
|
||||
self.play(dot.animate.move_to(axes.c2p(1, 1)))
|
||||
self.wait()
|
||||
|
||||
# If we tie the dot to a particular set of coordinates, notice
|
||||
# that as we move the axes around it respects the coordinate
|
||||
# system defined by them.
|
||||
f_always(dot.move_to, lambda: axes.c2p(1, 1))
|
||||
self.play(
|
||||
axes.animate.scale(0.75).to_corner(UL),
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOut(VGroup(axes, dot, h_line, v_line)))
|
||||
|
||||
# Other coordinate systems you can play around with include
|
||||
# ThreeDAxes, NumberPlane, and ComplexPlane.
|
||||
|
||||
|
||||
class GraphExample(Scene):
|
||||
def construct(self):
|
||||
axes = Axes((-3, 10), (-1, 8))
|
||||
axes.add_coordinate_labels()
|
||||
|
||||
self.play(Write(axes, lag_ratio=0.01, run_time=1))
|
||||
|
||||
# Axes.get_graph will return the graph of a function
|
||||
sin_graph = axes.get_graph(
|
||||
lambda x: 2 * math.sin(x),
|
||||
color=BLUE,
|
||||
)
|
||||
# By default, it draws it so as to somewhat smoothly interpolate
|
||||
# between sampled points (x, f(x)). If the graph is meant to have
|
||||
# a corner, though, you can set use_smoothing to False
|
||||
relu_graph = axes.get_graph(
|
||||
lambda x: max(x, 0),
|
||||
use_smoothing=False,
|
||||
color=YELLOW,
|
||||
)
|
||||
# For discontinuous functions, you can specify the point of
|
||||
# discontinuity so that it does not try to draw over the gap.
|
||||
step_graph = axes.get_graph(
|
||||
lambda x: 2.0 if x > 3 else 1.0,
|
||||
discontinuities=[3],
|
||||
color=GREEN,
|
||||
)
|
||||
|
||||
# Axes.get_graph_label takes in either a string or a mobject.
|
||||
# If it's a string, it treats it as a LaTeX expression. By default
|
||||
# it places the label next to the graph near the right side, and
|
||||
# has it match the color of the graph
|
||||
sin_label = axes.get_graph_label(sin_graph, "\\sin(x)")
|
||||
relu_label = axes.get_graph_label(relu_graph, Text("ReLU"))
|
||||
step_label = axes.get_graph_label(step_graph, Text("Step"), x=4)
|
||||
|
||||
self.play(
|
||||
ShowCreation(sin_graph),
|
||||
FadeIn(sin_label, RIGHT),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ReplacementTransform(sin_graph, relu_graph),
|
||||
FadeTransform(sin_label, relu_label),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(relu_graph, step_graph),
|
||||
FadeTransform(relu_label, step_label),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
parabola = axes.get_graph(lambda x: 0.25 * x**2)
|
||||
parabola.set_stroke(BLUE)
|
||||
self.play(
|
||||
FadeOut(step_graph),
|
||||
FadeOut(step_label),
|
||||
ShowCreation(parabola)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# You can use axes.input_to_graph_point, abbreviated
|
||||
# to axes.i2gp, to find a particular point on a graph
|
||||
dot = Dot(color=RED)
|
||||
dot.move_to(axes.i2gp(2, parabola))
|
||||
self.play(FadeIn(dot, scale=0.5))
|
||||
|
||||
# A value tracker lets us animate a parameter, usually
|
||||
# with the intent of having other mobjects update based
|
||||
# on the parameter
|
||||
x_tracker = ValueTracker(2)
|
||||
f_always(
|
||||
dot.move_to,
|
||||
lambda: axes.i2gp(x_tracker.get_value(), parabola)
|
||||
)
|
||||
|
||||
self.play(x_tracker.animate.set_value(4), run_time=3)
|
||||
self.play(x_tracker.animate.set_value(-2), run_time=3)
|
||||
self.wait()
|
||||
|
||||
|
||||
class SurfaceExample(Scene):
|
||||
CONFIG = {
|
||||
"camera_class": ThreeDCamera,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
surface_text = Text("For 3d scenes, try using surfaces")
|
||||
surface_text.fix_in_frame()
|
||||
surface_text.to_edge(UP)
|
||||
self.add(surface_text)
|
||||
self.wait(0.1)
|
||||
|
||||
torus1 = Torus(r1=1, r2=1)
|
||||
torus2 = Torus(r1=3, r2=1)
|
||||
sphere = Sphere(radius=3, resolution=torus1.resolution)
|
||||
# You can texture a surface with up to two images, which will
|
||||
# be interpreted as the side towards the light, and away from
|
||||
# the light. These can be either urls, or paths to a local file
|
||||
# in whatever you've set as the image directory in
|
||||
# the custom_config.yml file
|
||||
|
||||
# day_texture = "EarthTextureMap"
|
||||
# night_texture = "NightEarthTextureMap"
|
||||
day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
|
||||
night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg"
|
||||
|
||||
surfaces = [
|
||||
TexturedSurface(surface, day_texture, night_texture)
|
||||
for surface in [sphere, torus1, torus2]
|
||||
]
|
||||
|
||||
for mob in surfaces:
|
||||
mob.shift(IN)
|
||||
mob.mesh = SurfaceMesh(mob)
|
||||
mob.mesh.set_stroke(BLUE, 1, opacity=0.5)
|
||||
|
||||
# Set perspective
|
||||
frame = self.camera.frame
|
||||
frame.set_euler_angles(
|
||||
theta=-30 * DEGREES,
|
||||
phi=70 * DEGREES,
|
||||
)
|
||||
|
||||
surface = surfaces[0]
|
||||
|
||||
self.play(
|
||||
FadeIn(surface),
|
||||
ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
|
||||
)
|
||||
for mob in surfaces:
|
||||
mob.add(mob.mesh)
|
||||
surface.save_state()
|
||||
self.play(Rotate(surface, PI / 2), run_time=2)
|
||||
for mob in surfaces[1:]:
|
||||
mob.rotate(PI / 2)
|
||||
|
||||
self.play(
|
||||
Transform(surface, surfaces[1]),
|
||||
run_time=3
|
||||
)
|
||||
|
||||
self.play(
|
||||
Transform(surface, surfaces[2]),
|
||||
# Move camera frame during the transition
|
||||
frame.animate.increment_phi(-10 * DEGREES),
|
||||
frame.animate.increment_theta(-20 * DEGREES),
|
||||
run_time=3
|
||||
)
|
||||
# Add ambient rotation
|
||||
frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))
|
||||
|
||||
# Play around with where the light is
|
||||
light_text = Text("You can move around the light source")
|
||||
light_text.move_to(surface_text)
|
||||
light_text.fix_in_frame()
|
||||
|
||||
self.play(FadeTransform(surface_text, light_text))
|
||||
light = self.camera.light_source
|
||||
self.add(light)
|
||||
light.save_state()
|
||||
self.play(light.animate.move_to(3 * IN), run_time=5)
|
||||
self.play(light.animate.shift(10 * OUT), run_time=5)
|
||||
|
||||
drag_text = Text("Try moving the mouse while pressing d or s")
|
||||
drag_text.move_to(light_text)
|
||||
drag_text.fix_in_frame()
|
||||
|
||||
self.play(FadeTransform(light_text, drag_text))
|
||||
self.wait()
|
||||
|
||||
|
||||
class InteractiveDevelopment(Scene):
|
||||
def construct(self):
|
||||
circle = Circle()
|
||||
circle.set_fill(BLUE, opacity=0.5)
|
||||
circle.set_stroke(BLUE_E, width=4)
|
||||
square = Square()
|
||||
|
||||
self.play(ShowCreation(square))
|
||||
self.wait()
|
||||
|
||||
# This opens an iPython termnial where you can keep writing
|
||||
# lines as if they were part of this construct method.
|
||||
# In particular, 'square', 'circle' and 'self' will all be
|
||||
# part of the local namespace in that terminal.
|
||||
self.embed()
|
||||
|
||||
# Try copying and pasting some of the lines below into
|
||||
# the interactive shell
|
||||
self.play(ReplacementTransform(square, circle))
|
||||
self.wait()
|
||||
self.play(circle.animate.stretch(4, 0))
|
||||
self.play(Rotate(circle, 90 * DEGREES))
|
||||
self.play(circle.animate.shift(2 * RIGHT).scale(0.25))
|
||||
|
||||
text = Text("""
|
||||
In general, using the interactive shell
|
||||
is very helpful when developing new scenes
|
||||
""")
|
||||
self.play(Write(text))
|
||||
|
||||
# In the interactive shell, you can just type
|
||||
# play, add, remove, clear, wait, save_state and restore,
|
||||
# instead of self.play, self.add, self.remove, etc.
|
||||
|
||||
# To interact with the window, type touch(). You can then
|
||||
# scroll in the window, or zoom by holding down 'z' while scrolling,
|
||||
# and change camera perspective by holding down 'd' while moving
|
||||
# the mouse. Press 'r' to reset to the standard camera position.
|
||||
# Press 'q' to stop interacting with the window and go back to
|
||||
# typing new commands into the shell.
|
||||
|
||||
# In principle you can customize a scene to be responsive to
|
||||
# mouse and keyboard interactions
|
||||
always(circle.move_to, self.mouse_point)
|
||||
|
||||
|
||||
class ControlsExample(Scene):
|
||||
def setup(self):
|
||||
self.textbox = Textbox()
|
||||
self.checkbox = Checkbox()
|
||||
self.color_picker = ColorSliders()
|
||||
self.panel = ControlPanel(
|
||||
Text("Text", size=0.5), self.textbox, Line(),
|
||||
Text("Show/Hide Text", size=0.5), self.checkbox, Line(),
|
||||
Text("Color of Text", size=0.5), self.color_picker
|
||||
)
|
||||
self.add(self.panel)
|
||||
|
||||
def construct(self):
|
||||
text = Text("", size=2)
|
||||
|
||||
def text_updater(old_text):
|
||||
assert(isinstance(old_text, Text))
|
||||
new_text = Text(self.textbox.get_value(), size=old_text.size)
|
||||
# new_text.align_data_and_family(old_text)
|
||||
new_text.move_to(old_text)
|
||||
if self.checkbox.get_value():
|
||||
new_text.set_fill(
|
||||
color=self.color_picker.get_picked_color(),
|
||||
opacity=self.color_picker.get_picked_opacity()
|
||||
)
|
||||
else:
|
||||
new_text.set_opacity(0)
|
||||
old_text.become(new_text)
|
||||
|
||||
text.add_updater(text_updater)
|
||||
|
||||
self.add(MotionMobject(text))
|
||||
|
||||
self.textbox.set_value("Manim")
|
||||
# self.wait(60)
|
||||
# self.embed()
|
||||
|
||||
|
||||
# See https://github.com/3b1b/videos for many, many more
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,635 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
import scipy.stats
|
||||
|
||||
|
||||
CMARK_TEX = "\\text{\\ding{51}}"
|
||||
XMARK_TEX = "\\text{\\ding{55}}"
|
||||
|
||||
COIN_COLOR_MAP = {
|
||||
"H": BLUE_E,
|
||||
"T": RED_E,
|
||||
}
|
||||
|
||||
|
||||
class Histogram(Group):
|
||||
CONFIG = {
|
||||
"height": 5,
|
||||
"width": 10,
|
||||
"y_max": 1,
|
||||
"y_axis_numbers_to_show": range(20, 120, 20),
|
||||
"y_axis_label_height": 0.25,
|
||||
"y_tick_freq": 0.2,
|
||||
"x_label_freq": 1,
|
||||
"include_h_lines": True,
|
||||
"h_line_style": {
|
||||
"stroke_width": 1,
|
||||
"stroke_color": LIGHT_GREY,
|
||||
# "draw_stroke_behind_fill": True,
|
||||
},
|
||||
"bar_style": {
|
||||
"stroke_width": 1,
|
||||
"stroke_color": WHITE,
|
||||
"fill_opacity": 1,
|
||||
},
|
||||
"bar_colors": [BLUE, GREEN]
|
||||
}
|
||||
|
||||
def __init__(self, data, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.data = data
|
||||
|
||||
self.add_axes()
|
||||
if self.include_h_lines:
|
||||
self.add_h_lines()
|
||||
self.add_bars(data)
|
||||
self.add_x_axis_labels()
|
||||
self.add_y_axis_labels()
|
||||
|
||||
def add_axes(self):
|
||||
n_bars = len(self.data)
|
||||
axes_config = {
|
||||
"x_min": 0,
|
||||
"x_max": n_bars,
|
||||
"x_axis_config": {
|
||||
"unit_size": self.width / n_bars,
|
||||
"include_tip": False,
|
||||
},
|
||||
"y_min": 0,
|
||||
"y_max": self.y_max,
|
||||
"y_axis_config": {
|
||||
"unit_size": self.height / self.y_max,
|
||||
"include_tip": False,
|
||||
"tick_frequency": self.y_tick_freq,
|
||||
},
|
||||
}
|
||||
axes = Axes(**axes_config)
|
||||
axes.center()
|
||||
self.axes = axes
|
||||
self.add(axes)
|
||||
|
||||
def add_h_lines(self):
|
||||
axes = self.axes
|
||||
axes.h_lines = VGroup()
|
||||
for tick in axes.y_axis.tick_marks:
|
||||
line = Line(**self.h_line_style)
|
||||
line.match_width(axes.x_axis)
|
||||
line.move_to(tick.get_center(), LEFT)
|
||||
axes.h_lines.add(line)
|
||||
axes.add(axes.h_lines)
|
||||
|
||||
def add_bars(self, data):
|
||||
self.bars = self.get_bars(data)
|
||||
self.add(self.bars)
|
||||
|
||||
def add_x_axis_labels(self):
|
||||
axes = self.axes
|
||||
axes.x_labels = VGroup()
|
||||
for x, bar in list(enumerate(self.bars))[::self.x_label_freq]:
|
||||
label = Integer(x)
|
||||
label.set_height(0.25)
|
||||
label.next_to(bar, DOWN)
|
||||
axes.x_labels.add(label)
|
||||
axes.add(axes.x_labels)
|
||||
|
||||
def add_y_axis_labels(self):
|
||||
axes = self.axes
|
||||
labels = VGroup()
|
||||
for value in self.y_axis_numbers_to_show:
|
||||
label = Integer(value, unit="\\%")
|
||||
fix_percent(label[-1][0])
|
||||
label.set_height(self.y_axis_label_height)
|
||||
label.next_to(axes.y_axis.n2p(0.01 * value), LEFT)
|
||||
labels.add(label)
|
||||
axes.y_labels = labels
|
||||
axes.y_axis.add(labels)
|
||||
|
||||
# Bar manipulations
|
||||
def get_bars(self, data):
|
||||
portions = np.array(data).astype(float)
|
||||
total = portions.sum()
|
||||
if total == 0:
|
||||
portions[:] = 0
|
||||
else:
|
||||
portions /= total
|
||||
bars = VGroup()
|
||||
for x, prop in enumerate(portions):
|
||||
bar = Rectangle()
|
||||
width = get_norm(self.axes.c2p(1, 0) - self.axes.c2p(0, 0))
|
||||
height = get_norm(self.axes.c2p(0, 1) - self.axes.c2p(0, 0))
|
||||
bar.set_width(width)
|
||||
bar.set_height(height * prop, stretch=True)
|
||||
bar.move_to(self.axes.c2p(x, 0), DL)
|
||||
bars.add(bar)
|
||||
|
||||
bars.set_submobject_colors_by_gradient(*self.bar_colors)
|
||||
bars.set_style(**self.bar_style)
|
||||
return bars
|
||||
|
||||
|
||||
# Images of randomness
|
||||
|
||||
def fix_percent(sym):
|
||||
# Really need to make this unneeded...
|
||||
new_sym = sym.copy()
|
||||
path_lengths = [len(path) for path in sym.get_subpaths()]
|
||||
n = sum(path_lengths[:2])
|
||||
p1 = sym.points[:n]
|
||||
p2 = sym.points[n:]
|
||||
sym.points = p1
|
||||
new_sym.points = p2
|
||||
sym.add(new_sym)
|
||||
sym.lock_triangulation()
|
||||
|
||||
|
||||
def get_random_process(choices, shuffle_time=2, total_time=3, change_rate=0.05,
|
||||
h_buff=0.1, v_buff=0.1):
|
||||
content = choices[0]
|
||||
|
||||
container = Square()
|
||||
container.set_opacity(0)
|
||||
container.set_width(content.get_width() + 2 * h_buff, stretch=True)
|
||||
container.set_height(content.get_height() + 2 * v_buff, stretch=True)
|
||||
container.move_to(content)
|
||||
container.add(content)
|
||||
container.time = 0
|
||||
container.last_change_time = 0
|
||||
|
||||
def update(container, dt):
|
||||
container.time += dt
|
||||
|
||||
t = container.time
|
||||
change = all([
|
||||
(t % total_time) < shuffle_time,
|
||||
container.time - container.last_change_time > change_rate
|
||||
])
|
||||
if change:
|
||||
mob = container.submobjects[0]
|
||||
new_mob = random.choice(choices)
|
||||
new_mob.match_height(mob)
|
||||
new_mob.move_to(container, DL)
|
||||
new_mob.shift(2 * np.random.random() * h_buff * RIGHT)
|
||||
new_mob.shift(2 * np.random.random() * v_buff * UP)
|
||||
container.set_submobjects([new_mob])
|
||||
container.last_change_time = container.time
|
||||
|
||||
container.add_updater(update)
|
||||
return container
|
||||
|
||||
|
||||
def get_die_faces():
|
||||
dot = Dot()
|
||||
dot.set_width(0.15)
|
||||
dot.set_color(BLUE_B)
|
||||
|
||||
square = Square()
|
||||
square.round_corners(0.25)
|
||||
square.set_stroke(WHITE, 2)
|
||||
square.set_fill(DARKER_GREY, 1)
|
||||
square.set_width(0.6)
|
||||
|
||||
edge_groups = [
|
||||
(ORIGIN,),
|
||||
(UL, DR),
|
||||
(UL, ORIGIN, DR),
|
||||
(UL, UR, DL, DR),
|
||||
(UL, UR, ORIGIN, DL, DR),
|
||||
(UL, UR, LEFT, RIGHT, DL, DR),
|
||||
]
|
||||
|
||||
arrangements = VGroup(*[
|
||||
VGroup(*[
|
||||
dot.copy().move_to(square.get_bounding_box_point(ec))
|
||||
for ec in edge_group
|
||||
])
|
||||
for edge_group in edge_groups
|
||||
])
|
||||
square.set_width(1)
|
||||
|
||||
faces = VGroup(*[
|
||||
VGroup(square.copy(), arrangement)
|
||||
for arrangement in arrangements
|
||||
])
|
||||
faces.arrange(RIGHT)
|
||||
|
||||
return faces
|
||||
|
||||
|
||||
def get_random_die(**kwargs):
|
||||
return get_random_process(get_die_faces(), **kwargs)
|
||||
|
||||
|
||||
def get_random_card(height=1, **kwargs):
|
||||
cards = DeckOfCards()
|
||||
cards.set_height(height)
|
||||
return get_random_process(cards, **kwargs)
|
||||
|
||||
|
||||
# Coins
|
||||
def get_coin(symbol, color=None):
|
||||
if color is None:
|
||||
color = COIN_COLOR_MAP.get(symbol, GREY_E)
|
||||
coin = VGroup()
|
||||
circ = Circle()
|
||||
circ.set_fill(color, 1)
|
||||
circ.set_stroke(WHITE, 1)
|
||||
circ.set_height(1)
|
||||
label = TextMobject(symbol)
|
||||
label.set_height(0.5 * circ.get_height())
|
||||
label.move_to(circ)
|
||||
coin.add(circ, label)
|
||||
coin.symbol = symbol
|
||||
coin.lock_triangulation()
|
||||
return coin
|
||||
|
||||
|
||||
def get_random_coin(**kwargs):
|
||||
return get_random_process([get_coin("H"), get_coin("T")], **kwargs)
|
||||
|
||||
|
||||
def get_prob_coin_label(symbol="H", color=None, p=0.5, num_decimal_places=2):
|
||||
label = TexMobject("P", "(", "00", ")", "=",)
|
||||
coin = get_coin(symbol, color)
|
||||
template = label.get_part_by_tex("00")
|
||||
coin.replace(template)
|
||||
label.replace_submobject(label.index_of_part(template), coin)
|
||||
rhs = DecimalNumber(p, num_decimal_places=num_decimal_places)
|
||||
rhs.next_to(label, RIGHT, buff=MED_SMALL_BUFF)
|
||||
label.add(rhs)
|
||||
return label
|
||||
|
||||
|
||||
def get_q_box(mob):
|
||||
box = SurroundingRectangle(mob)
|
||||
box.set_stroke(WHITE, 1)
|
||||
box.set_fill(GREY_E, 1)
|
||||
q_marks = TexMobject("???")
|
||||
max_width = 0.8 * box.get_width()
|
||||
max_height = 0.8 * box.get_height()
|
||||
|
||||
if q_marks.get_width() > max_width:
|
||||
q_marks.set_width(max_width)
|
||||
|
||||
if q_marks.get_height() > max_height:
|
||||
q_marks.set_height(max_height)
|
||||
|
||||
q_marks.move_to(box)
|
||||
box.add(q_marks)
|
||||
return box
|
||||
|
||||
|
||||
def get_coin_grid(bools, height=6):
|
||||
coins = VGroup(*[
|
||||
get_coin("H" if heads else "T")
|
||||
for heads in bools
|
||||
])
|
||||
coins.arrange_in_grid()
|
||||
coins.set_height(height)
|
||||
return coins
|
||||
|
||||
|
||||
def get_prob_positive_experience_label(include_equals=False,
|
||||
include_decimal=False,
|
||||
include_q_mark=False):
|
||||
label = TexMobject(
|
||||
"P", "(", "00000", ")",
|
||||
)
|
||||
|
||||
pe = TextMobject("Positive\\\\experience")
|
||||
pe.set_color(GREEN)
|
||||
pe.replace(label[2], dim_to_match=0)
|
||||
label.replace_submobject(2, pe)
|
||||
VGroup(label[1], label[3]).match_height(
|
||||
pe, stretch=True, about_edge=DOWN,
|
||||
)
|
||||
if include_equals:
|
||||
eq = TexMobject("=").next_to(label, RIGHT)
|
||||
label.add(eq)
|
||||
if include_decimal:
|
||||
decimal = DecimalNumber(0.95)
|
||||
decimal.next_to(label, RIGHT)
|
||||
decimal.set_color(YELLOW)
|
||||
label.decimal = decimal
|
||||
label.add(decimal)
|
||||
if include_q_mark:
|
||||
q_mark = TexMobject("?")
|
||||
q_mark.relative_mob = label[-1]
|
||||
q_mark.add_updater(
|
||||
lambda m: m.next_to(m.relative_mob, RIGHT, SMALL_BUFF)
|
||||
)
|
||||
label.add(q_mark)
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def get_beta_dist_axes(y_max=20, y_unit=2, label_y=False, **kwargs):
|
||||
config = {
|
||||
"x_min": 0,
|
||||
"x_max": 1,
|
||||
"x_axis_config": {
|
||||
"unit_size": 0.1,
|
||||
"tick_frequency": 0.1,
|
||||
"include_tip": False,
|
||||
},
|
||||
"y_min": 0,
|
||||
"y_max": y_max,
|
||||
"y_axis_config": {
|
||||
"unit_size": 1,
|
||||
"tick_frequency": y_unit,
|
||||
"include_tip": False,
|
||||
},
|
||||
}
|
||||
result = Axes(**config)
|
||||
origin = result.c2p(0, 0)
|
||||
kw = {
|
||||
"about_point": origin,
|
||||
"stretch": True,
|
||||
}
|
||||
result.x_axis.set_width(11, **kw)
|
||||
result.y_axis.set_height(6, **kw)
|
||||
|
||||
x_vals = np.arange(0, 1, 0.2) + 0.2
|
||||
result.x_axis.add_numbers(
|
||||
*x_vals,
|
||||
number_config={"num_decimal_places": 1}
|
||||
)
|
||||
|
||||
if label_y:
|
||||
result.y_axis.add_numbers(
|
||||
*np.arange(y_unit, y_max, y_unit)
|
||||
)
|
||||
label = TextMobject("Probability density")
|
||||
label.scale(0.5)
|
||||
label.next_to(result.y_axis.get_top(), UR, SMALL_BUFF)
|
||||
label.next_to(result.y_axis, UP, SMALL_BUFF)
|
||||
label.align_to(result.y_axis.numbers, LEFT)
|
||||
result.add(label)
|
||||
result.y_axis_label = label
|
||||
|
||||
result.to_corner(DR, LARGE_BUFF)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def scaled_pdf_axes(scale_factor=3.5):
|
||||
axes = get_beta_dist_axes(
|
||||
label_y=True,
|
||||
y_unit=1,
|
||||
)
|
||||
axes.y_axis.numbers.set_submobjects([
|
||||
*axes.y_axis.numbers[:5],
|
||||
*axes.y_axis.numbers[4::5]
|
||||
])
|
||||
sf = scale_factor
|
||||
axes.y_axis.stretch(sf, 1, about_point=axes.c2p(0, 0))
|
||||
for number in axes.y_axis.numbers:
|
||||
number.stretch(1 / sf, 1)
|
||||
axes.y_axis_label.to_edge(LEFT)
|
||||
axes.y_axis_label.add_background_rectangle(opacity=1)
|
||||
axes.set_stroke(background=True)
|
||||
return axes
|
||||
|
||||
|
||||
def close_off_graph(axes, graph):
|
||||
x_max = axes.x_axis.p2n(graph.get_end())
|
||||
graph.add_line_to(axes.c2p(x_max, 0))
|
||||
graph.add_line_to(axes.c2p(0, 0))
|
||||
graph.lock_triangulation()
|
||||
return graph
|
||||
|
||||
|
||||
def get_beta_graph(axes, n_plus, n_minus, **kwargs):
|
||||
dist = scipy.stats.beta(n_plus + 1, n_minus + 1)
|
||||
graph = axes.get_graph(dist.pdf, **kwargs)
|
||||
close_off_graph(axes, graph)
|
||||
graph.set_stroke(BLUE, 2)
|
||||
graph.set_fill(BLUE_E, 1)
|
||||
graph.lock_triangulation()
|
||||
return graph
|
||||
|
||||
|
||||
def get_beta_label(n_plus, n_minus, point=ORIGIN):
|
||||
template = TextMobject("Beta(", "00", ",", "00", ")")
|
||||
template.scale(1.5)
|
||||
a_label = Integer(n_plus + 1)
|
||||
a_label.set_color(GREEN)
|
||||
b_label = Integer(n_minus + 1)
|
||||
b_label.set_color(RED)
|
||||
|
||||
for i, label in (1, a_label), (3, b_label):
|
||||
label.match_height(template[i])
|
||||
label.move_to(template[i], DOWN)
|
||||
template.replace_submobject(i, label)
|
||||
template.save_state()
|
||||
template.arrange(RIGHT, buff=0.15)
|
||||
for t1, t2 in zip(template, template.saved_state):
|
||||
t1.align_to(t2, DOWN)
|
||||
|
||||
return template
|
||||
|
||||
|
||||
def get_plusses_and_minuses(n_rows=15, n_cols=20, p=0.95):
|
||||
result = VGroup()
|
||||
for x in range(n_rows * n_cols):
|
||||
if random.random() < p:
|
||||
mob = TexMobject(CMARK_TEX)
|
||||
mob.set_color(GREEN)
|
||||
mob.is_plus = True
|
||||
else:
|
||||
mob = TexMobject(XMARK_TEX)
|
||||
mob.set_color(RED)
|
||||
mob.is_plus = False
|
||||
mob.set_width(1)
|
||||
result.add(mob)
|
||||
|
||||
result.arrange_in_grid(n_rows, n_cols)
|
||||
result.set_width(5.5)
|
||||
return result
|
||||
|
||||
|
||||
def get_checks_and_crosses(bools, width=12):
|
||||
result = VGroup()
|
||||
for positive in bools:
|
||||
if positive:
|
||||
mob = TexMobject(CMARK_TEX)
|
||||
mob.set_color(GREEN)
|
||||
else:
|
||||
mob = TexMobject(XMARK_TEX)
|
||||
mob.set_color(RED)
|
||||
mob.positive = positive
|
||||
mob.set_width(0.5)
|
||||
result.add(mob)
|
||||
result.arrange(RIGHT, buff=MED_SMALL_BUFF)
|
||||
result.set_width(width)
|
||||
return result
|
||||
|
||||
|
||||
def get_underlines(marks):
|
||||
underlines = VGroup()
|
||||
for mark in marks:
|
||||
underlines.add(Underline(mark))
|
||||
for line in underlines:
|
||||
line.align_to(underlines[-1], DOWN)
|
||||
return underlines
|
||||
|
||||
|
||||
def get_random_checks_and_crosses(n=50, s=0.95, width=12):
|
||||
return get_checks_and_crosses(
|
||||
bools=(np.random.random(n) < s),
|
||||
width=width
|
||||
)
|
||||
|
||||
|
||||
def get_random_num_row(s, n=10):
|
||||
values = np.random.random(n)
|
||||
nums = VGroup()
|
||||
syms = VGroup()
|
||||
for x, value in enumerate(values):
|
||||
num = DecimalNumber(value)
|
||||
num.set_height(0.25)
|
||||
num.move_to(x * RIGHT)
|
||||
num.positive = (num.get_value() < s)
|
||||
if num.positive:
|
||||
num.set_color(GREEN)
|
||||
sym = TexMobject(CMARK_TEX)
|
||||
else:
|
||||
num.set_color(RED)
|
||||
sym = TexMobject(XMARK_TEX)
|
||||
sym.match_color(num)
|
||||
sym.match_height(num)
|
||||
sym.positive = num.positive
|
||||
sym.next_to(num, UP)
|
||||
|
||||
nums.add(num)
|
||||
syms.add(sym)
|
||||
|
||||
row = VGroup(nums, syms)
|
||||
row.nums = nums
|
||||
row.syms = syms
|
||||
row.n_positive = sum([m.positive for m in nums])
|
||||
|
||||
row.set_width(10)
|
||||
row.center().to_edge(UP)
|
||||
return row
|
||||
|
||||
|
||||
def get_prob_review_label(n_positive, n_negative, s=0.95):
|
||||
label = TexMobject(
|
||||
"P(",
|
||||
f"{n_positive}\\,{CMARK_TEX}", ",\\,",
|
||||
f"{n_negative}\\,{XMARK_TEX}",
|
||||
"\\,|\\,",
|
||||
"s = {:.2f}".format(s),
|
||||
")",
|
||||
)
|
||||
label.set_color_by_tex_to_color_map({
|
||||
CMARK_TEX: GREEN,
|
||||
XMARK_TEX: RED,
|
||||
"0.95": YELLOW,
|
||||
})
|
||||
return label
|
||||
|
||||
|
||||
def get_binomial_formula(n, k, p):
|
||||
n_mob = Integer(n, color=WHITE)
|
||||
k_mob = Integer(k, color=GREEN)
|
||||
nmk_mob = Integer(n - k, color=RED)
|
||||
p_mob = DecimalNumber(p, color=YELLOW)
|
||||
|
||||
n_str = "N" * len(n_mob)
|
||||
k_str = "K" * len(k_mob)
|
||||
p_str = "P" * len(k_mob)
|
||||
nmk_str = "M" * len(nmk_mob)
|
||||
|
||||
formula = TexMobject(
|
||||
"\\left(",
|
||||
"{" + n_str,
|
||||
"\\over",
|
||||
k_str + "}",
|
||||
"\\right)",
|
||||
"(", p_str, ")",
|
||||
"^{" + k_str + "}",
|
||||
"(1 - ", p_str, ")",
|
||||
"^{" + nmk_str + "}",
|
||||
)
|
||||
parens = VGroup(formula[0], formula[4])
|
||||
parens.space_out_submobjects(0.7)
|
||||
formula.remove(formula.get_part_by_tex("\\over"))
|
||||
pairs = (
|
||||
(n_mob, n_str),
|
||||
(k_mob, k_str),
|
||||
(nmk_mob, nmk_str),
|
||||
(p_mob, p_str),
|
||||
)
|
||||
for mob, tex in pairs:
|
||||
parts = formula.get_parts_by_tex(tex)
|
||||
for part in parts:
|
||||
mob_copy = mob.copy()
|
||||
i = formula.index_of_part_by_tex(tex)
|
||||
mob_copy.match_height(part)
|
||||
mob_copy.move_to(part, DOWN)
|
||||
formula.replace_submobject(i, mob_copy)
|
||||
|
||||
terms = VGroup(
|
||||
formula[:4],
|
||||
formula[4:7],
|
||||
formula[7],
|
||||
formula[8:11],
|
||||
formula[11],
|
||||
)
|
||||
ys = [term.get_y() for term in terms]
|
||||
terms.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
terms[0].shift(SMALL_BUFF * LEFT)
|
||||
for term, y in zip(terms, ys):
|
||||
term.set_y(y)
|
||||
|
||||
return formula
|
||||
|
||||
|
||||
def get_check_count_label(nc, nx, include_rect=True):
|
||||
result = VGroup(
|
||||
Integer(nc),
|
||||
TexMobject(CMARK_TEX, color=GREEN),
|
||||
Integer(nx),
|
||||
TexMobject(XMARK_TEX, color=RED),
|
||||
)
|
||||
result.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
result[2:].shift(SMALL_BUFF * RIGHT)
|
||||
|
||||
if include_rect:
|
||||
rect = SurroundingRectangle(result)
|
||||
rect.set_stroke(WHITE, 1)
|
||||
rect.set_fill(GREY_E, 1)
|
||||
result.add_to_back(rect)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def reverse_smooth(t):
|
||||
return smooth(1 - t)
|
||||
|
||||
|
||||
def get_region_under_curve(axes, graph, min_x, max_x):
|
||||
props = [
|
||||
binary_search(
|
||||
function=lambda a: axes.x_axis.p2n(graph.pfp(a)),
|
||||
target=x,
|
||||
lower_bound=axes.x_min,
|
||||
upper_bound=axes.x_max,
|
||||
)
|
||||
for x in [min_x, max_x]
|
||||
]
|
||||
region = graph.copy()
|
||||
region.pointwise_become_partial(graph, *props)
|
||||
region.add_line_to(axes.c2p(max_x, 0))
|
||||
region.add_line_to(axes.c2p(min_x, 0))
|
||||
region.add_line_to(region.get_start())
|
||||
|
||||
region.set_stroke(GREEN, 2)
|
||||
region.set_fill(GREEN, 0.5)
|
||||
|
||||
region.axes = axes
|
||||
region.graph = graph
|
||||
region.min_x = min_x
|
||||
region.max_x = max_x
|
||||
|
||||
return region
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,754 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from from_3b1b.active.sir import *
|
||||
|
||||
|
||||
class LastFewMonths(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Last ", "few\\\\", "months:")
|
||||
words.set_height(4)
|
||||
underlines = VGroup()
|
||||
for word in words:
|
||||
underline = Line(LEFT, RIGHT)
|
||||
underline.match_width(word)
|
||||
underline.next_to(word, DOWN, SMALL_BUFF)
|
||||
underlines.add(underline)
|
||||
underlines[0].stretch(1.4, 0, about_edge=LEFT)
|
||||
underlines.set_color(BLUE)
|
||||
|
||||
# self.play(ShowCreation(underlines))
|
||||
self.play(ShowIncreasingSubsets(words, run_time=0.75, rate_func=linear))
|
||||
self.wait()
|
||||
|
||||
|
||||
class UnemploymentTitle(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Unemployment claims\\\\per week in the US")[0]
|
||||
words.set_width(FRAME_WIDTH - 1)
|
||||
words.to_edge(UP)
|
||||
arrow = Arrow(
|
||||
words.get_bottom(),
|
||||
words.get_bottom() + 3 * RIGHT + 3 * DOWN,
|
||||
stroke_width=10,
|
||||
tip_length=0.5,
|
||||
)
|
||||
arrow.set_color(BLUE_E)
|
||||
words.set_color(BLACK)
|
||||
self.play(
|
||||
ShowIncreasingSubsets(words),
|
||||
ShowCreation(arrow),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ExplainTracing(Scene):
|
||||
def construct(self):
|
||||
# Words
|
||||
words = VGroup(
|
||||
TextMobject("Testing, ", "Testing, ", "Testing!"),
|
||||
TextMobject("Contact Tracing"),
|
||||
)
|
||||
words[0].set_color(GREEN)
|
||||
words[1].set_color(BLUE_B)
|
||||
words.set_width(FRAME_WIDTH - 2)
|
||||
words.arrange(DOWN, buff=1)
|
||||
|
||||
self.play(ShowIncreasingSubsets(words[0], rate_func=linear))
|
||||
self.wait()
|
||||
self.play(Write(words[1], run_time=1))
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
words[1].to_edge, UP,
|
||||
FadeOutAndShift(words[0], 6 * UP)
|
||||
)
|
||||
|
||||
ct_word = words[1][0]
|
||||
|
||||
# Groups
|
||||
clusters = VGroup()
|
||||
for x in range(4):
|
||||
cluster = VGroup()
|
||||
for y in range(4):
|
||||
cluster.add(Randolph())
|
||||
cluster.arrange_in_grid(buff=LARGE_BUFF)
|
||||
clusters.add(cluster)
|
||||
clusters.scale(0.5)
|
||||
clusters.arrange_in_grid(buff=2)
|
||||
clusters.set_height(4)
|
||||
|
||||
self.play(FadeIn(clusters))
|
||||
|
||||
pis = VGroup()
|
||||
boxes = VGroup()
|
||||
for cluster in clusters:
|
||||
for pi in cluster:
|
||||
pis.add(pi)
|
||||
box = SurroundingRectangle(pi, buff=0.05)
|
||||
boxes.add(box)
|
||||
pi.box = box
|
||||
|
||||
boxes.set_stroke(WHITE, 1)
|
||||
|
||||
sicky = clusters[0][2]
|
||||
covid_words = TextMobject("COVID-19\\\\Positive!")
|
||||
covid_words.set_color(RED)
|
||||
arrow = Vector(RIGHT, color=RED)
|
||||
arrow.next_to(sicky, LEFT)
|
||||
covid_words.next_to(arrow, LEFT, SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
sicky.change, "sick",
|
||||
sicky.set_color, "#9BBD37",
|
||||
FadeInFrom(covid_words, RIGHT),
|
||||
GrowArrow(arrow),
|
||||
)
|
||||
self.play(ShowCreation(sicky.box))
|
||||
self.wait(2)
|
||||
anims = []
|
||||
for pi in clusters[0]:
|
||||
if pi is not sicky:
|
||||
anims.append(ApplyMethod(pi.change, "tired"))
|
||||
anims.append(ShowCreation(pi.box))
|
||||
self.play(*anims)
|
||||
self.wait()
|
||||
|
||||
self.play(VFadeIn(
|
||||
boxes[4:],
|
||||
run_time=2,
|
||||
rate_func=there_and_back_with_pause,
|
||||
))
|
||||
self.wait()
|
||||
|
||||
self.play(FadeOut(
|
||||
VGroup(
|
||||
covid_words,
|
||||
arrow,
|
||||
*boxes[:4],
|
||||
*pis,
|
||||
),
|
||||
lag_ratio=0.1,
|
||||
run_time=3,
|
||||
))
|
||||
self.play(ct_word.move_to, 2 * UP)
|
||||
|
||||
# Underlines
|
||||
implies = TexMobject("\\Downarrow")
|
||||
implies.scale(2)
|
||||
implies.next_to(ct_word, DOWN, MED_LARGE_BUFF)
|
||||
loc_tracking = TextMobject("Location Tracking")
|
||||
loc_tracking.set_color(GREY_BROWN)
|
||||
loc_tracking.match_height(ct_word)
|
||||
loc_tracking.next_to(implies, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
q_marks = TexMobject("???")
|
||||
q_marks.scale(2)
|
||||
q_marks.next_to(implies, RIGHT)
|
||||
|
||||
cross = Cross(implies)
|
||||
cross.set_stroke(RED, 7)
|
||||
|
||||
self.play(
|
||||
Write(implies),
|
||||
FadeInFrom(loc_tracking, UP)
|
||||
)
|
||||
self.play(FadeIn(q_marks, lag_ratio=0.1))
|
||||
self.wait()
|
||||
|
||||
parts = VGroup(ct_word[:7], ct_word[7:])
|
||||
lines = VGroup()
|
||||
for part in parts:
|
||||
line = Line(part.get_left(), part.get_right())
|
||||
line.align_to(part[0], DOWN)
|
||||
line.shift(0.1 * DOWN)
|
||||
lines.add(line)
|
||||
|
||||
ct_word.set_stroke(BLACK, 2, background=True)
|
||||
self.add(lines[1], ct_word)
|
||||
self.play(ShowCreation(lines[1]))
|
||||
self.wait()
|
||||
self.play(ShowCreation(lines[0]))
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
ShowCreation(cross),
|
||||
FadeOutAndShift(q_marks, RIGHT),
|
||||
FadeOut(lines),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
dp_3t = TextMobject("DP-3T")
|
||||
dp_3t.match_height(ct_word)
|
||||
dp_3t.move_to(loc_tracking)
|
||||
dp_3t_long = TextMobject("Decentralized Privacy-Preserving Proximity Tracing")
|
||||
dp_3t_long.next_to(dp_3t, DOWN, LARGE_BUFF)
|
||||
|
||||
arrow = Vector(UP)
|
||||
arrow.set_stroke(width=8)
|
||||
arrow.move_to(implies)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(dp_3t),
|
||||
FadeOut(loc_tracking),
|
||||
FadeOut(implies),
|
||||
FadeOut(cross),
|
||||
ShowCreation(arrow)
|
||||
)
|
||||
self.play(Write(dp_3t_long))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ContactTracingMisnomer(Scene):
|
||||
def construct(self):
|
||||
# Word play
|
||||
words = TextMobject("Contact ", "Tracing")
|
||||
words.scale(2)
|
||||
rects = VGroup(*[
|
||||
SurroundingRectangle(word, buff=0.2)
|
||||
for word in words
|
||||
])
|
||||
expl1 = TextMobject("Doesn't ``trace'' you...")
|
||||
expl2 = TextMobject("...or your contacts")
|
||||
expls = VGroup(expl1, expl2)
|
||||
colors = [RED, BLUE]
|
||||
|
||||
self.add(words)
|
||||
for vect, rect, expl, color in zip([UP, DOWN], reversed(rects), expls, colors):
|
||||
arrow = Vector(-vect)
|
||||
arrow.next_to(rect, vect, SMALL_BUFF)
|
||||
expl.next_to(arrow, vect, SMALL_BUFF)
|
||||
rect.set_color(color)
|
||||
arrow.set_color(color)
|
||||
expl.set_color(color)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(expl, -vect),
|
||||
GrowArrow(arrow),
|
||||
ShowCreation(rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.play(Write(
|
||||
VGroup(*self.mobjects),
|
||||
rate_func=lambda t: smooth(1 - t),
|
||||
run_time=3,
|
||||
))
|
||||
|
||||
|
||||
class ContactTracingWords(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Contact\\\\", "Tracing")
|
||||
words.set_height(4)
|
||||
for word in words:
|
||||
self.add(word)
|
||||
self.wait()
|
||||
self.wait()
|
||||
return
|
||||
self.play(ShowIncreasingSubsets(words))
|
||||
self.wait()
|
||||
self.play(
|
||||
words.set_height, 1,
|
||||
words.to_corner, UL,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WanderingDotsWithLines(Scene):
|
||||
def construct(self):
|
||||
sim = SIRSimulation(
|
||||
city_population=20,
|
||||
person_type=DotPerson,
|
||||
person_config={
|
||||
"color_map": {
|
||||
"S": GREY,
|
||||
"I": GREY,
|
||||
"R": GREY,
|
||||
},
|
||||
"infection_ring_style": {
|
||||
"stroke_color": YELLOW,
|
||||
},
|
||||
"max_speed": 0.5,
|
||||
},
|
||||
infection_time=100,
|
||||
)
|
||||
|
||||
for person in sim.people:
|
||||
person.set_status("S")
|
||||
person.infection_start_time += random.random()
|
||||
|
||||
lines = VGroup()
|
||||
|
||||
max_dist = 1.25
|
||||
|
||||
def update_lines(lines):
|
||||
lines.remove(*lines.submobjects)
|
||||
for p1 in sim.people:
|
||||
for p2 in sim.people:
|
||||
if p1 is p2:
|
||||
continue
|
||||
dist = get_norm(p1.get_center() - p2.get_center())
|
||||
if dist < max_dist:
|
||||
line = Line(p1.get_center(), p2.get_center())
|
||||
alpha = (max_dist - dist) / max_dist
|
||||
line.set_stroke(
|
||||
interpolate_color(WHITE, RED, alpha),
|
||||
width=4 * alpha
|
||||
)
|
||||
lines.add(line)
|
||||
|
||||
lines.add_updater(update_lines)
|
||||
|
||||
self.add(lines)
|
||||
self.add(sim)
|
||||
self.wait(10)
|
||||
for person in sim.people:
|
||||
person.set_status("I")
|
||||
person.infection_start_time += random.random()
|
||||
self.wait(50)
|
||||
|
||||
|
||||
class WhatAboutPeopleWithoutPhones(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"What about people\\\\without phones?",
|
||||
target_mode="sassy",
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.change_student_modes("angry", "angry", "sassy")
|
||||
self.wait()
|
||||
self.play(self.teacher.change, "tease")
|
||||
self.wait()
|
||||
|
||||
words = VectorizedPoint()
|
||||
words.scale(1.5)
|
||||
words.to_corner(UL)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(words),
|
||||
RemovePiCreatureBubble(self.students[2]),
|
||||
*[
|
||||
ApplyMethod(pi.change, "pondering", words)
|
||||
for pi in self.pi_creatures
|
||||
]
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class PiGesture1(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph(mode="raise_right_hand", height=2)
|
||||
bubble = randy.get_bubble(
|
||||
bubble_class=SpeechBubble,
|
||||
height=2, width=3,
|
||||
)
|
||||
bubble.write("This one's\\\\great")
|
||||
bubble.content.scale(0.8)
|
||||
bubble.content.set_color(BLACK)
|
||||
bubble.set_color(BLACK)
|
||||
bubble.set_fill(opacity=0)
|
||||
randy.set_stroke(BLACK, 5, background=True)
|
||||
self.add(randy, bubble, bubble.content)
|
||||
|
||||
|
||||
class PiGesture2(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph(mode="raise_left_hand", height=2)
|
||||
randy.look(UL)
|
||||
# randy.flip()
|
||||
randy.set_color(GREY_BROWN)
|
||||
bubble = randy.get_bubble(
|
||||
bubble_class=SpeechBubble,
|
||||
height=2, width=3,
|
||||
direction=LEFT,
|
||||
)
|
||||
bubble.write("So is\\\\this one")
|
||||
bubble.content.scale(0.8)
|
||||
bubble.content.set_color(BLACK)
|
||||
bubble.set_color(BLACK)
|
||||
bubble.set_fill(opacity=0)
|
||||
randy.set_stroke(BLACK, 5, background=True)
|
||||
self.add(randy, bubble, bubble.content)
|
||||
|
||||
|
||||
class PiGesture3(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph(mode="hooray", height=2)
|
||||
randy.flip()
|
||||
bubble = randy.get_bubble(
|
||||
bubble_class=SpeechBubble,
|
||||
height=2, width=3,
|
||||
direction=LEFT,
|
||||
)
|
||||
bubble.write("And this\\\\one")
|
||||
bubble.content.scale(0.8)
|
||||
bubble.content.set_color(BLACK)
|
||||
bubble.set_color(BLACK)
|
||||
bubble.set_fill(opacity=0)
|
||||
randy.set_stroke(BLACK, 5, background=True)
|
||||
self.add(randy, bubble, bubble.content)
|
||||
|
||||
|
||||
class AppleGoogleCoop(Scene):
|
||||
def construct(self):
|
||||
logos = Group(
|
||||
self.get_apple_logo(),
|
||||
self.get_google_logo(),
|
||||
)
|
||||
for logo in logos:
|
||||
logo.set_height(2)
|
||||
apple, google = logos
|
||||
|
||||
logos.arrange(RIGHT, buff=3)
|
||||
|
||||
arrows = VGroup()
|
||||
for vect, u in zip([UP, DOWN], [0, 1]):
|
||||
m1, m2 = logos[u], logos[1 - u]
|
||||
arrows.add(Arrow(
|
||||
m1.get_edge_center(vect),
|
||||
m2.get_edge_center(vect),
|
||||
path_arc=-90 * DEGREES,
|
||||
buff=MED_LARGE_BUFF,
|
||||
stroke_width=10,
|
||||
))
|
||||
|
||||
self.play(LaggedStart(
|
||||
Write(apple),
|
||||
FadeIn(google),
|
||||
lag_ratio=0.7,
|
||||
))
|
||||
self.wait()
|
||||
self.play(ShowCreation(arrows, run_time=2))
|
||||
self.wait()
|
||||
|
||||
def get_apple_logo(self):
|
||||
result = SVGMobject("apple_logo")
|
||||
result.set_color("#b3b3b3")
|
||||
return result
|
||||
|
||||
def get_google_logo(self):
|
||||
result = ImageMobject("google_logo_black")
|
||||
return result
|
||||
|
||||
|
||||
class LocationTracking(Scene):
|
||||
def construct(self):
|
||||
question = TextMobject(
|
||||
"Would you like this company to track\\\\",
|
||||
"and occasionally sell your location?"
|
||||
)
|
||||
question.to_edge(UP, buff=LARGE_BUFF)
|
||||
|
||||
slider = Rectangle(width=1.25, height=0.5)
|
||||
slider.round_corners(radius=0.25)
|
||||
slider.set_fill(GREEN, 1)
|
||||
slider.next_to(question, DOWN, buff=MED_LARGE_BUFF)
|
||||
|
||||
dot = Dot(radius=0.25)
|
||||
dot.set_fill(GREY_C, 1)
|
||||
dot.set_stroke(WHITE, 3)
|
||||
dot.move_to(slider, RIGHT)
|
||||
|
||||
morty = Mortimer()
|
||||
morty.next_to(slider, RIGHT)
|
||||
morty.to_edge(DOWN)
|
||||
|
||||
bubble = morty.get_bubble(
|
||||
height=2,
|
||||
width=3,
|
||||
direction=LEFT,
|
||||
)
|
||||
|
||||
answer = TextMobject("Um...", "no.")
|
||||
answer.set_height(0.4)
|
||||
answer.set_color(YELLOW)
|
||||
bubble.add_content(answer)
|
||||
|
||||
self.add(morty)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(question),
|
||||
Write(slider),
|
||||
FadeIn(dot),
|
||||
)
|
||||
self.play(morty.change, "confused", slider)
|
||||
self.play(Blink(morty))
|
||||
self.play(
|
||||
FadeIn(bubble),
|
||||
Write(answer[0]),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
dot.move_to, slider, LEFT,
|
||||
slider.set_fill, {"opacity": 0},
|
||||
FadeIn(answer[1]),
|
||||
morty.change, "sassy"
|
||||
)
|
||||
self.play(Blink(morty))
|
||||
self.wait(2)
|
||||
self.play(Blink(morty))
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class MoreLinks(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("See more links\\\\in the description.")
|
||||
words.scale(2)
|
||||
words.to_edge(UP, buff=2)
|
||||
arrows = VGroup(*[
|
||||
Vector(1.5 * DOWN, stroke_width=10)
|
||||
for x in range(4)
|
||||
])
|
||||
arrows.arrange(RIGHT, buff=0.75)
|
||||
arrows.next_to(words, DOWN, buff=0.5)
|
||||
for arrow, color in zip(arrows, [BLUE_D, BLUE_C, BLUE_E, GREY_BROWN]):
|
||||
arrow.set_color(color)
|
||||
self.play(Write(words))
|
||||
self.play(LaggedStartMap(ShowCreation, arrows))
|
||||
self.wait()
|
||||
|
||||
|
||||
class LDMEndScreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"scroll_time": 20,
|
||||
"specific_patrons": [
|
||||
"1stViewMaths",
|
||||
"Aaron",
|
||||
"Adam Dřínek",
|
||||
"Adam Margulies",
|
||||
"Aidan Shenkman",
|
||||
"Alan Stein",
|
||||
"Albin Egasse",
|
||||
"Alex Mijalis",
|
||||
"Alexander Mai",
|
||||
"Alexis Olson",
|
||||
"Ali Yahya",
|
||||
"Andreas Snekloth Kongsgaard",
|
||||
"Andrew Busey",
|
||||
"Andrew Cary",
|
||||
"Andrew R. Whalley",
|
||||
"Aravind C V",
|
||||
"Arjun Chakroborty",
|
||||
"Arthur Zey",
|
||||
"Ashwin Siddarth",
|
||||
"Augustine Lim",
|
||||
"Austin Goodman",
|
||||
"Avi Finkel",
|
||||
"Awoo",
|
||||
"Axel Ericsson",
|
||||
"Ayan Doss",
|
||||
"AZsorcerer",
|
||||
"Barry Fam",
|
||||
"Bartosz Burclaf",
|
||||
"Ben Delo",
|
||||
"Benjamin Bailey",
|
||||
"Bernd Sing",
|
||||
"Bill Gatliff",
|
||||
"Boris Veselinovich",
|
||||
"Bradley Pirtle",
|
||||
"Brandon Huang",
|
||||
"Brendan Shah",
|
||||
"Brian Cloutier",
|
||||
"Brian Staroselsky",
|
||||
"Britt Selvitelle",
|
||||
"Britton Finley",
|
||||
"Burt Humburg",
|
||||
"Calvin Lin",
|
||||
"Carl-Johan R. Nordangård",
|
||||
"Charles Southerland",
|
||||
"Charlie N",
|
||||
"Chris Connett",
|
||||
"Chris Druta",
|
||||
"Christian Kaiser",
|
||||
"cinterloper",
|
||||
"Clark Gaebel",
|
||||
"Colwyn Fritze-Moor",
|
||||
"Corey Ogburn",
|
||||
"D. Sivakumar",
|
||||
"Dan Herbatschek",
|
||||
"Daniel Brown",
|
||||
"Daniel Herrera C",
|
||||
"Darrell Thomas",
|
||||
"Dave B",
|
||||
"Dave Cole",
|
||||
"Dave Kester",
|
||||
"dave nicponski",
|
||||
"David B. Hill",
|
||||
"David Clark",
|
||||
"David Gow",
|
||||
"Delton Ding",
|
||||
"Dominik Wagner",
|
||||
"Eduardo Rodriguez",
|
||||
"Emilio Mendoza",
|
||||
"emptymachine",
|
||||
"Eric Younge",
|
||||
"Eryq Ouithaqueue",
|
||||
"Federico Lebron",
|
||||
"Fernando Via Canel",
|
||||
"Frank R. Brown, Jr.",
|
||||
"gary",
|
||||
"Giovanni Filippi",
|
||||
"Goodwine",
|
||||
"Hal Hildebrand",
|
||||
"Heptonion",
|
||||
"Hitoshi Yamauchi",
|
||||
"Isaac Gubernick",
|
||||
"Ivan Sorokin",
|
||||
"Jacob Baxter",
|
||||
"Jacob Harmon",
|
||||
"Jacob Hartmann",
|
||||
"Jacob Magnuson",
|
||||
"Jalex Stark",
|
||||
"Jameel Syed",
|
||||
"James Beall",
|
||||
"Jason Hise",
|
||||
"Jayne Gabriele",
|
||||
"Jean-Manuel Izaret",
|
||||
"Jeff Dodds",
|
||||
"Jeff Linse",
|
||||
"Jeff Straathof",
|
||||
"Jeffrey Wolberg",
|
||||
"Jimmy Yang",
|
||||
"Joe Pregracke",
|
||||
"Johan Auster",
|
||||
"John C. Vesey",
|
||||
"John Camp",
|
||||
"John Haley",
|
||||
"John Le",
|
||||
"John Luttig",
|
||||
"John Rizzo",
|
||||
"John V Wertheim",
|
||||
"jonas.app",
|
||||
"Jonathan Heckerman",
|
||||
"Jonathan Wilson",
|
||||
"Joseph John Cox",
|
||||
"Joseph Kelly",
|
||||
"Josh Kinnear",
|
||||
"Joshua Claeys",
|
||||
"Joshua Ouellette",
|
||||
"Juan Benet",
|
||||
"Julien Dubois",
|
||||
"Kai-Siang Ang",
|
||||
"Kanan Gill",
|
||||
"Karl Niu",
|
||||
"Kartik Cating-Subramanian",
|
||||
"Kaustuv DeBiswas",
|
||||
"Killian McGuinness",
|
||||
"kkm",
|
||||
"Klaas Moerman",
|
||||
"Kristoffer Börebäck",
|
||||
"Kros Dai",
|
||||
"L0j1k",
|
||||
"Lael S Costa",
|
||||
"LAI Oscar",
|
||||
"Lambda GPU Workstations",
|
||||
"Laura Gast",
|
||||
"Lee Redden",
|
||||
"Linh Tran",
|
||||
"Luc Ritchie",
|
||||
"Ludwig Schubert",
|
||||
"Lukas Biewald",
|
||||
"Lukas Zenick",
|
||||
"Magister Mugit",
|
||||
"Magnus Dahlström",
|
||||
"Magnus Hiie",
|
||||
"Manoj Rewatkar - RITEK SOLUTIONS",
|
||||
"Mark B Bahu",
|
||||
"Mark Heising",
|
||||
"Mark Hopkins",
|
||||
"Mark Mann",
|
||||
"Martin Price",
|
||||
"Mathias Jansson",
|
||||
"Matt Godbolt",
|
||||
"Matt Langford",
|
||||
"Matt Roveto",
|
||||
"Matt Russell",
|
||||
"Matteo Delabre",
|
||||
"Matthew Bouchard",
|
||||
"Matthew Cocke",
|
||||
"Maxim Nitsche",
|
||||
"Michael Bos",
|
||||
"Michael Hardel",
|
||||
"Michael W White",
|
||||
"Mirik Gogri",
|
||||
"Molly Mackinlay",
|
||||
"Mustafa Mahdi",
|
||||
"Márton Vaitkus",
|
||||
"Nero Li",
|
||||
"Nicholas Cahill",
|
||||
"Nikita Lesnikov",
|
||||
"Nitu Kitchloo",
|
||||
"Oleg Leonov",
|
||||
"Oliver Steele",
|
||||
"Omar Zrien",
|
||||
"Omer Tuchfeld",
|
||||
"Patrick Gibson",
|
||||
"Patrick Lucas",
|
||||
"Pavel Dubov",
|
||||
"Pesho Ivanov",
|
||||
"Petar Veličković",
|
||||
"Peter Ehrnstrom",
|
||||
"Peter Francis",
|
||||
"Peter Mcinerney",
|
||||
"Pierre Lancien",
|
||||
"Pradeep Gollakota",
|
||||
"Rafael Bove Barrios",
|
||||
"Raghavendra Kotikalapudi",
|
||||
"Randy C. Will",
|
||||
"rehmi post",
|
||||
"Rex Godby",
|
||||
"Ripta Pasay",
|
||||
"Rish Kundalia",
|
||||
"Roman Sergeychik",
|
||||
"Roobie",
|
||||
"Ryan Atallah",
|
||||
"Samuel Judge",
|
||||
"SansWord Huang",
|
||||
"Scott Gray",
|
||||
"Scott Walter, Ph.D.",
|
||||
"soekul",
|
||||
"Solara570",
|
||||
"Spyridon Michalakis",
|
||||
"Stephen Shanahan",
|
||||
"Steve Huynh",
|
||||
"Steve Muench",
|
||||
"Steve Sperandeo",
|
||||
"Steven Siddals",
|
||||
"Stevie Metke",
|
||||
"Sundar Subbarayan",
|
||||
"supershabam",
|
||||
"Suteerth Vishnu",
|
||||
"Suthen Thomas",
|
||||
"Tal Einav",
|
||||
"Taras Bobrovytsky",
|
||||
"Tauba Auerbach",
|
||||
"Ted Suzman",
|
||||
"Terry Hayes",
|
||||
"THIS IS THE point OF NO RE tUUurRrhghgGHhhnnn",
|
||||
"Thomas J Sargent",
|
||||
"Thomas Tarler",
|
||||
"Tianyu Ge",
|
||||
"Tihan Seale",
|
||||
"Tim Erbes",
|
||||
"Tim Kazik",
|
||||
"Tomasz Legutko",
|
||||
"Tyler Herrmann",
|
||||
"Tyler Parcell",
|
||||
"Tyler VanValkenburg",
|
||||
"Tyler Veness",
|
||||
"Ubiquity Ventures",
|
||||
"Vassili Philippov",
|
||||
"Vasu Dubey",
|
||||
"Veritasium",
|
||||
"Vignesh Ganapathi Subramanian",
|
||||
"Vinicius Reis",
|
||||
"Vladimir Solomatin",
|
||||
"Wooyong Ee",
|
||||
"Xuanji Li",
|
||||
"Yana Chernobilsky",
|
||||
"Yavor Ivanov",
|
||||
"Yetinother",
|
||||
"YinYangBalance.Asia",
|
||||
"Yu Jun",
|
||||
"Yurii Monastyrshyn",
|
||||
"Zachariah Rosenberg",
|
||||
],
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
from active_projects.diffyq.part1.pendulum import *
|
||||
from active_projects.diffyq.part1.staging import *
|
||||
from active_projects.diffyq.part1.pi_scenes import *
|
||||
from active_projects.diffyq.part1.phase_space import *
|
||||
from active_projects.diffyq.part1.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part1"
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
IntroducePendulum,
|
||||
MultiplePendulumsOverlayed,
|
||||
PeriodFormula,
|
||||
FormulasAreLies,
|
||||
MediumAnglePendulum,
|
||||
MediumHighAnglePendulum,
|
||||
HighAnglePendulum,
|
||||
LowAnglePendulum,
|
||||
SomeOfYouWatching,
|
||||
SmallAngleApproximationTex,
|
||||
VeryLowAnglePendulum,
|
||||
FormulasAreLies,
|
||||
TourOfDifferentialEquations,
|
||||
WherePendulumLeads,
|
||||
LongDoublePendulum,
|
||||
# FollowThisThread,
|
||||
StrogatzQuote,
|
||||
ShowHorizontalDashedLine,
|
||||
RabbitFoxPopulations,
|
||||
RabbitFoxEquation,
|
||||
# Something...
|
||||
ShowSimpleTrajectory,
|
||||
SimpleProjectileEquation,
|
||||
SimpleProjectileEquationVGraphFreedom,
|
||||
ShowGravityAcceleration,
|
||||
UniversalGravityLawSymbols,
|
||||
ExampleTypicalODE,
|
||||
AnalyzePendulumForce,
|
||||
ShowSineValues,
|
||||
BuildUpEquation,
|
||||
AirResistanceBrace,
|
||||
ShowDerivativeVideo,
|
||||
SubtleAirCurrents,
|
||||
SimpleDampenedPendulum,
|
||||
DefineODE,
|
||||
SecondOrderEquationExample,
|
||||
ODEvsPDEinFrames,
|
||||
ProveTeacherWrong,
|
||||
SetAsideSeekingSolution,
|
||||
#
|
||||
WriteInRadians,
|
||||
XEqLThetaToCorner,
|
||||
ComingUp,
|
||||
InputLabel,
|
||||
SoWhatIsThetaThen,
|
||||
ReallyHardToSolve,
|
||||
ReasonForSolution,
|
||||
PhysicistPhaseSpace,
|
||||
GleickQuote,
|
||||
SpectrumOfStartingStates,
|
||||
WritePhaseFlow,
|
||||
AskAboutStability,
|
||||
LoveExample,
|
||||
PassageOfTime,
|
||||
LovePhaseSpace,
|
||||
ComparePhysicsToLove,
|
||||
FramesComparingPhysicsToLove,
|
||||
SetupToTakingManyTinySteps,
|
||||
ShowClutterPrevention,
|
||||
# VisualizeHeightSlopeCurvature,
|
||||
VisualizeStates,
|
||||
ReferencePiCollisionStateSpaces,
|
||||
IntroduceVectorField,
|
||||
XComponentArrows,
|
||||
BreakingSecondOrderIntoTwoFirstOrder,
|
||||
ShowPendulumPhaseFlow,
|
||||
ShowHighVelocityCase,
|
||||
TweakMuInFormula,
|
||||
TweakMuInVectorField,
|
||||
FromODEToVectorField,
|
||||
LorenzVectorField,
|
||||
ThreeBodiesInSpace,
|
||||
AltThreeBodiesInSpace,
|
||||
TwoBodiesInSpace,
|
||||
TwoBodiesWithZPart,
|
||||
ThreeBodyTitle,
|
||||
ThreeBodySymbols,
|
||||
#
|
||||
HighAmplitudePendulum,
|
||||
WritePhaseSpace,
|
||||
#
|
||||
AskAboutActuallySolving,
|
||||
WriteODESolvingCode,
|
||||
TakeManyTinySteps,
|
||||
ManyStepsFromDifferentStartingPoints,
|
||||
InaccurateComputation,
|
||||
HungerForExactness,
|
||||
ShowRect,
|
||||
ShowSquare,
|
||||
JumpToThisPoint,
|
||||
ThreeBodyEquation,
|
||||
ItGetsWorse,
|
||||
ChaosTitle,
|
||||
RevisitQuote,
|
||||
EndScreen,
|
||||
Thumbnail,
|
||||
]
|
|
@ -1,41 +0,0 @@
|
|||
from active_projects.diffyq.part2.staging import *
|
||||
from active_projects.diffyq.part2.fourier_series import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.pi_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part2"
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
BrownianMotion,
|
||||
BlackScholes,
|
||||
ContrastChapters1And2,
|
||||
FourierSeriesIntro,
|
||||
FourierSeriesIntroBackground20,
|
||||
ExplainCircleAnimations,
|
||||
# FourierSeriesIntroBackground4,
|
||||
# FourierSeriesIntroBackground8,
|
||||
# FourierSeriesIntroBackground12,
|
||||
TwoDBodyWithManyTemperatures,
|
||||
TwoDBodyWithManyTemperaturesGraph,
|
||||
TwoDBodyWithManyTemperaturesContour,
|
||||
BringTwoRodsTogether,
|
||||
ShowEvolvingTempGraphWithArrows,
|
||||
# TodaysTargetWrapper,
|
||||
WriteHeatEquation,
|
||||
ReactionsToInitialHeatEquation,
|
||||
TalkThrough1DHeatGraph,
|
||||
ShowCubeFormation,
|
||||
CompareInputsOfGeneralCaseTo1D,
|
||||
ContrastXChangesToTChanges,
|
||||
ShowPartialDerivativeSymbols,
|
||||
WriteHeatEquation,
|
||||
ShowCurvatureToRateOfChangeIntuition,
|
||||
ContrastPDEToODE,
|
||||
TransitionToTempVsTime,
|
||||
Show1DAnd3DEquations,
|
||||
#
|
||||
AskAboutWhereEquationComesFrom,
|
||||
DiscreteSetup,
|
||||
]
|
|
@ -1,70 +0,0 @@
|
|||
from active_projects.diffyq.part3.staging import *
|
||||
from active_projects.diffyq.part3.temperature_graphs import *
|
||||
from active_projects.diffyq.part3.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part3.wordy_scenes import *
|
||||
from active_projects.diffyq.part3.discrete_case import *
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part3"
|
||||
SCENES_IN_ORDER = [
|
||||
LastChapterWrapper,
|
||||
ThreeConstraints,
|
||||
OceanOfPossibilities,
|
||||
ThreeMainObservations,
|
||||
SimpleCosExpGraph,
|
||||
AddMultipleSolutions,
|
||||
FourierSeriesIllustraiton,
|
||||
BreakDownAFunction,
|
||||
SineCurveIsUnrealistic,
|
||||
AnalyzeSineCurve,
|
||||
EquationAboveSineAnalysis,
|
||||
ExponentialDecay,
|
||||
InvestmentGrowth,
|
||||
GrowingPileOfMoney,
|
||||
CarbonDecayCurve,
|
||||
CarbonDecayingInMammoth,
|
||||
SineWaveScaledByExp,
|
||||
ShowSinExpDerivatives,
|
||||
IfOnly,
|
||||
BoundaryConditionInterlude,
|
||||
BoundaryConditionReference,
|
||||
GiantCross,
|
||||
SimulateRealSineCurve,
|
||||
DerivativesOfLinearFunction,
|
||||
StraightLine3DGraph,
|
||||
SimulateLinearGraph,
|
||||
EmphasizeBoundaryPoints,
|
||||
ShowNewRuleAtDiscreteBoundary,
|
||||
DiscreteEvolutionPoint25,
|
||||
DiscreteEvolutionPoint1,
|
||||
FlatEdgesForDiscreteEvolution,
|
||||
FlatEdgesForDiscreteEvolutionTinySteps,
|
||||
FlatEdgesContinuousEvolution,
|
||||
FlatAtBoundaryWords,
|
||||
SlopeToHeatFlow,
|
||||
CloserLookAtStraightLine,
|
||||
WriteOutBoundaryCondition,
|
||||
SoWeGotNowhere,
|
||||
ManipulateSinExpSurface,
|
||||
HeatEquationFrame,
|
||||
ShowFreq1CosExpDecay,
|
||||
ShowFreq2CosExpDecay,
|
||||
ShowFreq4CosExpDecay,
|
||||
CompareFreqDecays1to2,
|
||||
CompareFreqDecays1to4,
|
||||
CompareFreqDecays2to4,
|
||||
ShowHarmonics,
|
||||
ShowHarmonicSurfaces,
|
||||
|
||||
# SimpleCosExpGraph,
|
||||
# AddMultipleSolutions,
|
||||
# IveHeardOfThis,
|
||||
# FourierSeriesOfLineIllustration,
|
||||
# InFouriersShoes,
|
||||
]
|
||||
|
||||
PART_4_SCENES = [
|
||||
FourierSeriesIllustraiton,
|
||||
FourierNameIntro,
|
||||
CircleAnimationOfF,
|
||||
]
|
|
@ -1,65 +0,0 @@
|
|||
from active_projects.diffyq.part4.staging import *
|
||||
from active_projects.diffyq.part4.fourier_series_scenes import *
|
||||
from active_projects.diffyq.part4.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part4.three_d_graphs import *
|
||||
from active_projects.diffyq.part4.temperature_scenes import *
|
||||
from active_projects.diffyq.part4.complex_functions import *
|
||||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
from active_projects.diffyq.part3.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ComplexFourierSeriesExample,
|
||||
FourierOfFourier,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierSeriesFormula,
|
||||
RelationToOtherVideos,
|
||||
WhyWouldYouCare,
|
||||
ShowLinearity,
|
||||
CombineSeveralSolutions,
|
||||
FourierGainsImmortality,
|
||||
SolveForWavesNothingElse,
|
||||
CycleThroughManyLinearCombinations,
|
||||
StepFunctionExample,
|
||||
WhichWavesAreAvailable,
|
||||
AlternateBoundaryConditions,
|
||||
AskQuestionOfGraph,
|
||||
CommentOnFouriersImmortality,
|
||||
HangOnThere,
|
||||
ShowInfiniteSum,
|
||||
TechnicalNuances,
|
||||
BreakDownStepFunction,
|
||||
StepFunctionSolutionFormla,
|
||||
# How to compute
|
||||
FourierSeriesOfLineIllustration,
|
||||
GeneralizeToComplexFunctions,
|
||||
ClarifyInputAndOutput,
|
||||
GraphForFlattenedPi,
|
||||
PiFourierSeries,
|
||||
RealValuedFunctionFourierSeries,
|
||||
YouSaidThisWasEasier,
|
||||
AskAboutComplexNotVector,
|
||||
SimpleComplexExponentExample,
|
||||
LooseWithLanguage,
|
||||
DemonstrateAddingArrows,
|
||||
TRangingFrom0To1,
|
||||
LabelRotatingVectors,
|
||||
IntegralTrick,
|
||||
SwapIntegralAndSum,
|
||||
FootnoteOnSwappingIntegralAndSum,
|
||||
FormulaOutOfContext,
|
||||
ShowRangeOfCnFormulas,
|
||||
DescribeSVG,
|
||||
# TODO
|
||||
IncreaseOrderOfApproximation,
|
||||
ShowStepFunctionIn2dView,
|
||||
StepFunctionIntegral,
|
||||
GeneralChallenge,
|
||||
|
||||
# Oldies
|
||||
# FourierSeriesIllustraiton,
|
||||
# FourierNameIntro,
|
||||
# CircleAnimationOfF,
|
||||
]
|
|
@ -1,5 +0,0 @@
|
|||
from active_projects.diffyq.part5.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part5"
|
||||
SCENES_IN_ORDER = [
|
||||
]
|
|
@ -1,23 +0,0 @@
|
|||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ZoomedInFourierSeriesExample,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample100x,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier,
|
||||
SigmaZoomedInFourierSeriesExample,
|
||||
SigmaFourierSeriesExampleWithRectForZoom,
|
||||
NailAndGearZoomedInFourierSeriesExample,
|
||||
NailAndGearFourierSeriesExampleWithRectForZoom,
|
||||
TrebleClefZoomedInFourierSeriesExample,
|
||||
TrebleClefFourierSeriesExampleWithRectForZoom,
|
||||
FourierOfSeattle,
|
||||
FourierOfSeattleZoomedIn,
|
||||
FourierOfBritain,
|
||||
FourierOfBritainZoomedIn,
|
||||
FourierOfHilbert,
|
||||
FourierOfHilbertZoomedIn,
|
||||
]
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue