Dropdown filters - Action


#1

Hi all,

I just started learning the dash framework & would appreciate anyone who could help with my problem.

Problem:

I have a scatter plot between Profit & Sales based on Region in the United States & I’m trying to filter out the plot based on the region (Central, East, West, North). I’m successfully able to get the UI part of it but when I select a value in the drop-down, It doesn’t filter the dashboard - I’m having a hard time figuring out why?

Here’s my code:

import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go


data=pd.read_csv('/Users/harish/Downloads/Superstore.csv',sep=',')
data.head(10)
data.shape
data.columns
data.rename(columns={'Customer Name':'Customer_Name'})
data=data[(data.Sales<1000)]
data.Sales.max()

application=dash.Dash()

application.layout = html.Div([
                html.Label('Multi-Select Dropdown'),
    dcc.Dropdown(
        id='Dropdown',
        options=[
            {'label': 'East', 'value': 'East'},
            {'label':'West','value':'West'},
          {'label':'Central','value':'Central'},
            {'label':'South','value':'South'}
        ],
    
        multi=True,
       

        
    ),
        
    dcc.Graph(
        id='Regionlevel-Profit&Sales',
        figure={
            'data': [
                go.Scatter(
                    x=data[data['Region'] == i]['Sales'],
                    y=data[data['Region'] == i]['Profit'],
                    #text=df[df['Customer_Name'] == i]['Profit'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 5,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in data.Region.unique()
            ],

            'layout': go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    )
   
])

@application.callback(
    dash.dependencies.Output('Dropdown','options'),
    [dash.dependencies.Input('Dropdown', 'value')])
def callback_a(dropdown_value):
    return 'You\'ve selected "{}"'.format(dropdown_value)

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

Any help would be appreciated :slight_smile:


#2

Hi,

Well, you want the callback to update the graph, not the dropdown options. So you should do something like:

@application.callback(
    dash.dependencies.Output('Regionlevel-Profit&Sales','figure'),
    [dash.dependencies.Input('Dropdown', 'value')])
def callback_a(dropdown_value):
    traces = []
    for val in dropdown_value:
        traces.append(
           go.Scatter(
              x=data[data['Region'] == val]['Sales'],
              y=data[data['Region'] == val]['Profit'],
              #text=df[df['Customer_Name'] == i]['Profit'],
              mode='markers',
              opacity=0.7,
              marker={
                  'size': 5,
                  'line': {'width': 0.5, 'color': 'white'}
              },
              name=val
          )

      layout = go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
   
    figure = {'data': traces, 'layout': layout}
    return figure 

#3

Hi Gwen,

Thanks for your response! Im just wondering if my code is right, because each variable Region, Sales, & profit are separate columns in the data frame.

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go


data=pd.read_csv('/Users/harish/Downloads/Superstore.csv',sep=',')
data.head(10)
data.shape
data.columns
data.rename(columns={'Customer Name':'Customer_Name'})
data=data[(data.Sales<1000)]
data.Sales.max()

application=dash.Dash()

application.layout = html.Div([
                html.Label('Multi-Select Dropdown'),
    dcc.Dropdown(
        id='Dropdown',
        options=[
            {'label': 'East', 'value': 'East'},
            {'label':'West','value':'West'},
          {'label':'Central','value':'Central'},
            {'label':'South','value':'South'}
        ],
    
        multi=True,
       

        
    ),
        
    dcc.Graph(
        id='Regionlevel-Profit&Sales',
        figure={
            'data': [
                go.Scatter(
                    x=data[data['Region'] == i]['Sales'],
                    y=data[data['Region'] == i]['Profit'],
                    #text=df[df['Customer_Name'] == i]['Profit'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 5,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in data.Region.unique()
            ],

            'layout': go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    )
   
])

@application.callback(
    dash.dependencies.Output('Regionlevel-Profit&Sales','figure'),
    [dash.dependencies.Input('Dropdown', 'value')])
def callback_a(dropdown_value):
    traces = []
    for val in dropdown_value:
        traces.append(
           go.Scatter(
              x=data[data['Region'] == val]['Sales'],
              y=data[data['Region'] == val]['Profit'],
              #text=df[df['Customer_Name'] == i]['Profit'],
              mode='markers',
              opacity=0.7,
              marker={
                  'size': 5,
                  'line': {'width': 0.5, 'color': 'white'}
              },
              name=val
          ),

      layout=go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            ))
   
    figure = {'data': traces, 'layout': layout}
    return figure 

if __name__ == '__main__':
    application.run_server()```

The filters arent working even now :confused:

#4

It’s not really idiomatic for pandas, but it should be ok. Pandas prefers the syntax:

x = data.loc[data['Region']==val, 'Sales']

rather than

x = data[data['Region']==val]['Sales']

But it should work. What are the values in data['Region']? They should be one of East, West, Central or South. If you want, you can try to debug your code by adding a

print(val) # or whatever you want to see

at the beginning of the loop.

Btw, the following lines are useless as they do not change your dataframe neither print anything.

data.head(10)
data.shape
data.columns
data.rename(columns={'Customer Name':'Customer_Name'})
data.Sales.max()

#5

Hey Gwen,

I’m getting few error messages when i run the script & the dash is able to create a proper scatter plot with drop-down categories (East,west,North,South) but its just that it doesn’t update the graph whenever I select an option from the drop-down

.

Have attached the SC for the same.

Thanks.


#6

Ok. There are 2 errors apparently:

  1. TypeError : 'NoneType' object is not iterable
    I guess that as there is no default value for the dropdown (i.e. dropdown_value is None when nothing is selected), the graph fails. Just put
dcc.Dropdown(
    id='Dropdown',
    options=[
        {'label': 'East', 'value': 'East'},
        {'label':'West','value':'West'},
        {'label':'Central','value':'Central'},
        {'label':'South','value':'South'}
    ],
    value=['East'], # <- this line add default value
    multi=True,        
)
  1. Second error: KeyError: the label [Region] is not in [index]. This one indicate that there is no ‘Region’ column in the dataframe. Can you show the result of data.head()?

However, you know that you can click on a legend label to plot/unplot it? Just click on “East” and all the dot with the “East” label will disappear.


#7

Hi Gwen,

I have attached the screenshot of my data frame, and please find my updated code below:
Shouldn’t the graph get updated as per drop down selections? It’s not effective yet.

import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go




data=pd.read_csv('/Users/harish/Downloads/Superstore.csv',sep=',')
data.head(10)
data.shape
data.columns
data.rename(columns={'Customer Name':'Customer_Name'})
data=data[(data.Sales<1000)]
data.Sales.max()

application=dash.Dash()

application.layout = html.Div([
                html.Label('Multi-Select Dropdown'),
    dcc.Dropdown(
        id='Dropdown',
        options=[
            {'label': 'East', 'value': 'East'},
            {'label':'West','value':'West'},
          {'label':'Central','value':'Central'},
            {'label':'South','value':'South'}
        ],
    
        multi=True,
        value='East'
       

        
    ),
        
    dcc.Graph(
        id='Regionlevel-Profit&Sales',
        figure={
            'data': [
                go.Scatter(
                    x = data.loc[data['Region']==i, 'Sales'],
                    y=data.loc[data['Region'] == i,'Profit'],
                    #text=df[df['Customer_Name'] == i]['Profit'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 5,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                ) for i in data.Region.unique()
            ],

            'layout': go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    )
   
])

@application.callback(
    dash.dependencies.Output('Regionlevel-Profit&Sales','figure'),
    [dash.dependencies.Input('Dropdown', 'value')])
def update_graph(dropdown_value):
    traces = []
    for val in dropdown_value:
        traces.append(
           go.Scatter(
              x=data.loc[data['Region'] == val,'Sales'],
              y=data.loc[data['Region'] == val,'Profit'],
              #text=df[df['Customer_Name'] == i]['Profit'],
              mode='markers',
              opacity=0.7,
              marker={
                  'size': 5,
                  'line': {'width': 0.5, 'color': 'white'}
              },
              name=val
          ),

      layout=go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            ))
   
    figure = {'data': traces, 'layout': layout}
    return figure 

if __name__ == '__main__':
    application.run_server()``` 

THanks for your kind help.![14%20AM|690x431](upload://ikCaWJ2jPfECrwBC2R2byhSnWXO.png)

#8

Well, I can’t see where the bug can be. As a side note, there is a mistake here:

value='East'

should be a list:

value=['East']

Try to print the value of data['Region'] in your loop to debug it. For instance like:

for val in dropdown_value:
   print(data['Region'].head())

#9

Yup, I printed out the values of region and have attached the screen shot. It’s working fine but i have no idea why the graph doesn’t get updated based on the drop down selection.


#10

Ok I got it… This is a typo:

def update_graph(dropdown_value):
    traces = []
    for val in dropdown_value:
        traces.append(
           go.Scatter(
              x=data.loc[data['Region'] == val,'Sales'],
              y=data.loc[data['Region'] == val,'Profit'],
              #text=df[df['Customer_Name'] == i]['Profit'],
              mode='markers',
              opacity=0.7,
              marker={
                  'size': 5,
                  'line': {'width': 0.5, 'color': 'white'}
              },
              name=val
          ), # <- here is the typo. you close 'go.Scatter' but not the 'traces.append'

      layout=go.Layout(
                xaxis={'title': 'Sales'},
                yaxis={'title': 'Profit'},
                margin={'l': 50, 'b': 30, 't': 10, 'r': 0},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )) # <- and here, only one parenthesis is needed. The 'layout' should not be in the 'traces' variable

Please refer to my previous post to see the correct syntax.

You can see the error by checking the error message:

TypeError: append() takes no keyword arguments

as you try to add ‘layout=…’ in it.


#11

Hey Gwen,

It’s working now. Like you said, a small typo from my side. Appreciate your help!

Thanks,

Harish Krishnan