Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect/render Pyodide output in browser?

I have recently come across the Pyodide project.

I have built a little demo using Pyodide, but although I've spent a lot of time looking at the source, it is not obvious (yet) to me how to redirect print output from python (other than modifying the CPython source), and also, how to redirect output from matplotlib.pyplot to the browser.

From the source code, FigureCanvasWasm does have a show() method with the appropriate backend for plotting to the browser canvas - however, it is not clear to me how to instantiate this class and invoke it's show() method or indeed, if there is another more obvious way of redirecting plots to canvas.

My questions therefore are:

  1. How do I redirect print() messages
  2. How do I force pyodide to plot matplotlib figures in the browser?

Here is my test page:

<!doctype html>
<meta charset="utf-8">
<html lang="en">
<html>
<head>
    <title>Demo</title>
    <script src="../../pyodide/build/pyodide.js"></script>
</head>
<body>
</body>
    <script type="text/javascript">
      languagePluginLoader.then(() => {
      pyodide.loadPackage(['matplotlib']).then(() => {
          pyodide.runPython(`
                  import matplotlib.pyplot as plt
                  plt.plot([1, 2, 3, 4])
                  plt.ylabel('some numbers')
                  #fig = plt.gcf()
                  #fig.savefig(imgdata, format='png')                  
                  print('Done from python!')`
          );
          //var image = pyodide.pyimport('imgdata');
          //console.log(image);
      });});

    </script>
<html>
like image 652
Homunculus Reticulli Avatar asked Jun 13 '19 15:06

Homunculus Reticulli


1 Answers

First of all let's see if we can get just anything to show up in the browser; e.g. a normal string. Python variables are stored in the pyodide.globals attribute. Hence we can take the python object from there and place it into a <div> element on the page.

<!doctype html>
<meta charset="utf-8">
<html>
<head>
    <title>Demo</title>
    <script src="../pyodide/pyodide.js"></script>
</head>
<body>
</body>
    <script type="text/javascript">
      languagePluginLoader.then(() => {
          pyodide.runPython(`my_string = "This is a python string." `);

          document.getElementById("textfield").innerText = pyodide.globals.my_string;
      });

    </script>

    <div id="textfield"></div>
<html>

Now I guess we can do the same with a matplotlib figure. The following would show a saved png image in the document.

<!doctype html>
<meta charset="utf-8">
<html lang="en">
<html>
<head>
    <title>Demo</title>
    <script src="../pyodide/pyodide.js"></script>
</head>
<body>
</body>
    <script type="text/javascript">
      languagePluginLoader.then(() => {
      pyodide.loadPackage(['matplotlib']).then(() => {
          pyodide.runPython(`
                import matplotlib.pyplot as plt
                import io, base64

                fig, ax = plt.subplots()
                ax.plot([1,3,2])

                buf = io.BytesIO()
                fig.savefig(buf, format='png')
                buf.seek(0)
                img_str = 'data:image/png;base64,' + base64.b64encode(buf.read()).decode('UTF-8')`
          );

          document.getElementById("pyplotfigure").src=pyodide.globals.img_str

      });});

    </script>

    <div id="textfield">A matplotlib figure:</div>
    <div id="pyplotdiv"><img id="pyplotfigure"/></div>
<html>

I haven't looked into the backends.wasm_backend yet, so that may allow for a more automated way of the above.

like image 193
ImportanceOfBeingErnest Avatar answered Sep 23 '22 18:09

ImportanceOfBeingErnest