What would it take to put a live Matplotlib figure in a post?

I know this is out of the scope of most communities, but we are a scientific one, using Python and a lot of graphs (Matplotlib) that we share with each other over Discourse.

It would be so amazing to be able to share an interactive graph instead of a static jpg/png

Consider this example:

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

Fs = 4000
f = 100
sample = 200
x = np.arange(sample)
y = np.sin(2 * np.pi * f * x / Fs)
fig, ax = plt.subplots(1,1)
ax.plot(x, y, marker=".")
html_str = mpld3.fig_to_html(fig)
Html_file= open("index.html","w")
Html_file.write(html_str)
Html_file.close()

You would be able to open the index.html file and it will show that (only that it will be INTERACTIVE…)
A graph with four wavy lines, plotted on the x-axis, which corresponds to time, and y-axis, which corresponds to a variable, possibly frequency or another form of data.  (Captioned by AI)

So, I feel like we’re half way there, right?
Perhaps just uploading the html file so it will run in some iframe?

The method you described would be possible via a custom plugin, combining both a markdown-it style plugin and possibly a nice object storage for the HTMLs. However I’d be cautious about the security of it, letting user inputted code run anywhere on the server. Discourse already does a lot of work just to sanitize a post for HTML and JS to be safely parsed in the backend.

You might have better luck instead trying to embed a Python interpreter in the browser and let it run the code on client, skipping the whole HTML creation. JupyterLite would let you run JupyterLab on the browser with UI. From the documentation, it looks like you can have it auto run code on creation of the iframe. You can feed in the code with a custom HighlightJS plugin that will create an actionable button on any Python code block, or have it run automatically.

So something like:

  1. User sees a post with a Python code block.
  2. User hovers over the code block, where a button appears to let them run the code in browser.
  3. User clicks on the button, which creates an iframe to JupyterLite below the code, importing the code from the code block.

Since this would just be a HighlightJS plugin that just creates an iframe to JupyterLite, you can create it all within a Theme Component, no server code needed.

https://jupyterlite.readthedocs.io/en/latest/quickstart/embed-repl.html

One thing to note: JupyterLite is described as not being feature complete to JupyterLab, and I’m not sure how it goes about handling package imports, so you might have to host it yourself. JupyterLite uses Pyodide, which supports any wheel on PyPI, so it should be good

3 Likes

I think that the security risk is not that big in case the index.html runs on the client end (on the user’s browser, not on the Discourse server).

Also the advantage in the mpld3 approach is that it is a single-file with no dependencies. If you run raw Python you have to also be able to upload all dependencies like csv files, data files, etc. that are the source of what you want to plot.

Having said that, to be able to run raw Python scripts inside a Discourse post would be just fabulous!

2 Likes

Oh! I completely misunderstood how the HTML would be generated. If the user is pre-generating the HTML, you could have them iframe it from an external site, with the domain whitelisted.

For example, codepen, which should be allowed by default:

<iframe height="300" width="800" style="width: 100%;" scrolling="no" title="mplD3 example, actually working" src="https://codepen.io/gully/embed/BawMGr?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/gully/pen/BawMGr">
  mplD3 example, actually working</a> by gully (<a href="https://codepen.io/gully">@gully</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
1 Like

It absolutely can be done:

If you have lots of users you might need help automating some of the setup.

I can help if you have budget.

4 Likes

That’s really awesome!
I have a couple of questions:

  1. Do you think it will work with ipympl (otherwise the figures are not interactive, which invalidates the whole point)
  2. Do you think it can work with an underlying project folder where we can set PYTHONPATH env variable before launching Jupyter so that users can import functions and dependencies from the joined project?

and yes, I do have a budget if this is reasonable and feasible and can be contributed as open source for the entire Discourse community.

2 Likes

Very likely

I can see a way you could create a collaborative environment.

Feel free to DM me we can discuss on a call.

2 Likes