ScottScroggins commited on
Commit
28d3ad3
·
verified ·
1 Parent(s): 24222b3

Add bar chart

Browse files
Files changed (1) hide show
  1. app.py +96 -7
app.py CHANGED
@@ -1,6 +1,14 @@
1
  import panel as pn
2
  import pandas as pd
3
- pn.extension()
 
 
 
 
 
 
 
 
4
 
5
  ### Part 0: Getting data
6
 
@@ -23,7 +31,8 @@ def get_data():
23
  df['county_fips'] = df['county_fips'].astype(str).str.zfill(5)
24
 
25
  df.columns = ['state_abbr','FIPS','county','family','housing','food','transportation','healthcare',
26
- 'other_necessities','childcare','taxes','total','median_family_income','num_counties_in_st','st_cost_rank','st_med_aff_rank','st_income_rank']
 
27
 
28
  #Some counties share names across states; adding their state code makes them unique.
29
  df['county_state'] = df.county + ', ' + df.state_abbr
@@ -35,9 +44,10 @@ def get_data():
35
 
36
  df = get_data()
37
 
 
38
  ### Part 1: Find and display model budget
39
 
40
- #Function to represent data in US dollars
41
  def dol(value,df,row=0):
42
  return '${:0,}'.format(df[value][row])
43
 
@@ -46,7 +56,7 @@ def calculate_model(user_county,user_parents,user_children):
46
  user_family = f'{user_parents}p{user_children}c'
