Merge branch 'master' of github.com:3b1b/manim into diffyq

This commit is contained in:
Grant Sanderson 2019-06-29 15:21:00 -07:00
commit 92f4c0c001
8 changed files with 67 additions and 32 deletions

View file

@ -1,5 +1,4 @@
language: python
sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069)
dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
python: "3.7"
cache: pip

View file

@ -74,19 +74,29 @@ 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.
In order to do this with the Compose file, you must set the `INPUT_PATH`
environment variable to the directory containing your source code and the
`OUTPUT_DIRECTORY` environment variable to the directory where you want media
to be written.
The prebuilt container image has manin 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/dir/for/media \
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`.
<img src=./manim_docker_diagram.png/>
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.

View file

@ -10,7 +10,7 @@ services:
- manim
- --media_dir=/tmp/output
volumes:
- ${INPUT_DIR:?INPUT_DIR environment variable isn't set}:/tmp/input
- ${OUTPUT_DIR:?OUTPUT_DIR environment variable isn't set}:/tmp/output
- ${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"

BIN
manim_docker_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -116,8 +116,13 @@ def parse_cli():
"--media_dir",
help="directory to write media",
)
parser.add_argument(
video_group = parser.add_mutually_exclusive_group()
video_group.add_argument(
"--video_dir",
help="directory to write file tree for video",
)
video_group.add_argument(
"--video_output_dir",
help="directory to write video",
)
parser.add_argument(
@ -207,6 +212,7 @@ def get_configuration(args):
"leave_progress_bars": args.leave_progress_bars,
"media_dir": args.media_dir,
"video_dir": args.video_dir,
"video_output_dir": args.video_output_dir,
"tex_dir": args.tex_dir,
}

View file

@ -3,13 +3,26 @@ import os
MEDIA_DIR = ""
VIDEO_DIR = ""
VIDEO_OUTPUT_DIR = ""
TEX_DIR = ""
def initialize_directories(config):
global MEDIA_DIR
global VIDEO_DIR
global VIDEO_OUTPUT_DIR
global TEX_DIR
if not (config["video_dir"] and config["tex_dir"]):
video_path_specified = config["video_dir"] or config["video_output_dir"]
if not video_path_specified:
VIDEO_DIR = os.path.join(MEDIA_DIR, "videos")
elif config["video_output_dir"]:
VIDEO_OUTPUT_DIR = config["video_output_dir"]
else:
VIDEO_DIR = config["video_dir"]
TEX_DIR = config["tex_dir"] or os.path.join(MEDIA_DIR, "Tex")
if not (video_path_specified and config["tex_dir"]):
if config["media_dir"]:
MEDIA_DIR = config["media_dir"]
else:
@ -26,14 +39,12 @@ def initialize_directories(config):
else:
if config["media_dir"]:
print(
"Ignoring --media_dir, since --video_dir and --tex_dir were "
"both passed"
"Ignoring --media_dir, since both --tex_dir and a video "
"directory were both passed"
)
VIDEO_DIR = config["video_dir"] or os.path.join(MEDIA_DIR, "videos")
TEX_DIR = config["tex_dir"] or os.path.join(MEDIA_DIR, "Tex")
for folder in [VIDEO_DIR, TEX_DIR]:
if not os.path.exists(folder):
for folder in [VIDEO_DIR, VIDEO_OUTPUT_DIR, TEX_DIR]:
if folder != "" and not os.path.exists(folder):
os.makedirs(folder)
TEX_USE_CTEX = False

View file

@ -49,21 +49,30 @@ class SceneFileWriter(object):
module_directory = self.output_directory or self.get_default_module_directory()
scene_name = self.file_name or self.get_default_scene_name()
if self.save_last_frame:
if consts.VIDEO_DIR != "":
image_dir = guarantee_existence(os.path.join(
consts.VIDEO_DIR,
module_directory,
"images",
))
else:
image_dir = guarantee_existence(os.path.join(
consts.VIDEO_OUTPUT_DIR,
"images",
))
self.image_file_path = os.path.join(
image_dir,
add_extension_if_not_present(scene_name, ".png")
)
if self.write_to_movie:
if consts.VIDEO_DIR != "":
movie_dir = guarantee_existence(os.path.join(
consts.VIDEO_DIR,
module_directory,
self.get_resolution_directory(),
))
else:
movie_dir = guarantee_existence(consts.VIDEO_OUTPUT_DIR)
self.movie_file_path = os.path.join(
movie_dir,
add_extension_if_not_present(

View file

@ -44,8 +44,8 @@ def tex_to_dvi(tex_file):
"latex",
"-interaction=batchmode",
"-halt-on-error",
"-output-directory=\'{}\'".format(consts.TEX_DIR),
"\'{}\'".format(tex_file),
"-output-directory=\"{}\"".format(consts.TEX_DIR),
"\"{}\"".format(tex_file),
">",
os.devnull
] if not TEX_USE_CTEX else [
@ -53,8 +53,8 @@ def tex_to_dvi(tex_file):
"-no-pdf",
"-interaction=batchmode",
"-halt-on-error",
"-output-directory=\'{}\'".format(consts.TEX_DIR),
"\'{}\'".format(tex_file),
"-output-directory=\"{}\"".format(consts.TEX_DIR),
"\"{}\"".format(tex_file),
">",
os.devnull
]
@ -79,12 +79,12 @@ def dvi_to_svg(dvi_file, regen_if_exists=False):
if not os.path.exists(result):
commands = [
"dvisvgm",
"\'{}\'".format(dvi_file),
"\"{}\"".format(dvi_file),
"-n",
"-v",
"0",
"-o",
"\'{}\'".format(result),
"\"{}\"".format(result),
">",
os.devnull
]