Skip to content

Commit fa0a82c

Browse files
authored
Implements -q[l|m|h|k] (#514)
Consolidates quality flags under a single --quality or -q flag
1 parent 1e2a390 commit fa0a82c

File tree

9 files changed

+192
-106
lines changed

9 files changed

+192
-106
lines changed

docs/source/changelog.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ New Features
1919
Command line
2020
^^^^^^^^^^^^
2121

22-
#. Add 4k rendering option with the :code:`-k` option
23-
#. High quality rendering has gotten its own short argument (:code:`-e`)
2422
#. Output of 'manim --help' has been improved
2523
#. Implement logging with the :code:`rich` library and a :code:`logger` object instead of plain ol` prints
2624
#. Added a flag :code:`--dry_run`, which doesn’t write any media
@@ -33,6 +31,7 @@ Command line
3331
#. Added a :code:`--verbose` flag
3432
#. You can save the logs to a file by using :code:`--log_to_file`
3533
#. Add experimental javascript rendering with :code:`--use_js_renderer`
34+
#. Add :code:`-q/--quality [k|h|m|l]` flag and removed :code:`-m/-l` flags.
3635

3736

3837
Config system

docs/source/tutorials/configuration.rst

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Usually, manim is ran from the command line by executing
1717
1818
This asks manim to search for a Scene class called :code:`SceneName` inside the
1919
file <file.py> and render it. One can also specify the render quality by using
20-
the flags :code:`-l`, :code:`-m`, :code:`-e`, or :code:`-k`, for low, medium,
20+
the flags :code:`-ql`, :code:`-qm`, :code:`-qh`, or :code:`-qk`, for low, medium,
2121
high, and 4k quality, respectively.
2222

2323
.. code-block:: bash
@@ -46,89 +46,79 @@ The output looks as follows.
4646
.. testoutput::
4747
:options: -ELLIPSIS, +NORMALIZE_WHITESPACE
4848

49-
usage: manim [-h] [-o OUTPUT_FILE] [-p] [-f] [--sound] [--leave_progress_bars]
50-
[-a] [-w] [-s] [-g] [-i] [--disable_caching] [--flush_cache]
51-
[--log_to_file] [-c BACKGROUND_COLOR]
52-
[--background_opacity BACKGROUND_OPACITY] [--media_dir MEDIA_DIR]
53-
[--log_dir LOG_DIR] [--tex_template TEX_TEMPLATE] [--dry_run]
54-
[-t] [-l] [-m] [-e] [-k] [-r RESOLUTION]
55-
[-n FROM_ANIMATION_NUMBER] [--config_file CONFIG_FILE]
56-
[--custom_folders] [-v {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
57-
[--progress_bar True/False]
58-
{cfg} ... file [scene_names [scene_names ...]]
59-
60-
Animation engine for explanatory math videos
61-
62-
positional arguments:
63-
{cfg}
64-
file path to file holding the python code for the scene
65-
scene_names Name of the Scene class you want to see
66-
67-
optional arguments:
68-
-h, --help show this help message and exit
69-
-o OUTPUT_FILE, --output_file OUTPUT_FILE
70-
Specify the name of the output file, if it should be
71-
different from the scene class name
72-
-p, --preview Automatically open the saved file once its done
73-
-f, --show_in_file_browser
74-
Show the output file in the File Browser
75-
--sound Play a success/failure sound
76-
--leave_progress_bars
77-
Leave progress bars displayed in terminal
78-
-a, --write_all Write all the scenes from a file
79-
-w, --write_to_movie Render the scene as a movie file (this is on by
80-
default)
81-
-s, --save_last_frame
82-
Save the last frame only (no movie file is generated)
83-
-g, --save_pngs Save each frame as a png
84-
-i, --save_as_gif Save the video as gif
85-
--disable_caching Disable caching (will generate partial-movie-files
86-
anyway)
87-
--flush_cache Remove all cached partial-movie-files
88-
--log_to_file Log terminal output to file
89-
-c BACKGROUND_COLOR, --background_color BACKGROUND_COLOR
90-
Specify background color
91-
--background_opacity BACKGROUND_OPACITY
92-
Specify background opacity
93-
--media_dir MEDIA_DIR
94-
Directory to store media (including video files)
95-
--log_dir LOG_DIR Directory to store log files
96-
--tex_template TEX_TEMPLATE
97-
Specify a custom TeX template file
98-
--dry_run Do a dry run (render scenes but generate no output
99-
files)
100-
-t, --transparent Render a scene with an alpha channel
101-
-l, --low_quality Render at low quality
102-
-m, --medium_quality Render at medium quality
103-
-e, --high_quality Render at high quality
104-
-k, --fourk_quality Render at 4K quality
105-
-r RESOLUTION, --resolution RESOLUTION
106-
Resolution, passed as "height,width". Overrides the
107-
-l, -m, -e, and -k flags, if present
108-
-n FROM_ANIMATION_NUMBER, --from_animation_number FROM_ANIMATION_NUMBER
109-
Start rendering at the specified animation index,
110-
instead of the first animation. If you pass in two
111-
comma separated values, e.g. '3,6', it will end the
112-
rendering at the second value
113-
--config_file CONFIG_FILE
114-
Specify the configuration file
115-
--custom_folders Use the folders defined in the [custom_folders]
116-
section of the config file to define the output folder
117-
structure
118-
-v {DEBUG,INFO,WARNING,ERROR,CRITICAL}, --verbosity {DEBUG,INFO,WARNING,ERROR,CRITICAL}
119-
Verbosity level. Also changes the ffmpeg log level
120-
unless the latter is specified in the config
121-
--progress_bar True/False
122-
Display the progress bar
123-
124-
Made with <3 by the manim community devs
49+
usage: manim [-h] [-o OUTPUT_FILE] [-p] [-f] [--sound] [--leave_progress_bars] [-a] [-w] [-s] [-g] [-i] [--disable_caching] [--flush_cache] [--log_to_file] [-c BACKGROUND_COLOR]
50+
[--background_opacity BACKGROUND_OPACITY] [--media_dir MEDIA_DIR] [--log_dir LOG_DIR] [--tex_template TEX_TEMPLATE] [--dry_run] [-t] [-q {k,h,m,l}] [--low_quality] [--medium_quality]
51+
[--high_quality] [--fourk_quality] [-r RESOLUTION] [-n FROM_ANIMATION_NUMBER] [--use_js_renderer] [--js_renderer_path JS_RENDERER_PATH] [--config_file CONFIG_FILE] [--custom_folders]
52+
[-v {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--progress_bar True/False]
53+
{cfg} ... file [scene_names [scene_names ...]]
54+
55+
Animation engine for explanatory math videos
56+
57+
positional arguments:
58+
{cfg}
59+
file path to file holding the python code for the scene
60+
scene_names Name of the Scene class you want to see
61+
62+
optional arguments:
63+
-h, --help show this help message and exit
64+
-o OUTPUT_FILE, --output_file OUTPUT_FILE
65+
Specify the name of the output file, if it should be different from the scene class name
66+
-p, --preview Automatically open the saved file once its done
67+
-f, --show_in_file_browser
68+
Show the output file in the File Browser
69+
--sound Play a success/failure sound
70+
--leave_progress_bars
71+
Leave progress bars displayed in terminal
72+
-a, --write_all Write all the scenes from a file
73+
-w, --write_to_movie Render the scene as a movie file (this is on by default)
74+
-s, --save_last_frame
75+
Save the last frame only (no movie file is generated)
76+
-g, --save_pngs Save each frame as a png
77+
-i, --save_as_gif Save the video as gif
78+
--disable_caching Disable caching (will generate partial-movie-files anyway)
79+
--flush_cache Remove all cached partial-movie-files
80+
--log_to_file Log terminal output to file
81+
-c BACKGROUND_COLOR, --background_color BACKGROUND_COLOR
82+
Specify background color
83+
--background_opacity BACKGROUND_OPACITY
84+
Specify background opacity
85+
--media_dir MEDIA_DIR
86+
Directory to store media (including video files)
87+
--log_dir LOG_DIR Directory to store log files
88+
--tex_template TEX_TEMPLATE
89+
Specify a custom TeX template file
90+
--dry_run Do a dry run (render scenes but generate no output files)
91+
-t, --transparent Render a scene with an alpha channel
92+
-q {k,h,m,l}, --quality {k,h,m,l}
93+
Render at specific quality, short form of the --*_quality flags
94+
--low_quality Render at low quality
95+
--medium_quality Render at medium quality
96+
--high_quality Render at high quality
97+
--fourk_quality Render at 4K quality
98+
-r RESOLUTION, --resolution RESOLUTION
99+
Resolution, passed as "height,width". Overrides any quality flags, if present
100+
-n FROM_ANIMATION_NUMBER, --from_animation_number FROM_ANIMATION_NUMBER
101+
Start rendering at the specified animation index, instead of the first animation. If you pass in two comma separated values, e.g. '3,6', it will end the rendering at the second
102+
value
103+
--use_js_renderer Render animations using the javascript frontend
104+
--js_renderer_path JS_RENDERER_PATH
105+
Path to the javascript frontend
106+
--config_file CONFIG_FILE
107+
Specify the configuration file
108+
--custom_folders Use the folders defined in the [custom_folders] section of the config file to define the output folder structure
109+
-v {DEBUG,INFO,WARNING,ERROR,CRITICAL}, --verbosity {DEBUG,INFO,WARNING,ERROR,CRITICAL}
110+
Verbosity level. Also changes the ffmpeg log level unless the latter is specified in the config
111+
--progress_bar True/False
112+
Display the progress bar
113+
114+
Made with <3 by the manim community devs
125115

126116
For example, to render a scene in high quality, but only output the last frame
127117
of the scene instead of the whole video, you can execute
128118

129119
.. code-block:: bash
130120
131-
$ manim <file.py> SceneName -es
121+
$ manim <file.py> SceneName -sqh
132122
133123
The following example specifies the output file name (with the :code:`-o`
134124
flag), renders only the first ten animations (:code:`-n` flag) with a white

manim/config/config.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
import colour
1717

1818
from .. import constants
19-
from .config_utils import _run_config, _init_dirs, _from_command_line
19+
from .config_utils import (
20+
_determine_quality,
21+
_run_config,
22+
_init_dirs,
23+
_from_command_line,
24+
)
2025

2126
from .logger import set_rich_logger, set_file_logger, logger
2227
from ..utils.tex import TexTemplate, TexTemplateFromFile
@@ -80,13 +85,11 @@ def _parse_config(config_parser, args):
8085
# Handle the *_quality flags. These determine the section to read
8186
# and are stored in 'camera_config'. Note the highest resolution
8287
# passed as argument will be used.
83-
for flag in ["fourk_quality", "high_quality", "medium_quality", "low_quality"]:
84-
if getattr(args, flag):
85-
section = config_parser[flag]
86-
break
87-
else:
88-
section = config_parser["CLI"]
89-
config = {opt: section.getint(opt) for opt in config_parser[flag]}
88+
quality = _determine_quality(args)
89+
section = config_parser[quality if quality != "production" else "CLI"]
90+
91+
# Loop over low quality for the keys, could be any quality really
92+
config = {opt: section.getint(opt) for opt in config_parser["low_quality"]}
9093

9194
config["default_pixel_height"] = default.getint("pixel_height")
9295
config["default_pixel_width"] = default.getint("pixel_width")
@@ -152,6 +155,8 @@ def _parse_config(config_parser, args):
152155

153156
args, config_parser, file_writer_config, successfully_read_files = _run_config()
154157
logger.setLevel(file_writer_config["verbosity"])
158+
set_rich_logger(config_parser["logger"], file_writer_config["verbosity"])
159+
155160
if _from_command_line():
156161
logger.debug(
157162
f"Read configuration files: {[os.path.abspath(cfgfile) for cfgfile in successfully_read_files]}"
@@ -163,8 +168,6 @@ def _parse_config(config_parser, args):
163168
file_writer_config["disable_caching"] = True
164169
camera_config = config
165170

166-
# Set the different loggers
167-
set_rich_logger(config_parser["logger"], file_writer_config["verbosity"])
168171
if file_writer_config["log_to_file"]:
169172
# IMPORTANT note about file name : The log file name will be the scene_name get from the args (contained in file_writer_config). So it can differ from the real name of the scene.
170173
log_file_path = os.path.join(

manim/config/config_utils.py

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717

1818
import argparse
1919
import configparser
20+
import logging
2021
import os
2122
import sys
2223

23-
import colour
24-
2524
from .. import constants
26-
from ..utils.tex import TexTemplate, TexTemplateFromFile
2725

2826

2927
def _parse_file_writer_config(config_parser, args):
@@ -349,36 +347,60 @@ def _parse_cli(arg_list, input=True):
349347
# The following are mutually exclusive and each overrides
350348
# FRAME_RATE, PIXEL_HEIGHT, and PIXEL_WIDTH,
351349
parser.add_argument(
352-
"-l",
350+
"-q",
351+
"--quality",
352+
choices=constants.QUALITIES.values(),
353+
help="Render at specific quality, short form of the --*_quality flags",
354+
)
355+
parser.add_argument(
353356
"--low_quality",
354357
action="store_true",
355358
help="Render at low quality",
356359
)
357360
parser.add_argument(
358-
"-m",
359361
"--medium_quality",
360362
action="store_true",
361363
help="Render at medium quality",
362364
)
363365
parser.add_argument(
364-
"-e",
365366
"--high_quality",
366367
action="store_true",
367368
help="Render at high quality",
368369
)
369370
parser.add_argument(
370-
"-k",
371371
"--fourk_quality",
372372
action="store_true",
373373
help="Render at 4K quality",
374374
)
375375

376+
# Deprecated quality flags
377+
parser.add_argument(
378+
"-l",
379+
action="store_true",
380+
help="DEPRECATED: USE -ql or --quality l",
381+
)
382+
parser.add_argument(
383+
"-m",
384+
action="store_true",
385+
help="DEPRECATED: USE -qm or --quality m",
386+
)
387+
parser.add_argument(
388+
"-e",
389+
action="store_true",
390+
help="DEPRECATED: USE -qh or --quality h",
391+
)
392+
parser.add_argument(
393+
"-k",
394+
action="store_true",
395+
help="DEPRECATED: USE -qk or --quality k",
396+
)
397+
376398
# This overrides any of the above
377399
parser.add_argument(
378400
"-r",
379401
"--resolution",
380402
help='Resolution, passed as "height,width". '
381-
"Overrides the -l, -m, -e, and -k flags, if present",
403+
"Overrides any quality flags, if present",
382404
)
383405

384406
# This sets FROM_ANIMATION_NUMBER and UPTO_ANIMATION_NUMBER
@@ -624,3 +646,27 @@ def _init_cfg_subcmd(subparsers):
624646
cfg_export_parser.add_argument("--dir", default=os.getcwd())
625647

626648
return cfg_related
649+
650+
651+
def _determine_quality(args):
652+
old_qualities = {
653+
"k": "fourk_quality",
654+
"e": "high_quality",
655+
"m": "medium_quality",
656+
"l": "low_quality",
657+
}
658+
659+
for quality in constants.QUALITIES.keys():
660+
if getattr(args, quality) or (
661+
hasattr(args, "quality") and args.quality == constants.QUALITIES[quality]
662+
):
663+
return quality
664+
665+
for quality in old_qualities.keys():
666+
if getattr(args, quality):
667+
logging.getLogger("manim").warning(
668+
f"Option -{quality} is deprecated please use the --quality/-q flag."
669+
)
670+
return old_qualities[quality]
671+
672+
return "production"

manim/constants.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,11 @@ class MyText(Text):
126126
"you can either start it prior to running Manim or specify the path to the "
127127
"executable with the --js_renderer_path flag."
128128
)
129+
130+
# Video qualities
131+
QUALITIES = {
132+
"fourk_quality": "k",
133+
"high_quality": "h",
134+
"medium_quality": "m",
135+
"low_quality": "l",
136+
}

tests/test_cli_flags.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from manim import constants
2+
from manim.config.config_utils import _determine_quality, _parse_cli
3+
4+
5+
def test_quality_flags():
6+
# Assert that quality is None when not specifying it
7+
parsed = _parse_cli([], False)
8+
9+
assert not parsed.quality
10+
11+
for quality in constants.QUALITIES.keys():
12+
# Assert that quality is properly set when using -q*
13+
arguments = f"-q{constants.QUALITIES[quality]}".split()
14+
parsed = _parse_cli(arguments, False)
15+
16+
assert parsed.quality == constants.QUALITIES[quality]
17+
assert quality == _determine_quality(parsed)
18+
19+
# Assert that quality is properly set when using -q *
20+
arguments = f"-q {constants.QUALITIES[quality]}".split()
21+
parsed = _parse_cli(arguments, False)
22+
23+
assert parsed.quality == constants.QUALITIES[quality]
24+
assert quality == _determine_quality(parsed)
25+
26+
# Assert that quality is properly set when using --quality *
27+
arguments = f"--quality {constants.QUALITIES[quality]}".split()
28+
parsed = _parse_cli(arguments, False)
29+
30+
assert parsed.quality == constants.QUALITIES[quality]
31+
assert quality == _determine_quality(parsed)
32+
33+
# Assert that quality is properly set when using -*_quality
34+
arguments = f"--{quality}".split()
35+
parsed = _parse_cli(arguments, False)
36+
37+
assert getattr(parsed, quality)
38+
assert quality == _determine_quality(parsed)
39+
40+
# Assert that *_quality is False when not specifying it
41+
parsed = _parse_cli([], False)
42+
43+
assert not getattr(parsed, quality)
44+
assert "production" == _determine_quality(parsed)

0 commit comments

Comments
 (0)