Spaces:
Running
Running
| importScripts("https://cdn.jsdelivr.net/pyodide/v0.24.1/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.3.2-py3-none-any.whl', 'https://cdn.holoviz.org/panel/1.3.6/dist/wheels/panel-1.3.6-py3-none-any.whl', 'pyodide-http==0.2.1', 'hvplot', 'numpy', 'pandas'] | |
| 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 = ` | |
| import asyncio | |
| from panel.io.pyodide import init_doc, write_doc | |
| init_doc() | |
| """ | |
| # Caching Example | |
| See https://awesome-panel.org/resources/caching_example | |
| """ | |
| import time | |
| import hvplot.pandas # pylint: disable=unused-import | |
| import numpy as np | |
| import pandas as pd | |
| import panel as pn | |
| pn.extension(design="material") | |
| ACCENT_COLOR = "#1f77b4" | |
| np.random.seed([3, 1415]) | |
| PERIODS = 1 * 24 * 60 # minutes. I.e. 1 days | |
| DATA = pd.DataFrame( | |
| { | |
| "time": pd.date_range("2020-01-01", periods=PERIODS, freq="T"), | |
| "price": np.random.randn(PERIODS) + 98, | |
| } | |
| ) | |
| def _load_data(frac=0.1): | |
| time.sleep(0.5 + frac * 0.5) | |
| return DATA.sample(frac=frac) | |
| def _plot_data(frac=0.1): | |
| time.sleep(0.5) | |
| data = _load_data(frac) | |
| return data.hvplot(x="time", y="price") | |
| @pn.cache(per_session=True, ttl=60*60*24) | |
| def _plot_data_cached(frac): | |
| return _plot_data(frac) | |
| # Create Widgets | |
| fraction = pn.widgets.FloatSlider(value=0.1, start=0.1, end=1.0, step=0.1, name="Fraction of data") | |
| duration = pn.widgets.StaticText(value="", name="Time to create plot") | |
| use_cache = pn.widgets.Checkbox(value=False, name="Use Cache") | |
| preload_cache = pn.widgets.Button(name="Preload Cache", button_type="primary", disabled=True) | |
| clear_cache = pn.widgets.Button(name="Clear Cache", disabled=True) | |
| preload_progress = pn.widgets.Progress( | |
| name="Progress", active=False, value=0, max=100, sizing_mode="stretch_width", disabled=True | |
| ) | |
| plot_panel = pn.pane.HoloViews(min_height=500, sizing_mode="stretch_both") | |
| # Setup interactivity | |
| def _clear_cache(*_): | |
| _plot_data_cached.clear() | |
| clear_cache.on_click(_clear_cache) | |
| def _preload_cache(*_): | |
| for index in range(0, 11, 1): | |
| frac_ = round(index / 10, 1) | |
| preload_progress.value = int(frac_ * 100) | |
| _plot_data_cached(frac_) | |
| preload_progress.value = 0 | |
| preload_cache.on_click(_preload_cache) | |
| @pn.depends(frac=fraction, watch=True) | |
| def _update_plot(frac): | |
| start_counter = time.perf_counter() | |
| frac = round(frac, 1) | |
| if use_cache.value: | |
| plot = _plot_data_cached(frac) | |
| else: | |
| plot = _plot_data(frac) | |
| end_counter = time.perf_counter() | |
| duration.value = str(round(end_counter - start_counter, 4)) + " seconds" | |
| # Please note DiskCache does not cache the options | |
| plot.opts(color=ACCENT_COLOR, responsive=True) | |
| plot_panel.object = plot | |
| @pn.depends(use_cache=use_cache, watch=True) | |
| def _update_cache_widgets(use_cache): # pylint: disable=redefined-outer-name | |
| disabled = not use_cache | |
| preload_cache.disabled = disabled | |
| clear_cache.disabled = disabled | |
| preload_progress.disabled = disabled | |
| # Layout the app | |
| pn.Column( | |
| pn.pane.Markdown( | |
| "# Speed up slow functions with caching", sizing_mode="stretch_width" | |
| ), | |
| fraction, | |
| duration, | |
| use_cache, | |
| plot_panel, | |
| pn.Row(preload_cache, clear_cache,), | |
| preload_progress, | |
| ).servable() | |
| pn.state.onload(lambda: fraction.param.trigger("value")) | |
| await 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(` | |
| state.curdoc.apply_json_patch(patch.to_py(), 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() |