Skip to content

Instantly share code, notes, and snippets.

@jlstevens
Created February 26, 2025 15:52
Show Gist options
  • Save jlstevens/9bc1b7df72c9c3f16a9dd322707af15f to your computer and use it in GitHub Desktop.
Save jlstevens/9bc1b7df72c9c3f16a9dd322707af15f to your computer and use it in GitHub Desktop.
Dashboard JS
importScripts("https://cdn.jsdelivr.net/pyodide/v0.26.2/full/pyodide.js");
function sendPatch(patch, buffers, msg_id) {
self.postMessage({
type: 'patch',
patch: patch,
buffers: buffers
})
}
async function startApplication() {
console.log("Loading pyodide!");
self.postMessage({type: 'status', msg: 'Loading pyodide'})
self.pyodide = await loadPyodide();
self.pyodide.globals.set("sendPatch", sendPatch);
console.log("Loaded!");
await self.pyodide.loadPackage("micropip");
const env_spec = ['https://cdn.holoviz.org/panel/wheels/bokeh-3.6.0-py3-none-any.whl', 'https://cdn.holoviz.org/panel/1.5.2/dist/wheels/panel-1.5.2-py3-none-any.whl', 'pyodide-http==0.2.1', 'holoviews', 'openpyxl', 'pandas', 'param']
for (const pkg of env_spec) {
let pkg_name;
if (pkg.endsWith('.whl')) {
pkg_name = pkg.split('/').slice(-1)[0].split('-')[0]
} else {
pkg_name = pkg
}
self.postMessage({type: 'status', msg: `Installing ${pkg_name}`})
try {
await self.pyodide.runPythonAsync(`
import micropip
await micropip.install('${pkg}');
`);
} catch(e) {
console.log(e)
self.postMessage({
type: 'status',
msg: `Error while installing ${pkg_name}`
});
}
}
console.log("Packages loaded!");
self.postMessage({type: 'status', msg: 'Executing code'})
const code = `
\nimport asyncio\n\nfrom panel.io.pyodide import init_doc, write_doc\n\ninit_doc()\n\nimport param\nimport panel as pn\nimport pandas as pd\nimport openpyxl\nimport holoviews as hv\n\npn.extension(sizing_mode="stretch_width", template="fast")\n\n\n\n\n\n\n#pn.extension()\n\nclass MyFile(param.Parameterized):\n file = param.FileSelector() # changed this into a param\n file_data = None\n\n @param.depends('file', watch=True)\n def process_file(self):\n print('processing file')\n self.file_data = self.file # removed .value since this is a param so it's not needed\n self.df = pd.read_excel(self.file_data)\n\n @param.depends('file', watch=True)\n def df_info(self):\n if self.file_data:\n return f'Uploaded telemetry file is {len(self.file_data)} bytes in size'\n else:\n return 'Please upload a telemetry file'\n\n\nmy_file = MyFile()\n\n\n\n#file_input = pn.widgets.FileInput()\npn.state.template.param.update(\n site="Test dashboard",\n title="Test dashboard"\n)\n\n\npn.Column(#file_input,\n pn.Param(\n my_file.param['file'],\n widgets={'file': pn.widgets.FileInput}\n ),\n my_file.df_info,\n hv.Curve([1,2,3,1]),\n f"WASM test: Pandas version {pd.__version__}"\n).servable()\n\n\n\n\nawait write_doc()
`
try {
const [docs_json, render_items, root_ids] = await self.pyodide.runPythonAsync(code)
self.postMessage({
type: 'render',
docs_json: docs_json,
render_items: render_items,
root_ids: root_ids
})
} catch(e) {
const traceback = `${e}`
const tblines = traceback.split('\n')
self.postMessage({
type: 'status',
msg: tblines[tblines.length-2]
});
throw e
}
}
self.onmessage = async (event) => {
const msg = event.data
if (msg.type === 'rendered') {
self.pyodide.runPythonAsync(`
from panel.io.state import state
from panel.io.pyodide import _link_docs_worker
_link_docs_worker(state.curdoc, sendPatch, setter='js')
`)
} else if (msg.type === 'patch') {
self.pyodide.globals.set('patch', msg.patch)
self.pyodide.runPythonAsync(`
from panel.io.pyodide import _convert_json_patch
state.curdoc.apply_json_patch(_convert_json_patch(patch), setter='js')
`)
self.postMessage({type: 'idle'})
} else if (msg.type === 'location') {
self.pyodide.globals.set('location', msg.location)
self.pyodide.runPythonAsync(`
import json
from panel.io.state import state
from panel.util import edit_readonly
if state.location:
loc_data = json.loads(location)
with edit_readonly(state.location):
state.location.param.update({
k: v for k, v in loc_data.items() if k in state.location.param
})
`)
}
}
startApplication()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment