Пример #1
0
def set_test_scene(scene_object, module_name):
    """Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only
    when setting up tests. Please refer to the wiki.

    Parameters
    ----------
    scene_object : :class:`~.Scene`
        The scene with wich we want to set up a new test.
    module_name : :class:`str`
        The name of the module in which the functionnality tested is contained. For example, 'Write' is contained in the module 'creation'. This will be used in the folder architecture
        of '/tests_data'.

    Examples
    --------
    Normal usage::
        set_test_scene(DotTest, "geometry")
    """
    file_writer_config["skip_animations"] = True
    config["pixel_height"] = 480
    config["pixel_width"] = 854
    config["frame_rate"] = 15

    scene = scene_object()
    data = scene.get_frame()
    path = os.path.join("manim", "tests", "tests_data", "{}".format(module_name))
    if not os.path.isdir(path):
        os.makedirs(path)
    np.save(os.path.join(path, str(scene)), data)
    logger.info("Test data saved in " + path + "\n")
Пример #2
0
def set_test_scene(scene_object, module_name):
    """Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only
    when setting up tests. Please refer to the wiki.

    Parameters
    ----------
    scene_object : :class:`~.Scene`
        The scene with which we want to set up a new test.
    module_name : :class:`str`
        The name of the module in which the functionality tested is contained. For example, ``Write`` is contained in the module ``creation``. This will be used in the folder architecture
        of ``/tests_data``.

    Examples
    --------
    Normal usage::
        set_test_scene(DotTest, "geometry")

    """
    config["write_to_movie"] = False
    config["disable_caching"] = True
    config["format"] = "png"
    config["pixel_height"] = 480
    config["pixel_width"] = 854
    config["frame_rate"] = 15

    with tempfile.TemporaryDirectory() as tmpdir:
        os.makedirs(os.path.join(tmpdir, "tex"))
        config["text_dir"] = os.path.join(tmpdir, "text")
        config["tex_dir"] = os.path.join(tmpdir, "tex")
        scene = scene_object(skip_animations=True)
        scene.render()
        data = scene.renderer.get_frame()

    assert not np.all(
        data == np.array([0, 0, 0, 255]),
    ), f"Control data generated for {str(scene)} only contains empty pixels."
    assert data.shape == (480, 854, 4)
    tests_directory = os.path.dirname(
        os.path.dirname(os.path.abspath(__file__)))
    path_control_data = os.path.join(
        tests_directory,
        "control_data",
        "graphical_units_data",
    )
    path = os.path.join(path_control_data, module_name)
    if not os.path.isdir(path):
        os.makedirs(path)
    np.savez_compressed(os.path.join(path, str(scene)), frame_data=data)
    logger.info(f"Test data for {str(scene)} saved in {path}\n")
Пример #3
0
 def set_style(self, fill_opacity, **kwargs):
     # Unchangeable style, except for fill_opacity
     # All other style arguments are ignored
     super().set_style(
         stroke_color=BLACK,
         stroke_width=0,
         fill_color=BLACK,
         fill_opacity=fill_opacity,
     )
     if len(kwargs) > 0:
         logger.info(
             "Argument %s is ignored in BackgroundRectangle.set_style.",
             kwargs,
         )
     return self
Пример #4
0
def set_test_scene(scene_object, module_name):
    """Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only
    when setting up tests. Please refer to the wiki.

    Parameters
    ----------
    scene_object : :class:`~.Scene`
        The scene with wich we want to set up a new test.
    module_name : :class:`str`
        The name of the module in which the functionnality tested is contained. For example, 'Write' is contained in the module 'creation'. This will be used in the folder architecture
        of '/tests_data'.

    Examples
    --------
    Normal usage::
        set_test_scene(DotTest, "geometry")
    """

    CONFIG_TEST = {
        'camera_config': {
            'frame_rate': 15,
            'pixel_height': 480,
            'pixel_width': 854
        },
        'end_at_animation_number': None,
        'file_writer_config': {
            'file_name': None,
            'input_file_path': 'test.py',
            'movie_file_extension': '.mp4',
            'png_mode': 'RGB',
            'save_as_gif': False,
            'save_last_frame': False,
            'save_pngs': False,
            'write_to_movie': False
        },
        'leave_progress_bars': False,
        'skip_animations': True,
        'start_at_animation_number': None
    }

    scene = scene_object(**CONFIG_TEST)
    data = scene.get_frame()
    path = os.path.join("manim", "tests", "tests_data",
                        "{}".format(module_name))
    if not os.path.isdir(path):
        os.makedirs(path)
    np.save(os.path.join(path, str(scene)), data)
    logger.info('Test data saved in ' + path + '\n')
Пример #5
0
def open_media_file(file_writer):
    file_paths = []

    if config["save_last_frame"]:
        file_paths.append(file_writer.image_file_path)
    if write_to_movie() and not is_gif_format():
        file_paths.append(file_writer.movie_file_path)
    if write_to_movie() and is_gif_format():
        file_paths.append(file_writer.gif_file_path)

    for file_path in file_paths:
        if config["show_in_file_browser"]:
            open_file(file_path, True)
        if config["preview"]:
            open_file(file_path, False)

            logger.info(f"Previewed File at: '{file_path}'")
