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 construct(self): matrix1 = Matrix( m1, v_buff=1.3, h_buff=0.8, bracket_h_buff=SMALL_BUFF, bracket_v_buff=SMALL_BUFF) matrix1.set_color(DEFAULT_COLOR) matrix1.get_entries()[0].set_color(RECT_COLOR) matrix1.get_entries()[-1].set_color(RECT_COLOR) self.add(matrix1) matrix2 = Matrix( m2, v_buff=1.3, h_buff=0.8, bracket_h_buff=SMALL_BUFF, bracket_v_buff=SMALL_BUFF) matrix2.set_color(DEFAULT_COLOR) self.add(matrix2) equals = MathTex(r'=') self.add(equals) m3 = (m1@m2) matrix3 = Matrix( m3, v_buff=1.3, h_buff=0.8, bracket_h_buff=SMALL_BUFF, bracket_v_buff=SMALL_BUFF) matrix3.set_color(DEFAULT_COLOR) # args = [BLACK]*m3.shape[1] # matrix3.set_column_colors(*args) for i in matrix3.get_entries(): i.set_opacity(0) self.add(matrix3) g = Group(matrix1, matrix2, equals, matrix3).arrange(buff=1).shift(UP) g.set_color(DEFAULT_COLOR) self.add(g) i = 0 for m1_row in matrix1.get_rows(): for m2_column in matrix2.get_columns(): rect_1 = SurroundingRectangle(m1_row).set_stroke(color=RECT_COLOR) rect_2 = SurroundingRectangle(m2_column).set_stroke(color=RECT_COLOR) self.play(Create(rect_1)) self.wait() self.play(ReplacementTransform(rect_1, rect_2)) math_strings = [] values_to_sum = [] for m1_val, m2_val in zip(m1_row, m2_column): val_left = int(m1_val.get_tex_string()) val_right = int(m2_val.get_tex_string()) values_to_sum.append(val_left * val_right) text_left = m1_val.get_tex_string() text_right = m2_val.get_tex_string() if val_left < 0: text_left = f'({text_left})' if val_right < 0: text_right = f'({text_right})' math_strings.extend([text_left, " \\times ", text_right, " + "]) math_strings = math_strings[:-1] math_strings.extend([" = ", sum(values_to_sum)]) ds_m = MathTex(*math_strings) ds_m.set_color(BLACK) offset = 0 for j in range(m1.shape[0]): pos = j + offset # ds_m[pos].set_color(M1_COLOR) # ds_m[pos + 2].set_color(M2_COLOR) offset += 3 ds_m[-1].set_opacity(0) # ds_m[-1].set_color(CALCULATED_COLOR) ds_m.shift(2 * DOWN) self.play(ReplacementTransform(rect_1, rect_2), Write(ds_m)) self.wait() rect_3 = SurroundingRectangle(matrix3.get_entries()[i]).set_color(RECT_COLOR) # matrix3.get_entries()[i].set_color(CALCULATED_COLOR) self.play( ReplacementTransform(rect_2, rect_3), ApplyMethod(matrix3.get_entries()[i].set_opacity, 1), ApplyMethod(ds_m[-1].set_opacity, 1) ) self.wait() self.remove(ds_m) self.remove(rect_3) m1_row.set_color(BLACK) m2_column.set_color(BLACK) i += 1 self.wait()