def __init__(self, scene_class, module_tested, tmpdir, rgb_atol=0): # Disable the the logs, (--quiet is broken) TODO logging.disable(logging.CRITICAL) tests_directory = Path(__file__).absolute().parent.parent self.path_tests_medias_cache = ( Path(tmpdir) / "test_graphical_units" / "tests_cache" / module_tested / scene_class.__name__ ) self.path_control_data = ( Path(tests_directory) / "control_data" / "graphical_units_data" / module_tested ) self.rgb_atol = rgb_atol # IMPORTANT NOTE : The graphical units tests don't use for now any # custom manim.cfg, since it is impossible to manually select a # manim.cfg from a python file. (see issue #293) config["text_dir"] = Path(self.path_tests_medias_cache) / "Text" config["tex_dir"] = Path(self.path_tests_medias_cache) / "Tex" config["disable_caching"] = True config["quality"] = "low_quality" for dir_temp in [ self.path_tests_medias_cache, config["text_dir"], config["tex_dir"], ]: Path(dir_temp).mkdir(parents=True) with tempconfig({"dry_run": True}): if config["renderer"] == "opengl": self.scene = scene_class(renderer=OpenGLRenderer()) else: self.scene = scene_class(skip_animations=True) self.scene.render()
def __init__(self, scene_class, module_tested, tmpdir, rgb_atol=0): # Disable the the logs, (--quiet is broken) TODO logging.disable(logging.CRITICAL) tests_directory = os.path.dirname( os.path.dirname(os.path.abspath(__file__))) self.path_tests_medias_cache = os.path.join( tmpdir, "test_graphical_units", "tests_cache", module_tested, scene_class.__name__, ) self.path_control_data = os.path.join( tests_directory, "control_data", "graphical_units_data", module_tested, ) self.rgb_atol = rgb_atol # IMPORTANT NOTE : The graphical units tests don't use for now any # custom manim.cfg, since it is impossible to manually select a # manim.cfg from a python file. (see issue #293) config["text_dir"] = os.path.join(self.path_tests_medias_cache, "Text") config["tex_dir"] = os.path.join(self.path_tests_medias_cache, "Tex") config["disable_caching"] = True config["quality"] = "low_quality" for dir_temp in [ self.path_tests_medias_cache, config["text_dir"], config["tex_dir"], ]: os.makedirs(dir_temp) with tempconfig({"dry_run": True}): if config["renderer"] == "opengl": self.scene = scene_class(renderer=OpenGLRenderer()) else: self.scene = scene_class(skip_animations=True) self.scene.render()
def render(**args, ): """Render SCENE(S) from the input FILE. FILE is the file path of the script or a config file. SCENES is an optional list of scenes in the file. """ if args["use_opengl_renderer"]: logger.warning( "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!", ) args["renderer"] = "opengl" if args["use_webgl_renderer"]: logger.warning( "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!", ) args["renderer"] = "webgl" if args["use_webgl_renderer"] and args["use_opengl_renderer"]: logger.warning("You may select only one renderer!") sys.exit() if args["save_as_gif"]: logger.warning( "--save_as_gif is deprecated, please use --format=gif instead!") args["format"] = "gif" if args["save_pngs"]: logger.warning( "--save_pngs is deprecated, please use --format=png instead!") args["format"] = "png" if args["show_in_file_browser"]: logger.warning( "The short form of show_in_file_browser is deprecated and will be moved to support --format.", ) class ClickArgs: def __init__(self, args): for name in args: setattr(self, name, args[name]) def _get_kwargs(self): return list(self.__dict__.items()) def __eq__(self, other): if not isinstance(other, ClickArgs): return NotImplemented return vars(self) == vars(other) def __contains__(self, key): return key in self.__dict__ def __repr__(self): return str(self.__dict__) click_args = ClickArgs(args) if args["jupyter"]: return click_args config.digest_args(click_args) file = Path(config.input_file) if config.renderer == "opengl": from manim.renderer.opengl_renderer import OpenGLRenderer try: renderer = OpenGLRenderer() keep_running = True while keep_running: for SceneClass in scene_classes_from_file(file): scene = SceneClass(renderer) rerun = scene.render() if rerun or config["write_all"]: renderer.num_plays = 0 continue else: keep_running = False break if config["write_all"]: keep_running = False except Exception: error_console.print_exception() sys.exit(1) elif config.renderer == "webgl": try: from manim.grpc.impl import frame_server_impl server = frame_server_impl.get(file) server.start() server.wait_for_termination() except ModuleNotFoundError: console.print( "Dependencies for the WebGL render are missing. Run " "pip install manim[webgl_renderer] to install them.", ) error_console.print_exception() sys.exit(1) else: for SceneClass in scene_classes_from_file(file): try: scene = SceneClass() scene.render() except Exception: error_console.print_exception() sys.exit(1) if config.notify_outdated_version: manim_info_url = "https://pypi.org/pypi/manim/json" warn_prompt = "Cannot check if latest release of manim is installed" req_info = {} try: req_info = requests.get(manim_info_url) req_info.raise_for_status() stable = req_info.json()["info"]["version"] if stable != __version__: console.print( f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.", ) console.print( "You should consider upgrading via [yellow]pip install -U manim[/yellow]", ) except requests.exceptions.HTTPError: logger.debug(f"HTTP Error: {warn_prompt}") except requests.exceptions.ConnectionError: logger.debug(f"Connection Error: {warn_prompt}") except requests.exceptions.Timeout: logger.debug(f"Timed Out: {warn_prompt}") except json.JSONDecodeError: logger.debug(warn_prompt) logger.debug(f"Error decoding JSON from {manim_info_url}") except Exception: logger.debug(f"Something went wrong: {warn_prompt}") return args
def manim( self, line: str, cell: str = None, local_ns: dict[str, Any] = None, ) -> None: r"""Render Manim scenes contained in IPython cells. Works as a line or cell magic. .. hint:: This line and cell magic works best when used in a JupyterLab environment: while all of the functionality is available for classic Jupyter notebooks as well, it is possible that videos sometimes don't update on repeated execution of the same cell if the scene name stays the same. This problem does not occur when using JupyterLab. Please refer to `<https://jupyter.org/>`_ for more information about JupyterLab and Jupyter notebooks. Usage in line mode:: %manim [CLI options] MyAwesomeScene Usage in cell mode:: %%manim [CLI options] MyAwesomeScene class MyAweseomeScene(Scene): def construct(self): ... Run ``%manim --help`` and ``%manim render --help`` for possible command line interface options. .. note:: The maximal width of the rendered videos that are displayed in the notebook can be configured via the ``media_width`` configuration option. The default is set to ``25vw``, which is 25% of your current viewport width. To allow the output to become as large as possible, set ``config.media_width = "100%"``. Examples -------- First make sure to put ``import manim``, or even ``from manim import *`` in a cell and evaluate it. Then, a typical Jupyter notebook cell for Manim could look as follows:: %%manim -v WARNING --disable_caching -qm BannerExample config.media_width = "75%" class BannerExample(Scene): def construct(self): self.camera.background_color = "#ece6e2" banner_large = ManimBanner(dark_theme=False).scale(0.7) self.play(banner_large.create()) self.play(banner_large.expand()) Evaluating this cell will render and display the ``BannerExample`` scene defined in the body of the cell. .. note:: In case you want to hide the red box containing the output progress bar, the ``progress_bar`` config option should be set to ``None``. This can also be done by passing ``--progress_bar None`` as a CLI flag. """ if cell: exec(cell, local_ns) args = line.split() if not len(args) or "-h" in args or "--help" in args or "--version" in args: main(args, standalone_mode=False, prog_name="manim") return modified_args = self.add_additional_args(args) args = main(modified_args, standalone_mode=False, prog_name="manim") with tempconfig(local_ns.get("config", {})): config.digest_args(args) renderer = None if config.renderer == "opengl": # Check if the imported mobjects extend the OpenGLMobject class # meaning ConvertToOpenGL did its job if "OpenGLMobject" in map(lambda cls: cls.__name__, Group.mro()): from manim.renderer.opengl_renderer import OpenGLRenderer renderer = OpenGLRenderer() else: logger.warning( "Renderer must be set to OpenGL in the configuration file " "before importing Manim! Using cairo renderer instead.", ) config.renderer = "cairo" try: SceneClass = local_ns[config["scene_names"][0]] scene = SceneClass(renderer=renderer) scene.render() finally: # Shader cache becomes invalid as the context is destroyed shader_program_cache.clear() # Close OpenGL window here instead of waiting for the main thread to # finish causing the window to stay open and freeze if renderer is not None and renderer.window is not None: renderer.window.close() if config["output_file"] is None: logger.info("No output file produced") return local_path = Path(config["output_file"]).relative_to(Path.cwd()) tmpfile = ( Path(config["media_dir"]) / "jupyter" / f"{_generate_file_name()}{local_path.suffix}" ) if local_path in self.rendered_files: self.rendered_files[local_path].unlink() self.rendered_files[local_path] = tmpfile os.makedirs(tmpfile.parent, exist_ok=True) shutil.copy(local_path, tmpfile) file_type = mimetypes.guess_type(config["output_file"])[0] if file_type.startswith("image"): display(Image(filename=config["output_file"])) return # videos need to be embedded when running in google colab video_embed = "google.colab" in str(get_ipython()) display( Video( tmpfile, html_attributes=f'controls autoplay loop style="max-width: {config["media_width"]};"', embed=video_embed, ), )
def main(): console.print(f"Manim Community [green]v{__version__}[/green]") args = parse_args(sys.argv) if hasattr(args, "cmd"): if args.cmd == "cfg": if args.subcmd: from manim._config import cfg_subcmds if args.subcmd == "write": cfg_subcmds.write(args.level, args.open) elif args.subcmd == "show": cfg_subcmds.show() elif args.subcmd == "export": cfg_subcmds.export(args.dir) else: logger.error("No subcommand provided; Exiting...") elif args.cmd == "plugins": from manim.plugins import plugins_flags if args.list: plugins_flags.list_plugins() elif not args.list: logger.error("No flag provided; Exiting...") # elif args.cmd == "some_other_cmd": # something_else_here() else: config.digest_args(args) input_file = config.get_dir("input_file") if config["use_opengl_renderer"]: from manim.renderer.opengl_renderer import OpenGLRenderer for SceneClass in scene_classes_from_file(input_file): try: renderer = OpenGLRenderer() scene = SceneClass(renderer) scene.render() except Exception: console.print_exception() elif config["use_webgl_renderer"]: try: from manim.grpc.impl import frame_server_impl server = frame_server_impl.get(input_file) server.start() server.wait_for_termination() except ModuleNotFoundError as e: console.print( "Dependencies for the WebGL render are missing. Run " "pip install manim[webgl_renderer] to install them.") console.print_exception() else: for SceneClass in scene_classes_from_file(input_file): try: scene = SceneClass() scene.render() except Exception: console.print_exception()
def render( ctx, **args, ): """Render SCENE(S) from the input FILE. FILE is the file path of the script. SCENES is an optional list of scenes in the file. """ for scene in args["scene_names"]: if str(scene).startswith("-"): logger.warning( dedent( """\ Manim Community has moved to Click for the CLI. This means that options in the CLI are provided BEFORE the positional arguments for your FILE and SCENE(s): `manim render [OPTIONS] [FILE] [SCENES]...` For example: New way - `manim -p -ql file.py SceneName1 SceneName2 ...` Old way - `manim file.py SceneName1 SceneName2 ... -p -ql` To see the help page for the new available options, run: `manim render -h` """ ) ) sys.exit() if args["use_opengl_renderer"]: logger.warning( "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!" ) renderer = "opengl" if args["use_webgl_renderer"]: logger.warning( "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!" ) renderer = "webgl" if args["use_webgl_renderer"] and args["use_opengl_renderer"]: logger.warning("You may select only one renderer!") sys.exit() class ClickArgs: def __init__(self, args): for name in args: setattr(self, name, args[name]) def _get_kwargs(self): return list(self.__dict__.items()) def __eq__(self, other): if not isinstance(other, ClickArgs): return NotImplemented return vars(self) == vars(other) def __contains__(self, key): return key in self.__dict__ def __repr__(self): return str(self.__dict__) click_args = ClickArgs(args) if args["jupyter"]: return click_args config.digest_args(click_args) file = args["file"] if config.renderer == "opengl": from manim.renderer.opengl_renderer import OpenGLRenderer for SceneClass in scene_classes_from_file(file): try: renderer = OpenGLRenderer() scene = SceneClass(renderer) scene.render() except Exception: console.print_exception() elif config.renderer == "webgl": try: from manim.grpc.impl import frame_server_impl server = frame_server_impl.get(file) server.start() server.wait_for_termination() except ModuleNotFoundError: console.print( "Dependencies for the WebGL render are missing. Run " "pip install manim[webgl_renderer] to install them." ) console.print_exception() else: for SceneClass in scene_classes_from_file(file): try: scene = SceneClass() scene.render() except Exception: console.print_exception() if config.notify_outdated_version: manim_info_url = "https://pypi.org/pypi/manim/json" warn_prompt = "Cannot check if latest release of manim is installed" req_info = {} try: req_info = requests.get(manim_info_url) req_info.raise_for_status() except requests.exceptions.HTTPError: logger.debug(f"HTTP Error: {warn_prompt}") except requests.exceptions.ConnectionError: logger.debug(f"Connection Error: {warn_prompt}") except requests.exceptions.Timeout: logger.debug(f"Timed Out: {warn_prompt}") except Exception: logger.debug(f"Something went wrong: {warn_prompt}") try: stable = req_info.json()["info"]["version"] if stable != __version__: console.print( f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available." ) console.print( "You should consider upgrading via [yellow]pip install -U manim[/yellow]" ) except json.JSONDecodeError: logger.debug(warn_prompt) logger.debug(f"Error decoding JSON from {manim_info_url}") return args
def render( ctx, **args, ): """Render SCENE(S) from the input FILE. FILE is the file path of the script. SCENES is an optional list of scenes in the file. """ for scene in args["scene_names"]: if str(scene).startswith("-"): logger.warning( dedent("""\ Manim Community has moved to Click for the CLI. This means that options in the CLI are provided BEFORE the positional arguments for your FILE and SCENE(s): `manim render [OPTIONS] [FILE] [SCENES]...` For example: New way - `manim -p -ql file.py SceneName1 SceneName2 ...` Old way - `manim file.py SceneName1 SceneName2 ... -p -ql` To see the help page for the new available options, run: `manim render -h` """)) sys.exit() if args["use_opengl_renderer"]: logger.warning( "--use_opengl_renderer is deprecated, please use --renderer=opengl instead!" ) renderer = "opengl" if args["use_webgl_renderer"]: logger.warning( "--use_webgl_renderer is deprecated, please use --renderer=webgl instead!" ) renderer = "webgl" if args["use_webgl_renderer"] and args["use_opengl_renderer"]: logger.warning("You may select only one renderer!") sys.exit() class ClickArgs: def __init__(self, args): for name in args: setattr(self, name, args[name]) def _get_kwargs(self): return list(self.__dict__.items()) def __eq__(self, other): if not isinstance(other, ClickArgs): return NotImplemented return vars(self) == vars(other) def __contains__(self, key): return key in self.__dict__ def __repr__(self): return str(self.__dict__) click_args = ClickArgs(args) if args["jupyter"]: return click_args config.digest_args(click_args) file = args["file"] if config.renderer == "opengl": from manim.renderer.opengl_renderer import OpenGLRenderer for SceneClass in scene_classes_from_file(file): try: renderer = OpenGLRenderer() scene = SceneClass(renderer) scene.render() except Exception: console.print_exception() elif config.renderer == "webgl": try: from manim.grpc.impl import frame_server_impl server = frame_server_impl.get(file) server.start() server.wait_for_termination() except ModuleNotFoundError: console.print("Dependencies for the WebGL render are missing. Run " "pip install manim[webgl_renderer] to install them.") console.print_exception() else: for SceneClass in scene_classes_from_file(file): try: scene = SceneClass() scene.render() except Exception: console.print_exception() return args