Пример #6
0
def save_control_data_from_video(path_to_video: str, name: str) -> None:
    """Helper used to set up a new test that will compare videos.

    This will create a new ``.json`` file in ``control_data/videos_data`` that contains:
    - the name of the video,
    - the metadata of the video, like fps and resolution and
    - the paths of all files in the sections subdirectory (like section videos).

    Refer to the documentation for more information.

    Parameters
    ----------
    path_to_video : :class:`str`
        Path to the video to extract information from.
    name : :class:`str`
        Name of the test. The .json file will be named with it.

    See Also
    --------
    tests/utils/video_tester.py : read control data and compare with output of test
    """
    path_to_sections = os.path.join(
        pathlib.Path(path_to_video).parent.absolute(), "sections")
    tests_directory = os.path.dirname(
        os.path.dirname(os.path.abspath(__file__)))
    path_control_data = os.path.join(tests_directory, "control_data",
                                     "videos_data")
    # this is the name of the section used in the test, not the name of the test itself, it can be found as a parameter of this function
    scene_name = "".join(os.path.basename(path_to_video).split(".")[:-1])

    movie_metadata = get_video_metadata(path_to_video)
    section_dir_layout = get_section_dir_layout(path_to_sections)
    section_index = get_section_index(
        os.path.join(path_to_sections, f"{scene_name}.json"))
    data = {
        "name": name,
        "movie_metadata": movie_metadata,
        "section_dir_layout": section_dir_layout,
        "section_index": section_index,
    }
    path_saved = os.path.join(path_control_data, f"{name}.json")
    with open(path_saved, "w") as f:
        json.dump(data, f, indent=4)
    logger.info(f"Data for {name} saved in {path_saved}")
Пример #7
0
def set_test_scene(scene_object, module_name):
    """Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only
    when setting up tests. Please refer to the wiki.

    Parameters
    ----------
    scene_object : :class:`~.Scene`
        The scene with wich we want to set up a new test.
    module_name : :class:`str`
        The name of the module in which the functionnality tested is contained. For example, 'Write' is contained in the module 'creation'. This will be used in the folder architecture
        of '/tests_data'.

    Examples
    --------
    Normal usage::

        set_test_scene(DotTest, "geometry")
    """

    file_writer_config["skip_animations"] = True
    file_writer_config["write_to_movie"] = False
    file_writer_config["disable_caching"] = True
    config["pixel_height"] = 480
    config["pixel_width"] = 854
    config["frame_rate"] = 15

    with tempfile.TemporaryDirectory() as tmpdir:
        os.makedirs(os.path.join(tmpdir, "tex"))
        file_writer_config["text_dir"] = os.path.join(tmpdir, "text")
        file_writer_config["tex_dir"] = os.path.join(tmpdir, "tex")
        scene = scene_object()
        data = scene.get_frame()

    tests_directory = os.path.dirname(
        os.path.dirname(os.path.abspath(__file__)))
    path_control_data = os.path.join(tests_directory, "control_data",
                                     "graphical_units_data")
    print(path_control_data)
    path = os.path.join(path_control_data, module_name)
    if not os.path.isdir(path):
        os.makedirs(path)
    np.save(os.path.join(path, str(scene)), data)
    logger.info(f"Test data for {str(scene)} saved in {path}\n")
Пример #8
0
def set_file_logger():
    # Note: The log file name will be
    # <name_of_animation_file>_<name_of_scene>.log, gotten from
    # file_writer_config.  So it can differ from the real name of the scene.
    # <name_of_scene> would only appear if scene name was provided when manim
    # was called.
    scene_name_suffix = "".join(file_writer_config["scene_names"])
    scene_file_name = os.path.basename(file_writer_config["input_file"]).split(".")[0]
    log_file_name = (
        f"{scene_file_name}_{scene_name_suffix}.log"
        if scene_name_suffix
        else f"{scene_file_name}.log"
    )
    log_file_path = os.path.join(file_writer_config["log_dir"], log_file_name)

    file_handler = logging.FileHandler(log_file_path, mode="w")
    file_handler.setFormatter(JSONFormatter())

    logger.addHandler(file_handler)
    logger.info("Log file will be saved in %(logpath)s", {"logpath": log_file_path})
Пример #9
0
def save_control_data_from_video(path_to_video, name):
    """Helper used to set up a new test that will compare videos. This will create a new .json file in control_data/videos_data that contains
    informations tested of the video, including its hash. Refer to the wiki for more informations.

    Parameters
    ----------
    path_to_video : :class:`str`
        Path to the video to extract information from.
    name : :class:`str`
        Name of the test. The .json file will be named with it.
    """
    tests_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    path_control_data = os.path.join(tests_directory, "control_data", "videos_data")
    config_video = get_config_from_video(path_to_video)
    data = {
        "name": name,
        "config": json.loads(config_video)["streams"][0],
    }
    path_saved = os.path.join(path_control_data, f"{name}.json")
    json.dump(data, open(path_saved, "w"), indent=4)
    logger.info(f"Data for {name} saved in {path_saved}")
Пример #10
0
        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,
                    ),
                )
Пример #11
0
 def save_contol_data(self):
     self.frames = self.frames.astype("uint8")
     np.savez_compressed(self.file_path, frame_data=self.frames)
     logger.info(
         f"{self._number_frames_written} control frames saved in {self.file_path}",
     )