Skip to content

Commit

Permalink
Merge pull request #1740 from martinholmer/add-cookbook
Browse files Browse the repository at this point in the history
Add to docs a cookbook of tested recipes for Python programming with taxcalc
  • Loading branch information
martinholmer authored Dec 11, 2017
2 parents 9860c21 + 5cd4516 commit d331bec
Show file tree
Hide file tree
Showing 11 changed files with 629 additions and 16 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ you should begin by reading the [user
documentation](http://open-source-economics.github.io/Tax-Calculator/)
that describes how to use Tax-Calculator on your own computer (without
doing any programming) and how to use the Tax-Calculator web application
called [TaxBrain](http://www.ospc.org/taxbrain/).
called [TaxBrain](http://www.ospc.org/taxbrain/). If you want the most
flexibility in using Tax-Calculator on your own computer, start
by reading our [Cookbook of Tested Recipes for Python Programming with
Tax-Calculator](http://open-source-economics.github.io/Tax-Calculator/cookbook.html).


What is Tax-Calculator?
-----------------------
Expand Down
7 changes: 5 additions & 2 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Go [here](https://github.com/open-source-economics/Tax-Calculator/pulls?q=is%3Ap
for a complete commit history.


2017-12-?? Release 0.14.0
2017-12-11 Release 0.14.0
-------------------------
(last merged pull request is
[#xxxx](https://github.com/open-source-economics/Tax-Calculator/pull/xxxx))
[#1742](https://github.com/open-source-economics/Tax-Calculator/pull/1742))

**API Changes**
- Add several Calculator table methods and revise table utilities to not use Calculator object(s)
Expand All @@ -30,6 +30,9 @@ for a complete commit history.
- Add ability to specify partial customized CLI `tc --dump` output
[[#1735](https://github.com/open-source-economics/Tax-Calculator/pull/1735)
by Martin Holmer as suggested by Sean Wang]
- Add *Cookbook of Tested Recipes for Python Programming with Tax-Calculator*
[[#1740](https://github.com/open-source-economics/Tax-Calculator/pull/1740)
by Martin Holmer]
- Add calculation of two values on the ALL row of the difference table
[[#1741](https://github.com/open-source-economics/Tax-Calculator/pull/1741)
by Martin Holmer]
Expand Down
209 changes: 209 additions & 0 deletions docs/cookbook.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<!DOCTYPE html>
<html>
<head>
<title>Tax-Calculator Cookbook</title>
<style>
div { max-width: 19cm }
</style>
</head>
<body>
<div>

<h1 id="toc">A Cookbook of Tested Recipes for Python Programming with
Tax-Calculator</h1>

<p>This document tells you how to use Tax-Calculator, an open-source
federal income and payroll tax simulation model, in Python scripts
that you can run on your own computer. Note that these recipes
require Tax-Calculator release 0.14.0 or higher. For other ways of
using Tax-Calculator, see the
<a href="https://open-source-economics.github.io/Tax-Calculator/">
user documentation</a>.</p>

<h2>Cookbook Contents</h2>

<p><b>Preliminaries</b></p>

<p><a href="#setup">Kitchen Setup</a> on how to setup your computer to
follow these recipes</p>

<p><a href="#techniques">Recipe Techniques</a> on rules to follow when
modifying the recipes in this cookbook</p>

<p><a href="#ingredients">Recipe Ingredients</a> on how get the
ingredients required for these recipes in your kitchen</p>

<p><a href="#feedback">Recipe Feedback</a> on how request a new recipe
be added to this cookbook or <br> report problems encountered when
following an existing recipe</p>

<p><b>Basic Recipe</b></p>

<p><a href="#recipe00">Static Analysis of a Simple Reform</a></p>

<p><b>Other Recipes</b></p>

<p><i>coming soon</i></p>


<h2 id="setup">Preliminaries: Kitchen Setup</h2>

<p>You need to setup your computer in certain ways in order to follow
these recipes. First, follow
<a href="http://open-source-economics.github.io/Tax-Calculator/#cli-install-test">these instructions</a> on installing Anaconda and a taxcalc package on
your computer. And second, install the recipes and ingredients in this
cookbook on your computer. There are several ways to do this. If you
have cloned the Tax-Calculator repository (see the
<a href="http://taxcalc.readthedocs.io/en/latest/contributor_guide.html">
Contributor Guide</a>), then the recipes are located in the
<kbd>Tax-Calculator/docs/cookbook</kbd> directory. If you haven't
cloned the repository, you have a couple of choices. You can download
the source code as a zip file by clicking on the green <q>Clone or
download</q> button on
<a href="https://github.com/open-source-economics/Tax-Calculator">
this page</a>. This choice has the advantage of replicating the
directory structure and file names that we use in our test kitchen.
To comfirm your unzipped installation is valid, execute
<kbd>python test_recipes.py</kbd> in the
<kbd>Tax-Calculator/docs/cookbook</kbd> directory to make sure all the
recipes <kbd>PASS</kbd>. Or you can copy and paste the recipes and
ingredients, as needed, to your local computer. If you make this
second choice, you may need to edit file paths in the recipes
depending on how you've organized and named the copied-and-pasted
files.</p>

<p><a href="#toc">Back to Cookbook Contents</a></p>


<h2 id="techniques">Preliminaries: Recipe Techniques</h2>

<p>As with any cookbook, the best approach is to follow a recipe
exactly the first time and then, if needed, modify the recipe to get
the exactly the <q>dish</q> you want. Remember to copy a recipe file
and give it a new file name before you start to modify the recipe.</p>

<p>The Calculator object is the central object in Tax-Calculator and
it is created by passing four secondary objects (a Policy object, a
Records object, a Behavior object, and a Consumption object) to the
Calculator class constructor. When modifying a recipe, following a
few rules will minimize the chance of running into problems.</p>

<p>Fully specify Consumption, Behavior, Records, and Policy objects
before passing them to the Calculator class constructor.</p>

<p>After initializing a Calculator object, manipulate it using only
Calculator class methods.</p>

<p>Following these two rules means avoiding the manipulation of a
Calculator object's private internal objects. You should definitely
avoid trying to change those internal Calculator objects. And if you
find yourself wanting to read those internal objects, look for a way
to do that using public Calculator methods. If no Calculator methods
allow you to get out of the Calculator object the information you
need,
<a href="https://github.com/open-source-economics/Tax-Calculator/issues">
create a new issue</a> asking for a Tax-Calculator enhancement.</p>

<p id="execution">The recipes in this cookbook are Python scripts that
can be executed from the command line like this:
<pre>
python recipe00.py > recipe00.out
diff recipe00.out recipe00.res
</pre>
Your kitchen setup and ability to follow a recipe and produce the same
<q>dish</q> as we produce in our test kitchen would be validated if
the above <kbd>diff</kbd> command yields no differences. Of course,
you can substitute your favorite graphical diff program
for <kbd>diff</kbd> to get an easier to read set of differences.</p>

<p>Some people like to use Tax-Calculator inside an interactive
notebook. You should be able to load a recipe into an empty notebook
and execute it there. If you want to work that way, the recipes may
require some modification to show results interactively. But if you
are a notebook user, you will know how to make a recipe work in a
notebook.</p>

<p>After writing an HTML graph file to disk, you can view it in your
favorite browser. The easiest way to do that varies by operating
system.</p>

<p><a href="#toc">Back to Cookbook Contents</a></p>


<h2 id="ingredients">Preliminaries: Recipe Ingredients</h2>

<p>All the ingredients needed for the recipes are included in
the <kbd>Tax-Calculator/docs/cookbook/ingredients</kbd> directory. If
you organize the recipes and ingredients in a different way than they
are organized in our test kitchen, you will need to change the file
path for each ingredient in each recipe.</p>

<p>Just like with recipe modification, copy and rename an ingredient
file before you make modifications to it.</p>

<p><a href="#toc">Back to Cookbook Contents</a></p>


<h2 id="feedback">Preliminaries: Recipe Feedback</h2>

<p>If you want to request a recipe that makes a new <q>dish</q>,
create a new issue
<a href="https://github.com/open-source-economics/Tax-Calculator/issues">here</a>
providing details on what you want to make and why the existing
recipes cannot be easily modified to make what you want.</p>

<p>Also, please report, in the same way, any problems you experience
following an existing recipe.</p>

<p><a href="#toc">Back to Cookbook Contents</a></p>


<h2 id="recipe00">Basic Recipe: Static Analysis of a Simple Reform</h2>

<p>This is the recipe you should follow first. Mastering this recipe
is a prerequisite for all the other recipes in this cookbook.</p>

<p><b>Ingredients</b></p>


<p><a href="cookbook/ingredients/raise_rates_and_stdded.json">Policy
reform</a> in the <kbd>ingredients/raise_rates_and_stdded.json</kbd>
file</p>

<p><b>Instructions</b></p>

<p><a href="cookbook/recipe00.py">Step-by-step instructions</a> included in the <kbd>recipe00.py</kbd> file</p>

<p><b>Results</b></p>

<p><em>
When following the recipe as shown below, you will get three instances
of the same <b>ignored</b> error message from deep inside the Pandas
library that is being used by Tax-Calculator. After conferring with
the Pandas developers, our expectation is these error messages will go
away when we upgrade to Pandas version 0.22.0, which is scheduled to
be released in January 2018, and which fixes a bug in the Pandas
library. Meanwhile, the error messages are annoying but harmless.
</em></p>

<p><a href="cookbook/recipe00.res">Expected text results</a> from
executing <kbd>python recipe00.py > recipe00.out</kbd> at the command
prompt as shown <a href="#execution">above</a>.</p>

<p><a href="cookbook/recipe00-graph.png">Expected graph</a> (located
in the same directory as <kbd>recipe00.py</kbd> and named
<kbd>recipe00-graph.html</kbd>) from executing
<kbd>python recipe00.py > recipe00.out</kbd> at the command prompt as
shown <a href="#execution">above</a>. To view the HTML graph file
generated when you follow the recipe, open it in your favorite
browser. For example, on a Mac, you would enter at the command prompt
the following
<pre>open recipe00-graph.html</pre>
to start your default browser showing the graph.</p>

<p><a href="#toc">Back to Cookbook Contents</a></p>


</div>
</body>
</html>
19 changes: 19 additions & 0 deletions docs/cookbook/ingredients/raise_rates_and_stdded.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Raise standard deduction and raise regular tax rates in top three brackets
// from (0.33, 0.35, 0.396) to (0.35, 0.37, 0.42) beginning in 2018.
{
"policy": {
// raise standard deduction and eliminate Dep and Aged differentials
"_STD": {"2018": [[12000, 24000, 12000, 18000, 24000]]},
"_STD_Dep": {"2018": [0]},
"_STD_Aged": {"2018": [[0, 0, 0, 0, 0]]},
// raise tax rates in the top three brackets
// ... raise non-AMT rates on non-pass-through income
"_II_rt5": {"2018": [0.350]},
"_II_rt6": {"2018": [0.370]},
"_II_rt7": {"2018": [0.420]},
// ... raise non-AMT rates on pass-through income
"_PT_rt5": {"2018": [0.350]},
"_PT_rt6": {"2018": [0.370]},
"_PT_rt7": {"2018": [0.420]}
}
}
Binary file added docs/cookbook/recipe00-graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions docs/cookbook/recipe00.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from __future__ import print_function # necessary only if using Python 2.7
from taxcalc import *

# use publicly-available CPS input file
recs = Records.cps_constructor()
# NOTE: if you have access to the restricted-use IRS-SOI PUF-based input file
# and you have that file (named 'puf.csv') located in the directory
# where this script is located, then you can substitute the following
# statement for the prior statement:
# recs = Records()

# specify Calculator object for static analysis of current-law policy
pol = Policy()
calc1 = Calculator(policy=pol, records=recs)

# NOTE: calc1 now contains a PRIVATE COPY of pol and a PRIVATE COPY of recs,
# so we can continue to use pol and recs in this script without any
# concern about side effects from Calculator method calls on calc1.

# calculate aggregate current-law income tax liabilities for 2018
calc1.advance_to_year(2018)
calc1.calc_all()
itax_rev1 = calc1.weighted_total('iitax')

# read JSON reform file and use (the default) static analysis assumptions
reform_filename = './ingredients/raise_rates_and_stdded.json'
params = Calculator.read_json_param_objects(reform=reform_filename,
assump=None)

# specify Calculator object for static analysis of reform policy
pol.implement_reform(params['policy'])
if pol.reform_errors: # check for reform error messages
print(pol.reform_errors)
exit(1)
calc2 = Calculator(policy=pol, records=recs)

# calculate reform income tax liabilities for 2018
calc2.advance_to_year(2018)
calc2.calc_all()
itax_rev2 = calc2.weighted_total('iitax')

# print reform documentation
print('')
print(Calculator.reform_documentation(params))

# print total revenue estimates for 2018
# (estimates in billons of dollars rounded to nearest hundredth of a billion)
print('2018_CLP_itax_rev($B)= {:.2f}'.format(itax_rev1 * 1e-9))
print('2018_REF_itax_rev($B)= {:.2f}'.format(itax_rev2 * 1e-9))
print('')

# generate several other standard results tables:

# aggregate diagnostic tables for 2018
clp_diagnostic_table = calc1.diagnostic_table(1)
ref_diagnostic_table = calc2.diagnostic_table(1)

# income-tax distribution for 2018 with CLP and REF results side-by-side
dist_table1, dist_table2 = calc1.distribution_tables(calc2)
assert isinstance(dist_table1, pd.DataFrame)
assert isinstance(dist_table2, pd.DataFrame)
dist_extract = pd.DataFrame()
dist_extract['funits(#m)'] = dist_table1['s006'] * 1e-6
dist_extract['itax1($b)'] = dist_table1['iitax'] * 1e-9
dist_extract['itax2($b)'] = dist_table2['iitax'] * 1e-9
dist_extract['aftertax_inc1($b)'] = dist_table1['aftertax_income'] * 1e-9
dist_extract['aftertax_inc2($b)'] = dist_table2['aftertax_income'] * 1e-9

# income-tax difference table by expanded-income decile for 2018
diff_table = calc1.difference_table(calc2, tax_to_diff='iitax')
assert isinstance(diff_table, pd.DataFrame)
diff_extract = pd.DataFrame()
dif_colnames = ['count', 'tot_change', 'mean',
'pc_aftertaxinc']
ext_colnames = ['funits(#m)', 'agg_diff($b)', 'mean_diff($)',
'aftertaxinc_diff(%)']
scaling_factors = [1e-6, 1e-9, 1e0, 1e0, 1e0]
for dname, ename, sfactor in zip(dif_colnames, ext_colnames, scaling_factors):
diff_extract[ename] = diff_table[dname] * sfactor

# generate a graph and save in an HTML file
fig = calc1.decile_graph(calc2)
write_graph_file(fig, 'recipe00-graph.html', 'recipe00 graph')

print('CLP diagnostic table for 2018:')
print(clp_diagnostic_table)
print('')
print('REF diagnostic table for 2018:')
print(ref_diagnostic_table)
print('')

print('Extract of 2018 distribution tables by baseline expanded-income decile:')
print(dist_extract)
print('Note: deciles are numbered 0-9 with top decile divided into bottom 5%,')
print(' next 4%, and top 1%, in the lines numbered 11-13, respectively')
print('')

print('Extract of 2018 income-tax difference table by expanded-income decile:')
print(diff_extract)
print('Note: deciles are numbered 0-9 with top decile divided into bottom 5%,')
print(' next 4%, and top 1%, in the lines numbered 11-13, respectively')
Loading

0 comments on commit d331bec

Please sign in to comment.