Pharaonicode
Pharaonicode

Reputation: 25

How to create a dynamic dependent dropdown menu using ipywidgets?

I created a form with two drop down menu's:

My goal is to make one dropdown dependent on the other dropdown.

This picture illustrates my goal and the current situation.

The sample code below can be run in Google Colab or Jupyter notebook to replicate the current situation.

#@title 
import ipywidgets as widgets
from ipywidgets import HBox, Label
from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider
import time
import pandas as pd

#Create DF
df = df = pd.DataFrame(columns = ['Dropdown_column', 'Float_column'])
df

# Layout
form_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='space-between',
)


button_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='center',
    padding = '5%'
)


# Independent dropdown item

drop_down_input = 'Dropdown_input_1'

drop_down = widgets.Dropdown(options=('Dropdown_input_1', 'Dropdown_input_2'))

def dropdown_handler(change):
    global drop_down_input
    print('\r','Dropdown: ' + str(change.new),end='')
    drop_down_input = change.new

drop_down.observe(dropdown_handler, names='value')


# Dependent drop down

# Dependent drop down elements

dependent_drop_down_elements = {}
dependent_drop_down_elements['Dropdown_input_1'] = ['A', 'B']
dependent_drop_down_elements['Dropdown_input_2'] = ['C', 'D', 'E'] 

# Define dependent drop down

dependent_drop_down = widgets.Dropdown(options=(dependent_drop_down_elements['Dropdown_input_1']))

def dropdown_handler(change):
    global drop_down_input
    print('\r','Dropdown: ' + str(change.new),end='')
    drop_down_input = change.new  
drop_down.observe(dropdown_handler, names='value')



# Button

button = widgets.Button(description='Add row to dataframe')
out = widgets.Output()
def on_button_clicked(b):
    global df
    button.description = 'Row added'
    time.sleep(1)
    with out:
      new_row = {'Dropdown_column': drop_down_input, 'Float_column': float_input}
      df = df.append(new_row, ignore_index=True)
      button.description = 'Add row to dataframe'
      out.clear_output()  
      display(df)
button.on_click(on_button_clicked)

# Form items

form_items = [         
    Box([Label(value='Independent dropdown'),
         drop_down], layout=form_item_layout),
    Box([Label(value='Dependent dropdown'),
         dependent_drop_down], layout=form_item_layout)
         ]

form = Box(form_items, layout=Layout(
    display='flex',
    flex_flow='column',
    border='solid 1px',
    align_items='stretch',
    width='30%',
    padding = '1%'
))
display(form)
display(out)

Is this possible? If so, can you explain how?

Upvotes: 2

Views: 3514

Answers (1)

jylls
jylls

Reputation: 4695

You can do this by setting a if statement in your dropdown_handler function that checks if the value chosen in your independent dropdown is Dropdown_input_1 or Dropdown_input2. Still in the dropdown_handler, you can then modify accordingly the options arguments to either dependent_drop_down_elements['Dropdown_input_1'] or dependent_drop_down_elements['Dropdown_input_2'].

See code below:

import ipywidgets as widgets
from ipywidgets import HBox, Label
from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider
import time
import pandas as pd

#Create DF
df = df = pd.DataFrame(columns = ['Dropdown_column', 'Float_column'])
df

# Layout
form_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='space-between',
)


button_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='center',
    padding = '5%'
)


# Independent dropdown item

drop_down_input = 'Dropdown_input_1'
drop_down = widgets.Dropdown(options=('Dropdown_input_1', 'Dropdown_input_2'))


# Dependent drop down
# Dependent drop down elements
dependent_drop_down_elements = {}
dependent_drop_down_elements['Dropdown_input_1'] = ['A', 'B']
dependent_drop_down_elements['Dropdown_input_2'] = ['C', 'D', 'E'] 

# Define dependent drop down

dependent_drop_down = widgets.Dropdown(options=(dependent_drop_down_elements['Dropdown_input_1']))

def dropdown_handler(change):
    global drop_down_input
    print('\r','Dropdown: ' + str(change.new),end='')
    drop_down_input = change.new
    #If statement checking on dropdown value and changing options of the dependent dropdown accordingly
    if change.new=='Dropdown_input_2':
       dependent_drop_down.options=dependent_drop_down_elements['Dropdown_input_2']
    elif change.new=='Dropdown_input_1':
        dependent_drop_down.options=dependent_drop_down_elements['Dropdown_input_1']
drop_down.observe(dropdown_handler, names='value')

# Button

button = widgets.Button(description='Add row to dataframe')
out = widgets.Output()
def on_button_clicked(b):
    global df
    button.description = 'Row added'
    time.sleep(1)
    with out:
      new_row = {'Dropdown_column': drop_down_input, 'Float_column': float_input}
      df = df.append(new_row, ignore_index=True)
      button.description = 'Add row to dataframe'
      out.clear_output()  
      display(df)
button.on_click(on_button_clicked)

# Form items

form_items = [         
    Box([Label(value='Independent dropdown'),
         drop_down], layout=form_item_layout),
    Box([Label(value='Dependent dropdown'),
         dependent_drop_down], layout=form_item_layout)
         ]

form = Box(form_items, layout=Layout(
    display='flex',
    flex_flow='column',
    border='solid 1px',
    align_items='stretch',
    width='30%',
    padding = '1%'
))
display(form)
display(out)

As an example, this is what the output looks like when you pick Dropdown_input_2 on the first widget:

enter image description here

Upvotes: 3

Related Questions