Created
February 26, 2025 15:52
-
-
Save jlstevens/9bc1b7df72c9c3f16a9dd322707af15f to your computer and use it in GitHub Desktop.
Dashboard JS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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