Skip to content

Commit

Permalink
Merge pull request #637 from OpenSourcePolicyCenter/634_btax_dataframes
Browse files Browse the repository at this point in the history
Handle data from new BTAX Version
  • Loading branch information
brittainhard committed Sep 18, 2017
2 parents 92e6b77 + cf0d3e7 commit e66ac88
Show file tree
Hide file tree
Showing 14 changed files with 487 additions and 22 deletions.
2 changes: 1 addition & 1 deletion conda-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
nomkl
taxcalc==0.10.2
btax==0.1.8
btax==0.1.9
numba==0.33.0
pandas
gevent
Expand Down
2 changes: 1 addition & 1 deletion deploy/fab/dropq_environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dependencies:
- pandas>=0.20.1
- flask
- greenlet
- bokeh
- bokeh>=0.12.7
- xlrd
- redis
- pip:
Expand Down
12 changes: 10 additions & 2 deletions deploy/taxbrain_server/celery_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,16 @@ def ogusa_async(user_mods, ogusa_params, guid):
def btax_async(user_mods):
print("user mods: ", user_mods)
results = {}
results.update(runner_json_tables(**user_mods))
#Add taxcalc version to results
tables = runner_json_tables(**user_mods)
if tables.get("json_table"):
results.update(tables["json_table"])
if tables.get("dataframes"):
dataframes = json.loads(tables["dataframes"])
for x, y in dataframes.items():
dataframes[x] = json.loads(y)
results["dataframes"] = dataframes
else:
results.update(tables)
vinfo = taxcalc._version.get_versions()
results['taxcalc_version'] = vinfo['version'] + '.' + vinfo['full'][:6]
results['dropq_version'] = vinfo['version'] + '.' + vinfo['full'][:6]
Expand Down
8 changes: 6 additions & 2 deletions templates/btax/not_ready.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,28 @@ <h4>About <span id="eta"></span> remaining</h4>
$('#eta').text(moment.duration(eta, 'minutes').humanize());
}

var interval;
function ajaxEta() {
$.ajax(window.location.href, {
type: 'post',
data: { csrfmiddlewaretoken: $('meta[name="csrf-token"]').attr('content') },
success: function(data, textStatus, xhr) {
if (xhr.status === 202) {
insertEta(data.eta);
clearInterval(interval);
interval = setInterval(ajaxEta, data.wait_interval);
} else if (xhr.status === 200) {
clearInterval(interval);
insertEta(data.eta);
setTimeout(function() {
window.location.reload(1);
}, 5000)
}
}
},
});
}
ajaxEta();
setInterval(ajaxEta, 7000);
interval = setInterval(ajaxEta, 7000);
});
</script>
{% endblock %}
17 changes: 17 additions & 0 deletions templates/btax/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
<link href="{% static 'js/vendor/DataTables/datatables.min.css' %}" rel="stylesheet"></link>
<link href="{% static 'css/vendor/bootstrap/bootstrap.min.css' %}" rel="stylesheet"></link>
<link href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" rel="stylesheet">
<link rel='stylesheet' href={{cdn_css|safe}} type="text/css"/>
<script type="text/javascript" src={{cdn_js|safe}}></script>
<link
href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css"
rel="stylesheet" type="text/css">
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.js"></script>

<style>
.btn {
Expand Down Expand Up @@ -49,6 +55,10 @@
#results-container {
}

.bk-root .bk-grid-column {
margin: 0 auto;
}

