matplotlib-pyodide
matplotlib-pyodide copied to clipboard
Document some pyodide matplotlib suggestions for node and deno
The Node and Deno contexts can't use the matplotlib_pyodide backends but work fine with Agg.
Takes a second to piece together but one pattern I'm finding useful is to save the output as a data: url.
import base64
import io
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
matplotlib.use('Agg')
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
pic_IObytes = io.BytesIO()
plt.savefig(pic_IObytes, format='png')
pic_IObytes.seek(0)
pic_hash = base64.b64encode(pic_IObytes.read()).decode('utf-8')
dataurl = f'data:image/png;base64,{pic_hash}'
dataurl
Which seems to work! :D
Couldn't think of the right place for it but I think an example like that could be handy (even if just in this issue). Also interested in easier / more efficient patterns for sharing matplotlib figures between the python and JS contexts.
Ah lol it was right there the whole time
https://github.com/pyodide/matplotlib-pyodide/blob/6a6d6fb56889adade87771d5216cfa173a38867e/matplotlib_pyodide/wasm_backend.py#L71-L82
Well I wouldn't necessarily recommend this if you can avoid it. I think the technique here: https://github.com/pyodide/matplotlib-pyodide/blob/6a6d6fb56889adade87771d5216cfa173a38867e/matplotlib_pyodide/wasm_backend.py#L50 Is more efficient than base64 encoding it (though creating a bytes object may still be an unnecessary copy).
It depends a bit on what you want to do with the image. Do you want to store it to the file system?
Ahh. Yea, just trying to get the byte array into the js context. Looks like the following is how to access the buffer with FigureCanvasAgg:
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
matplotlib.use('Agg')
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
fig.canvas.draw()
buff = fig.canvas.get_renderer().buffer_rgba()
# For illustration
import js
js.window.buff = buff
# data is typed array view on wasm memory
# let data = window.buff.getBuffer('u8').data;
Seems much better than the data URL (assuming the raw buffer is useful)! Would it be zero copies up to this point? If so that's pretty fancy
You'll need to use pyodide.ffi.create_proxy but yes this should be zero copy.