Reputation: 859
I just started using ipywidgets and I am trying to find the ropes, so if this question has been answered previously or the documentation covers it in some way, kindly point me to that section. Essentially, here is a miniature version of the UI I am trying to develop.
The question that has got me perplexed is, once I construct a UI like shown below, and the user provides their input, how do I unload the input? I am hoping to collect values for each of the variables and trigger my logic, but the only thing I see in the documentation talks about using either interact or interactive.
However I am not really sure how to use them with multiple widgets, all the examples I have come across seem to point to using them with a single widget. If anyone could point me to a good resource or provide a sample, that would be helpful.
With that classifier, here is what I am trying to do:
import ipywidgets as widgets
style = {'description_width': 'initial'}
def input_tab(tab_list, tab_names_list):
if len(tab_list) == len(tab_names_list):
this_tab = Tab()
this_tab.children = tab_list
[this_tab.set_title(i, title) for i, title in enumerate(tab_names_list)]
return this_tab
else:
raise ValueError('\n Input lists should be of the same size')
def get_input_panel_num():
input_1 = widgets.Text(value='3000', description='Input-1', style=style)
input_2 = widgets.Dropdown(options=['yes', 'no'], description='Select one', value='yes', disabled=False, style=style)
input_3 = widgets.IntSlider(value=0, min=0, max=1, step=1, description='Input-3', orientation='horizontal', readout=True,
style=style)
input_list_num = [input_1, input_2, input_3]
return input_list_num
def get_input_panel_char():
input_a = widgets.Text(value='3000', description='Input-1', style=style)
input_b = widgets.Dropdown(options=['yes', 'no'], description='Select one', value='yes', disabled=False, style=style)
input_c = widgets.IntSlider(value=0, min=0, max=1, step=1, description='Input-3', orientation='horizontal', readout=True,
style=style)
input_list_char = [input_a, input_b, input_c]
return input_list_char
def create_master_tab():
tab_names = ["tab-1", "tab-2"]
panel_num = VBox(get_input_panel_num())
panel_char = VBox(get_input_panel_char())
final = input_tab(tab_list=[panel_num, panel_char], tab_names_list=tab_names)
return final
demo = create_master_tab()
demo
***************** UPDATED QUESTION ***************************** @ac24: I was unable to post all the code in the comments, so here is my updated code after incorporating your advice. It runs as expected for the large part, but refuses to accept titles which is what I am confused about. I was able to set titles to the tabs when they were functions using the exact same approach, so I am not sure what has changed really:
import ipywidgets as widgets
from ipywidgets import HBox
from ipywidgets import Tab
# Definition of style
style = {'description_width': 'initial'}
class TabHolder(Tab):
def __init__(self, tab_objects, tab_names):
"""
Initialization of TabHolder object class
:param list tab_objects: collection of display objects to be captured in the tabs
:param list tab_names: names to assign to the tabs
:return: tab widget containing all the tabs
:rtype: Tab
"""
if len(tab_names) != len(tab_objects):
raise ValueError("\n Failed in TabHolder creation, because of lengths of inputs don't match")
else:
self.tab = Tab()
self.tab_names = tab_names
self.tab_objects = tab_objects
self.inputs = []
for i in tab_objects:
self.inputs.append(i)
super().__init__(children=self.inputs)
[self.tab.set_title(i, title) for i, title in enumerate(self.tab_names)] # Why titles not being set?
class InputPanelChar(HBox):
def __init__(self):
self.input_a = widgets.Text(value='3000', description='Input-1', style=style)
self.input_b = widgets.Dropdown(options=['yes', 'no'], description='Select one', value='yes', disabled=False,
style=style)
self.input_c = widgets.IntSlider(value=0, min=0, max=1, step=1, description='Input-3', orientation='horizontal',
readout=True, style=style)
self.input_list_char = [self.input_a, self.input_b, self.input_c]
super().__init__(children= self.input_list_char)
def get_interact_value(self):
return {
w.description: w.get_interact_value()
for w in self.input_list_char
}
class InputPanelNum(HBox):
def __init__(self):
self.input_1 = widgets.Text(value='3000', description='Input-1', style=style)
self.input_2 = widgets.Dropdown(options=['yes', 'no'], description='Select one', value='yes', disabled=False,
style=style)
self.input_3 = widgets.IntSlider(value=0, min=0, max=1, step=1, description='Input-3', orientation='horizontal',
readout=True, style=style)
self.input_list_num = [self.input_1, self.input_2, self.input_3]
super().__init__(children= self.input_list_num)
def get_interact_value(self):
return {
w.description: w.get_interact_value()
for w in self.input_list_num
}
Upvotes: 0
Views: 551
Reputation: 5565
Having been through the exact same issue, my solution was to develop classes of widget groups that make sense together.
If you convert your various functions into classes, you can extract the various widget values. I've adapted your input_panel_char
function into a subclass of HBox.
I've assumed you want to get the widget values as a dictionary with the widget description as the key.
class InputPanelChar(widgets.HBox):
def __init__(self):
self.input_a = widgets.Text(value='3000', description='Input-1', style=style)
self.input_b = widgets.Dropdown(options=['yes', 'no'], description='Select one', value='yes', disabled=False, style=style)
self.input_c = widgets.IntSlider(value=0, min=0, max=1, step=1, description='Input-3', orientation='horizontal', readout=True,
style=style)
self.input_list_char = [self.input_a, self.input_b, self.input_c]
super().__init__(children= self.input_list_char)
def get_interact_value(self):
return {
w.description: w.get_interact_value()
for w in self.input_list_char
}
*****UPDATE*****
When creating your tab holder, you subclass Tab
AND create a tab instance, which is causing the confusion. All you need to do is subclass Tab
and then self
is a Tab
instance, no need to create self.tabs within your instance. Hope this example is clear:
class TabHolder(Tab):
def __init__(self, tab_objects, tab_names):
if len(tab_names) != len(tab_objects):
raise ValueError("\n Failed in TabHolder creation, because of lengths of inputs don't match")
else:
self.tab_names = list(tab_names)
self.tab_objects = list(tab_objects)
super().__init__(children=self.tab_objects)
for i, title in enumerate(self.tab_names):
self.set_title(i, title)
Upvotes: 1