Using Panel in Pyodide & PyScript#

Installing Panel in the browser#

To install Panel in the browser you merely have to use the installation mechanism provided by each supported runtime:

Pyodide#

Currently, the best supported mechanism for installing packages in Pyodide is micropip.

To get started with Pyodide simply follow their Getting started guide. Note that if you want to render Panel output you will also have to load Bokeh.js and Panel.js from CDN. The most basic pyodide application therefore looks like this:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js"></script>

    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.js"></script>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js"></script>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js"></script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/panel@1.4.2/dist/panel.min.js"></script>

  </head>
  <body>
    <div id="simple_app"></div>
    <script type="text/javascript">
      async function main(){
        let pyodide = await loadPyodide();
        await pyodide.loadPackage("micropip");
        const micropip = pyodide.pyimport("micropip");
        await micropip.install([
          "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/bokeh-3.4.1-py3-none-any.whl",
          "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/panel-1.4.2-py3-none-any.whl"]
        )
        pyodide.runPython(`
          import panel as pn

          pn.extension(sizing_mode="stretch_width")

          slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')

          def callback(new):
              return f'Amplitude is: {new}'

          pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
	    `);
      }
      main();
    </script>
  </body>
</html>

The app should look like this

Panel Pyodide App

warn

The default bokeh and panel packages are very large, therefore we recommend you pip install specialized wheels:

const bk_whl = "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/bokeh-3.4.1-py3-none-any.whl"
const pn_whl = "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/panel-1.4.2-py3-none-any.whl"
await micropip.install(bk_whl, pn_whl)

PyScript#

PyScript makes it even easier to manage your dependencies, with a <py-config> HTML tag. Simply include panel in the list of dependencies and PyScript will install it automatically:

<py-config>
packages = [
  "panel",
  ...
]
</py-config>

Once installed you will be able to import panel in your <py-script> tag. Again, make sure you also load Bokeh.js and Panel.js:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.js"></script>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js"></script>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js"></script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/panel@1.4.2/dist/panel.min.js"></script>

    <link rel="stylesheet" href="https://pyscript.net/releases/2024.2.1/pyscript.css" />
    <script defer src="https://pyscript.net/releases/2024.2.1/pyscript.js"></script>
  </head>
  <body>
    <py-config>
       packages = [
          "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/bokeh-3.4.1-py3-none-any.whl",
          "https://cdn.holoviz.org/panel/1.4.2/dist/wheels/panel-1.4.2-py3-none-any.whl"
       ]
    </py-config>
    <div id="simple_app"></div>
    <py-script>
      import panel as pn

      pn.extension(sizing_mode="stretch_width")

      slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')

      def callback(new):
         return f'Amplitude is: {new}'

      pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
    </py-script>
  </body>
</html>

The app should look identical to the one above but show a loading spinner while Pyodide is initializing.

Rendering Panel components in Pyodide or Pyscript#

Rendering Panel components into the DOM is quite straightforward. You can simply use the .servable() method on any component and provide a target that should match the id of a DOM node:

import panel as pn

slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')

def callback(new):
    return f'Amplitude is: {new}'

pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');

This code will render this simple application into the simple_app DOM node:

<div id="simple_app"></div>

Alternatively you can also use the panel.io.pyodide.write function to write into a particular DOM node:

await pn.io.pyodide.write('simple_app', component)