Today you can panel.bind to the value trait of an ipywidgets. But ipywidgets sometimes don't have a value trait or sometimes it has lots of extra, interesting traits.
In https://discourse.holoviz.org/t/panel-works-with-anywidget/6466 I demonstrate how you can easily create an observer, A Parameterized object with parameters corresponding to the ipywidgets that observe for trait changes. Such an observer makes it easy to .watch, @depends, bind and more to the ipywidget.
Please consolidate this functionality and add it to Param.
It should probably be easy to only observe a specified selection of traits (white list) as well as a specified selection of traits not to watch (black list).
# pip install panel ipywidgets_bokeh anywidget
import anywidget
import traitlets
class CounterWidget(anywidget.AnyWidget):
_esm = """
export function render({ model, el }) {
let getCount = () => model.get("count");
let button = document.createElement("button");
button.classList.add("counter-button");
button.innerHTML = `Count is ${getCount()}`;
button.addEventListener("click", () => {
model.set("count", getCount() + 1);
model.save_changes();
});
model.on("change:count", () => {
button.innerHTML = `Count is ${getCount()}`;
});
el.appendChild(button);
}
"""
_css="""
.counter-button { background-color: pink; font-size: 48px}
.counter-button:hover { background-color: pink; }
"""
count = traitlets.Int(0).tag(sync=True)
counter = CounterWidget()
# HELP FUNCTIONALITY to convert Traitlets Classes/ Events to Param Classes/ Events
import param
_ipywidget_classes = {}
_any_widget_traits = set(anywidget.AnyWidget().traits())
def create_observer(obj, traits=None)->param.Parameterized:
"""Returns a Parameterized class with parameters corresponding to the traits of the obj
Args:
traits: A list of traits to observe. If None all traits not on the base AnyWidget will be
observed.
"""
if not traits:
traits = list(set(obj.traits())-_any_widget_traits)
name = type(obj).__name__
if name in _ipywidget_classes:
observer_class = _ipywidget_classes[name]
else:
observer_class = param.parameterized_class(name, {trait: param.Parameter() for trait in traits})
_ipywidget_classes[name] = observer_class
values = {trait: getattr(obj, trait) for trait in traits}
observer = observer_class(**values)
obj.observe(lambda event: setattr(observer, event["name"], event["new"]), names=traits)
return observer
# THE PANEL APP
import panel as pn
pn.extension("ipywidgets")
observer = create_observer(counter)
def some_output(count):
return f"The count is {count}!"
component = pn.Column(counter, pn.bind(some_output, observer.param.count))
pn.template.FastListTemplate(
site="Panel",
title="Works with AnyWidget",
main=[component],
).servable()
Today you can
panel.bind
to thevalue
trait of anipywidgets
. But ipywidgets sometimes don't have avalue
trait or sometimes it has lots of extra, interesting traits.In https://discourse.holoviz.org/t/panel-works-with-anywidget/6466 I demonstrate how you can easily create an observer, A Parameterized object with parameters corresponding to the
ipywidgets
that observe for trait changes. Such an observer makes it easy to.watch
,@depends
,bind
and more to the ipywidget.Please consolidate this functionality and add it to Param.
It should probably be easy to only observe a specified selection of traits (white list) as well as a specified selection of traits not to watch (black list).
https://github.com/holoviz/param/assets/42288570/d68bb4dc-d83f-44fd-8e0e-4628f75fc86f