Jupyter Notebook – ipywidgets – Automatic feedback from selected
Question:
I am trying to create a function in a Jupyter notebook to:
- Display with an
ipywidget
a series of radio buttons from a list of options.
- Automatically display the selected value.
- Save the selected value in a variable.
So far, I managed step 1 (widget named radio_buttons
in the MWE below) and to create a second ipythonwidget
to display the result (widget named display_result
, not yet displaying said result). I understand I need to bind the selected result to the value of the display_result
(attempted with the function bind_selected_to_output
) but I do not understand how.
MWE
from ipywidgets import interact, widgets
from IPython.display import display
options=["A","B","C"]
# Tentative function to get the input value into the output widget
def bind_selected_to_output(display):
display.value=#The selected value of radio buttons
# The function I am trying to create
def display_radio_buttons(options):
# Input widget
radio_buttons=widgets.RadioButtons(
options=options,
value=None,
disabled=False
# Output widget
display_result=widgets.Text(description = "Saved as:",
disabled=True)
# Trying to monitor selection on the input widget
radio_buttons.observe(bind_selected_to_output(display_result))
# Show the widgets
display(radio_buttons)
display(display_result)
# Return selected value for use elsewhere
return display_result.value
# Use function
display_radio_buttons(options)
)
How can I make this function work?
Answers:
To give you an idea of how to do those three aims, I went here and adapted my code that was accomplishing those aims in a different context with a different widget. I’m posting the resulting code here.
Essentially, for the first code block I just had to substitute ToggleButtons
with RadioButtons
to make the code block below that would set up some radio buttons that were interactive:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons
def print_choices(choice1, choice2, choice3):
print(choice1)
print(choice2)
print(choice3)
choice1Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice1:',disabled=False,style= {'description_width': '300px'})
choice2Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice2:',disabled=False,style= {'description_width': '300px'})
choice3Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice3:',disabled=False,style= {'description_width': '300px'})
w = interactive(print_choices, choice1=choice1Select, choice2=choice2Select, choice3=choice3Select)
w
Now in another cell to demonstrate assigning the value to something, you don’t seem to need something as complex as what I had for ‘example embedded in the wrapper function’ there and so maybe this suffices as example of saving the selected value in a variable?:
def return_choice1(choices):
return choices["choice1"]
current_choice1 = return_choice1(w.kwargs)
print(current_choice1)
Adapting that more closely to what you describe as displaying ‘a series of radio buttons from a list of options’:
A lot of streamlining is possible in the course of adapting since you only seem to want one radio widget. And the printing linked to the original function tied the interactive widget can be dispensed with. We can even tap into using the result
attribute of the widget to get the current value. See the documentation for interactive
. Putting that together you may come up with following for a cell that sets up the widget and the monitor of it:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons
options=["A","B","C"]
def radio_selector_monitor(radio_choice_selection):
return radio_choice_selection
radio_selector_widget = RadioButtons(options=options,description='Radio Selector:',disabled=False,style= {'description_width': '300px'})
radio_widget_instance = interactive(radio_selector_monitor, radio_choice_selection=radio_selector_widget)
radio_widget_instance
Now in another cell you can access the current ‘result’ chosen among the selection options by the following:
print(radio_widget_instance.result)
That will keep current with the current setting. You specify your third aim is to, "Save the selected value in a variable."
With interactive
use there isn’t really a need to ‘save the selected value in a variable’, but you can if you want a better named handler for it.
If you’d prefer to assign the current value of the widget to a simpler named variable you can do that, too. However, they are really just names for the same object. For example, if you draft this code in the next cell, you can do that:
print(radio_widget_instance.result)
current_radio_choice = radio_widget_instance.result
current_radio_choice
print(current_radio_choice)
print(current_radio_choice is radio_widget_instance.result)
print(current_radio_choice == radio_widget_instance.result)
In other words, now radio_widget_instance.result
and current_radio_choice
are pointing to the same object.
Adapting the streamlined version to display the value in a second widget
The OP also indicated wanting the value of the radio widget setting to be displayed as the value of a second widget. To demonstrate that, his code block adapts the code from the above section to add setting the value of a second widget when the radio button is updated:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons, Text, VBox
options=["A","B","C"]
output_text = Text()
def radio_selector_monitor_and_binder_to_other_widget(radio_choice_selection):
global current_radio_choice # didn't need as global if just using in this cell, in this function. But if need for later in other cells, make global
current_radio_choice = radio_choice_selection
#display(current_radio_choice) # uncomment this line out if you also the current selection displayed for more feedback
output_text.value = current_radio_choice
return radio_choice_selection
radio_selector_widget = RadioButtons(options=options,description='Radio Selector:',disabled=False,style= {'description_width': '300px'})
radio_widget_instance = interactive(radio_selector_monitor_and_binder_to_other_widget, radio_choice_selection=radio_selector_widget)
VBox([radio_widget_instance, output_text])
The variable current_radio_choice
can also be used in later cells to report the current value of the radio selector. If current_radio_choice
is not to be used outside of that cell and outside of the interactive function than it doesn’t need to be a global.
Asyncio may be the way to go if interactive()
not useable
As I pointed out at the bottom of here, this solution to Is it possible to get the current value of a widget slider from a function without using multithreading? might be of interest to those looking for access current values. In that example the use of asyncio there allows to keep getting updated information from a widget that selects a value while allowing use of time.sleep()
which seems to block interactive()
from working
I found a much more practical solution to my problem. It creates a function display_radio_buttons
which generates radio buttons from the parameter options
(a list of the choices to display). The selected option is displayed in a Text()
widget whose value is linked to the value of the radio buttons. The selected option is also returned for later use (e.g., printing it).
This function can be easily reused, as all elements are defined within the function.
from ipywidgets import widgets, link
from IPython.display import display
options=["A","B","C"]
def display_radio_buttons(options):
button = widgets.RadioButtons(options=options,description='Radio Selector:')
out = widgets.Text(disabled=True)
l = link((button, 'value'), (out, 'value'))
display(button,out)
return out.value
selected = display_radio_buttons(options)
print(selected)
EDIT following Wayne’s comment
Instead of returning the value of the out
which is no longer updated, the button
is return and its value is later printed (or utilized), remaining updated.
from ipywidgets import widgets, link
from IPython.display import display
options=["A","B","C"]
def display_radio_buttons(options):
button = widgets.RadioButtons(options=options,description='Radio Selector:')
out = widgets.Text(disabled=True)
l = link((button, 'value'), (out, 'value'))
display(button, out)
return button
selected = display_radio_buttons(options)
print(selected.value)
I am trying to create a function in a Jupyter notebook to:
- Display with an
ipywidget
a series of radio buttons from a list of options. - Automatically display the selected value.
- Save the selected value in a variable.
So far, I managed step 1 (widget named radio_buttons
in the MWE below) and to create a second ipythonwidget
to display the result (widget named display_result
, not yet displaying said result). I understand I need to bind the selected result to the value of the display_result
(attempted with the function bind_selected_to_output
) but I do not understand how.
MWE
from ipywidgets import interact, widgets
from IPython.display import display
options=["A","B","C"]
# Tentative function to get the input value into the output widget
def bind_selected_to_output(display):
display.value=#The selected value of radio buttons
# The function I am trying to create
def display_radio_buttons(options):
# Input widget
radio_buttons=widgets.RadioButtons(
options=options,
value=None,
disabled=False
# Output widget
display_result=widgets.Text(description = "Saved as:",
disabled=True)
# Trying to monitor selection on the input widget
radio_buttons.observe(bind_selected_to_output(display_result))
# Show the widgets
display(radio_buttons)
display(display_result)
# Return selected value for use elsewhere
return display_result.value
# Use function
display_radio_buttons(options)
)
How can I make this function work?
To give you an idea of how to do those three aims, I went here and adapted my code that was accomplishing those aims in a different context with a different widget. I’m posting the resulting code here.
Essentially, for the first code block I just had to substitute ToggleButtons
with RadioButtons
to make the code block below that would set up some radio buttons that were interactive:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons
def print_choices(choice1, choice2, choice3):
print(choice1)
print(choice2)
print(choice3)
choice1Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice1:',disabled=False,style= {'description_width': '300px'})
choice2Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice2:',disabled=False,style= {'description_width': '300px'})
choice3Select = RadioButtons(options=['Not Included', 'Included', 'Favorite'],description='Choice3:',disabled=False,style= {'description_width': '300px'})
w = interactive(print_choices, choice1=choice1Select, choice2=choice2Select, choice3=choice3Select)
w
Now in another cell to demonstrate assigning the value to something, you don’t seem to need something as complex as what I had for ‘example embedded in the wrapper function’ there and so maybe this suffices as example of saving the selected value in a variable?:
def return_choice1(choices):
return choices["choice1"]
current_choice1 = return_choice1(w.kwargs)
print(current_choice1)
Adapting that more closely to what you describe as displaying ‘a series of radio buttons from a list of options’:
A lot of streamlining is possible in the course of adapting since you only seem to want one radio widget. And the printing linked to the original function tied the interactive widget can be dispensed with. We can even tap into using the result
attribute of the widget to get the current value. See the documentation for interactive
. Putting that together you may come up with following for a cell that sets up the widget and the monitor of it:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons
options=["A","B","C"]
def radio_selector_monitor(radio_choice_selection):
return radio_choice_selection
radio_selector_widget = RadioButtons(options=options,description='Radio Selector:',disabled=False,style= {'description_width': '300px'})
radio_widget_instance = interactive(radio_selector_monitor, radio_choice_selection=radio_selector_widget)
radio_widget_instance
Now in another cell you can access the current ‘result’ chosen among the selection options by the following:
print(radio_widget_instance.result)
That will keep current with the current setting. You specify your third aim is to, "Save the selected value in a variable."
With interactive
use there isn’t really a need to ‘save the selected value in a variable’, but you can if you want a better named handler for it.
If you’d prefer to assign the current value of the widget to a simpler named variable you can do that, too. However, they are really just names for the same object. For example, if you draft this code in the next cell, you can do that:
print(radio_widget_instance.result)
current_radio_choice = radio_widget_instance.result
current_radio_choice
print(current_radio_choice)
print(current_radio_choice is radio_widget_instance.result)
print(current_radio_choice == radio_widget_instance.result)
In other words, now radio_widget_instance.result
and current_radio_choice
are pointing to the same object.
Adapting the streamlined version to display the value in a second widget
The OP also indicated wanting the value of the radio widget setting to be displayed as the value of a second widget. To demonstrate that, his code block adapts the code from the above section to add setting the value of a second widget when the radio button is updated:
#based on https://stackoverflow.com/a/73832884/8508004 and https://stackoverflow.com/q/65137656/8508004 and https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html?highlight=interactive#interactive
from ipywidgets import interactive, RadioButtons, Text, VBox
options=["A","B","C"]
output_text = Text()
def radio_selector_monitor_and_binder_to_other_widget(radio_choice_selection):
global current_radio_choice # didn't need as global if just using in this cell, in this function. But if need for later in other cells, make global
current_radio_choice = radio_choice_selection
#display(current_radio_choice) # uncomment this line out if you also the current selection displayed for more feedback
output_text.value = current_radio_choice
return radio_choice_selection
radio_selector_widget = RadioButtons(options=options,description='Radio Selector:',disabled=False,style= {'description_width': '300px'})
radio_widget_instance = interactive(radio_selector_monitor_and_binder_to_other_widget, radio_choice_selection=radio_selector_widget)
VBox([radio_widget_instance, output_text])
The variable current_radio_choice
can also be used in later cells to report the current value of the radio selector. If current_radio_choice
is not to be used outside of that cell and outside of the interactive function than it doesn’t need to be a global.
Asyncio may be the way to go if interactive()
not useable
As I pointed out at the bottom of here, this solution to Is it possible to get the current value of a widget slider from a function without using multithreading? might be of interest to those looking for access current values. In that example the use of asyncio there allows to keep getting updated information from a widget that selects a value while allowing use of time.sleep()
which seems to block interactive()
from working
I found a much more practical solution to my problem. It creates a function display_radio_buttons
which generates radio buttons from the parameter options
(a list of the choices to display). The selected option is displayed in a Text()
widget whose value is linked to the value of the radio buttons. The selected option is also returned for later use (e.g., printing it).
This function can be easily reused, as all elements are defined within the function.
from ipywidgets import widgets, link
from IPython.display import display
options=["A","B","C"]
def display_radio_buttons(options):
button = widgets.RadioButtons(options=options,description='Radio Selector:')
out = widgets.Text(disabled=True)
l = link((button, 'value'), (out, 'value'))
display(button,out)
return out.value
selected = display_radio_buttons(options)
print(selected)
EDIT following Wayne’s comment
Instead of returning the value of the out
which is no longer updated, the button
is return and its value is later printed (or utilized), remaining updated.
from ipywidgets import widgets, link
from IPython.display import display
options=["A","B","C"]
def display_radio_buttons(options):
button = widgets.RadioButtons(options=options,description='Radio Selector:')
out = widgets.Text(disabled=True)
l = link((button, 'value'), (out, 'value'))
display(button, out)
return button
selected = display_radio_buttons(options)
print(selected.value)