Viewer#

Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).


import panel as pn

pn.extension()

A Viewer is a good abstraction for combining some business logic about your application with Panel components and then letting you use it as if it was a Panel component. It provides a useful abstraction extension of a simple Parameterized class. Note however that it is not actually a Panel component, i.e. it does not behave like a widget, layout or pane. If you want to build a Panel component in Python the PyComponent class is a better option.

import panel as pn
import param

from panel.viewable import Viewer


class CounterButton(Viewer):

    value = param.Integer()

    def __init__(self, **params):
        super().__init__()
        self._layout = pn.widgets.Button(
            name=self._button_name, on_click=self._on_click, **params
        )

    def _on_click(self, event):
        self.value += 1

    @param.depends("value")
    def _button_name(self):
        return f"count is {self.value}"

    def __panel__(self):
        return self._layout

CounterButton()

Note

If you are looking to create new components using JavaScript, check out JSComponent, ReactComponent, or AnyWidgetComponent instead.

API#

Attributes#

None. The Viewer class does not have any special attributes. It is a simple param.Parameterized class with a few additional methods. This also means you will have to add or support parameters like height, width, sizing_mode, etc., yourself if needed.

Methods#

  • __panel__: Must be implemented. Should return the Panel component or object to be displayed.

  • servable: This method serves the component using Panel’s built-in server when running panel serve ....

  • show: Displays the component in a new browser tab when running python ....

Usage#

Styling with CSS#

You can style the component by styling the component(s) returned by __panel__ using their styles or stylesheets attributes.

import panel as pn
import param

from panel.viewable import Viewer


class StyledCounterButton(Viewer):

    value = param.Integer()

    _stylesheets = [
        """
        :host(.solid) .bk-btn.bk-btn-default
        {
            background: #0072B5;
            color: white;
            border: none;
            padding: 10px;
            border-radius: 4px;
        }
        :host(.solid) .bk-btn.bk-btn-default:hover {
            background: #4099da;
        }
        """
    ]

    def __init__(self, **params):
        super().__init__()

        self._layout = pn.widgets.Button(
            name=self._button_name,
            on_click=self._on_click,
            stylesheets=self._stylesheets,
            **params,
        )

    def _on_click(self, event):
        self.value += 1

    @param.depends("value")
    def _button_name(self):
        return f"Clicked {self.value} times"

    def __panel__(self):
        return self._layout


StyledCounterButton().servable()

See the Apply CSS guide for more information on styling Panel components.

Displaying A Single Child#

You can display Panel components (Viewables) by defining a Child parameter.

Let’s start with the simplest example:

import panel as pn

from panel.custom import Child
from panel.viewable import Viewer

class SingleChild(Viewer):

    object = Child()

    def __panel__(self):
      return pn.Column("A Single Child", self.param.object.rx())

single_child = SingleChild(object=pn.pane.Markdown("A **Markdown** pane!"))

single_child.servable()

Calling self.param.object.rx() creates a reactive expression which updates when the object parameter is updated.

Let’s replace the object with a Button:

single_child.object = pn.widgets.Button(name="Click me")

Let’s change it back

single_child.object = pn.pane.Markdown("A **Markdown** pane!")

If you provide a non-Viewable child it will automatically be converted to a Viewable by pn.panel:

SingleChild(object="A **Markdown** pane!").servable()

If you want to allow a certain type of Panel components only, you can specify the specific type in the class_ argument.

import panel as pn

from panel.custom import Child
from panel.viewable import Viewer

class SingleChild(Viewer):

    object = Child(class_=pn.pane.Markdown)

    def __panel__(self):
        return pn.Column("A Single Child", self.param.object.rx())


SingleChild(object=pn.pane.Markdown("A **Markdown** pane!")).servable()

The class_ argument also supports a tuple of types:

    object = Child(class_=(pn.pane.Markdown, pn.widgets.Button))

Displaying a List of Children#

You can also display a List of Viewable objects using the Children parameter type:

import panel as pn

from panel.custom import Children
from panel.viewable import Viewer


class MultipleChildren(Viewer):

    objects = Children()

    def __init__(self, **params):
        super().__init__(**params)
        self._layout = pn.Column(objects=self.param['objects'], styles={"background": "silver"})

    def __panel__(self):
        return self._layout


MultipleChildren(
    objects=[
        pn.panel("A **Markdown** pane!"),
        pn.widgets.Button(name="Click me!"),
        {"text": "I'm shown as a JSON Pane"},
    ]
).servable()

You can change the item_type to a specific subtype of Viewable or a tuple of Viewable subtypes.

References#

Tutorials#

How-To Guides#


Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).