.controls-row {
margin-left:100px;
margin-right:100px;
Expand Down Expand Up @@ -84,6 +94,12 @@ <h1>{% flatblock "ccc_results_header" %}</h1>
<a href="/ccc/edit/{{ unique_url.pk }}/" class="text-white btn btn-secondary">Edit Parameters</a>
</div>
<br>

<div class="center-block">
{{ bubble_div|safe }}
{{ bubble_js|safe }}
</div>

<div id="results-container" class="container">
<div class="row controls-row">
<div id="view_by_inputs" class="col-sm-12">
Expand Down Expand Up @@ -147,6 +163,7 @@ <h2>Output Format:</h2>
</label>
</div>
</div>

<div class="row">
<div id="results-table-area" class="col-sm-12">
</div>
Expand Down
Empty file.
241 changes: 241 additions & 0 deletions webapp/apps/btax/bubble_plot/bubble_plot_tabs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import pandas as pd
from os import path
import json
pd.options.mode.chained_assignment = None

# importing Bokeh libraries
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Title, CustomJS
from bokeh.models.widgets import Select, Panel, Tabs, RadioButtonGroup
from bokeh.models import HoverTool, WheelZoomTool, ResetTool, SaveTool
from bokeh.models import NumeralTickFormatter
from bokeh.layouts import gridplot
from bokeh.embed import components
from bokeh.resources import CDN

# import styles and callback
from styles import (PLOT_FORMATS, TITLE_FORMATS, RED, BLUE)
from controls_callback_script import CONTROLS_CALLBACK_SCRIPT


def bubble_plot_tabs(dataframes):
dataframes = dataframes.copy()

# convert asset dicts to pandas dataframes
base_df = pd.DataFrame.from_dict(dataframes['base_output_by_asset'])
reform_df = pd.DataFrame.from_dict(dataframes['reform_output_by_asset'])
change_df = pd.DataFrame.from_dict(dataframes['changed_output_by_asset'])

list_df = [base_df, change_df, reform_df]
list_string = ['base', 'change', 'reform']

data_sources = {}
for i, df in enumerate(list_df):
# remove data from Intellectual Property, Land, and Inventories Categories
df = df[~df['asset_category'].isin(['Intellectual Property','Land','Inventories'])].copy()
df = df.dropna()

# define the size DataFrame, if change, use base sizes
if list_string[i] == 'base':
SIZES = list(range(20, 80, 15))
size = pd.qcut(df['assets_c'].values, len(SIZES), labels=SIZES)
size_c = pd.qcut(df['assets_c'].values, len(SIZES), labels=SIZES)
size_nc = pd.qcut(df['assets_nc'].values, len(SIZES), labels=SIZES)
df['size'] = size
df['size_c'] = size_c
df['size_nc'] = size_nc
else:
df['size'] = size
df['size_c'] = size_c
df['size_nc'] = size_nc

# form the two Categories: Equipment and Structures
equipment_df = df[(~df.asset_category.str.contains('Structures')) & (~df.asset_category.str.contains('Buildings'))]
structure_df = df[(df.asset_category.str.contains('Structures')) | (df.asset_category.str.contains('Buildings'))]

format_fields = ['metr_c', 'metr_nc', 'metr_c_d', 'metr_nc_d',
'metr_c_e', 'metr_nc_e', 'mettr_c', 'mettr_nc',
'mettr_c_d', 'mettr_nc_d', 'mettr_c_e', 'mettr_nc_e',
'rho_c', 'rho_nc', 'rho_c_d', 'rho_nc_d', 'rho_c_e',
'rho_nc_e', 'z_c', 'z_nc', 'z_c_d', 'z_nc_d', 'z_c_e',
'z_nc_e']

# Make short category
make_short = {'Instruments and Communications Equipment': 'Instruments and Communications',
'Office and Residential Equipment': 'Office and Residential',
'Other Equipment': 'Other',
'Transportation Equipment': 'Transportation',
'Other Industrial Equipment': 'Other Industrial',
'Nonresidential Buildings': 'Nonresidential Bldgs',
'Residential Buildings': 'Residential Bldgs',
'Mining and Drilling Structures': 'Mining and Drilling',
'Other Structures': 'Other',
'Computers and Software': 'Computers and Software',
'Industrial Machinery': 'Industrial Machinery'}
equipment_df['short_category'] = equipment_df['asset_category'].map(make_short)
structure_df['short_category'] = structure_df['asset_category'].map(make_short)

# Add the Reform and the Baseline to Equipment Asset
for f in format_fields:
equipment_copy = equipment_df.copy()
equipment_copy['rate'] = equipment_copy[f]
equipment_copy['hover'] = equipment_copy.apply(lambda x: "{0:.1f}%".format(x[f] * 100), axis=1)
simple_equipment_copy = equipment_copy.filter(items=['size', 'size_c', 'size_nc', 'rate', 'hover', 'short_category', 'Asset'])
data_sources[list_string[i] + '_equipment_' + f] = ColumnDataSource(simple_equipment_copy)

# Add the Reform and the Baseline to Structures Asset
for f in format_fields:
structure_copy = structure_df.copy()
structure_copy['rate'] = structure_copy[f]
structure_copy['hover'] = structure_copy.apply(lambda x: "{0:.1f}%".format(x[f] * 100), axis=1)
simple_structure_copy = structure_copy.filter(items=['size', 'size_c', 'size_nc', 'rate', 'hover', 'short_category', 'Asset'])
data_sources[list_string[i] + '_structure_' + f] = ColumnDataSource(simple_structure_copy)

# Create initial data sources to plot on load
if list_string[i] == 'base':
equipment_copy = equipment_df.copy()
equipment_copy['rate'] = equipment_copy['mettr_c']
equipment_copy['hover'] = equipment_copy.apply(lambda x: "{0:.1f}%".format(x[f] * 100), axis=1)
simple_equipment_copy = equipment_copy.filter(items=['size', 'size_c', 'size_nc', 'rate', 'hover', 'short_category', 'Asset'])
data_sources['equip_source'] = ColumnDataSource(simple_equipment_copy)

structure_copy = structure_df.copy()
structure_copy['rate'] = structure_copy['mettr_c']
structure_copy['hover'] = structure_copy.apply(lambda x: "{0:.1f}%".format(x[f] * 100), axis=1)
simple_structure_copy = structure_copy.filter(items=['size', 'size_c', 'size_nc', 'rate', 'hover', 'short_category', 'Asset'])
data_sources['struc_source'] = ColumnDataSource(simple_structure_copy)

# Define categories for Equipments assets
equipment_assets = ['Computers and Software',
'Instruments and Communications',
'Office and Residential',
'Transportation',
'Industrial Machinery',
'Other Industrial',
'Other']

# Define categories for Structures assets
structure_assets = ['Residential Bldgs',
'Nonresidential Bldgs',
'Mining and Drilling',
'Other']

# Equipment plot
p = figure(plot_height=540,
plot_width=990,
y_range=list(reversed(equipment_assets)),
tools='hover',
background_fill_alpha=0
)
p.add_layout(Title(text='Marginal Effective Tax Rates on Corporate Investments in Equipment', **TITLE_FORMATS), "above")

hover = p.select(dict(type=HoverTool))
hover.tooltips = [('Asset', ' @Asset (@hover)')]

p.xaxis.axis_label = "Marginal Effective Tax Rate"
p.xaxis[0].formatter = NumeralTickFormatter(format="0.1%")

p.toolbar_location = None
p.min_border_right = 5

p.outline_line_width = 5
p.border_fill_alpha = 0
p.xaxis.major_tick_line_color = "firebrick"
p.xaxis.major_tick_line_width = 3
p.xaxis.minor_tick_line_color = "orange"

p.outline_line_width = 1
p.outline_line_alpha = 1
p.outline_line_color = "black"

p.circle(x='rate',
y='short_category',
color=BLUE,
size='size',
line_color="#333333",
fill_alpha=.4,
source=data_sources['equip_source'],
alpha=.4
)

# Style the tools
p.add_tools(WheelZoomTool(), ResetTool(), SaveTool())
p.toolbar_location = "right"
p.toolbar.logo = None

# Structures plot
p2 = figure(plot_height=540,
plot_width=990,
y_range=list(reversed(structure_assets)),
tools='hover',
background_fill_alpha=0)
p2.add_layout(Title(text='Marginal Effective Tax Rates on Corporate Investments in Structures', **TITLE_FORMATS),"above")

hover = p2.select(dict(type=HoverTool))
hover.tooltips = [('Asset', ' @Asset (@hover)')]
p2.xaxis.axis_label = "Marginal Effective Tax Rate"
p2.xaxis[0].formatter = NumeralTickFormatter(format="0.1%")
p2.toolbar_location = None
p2.min_border_right = 5
p2.outline_line_width = 0
p2.border_fill_alpha = 0

p2.xaxis.major_tick_line_color = "firebrick"
p2.xaxis.major_tick_line_width = 3
p2.xaxis.minor_tick_line_color = "orange"


p2.circle(x='rate',
y='short_category',
color=RED,
size='size',
line_color="#333333",
fill_alpha=.4,
source=data_sources['struc_source'],
alpha=.4)

p2.outline_line_width = 1
p2.outline_line_alpha = 1
p2.outline_line_color = "black"

# Style the tools
p2.add_tools(WheelZoomTool(), ResetTool(), SaveTool())
p2.toolbar_location = "right"
p2.toolbar.logo = None

# add buttons
controls_callback = CustomJS(args=data_sources,
code=CONTROLS_CALLBACK_SCRIPT)

c_nc_buttons = RadioButtonGroup(labels=['Corporate', 'Noncorporate'],
active=0, callback=controls_callback)
controls_callback.args['c_nc_buttons'] = c_nc_buttons

format_buttons = RadioButtonGroup(labels=['Baseline', 'Reform', 'Change'],
active=0, callback=controls_callback)
controls_callback.args['format_buttons'] = format_buttons

interest_buttons = RadioButtonGroup(labels=['METTR', 'METR', 'Cost of Capital', 'Depreciation'],
active=0, width=700, callback=controls_callback)
controls_callback.args['interest_buttons'] = interest_buttons

type_buttons = RadioButtonGroup(labels=['Typically Financed', 'Equity Financed', 'Debt Financed'],
active=0, width=700, callback=controls_callback)
controls_callback.args['type_buttons'] = type_buttons

# Create Tabs
tab = Panel(child=p, title='Equipment')
tab2 = Panel(child=p2, title='Structures')
tabs = Tabs(tabs=[tab, tab2])
layout = gridplot(
children=[[tabs],
[c_nc_buttons, interest_buttons],
[format_buttons, type_buttons]]
)

# Create components
js, div = components(layout)
cdn_js = CDN.js_files[0]
cdn_css = CDN.css_files[0]

return js, div, cdn_js, cdn_css

0 comments on commit e66ac88

Please sign in to comment.