Py.Cafe

iisakkirotko/

dash-county-investment-analysis

County Investment Analysis with Dash

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# check out https://dash.plotly.com/ for documentation
# And check out https://py.cafe/maartenbreddels for more examples
from dash import Dash, Input, Output, callback, dcc, html
import pandas as pd
import plotly.express as px

app = Dash(__name__)
md = """
# Dash demo

See [The dash examples index](https://dash-example-index.herokuapp.com/) for more examples.
"""
#dtype = str is the lazy way of making sure the county fips are read ok
df = pd.read_csv('rural_download.csv', dtype=str)
df['Investment Dollars'] = df['Investment Dollars'].str.replace(',', '').astype(float)
index_cols = ['County', 'County FIPS', 'State Name']
county_investments = df.groupby(index_cols)['Investment Dollars'].sum().reset_index()
county_investments.sort_values('Investment Dollars', inplace = True)
# this fips can get cast as a number
county_investments['County FIPS'] = county_investments['County FIPS'].astype(str)
# bring in county level population estimates
pop = pd.read_csv('population_fips.csv', dtype=str)
pop['POP_ESTIMATE_2023'] = pop['POP_ESTIMATE_2023'].str.replace(',', '').astype(float)

ci_pop = pd.merge(county_investments, pop[['County FIPS', 'POP_ESTIMATE_2023']], 
                                  on='County FIPS', how='left')
ci_pop['Dollars / Capita'] = ci_pop['Investment Dollars'] / ci_pop['POP_ESTIMATE_2023']
ci_pop['Dollars / Capita'] = ci_pop['Dollars / Capita'].round(1)
# get county level investments per program area
county_program = pd.pivot_table(df, index=index_cols, 
               columns='Program Area', values='Investment Dollars').reset_index()
county_program.fillna(0, inplace=True)
ci_pop = pd.merge(ci_pop, county_program, on=index_cols, how='left')

fig = px.choropleth(
    ci_pop,
    geojson="https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json",
                    locations='County FIPS',
                    color='Dollars / Capita',
                    color_continuous_scale="Viridis",
                    scope="usa",
                    labels={'Investment Dollars / Capita': 'Investment ($) / Capita'},
                    hover_data=['County', 'Investment Dollars'],
                    title='Investment Dollars / Capita per County')

features =  set(ci_pop.columns).difference(set(index_cols))                  
app.layout = html.Div([
    html.H1("Choropleth Map with Dash"),
    dcc.Dropdown(
        id='column-dropdown',
        options=[{'label': col, 'value': col} for col in ci_pop.columns if col not in index_cols],
        value='Dollars / Capita'  # default value
    ),
    dcc.RangeSlider(
        id='value-slider',
        min=ci_pop['Dollars / Capita'].min(),
        max=ci_pop['Dollars / Capita'].max(),
        value=[ci_pop['Dollars / Capita'].min()],
    ),
    dcc.Graph(id='choropleth-map', figure=fig)
])


# Callback to update the slider based on the selected column
@app.callback(
    Output('value-slider', 'min'),
    Output('value-slider', 'max'),
    Output('value-slider', 'value'),
    Input('column-dropdown', 'value')
)
def update_slider(column):
    min_val = ci_pop[column].min()
    max_val = ci_pop[column].max()
    return min_val, max_val, [min_val, max_val]


# Callback to update the map based on the selected column
@app.callback(
    Output('choropleth-map', 'figure'),
    [Input('column-dropdown', 'value'), Input('value-slider', 'value')]
)
def update_choropleth_column(selected_column, selected_range):
    df = ci_pop[(ci_pop[selected_column] >= selected_range[0]) & (ci_pop[selected_column] <= selected_range[1])]
    fig = px.choropleth(
        df,
        geojson="https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json",
        locations='County FIPS',
        color=selected_column,
        color_continuous_scale="Viridis",
        scope="usa",
        labels={'Investment Dollars / Capita': 'Investment ($) / Capita'},
        hover_data={'County': True, 'Investment Dollars': ':,', 'Dollars / Capita': ':$'}
    )
    return fig

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