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', 'holoviews', '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() """*Linked Brushing* is a very powerful technique. It's also often called *Linked Selections* or *Crossfiltering*. This example is inspired by the HoloViews [Linked Brushing Reference Guide]\ (http://holoviews.org/user_guide/Linked_Brushing.html) and the Plotly blog post [Introducing Dash HoloViews]\ (https://medium.com/plotly/introducing-dash-holoviews-6a05c088ebe5). This example uses the *Iris* dataset. """ from typing import Tuple import holoviews as hv import pandas as pd import panel as pn from holoviews import opts from panel.template import FastListTemplate @pn.cache def get_iris_data(): return pd.read_csv("https://cdn.awesome-panel.org/resources/crossfiltering_holoviews/iris.csv.gz") ACCENT = "#F08080" CSS = """ .main .card-margin.stretch_both { height: calc(50vh - 65px) !important; } """ if not CSS in pn.config.raw_css: pn.config.raw_css.append(CSS) BOKEH_TOOLS = { "tools": ["hover"], "active_tools": ["box_select"] } def get_linked_plots() -> Tuple: """Returns a tuple (scatter, hist) of linked plots See http://holoviews.org/user_guide/Linked_Brushing.html """ dataset = hv.Dataset(get_iris_data()) scatter = hv.Scatter(dataset, kdims=["sepal_length"], vdims=["sepal_width"]) hist = hv.operation.histogram(dataset, dimension="petal_width", normed=False) # pylint: disable=no-value-for-parameter selection_linker = hv.selection.link_selections.instance() # pylint: disable=no-member scatter = selection_linker(scatter).opts( opts.Scatter(color=ACCENT, responsive=True, size=10, **BOKEH_TOOLS), ) hist = selection_linker(hist).opts( opts.Histogram(color=ACCENT, responsive=True, **BOKEH_TOOLS) ) return scatter, hist def create_app(): """Returns the app in a nice FastListTemplate""" scatter, hist = get_linked_plots() scatter_panel = pn.pane.HoloViews(scatter, sizing_mode="stretch_both") hist_panel = pn.pane.HoloViews(hist, sizing_mode="stretch_both") template = FastListTemplate( site="Awesome Panel", site_url="https://awesome-panel.org", title="Crossfiltering with HoloViews and Bokeh", accent=ACCENT, main=[ # We need to wrap in Columns to get them to stretch properly pn.Column(scatter_panel, sizing_mode="stretch_both"), pn.Column(hist_panel, sizing_mode="stretch_both"), ], ) return template pn.extension() hv.extension("bokeh") create_app().servable() 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()