Skip to content

Commit 8350c07

Browse files
authored
patch matplotlib’s show (#294)
* patch matplotlib’s show * font-awesome for matplotlib buttons * fix for redrawing figure * only remove if parent is body
1 parent 40d6193 commit 8350c07

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

src/py.js

+49-4
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,62 @@ import {pyodide as Pyodide} from "./dependencies.js";
22

33
export default async function py(require) {
44
const pyodide = await (await require(Pyodide.resolve())).loadPyodide();
5+
let patch; // a promise for patching matplotlib (if needed)
56
return async function py(strings, ...values) {
6-
let globals = {};
7+
const globals = {};
78
const code = strings.reduce((code, string, i) => {
89
if (!(i in values)) return code + string;
910
const name = `_${i}`;
1011
globals[name] = values[i];
1112
return code + string + name;
1213
}, "");
13-
globals = pyodide.toPy(globals);
14-
await pyodide.loadPackagesFromImports(code);
15-
const value = await pyodide.runPythonAsync(code, {globals});
14+
const imports = findImports(pyodide, code);
15+
if (imports.includes("matplotlib") && !patch) await (patch = patchMatplotlib(require, pyodide));
16+
if (imports.length) await pyodide.loadPackagesFromImports(code);
17+
const value = await pyodide.runPythonAsync(code, {globals: pyodide.toPy(globals)});
1618
return pyodide.isPyProxy(value) ? value.toJs() : value;
1719
};
1820
}
21+
22+
// https://github.com/pyodide/pyodide/blob/1624e4a62445876a2d810fdbfc9ddb69a8321a8e/src/js/api.ts#L119-L125
23+
function findImports(pyodide, code) {
24+
const imports = pyodide.pyodide_py.find_imports(code);
25+
try {
26+
return imports.toJs();
27+
} finally {
28+
imports.destroy();
29+
}
30+
}
31+
32+
// Overrides matplotlib’s show function to return a DIV such that when used as
33+
// the last expression in an Observable cell, the inspector will display it.
34+
async function patchMatplotlib(require, pyodide) {
35+
require.resolve("[email protected]/css/font-awesome.min.css").then(href => {
36+
const link = document.createElement("link");
37+
link.rel = "stylesheet";
38+
link.href = href;
39+
document.head.appendChild(link);
40+
});
41+
await pyodide.loadPackage("matplotlib");
42+
await pyodide.runPythonAsync(`from matplotlib import pyplot as plt
43+
from js import document
44+
45+
_show = plt.show
46+
47+
def create_root_element(self):
48+
div = document.createElement("div")
49+
document.body.appendChild(div)
50+
return div
51+
52+
def show(self):
53+
c = plt.gcf().canvas
54+
c.create_root_element = create_root_element.__get__(c, c.__class__)
55+
_show()
56+
div = c.get_element("")
57+
if (div.parentNode == document.body):
58+
document.body.removeChild(div)
59+
return div
60+
61+
plt.show = show.__get__(plt, plt.__class__)
62+
`);
63+
}

0 commit comments

Comments
 (0)