47
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
48
  return (
49
- f'Moderately frugal families of {user_parents} {"adult" if user_parents == 1 else "adults"} and {user_children} {"child" if user_children == 1 else "children"} living in {user_county} '
50
  'tend to have a monthly family budget similar to the following:\n'
51
  f'\nHousing: {dol("housing",user_df)}'
52
  f'\nFood: {dol("food",user_df)}'
@@ -66,7 +76,7 @@ user_county = pn.widgets.AutocompleteInput(
66
  case_sensitive=False,
67
  placeholder='Input county name')
68
 
69
- adult_title = pn.pane.Markdown('Number of adults in household:')
70
  user_parents = pn.widgets.RadioButtonGroup(
71
  name='Number of adults', options=['1', '2'], button_type='default', margin=(12,0,0,0))
72
 
@@ -102,8 +112,10 @@ def calculate_percentage(user_value,column,df):
102
 
103
  #Function that takes user budget input and returns how it compares to model.
104
  def calculate_budget_percentage(user_county,user_parents,user_children,user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes):
 
105
  user_family = f'{user_parents}p{user_children}c'
106
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
 
107
  income_p = calculate_percentage(user_income,'median_monthly_family_income',user_df)
108
  housing_p = calculate_percentage(user_housing,'housing',user_df)
109
  food_p = calculate_percentage(user_food,'food',user_df)
@@ -158,11 +170,13 @@ def budget_result(clicked):
158
 
159
  budget_result = pn.pane.Markdown(pn.bind(budget_result,budget_submit))
160
 
 
161
  ### Part 3: Calculate and display most afforable counties and budgets
162
 
163
  #Function to take user constraints, find most affordable counties, and calculate budgets
164
  def calculate_comparison(user_county,user_parents,user_children,user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes,
165
  bring_income,income_cap,income_cap_amount,state_restriction,states_allowed,result_count):
 
166
  user_family = f'{user_parents}p{user_children}c'
167
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
168
  income_p = calculate_percentage(user_income,'median_monthly_family_income',user_df)
@@ -173,6 +187,7 @@ def calculate_comparison(user_county,user_parents,user_children,user_income,user
173
  childcare_p = calculate_percentage(user_childcare,'childcare',user_df)
174
  other_p = calculate_percentage(user_other,'other_necessities',user_df)
175
  taxes_p = calculate_percentage(user_taxes,'taxes',user_df)
 
176
  new_df = df.loc[(df.family == user_family)].reset_index(drop=True)
177
  if bring_income:
178
  new_df.median_monthly_family_income = user_income
@@ -256,7 +271,75 @@ def comparison_result(clicked):
256
 
257
  comparison_result = pn.pane.Markdown(pn.bind(comparison_result,comparison_submit))
258
 
259
- ### Part 4: Templating
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
  template = pn.template.BootstrapTemplate(title='Affordable County Locator')
262
 
@@ -288,8 +371,14 @@ main3 = pn.Card(
288
  styles={'background': 'WhiteSmoke'},
289
  max_height = 300
290
  )
 
 
 
 
 
 
291
  template.main.append(
292
- pn.Column(main1,main2,main3)
293
  )
294
 
295
  template.servable();
 
1
  import panel as pn
2
  import pandas as pd
3
+ import matplotlib
4
+ from matplotlib.figure import Figure
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+
9
+ matplotlib.use("agg")
10
+
11
+ pn.extension('ipywidgets')
12
 
13
  ### Part 0: Getting data
14
 
 
31
  df['county_fips'] = df['county_fips'].astype(str).str.zfill(5)
32
 
33
  df.columns = ['state_abbr','FIPS','county','family','housing','food','transportation','healthcare',
34
+ 'other_necessities','childcare','taxes','total','median_family_income',
35
+ 'num_counties_in_st','st_cost_rank','st_med_aff_rank','st_income_rank']
36
 
37
  #Some counties share names across states; adding their state code makes them unique.
38
  df['county_state'] = df.county + ', ' + df.state_abbr
 
44
 
45
  df = get_data()
46
 
47
+
48
  ### Part 1: Find and display model budget
49
 
50
+ #Helper function to represent data in US dollars
51
  def dol(value,df,row=0):
52
  return '${:0,}'.format(df[value][row])
53
 
 
56
  user_family = f'{user_parents}p{user_children}c'
57
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
58
  return (
59
+ f'Moderately frugal families of {user_parents} {"adult" if user_parents == "1" else "adults"} and {user_children} {"child" if user_children == 1 else "children"} living in {user_county} '
60
  'tend to have a monthly family budget similar to the following:\n'
61
  f'\nHousing: {dol("housing",user_df)}'
62
  f'\nFood: {dol("food",user_df)}'
 
76
  case_sensitive=False,
77
  placeholder='Input county name')
78
 
79
+ adult_title = pn.pane.Markdown('Number of adults in household:') #Radio buttons don't have their name displayed as a title, so I add it here
80
  user_parents = pn.widgets.RadioButtonGroup(
81
  name='Number of adults', options=['1', '2'], button_type='default', margin=(12,0,0,0))
82
 
 
112
 
113
  #Function that takes user budget input and returns how it compares to model.
114
  def calculate_budget_percentage(user_county,user_parents,user_children,user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes):
115
+ #Repeated code. Could potentially be avoided with more binding, but that wouldn't change performance
116
  user_family = f'{user_parents}p{user_children}c'
117
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
118
+ #New code
119
  income_p = calculate_percentage(user_income,'median_monthly_family_income',user_df)
120
  housing_p = calculate_percentage(user_housing,'housing',user_df)
121
  food_p = calculate_percentage(user_food,'food',user_df)
 
170
 
171
  budget_result = pn.pane.Markdown(pn.bind(budget_result,budget_submit))
172
 
173
+
174
  ### Part 3: Calculate and display most afforable counties and budgets
175
 
176
  #Function to take user constraints, find most affordable counties, and calculate budgets
177
  def calculate_comparison(user_county,user_parents,user_children,user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes,
178
  bring_income,income_cap,income_cap_amount,state_restriction,states_allowed,result_count):
179
+ #Repeated code:
180
  user_family = f'{user_parents}p{user_children}c'
181
  user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
182
  income_p = calculate_percentage(user_income,'median_monthly_family_income',user_df)
 
187
  childcare_p = calculate_percentage(user_childcare,'childcare',user_df)
188
  other_p = calculate_percentage(user_other,'other_necessities',user_df)
189
  taxes_p = calculate_percentage(user_taxes,'taxes',user_df)
190
+ #New code:
191
  new_df = df.loc[(df.family == user_family)].reset_index(drop=True)
192
  if bring_income:
193
  new_df.median_monthly_family_income = user_income
 
271
 
272
  comparison_result = pn.pane.Markdown(pn.bind(comparison_result,comparison_submit))
273
 
274
+
275
+ ### Part 4: Bar chart of results
276
+ def calculate_bar(user_county,user_parents,user_children,user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes,
277
+ bring_income,income_cap,income_cap_amount,state_restriction,states_allowed,result_count):
278
+ #Repeated code:
279
+ user_family = f'{user_parents}p{user_children}c'
280
+ user_df = df.loc[(df.county_state == user_county) & (df.family == user_family)].reset_index(drop=True)
281
+ income_p = calculate_percentage(user_income,'median_monthly_family_income',user_df)
282
+ housing_p = calculate_percentage(user_housing,'housing',user_df)
283
+ food_p = calculate_percentage(user_food,'food',user_df)
284
+ transportation_p = calculate_percentage(user_transportation,'transportation',user_df)
285
+ healthcare_p = calculate_percentage(user_healthcare,'healthcare',user_df)
286
+ childcare_p = calculate_percentage(user_childcare,'childcare',user_df)
287
+ other_p = calculate_percentage(user_other,'other_necessities',user_df)
288
+ taxes_p = calculate_percentage(user_taxes,'taxes',user_df)
289
+ new_df = df.loc[(df.family == user_family)].reset_index(drop=True)
290
+ if bring_income:
291
+ new_df.median_monthly_family_income = user_income
292
+ else:
293
+ new_df.median_monthly_family_income = new_df.median_monthly_family_income.mul(income_p).round(0).astype('int64')
294
+ new_df['median_monthly_family_income_uncapped'] = new_df.median_monthly_family_income
295
+ if income_cap:
296
+ new_df.median_monthly_family_income.clip(upper=income_cap_amount,inplace=True)
297
+ if state_restriction:
298
+ new_df = new_df.loc[(new_df.state_abbr.isin(states_allowed))].reset_index(drop=True)
299
+ new_df.housing = new_df.housing.mul(housing_p).round(0).astype('int64')
300
+ new_df.food = new_df.food.mul(food_p).round(0).astype('int64')
301
+ new_df.transportation = new_df.transportation.mul(transportation_p).round(0).astype('int64')
302
+ new_df.healthcare = new_df.healthcare.mul(healthcare_p).round(0).astype('int64')
303
+ new_df.other_necessities = new_df.other_necessities.mul(other_p).round(0).astype('int64')
304
+ new_df.childcare = new_df.childcare.mul(childcare_p).round(0).astype('int64')
305
+ new_df.taxes = new_df.taxes.mul(taxes_p).round(0).astype('int64')
306
+ new_df.total = new_df.housing + new_df.food + new_df.transportation + new_df.healthcare + new_df.other_necessities + new_df.childcare + new_df.taxes
307
+ new_df.remaining_money = new_df.median_monthly_family_income - new_df.total
308
+ new_df = new_df.sort_values('remaining_money',ascending=False).reset_index(drop=True)
309
+ #New code:
310
+ new_df = new_df[:result_count]
311
+ fig = Figure(figsize=(result_count,4))
312
+ ax = fig.add_subplot(111)
313
+ ax = new_df.median_monthly_family_income.plot.bar(width=0.4, position=1, ax=ax)
314
+ ax = new_df[['housing', 'food','transportation','healthcare','childcare','other_necessities','taxes']].plot.bar(stacked=True, width=0.4, position=0, ax=ax, alpha=0.7)
315
+ ax.legend(labels=['Income','Housing','Food','Transportation','Healthcare','Childcare','Other','Taxes'],loc="upper right",bbox_to_anchor=(1 + 2/result_count, 1))
316
+ ax.set_xticks(ticks=np.arange(len(new_df)),labels=new_df.county_state.values)
317
+ ax.yaxis.set_major_formatter('${x:,.0f}')
318
+ ax.yaxis.grid(linestyle='--',alpha=.4)
319
+ ax.set_xlim([-.5, len(new_df)-.5])
320
+ plt.close(fig)
321
+ return fig
322
+
323
+ def nothing_fig():
324
+ fig = Figure(figsize=(5,4))
325
+ ax = fig.add_subplot(111)
326
+ return fig
327
+
328
+ bar = pn.bind(calculate_bar, user_county,user_parents,user_children,
329
+ user_income,user_housing,user_food,user_transportation,user_healthcare,user_childcare,user_other,user_taxes,
330
+ bring_income,income_cap,income_cap_amount,state_restriction,states_allowed,result_count)
331
+
332
+ def bar_result(clicked):
333
+ if clicked:
334
+ if user_county.value == '':
335
+ return nothing_fig()
336
+ return bar()
337
+ return nothing_fig()
338
+
339
+ bar_result = pn.pane.Matplotlib(pn.bind(bar_result,comparison_submit), dpi=144, tight=True)
340
+
341
+
342
+ ### Part 5: Templating
343
 
344
  template = pn.template.BootstrapTemplate(title='Affordable County Locator')
345
 
 
371
  styles={'background': 'WhiteSmoke'},
372
  max_height = 300
373
  )
374
+ main4 = pn.Card(
375
+ bar_result,
376
+ title='Most Affordable Counties, bar chart',
377
+ styles={'background':'WhiteSmoke'},
378
+ collapsed=True
379
+ )
380
  template.main.append(
381
+ pn.Column(main1,main2,main3,main4)
382
  )
383
 
384
  template.servable();