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

Having trouble with multiple filters, please help!

A previous (older post) by chriddyp provided the following example of a dropdown filter on callback. How could this be modified to filter by two columns based off their values instead of one?

import dash
import dash_core_components as dcc
import dash_html_components as html

import pandas as pd

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/'
    'c78bf172206ce24f77d6363a2d754b59/raw/'
    'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
    'usa-agricultural-exports-2011.csv')

def generate_table(dataframe, max_rows=50):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

app = dash.Dash()

app.layout = html.Div(children=[
    html.H4(children='US Agriculture Exports (2011)'),
    dcc.Dropdown(id='dropdown', options=[
        {'label': i, 'value': i} for i in df.state.unique()
    ], multi=True, placeholder='Filter by state...'),
    html.Div(id='table-container')
])

@app.callback(
    dash.dependencies.Output('table-container', 'children'),
    [dash.dependencies.Input('dropdown', 'value')])
def display_table(dropdown_value):
    if dropdown_value is None:
        return generate_table(df)

    dff = df[df.state.str.contains('|'.join(dropdown_value))]
    return generate_table(dff)

app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

if __name__ == '__main__':
    app.run_server(debug=True)

This is my attempt so far… That is not working on the second filter option…
I am thinking something more needs to happen around this line area —
dff = df[df.state.str.contains(’|’.join(state_value))] but all my attempts so far not not working…

import dash
import dash_core_components as dcc
import dash_html_components as html

import pandas as pd

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/'
    'c78bf172206ce24f77d6363a2d754b59/raw/'
    'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
    'usa-agricultural-exports-2011.csv')

def generate_table(dataframe, max_rows=50):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

app = dash.Dash()

app.layout = html.Div(children=[
    html.H4(children='US Agriculture Exports (2011)'),
    dcc.Dropdown(id='state', options=[
        {'label': i, 'value': i} for i in df.state.unique()
    ], multi=True, placeholder='Filter by state...'),
	
	dcc.Dropdown(id='beef', options=[
    {'label': i, 'value': i} for i in df.beef.unique()
    ], multi=True, placeholder='Filter by beef...'),
	
    html.Div(id='table-container')
])

@app.callback(
    dash.dependencies.Output('table-container', 'children'),
    [dash.dependencies.Input('state', 'value'),
	dash.dependencies.Input('beef', 'value')])
def display_table(state_value, beef_value):
    if state_value is None:
        return generate_table(df)
    if beef_value is None:
        return generate_table(df)
    dff = df[df.state.str.contains('|'.join(state_value))]
    return generate_table(dff)

#app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

if __name__ == '__main__':
    app.run_server(debug=True)

Hi @newbie2020,

Issue is in display_table code, now you have two inputs and in both input you haven’t provided any default values. Currently both state_value and beef_value are None which implies your both if condition in display_table function are true.

Once you are passing value through state_value, your beef_value is still None due to which your unable to generate modified table.

You need to update your function.

Thank you for you comments @Abhinav . I feel like I am getting somewhat closer, but still hitting different errors.

def display_table(state_value, beef_value):
    if state_value is None and beef_value is None:
        return generate_table(df)
    if state_value is not None and beef_value is None:
        dff = df[df.state.str.contains('|'.join(state_value))]
        return generate_table(dff)
    if beef_value is not None and state_value is None:
        dff = df.loc[df['beef'] == beef_value]
        return generate_table(dff)
    if state_value is not None and beef_value is not None:
        dff = df[df.state.str.contains('|'.join(state_value)) & df.loc[df['beef'] == beef_value]]
        return generate_table(dff)

I am getting:
invalid type comparison - after filtering beef
Must pass DataFrame with boolean values only - after a value has been picked for both filters
Please help!

Hi @newbie2020,

Issue is you are using drop-down button with multi option and it will pass as list to the function. Remove multi option from beef drop down or write a function or program to extract value from list.

# -*- coding: utf-8 -*-
"""
Created on Thu Apr 16 09:41:48 2020

@author: Abhinav
"""

import dash
import dash_core_components as dcc
import dash_html_components as html

import pandas as pd

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/'
    'c78bf172206ce24f77d6363a2d754b59/raw/'
    'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
    'usa-agricultural-exports-2011.csv')

def generate_table(dataframe, max_rows=50):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

app = dash.Dash()

app.layout = html.Div(children=[
    html.H4(children='US Agriculture Exports (2011)'),
    dcc.Dropdown(id='state', options=[
        {'label': i, 'value': i} for i in df.state.unique()
    ], multi=True, placeholder='Filter by state...'),
	
	dcc.Dropdown(id='beef', options=[
    {'label': i, 'value': i} for i in df.beef.unique()
    ], placeholder='Filter by beef...'),
	
    html.Div(id='table-container')
])

@app.callback(
    dash.dependencies.Output('table-container', 'children'),
    [dash.dependencies.Input('state', 'value'),
	dash.dependencies.Input('beef', 'value')])    
def display_table(state_value, beef_value):
    if state_value is None and beef_value is None:
        return generate_table(df)
    if state_value is not None and beef_value is None:
        dff = df[df.state.str.contains('|'.join(state_value))]
        return generate_table(dff)
    if beef_value is not None and state_value is None:
        dff = df.loc[df['beef'] == beef_value]
        return generate_table(dff)
    if state_value is not None and beef_value is not None:
        dff = df[df.state.str.contains('|'.join(state_value))]
        dff = dff.loc[dff['beef'] == beef_value]
        return generate_table(dff)

#app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

if __name__ == '__main__':
    app.run_server()

I have removed multi from beef drop-down now it is working fine.