panel icon indicating copy to clipboard operation
panel copied to clipboard

Document how to use .from_param to create a widget from a reactive parameter

Open MarcSkovMadsen opened this issue 1 year ago • 4 comments

I can't figure out how to create a widget from a reactive parameter.

More specifically

import panel as pn

pn.extension()

zoom = pn.rx(2)

slider = pn.widgets.IntSlider.from_param(zoom, start=1, end=10)

I get

AttributeError: 'rx' object has no attribute 'name'

Traceback (most recent call last):
  File "/home/jovyan/repos/private/panel-geospatial/.venv/lib/python3.11/site-packages/panel/io/handlers.py", line 389, in run
    exec(self._code, module.__dict__)
  File "/home/jovyan/repos/private/panel-geospatial/pages/03_mapbox.py", line 11, in <module>
    pn.widgets.IntSlider.from_param(zoom, start=1, end=10)
  File "/home/jovyan/repos/private/panel-geospatial/.venv/lib/python3.11/site-packages/panel/widgets/base.py", line 93, in from_param
    parameter, widgets={parameter.name: dict(type=cls, **params)},
                        ^^^^^^^^^^^^^^
  File "/home/jovyan/repos/private/panel-geospatial/.venv/lib/python3.11/site-packages/param/reactive.py", line 1032, in __getattribute__
    return super().__getattribute__(name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'rx' object has no attribute 'name'

I cannot find this documented anywhere.

MarcSkovMadsen avatar Jun 10 '24 19:06 MarcSkovMadsen

A workaround would be to define the widget first and the from it the reactive parameter. But the problem is that then I cannot update the value of the reactive parameter

AttributeError: Setting the value of a reactive expression is only supported if it wraps a concrete value. A reactive expression wrapping a Parameter or another dynamic reference cannot be updated.

I believe it should be possible to update it.

import panel as pn

pn.extension()

zoom_input = pn.widgets.IntSlider(value=2, start=1, end=10, name="Zoom")
zoom = zoom_input.rx()
zoom.rx.value=3

MarcSkovMadsen avatar Jun 10 '24 19:06 MarcSkovMadsen

This does not work either

import panel as pn

pn.extension()

zoom = pn.rx(2)
zoom_input = pn.widgets.FloatSlider(value=zoom, start=1, end=10, step=1.0, name="Zoom")
zoom_input.value=3
print(zoom.rx.value)

Here the problem is that there is only one-way binding from reactive parameter to widget. Not the other way.

MarcSkovMadsen avatar Jun 10 '24 19:06 MarcSkovMadsen

There is no way to reverse bind an rx expression since it isn't possible to invert arbitrary expressions.

philippjfr avatar Jun 15 '24 16:06 philippjfr

We could add support for inverting an expression that simply mirrors a parameter value but as soon as you do something with it there's no way.

philippjfr avatar Jun 15 '24 16:06 philippjfr

This can be achieved by this code

import panel as pn

pn.extension()

frequency = pn.rx(1)

slider = pn.widgets.FloatSlider(value=1, start=0, end=10)

def set(value):
    frequency.rx.value=value

slider.rx().rx.watch(set)

pn.Column(slider, frequency).servable()

I think that is lengthy. In react you always get value, set_value where set_value is a function to update the value. I think there should be a set, set_value or update special method on .rx to make this easier.

import panel as pn

pn.extension()

frequency = pn.rx(1)

slider = pn.widgets.FloatSlider(value=1, start=0, end=10)

slider.rx().rx.watch(frequency.rx.set_value)

pn.Column(slider, frequency).servable()

Do you agree? Should I file a request with param?

MarcSkovMadsen avatar Jul 16 '24 14:07 MarcSkovMadsen

Closing since this has been filed upstream: https://github.com/holoviz/param/issues/956

philippjfr avatar Sep 03 '25 11:09 philippjfr

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

github-actions[bot] avatar Dec 16 '25 01:12 github-actions[bot]