Skip to content

Commit 22834b5

Browse files
committed
patch pyodide
1 parent 0bfebe1 commit 22834b5

File tree

6 files changed

+79
-9
lines changed

6 files changed

+79
-9
lines changed

app/epics/pyodideEpics.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
plotTestPlot,
2121
saveEpochs,
2222
loadPyodide,
23+
loadPatches,
24+
applyPatches,
2325
loadUtils,
2426
} from '../utils/pyodide';
2527
import {
@@ -43,8 +45,11 @@ const launchEpic: Epic<PyodideActionType, PyodideActionType, RootState> = (
4345
tap(() => console.log('launching')),
4446
mergeMap(loadPyodide),
4547
tap((worker) => {
46-
console.log('loadPyodide completed, laoding utils');
47-
// loadUtils(worker);
48+
console.log('loadPyodide completed, loading patches');
49+
loadPatches(worker);
50+
applyPatches(worker);
51+
console.log('Now loading utils');
52+
loadUtils(worker);
4853
}),
4954
map(PyodideActions.SetPyodideWorker)
5055
);

app/utils/pyodide/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ export const loadPyodide = async () => {
1414
return freshWorker;
1515
};
1616

17+
export const loadPatches = async (worker: Worker) =>
18+
worker.postMessage({
19+
data: readFileSync(path.join(__dirname, '/utils/pyodide/patches.py'), 'utf8'),
20+
});
21+
22+
export const applyPatches = async (worker: Worker) =>
23+
worker.postMessage({
24+
data: `apply_patches()`,
25+
});
26+
1727
export const loadUtils = async (worker: Worker) =>
1828
worker.postMessage({
1929
data: readFileSync(path.join(__dirname, '/utils/pyodide/utils.py'), 'utf8'),
@@ -117,7 +127,7 @@ export const plotTestPlot = async (worker: Worker | null) => {
117127
}
118128
// TODO: Figure out how to get image results from pyodide
119129
return worker.postMessage({
120-
data: `print('hello world')`,
130+
data: `import matplotlib.pyplot as plt; fig= plt.plot([1,2,3,4])`,
121131
});
122132
};
123133

app/utils/pyodide/patches.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# patch implemented in Pyolite
2+
# https://github.com/jupyterlite/jupyterlite/blob/0d563b9a4cca4b54411229128cb51ac4ba333c8f/packages/pyolite-kernel/py/pyolite/pyolite/patches.py
3+
def patch_matplotlib():
4+
import os
5+
from io import BytesIO
6+
7+
# before importing matplotlib
8+
# to avoid the wasm backend (which needs `js.document`, not available in worker)
9+
os.environ["MPLBACKEND"] = "AGG"
10+
11+
import matplotlib.pyplot
12+
from IPython.display import display
13+
14+
from .display import Image
15+
16+
_old_show = matplotlib.pyplot.show
17+
assert _old_show, "matplotlib.pyplot.show"
18+
19+
def show():
20+
buf = BytesIO()
21+
matplotlib.pyplot.savefig(buf, format="png")
22+
buf.seek(0)
23+
display(Image(buf.read()))
24+
matplotlib.pyplot.clf()
25+
26+
matplotlib.pyplot.show = show
27+
28+
29+
def patch_pillow():
30+
import base64
31+
32+
from PIL import Image as PILImage
33+
34+
_old_repr_png = PILImage.Image._repr_png_
35+
assert _old_repr_png
36+
37+
def _repr_png_(self):
38+
byte = _old_repr_png(self)
39+
return base64.b64encode(byte).decode("utf-8")
40+
41+
PILImage.Image._repr_png_ = _repr_png_
42+
43+
44+
ALL_PATCHES = [
45+
patch_pillow,
46+
patch_matplotlib,
47+
]
48+
49+
50+
def apply_patches():
51+
import warnings
52+
53+
for patch in ALL_PATCHES:
54+
try:
55+
patch()
56+
except Exception as err:
57+
warnings.warn("faield to apply patch", patch, err)

app/utils/pyodide/utils.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
find_events, read_epochs, set_eeg_reference, viz)
1313
from mne.io import RawArray
1414
from io import StringIO
15-
from mne.channels import read_montage
1615

1716

1817
# plt.style.use(fivethirtyeight)
@@ -68,15 +67,14 @@ def load_data(sfreq=128., replace_ch_names=None):
6867

6968
# type of each channels
7069
ch_types = ['eeg'] * (len(ch_ind) - 1) + ['stim']
71-
montage = read_montage('standard_1005')
7270

7371
# get data and exclude Aux channel
7472
data = data.values[:, ch_ind].T
7573

7674
# create MNE object
7775
info = create_info(ch_names=ch_names, ch_types=ch_types,
78-
sfreq=sfreq, montage=montage)
79-
raw.append(RawArray(data=data, info=info))
76+
sfreq=sfreq)
77+
raw.append(RawArray(data=data, info=info).set_montage('standard_1005'))
8078

8179
# concatenate all raw objects
8280
raws = concatenate_raws(raw)

app/utils/pyodide/webworker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ importScripts('./src/pyodide/pyodide.js');
88

99
async function loadPyodideAndPackages() {
1010
self.pyodide = await loadPyodide({ indexURL: './src/pyodide/' });
11-
await self.pyodide.loadPackage(['numpy']);
11+
await self.pyodide.loadPackage(['matplotlib', 'mne', 'pandas']);
1212
}
1313
let pyodideReadyPromise = loadPyodideAndPackages();
1414

internals/scripts/InstallPyodide.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import tar from 'tar-fs';
66
import url from 'url';
77
import bz2 from 'unbzip2-stream';
88

9-
const PYODIDE_VERSION = '0.17.0';
9+
const PYODIDE_VERSION = '0.18.0';
1010
const TAR_NAME = `pyodide-build-${PYODIDE_VERSION}.tar.bz2`;
1111
const TAR_URL = `https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-build-${PYODIDE_VERSION}.tar.bz2`;
1212
const PYODIDE_DIR = 'app/utils/pyodide/src/';

0 commit comments

Comments
 (0)