diff --git a/dash/.gitignore b/dash/.gitignore
new file mode 100644
index 0000000..6b52afc
--- /dev/null
+++ b/dash/.gitignore
@@ -0,0 +1,4 @@
+venv
+*.pyc
+.env
+.DS_Store
\ No newline at end of file
diff --git a/dash/Procfile.txt b/dash/Procfile.txt
new file mode 100644
index 0000000..e828b2c
--- /dev/null
+++ b/dash/Procfile.txt
@@ -0,0 +1 @@
+web: gunicorn funding:server
\ No newline at end of file
diff --git a/funding.py b/funding.py
index f85efbf..eced0fc 100644
--- a/funding.py
+++ b/funding.py
@@ -9,16 +9,52 @@
import dash_bootstrap_components as dbc
import microdf as mdf
-person = pd.read_csv('https://github.com/ngpsu22/Funding/raw/main/person_ubi_funding.csv')
BLUE = '#1976D2'
+person = pd.read_csv('https://raw.githubusercontent.com/ngpsu22/Funding/main/person_ubi_funding%20(7).csv')
+
+# Calculate orginal poverty
population = person.asecwt.sum()
+original_total_poor = (person.original_poor * person.asecwt).sum()
+original_poverty_rate = (original_total_poor / population) * 100
+
+spmu = person.drop_duplicates(subset=['spmfamunit'])
+spmu['original_poverty_gap'] = person.spmthresh - person.spmtotres
+original_poverty_gap = (((spmu.original_poor * spmu.original_poverty_gap *
+ spmu.asecwth).sum()))
+
+# Calculate original child poverty
+child_population = (person.child * person.asecwt).sum()
+original_child_poor = (person.child * person.original_poor * person.asecwt).sum()
+original_child_poverty_rate = (original_child_poor / child_population) * 100
+
+# Calculate original adult poverty
+adult_population = (person.adult * person.asecwt).sum()
+original_adult_poor = (person.adult * person.original_poor * person.asecwt).sum()
+original_adult_poverty_rate = (original_adult_poor / adult_population) * 100
+
+# Calculate original pwb poverty
+pwb_population = (person.pwb * person.asecwt).sum()
+original_pwb_poor = (person.pwb * person.original_poor * person.asecwt).sum()
+original_pwb_poverty_rate = (original_pwb_poor / pwb_population) * 100
+
+# Calculate original White poverty
+white_population = (person.white_non_hispanic * person.asecwt).sum()
+original_white_poor = (person.white_non_hispanic * person.original_poor * person.asecwt).sum()
+original_white_poverty_rate = (original_white_poor / white_population) * 100
-og_total_poor = (person.original_poor * person.asecwt).sum()
-original_poverty_rate = (og_total_poor / population) * 100
+# Calculate original Black poverty
+black_population = (person.black * person.asecwt).sum()
+original_black_poor = (person.black * person.original_poor * person.asecwt).sum()
+original_black_poverty_rate = (original_black_poor / black_population) * 100
-person['spm_resources_per_person'] = person.spmtotres / person.pernum
+# Calculate original Hispanic poverty
+hispanic_population = (person.hispanic * person.asecwt).sum()
+original_hispanic_poor = (person.hispanic * person.original_poor * person.asecwt).sum()
+original_hispanic_poverty_rate = (original_hispanic_poor / hispanic_population) * 100
+
+# Caluclate original gini
gini = (mdf.gini(person, 'spm_resources_per_person' , 'asecwt'))
card_main = dbc.Card(
@@ -35,12 +71,11 @@
'fontSize':20}),
dcc.Checklist(id='my-checklist',
options=[
- {'label': ' Social Security', 'value': 'ss'},
- {'label': ' Supplemental Security Income (SSI)', 'value': 'ssi'},
- {'label': ' Unemployment', 'value': 'unemp'},
- {'label': ' Earned Income Tax Credit', 'value': 'eitc'},
{'label': ' Child Tax Credit', 'value': 'ctc'},
+ {'label': ' Supplemental Security Income (SSI)', 'value': 'ssi'},
{'label': ' Snap (food stamps)', 'value': 'snap'},
+ {'label': ' Earned Income Tax Credit', 'value': 'eitc'},
+ {'label': ' Unemployment', 'value': 'unemp'},
{'label': ' Energy Subsidy (LIHEAP)', 'value': 'energy'}
],
@@ -48,59 +83,46 @@
labelStyle={'display': 'block'}
),
html.Br(),
- html.Label(['Flat Tax on AGI'],style={'font-weight': 'bold',
+ html.Label(['Repeal current taxes:'],style={'font-weight': 'bold',
"text-align": "center",
"color":"white",
'fontSize':20}),
- dcc.Slider(
- id='agi-slider',
- min=0,
- max=10,
- step=1,
- value=0,
- marks={0: {'label': '0%', 'style': {'color': '#F8F8FF'}},
- 1: {'label': '1%', 'style': {'color': '#F8F8FF'}},
- 2: {'label': '2%', 'style': {'color': '#F8F8FF'}},
- 3: {'label': '3%', 'style': {'color': '#F8F8FF'}},
- 4: {'label': '4%', 'style': {'color': '#F8F8FF'}},
- 5: {'label': '5%', 'style': {'color': '#F8F8FF'}},
- 6: {'label': '6%', 'style': {'color': '#F8F8FF'}},
- 7: {'label': '7%', 'style': {'color': '#F8F8FF'}},
- 8: {'label': '8%', 'style': {'color': '#F8F8FF'}},
- 9: {'label': '9%', 'style': {'color': '#F8F8FF'}},
- 10: {'label': '10%', 'style': {'color': '#F8F8FF'}},
- }
- ),
- html.Div(id='slider-output-container'),
- html.Br(),
- html.Label(['Flat Tax on Taxable Income'],style={'font-weight': 'bold',
+ html.Br(),
+ dcc.Checklist(id='my-checklist2',
+ options=[
+ {'label': 'Income taxes', 'value': 'income_taxes'},
+ {'label': 'Employee side payroll', 'value': 'fica'},
+ ],
+ value=[],
+ labelStyle={'display': 'block'}
+ ),
+
+ html.Br(),
+
+ html.Label(['Add flat tax on AGI:'],style={'font-weight': 'bold',
"text-align": "center",
"color":"white",
'fontSize':20}),
dcc.Slider(
- id='taxable-slider',
+ id='agi-slider',
min=0,
- max=10,
+ max=50,
step=1,
value=0,
+ tooltip = { 'always_visible': True, 'placement': 'bottom'},
marks={0: {'label': '0%', 'style': {'color': '#F8F8FF'}},
- 1: {'label': '1%', 'style': {'color': '#F8F8FF'}},
- 2: {'label': '2%', 'style': {'color': '#F8F8FF'}},
- 3: {'label': '3%', 'style': {'color': '#F8F8FF'}},
- 4: {'label': '4%', 'style': {'color': '#F8F8FF'}},
- 5: {'label': '5%', 'style': {'color': '#F8F8FF'}},
- 6: {'label': '6%', 'style': {'color': '#F8F8FF'}},
- 7: {'label': '7%', 'style': {'color': '#F8F8FF'}},
- 8: {'label': '8%', 'style': {'color': '#F8F8FF'}},
- 9: {'label': '9%', 'style': {'color': '#F8F8FF'}},
10: {'label': '10%', 'style': {'color': '#F8F8FF'}},
+ 20: {'label': '20%', 'style': {'color': '#F8F8FF'}},
+ 30: {'label': '30%', 'style': {'color': '#F8F8FF'}},
+ 40: {'label': '40%', 'style': {'color': '#F8F8FF'}},
+ 50: {'label': '50%', 'style': {'color': '#F8F8FF'}},
}
),
- html.Div(id='slider-output-container2'),
-
+ html.Div(id='slider-output-container'),
+ html.Br(),
]
),
],
@@ -113,6 +135,12 @@
figure={}), body=True, color="info",
)
+card_graph2 = dbc.Card(
+ dcc.Graph(id='my-graph2',
+ figure={}), body=True, color="info",
+)
+
+
app = dash.Dash(__name__,
external_stylesheets=[dbc.themes.FLATLY])
@@ -120,6 +148,11 @@
app.layout = html.Div([
# Row 1 - header
+ dbc.Row(
+ [
+ dbc.Col(html.A([
+ html.Img(src="https://blog.ubicenter.org/_static/ubi_center_logo_wide_blue.png", style={'height':'60%', 'width':'60%'})
+ ], href='https://www.ubicenter.org/'),width=2)]),
html.Br(),
dbc.Row(
[
@@ -142,19 +175,27 @@
dbc.Row([
dbc.Col(card_main, width=3),
dbc.Col(card_graph, width=6.8)],justify="around"),
+ html.Br(),
+ html.Br(),
+ dbc.Row(
+ dbc.Col(card_graph2, width={'size': 6, 'offset': 5}), justify="around"),
+ html.Br(),
+ html.Br(),
+ html.Br(),
+ html.Br(),
])
@app.callback(
Output(component_id='my-graph', component_property='figure'),
+ Output(component_id='my-graph2', component_property='figure'),
Input(component_id='agi-slider', component_property='value'),
- Input(component_id='taxable-slider', component_property='value'),
- Input(component_id='my-checklist', component_property='value')
+ Input(component_id='my-checklist', component_property='value'),
+ Input(component_id='my-checklist2', component_property='value')
)
-def ubi(agi_tax, taxable_tax, benefits):
-
+def ubi(agi_tax, benefits, taxes):
target_persons = person.copy(deep=True)
- # Calculate the new taxes each person pays
+ # Calculate the new taxes from tax on AGI
tax_rate = agi_tax / 100
target_persons['new_taxes'] = target_persons.adjginc * tax_rate
@@ -163,126 +204,174 @@ def ubi(agi_tax, taxable_tax, benefits):
spmu.columns = ['total_tax_increase']
target_persons = target_persons.merge(spmu,left_on=['spmfamunit'],
right_index=True)
-
- # Calculate the new taxes each person pays
- tax_rate2 = taxable_tax / 100
- target_persons['new_taxes2'] = target_persons.taxinc * tax_rate2
+ # Calculate funding from taxes
+ funding = (target_persons.new_taxes * target_persons.asecwt).sum()
- # Calculate the total tax increase of an SPM unit
- spmu2 = target_persons.groupby(['spmfamunit'])[['new_taxes2']].sum()
- spmu2.columns = ['total_tax_increase2']
- target_persons = target_persons.merge(spmu2,left_on=['spmfamunit'],
- right_index=True)
+ #Calculate SPM unit new resources after taxes
+ target_persons['new_spm_resources'] = target_persons.spmtotres - target_persons.total_tax_increase
- # Calculate tax revenue
- tax_revenue = ((target_persons.new_taxes * target_persons.asecwt).sum() +
- (target_persons.new_taxes2 * target_persons.asecwt).sum())
-
- if 'ss' in benefits:
- ubi_ss = (target_persons.incss * target_persons.asecwt).sum()
- target_persons['new_ssspm'] = 0
- else:
- ubi_ss = 0
- target_persons['new_ssspm'] = target_persons.spmss
-
if 'ssi' in benefits:
- ubi_ssi = (target_persons.incssi * target_persons.asecwt).sum()
- target_persons['new_ssispm'] = 0
- else:
- ubi_ssi = 0
- target_persons['new_ssispm'] = target_persons.spmssi
+ funding += (target_persons.incssi * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.incssi
if 'unemp' in benefits:
- ubi_unemp = (target_persons.incunemp * target_persons.asecwt).sum()
- target_persons['new_spmincunemp'] = 0
- else:
- ubi_unemp = 0
- target_persons['new_spmincunemp'] = target_persons.spmincunemp
+ funding += (target_persons.incunemp * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.incunemp
if 'eitc' in benefits:
- ubi_eitc = (target_persons.eitcred * target_persons.asecwt).sum()
- target_persons['new_spmeitc'] = 0
- else:
- ubi_eitc = 0
- target_persons['new_spmeitc'] = target_persons.spmeitc
+ funding += (target_persons.eitcred * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.spmeitc
if 'ctc' in benefits:
- ubi_ctc = (target_persons.ctc * target_persons.asecwt).sum()
- target_persons['new_spmctc'] = 0
- else:
- ubi_ctc = 0
- target_persons['new_spmctc'] = target_persons.spmctc
+ funding += (target_persons.ctc * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.spmctc
if 'snap' in benefits:
- ubi_snap = (target_persons.snap_pp * target_persons.asecwt).sum()
- target_persons['new_spmsnap'] = 0
- else:
- ubi_snap = 0
- target_persons['new_spmsnap'] = target_persons.spmsnap
-
+ funding += (target_persons.snap_pp * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.snap_pp
+
if 'energy' in benefits:
- ubi_energy = (target_persons.energy_pp * target_persons.asecwt).sum()
- target_persons['new_spmenergy'] = 0
- else:
- ubi_energy = 0
- target_persons['new_spmenergy'] = target_persons.spmheat
-
- funding = (ubi_ss + ubi_ssi + ubi_unemp + ubi_eitc + ubi_ctc +
- ubi_snap + ubi_energy + tax_revenue)
+ funding += (target_persons.energy_pp * target_persons.asecwt).sum()
+ target_persons.new_spm_resources -= target_persons.energy_pp
+
+ if 'income_taxes' in taxes:
+ funding -= (target_persons.fedtaxac * target_persons.asecwt).sum()
+ target_persons.new_spm_resources += target_persons.fedtaxac
+
+ if 'fica' in taxes:
+ funding -= (target_persons.fica * target_persons.asecwt).sum()
+ target_persons.new_spm_resources += target_persons.fica
+
+ if ('income_taxes' in taxes) & ('ctc' in benefits):
+ funding -= (target_persons.ctc * target_persons.asecwt).sum()
+ target_persons.new_spm_resources += target_persons.spmctc
+
+ if ('income_taxes' in taxes) & ('eitc' in benefits):
+ funding -= (target_persons.eitcred * target_persons.asecwt).sum()
+ target_persons.new_spm_resources += target_persons.spmeitc
+
+
ubi = funding / population
- target_persons['total_ubi'] = ubi * target_persons.pernum
-
- # Calculate new total resources
- target_persons['new_spm_resources'] = (target_persons.spmtotres +
- target_persons.new_ssspm -
- target_persons.spmss +
- target_persons.new_ssispm -
- target_persons.spmssi +
- target_persons.new_spmincunemp -
- target_persons.spmincunemp +
- target_persons.new_spmeitc -
- target_persons.spmeitc +
- target_persons.new_spmctc -
- target_persons.spmctc +
- target_persons.new_spmsnap -
- target_persons.spmsnap +
- target_persons.new_spmenergy -
- target_persons.spmheat +
- target_persons.total_ubi -
- target_persons.total_tax_increase +
- target_persons.total_tax_increase2)
+ target_persons['total_ubi'] = ubi * target_persons.numper
+ target_persons.new_spm_resources += target_persons.total_ubi
target_persons['new_resources_per_person'] = (target_persons.new_spm_resources /
- target_persons.pernum)
+ target_persons.numper)
# Calculate the change in poverty rate
target_persons['poor'] = (target_persons.new_spm_resources <
target_persons.spmthresh)
-
total_poor = (target_persons.poor * target_persons.asecwt).sum()
poverty_rate = (total_poor / population) * 100
-
- poverty_change = ((poverty_rate - original_poverty_rate) /
+ poverty_rate_change = ((poverty_rate - original_poverty_rate) /
original_poverty_rate * 100).round(2)
+
+ # Calculate the change in child poverty
+ total_child_poor = (target_persons.child * target_persons.poor * target_persons.asecwt).sum()
+ child_poverty_rate = (total_child_poor / child_population) * 100
+ child_poverty_rate_change = ((child_poverty_rate - original_child_poverty_rate)/
+ original_child_poverty_rate * 100).round(2)
+
+ # Calculate the change in poverty gap
+ target_persons['poverty_gap'] = target_persons.spmthresh - target_persons.new_spm_resources
+ spmu = target_persons.drop_duplicates(subset=['spmfamunit'])
+ poverty_gap = (((spmu.poor * spmu.poverty_gap
+ * spmu.asecwth).sum()))
+ poverty_gap_change = ((poverty_gap - original_poverty_gap) /
+ original_poverty_gap * 100).round(1)
# Calculate change in Gini
new_gini = (mdf.gini(target_persons, 'new_resources_per_person' , 'asecwt'))
gini_change = ((new_gini - gini) / gini * 100).round(2)
+ # Calculate percent winners
+ target_persons['winner'] = (target_persons.new_spm_resources >
+ target_persons.spmtotres)
+ total_winners = (target_persons.winner * target_persons.asecwt).sum()
+ percent_winners = (total_winners / population * 100).round(1)
+
+ # Calculate adult poverty
+ total_adult_poor = (target_persons.adult * target_persons.poor * target_persons.asecwt).sum()
+ adult_poverty_rate = (total_adult_poor / adult_population) * 100
+ adult_poverty_rate_change = ((adult_poverty_rate - original_adult_poverty_rate)/
+ original_adult_poverty_rate * 100).round(2)
+
+ # Calculate pwb poverty
+ total_pwb_poor = (target_persons.pwb * target_persons.poor * target_persons.asecwt).sum()
+ pwb_poverty_rate = (total_pwb_poor / pwb_population) * 100
+ pwb_poverty_rate_change = ((pwb_poverty_rate - original_pwb_poverty_rate)/
+ original_pwb_poverty_rate * 100).round(2)
+
+ # Calculate White poverty
+ total_white_poor = (target_persons.white_non_hispanic * target_persons.poor * target_persons.asecwt).sum()
+ white_poverty_rate = (total_white_poor / white_population) * 100
+ white_poverty_rate_change = ((white_poverty_rate - original_white_poverty_rate)/
+ original_white_poverty_rate * 100).round(2)
+
+ # Calculate Black poverty
+ total_black_poor = (target_persons.black * target_persons.poor * target_persons.asecwt).sum()
+ black_poverty_rate = (total_black_poor / black_population) * 100
+ black_poverty_rate_change = ((black_poverty_rate - original_black_poverty_rate)/
+ original_black_poverty_rate * 100).round(2)
+
+ # Calculate Hispanic poverty
+ total_hispanic_poor = (target_persons.hispanic * target_persons.poor * target_persons.asecwt).sum()
+ hispanic_poverty_rate = (total_hispanic_poor / hispanic_population) * 100
+ hispanic_poverty_rate_change = ((hispanic_poverty_rate - original_hispanic_poverty_rate)/
+ original_hispanic_poverty_rate * 100).round(2)
+
ubi_int = int(ubi)
ubi_int = "{:,}".format(ubi_int)
ubi_string = str(ubi_int)
+ winners_string = str(percent_winners)
- x=['Poverty Change', 'Inequality Change']
+ x2=['Child', 'Adult', 'People
with
disabilities', 'White
non
Hispanic', 'Black', 'Hispanic']
- fig = go.Figure([go.Bar(x=x, y=[poverty_change, gini_change],
- text=[poverty_change, gini_change],
+ fig2 = go.Figure([go.Bar(x=x2, y=[child_poverty_rate_change,
+ adult_poverty_rate_change,
+ pwb_poverty_rate_change,
+ white_poverty_rate_change,
+ black_poverty_rate_change,
+ hispanic_poverty_rate_change],
+ text=[child_poverty_rate_change,
+ adult_poverty_rate_change,
+ pwb_poverty_rate_change,
+ white_poverty_rate_change,
+ black_poverty_rate_change,
+ hispanic_poverty_rate_change],
+ marker_color=BLUE)])
+
+ fig2.update_layout(uniformtext_minsize=10, uniformtext_mode='hide', plot_bgcolor='white')
+ fig2.update_traces(texttemplate='%{text}%', textposition='auto')
+ fig2.update_layout(title_text='Poverty rate breakdown')
+
+ fig2.update_xaxes(
+ tickangle = 0,
+ title_text = "",
+ tickfont = {"size": 14},
+ title_standoff = 25)
+
+ fig2.update_yaxes(
+ title_text = "Percent change",
+ ticksuffix ="%",
+ tickprefix = "",
+ tickfont = {'size':14},
+ title_standoff = 25)
+
+ fig2.update_xaxes(title_font=dict(size=14, family='Roboto', color='black'))
+ fig2.update_yaxes(title_font=dict(size=14, family='Roboto', color='black'))
+
+ x=['Poverty Rate', 'Poverty Gap', 'Inequality (Gini)']
+
+ fig = go.Figure([go.Bar(x=x, y=[child_poverty_rate_change, poverty_rate_change, poverty_gap_change, gini_change],
+ text=[child_poverty_rate_change, poverty_rate_change, poverty_gap_change, gini_change],
marker_color=BLUE)])
fig.update_layout(uniformtext_minsize=10, uniformtext_mode='hide', plot_bgcolor='white')
fig.update_traces(texttemplate='%{text}%', textposition='auto')
- fig.update_layout(title_text='Your changes would fund an annual UBI of $'+ ubi_string + ' per person')
+ fig.update_layout(title_text='Your changes would fund an annual UBI of $'+ ubi_string + ' per person.
' +
+ winners_string + '% of people would be better off under this plan.')
fig.update_xaxes(
tickangle = 0,
@@ -299,8 +388,9 @@ def ubi(agi_tax, taxable_tax, benefits):
fig.update_xaxes(title_font=dict(size=14, family='Roboto', color='black'))
fig.update_yaxes(title_font=dict(size=14, family='Roboto', color='black'))
+
+ return fig, fig2
- return fig
if __name__ == '__main__':
app.run_server(debug=True, port=8000, host='127.0.0.1')