DPI and figsize#

[1]:
import matplotlib.pyplot as plt
import numpy as np
from manim import *
config.media_embed = True

def figtoimg(fig):
    fig.canvas.draw()
    img = fig.canvas.buffer_rgba()
    plt.close(fig)
    return img
Manim Community v0.17.2

[2]:
x = np.linspace(0, 10, 100)

def make_plot(dpi, my_fig_size):
    fig, ax = plt.subplots(figsize=(my_fig_size, my_fig_size), dpi=dpi)
    ax.plot(x, np.sin(x))
    ax.set_ylim(-1, 1)
    return figtoimg(fig)

def make_mobject(dpi, my_fig_size, position=3 * LEFT):
    array = make_plot(dpi, my_fig_size)
    img = ImageMobject(array)
    img.shift(position)
    fsround = f"{my_fig_size:.1f}"
    annoA = Text(f"fig_size = ({fsround}, {fsround})\n{dpi=:.0f}", color=BLACK)
    annoA.to_edge(UP).scale(0.4)
    all = Group(img, annoA.next_to(img, UP))
    return all


plt.imshow(make_plot(100, 4))
plt.axis("off")

[2]:
(-0.5, 399.5, 399.5, -0.5)
_images/manimplotlib4_2_1.png
[3]:
class Example(Scene):
    def construct(self):
        self.camera.background_color = BLUE_A
        fig_size_tracker = ValueTracker(4)  # for figsize = (4,4)
        dpi_tracker = ValueTracker(100)  # for dpi = 100

        imageA = Group()
        self.add(imageA)

        def update_imageA(mob):
            if len(mob.submobjects) > 0:  # TODO: can this be removed somehow?
                mob.remove(mob.submobjects[-1])
            mob.add(make_mobject(100, fig_size_tracker.get_value(), position=3 * LEFT))

        imageA.add_updater(update_imageA)

        imageB = Group()
        self.add(imageB)

        def update_imageB(mob):
            if len(mob.submobjects) > 0:  # TODO: can this be removed somehow?
                mob.remove(mob.submobjects[-1])
            mob.add(make_mobject(dpi_tracker.get_value(), 4, position=3 * RIGHT))

        imageB.add_updater(update_imageB)

        self.play(
            dpi_tracker.animate.set_value(200),
            fig_size_tracker.animate.set_value(8),
            run_time=1,
        )
        imageA.add_updater(lambda x, dt: x)  # why is this line needed?
        self.wait()
        dpi_tracker.set_value(175)
        fig_size_tracker.set_value(7)
        self.wait()
        dpi_tracker.set_value(150)
        fig_size_tracker.set_value(6)
        self.wait()
        dpi_tracker.set_value(125)
        fig_size_tracker.set_value(5)
        self.wait()
        dpi_tracker.set_value(100)
        fig_size_tracker.set_value(4)
        self.wait()


%manim -v WARNING -qh --disable_caching --progress_bar None Example
[4]:
class Example(Scene):  # TODO: This is not working, but the syntax would be amazing!
    def construct(self):
        fig_size_tracker = ValueTracker(4)  # for figsize = (4,4)
        dpi_tracker = ValueTracker(100)  # for dpi = 100

        imageA = make_mobject(100, fig_size_tracker.get_value(), position=3 * LEFT)
        self.add(imageA)

        def update_imageA(mob):
            new_mob = make_mobject(100, fig_size_tracker.get_value(), position=3 * LEFT)
            mob.become(new_mob)

        imageA.add_updater(update_imageA)
        self.play(fig_size_tracker.animate.set_value(6), run_time=1)
        self.wait()


%manim -v WARNING -qh --disable_caching --progress_bar None Example
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In [4], line 18
     14         self.play(fig_size_tracker.animate.set_value(6), run_time=1)
     15         self.wait()
---> 18 get_ipython().run_line_magic('manim', '-v WARNING -qh --disable_caching --progress_bar None Example')

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/IPython/core/interactiveshell.py:2309, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
   2307     kwargs['local_ns'] = self.get_local_scope(stack_depth)
   2308 with self.builtin_trap:
-> 2309     result = fn(*args, **kwargs)
   2310 return result

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/utils/ipython_magic.py:141, in ManimMagic.manim(self, line, cell, local_ns)
    139     SceneClass = local_ns[config["scene_names"][0]]
    140     scene = SceneClass(renderer=renderer)
