@@ -2,17 +2,62 @@ import {pyodide as Pyodide} from "./dependencies.js";
2
2
3
3
export default async function py ( require ) {
4
4
const pyodide = await ( await require ( Pyodide . resolve ( ) ) ) . loadPyodide ( ) ;
5
+ let patch ; // a promise for patching matplotlib (if needed)
5
6
return async function py ( strings , ...values ) {
6
- let globals = { } ;
7
+ const globals = { } ;
7
8
const code = strings . reduce ( ( code , string , i ) => {
8
9
if ( ! ( i in values ) ) return code + string ;
9
10
const name = `_${ i } ` ;
10
11
globals [ name ] = values [ i ] ;
11
12
return code + string + name ;
12
13
} , "" ) ;
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 ) } ) ;
16
18
return pyodide . isPyProxy ( value ) ? value . toJs ( ) : value ;
17
19
} ;
18
20
}
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