2
votes

I am trying to create a bar graph that updates from a multi-select drop-down menu on Dash but when I select an area code to graph, nothing changes.

My dataframe consists of about 11 rows with 4 columns:

  Zip Code  Area Name     percent no internet   Mean Income Past 12 Months
0   38126   South Forum   0.8308                26346
1   38106   South Memphis 0.8223                31403
2   38108   Hollywood     0.7356                31278

Here is the code for the callback:

@app.callback(
    dash.dependencies.Output('graph1', 'figure'),
    [dash.dependencies.Input('demo-dropdown', 'value')])
def update_image_src(selector):
    data = []
    filtered_data = df[df['Zip Code'] == zip_code]
    for zip_code in selector:
        data.append(dict(
            x=filtered_data['Area Name'][0],
            y=filtered_data['percent no internet'][0],
            type='bar',
            name=zip_code))
    figure = {
        'data': data,
        'layout': {
            'title': 'Percent of homes lacking broadband internet',
            'xaxis' : dict(
                title=data[0],
                titlefont=dict(
                family='Courier New, monospace',
                size=20,
                color='#7f7f7f'
            )),
            'yaxis' : dict(
                title='% No Internet',
                titlefont=dict(
                family='Helvetica, monospace',
                size=20,
                color='#7f7f7f'
            ))
        }
    }
    return figure
1
Should filtered_data = df[df['Zip Code'] == zip_code] be in the loop for zip_code in selector and not before? - Ben.T
I tried this and the graph updates and recognizes the change by adding in the axis titles, but the data itself still doesnt actually plot. It is just an empty graph with titles. @Ben.T - Zach Cornelison
I see, can you post the dataframe as text in the question (you can click on edit, at the bottom of the question), I can't see the image. The problem may come from the way you get the data from filtered_data, indeed, doing this filtered_data['Area Name'][0] means you get the column 'Area Name' and the index with the label 0 not the position 0, so without the being able to see the data I'm not sure, but I guess your index are different labels? - Ben.T
@Ben.T I added the first 3 rows in the question! - Zach Cornelison
@Ben.T I also tried storing the data needed as a list and feeding it in that way like so-- l = [], x = df[df['Zip Code'] == '38126']['Zip Code'][0], l.append(x), l Since I currently have the graphs working by manually creating a dictionary with a subset of the data. It works with this, but I obviously want to pull from my dataframe, which is why I tried this method since feeding the data in as a list was what I thought would be needed, but the above method also did not work :/ - Zach Cornelison

1 Answers

1
votes

IIUC, here is a code that seem to do what you want. The point I can address with your original code is that first you don't define the type of graph, second instead of iterating over the selector, you can use isin to get all at once. Hope it will help you

import dash
from dash.dependencies import Output,Input
import dash_core_components as dcc
import dash_html_components as html

# the few rows of your question
import pandas as pd
df = pd.DataFrame( {'Zip Code': {0: 38126, 1: 38106, 2: 38108},
                    'Area Name': {0: 'South Forum', 1: 'South Memphis', 2: 'Hollywood'},
                    'percent no internet': {0: 0.8308, 1: 0.8223, 2: 0.7356},
                    'Mean Income Past 12 Months': {0: 26346, 1: 31403, 2: 31278}})   
# main app
app = dash.Dash(__name__)
app.layout = html.Div(children=[
    dcc.Dropdown(
        id='demo-dropdown', 
        options=[
            {'label': 38126, 'value': 38126},
            {'label': 38106, 'value': 38106},
            {'label': 38108, 'value': 38108}
        ],
        value=[38126, 38106],
        multi=True
    ),
    dcc.Graph(id='graph1'),
])

@app.callback(
    dash.dependencies.Output('graph1', 'figure'),
    [dash.dependencies.Input('demo-dropdown', 'value')])
def update_image_src(selector):
    # instead of iterating, use isin to select all the zipcode from the dropdown
    filtered_data = df.loc[ df['Zip Code'].isin(selector), 
                            ['Area Name', 'percent no internet']]

    figure = {
        # in figure, see how the data is defined
        'data': [{'x': filtered_data['Area Name'], 
                  'y': filtered_data['percent no internet'], 
                  'type': 'bar'}
        ],
        'layout': {
            'title': 'Percent of homes lacking broadband internet',
            'xaxis' : dict(
                title='Area Name', #change this, I'm not sure what you wanted
                titlefont=dict(
                    family='Courier New, monospace',
                    size=20,
                    color='#7f7f7f'
                )
            ),
            'yaxis' : dict(
                title='% No Internet',
                titlefont=dict(
                    family='Helvetica, monospace',
                    size=20,
                    color='#7f7f7f'
                )
            )
        }
    }
    return figure


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

EDIT: to get different colors and the legend, then replace in the dictionnary figure with this:

figure = {
        # in figure, see how is define the data
        'data': [{'x': [area_name], 
                  'y': [percent], 
                  'type': 'bar', 
                  'name': area_name}
                  for area_name, percent in filtered_data.to_numpy()
        ],
...