question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Idea: Connection to matplotlib over BytesIO

See original GitHub issue

Note: This is only an idea, and should not have high priority. Related to #363

It would be really cool to have manim smoothly interact with matplotlib. Therefore one idea: Do you think it is possible, to save figures created in matplotlib to a byte stream, which is then read by ImageMobject? Then there is no reading and writing to the disk in between. One ide based on the idea of https://mellowd.dev/python/using-io-bytesio/, I tried the following:

from manim import *
import matplotlib.pyplot as plt
import io


class ConnectingMatplotlib(Scene):
    def construct(self):
        t = np.arange(0.0, 2.0, 0.01)
        s = 1 + np.sin(2 * np.pi * t)
        fig, ax = plt.subplots()
        ax.plot(t, s)
        ax.set(xlabel='time (s)', ylabel='voltage (mV)',
               title='About as simple as it gets')
        ax.grid()

        b = io.BytesIO()
        plt.savefig(b, format='png')
        img = ImageMobject(b.read())  ## error: IndexError: tuple index out of range
        self.add(img)

But reading the byte stream is not possible just like that. Do you think this is something, that can be easily solved?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

7reactions
kolibril13commented, Aug 28, 2020

@behackl : Wow,thank you so much! I’m speechless and happy! With saving and loading from disk (my method): — 35.34524869918823 seconds — With your method: — 6.816277742385864 seconds — And here is a script:

from manim import *
import matplotlib.pyplot as plt


def my_function(amplitude, x):
    return amplitude * np.sin(x)


def get_image_plot(amplitude, x):
    fig, ax = plt.subplots()
    ax.plot(x, my_function(amplitude, x))
    plt.ylim(-1, 1)
    ax.set(xlabel='distance (x)', ylabel='amplitude',
           title='My animated plot')
    fig.canvas.draw()
    img = ImageMobject(fig.canvas.buffer_rgba()).scale(4.5)
    plt.close(fig)
    return img


class ConnectingMatplotlib(Scene):
    def construct(self):
        x_values = np.linspace(0, 30, 400)
        amp1 = 0.5
        amp2 = 1
        tr_amplitude = ValueTracker(amp1)
        image = get_image_plot(amp1, x_values)
        self.add(image)

        def update_image(mob):
            new_mob = get_image_plot(tr_amplitude.get_value(), x_values)
            mob.become(new_mob)

        image.add_updater(update_image)

        self.play(tr_amplitude.set_value, amp2, run_time=3)

import time
from pathlib import Path

if __name__ == "__main__":
    script = f"{Path(__file__).resolve()}"
    start_time = time.time()

    os.system( f"manim  -l --custom_folders  --disable_caching  -p -c 'BLACK" + script)
    print("--- %s seconds ---" % (time.time() - start_time))

ConnectingMatplotlib

2reactions
behacklcommented, Aug 28, 2020

For me, running the code from https://mellowd.dev/python/using-io-bytesio/ always leads to an empty image. I think that before accessing the byte stream, something like b.seek(0) has to be called.

Anyhow, matplotlib also allows to get the rendered figure in a format suitable for ImageMobject by calling buffer_rgba() of the corresponding canvas:

import matplotlib
import matplotlib.pyplot as plt
import numpy as np

from manim import Scene, ImageMobject

class ConnectingMatplotlib(Scene):
    def construct(self):        
        t = np.arange(0.0, 2.0, 0.01)
        s = 1 + np.sin(2 * np.pi * t)

        fig, ax = plt.subplots()
        ax.plot(t, s)

        ax.set(xlabel='time (s)', ylabel='voltage (mV)',
               title='About as simple as it gets')
        ax.grid()
        
        fig.canvas.draw()
        img = ImageMobject(fig.canvas.buffer_rgba())

        self.add(img)
        self.wait()
Read more comments on GitHub >

github_iconTop Results From Across the Web

Matplotlib saving state between different uses of io.bytesIo
The problem is, if I click the button multiple times with different parameters, the images "pile on top" of each other; I see...
Read more >
How-To — Matplotlib 2.1.2 documentation
By default, Matplotlib positions the x location of the ylabel so that it does not overlap any of the y ticks.
Read more >
Python StringIO and BytesIO Compared With Open() - Medium
This classes create file like object that operate on string data. The StringIO and BytesIO classes are most useful in scenarios where you...
Read more >
Using Web Frameworks for Scientific Applications
The idea is to let Matplotlib write to a io.BytesIO object and afterwards extract the series of bytes in the plot file from...
Read more >
Get Started: 3 Ways to Load CSV files into Colab | by A Apte
Some of the advantages of Colab over Jupyter include an easier installation ... (if not click on Connect more apps, search for Colaboratory...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found