--> 141     scene.render()
    142 finally:
    143     # Shader cache becomes invalid as the context is destroyed
    144     shader_program_cache.clear()

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/scene/scene.py:223, in Scene.render(self, preview)
    221 self.setup()
    222 try:
--> 223     self.construct()
    224 except EndSceneEarlyException:
    225     pass

Cell In [4], line 14, in Example.construct(self)
     11     mob.become(new_mob)
     13 imageA.add_updater(update_imageA)
---> 14 self.play(fig_size_tracker.animate.set_value(6), run_time=1)
     15 self.wait()

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/scene/scene.py:1033, in Scene.play(self, subcaption, subcaption_duration, subcaption_offset, *args, **kwargs)
   1030     return
   1032 start_time = self.renderer.time
-> 1033 self.renderer.play(self, *args, **kwargs)
   1034 run_time = self.renderer.time - start_time
   1035 if subcaption:

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/renderer/cairo_renderer.py:104, in CairoRenderer.play(self, scene, *args, **kwargs)
    102     self.freeze_current_frame(scene.duration)
    103 else:
--> 104     scene.play_internal()
    105 self.file_writer.end_animation(not self.skip_animations)
    107 self.num_plays += 1

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/scene/scene.py:1198, in Scene.play_internal(self, skip_rendering)
   1193 self.time_progression = self._get_animation_time_progression(
   1194     self.animations,
   1195     self.duration,
   1196 )
   1197 for t in self.time_progression:
-> 1198     self.update_to_time(t)
   1199     if not skip_rendering and not self.skip_animation_preview:
   1200         self.renderer.render(self, t, self.moving_mobjects)

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/scene/scene.py:1432, in Scene.update_to_time(self, t)
   1430     alpha = t / animation.run_time
   1431     animation.interpolate(alpha)
-> 1432 self.update_mobjects(dt)
   1433 self.update_meshes(dt)
   1434 self.update_self(dt)

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/scene/scene.py:342, in Scene.update_mobjects(self, dt)
    333 """
    334 Begins updating all mobjects in the Scene.
    335
   (...)
    339     Change in time between updates. Defaults (mostly) to 1/frames_per_second
    340 """
    341 for mobject in self.mobjects:
--> 342     mobject.update(dt)

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/mobject/mobject.py:841, in Mobject.update(self, dt, recursive)
    839         updater(self, dt)
    840     else:
--> 841         updater(self)
    842 if recursive:
    843     for submob in self.submobjects:

Cell In [4], line 11, in Example.construct.<locals>.update_imageA(mob)
      9 def update_imageA(mob):
     10     new_mob = make_mobject(100, fig_size_tracker.get_value(), position=3 * LEFT)
---> 11     mob.become(new_mob)

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/mobject/mobject.py:2703, in Mobject.become(self, mobject, copy_submobjects, match_height, match_width, match_depth, match_center, stretch)
   2701 for sm1, sm2 in zip(self.get_family(), mobject.get_family()):
   2702     sm1.points = np.array(sm2.points)
-> 2703     sm1.interpolate_color(sm1, sm2, 1)
   2704 return self

File ~/checkouts/readthedocs.org/user_builds/manimplotlib/envs/latest/lib/python3.11/site-packages/manim/mobject/mobject.py:2638, in Mobject.interpolate_color(self, mobject1, mobject2, alpha)
   2637 def interpolate_color(self, mobject1, mobject2, alpha):
-> 2638     raise NotImplementedError("Please override in a child class.")

NotImplementedError: Please override in a child class.
[5]:
# for future: this annotates the frame
# pyFrame = config["pixel_height"]  # 1080 default
# pxFrame = config["pixel_width"]  # 1920 #default
# frame_width = config["frame_width"]
# frame_height = config["frame_height"]
# d1 = Line(frame_width * LEFT / 2, frame_width * RIGHT / 2).to_edge(DOWN)
# d2 = Line(frame_height * UP / 2, frame_height * DOWN / 2).to_edge(LEFT)
# t1 = Text(str(pxFrame)).scale(0.5).next_to(d1, DOWN, buff=SMALL_BUFF)
# t2 = Text(str(pyFrame)).scale(0.5).rotate(90*DEGREES).next_to(d2, LEFT, buff=SMALL_BUFF)

# class Example(Scene):
#     def construct(self):
#         self.add(d1, d2, t1, t2)


# %manim -v WARNING -qh --disable_caching --progress_bar None Example