Dynamically creating widgets

Are there any examples of dynamically creating widgets with the reactive API? I was expecting this to work but the sliders don’t seem to move. I work on Shiny for Python, but am quite new to Panel so my apologies if this is an obvious question. For reference here is the Shiny implementation that I’m trying to replicate.

import panel as pn


def create_sliders(n):
    sliders = [pn.widgets.IntSlider(name=f"Slider {i+1}") for i in range(n)]
    outputs = [pn.widgets.TextInput(value=f"Slider {i+1} value: {slider.value}") for i, slider in enumerate(sliders)]
    return pn.Column(*(slider, output) for slider, output in zip(sliders, outputs))


n_input = pn.widgets.IntInput(name="Number of Sliders", value=1)
sliders = pn.bind(create_sliders, n=n_input)

app = pn.Column(n_input, sliders)

# Make the app servable
app.servable()
1 Like

Hi @gshotwell

Welcome to the community.

The main thing to understand is that f"Slider {i+1} value: {slider.value}" is a static value, not dynamic/ reactive.

To make it reactive you will have to apply one of the reactive apis. Like .bind, .depends or .rx.

.bind

.bind is the basic, reactive api we recommend using. In my experience you can do everything with .bind.

import panel as pn

def get_text(i, value):
    return f"Slider {i+1} value: {value}"

def create_sliders(n):
    sliders = [pn.widgets.IntSlider(name=f"Slider {i+1}", value=5, start=0, end=10) for i in range(n)]
    outputs = [pn.bind(get_text, i=i, value=slider) for i, slider in enumerate(sliders)]
    
    return pn.Column(*(item for pair in zip(sliders, outputs) for item in pair))
    

n_input = pn.widgets.IntSlider(name="Number of Sliders", value=1, start=1, end=10)
app = pn.Column(n_input, pn.layout.Divider(), pn.bind(create_sliders, n_input))

app.servable()

.rx

Reactive Expressions (.rx) is a new api that we have just started to use and understand.

import panel as pn

def create_sliders(n):
    sliders = [pn.widgets.IntSlider(name=f"Slider {i+1}", value=5, start=0, end=10) for i in range(n)]
    outputs = [f"Slider {i+1} value: " + slider.rx().__str__() for i, slider in enumerate(sliders)]
    
    return pn.Column(*(item for pair in zip(sliders, outputs) for item in pair))
    

n_input = pn.widgets.IntSlider(name="Number of Sliders", value=1, start=1, end=10)
app = pn.Column(n_input, pn.layout.Divider(), pn.bind(create_sliders, n_input))

app.servable()

image

1 Like

Thanks! I knew it must be something obvious.

1 Like