I am trying to make a simple navigation dashboard for a CSV file like below.

The data structure is essentially a tree and I want to navigate the nodes. The first Select widget is for parent nodes (usually 1, but can be more than 1), the middle Label widget is for current node value, and last Select widget is for children nodes.
The goal is when I select an option, I want to update all 3 widgets with new options (including the one I selected in). How can I force overwrite this.
Here is my current (not working) code, where I omitted the data code.
import panel as pn
pn.extension()
current_code = "root"
label_widget = pn.widgets.StaticText()
parent_select = pn.widgets.Select(size=10)
children_select = pn.widgets.Select(size=10)
Updating = False
dashboard = pn.Row(
parent_select,
label_widget,
children_select
)
def set_parent_select(code):
def get_parent_options(code):
...
options = get_parent_options(code)
if options == []:
parent_select.disabled = True
else:
parent_select.options = options
def set_children_select(code):
def get_children_options(code)
...
options = get_children_options(code)
if options == []:
children_select.disabled = True
else:
children_select.options = options
def set_label_widget(event):
global Updating
if Updating:
return
Updating = True
print(event.new)
label_widget.value = event.new
set_parent_select(event.new)
set_children_select(event.new)
Updating = False
parent_select.param.watch(set_label_widget, 'value')
children_select.param.watch(set_label_widget, 'value')
Updating = True
label_widget.value = current_code
set_parent_select(current_code)
set_children_select(current_code)
Updating = False
dashboard.servable()
When I select an option, I get the error ValueError: foobar not in list
if I for example select foobar from any of the two Select widgets that have that option.
I didn’t look too closely, but I suggest using pn.bind
and also param.parameterized.watch_batch_caller
(or I forget the exact name, equivalent of the deprecated param.batch_watch()
to update the options and value at the same time)
I managed to temporarily resolve the issue by replacing the Select widget with a new one, here is updated working code
import panel as pn
pn.extension()
placeholder_code = '---SELECT OPTION---'
def create_select():
return pn.widgets.Select(size=10)
def create_parent_select(label_widget, code):
def get_parent_options(code):
...
options = get_parent_options(code)
parent_select = create_select()
parent_select.link(label_widget, callbacks={'value': set_label_widget})
if options == []:
parent_select.disabled = True
parent_select.options = []
else:
parent_select.options = [placeholder_code] + options
return parent_select
def create_children_select(label_widget, code):
def get_children_options(code):
...
children_select = create_select()
children_select.link(label_widget, callbacks={'value': set_label_widget})
options = get_children_options(code)
if options == []:
children_select.disabled = True
children_select.options = []
else:
children_select.options = [placeholder_code] + options
return children_select
def create_dashboard(dashboard, starting_code="root"):
if starting_code == placeholder_code:
return
dashboard.clear()
label_widget = pn.widgets.StaticText(value=starting_code)
parent_select = create_parent_select(label_widget, starting_code)
children_select = create_children_select(label_widget, starting_code)
dashboard.append(parent_select)
dashboard.append(label_widget)
dashboard.append(children_select)
return dashboard
dashboard = pn.Row()
Updating = True
create_dashboard(dashboard)
Updating = False
def set_label_widget(target, event):
global Updating
global dashboard
if Updating:
return
Updating = True
create_dashboard(dashboard, event.new)
Updating = False
dashboard.servable()
Essentially with each new option selection, I remove the old widget and create a new one with the updated options. I needed to append a place holder option, that is skipped on purpose, because otherwise it would right away callback again on the new selection of first element in widget upon creation.
For my purposes, the option lists are small and therefore it is acceptable solution for the time being.
1 Like