I’m still trying to understand how to use param.Parameterized
to reproduce something like this. I see how the GoogleMapViewer example allows the available objects in the selectors to be dynamic, but I don’t yet understand how to use this model to create and refer to new, or variable numbers of widgets. The example I currently have working (following @nghenzi’s suggestion), is
import panel as pn
pn.extension()
wBox = pn.WidgetBox(horizontal=True)
widget_definer = pn.widgets.MultiSelect(options=['a', 'b', 'c'])
values = pn.widgets.StaticText(value='')
@pn.depends(widget_definer.param.value, watch=True)
def get_widgetBox(values):
selects = []
for v in values:
selects.append(pn.widgets.MultiSelect(name=v, options=[1,2,3,4,5]))
wBox[:] = [*selects]
btn = pn.widgets.Button(name='show selects')
def show(event):
s = ''
for select in wBox:
s += f'{select.name}: {select.value}' + '\n'
values.value = s
btn.on_click(show)
col = pn.Column(widget_definer, wBox, values)
pn.Row(col, btn).servable()
This is accomplished by predefining the wBox
as empty, treating it as a global, and then having the callback redefine its objects. I don’t yet see how to do this all within a single parameterized class; it’s almost as if wBox
itself would need to be a parameter, and I don’t know how to do that.
Edit: For example, the following gives close to the idea I want, but I don’t know how to access the values selected in the dynamic widgetbox in a param-ish way:
import panel as pn
import param
pn.extension()
class DynamicWidgetBox(param.Parameterized):
options = param.ListSelector(default=[], objects=['a', 'b', 'c'])
@param.depends('options')
def widgets(self):
selects = []
for v in self.options:
selects.append(pn.widgets.MultiSelect(name=v, options=[1,2,3,4,5]))
return pn.WidgetBox(*selects, horizontal=True)
@param.depends('widgets') # how do I depend on the *values* of the result of the above?
def values(self):
s = ''
for select in self.widgets():
s += f'{select.name}: {select.value}; '
return pn.widgets.StaticText(value=s)
dwb = DynamicWidgetBox()
pn.Column(dwb.param, dwb.widgets, dwb.values)
Further edit:
A sort of “hybrid” approach might look something like this. I’d be curious for any tips on how to do this more cleanly using only param.Parameterized
objects and depends
decorators.
import panel as pn
import param
pn.extension()
class DynamicWidgetBox(param.Parameterized):
options = param.ListSelector(default=[], objects=['a', 'b', 'c'])
wBox = pn.WidgetBox(horizontal=True)
@param.depends('options')
def widgets(self):
selects = []
for v in self.options:
selects.append(pn.widgets.MultiSelect(name=v, options=[1,2,3,4,5]))
self.wBox[:] = [*selects]
return self.wBox
dwb = DynamicWidgetBox()
values = pn.widgets.StaticText(value='')
button = pn.widgets.Button(name='Update Values')
def update_values(event):
s = ''
for select in dwb.wBox:
s += f'{select.name}: {select.value}; '
values.value = s
button.on_click(update_values)
pn.Column(dwb.param, dwb.widgets, button, values)