panel icon indicating copy to clipboard operation
panel copied to clipboard

Enable me to create Viewer widgets

Open MarcSkovMadsen opened this issue 1 year ago • 4 comments

I've many, many times been wanting to create custom widgets using the Viewer. But I've experienced just as many times its not possible.

For example now to help P720 in https://discourse.holoviz.org/t/panel-chat-interface/7505 I would like to create a custom widget and use that for the ChatInterface. But it cannot work as the Viewer cannot be made to work like a Widget.

Minimum, Reproducible Example

import panel as pn
import param

pn.extension()

class PreferenceInput(pn.viewable.Layoutable, pn.widgets.WidgetBase, pn.viewable.Viewer):
    value = param.Parameter()

    def __init__(self, **params):
        super().__init__(**params)
        
        self._preference_widget = pn.widgets.RadioBoxGroup(options=["blue", "red", "green"], value="blue", name="preference")
        pn.bind(self._update_value, self._preference_widget)
        self._layout = pn.Column(
            "What is your preference?",
            self._preference_widget,
        )
    
    def _update_value(self, preference):
        self.value = "My preference is {preference}."

    def __panel__(self):
        return self._layout

preference_input = PreferenceInput()

def even_or_odd(contents, user, instance):
    if len(contents) % 2 == 0:
        return "Even number of characters."
    return "Odd number of characters."

pn.chat.ChatInterface(callback=even_or_odd, widgets=[preference_input]).servable()

image

It works fine until I click send. Then I get

  File "/home/jovyan/repos/private/panel/panel/chat/interface.py", line 405, in _click_send
    value = active_widget.value

In this case the problem is that when a Viewer is put in a row its replaced with its __panel__(). Thus then the assumptions about how to retrieve the ChatInterface.active_widget property breaks down. In this case you could probable "fix" the active_widget implementation. But in my experience its a problem all over the place that its not possible to get a Viewer to behave like a widget.

image

As a bonus its also hard and not documented how to get a Viewer to be Layoutable. That is always another friction. The ChatInterface also assumes that about the input widgets. It assumes there is a sizing_mode on the widget.

MarcSkovMadsen avatar Jul 28 '24 04:07 MarcSkovMadsen

Just skimmed this issue; wondering whether you can inherit from Widget rather than Viewer, or what the benefit of using Viewer over Widget is?

ahuang11 avatar Jul 29 '24 16:07 ahuang11

Its a good question. If that is possible it should be documented.

I don't believe its possible though. The Widget is for creating widgets from Bokeh JavaScript/ Typescript models?

MarcSkovMadsen avatar Jul 29 '24 17:07 MarcSkovMadsen

Here's my take using CompositeWidget.

import panel as pn
import param

pn.extension()


class PreferenceInput(pn.widgets.CompositeWidget):
    value = param.Parameter()

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

        self._preference_widget = pn.widgets.RadioBoxGroup(
            options=["blue", "red", "green"], value="blue", name="preference"
        )
        pn.bind(self._update_value, self._preference_widget, watch=True)
        self._composite[:] = [
            "What is your preference?",
            self._preference_widget,
        ]

    def _update_value(self, preference):
        self.value = f"My preference is {preference}."


preference_input = PreferenceInput()


def even_or_odd(contents, user, instance):
    if len(contents) % 2 == 0:
        return "Even number of characters."
    return "Odd number of characters."


pn.chat.ChatInterface(callback=even_or_odd, widgets=[preference_input]).servable()
image

ahuang11 avatar Jul 29 '24 18:07 ahuang11

That is great.

This should be documented.

Why do we have both the Viewer and the CompositeWidget @philippjfr ?

MarcSkovMadsen avatar Jul 30 '24 01:07 MarcSkovMadsen

We now have documents about using PyComponent + WidgetBase to create widgets.

philippjfr avatar Sep 03 '25 07:09 philippjfr