Black Lives Matter. Please consider donating to Black Girls Code today.

Dropdown Callback for Dropdown Options not behaving as expected

I am experiencing some unexpected behaviour with my dropdown call backs, in that the dropdowns are not being populated with the options. Instead I get a dropdown that is scrollable and appears to have the right number of options but I just can’t see them:

06

The four dropdowns represent four columns in my data frame and what I am trying to do is populate them with the unique values in the data frame, but at the same time dependent on the options selected in the other dropdowns. So if I selected Toyota in box 1, I should only see Toyota models in box 2. And if I select Rav4 in box 2, then only Toyota in box1 and the various different colours that apply to Rav4’s in box3 (based on data in the df) etc. (hope that makes sense!)

How I’ve tried to approach this is having four callback functions similar to this one:

@app.callback(Output('brandDropdown', 'options'),
                    [Input('brandDropdown', 'value'),
                    Input('modelDropdown', 'value'),
                    Input('bodyTypeDropdown', 'value'),
                    Input('colorDropdown', 'value')])

def brandOptions(brand, model, bodyType, color):
    request = 'brandOptions'
    options = dashboard_functions.dataRequest(df_data, brand, model, bodyType, color, request)
    return options

The dataRequest function looks like this (extract of relevant bits):

def dataRequest(df_data, brand, model, type, color, request):`
brandSelection = []
modelSelection = []
typeSelection = []
colorSelection = []

#if no options selected then default to "All"
if brand == []:
    brandSelection = df_data['Car Make'].unique()
else:
    brandSelection = brand

if model == []:
    modelSelection = df_data['Car Model'].unique()
else:
    modelSelection = model

if type == []:
    typeSelection = df_data['Car Body'].unique()
else:
    typeSelection = type

if color == []:
    colorSelection = df_data['Exterior Color'].unique()
else:
    colorSelection = color

#filter data based on options selected in the four dropdowns
df_data = df_data.loc[df_data['Car Make'].isin(brandSelection) & \
            df_data['Car Model'].isin(modelSelection) & \
            df_data['Car Body'].isin(typeSelection) & \
            df_data['Exterior Color'].isin(colorSelection)]

#Get latest available options for each of the dropdowns
brandOptions = df_data['Car Make'].unique()
modelOptions = df_data['Car Model'].unique()
bodyTypeOptions = df_data['Car Body'].unique()
colorOptions = df_data['Exterior Color'].unique()

if request == 'brandOptions':
    print(brandOptions)
    return brandOptions

Now when I first run my dash the Brand dropdown is empty (same as above screenshot) but interestingly the print statement is outputting the correct values:

['Toyota' 'Hyundai' 'Chevrolet' 'Ford' 'BMW' 'Nissan' 'Mercedes-Benz'
 'Mazda' 'Honda' 'Dodge' 'Lexus' 'INFINITI' 'Subaru' 'Kia' 'Scion'
 'Volkswagen']

But why are these not being fed back to my Dropdown as selectable options?

Thanks

Chris

Update:

Realised that my code was a little flawed, in that if you select an option it effectively removes all other options from the dropdown. So I have now revised a little like so:

@app.callback(Output('modelDropdown', 'options'),
                [Input('brandDropdown', 'value'),
                Input('bodyTypeDropdown', 'value'),
                Input('colorDropdown', 'value')])

def modelOptions(brand, bodyType, color):
    options = dashboard_functions.modelOptions(df_data, brand, bodyType, color)
    print(options)
    return options

and

def modelOptions(df_data, brand, type, color):
brandSelection = []
typeSelection = []
colorSelection = []

if brand == []:
    brandSelection = df_data['Car Make'].unique()
else:
    brandSelection = brand

if type == []:
    typeSelection = df_data['Car Body'].unique()
else:
    typeSelection = type

if color == []:
    colorSelection = df_data['Exterior Color'].unique()
else:
    colorSelection = color

#filter data based on options selected in the three dropdowns
df_data = df_data.loc[df_data['Car Make'].isin(brandSelection) & \
            df_data['Car Body'].isin(typeSelection) & \
            df_data['Exterior Color'].isin(colorSelection)]

modelOptions = df_data['Car Model'].unique()
return modelOptions

Now when I first run the dash, Dropdowns 3 and 4 do have selectable options when I first run the dash (I’m not sure why 1 and 2 don’t)… but as soon as I choose an option, the dropdowns become blank again.



I am also getting the options I’m expecting to see from my print statements.

For example, I selected “BLUE” in box 4. The print statements show:

 'SILVER KNOCKOUT METALLIC W BLACK ROOF' 'Salsa Red Pearl' 'Frost'
 'Indigo Blue Metallic' 'Hypersonic Red' 'BLACK SAND PEARL'
 'Brown Sugar Metallic' 'Bright Silver Metallic' 'Midnight Black'
 ...
 'HARBOR GRAY METALLIC' 'GRAY' 'WHITE' 'RED' 'SILVER' 'BLUE' 'BROWN'
 'PURPLE' 'Magnetic Gray Met.' 'BRONZE' 'INFERNO' 'Army Green']
['Corolla' 'RAV4' 'Highlander' 'Camry' 'Sienna' 'RAV4 Hybrid' '4Runner']
['Sedan' 'Sport Utility Vehicle' nan 'Passenger Minivan']
['Toyota']

i.e. all BLUE vehicles are Toyota and either Corolla/RAV4/Highlander etc and either Sedan/SUV etc

So my logic is now working but I can’t get these options to be populated in the dropdown? It’s like they are not rendering correctly?

Just in case anyone happens to have the same issue with blank dropdowns and stumbles across this thread, the issue was that I was returning a list of options and not a dictionary

Using this:

brandOptions = [{'label' : i, 'value' : i} for i in df_data['Car Make'].unique()]

Instead of this:

brandOptions = df_data['Car Make'].unique()

Fixed it

1 Like