ipywidgets
ipywidgets copied to clipboard
(enhancement?) Dropdown options update to try to keep the same displayed value if available in new options
trafficstars
Because of self.index = 0 in widget_selection.py#L214, an update to a dropdown's options would reset the selected option to the one at index=0.
However, if the new options list still contain the currently selected value, it would be nice to update the index such that the selected value is still the same.
Example demonstrating current status:
w_dropdown = widgets.Dropdown(options=[1,2,3], index=0)
assert w_dropdown.value==1
w_dropdown.options = [3,2,1]
assert w_dropdown.value==3 # nice if this stays at 1
Example patch (added section surrounded with >>>>>>>)
# Again, with my own patch
w_dropdown = widgets.Dropdown(options=[1,2,3], index=0)
assert w_dropdown.value==1
display(w_dropdown)
print("sleep 5 to observe any value change")
import time
time.sleep(5)
def _propagate_options(self, change):
"Set the values and labels, and select the first option if we aren't initializing"
options = self._options_full
self.set_trait('_options_labels', tuple(i[0] for i in options))
self._options_values = tuple(i[1] for i in options)
#print(f"Options changed: {self.options} -> {self._options_values}")
if self.index is None:
# Do nothing, we don't want to force a selection if
# the options list changed
return
if self._initializing_traits_ is not True:
if len(options) > 0:
# >>>>>>>>>>>>>>>>>>>>>>>>
# try to keep the same value
if self.value in self._options_values:
index_new = self._options_values.index(self.value)
#print(f"try to keep same value {self.value} by changing index from {self.index} to {index_new}")
self.index = index_new
return
# >>>>>>>>>>>>>>>>>>>>>>>>
if self.index == 0:
# Explicitly trigger the observers to pick up the new value and
# label. Just setting the value would not trigger the observers
# since traitlets thinks the value hasn't changed.
self._notify_trait('index', 0, 0)
else:
self.index = 0
else:
self.index = None
# Avoid using "w_dropdown.options = ..." so as not to trigger the upstream "_propagate_options"
w_dropdown._options_full = widgets.widget_selection._make_options([3,2,1])
_propagate_options(w_dropdown, None)
assert w_dropdown.value==1 # indeed this stays 1
# Visually confirm that the displayed value is still 1