diff --git a/.github/workflows/versioning.yaml b/.github/workflows/versioning.yaml index 53709c4e..c4ccf09b 100644 --- a/.github/workflows/versioning.yaml +++ b/.github/workflows/versioning.yaml @@ -4,10 +4,11 @@ name: Versioning updates on: push: branches: - - main + - main paths: - - changelog_entry.yaml + - changelog_entry.yaml + - "!pyproject.toml" jobs: Versioning: diff --git a/Makefile b/Makefile index c1b795b7..49972175 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ all: build documentation: jb clean docs jb build docs + python docs/add_plotly_to_book.py docs/ install: pip install -e .[dev] diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29b..d1b35788 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Chart generation for macro charts. diff --git a/docs/_toc.yml b/docs/_toc.yml index 6b3c3baa..e901296a 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -4,4 +4,9 @@ parts: - caption: Reference chapters: - file: reference/simulation + - file: reference/calculate_single_household + - file: reference/calculate_household_comparison + - file: reference/calculate_single_economy + - file: reference/calculate_economy_comparison + - file: reference/create_charts \ No newline at end of file diff --git a/docs/add_plotly_to_book.py b/docs/add_plotly_to_book.py new file mode 100644 index 00000000..822e77ab --- /dev/null +++ b/docs/add_plotly_to_book.py @@ -0,0 +1,27 @@ +import argparse +from pathlib import Path + +# This command-line tools enables Plotly charts to show in the HTML files for the Jupyter Book documentation. + +parser = argparse.ArgumentParser() +parser.add_argument("book_path", help="Path to the Jupyter Book.") + +args = parser.parse_args() + +# Find every HTML file in the Jupyter Book. Then, add a script tag to the start of the tag in each file, with the contents: +# + +book_folder = Path(args.book_path) + +for html_file in book_folder.glob("**/*.html"): + with open(html_file, "r") as f: + html = f.read() + + # Add the script tag to the start of the tag. + html = html.replace( + "", + '', + ) + + with open(html_file, "w") as f: + f.write(html) diff --git a/docs/reference/calculate_economy_comparison.ipynb b/docs/reference/calculate_economy_comparison.ipynb new file mode 100644 index 00000000..2d6fcfd4 --- /dev/null +++ b/docs/reference/calculate_economy_comparison.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare outcomes for large population scenarios\n", + "\n", + "Use `Simulation.calculate_economy_comparison()` to use PolicyEngine's tax-benefit model to compare how taxes, benefits and other household properties change under a reform scenario. This notebook demonstrates how to use this function." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "EconomyComparison(headlines=Headlines(budgetary_impact=-20688882917.062927, poverty_impact=-0.009522052793635733, winner_share=0.8345739005338316), fiscal=FiscalComparison(baseline=FiscalSummary(tax_revenue=658911285719.5891, federal_tax=658911285719.5891, federal_balance=309089098855.4849, state_tax=0.0, government_spending=349822186864.1042, tax_benefit_programs={'income_tax': 333376287037.05945, 'national_insurance': 52985626776.773834, 'ni_employer': 126330649370.35953, 'vat': 211671832822.39133, 'council_tax': 49007055050.00724, 'fuel_duty': 26506672341.204205, 'tax_credits': -34929879.49872104, 'universal_credit': -73459549194.97665, 'child_benefit': -14311471487.935827, 'state_pension': -132795868621.44594, 'pension_credit': -6252358021.417119}, household_net_income=1566028514855.0789), reform=FiscalSummary(tax_revenue=637686731286.3723, federal_tax=637686731286.3723, federal_balance=288400215938.422, state_tax=0.0, government_spending=349286515347.9503, tax_benefit_programs={'income_tax': 312151564998.6612, 'national_insurance': 52985626776.773834, 'ni_employer': 126330649370.35953, 'vat': 211671832822.39133, 'council_tax': 49007055050.00724, 'fuel_duty': 26506672341.204205, 'tax_credits': -34929879.49872104, 'universal_credit': -73099552696.20555, 'child_benefit': -14311471487.935827, 'state_pension': -132795868621.44594, 'pension_credit': -6181432287.167828}, household_net_income=1586717263122.5647), change=FiscalSummary(tax_revenue=-21224554433.216797, federal_tax=-21224554433.216797, federal_balance=-20688882917.062927, state_tax=0.0, government_spending=-535671516.1538696, tax_benefit_programs={'income_tax': -21224722038.398254, 'national_insurance': 0.0, 'ni_employer': 0.0, 'vat': 0.0, 'council_tax': 0.0, 'fuel_duty': 0.0, 'tax_credits': 0.0, 'universal_credit': 359996498.7711029, 'child_benefit': 0.0, 'state_pension': 0.0, 'pension_credit': 70925734.24929142}, household_net_income=20688748267.48584), relative_change=FiscalSummary(tax_revenue=-0.03221155092227281, federal_tax=-0.03221155092227281, federal_balance=-0.06693501321680725, state_tax=0.0, government_spending=-0.0015312679877619157, tax_benefit_programs={'income_tax': -0.06366596204858095, 'national_insurance': 0.0, 'ni_employer': 0.0, 'vat': 0.0, 'council_tax': 0.0, 'fuel_duty': 0.0, 'tax_credits': -0.0, 'universal_credit': -0.004900608603186478, 'child_benefit': -0.0, 'state_pension': -0.0, 'pension_credit': -0.01134383763795021}, household_net_income=0.013210965235457662)), inequality=InequalityComparison(baseline=InequalitySummary(gini=0.36255397405553097, top_10_share=0.3260927004295773, top_1_share=0.13145609415091833), reform=InequalitySummary(gini=0.36210731670764496, top_10_share=0.32470725674255146, top_1_share=0.1300325825945402), change=InequalitySummary(gini=-0.00044665734788601474, top_10_share=-0.0013854436870258113, top_1_share=-0.0014235115563781264), relative_change=InequalitySummary(gini=-0.0012319747674800056, top_10_share=-0.004248619135603775, top_1_share=-0.010828798509286775)), distributional=DecileImpacts(income=IncomeMeasureSpecificDecileImpacts(income_change=IncomeMeasureSpecificDecileIncomeChange(relative={1: 0.006888474767108438, 2: 0.012069475259054711, 3: 0.01362845736941666, 4: 0.016099117695117186, 5: 0.01374886913709005, 6: 0.016868831714948112, 7: 0.01753355279609095, 8: 0.016653943875645758, 9: 0.016768055951517695, 10: 0.007412182918826308}, average={1: 104.9760740138715, 2: 345.3564489476293, 3: 505.97466813661975, 4: 693.4608276094718, 5: 633.0583755079966, 6: 916.7936598562601, 7: 1160.9595929383368, 8: 1339.97187253835, 9: 1645.9437072259466, 10: 1555.8434910392261}), winners_and_losers=IncomeMeasureSpecificDecileWinnersLosers(deciles={1: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.00016742770708814546, lose_share=0.00016742770708814546, no_change_share=0.7777537048412824, gain_share=0.22207886745162944, gain_less_than_5_percent_share=0.1144106783823729, gain_more_than_5_percent_share=0.10766818906925654), 2: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.008307581771885529, lose_share=0.008307581771885529, no_change_share=0.32972785891469386, gain_share=0.6619645593134206, gain_less_than_5_percent_share=0.5622028657847857, gain_more_than_5_percent_share=0.09976169352863486), 3: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=7.96157411760938e-05, lose_share=7.96157411760938e-05, no_change_share=0.24138511806270913, gain_share=0.7585352661961148, gain_less_than_5_percent_share=0.5985049210228661, gain_more_than_5_percent_share=0.16003034517324866), 4: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.1274989463786316, gain_share=0.8725010536213684, gain_less_than_5_percent_share=0.8390939448490379, gain_more_than_5_percent_share=0.033407108772330475), 5: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.039569164250678565, gain_share=0.9604308357493214, gain_less_than_5_percent_share=0.9576740433060911, gain_more_than_5_percent_share=0.002756792443230341), 6: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.047391872522306096, gain_share=0.9526081274776939, gain_less_than_5_percent_share=0.9027059122375464, gain_more_than_5_percent_share=0.049902215240147485), 7: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=5.104037721866914e-07, lose_share=5.104037721866914e-07, no_change_share=0.018556113733354175, gain_share=0.9814433758628737, gain_less_than_5_percent_share=0.9347186693787157, gain_more_than_5_percent_share=0.046724706484157955), 8: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.0078485273494483, gain_share=0.9921514726505517, gain_less_than_5_percent_share=0.9786379299391095, gain_more_than_5_percent_share=0.013513542711442263), 9: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.015484773300234851, gain_share=0.9845152266997651, gain_less_than_5_percent_share=0.9787986406237482, gain_more_than_5_percent_share=0.00571658607601697), 10: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.09527409658848911, gain_share=0.9047259034115109, gain_less_than_5_percent_share=0.9047259034115109, gain_more_than_5_percent_share=0.0)}, all=IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0008383266758003545, lose_share=0.0008383266758003545, no_change_share=0.16458777279036807, gain_share=0.8345739005338316, gain_less_than_5_percent_share=0.7829682328930914, gain_more_than_5_percent_share=0.051605667640740344))), wealth=IncomeMeasureSpecificDecileImpacts(income_change=IncomeMeasureSpecificDecileIncomeChange(relative={1: 0.008709379861137914, 2: 0.009055801198624003, 3: 0.012492298883059996, 4: 0.011526120801509328, 5: 0.013211703237973082, 6: 0.015499285448067033, 7: 0.01507564337455649, 8: 0.013872555873086258, 9: 0.01486308861202786, 10: 0.013423195198765777}, average={1: 369.7032427197275, 2: 348.23782779938443, 3: 552.8656647582718, 4: 568.6862981673706, 5: 788.7199254212952, 6: 1082.0251273410129, 7: 995.5414649462065, 8: 980.0266932010006, 9: 1104.9136440223838, 10: 1148.3564916388677}), winners_and_losers=IncomeMeasureSpecificDecileWinnersLosers(deciles={1: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=2.6088522714454665e-05, lose_share=2.6088522714454665e-05, no_change_share=0.4508804429091072, gain_share=0.5490934685681783, gain_less_than_5_percent_share=0.5339710702731965, gain_more_than_5_percent_share=0.015122398294981835), 2: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.494450094962446, gain_share=0.505549905037554, gain_less_than_5_percent_share=0.4987036905338977, gain_more_than_5_percent_share=0.006846214503656335), 3: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.02404055636315165, gain_share=0.9759594436368484, gain_less_than_5_percent_share=0.9651062221540542, gain_more_than_5_percent_share=0.010853221482794195), 4: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=8.272884193213454e-07, lose_share=8.272884193213454e-07, no_change_share=0.36369619644130957, gain_share=0.6363029762702711, gain_less_than_5_percent_share=0.5981897126055431, gain_more_than_5_percent_share=0.038113263664727975), 5: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.00024460254119754784, lose_share=0.00024460254119754784, no_change_share=0.16613074345434808, gain_share=0.8336246540044544, gain_less_than_5_percent_share=0.8172183492970724, gain_more_than_5_percent_share=0.01640630470738194), 6: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.025790631489697343, gain_share=0.9742093685103027, gain_less_than_5_percent_share=0.9603855562910443, gain_more_than_5_percent_share=0.013823812219258384), 7: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=4.163438722119544e-05, lose_share=4.163438722119544e-05, no_change_share=0.08407934672412146, gain_share=0.9158790188886573, gain_less_than_5_percent_share=0.8182000678180964, gain_more_than_5_percent_share=0.09767895107056095), 8: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.056524409525954916, gain_share=0.9434755904740451, gain_less_than_5_percent_share=0.880163733821962, gain_more_than_5_percent_share=0.06331185665208312), 9: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.008053685714292545, lose_share=0.008053685714292545, no_change_share=0.027806404912023186, gain_share=0.9641399093736843, gain_less_than_5_percent_share=0.9093577338323074, gain_more_than_5_percent_share=0.05478217554137677), 10: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0, lose_share=0.0, no_change_share=0.06985295508301145, gain_share=0.9301470449169885, gain_less_than_5_percent_share=0.7369159251943521, gain_more_than_5_percent_share=0.1932311197226364)}, all=IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0, lose_less_than_5_percent_share=0.0008383266758003545, lose_share=0.0008383266758003545, no_change_share=0.16458777279036807, gain_share=0.8345739005338316, gain_less_than_5_percent_share=0.7829682328930914, gain_more_than_5_percent_share=0.051605667640740344)))), poverty=[PovertyRateMetricComparison(age_group='child', gender='male', racial_group='all', relative=True, poverty_rate='regular', baseline=0.0937829241156578, reform=0.09370723366737366, change=-7.569044828414917e-05, relative_change=-0.000807081342343345), PovertyRateMetricComparison(age_group='child', gender='male', racial_group='all', relative=True, poverty_rate='deep', baseline=0.006947669200599194, reform=0.0069471439346671104, change=-5.252659320831299e-07, relative_change=-7.560318675475064e-05), PovertyRateMetricComparison(age_group='child', gender='male', racial_group='all', relative=False, poverty_rate='regular', baseline=770371.125, reform=769749.375, change=-621.75, relative_change=-0.000807078536335328), PovertyRateMetricComparison(age_group='child', gender='male', racial_group='all', relative=False, poverty_rate='deep', baseline=57070.984375, reform=57066.66796875, change=-4.31640625, relative_change=-7.5632237594465e-05), PovertyRateMetricComparison(age_group='child', gender='female', racial_group='all', relative=True, poverty_rate='regular', baseline=0.08119998127222061, reform=0.0811329185962677, change=-6.706267595291138e-05, relative_change=-0.0008258952145331866), PovertyRateMetricComparison(age_group='child', gender='female', racial_group='all', relative=True, poverty_rate='deep', baseline=0.005070670507848263, reform=0.00507007073611021, change=-5.997717380523682e-07, relative_change=-0.00011828253031311259), PovertyRateMetricComparison(age_group='child', gender='female', racial_group='all', relative=False, poverty_rate='regular', baseline=866217.375, reform=865501.9375, change=-715.4375, relative_change=-0.0008259329824687481), PovertyRateMetricComparison(age_group='child', gender='female', racial_group='all', relative=False, poverty_rate='deep', baseline=54092.4140625, reform=54086.015625, change=-6.3984375, relative_change=-0.00011828715007259712), PovertyRateMetricComparison(age_group='child', gender='all', racial_group='all', relative=True, poverty_rate='regular', baseline=0.0866740345954895, reform=0.08660321682691574, change=-7.081776857376099e-05, relative_change=-0.0008170586370447596), PovertyRateMetricComparison(age_group='child', gender='all', racial_group='all', relative=True, poverty_rate='deep', baseline=0.005887233652174473, reform=0.005886665545403957, change=-5.681067705154419e-07, relative_change=-9.649808451302242e-05), PovertyRateMetricComparison(age_group='child', gender='all', racial_group='all', relative=False, poverty_rate='regular', baseline=1636588.5, reform=1635251.25, change=-1337.25, relative_change=-0.0008170960507176972), PovertyRateMetricComparison(age_group='child', gender='all', racial_group='all', relative=False, poverty_rate='deep', baseline=111163.3828125, reform=111152.65625, change=-10.7265625, relative_change=-9.649366750643566e-05), PovertyRateMetricComparison(age_group='working_age', gender='male', racial_group='all', relative=True, poverty_rate='regular', baseline=0.09058031439781189, reform=0.08946093916893005, change=-0.001119375228881836, relative_change=-0.012357820088432772), PovertyRateMetricComparison(age_group='working_age', gender='male', racial_group='all', relative=True, poverty_rate='deep', baseline=0.0320294052362442, reform=0.03202878311276436, change=-6.221234798431396e-07, relative_change=-1.9423510216766375e-05), PovertyRateMetricComparison(age_group='working_age', gender='male', racial_group='all', relative=False, poverty_rate='regular', baseline=2207394.25, reform=2180115.75, change=-27278.5, relative_change=-0.012357783390982377), PovertyRateMetricComparison(age_group='working_age', gender='male', racial_group='all', relative=False, poverty_rate='deep', baseline=780539.625, reform=780524.5, change=-15.125, relative_change=-1.9377619682024472e-05), PovertyRateMetricComparison(age_group='working_age', gender='female', racial_group='all', relative=True, poverty_rate='regular', baseline=0.06885619461536407, reform=0.06755512952804565, change=-0.0013010650873184204, relative_change=-0.018895396334146386), PovertyRateMetricComparison(age_group='working_age', gender='female', racial_group='all', relative=True, poverty_rate='deep', baseline=0.006544755306094885, reform=0.006544151809066534, change=-6.034970283508301e-07, relative_change=-9.221078560245269e-05), PovertyRateMetricComparison(age_group='working_age', gender='female', racial_group='all', relative=False, poverty_rate='regular', baseline=1406585.625, reform=1380007.625, change=-26578.0, relative_change=-0.01889540140864158), PovertyRateMetricComparison(age_group='working_age', gender='female', racial_group='all', relative=False, poverty_rate='deep', baseline=133695.4375, reform=133683.109375, change=-12.328125, relative_change=-9.221051391525608e-05), PovertyRateMetricComparison(age_group='working_age', gender='all', racial_group='all', relative=True, poverty_rate='regular', baseline=0.08067396283149719, reform=0.07947173714637756, change=-0.001202225685119629, relative_change=-0.014902276309776728), PovertyRateMetricComparison(age_group='working_age', gender='all', racial_group='all', relative=True, poverty_rate='deep', baseline=0.02040824294090271, reform=0.020407630130648613, change=-6.128102540969849e-07, relative_change=-3.0027585219929702e-05), PovertyRateMetricComparison(age_group='working_age', gender='all', racial_group='all', relative=False, poverty_rate='regular', baseline=3613979.5, reform=3560123.0, change=-53856.5, relative_change=-0.014902270474970874), PovertyRateMetricComparison(age_group='working_age', gender='all', racial_group='all', relative=False, poverty_rate='deep', baseline=914235.1875, reform=914207.75, change=-27.4375, relative_change=-3.001142416649764e-05), PovertyRateMetricComparison(age_group='senior', gender='male', racial_group='all', relative=True, poverty_rate='regular', baseline=0.019906071946024895, reform=0.01964147388935089, change=-0.0002645980566740036, relative_change=-0.013292328963316242), PovertyRateMetricComparison(age_group='senior', gender='male', racial_group='all', relative=True, poverty_rate='deep', baseline=0.0001492029696237296, reform=0.00014823427773080766, change=-9.686918929219246e-07, relative_change=-0.0064924437855683375), PovertyRateMetricComparison(age_group='senior', gender='male', racial_group='all', relative=False, poverty_rate='regular', baseline=120630.84375, reform=119027.3828125, change=-1603.4609375, relative_change=-0.013292296461285425), PovertyRateMetricComparison(age_group='senior', gender='male', racial_group='all', relative=False, poverty_rate='deep', baseline=904.1703491210938, reform=898.3001098632812, change=-5.8702392578125, relative_change=-0.006492404073545117), PovertyRateMetricComparison(age_group='senior', gender='female', racial_group='all', relative=True, poverty_rate='regular', baseline=0.04476610943675041, reform=0.04424646124243736, change=-0.0005196481943130493, relative_change=-0.011608071392651511), PovertyRateMetricComparison(age_group='senior', gender='female', racial_group='all', relative=True, poverty_rate='deep', baseline=0.0012297447538003325, reform=0.0012286300770938396, change=-1.1146767064929008e-06, relative_change=-0.0009064293244985742), PovertyRateMetricComparison(age_group='senior', gender='female', racial_group='all', relative=False, poverty_rate='regular', baseline=315600.8125, reform=311937.28125, change=-3663.53125, relative_change=-0.011608117295325404), PovertyRateMetricComparison(age_group='senior', gender='female', racial_group='all', relative=False, poverty_rate='deep', baseline=8669.693359375, reform=8661.8349609375, change=-7.8583984375, relative_change=-0.000906421728169001), PovertyRateMetricComparison(age_group='senior', gender='all', racial_group='all', relative=True, poverty_rate='regular', baseline=0.03327473625540733, reform=0.03287297859787941, change=-0.0004017576575279236, relative_change=-0.012073954679735011), PovertyRateMetricComparison(age_group='senior', gender='all', racial_group='all', relative=True, poverty_rate='deep', baseline=0.0007302720914594829, reform=0.0007292248192243278, change=-1.0472722351551056e-06, relative_change=-0.0014340849765490601), PovertyRateMetricComparison(age_group='senior', gender='all', racial_group='all', relative=False, poverty_rate='regular', baseline=436231.65625, reform=430964.59375, change=-5267.0625, relative_change=-0.01207400339828043), PovertyRateMetricComparison(age_group='senior', gender='all', racial_group='all', relative=False, poverty_rate='deep', baseline=9573.8642578125, reform=9560.134765625, change=-13.7294921875, relative_change=-0.0014340596250146758), PovertyRateMetricComparison(age_group='all', gender='male', racial_group='all', relative=True, poverty_rate='regular', baseline=0.08017819374799728, reform=0.0794147327542305, change=-0.0007634609937667847, relative_change=-0.009522052793635733), PovertyRateMetricComparison(age_group='all', gender='male', racial_group='all', relative=True, poverty_rate='deep', baseline=0.021698515862226486, reform=0.021697862073779106, change=-6.537884473800659e-07, relative_change=-3.013056061212938e-05), PovertyRateMetricComparison(age_group='all', gender='male', racial_group='all', relative=False, poverty_rate='regular', baseline=3098396.25, reform=3068893.0, change=-29503.25, relative_change=-0.009522103572130259), PovertyRateMetricComparison(age_group='all', gender='male', racial_group='all', relative=False, poverty_rate='deep', baseline=838514.75, reform=838489.5, change=-25.25, relative_change=-3.0112767843380216e-05), PovertyRateMetricComparison(age_group='all', gender='female', racial_group='all', relative=True, poverty_rate='regular', baseline=0.06785593926906586, reform=0.06704439222812653, change=-0.0008115470409393311, relative_change=-0.011959852736270336), PovertyRateMetricComparison(age_group='all', gender='female', racial_group='all', relative=True, poverty_rate='deep', baseline=0.005150204990059137, reform=0.005149507895112038, change=-6.970949470996857e-07, relative_change=-0.0001353528545844699), PovertyRateMetricComparison(age_group='all', gender='female', racial_group='all', relative=False, poverty_rate='regular', baseline=2588403.75, reform=2557447.0, change=-30956.75, relative_change=-0.011959784094734062), PovertyRateMetricComparison(age_group='all', gender='female', racial_group='all', relative=False, poverty_rate='deep', baseline=196457.53125, reform=196430.9375, change=-26.59375, relative_change=-0.000135366406320959), PovertyRateMetricComparison(age_group='all', gender='all', racial_group='all', relative=True, poverty_rate='regular', baseline=0.07405701279640198, reform=0.07326967269182205, change=-0.0007873401045799255, relative_change=-0.01063154014521874), PovertyRateMetricComparison(age_group='all', gender='all', racial_group='all', relative=True, poverty_rate='deep', baseline=0.013478054665029049, reform=0.013477379456162453, change=-6.752088665962219e-07, relative_change=-5.0096908150117427e-05), PovertyRateMetricComparison(age_group='all', gender='all', racial_group='all', relative=False, poverty_rate='regular', baseline=5686797.5, reform=5626338.5, change=-60459.0, relative_change=-0.010631467007573243), PovertyRateMetricComparison(age_group='all', gender='all', racial_group='all', relative=False, poverty_rate='deep', baseline=1034972.5, reform=1034920.625, change=-51.875, relative_change=-5.012210469360297e-05)], labor_supply=[])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine import Simulation\n", + "\n", + "sim = Simulation({\n", + " \"scope\": \"macro\", # Required for this\n", + " \"country\": \"uk\", # or \"us\"\n", + " \"time_period\": 2025,\n", + " \"reform\": {\n", + " \"gov.hmrc.income_tax.allowances.personal_allowance.amount\": 15_000,\n", + " }\n", + "})\n", + "\n", + "sim.calculate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Output schema\n", + "\n", + "`calculate_economy_comparison` or `calculate` (when `scope=household` and `reform is not None`) return the following schema." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'$defs': {'DecileImpacts': {'properties': {'income': {'$ref': '#/$defs/IncomeMeasureSpecificDecileImpacts'},\n", + " 'wealth': {'anyOf': [{'$ref': '#/$defs/IncomeMeasureSpecificDecileImpacts'},\n", + " {'type': 'null'}]}},\n", + " 'required': ['income', 'wealth'],\n", + " 'title': 'DecileImpacts',\n", + " 'type': 'object'},\n", + " 'FiscalComparison': {'properties': {'baseline': {'$ref': '#/$defs/FiscalSummary'},\n", + " 'reform': {'$ref': '#/$defs/FiscalSummary'},\n", + " 'change': {'$ref': '#/$defs/FiscalSummary'},\n", + " 'relative_change': {'$ref': '#/$defs/FiscalSummary'}},\n", + " 'required': ['baseline', 'reform', 'change', 'relative_change'],\n", + " 'title': 'FiscalComparison',\n", + " 'type': 'object'},\n", + " 'FiscalSummary': {'properties': {'tax_revenue': {'title': 'Tax Revenue',\n", + " 'type': 'number'},\n", + " 'federal_tax': {'title': 'Federal Tax', 'type': 'number'},\n", + " 'federal_balance': {'title': 'Federal Balance', 'type': 'number'},\n", + " 'state_tax': {'title': 'State Tax', 'type': 'number'},\n", + " 'government_spending': {'title': 'Government Spending', 'type': 'number'},\n", + " 'tax_benefit_programs': {'additionalProperties': {'type': 'number'},\n", + " 'title': 'Tax Benefit Programs',\n", + " 'type': 'object'},\n", + " 'household_net_income': {'title': 'Household Net Income',\n", + " 'type': 'number'}},\n", + " 'required': ['tax_revenue',\n", + " 'federal_tax',\n", + " 'federal_balance',\n", + " 'state_tax',\n", + " 'government_spending',\n", + " 'tax_benefit_programs',\n", + " 'household_net_income'],\n", + " 'title': 'FiscalSummary',\n", + " 'type': 'object'},\n", + " 'Headlines': {'properties': {'budgetary_impact': {'title': 'Budgetary Impact',\n", + " 'type': 'number'},\n", + " 'poverty_impact': {'title': 'Poverty Impact', 'type': 'number'},\n", + " 'winner_share': {'title': 'Winner Share', 'type': 'number'}},\n", + " 'required': ['budgetary_impact', 'poverty_impact', 'winner_share'],\n", + " 'title': 'Headlines',\n", + " 'type': 'object'},\n", + " 'IncomeMeasureSpecificDecileImpacts': {'properties': {'income_change': {'$ref': '#/$defs/IncomeMeasureSpecificDecileIncomeChange'},\n", + " 'winners_and_losers': {'$ref': '#/$defs/IncomeMeasureSpecificDecileWinnersLosers'}},\n", + " 'required': ['income_change', 'winners_and_losers'],\n", + " 'title': 'IncomeMeasureSpecificDecileImpacts',\n", + " 'type': 'object'},\n", + " 'IncomeMeasureSpecificDecileIncomeChange': {'properties': {'relative': {'additionalProperties': {'type': 'number'},\n", + " 'title': 'Relative',\n", + " 'type': 'object'},\n", + " 'average': {'additionalProperties': {'type': 'number'},\n", + " 'title': 'Average',\n", + " 'type': 'object'}},\n", + " 'required': ['relative', 'average'],\n", + " 'title': 'IncomeMeasureSpecificDecileIncomeChange',\n", + " 'type': 'object'},\n", + " 'IncomeMeasureSpecificDecileWinnersLosers': {'properties': {'deciles': {'additionalProperties': {'$ref': '#/$defs/IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes'},\n", + " 'title': 'Deciles',\n", + " 'type': 'object'},\n", + " 'all': {'$ref': '#/$defs/IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes'}},\n", + " 'required': ['deciles', 'all'],\n", + " 'title': 'IncomeMeasureSpecificDecileWinnersLosers',\n", + " 'type': 'object'},\n", + " 'IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes': {'properties': {'lose_more_than_5_percent_share': {'title': 'Lose More Than 5 Percent Share',\n", + " 'type': 'number'},\n", + " 'lose_less_than_5_percent_share': {'title': 'Lose Less Than 5 Percent Share',\n", + " 'type': 'number'},\n", + " 'lose_share': {'title': 'Lose Share', 'type': 'number'},\n", + " 'no_change_share': {'title': 'No Change Share', 'type': 'number'},\n", + " 'gain_share': {'title': 'Gain Share', 'type': 'number'},\n", + " 'gain_less_than_5_percent_share': {'title': 'Gain Less Than 5 Percent Share',\n", + " 'type': 'number'},\n", + " 'gain_more_than_5_percent_share': {'title': 'Gain More Than 5 Percent Share',\n", + " 'type': 'number'}},\n", + " 'required': ['lose_more_than_5_percent_share',\n", + " 'lose_less_than_5_percent_share',\n", + " 'lose_share',\n", + " 'no_change_share',\n", + " 'gain_share',\n", + " 'gain_less_than_5_percent_share',\n", + " 'gain_more_than_5_percent_share'],\n", + " 'title': 'IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes',\n", + " 'type': 'object'},\n", + " 'InequalityComparison': {'properties': {'baseline': {'$ref': '#/$defs/InequalitySummary'},\n", + " 'reform': {'$ref': '#/$defs/InequalitySummary'},\n", + " 'change': {'$ref': '#/$defs/InequalitySummary'},\n", + " 'relative_change': {'$ref': '#/$defs/InequalitySummary'}},\n", + " 'required': ['baseline', 'reform', 'change', 'relative_change'],\n", + " 'title': 'InequalityComparison',\n", + " 'type': 'object'},\n", + " 'InequalitySummary': {'properties': {'gini': {'title': 'Gini',\n", + " 'type': 'number'},\n", + " 'top_10_share': {'title': 'Top 10 Share', 'type': 'number'},\n", + " 'top_1_share': {'title': 'Top 1 Share', 'type': 'number'}},\n", + " 'required': ['gini', 'top_10_share', 'top_1_share'],\n", + " 'title': 'InequalitySummary',\n", + " 'type': 'object'},\n", + " 'LaborSupplyMetricImpact': {'properties': {'elasticity': {'enum': ['income',\n", + " 'substitution',\n", + " 'all'],\n", + " 'title': 'Elasticity',\n", + " 'type': 'string'},\n", + " 'decile': {'enum': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'all'],\n", + " 'title': 'Decile'},\n", + " 'unit': {'enum': ['earnings', 'hours'], 'title': 'Unit', 'type': 'string'},\n", + " 'baseline': {'title': 'Baseline', 'type': 'number'},\n", + " 'reform': {'title': 'Reform', 'type': 'number'},\n", + " 'change': {'title': 'Change', 'type': 'number'},\n", + " 'relative_change': {'title': 'Relative Change', 'type': 'number'},\n", + " 'average_change': {'title': 'Average Change', 'type': 'number'}},\n", + " 'required': ['elasticity',\n", + " 'decile',\n", + " 'unit',\n", + " 'baseline',\n", + " 'reform',\n", + " 'change',\n", + " 'relative_change',\n", + " 'average_change'],\n", + " 'title': 'LaborSupplyMetricImpact',\n", + " 'type': 'object'},\n", + " 'PovertyRateMetricComparison': {'properties': {'age_group': {'enum': ['child',\n", + " 'working_age',\n", + " 'senior',\n", + " 'all'],\n", + " 'title': 'Age Group',\n", + " 'type': 'string'},\n", + " 'gender': {'enum': ['male', 'female', 'all'],\n", + " 'title': 'Gender',\n", + " 'type': 'string'},\n", + " 'racial_group': {'enum': ['white', 'black', 'hispanic', 'other', 'all'],\n", + " 'title': 'Racial Group',\n", + " 'type': 'string'},\n", + " 'relative': {'title': 'Relative', 'type': 'boolean'},\n", + " 'poverty_rate': {'enum': ['regular',\n", + " 'deep',\n", + " 'uk_hbai_bhc',\n", + " 'uk_hbai_bhc_half',\n", + " 'us_spm',\n", + " 'us_spm_half'],\n", + " 'title': 'Poverty Rate',\n", + " 'type': 'string'},\n", + " 'baseline': {'title': 'Baseline', 'type': 'number'},\n", + " 'reform': {'title': 'Reform', 'type': 'number'},\n", + " 'change': {'title': 'Change', 'type': 'number'},\n", + " 'relative_change': {'title': 'Relative Change', 'type': 'number'}},\n", + " 'required': ['age_group',\n", + " 'gender',\n", + " 'racial_group',\n", + " 'relative',\n", + " 'poverty_rate',\n", + " 'baseline',\n", + " 'reform',\n", + " 'change',\n", + " 'relative_change'],\n", + " 'title': 'PovertyRateMetricComparison',\n", + " 'type': 'object'}},\n", + " 'properties': {'headlines': {'$ref': '#/$defs/Headlines'},\n", + " 'fiscal': {'$ref': '#/$defs/FiscalComparison'},\n", + " 'inequality': {'$ref': '#/$defs/InequalityComparison'},\n", + " 'distributional': {'$ref': '#/$defs/DecileImpacts'},\n", + " 'poverty': {'items': {'$ref': '#/$defs/PovertyRateMetricComparison'},\n", + " 'title': 'Poverty',\n", + " 'type': 'array'},\n", + " 'labor_supply': {'items': {'$ref': '#/$defs/LaborSupplyMetricImpact'},\n", + " 'title': 'Labor Supply',\n", + " 'type': 'array'}},\n", + " 'required': ['headlines',\n", + " 'fiscal',\n", + " 'inequality',\n", + " 'distributional',\n", + " 'poverty',\n", + " 'labor_supply'],\n", + " 'title': 'EconomyComparison',\n", + " 'type': 'object'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine.outputs.macro.comparison.calculate_economy_comparison import EconomyComparison\n", + "\n", + "EconomyComparison.model_json_schema()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/reference/calculate_household_comparison.ipynb b/docs/reference/calculate_household_comparison.ipynb new file mode 100644 index 00000000..f86d3f12 --- /dev/null +++ b/docs/reference/calculate_household_comparison.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare outcomes for specific household scenarios\n", + "\n", + "Use `Simulation.calculate_household_comparison()` to use PolicyEngine's tax-benefit model to compare how taxes, benefits and other household properties change under a change in tax or benefit rules. This notebook demonstrates how to use this function to compare outcomes for specific households." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "HouseholdComparison(full_household_baseline={'people': {'person': {'age': {'2025': 30.0}, 'employment_income': {'2025': 30000.0}, 'employment_income_before_lsr': {'2025': 30000.0}, 'private_pension_income': {'2025': 0.0}, 'pension_income': {'2025': 0.0}, 'state_pension': {'2025': 0.0}, 'self_employment_income': {'2025': 0.0}, 'property_income': {'2025': 0.0}, 'savings_interest_income': {'2025': 0.0}, 'dividend_income': {'2025': 0.0}, 'sublet_income': {'2025': 0.0}, 'miscellaneous_income': {'2025': 0.0}, 'private_transfer_income': {'2025': 0.0}, 'lump_sum_income': {'2025': 0.0}, 'maintenance_income': {'2025': 0.0}, 'other_investment_income': {'2025': 0.0}, 'dla_sc_category': {'2025': 'NONE'}, 'dla_m_category': {'2025': 'NONE'}, 'pip_m_category': {'2025': 'NONE'}, 'pip_dl_category': {'2025': 'NONE'}, 'receives_carers_allowance': {'2025': False}, 'childcare_expenses': {'2025': 0.0}, 'employer_pension_contributions': {'2025': 0.0}, 'employee_pension_contributions': {'2025': 0.0}, 'personal_pension_contributions': {'2025': 0.0}, 'maintenance_expenses': {'2025': 0.0}, 'bi_individual_phaseout': {'2025': 0.0}, 'bi_household_phaseout': {'2025': 0.0}, 'bi_phaseout': {'2025': 0.0}, 'basic_income': {'2025': 0.0}, 'bi_maximum': {'2025': 0.0}, 'attends_private_school': {'2025': False}, 'employer_cost': {'2025': 32884.2}, 'baseline_employer_cost': {'2025': 32884.2}, 'adjusted_employer_cost': {'2025': 32884.2}, 'employer_ni_response_consumer_incidence': {'2025': 0.0}, 'employer_ni_response_capital_incidence': {'2025': 0.0}, 'employer_ni_fixed_employer_cost_change': {'2025': 0.0}, 'marginal_tax_rate': {'2025': 0.27999997}, 'cliff_evaluated': {'2025': True}, 'cliff_gap': {'2025': 0.0}, 'is_on_cliff': {'2025': False}, 'person_id': {'2025': 0.0}, 'people': {'2025': 1.0}, 'raw_person_weight': {'2025': 1.0}, 'person_weight': {'2025': 1.0}, 'adult_index': {'2025': 1.0}, 'birth_year': {'2025': 1995.0}, 'over_16': {'2025': True}, 'is_adult': {'2025': True}, 'is_child': {'2025': False}, 'child_index': {'2025': -1.0}, 'is_eldest_child': {'2025': True}, 'is_benunit_eldest_child': {'2025': False}, 'marital_status': {'2025': 'SINGLE'}, 'current_education': {'2025': 'NOT_IN_EDUCATION'}, 'highest_education': {'2025': 'UPPER_SECONDARY'}, 'in_FE': {'2025': False}, 'in_HE': {'2025': False}, 'gender': {'2025': 'MALE'}, 'is_male': {'2025': True}, 'is_female': {'2025': False}, 'is_household_head': {'2025': True}, 'is_benunit_head': {'2025': True}, 'in_social_housing': {'2025': False}, 'is_WA_adult': {'2025': True}, 'is_young_child': {'2025': False}, 'age_under_18': {'2025': False}, 'age_18_64': {'2025': True}, 'age_over_64': {'2025': False}, 'is_older_child': {'2025': False}, 'is_higher_earner': {'2025': True}, 'person_benunit_id': {'2025': 0.0}, 'person_household_id': {'2025': 0.0}, 'role': {'2025': ''}, 'person_benunit_role': {'2025': ''}, 'person_household_role': {'2025': ''}, 'is_disabled_for_benefits': {'2025': False}, 'is_enhanced_disabled_for_benefits': {'2025': False}, 'is_severely_disabled_for_benefits': {'2025': False}, 'person_state_id': {'2025': 0.0}, 'person_state_role': {'2025': ''}, 'is_blind': {'2025': False}, 'is_carer_for_benefits': {'2025': False}, 'personal_rent': {'2025': 0.0}, 'weekly_childcare_expenses': {'2025': 0.0}, 'earned_income': {'2025': 30000.0}, 'market_income': {'2025': 30000.0}, 'hours_worked': {'2025': 0.0}, 'in_work': {'2025': True}, 'weekly_hours': {'2025': 0.0}, 'employment_status': {'2025': 'UNEMPLOYED'}, 'capital_income': {'2025': 0.0}, 'base_net_income': {'2025': 0.0}, 'is_apprentice': {'2025': False}, 'minimum_wage_category': {'2025': 'OVER_24'}, 'minimum_wage': {'2025': 9.5}, 'income_decile': {'2025': 10.0}, 'household_statutory_maternity_pay': {'2025': 0.0}, 'household_statutory_paternity_pay': {'2025': 0.0}, 'household_statutory_sick_pay': {'2025': 0.0}, 'capital_gains': {'2025': 0.0}, 'is_QYP': {'2025': False}, 'is_child_or_QYP': {'2025': False}, 'employment_benefits': {'2025': 0.0}, 'relative_income_change': {'2025': 0.0}, 'relative_wage_change': {'2025': 0.0}, 'income_elasticity_lsr': {'2025': 0.0}, 'substitution_elasticity_lsr': {'2025': 0.0}, 'employment_income_behavioral_response': {'2025': 0.0}, 'income_support_reported': {'2025': 0.0}, 'attendance_allowance': {'2025': 0.0}, 'attendance_allowance_reported': {'2025': 0.0}, 'aa_category': {'2025': 'NONE'}, 'esa_income_reported': {'2025': 0.0}, 'iidb': {'2025': 0.0}, 'iidb_reported': {'2025': 0.0}, 'jsa_contrib': {'2025': 0.0}, 'jsa_contrib_reported': {'2025': 0.0}, 'maternity_allowance_reported': {'2025': 0.0}, 'maternity_allowance': {'2025': 0.0}, 'ssmg_reported': {'2025': 0.0}, 'ssmg': {'2025': 0.0}, 'council_tax_benefit_reported': {'2025': 0.0}, 'working_tax_credit_reported': {'2025': 0.0}, 'child_tax_credit_reported': {'2025': 0.0}, 'is_CTC_child_limit_exempt': {'2025': True}, 'is_child_for_CTC': {'2025': False}, 'jsa_income_reported': {'2025': 0.0}, 'bsp': {'2025': 0.0}, 'bsp_reported': {'2025': 0.0}, 'incapacity_benefit': {'2025': 0.0}, 'incapacity_benefit_reported': {'2025': 0.0}, 'sda': {'2025': 0.0}, 'sda_reported': {'2025': 0.0}, 'carers_allowance': {'2025': 0.0}, 'care_hours': {'2025': 0.0}, 'carers_allowance_reported': {'2025': 0.0}, 'armed_forces_independence_payment': {'2025': 0.0}, 'esa_contrib': {'2025': 0.0}, 'esa_contrib_reported': {'2025': 0.0}, 'esa': {'2025': 0.0}, 'afcs': {'2025': 0.0}, 'afcs_reported': {'2025': 0.0}, 'student_loans': {'2025': 0.0}, 'adult_ema': {'2025': 0.0}, 'child_ema': {'2025': 0.0}, 'access_fund': {'2025': 0.0}, 'education_grants': {'2025': 0.0}, 'student_payments': {'2025': 0.0}, 'state_pension_age': {'2025': 66.0}, 'is_SP_age': {'2025': False}, 'state_pension_type': {'2025': 'NONE'}, 'basic_state_pension': {'2025': 0.0}, 'additional_state_pension': {'2025': 0.0}, 'new_state_pension': {'2025': 0.0}, 'state_pension_reported': {'2025': 0.0}, 'winter_fuel_allowance_reported': {'2025': 0.0}, 'dla_m_reported': {'2025': 0.0}, 'dla_m': {'2025': 0.0}, 'dla_sc_reported': {'2025': 0.0}, 'dla_sc': {'2025': 0.0}, 'dla_sc_middle_plus': {'2025': False}, 'receives_highest_dla_sc': {'2025': False}, 'dla': {'2025': 0.0}, 'housing_benefit_reported': {'2025': 0.0}, 'household_benefits_individual_non_dep_deduction': {'2025': 6476.6}, 'housing_benefit_individual_non_dep_deduction_eligible': {'2025': True}, 'universal_credit_reported': {'2025': 0.0}, 'uc_is_child_born_before_child_limit': {'2025': False}, 'uc_individual_child_element': {'2025': 0.0}, 'uc_individual_disabled_child_element': {'2025': 0.0}, 'uc_individual_severely_disabled_child_element': {'2025': 0.0}, 'uc_is_in_startup_period': {'2025': False}, 'uc_minimum_income_floor': {'2025': 17290.0}, 'uc_mif_applies': {'2025': False}, 'uc_mif_capped_earned_income': {'2025': 30000.0}, 'uc_limited_capability_for_WRA': {'2025': False}, 'uc_individual_non_dep_deduction_eligible': {'2025': True}, 'uc_individual_non_dep_deduction': {'2025': 1125.3458}, 'uc_non_dep_deduction_exempt': {'2025': False}, 'pip_m_reported': {'2025': 0.0}, 'pip_m': {'2025': 0.0}, 'pip_dl_reported': {'2025': 0.0}, 'pip_dl': {'2025': 0.0}, 'receives_enhanced_pip_dl': {'2025': False}, 'pip': {'2025': 0.0}, 'pension_credit_reported': {'2025': 0.0}, 'tax': {'2025': 4880.4033}, 'tax_reported': {'2025': 0.0}, 'tax_modelling': {'2025': 4880.4033}, 'child_benefit_reported': {'2025': 0.0}, 'child_benefit_respective_amount': {'2025': 0.0}, 'relative_capital_gains_mtr_change': {'2025': 0.0}, 'capital_gains_elasticity': {'2025': 0.0}, 'capital_gains_behavioural_response': {'2025': 0.0}, 'capital_gains_before_response': {'2025': 0.0}, 'adult_index_cg': {'2025': 1.0}, 'marginal_tax_rate_on_capital_gains': {'2025': 0.0}, 'capital_gains_tax': {'2025': 0.0}, 'ni_employee': {'2025': 1394.4033}, 'national_insurance': {'2025': 1394.4033}, 'ni_employer': {'2025': 2884.2}, 'ni_self_employed': {'2025': 0.0}, 'total_national_insurance': {'2025': 4278.6035}, 'ni_class_4_maximum': {'2025': 917.73663}, 'ni_class_4': {'2025': 0.0}, 'ni_class_4_main': {'2025': 0.0}, 'ni_class_3': {'2025': 0.0}, 'ni_class_2': {'2025': 0.0}, 'ni_class_1_employee_primary': {'2025': 1394.4033}, 'ni_class_1_income': {'2025': 30000.0}, 'ni_class_1_employee': {'2025': 1394.4033}, 'ni_class_1_employee_additional': {'2025': 0.0}, 'ni_liable': {'2025': True}, 'ni_class_1_employer': {'2025': 2884.2}, 'other_tax_credits': {'2025': 0.0}, 'earned_income_tax': {'2025': 3486.0}, 'total_income': {'2025': 30000.0}, 'income_tax': {'2025': 3486.0}, 'taxed_income': {'2025': 17430.0}, 'adjusted_net_income': {'2025': 30000.0}, 'total_pension_income': {'2025': 0.0}, 'social_security_income': {'2025': 0.0}, 'income_tax_pre_charges': {'2025': 3486.0}, 'personal_allowance': {'2025': 12570.0}, 'blind_persons_allowance': {'2025': 0.0}, 'married_couples_allowance': {'2025': 0.0}, 'married_couples_allowance_deduction': {'2025': 0.0}, 'capped_mcad': {'2025': 0.0}, 'pension_annual_allowance': {'2025': 40000.0}, 'trading_allowance': {'2025': 1000.0}, 'trading_allowance_deduction': {'2025': 0.0}, 'property_allowance': {'2025': 1000.0}, 'property_allowance_deduction': {'2025': 0.0}, 'savings_allowance': {'2025': 1000.0}, 'dividend_allowance': {'2025': 500.0}, 'gift_aid': {'2025': 0.0}, 'covenanted_payments': {'2025': 0.0}, 'charitable_investment_gifts': {'2025': 0.0}, 'other_deductions': {'2025': 0.0}, 'allowances': {'2025': 12570.0}, 'unused_personal_allowance': {'2025': 0.0}, 'meets_marriage_allowance_income_conditions': {'2025': True}, 'partners_unused_personal_allowance': {'2025': 0.0}, 'marriage_allowance': {'2025': 0.0}, 'received_allowances': {'2025': 12570.0}, 'received_allowances_savings_income': {'2025': 0.0}, 'received_allowances_dividend_income': {'2025': 0.0}, 'received_allowances_earned_income': {'2025': 12570.0}, 'savings_income_tax': {'2025': 0.0}, 'dividend_income_tax': {'2025': 0.0}, 'loss_relief': {'2025': 0.0}, 'capital_allowances': {'2025': 0.0}, 'deficiency_relief': {'2025': 0.0}, 'employment_deductions': {'2025': 0.0}, 'employment_expenses': {'2025': 0.0}, 'CB_HITC': {'2025': 0.0}, 'higher_rate_earned_income': {'2025': 0.0}, 'add_rate_earned_income': {'2025': 0.0}, 'earned_taxable_income': {'2025': 17430.0}, 'basic_rate_earned_income': {'2025': 17430.0}, 'taxable_pension_income': {'2025': 0.0}, 'taxable_miscellaneous_income': {'2025': 0.0}, 'taxed_dividend_income': {'2025': 0.0}, 'taxable_dividend_income': {'2025': 0.0}, 'taxable_social_security_income': {'2025': 0.0}, 'taxable_employment_income': {'2025': 30000.0}, 'trading_loss': {'2025': 0.0}, 'taxable_self_employment_income': {'2025': 0.0}, 'taxable_property_income': {'2025': 0.0}, 'individual_savings_account_interest_income': {'2025': 0.0}, 'taxable_savings_interest_income': {'2025': 0.0}, 'tax_free_savings_income': {'2025': 0.0}, 'higher_rate_earned_income_tax': {'2025': 0.0}, 'add_rate_earned_income_tax': {'2025': 0.0}, 'tax_band': {'2025': 'BASIC'}, 'basic_rate_earned_income_tax': {'2025': 3486.0}, 'basic_rate_savings_income_pre_starter': {'2025': 0.0}, 'taxed_savings_income': {'2025': 0.0}, 'higher_rate_savings_income': {'2025': 0.0}, 'savings_starter_rate_income': {'2025': 0.0}, 'add_rate_savings_income': {'2025': 0.0}, 'basic_rate_savings_income': {'2025': 0.0}, 'personal_pension_contributions_tax': {'2025': 0.0}, 'pension_contributions_relief': {'2025': 0.0}, 'pension_contributions': {'2025': 0.0}, 'statutory_maternity_pay': {'2025': 0.0}, 'statutory_sick_pay': {'2025': 0.0}, 'pays_scottish_income_tax': {'2025': False}}}}, full_household_reform={'people': {'person': {'age': {'2025': 30.0}, 'employment_income': {'2025': 30000.0}, 'employment_income_before_lsr': {'2025': 30000.0}, 'private_pension_income': {'2025': 0.0}, 'pension_income': {'2025': 0.0}, 'state_pension': {'2025': 0.0}, 'self_employment_income': {'2025': 0.0}, 'property_income': {'2025': 0.0}, 'savings_interest_income': {'2025': 0.0}, 'dividend_income': {'2025': 0.0}, 'sublet_income': {'2025': 0.0}, 'miscellaneous_income': {'2025': 0.0}, 'private_transfer_income': {'2025': 0.0}, 'lump_sum_income': {'2025': 0.0}, 'maintenance_income': {'2025': 0.0}, 'other_investment_income': {'2025': 0.0}, 'dla_sc_category': {'2025': 'NONE'}, 'dla_m_category': {'2025': 'NONE'}, 'pip_m_category': {'2025': 'NONE'}, 'pip_dl_category': {'2025': 'NONE'}, 'receives_carers_allowance': {'2025': False}, 'childcare_expenses': {'2025': 0.0}, 'employer_pension_contributions': {'2025': 0.0}, 'employee_pension_contributions': {'2025': 0.0}, 'personal_pension_contributions': {'2025': 0.0}, 'maintenance_expenses': {'2025': 0.0}, 'bi_individual_phaseout': {'2025': 0.0}, 'bi_household_phaseout': {'2025': 0.0}, 'bi_phaseout': {'2025': 0.0}, 'basic_income': {'2025': 0.0}, 'bi_maximum': {'2025': 0.0}, 'attends_private_school': {'2025': False}, 'employer_cost': {'2025': 32884.2}, 'baseline_employer_cost': {'2025': 32884.2}, 'adjusted_employer_cost': {'2025': 32884.2}, 'employer_ni_response_consumer_incidence': {'2025': 0.0}, 'employer_ni_response_capital_incidence': {'2025': 0.0}, 'employer_ni_fixed_employer_cost_change': {'2025': 0.0}, 'marginal_tax_rate': {'2025': 0.27999997}, 'cliff_evaluated': {'2025': True}, 'cliff_gap': {'2025': 0.0}, 'is_on_cliff': {'2025': False}, 'person_id': {'2025': 0.0}, 'people': {'2025': 1.0}, 'raw_person_weight': {'2025': 1.0}, 'person_weight': {'2025': 1.0}, 'adult_index': {'2025': 1.0}, 'birth_year': {'2025': 1995.0}, 'over_16': {'2025': True}, 'is_adult': {'2025': True}, 'is_child': {'2025': False}, 'child_index': {'2025': -1.0}, 'is_eldest_child': {'2025': True}, 'is_benunit_eldest_child': {'2025': False}, 'marital_status': {'2025': 'SINGLE'}, 'current_education': {'2025': 'NOT_IN_EDUCATION'}, 'highest_education': {'2025': 'UPPER_SECONDARY'}, 'in_FE': {'2025': False}, 'in_HE': {'2025': False}, 'gender': {'2025': 'MALE'}, 'is_male': {'2025': True}, 'is_female': {'2025': False}, 'is_household_head': {'2025': True}, 'is_benunit_head': {'2025': True}, 'in_social_housing': {'2025': False}, 'is_WA_adult': {'2025': True}, 'is_young_child': {'2025': False}, 'age_under_18': {'2025': False}, 'age_18_64': {'2025': True}, 'age_over_64': {'2025': False}, 'is_older_child': {'2025': False}, 'is_higher_earner': {'2025': True}, 'person_benunit_id': {'2025': 0.0}, 'person_household_id': {'2025': 0.0}, 'role': {'2025': ''}, 'person_benunit_role': {'2025': ''}, 'person_household_role': {'2025': ''}, 'is_disabled_for_benefits': {'2025': False}, 'is_enhanced_disabled_for_benefits': {'2025': False}, 'is_severely_disabled_for_benefits': {'2025': False}, 'person_state_id': {'2025': 0.0}, 'person_state_role': {'2025': ''}, 'is_blind': {'2025': False}, 'is_carer_for_benefits': {'2025': False}, 'personal_rent': {'2025': 0.0}, 'weekly_childcare_expenses': {'2025': 0.0}, 'earned_income': {'2025': 30000.0}, 'market_income': {'2025': 30000.0}, 'hours_worked': {'2025': 0.0}, 'in_work': {'2025': True}, 'weekly_hours': {'2025': 0.0}, 'employment_status': {'2025': 'UNEMPLOYED'}, 'capital_income': {'2025': 0.0}, 'base_net_income': {'2025': 0.0}, 'is_apprentice': {'2025': False}, 'minimum_wage_category': {'2025': 'OVER_24'}, 'minimum_wage': {'2025': 9.5}, 'income_decile': {'2025': 10.0}, 'household_statutory_maternity_pay': {'2025': 0.0}, 'household_statutory_paternity_pay': {'2025': 0.0}, 'household_statutory_sick_pay': {'2025': 0.0}, 'capital_gains': {'2025': 0.0}, 'is_QYP': {'2025': False}, 'is_child_or_QYP': {'2025': False}, 'employment_benefits': {'2025': 0.0}, 'relative_income_change': {'2025': 0.019470373}, 'relative_wage_change': {'2025': 0.0}, 'income_elasticity_lsr': {'2025': 0.0}, 'substitution_elasticity_lsr': {'2025': 0.0}, 'employment_income_behavioral_response': {'2025': 0.0}, 'income_support_reported': {'2025': 0.0}, 'attendance_allowance': {'2025': 0.0}, 'attendance_allowance_reported': {'2025': 0.0}, 'aa_category': {'2025': 'NONE'}, 'esa_income_reported': {'2025': 0.0}, 'iidb': {'2025': 0.0}, 'iidb_reported': {'2025': 0.0}, 'jsa_contrib': {'2025': 0.0}, 'jsa_contrib_reported': {'2025': 0.0}, 'maternity_allowance_reported': {'2025': 0.0}, 'maternity_allowance': {'2025': 0.0}, 'ssmg_reported': {'2025': 0.0}, 'ssmg': {'2025': 0.0}, 'council_tax_benefit_reported': {'2025': 0.0}, 'working_tax_credit_reported': {'2025': 0.0}, 'child_tax_credit_reported': {'2025': 0.0}, 'is_CTC_child_limit_exempt': {'2025': True}, 'is_child_for_CTC': {'2025': False}, 'jsa_income_reported': {'2025': 0.0}, 'bsp': {'2025': 0.0}, 'bsp_reported': {'2025': 0.0}, 'incapacity_benefit': {'2025': 0.0}, 'incapacity_benefit_reported': {'2025': 0.0}, 'sda': {'2025': 0.0}, 'sda_reported': {'2025': 0.0}, 'carers_allowance': {'2025': 0.0}, 'care_hours': {'2025': 0.0}, 'carers_allowance_reported': {'2025': 0.0}, 'armed_forces_independence_payment': {'2025': 0.0}, 'esa_contrib': {'2025': 0.0}, 'esa_contrib_reported': {'2025': 0.0}, 'esa': {'2025': 0.0}, 'afcs': {'2025': 0.0}, 'afcs_reported': {'2025': 0.0}, 'student_loans': {'2025': 0.0}, 'adult_ema': {'2025': 0.0}, 'child_ema': {'2025': 0.0}, 'access_fund': {'2025': 0.0}, 'education_grants': {'2025': 0.0}, 'student_payments': {'2025': 0.0}, 'state_pension_age': {'2025': 66.0}, 'is_SP_age': {'2025': False}, 'state_pension_type': {'2025': 'NONE'}, 'basic_state_pension': {'2025': 0.0}, 'additional_state_pension': {'2025': 0.0}, 'new_state_pension': {'2025': 0.0}, 'state_pension_reported': {'2025': 0.0}, 'winter_fuel_allowance_reported': {'2025': 0.0}, 'dla_m_reported': {'2025': 0.0}, 'dla_m': {'2025': 0.0}, 'dla_sc_reported': {'2025': 0.0}, 'dla_sc': {'2025': 0.0}, 'dla_sc_middle_plus': {'2025': False}, 'receives_highest_dla_sc': {'2025': False}, 'dla': {'2025': 0.0}, 'housing_benefit_reported': {'2025': 0.0}, 'household_benefits_individual_non_dep_deduction': {'2025': 6476.6}, 'housing_benefit_individual_non_dep_deduction_eligible': {'2025': True}, 'universal_credit_reported': {'2025': 0.0}, 'uc_is_child_born_before_child_limit': {'2025': False}, 'uc_individual_child_element': {'2025': 0.0}, 'uc_individual_disabled_child_element': {'2025': 0.0}, 'uc_individual_severely_disabled_child_element': {'2025': 0.0}, 'uc_is_in_startup_period': {'2025': False}, 'uc_minimum_income_floor': {'2025': 17290.0}, 'uc_mif_applies': {'2025': False}, 'uc_mif_capped_earned_income': {'2025': 30000.0}, 'uc_limited_capability_for_WRA': {'2025': False}, 'uc_individual_non_dep_deduction_eligible': {'2025': True}, 'uc_individual_non_dep_deduction': {'2025': 1125.3458}, 'uc_non_dep_deduction_exempt': {'2025': False}, 'pip_m_reported': {'2025': 0.0}, 'pip_m': {'2025': 0.0}, 'pip_dl_reported': {'2025': 0.0}, 'pip_dl': {'2025': 0.0}, 'receives_enhanced_pip_dl': {'2025': False}, 'pip': {'2025': 0.0}, 'pension_credit_reported': {'2025': 0.0}, 'tax': {'2025': 4394.4033}, 'tax_reported': {'2025': 0.0}, 'tax_modelling': {'2025': 4394.4033}, 'child_benefit_reported': {'2025': 0.0}, 'child_benefit_respective_amount': {'2025': 0.0}, 'relative_capital_gains_mtr_change': {'2025': 0.0}, 'capital_gains_elasticity': {'2025': 0.0}, 'capital_gains_behavioural_response': {'2025': 0.0}, 'capital_gains_before_response': {'2025': 0.0}, 'adult_index_cg': {'2025': 1.0}, 'marginal_tax_rate_on_capital_gains': {'2025': 0.0}, 'capital_gains_tax': {'2025': 0.0}, 'ni_employee': {'2025': 1394.4033}, 'national_insurance': {'2025': 1394.4033}, 'ni_employer': {'2025': 2884.2}, 'ni_self_employed': {'2025': 0.0}, 'total_national_insurance': {'2025': 4278.6035}, 'ni_class_4_maximum': {'2025': 917.73663}, 'ni_class_4': {'2025': 0.0}, 'ni_class_4_main': {'2025': 0.0}, 'ni_class_3': {'2025': 0.0}, 'ni_class_2': {'2025': 0.0}, 'ni_class_1_employee_primary': {'2025': 1394.4033}, 'ni_class_1_income': {'2025': 30000.0}, 'ni_class_1_employee': {'2025': 1394.4033}, 'ni_class_1_employee_additional': {'2025': 0.0}, 'ni_liable': {'2025': True}, 'ni_class_1_employer': {'2025': 2884.2}, 'other_tax_credits': {'2025': 0.0}, 'earned_income_tax': {'2025': 3000.0}, 'total_income': {'2025': 30000.0}, 'income_tax': {'2025': 3000.0}, 'taxed_income': {'2025': 15000.0}, 'adjusted_net_income': {'2025': 30000.0}, 'total_pension_income': {'2025': 0.0}, 'social_security_income': {'2025': 0.0}, 'income_tax_pre_charges': {'2025': 3000.0}, 'personal_allowance': {'2025': 15000.0}, 'blind_persons_allowance': {'2025': 0.0}, 'married_couples_allowance': {'2025': 0.0}, 'married_couples_allowance_deduction': {'2025': 0.0}, 'capped_mcad': {'2025': 0.0}, 'pension_annual_allowance': {'2025': 40000.0}, 'trading_allowance': {'2025': 1000.0}, 'trading_allowance_deduction': {'2025': 0.0}, 'property_allowance': {'2025': 1000.0}, 'property_allowance_deduction': {'2025': 0.0}, 'savings_allowance': {'2025': 1000.0}, 'dividend_allowance': {'2025': 500.0}, 'gift_aid': {'2025': 0.0}, 'covenanted_payments': {'2025': 0.0}, 'charitable_investment_gifts': {'2025': 0.0}, 'other_deductions': {'2025': 0.0}, 'allowances': {'2025': 15000.0}, 'unused_personal_allowance': {'2025': 0.0}, 'meets_marriage_allowance_income_conditions': {'2025': True}, 'partners_unused_personal_allowance': {'2025': 0.0}, 'marriage_allowance': {'2025': 0.0}, 'received_allowances': {'2025': 15000.0}, 'received_allowances_savings_income': {'2025': 0.0}, 'received_allowances_dividend_income': {'2025': 0.0}, 'received_allowances_earned_income': {'2025': 15000.0}, 'savings_income_tax': {'2025': 0.0}, 'dividend_income_tax': {'2025': 0.0}, 'loss_relief': {'2025': 0.0}, 'capital_allowances': {'2025': 0.0}, 'deficiency_relief': {'2025': 0.0}, 'employment_deductions': {'2025': 0.0}, 'employment_expenses': {'2025': 0.0}, 'CB_HITC': {'2025': 0.0}, 'higher_rate_earned_income': {'2025': 0.0}, 'add_rate_earned_income': {'2025': 0.0}, 'earned_taxable_income': {'2025': 15000.0}, 'basic_rate_earned_income': {'2025': 15000.0}, 'taxable_pension_income': {'2025': 0.0}, 'taxable_miscellaneous_income': {'2025': 0.0}, 'taxed_dividend_income': {'2025': 0.0}, 'taxable_dividend_income': {'2025': 0.0}, 'taxable_social_security_income': {'2025': 0.0}, 'taxable_employment_income': {'2025': 30000.0}, 'trading_loss': {'2025': 0.0}, 'taxable_self_employment_income': {'2025': 0.0}, 'taxable_property_income': {'2025': 0.0}, 'individual_savings_account_interest_income': {'2025': 0.0}, 'taxable_savings_interest_income': {'2025': 0.0}, 'tax_free_savings_income': {'2025': 0.0}, 'higher_rate_earned_income_tax': {'2025': 0.0}, 'add_rate_earned_income_tax': {'2025': 0.0}, 'tax_band': {'2025': 'BASIC'}, 'basic_rate_earned_income_tax': {'2025': 3000.0}, 'basic_rate_savings_income_pre_starter': {'2025': 0.0}, 'taxed_savings_income': {'2025': 0.0}, 'higher_rate_savings_income': {'2025': 0.0}, 'savings_starter_rate_income': {'2025': 0.0}, 'add_rate_savings_income': {'2025': 0.0}, 'basic_rate_savings_income': {'2025': 0.0}, 'personal_pension_contributions_tax': {'2025': 0.0}, 'pension_contributions_relief': {'2025': 0.0}, 'pension_contributions': {'2025': 0.0}, 'statutory_maternity_pay': {'2025': 0.0}, 'statutory_sick_pay': {'2025': 0.0}, 'pays_scottish_income_tax': {'2025': False}}}}, change={'people': {'person': {'age': {'2025': 0.0}, 'employment_income': {'2025': 0.0}, 'employment_income_before_lsr': {'2025': 0.0}, 'private_pension_income': {'2025': 0.0}, 'pension_income': {'2025': 0.0}, 'state_pension': {'2025': 0.0}, 'self_employment_income': {'2025': 0.0}, 'property_income': {'2025': 0.0}, 'savings_interest_income': {'2025': 0.0}, 'dividend_income': {'2025': 0.0}, 'sublet_income': {'2025': 0.0}, 'miscellaneous_income': {'2025': 0.0}, 'private_transfer_income': {'2025': 0.0}, 'lump_sum_income': {'2025': 0.0}, 'maintenance_income': {'2025': 0.0}, 'other_investment_income': {'2025': 0.0}, 'dla_sc_category': {'2025': 0.0}, 'dla_m_category': {'2025': 0.0}, 'pip_m_category': {'2025': 0.0}, 'pip_dl_category': {'2025': 0.0}, 'receives_carers_allowance': {'2025': 0.0}, 'childcare_expenses': {'2025': 0.0}, 'employer_pension_contributions': {'2025': 0.0}, 'employee_pension_contributions': {'2025': 0.0}, 'personal_pension_contributions': {'2025': 0.0}, 'maintenance_expenses': {'2025': 0.0}, 'bi_individual_phaseout': {'2025': 0.0}, 'bi_household_phaseout': {'2025': 0.0}, 'bi_phaseout': {'2025': 0.0}, 'basic_income': {'2025': 0.0}, 'bi_maximum': {'2025': 0.0}, 'attends_private_school': {'2025': 0.0}, 'employer_cost': {'2025': 0.0}, 'baseline_employer_cost': {'2025': 0.0}, 'adjusted_employer_cost': {'2025': 0.0}, 'employer_ni_response_consumer_incidence': {'2025': 0.0}, 'employer_ni_response_capital_incidence': {'2025': 0.0}, 'employer_ni_fixed_employer_cost_change': {'2025': 0.0}, 'marginal_tax_rate': {'2025': 0.0}, 'cliff_evaluated': {'2025': 0.0}, 'cliff_gap': {'2025': 0.0}, 'is_on_cliff': {'2025': 0.0}, 'person_id': {'2025': 0.0}, 'people': {'2025': 0.0}, 'raw_person_weight': {'2025': 0.0}, 'person_weight': {'2025': 0.0}, 'adult_index': {'2025': 0.0}, 'birth_year': {'2025': 0.0}, 'over_16': {'2025': 0.0}, 'is_adult': {'2025': 0.0}, 'is_child': {'2025': 0.0}, 'child_index': {'2025': 0.0}, 'is_eldest_child': {'2025': 0.0}, 'is_benunit_eldest_child': {'2025': 0.0}, 'marital_status': {'2025': 0.0}, 'current_education': {'2025': 0.0}, 'highest_education': {'2025': 0.0}, 'in_FE': {'2025': 0.0}, 'in_HE': {'2025': 0.0}, 'gender': {'2025': 0.0}, 'is_male': {'2025': 0.0}, 'is_female': {'2025': 0.0}, 'is_household_head': {'2025': 0.0}, 'is_benunit_head': {'2025': 0.0}, 'in_social_housing': {'2025': 0.0}, 'is_WA_adult': {'2025': 0.0}, 'is_young_child': {'2025': 0.0}, 'age_under_18': {'2025': 0.0}, 'age_18_64': {'2025': 0.0}, 'age_over_64': {'2025': 0.0}, 'is_older_child': {'2025': 0.0}, 'is_higher_earner': {'2025': 0.0}, 'person_benunit_id': {'2025': 0.0}, 'person_household_id': {'2025': 0.0}, 'role': {'2025': 0.0}, 'person_benunit_role': {'2025': 0.0}, 'person_household_role': {'2025': 0.0}, 'is_disabled_for_benefits': {'2025': 0.0}, 'is_enhanced_disabled_for_benefits': {'2025': 0.0}, 'is_severely_disabled_for_benefits': {'2025': 0.0}, 'person_state_id': {'2025': 0.0}, 'person_state_role': {'2025': 0.0}, 'is_blind': {'2025': 0.0}, 'is_carer_for_benefits': {'2025': 0.0}, 'personal_rent': {'2025': 0.0}, 'weekly_childcare_expenses': {'2025': 0.0}, 'earned_income': {'2025': 0.0}, 'market_income': {'2025': 0.0}, 'hours_worked': {'2025': 0.0}, 'in_work': {'2025': 0.0}, 'weekly_hours': {'2025': 0.0}, 'employment_status': {'2025': 0.0}, 'capital_income': {'2025': 0.0}, 'base_net_income': {'2025': 0.0}, 'is_apprentice': {'2025': 0.0}, 'minimum_wage_category': {'2025': 0.0}, 'minimum_wage': {'2025': 0.0}, 'income_decile': {'2025': 0.0}, 'household_statutory_maternity_pay': {'2025': 0.0}, 'household_statutory_paternity_pay': {'2025': 0.0}, 'household_statutory_sick_pay': {'2025': 0.0}, 'capital_gains': {'2025': 0.0}, 'is_QYP': {'2025': 0.0}, 'is_child_or_QYP': {'2025': 0.0}, 'employment_benefits': {'2025': 0.0}, 'relative_income_change': {'2025': 0.019470373}, 'relative_wage_change': {'2025': 0.0}, 'income_elasticity_lsr': {'2025': 0.0}, 'substitution_elasticity_lsr': {'2025': 0.0}, 'employment_income_behavioral_response': {'2025': 0.0}, 'income_support_reported': {'2025': 0.0}, 'attendance_allowance': {'2025': 0.0}, 'attendance_allowance_reported': {'2025': 0.0}, 'aa_category': {'2025': 0.0}, 'esa_income_reported': {'2025': 0.0}, 'iidb': {'2025': 0.0}, 'iidb_reported': {'2025': 0.0}, 'jsa_contrib': {'2025': 0.0}, 'jsa_contrib_reported': {'2025': 0.0}, 'maternity_allowance_reported': {'2025': 0.0}, 'maternity_allowance': {'2025': 0.0}, 'ssmg_reported': {'2025': 0.0}, 'ssmg': {'2025': 0.0}, 'council_tax_benefit_reported': {'2025': 0.0}, 'working_tax_credit_reported': {'2025': 0.0}, 'child_tax_credit_reported': {'2025': 0.0}, 'is_CTC_child_limit_exempt': {'2025': 0.0}, 'is_child_for_CTC': {'2025': 0.0}, 'jsa_income_reported': {'2025': 0.0}, 'bsp': {'2025': 0.0}, 'bsp_reported': {'2025': 0.0}, 'incapacity_benefit': {'2025': 0.0}, 'incapacity_benefit_reported': {'2025': 0.0}, 'sda': {'2025': 0.0}, 'sda_reported': {'2025': 0.0}, 'carers_allowance': {'2025': 0.0}, 'care_hours': {'2025': 0.0}, 'carers_allowance_reported': {'2025': 0.0}, 'armed_forces_independence_payment': {'2025': 0.0}, 'esa_contrib': {'2025': 0.0}, 'esa_contrib_reported': {'2025': 0.0}, 'esa': {'2025': 0.0}, 'afcs': {'2025': 0.0}, 'afcs_reported': {'2025': 0.0}, 'student_loans': {'2025': 0.0}, 'adult_ema': {'2025': 0.0}, 'child_ema': {'2025': 0.0}, 'access_fund': {'2025': 0.0}, 'education_grants': {'2025': 0.0}, 'student_payments': {'2025': 0.0}, 'state_pension_age': {'2025': 0.0}, 'is_SP_age': {'2025': 0.0}, 'state_pension_type': {'2025': 0.0}, 'basic_state_pension': {'2025': 0.0}, 'additional_state_pension': {'2025': 0.0}, 'new_state_pension': {'2025': 0.0}, 'state_pension_reported': {'2025': 0.0}, 'winter_fuel_allowance_reported': {'2025': 0.0}, 'dla_m_reported': {'2025': 0.0}, 'dla_m': {'2025': 0.0}, 'dla_sc_reported': {'2025': 0.0}, 'dla_sc': {'2025': 0.0}, 'dla_sc_middle_plus': {'2025': 0.0}, 'receives_highest_dla_sc': {'2025': 0.0}, 'dla': {'2025': 0.0}, 'housing_benefit_reported': {'2025': 0.0}, 'household_benefits_individual_non_dep_deduction': {'2025': 0.0}, 'housing_benefit_individual_non_dep_deduction_eligible': {'2025': 0.0}, 'universal_credit_reported': {'2025': 0.0}, 'uc_is_child_born_before_child_limit': {'2025': 0.0}, 'uc_individual_child_element': {'2025': 0.0}, 'uc_individual_disabled_child_element': {'2025': 0.0}, 'uc_individual_severely_disabled_child_element': {'2025': 0.0}, 'uc_is_in_startup_period': {'2025': 0.0}, 'uc_minimum_income_floor': {'2025': 0.0}, 'uc_mif_applies': {'2025': 0.0}, 'uc_mif_capped_earned_income': {'2025': 0.0}, 'uc_limited_capability_for_WRA': {'2025': 0.0}, 'uc_individual_non_dep_deduction_eligible': {'2025': 0.0}, 'uc_individual_non_dep_deduction': {'2025': 0.0}, 'uc_non_dep_deduction_exempt': {'2025': 0.0}, 'pip_m_reported': {'2025': 0.0}, 'pip_m': {'2025': 0.0}, 'pip_dl_reported': {'2025': 0.0}, 'pip_dl': {'2025': 0.0}, 'receives_enhanced_pip_dl': {'2025': 0.0}, 'pip': {'2025': 0.0}, 'pension_credit_reported': {'2025': 0.0}, 'tax': {'2025': -486.0}, 'tax_reported': {'2025': 0.0}, 'tax_modelling': {'2025': -486.0}, 'child_benefit_reported': {'2025': 0.0}, 'child_benefit_respective_amount': {'2025': 0.0}, 'relative_capital_gains_mtr_change': {'2025': 0.0}, 'capital_gains_elasticity': {'2025': 0.0}, 'capital_gains_behavioural_response': {'2025': 0.0}, 'capital_gains_before_response': {'2025': 0.0}, 'adult_index_cg': {'2025': 0.0}, 'marginal_tax_rate_on_capital_gains': {'2025': 0.0}, 'capital_gains_tax': {'2025': 0.0}, 'ni_employee': {'2025': 0.0}, 'national_insurance': {'2025': 0.0}, 'ni_employer': {'2025': 0.0}, 'ni_self_employed': {'2025': 0.0}, 'total_national_insurance': {'2025': 0.0}, 'ni_class_4_maximum': {'2025': 0.0}, 'ni_class_4': {'2025': 0.0}, 'ni_class_4_main': {'2025': 0.0}, 'ni_class_3': {'2025': 0.0}, 'ni_class_2': {'2025': 0.0}, 'ni_class_1_employee_primary': {'2025': 0.0}, 'ni_class_1_income': {'2025': 0.0}, 'ni_class_1_employee': {'2025': 0.0}, 'ni_class_1_employee_additional': {'2025': 0.0}, 'ni_liable': {'2025': 0.0}, 'ni_class_1_employer': {'2025': 0.0}, 'other_tax_credits': {'2025': 0.0}, 'earned_income_tax': {'2025': -486.0}, 'total_income': {'2025': 0.0}, 'income_tax': {'2025': -486.0}, 'taxed_income': {'2025': -2430.0}, 'adjusted_net_income': {'2025': 0.0}, 'total_pension_income': {'2025': 0.0}, 'social_security_income': {'2025': 0.0}, 'income_tax_pre_charges': {'2025': -486.0}, 'personal_allowance': {'2025': 2430.0}, 'blind_persons_allowance': {'2025': 0.0}, 'married_couples_allowance': {'2025': 0.0}, 'married_couples_allowance_deduction': {'2025': 0.0}, 'capped_mcad': {'2025': 0.0}, 'pension_annual_allowance': {'2025': 0.0}, 'trading_allowance': {'2025': 0.0}, 'trading_allowance_deduction': {'2025': 0.0}, 'property_allowance': {'2025': 0.0}, 'property_allowance_deduction': {'2025': 0.0}, 'savings_allowance': {'2025': 0.0}, 'dividend_allowance': {'2025': 0.0}, 'gift_aid': {'2025': 0.0}, 'covenanted_payments': {'2025': 0.0}, 'charitable_investment_gifts': {'2025': 0.0}, 'other_deductions': {'2025': 0.0}, 'allowances': {'2025': 2430.0}, 'unused_personal_allowance': {'2025': 0.0}, 'meets_marriage_allowance_income_conditions': {'2025': 0.0}, 'partners_unused_personal_allowance': {'2025': 0.0}, 'marriage_allowance': {'2025': 0.0}, 'received_allowances': {'2025': 2430.0}, 'received_allowances_savings_income': {'2025': 0.0}, 'received_allowances_dividend_income': {'2025': 0.0}, 'received_allowances_earned_income': {'2025': 2430.0}, 'savings_income_tax': {'2025': 0.0}, 'dividend_income_tax': {'2025': 0.0}, 'loss_relief': {'2025': 0.0}, 'capital_allowances': {'2025': 0.0}, 'deficiency_relief': {'2025': 0.0}, 'employment_deductions': {'2025': 0.0}, 'employment_expenses': {'2025': 0.0}, 'CB_HITC': {'2025': 0.0}, 'higher_rate_earned_income': {'2025': 0.0}, 'add_rate_earned_income': {'2025': 0.0}, 'earned_taxable_income': {'2025': -2430.0}, 'basic_rate_earned_income': {'2025': -2430.0}, 'taxable_pension_income': {'2025': 0.0}, 'taxable_miscellaneous_income': {'2025': 0.0}, 'taxed_dividend_income': {'2025': 0.0}, 'taxable_dividend_income': {'2025': 0.0}, 'taxable_social_security_income': {'2025': 0.0}, 'taxable_employment_income': {'2025': 0.0}, 'trading_loss': {'2025': 0.0}, 'taxable_self_employment_income': {'2025': 0.0}, 'taxable_property_income': {'2025': 0.0}, 'individual_savings_account_interest_income': {'2025': 0.0}, 'taxable_savings_interest_income': {'2025': 0.0}, 'tax_free_savings_income': {'2025': 0.0}, 'higher_rate_earned_income_tax': {'2025': 0.0}, 'add_rate_earned_income_tax': {'2025': 0.0}, 'tax_band': {'2025': 0.0}, 'basic_rate_earned_income_tax': {'2025': -486.0}, 'basic_rate_savings_income_pre_starter': {'2025': 0.0}, 'taxed_savings_income': {'2025': 0.0}, 'higher_rate_savings_income': {'2025': 0.0}, 'savings_starter_rate_income': {'2025': 0.0}, 'add_rate_savings_income': {'2025': 0.0}, 'basic_rate_savings_income': {'2025': 0.0}, 'personal_pension_contributions_tax': {'2025': 0.0}, 'pension_contributions_relief': {'2025': 0.0}, 'pension_contributions': {'2025': 0.0}, 'statutory_maternity_pay': {'2025': 0.0}, 'statutory_sick_pay': {'2025': 0.0}, 'pays_scottish_income_tax': {'2025': 0.0}}}})" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine import Simulation\n", + "\n", + "sim = Simulation({\n", + " \"scope\": \"household\", # Required for this\n", + " \"country\": \"uk\", # or \"us\"\n", + " \"time_period\": 2025,\n", + " \"data\": { # Required for this\n", + " \"people\": {\n", + " \"person\": {\n", + " \"age\": {\n", + " \"2025\": 30,\n", + " },\n", + " \"employment_income\": {\n", + " \"2025\": 30_000,\n", + " },\n", + " }\n", + " }\n", + " },\n", + " \"reform\": {\n", + " \"gov.hmrc.income_tax.allowances.personal_allowance.amount\": 15_000,\n", + " }\n", + "})\n", + "\n", + "sim.calculate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Output schema\n", + "\n", + "`calculate_household_comparison` or `calculate` (when `scope=household` and `reform is not None`) return the following schema." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'properties': {'full_household_baseline': {'additionalProperties': {'anyOf': [{'additionalProperties': {'additionalProperties': {'additionalProperties': {'anyOf': [{'type': 'number'},\n", + " {'type': 'string'},\n", + " {'type': 'boolean'},\n", + " {'items': {}, 'type': 'array'},\n", + " {'type': 'null'}]},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " {'items': {'items': {'additionalProperties': {'anyOf': [{'type': 'string'},\n", + " {'type': 'integer'}]},\n", + " 'type': 'object'},\n", + " 'type': 'array'},\n", + " 'type': 'array'}]},\n", + " 'title': 'Full Household Baseline',\n", + " 'type': 'object'},\n", + " 'full_household_reform': {'additionalProperties': {'anyOf': [{'additionalProperties': {'additionalProperties': {'additionalProperties': {'anyOf': [{'type': 'number'},\n", + " {'type': 'string'},\n", + " {'type': 'boolean'},\n", + " {'items': {}, 'type': 'array'},\n", + " {'type': 'null'}]},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " {'items': {'items': {'additionalProperties': {'anyOf': [{'type': 'string'},\n", + " {'type': 'integer'}]},\n", + " 'type': 'object'},\n", + " 'type': 'array'},\n", + " 'type': 'array'}]},\n", + " 'title': 'Full Household Reform',\n", + " 'type': 'object'},\n", + " 'change': {'additionalProperties': {'anyOf': [{'additionalProperties': {'additionalProperties': {'additionalProperties': {'anyOf': [{'type': 'number'},\n", + " {'type': 'string'},\n", + " {'type': 'boolean'},\n", + " {'items': {}, 'type': 'array'},\n", + " {'type': 'null'}]},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " {'items': {'items': {'additionalProperties': {'anyOf': [{'type': 'string'},\n", + " {'type': 'integer'}]},\n", + " 'type': 'object'},\n", + " 'type': 'array'},\n", + " 'type': 'array'}]},\n", + " 'title': 'Change',\n", + " 'type': 'object'}},\n", + " 'required': ['full_household_baseline', 'full_household_reform', 'change'],\n", + " 'title': 'HouseholdComparison',\n", + " 'type': 'object'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine.outputs.household.comparison.calculate_household_comparison import HouseholdComparison\n", + "\n", + "HouseholdComparison.model_json_schema()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/reference/calculate_single_economy.ipynb b/docs/reference/calculate_single_economy.ipynb new file mode 100644 index 00000000..0966e8ee --- /dev/null +++ b/docs/reference/calculate_single_economy.ipynb @@ -0,0 +1,157 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulate outcomes for a large population\n", + "\n", + "Use `Simulation.calculate_single_economy()` to use PolicyEngine's tax-benefit model to compute taxes, benefits and other household properties for a large dataset (usually representing a country). This notebook demonstrates how to use this function." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SingleEconomy(fiscal=FiscalSummary(tax_revenue=658911285719.5891, federal_tax=658911285719.5891, federal_balance=309089098855.4849, state_tax=0.0, government_spending=349822186864.1042, tax_benefit_programs={'income_tax': 333376287037.05945, 'national_insurance': 52985626776.773834, 'ni_employer': 126330649370.35953, 'vat': 211671832822.39133, 'council_tax': 49007055050.00724, 'fuel_duty': 26506672341.204205, 'tax_credits': -34929879.49872104, 'universal_credit': -73459549194.97665, 'child_benefit': -14311471487.935827, 'state_pension': -132795868621.44594, 'pension_credit': -6252358021.417119}, household_net_income=1566028514855.0789), inequality=InequalitySummary(gini=0.36255397405553097, top_10_share=0.3260927004295773, top_1_share=0.13145609415091833), poverty=[PovertyRateMetric(age_group='child', racial_group='all', gender='male', relative=True, poverty_rate='regular', value=0.0937829241156578), PovertyRateMetric(age_group='child', racial_group='all', gender='male', relative=True, poverty_rate='deep', value=0.006947669200599194), PovertyRateMetric(age_group='child', racial_group='all', gender='male', relative=False, poverty_rate='regular', value=770371.125), PovertyRateMetric(age_group='child', racial_group='all', gender='male', relative=False, poverty_rate='deep', value=57070.984375), PovertyRateMetric(age_group='child', racial_group='all', gender='female', relative=True, poverty_rate='regular', value=0.08119998127222061), PovertyRateMetric(age_group='child', racial_group='all', gender='female', relative=True, poverty_rate='deep', value=0.005070670507848263), PovertyRateMetric(age_group='child', racial_group='all', gender='female', relative=False, poverty_rate='regular', value=866217.375), PovertyRateMetric(age_group='child', racial_group='all', gender='female', relative=False, poverty_rate='deep', value=54092.4140625), PovertyRateMetric(age_group='child', racial_group='all', gender='all', relative=True, poverty_rate='regular', value=0.0866740345954895), PovertyRateMetric(age_group='child', racial_group='all', gender='all', relative=True, poverty_rate='deep', value=0.005887233652174473), PovertyRateMetric(age_group='child', racial_group='all', gender='all', relative=False, poverty_rate='regular', value=1636588.5), PovertyRateMetric(age_group='child', racial_group='all', gender='all', relative=False, poverty_rate='deep', value=111163.3828125), PovertyRateMetric(age_group='working_age', racial_group='all', gender='male', relative=True, poverty_rate='regular', value=0.09058031439781189), PovertyRateMetric(age_group='working_age', racial_group='all', gender='male', relative=True, poverty_rate='deep', value=0.0320294052362442), PovertyRateMetric(age_group='working_age', racial_group='all', gender='male', relative=False, poverty_rate='regular', value=2207394.25), PovertyRateMetric(age_group='working_age', racial_group='all', gender='male', relative=False, poverty_rate='deep', value=780539.625), PovertyRateMetric(age_group='working_age', racial_group='all', gender='female', relative=True, poverty_rate='regular', value=0.06885619461536407), PovertyRateMetric(age_group='working_age', racial_group='all', gender='female', relative=True, poverty_rate='deep', value=0.006544755306094885), PovertyRateMetric(age_group='working_age', racial_group='all', gender='female', relative=False, poverty_rate='regular', value=1406585.625), PovertyRateMetric(age_group='working_age', racial_group='all', gender='female', relative=False, poverty_rate='deep', value=133695.4375), PovertyRateMetric(age_group='working_age', racial_group='all', gender='all', relative=True, poverty_rate='regular', value=0.08067396283149719), PovertyRateMetric(age_group='working_age', racial_group='all', gender='all', relative=True, poverty_rate='deep', value=0.02040824294090271), PovertyRateMetric(age_group='working_age', racial_group='all', gender='all', relative=False, poverty_rate='regular', value=3613979.5), PovertyRateMetric(age_group='working_age', racial_group='all', gender='all', relative=False, poverty_rate='deep', value=914235.1875), PovertyRateMetric(age_group='senior', racial_group='all', gender='male', relative=True, poverty_rate='regular', value=0.019906071946024895), PovertyRateMetric(age_group='senior', racial_group='all', gender='male', relative=True, poverty_rate='deep', value=0.0001492029696237296), PovertyRateMetric(age_group='senior', racial_group='all', gender='male', relative=False, poverty_rate='regular', value=120630.84375), PovertyRateMetric(age_group='senior', racial_group='all', gender='male', relative=False, poverty_rate='deep', value=904.1703491210938), PovertyRateMetric(age_group='senior', racial_group='all', gender='female', relative=True, poverty_rate='regular', value=0.04476610943675041), PovertyRateMetric(age_group='senior', racial_group='all', gender='female', relative=True, poverty_rate='deep', value=0.0012297447538003325), PovertyRateMetric(age_group='senior', racial_group='all', gender='female', relative=False, poverty_rate='regular', value=315600.8125), PovertyRateMetric(age_group='senior', racial_group='all', gender='female', relative=False, poverty_rate='deep', value=8669.693359375), PovertyRateMetric(age_group='senior', racial_group='all', gender='all', relative=True, poverty_rate='regular', value=0.03327473625540733), PovertyRateMetric(age_group='senior', racial_group='all', gender='all', relative=True, poverty_rate='deep', value=0.0007302720914594829), PovertyRateMetric(age_group='senior', racial_group='all', gender='all', relative=False, poverty_rate='regular', value=436231.65625), PovertyRateMetric(age_group='senior', racial_group='all', gender='all', relative=False, poverty_rate='deep', value=9573.8642578125), PovertyRateMetric(age_group='all', racial_group='all', gender='male', relative=True, poverty_rate='regular', value=0.08017819374799728), PovertyRateMetric(age_group='all', racial_group='all', gender='male', relative=True, poverty_rate='deep', value=0.021698515862226486), PovertyRateMetric(age_group='all', racial_group='all', gender='male', relative=False, poverty_rate='regular', value=3098396.25), PovertyRateMetric(age_group='all', racial_group='all', gender='male', relative=False, poverty_rate='deep', value=838514.75), PovertyRateMetric(age_group='all', racial_group='all', gender='female', relative=True, poverty_rate='regular', value=0.06785593926906586), PovertyRateMetric(age_group='all', racial_group='all', gender='female', relative=True, poverty_rate='deep', value=0.005150204990059137), PovertyRateMetric(age_group='all', racial_group='all', gender='female', relative=False, poverty_rate='regular', value=2588403.75), PovertyRateMetric(age_group='all', racial_group='all', gender='female', relative=False, poverty_rate='deep', value=196457.53125), PovertyRateMetric(age_group='all', racial_group='all', gender='all', relative=True, poverty_rate='regular', value=0.07405701279640198), PovertyRateMetric(age_group='all', racial_group='all', gender='all', relative=True, poverty_rate='deep', value=0.013478054665029049), PovertyRateMetric(age_group='all', racial_group='all', gender='all', relative=False, poverty_rate='regular', value=5686797.5), PovertyRateMetric(age_group='all', racial_group='all', gender='all', relative=False, poverty_rate='deep', value=1034972.5)])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine import Simulation\n", + "\n", + "sim = Simulation({\n", + " \"scope\": \"macro\", # Required for this\n", + " \"country\": \"uk\", # or \"us\"\n", + " \"time_period\": 2025,\n", + "})\n", + "\n", + "sim.calculate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Output schema\n", + "\n", + "`calculate_single_economy` or `calculate` (when `scope=macro` and `reform=None`) return the following schema." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'$defs': {'FiscalSummary': {'properties': {'tax_revenue': {'title': 'Tax Revenue',\n", + " 'type': 'number'},\n", + " 'federal_tax': {'title': 'Federal Tax', 'type': 'number'},\n", + " 'federal_balance': {'title': 'Federal Balance', 'type': 'number'},\n", + " 'state_tax': {'title': 'State Tax', 'type': 'number'},\n", + " 'government_spending': {'title': 'Government Spending', 'type': 'number'},\n", + " 'tax_benefit_programs': {'additionalProperties': {'type': 'number'},\n", + " 'title': 'Tax Benefit Programs',\n", + " 'type': 'object'},\n", + " 'household_net_income': {'title': 'Household Net Income',\n", + " 'type': 'number'}},\n", + " 'required': ['tax_revenue',\n", + " 'federal_tax',\n", + " 'federal_balance',\n", + " 'state_tax',\n", + " 'government_spending',\n", + " 'tax_benefit_programs',\n", + " 'household_net_income'],\n", + " 'title': 'FiscalSummary',\n", + " 'type': 'object'},\n", + " 'InequalitySummary': {'properties': {'gini': {'title': 'Gini',\n", + " 'type': 'number'},\n", + " 'top_10_share': {'title': 'Top 10 Share', 'type': 'number'},\n", + " 'top_1_share': {'title': 'Top 1 Share', 'type': 'number'}},\n", + " 'required': ['gini', 'top_10_share', 'top_1_share'],\n", + " 'title': 'InequalitySummary',\n", + " 'type': 'object'},\n", + " 'PovertyRateMetric': {'properties': {'age_group': {'enum': ['child',\n", + " 'working_age',\n", + " 'senior',\n", + " 'all'],\n", + " 'title': 'Age Group',\n", + " 'type': 'string'},\n", + " 'racial_group': {'enum': ['white', 'black', 'hispanic', 'other', 'all'],\n", + " 'title': 'Racial Group',\n", + " 'type': 'string'},\n", + " 'gender': {'enum': ['male', 'female', 'all'],\n", + " 'title': 'Gender',\n", + " 'type': 'string'},\n", + " 'relative': {'title': 'Relative', 'type': 'boolean'},\n", + " 'poverty_rate': {'enum': ['regular',\n", + " 'deep',\n", + " 'uk_hbai_bhc',\n", + " 'uk_hbai_bhc_half',\n", + " 'us_spm',\n", + " 'us_spm_half'],\n", + " 'title': 'Poverty Rate',\n", + " 'type': 'string'},\n", + " 'value': {'title': 'Value', 'type': 'number'}},\n", + " 'required': ['age_group',\n", + " 'racial_group',\n", + " 'gender',\n", + " 'relative',\n", + " 'poverty_rate',\n", + " 'value'],\n", + " 'title': 'PovertyRateMetric',\n", + " 'type': 'object'}},\n", + " 'properties': {'fiscal': {'$ref': '#/$defs/FiscalSummary'},\n", + " 'inequality': {'$ref': '#/$defs/InequalitySummary'},\n", + " 'poverty': {'items': {'$ref': '#/$defs/PovertyRateMetric'},\n", + " 'title': 'Poverty',\n", + " 'type': 'array'}},\n", + " 'required': ['fiscal', 'inequality', 'poverty'],\n", + " 'title': 'SingleEconomy',\n", + " 'type': 'object'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine.outputs.macro.single.calculate_single_economy import SingleEconomy\n", + "\n", + "SingleEconomy.model_json_schema()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/reference/calculate_single_household.ipynb b/docs/reference/calculate_single_household.ipynb new file mode 100644 index 00000000..7801a627 --- /dev/null +++ b/docs/reference/calculate_single_household.ipynb @@ -0,0 +1,123 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulate outcomes for specific households\n", + "\n", + "Use `Simulation.calculate_single_household()` to use PolicyEngine's tax-benefit model to compute taxes, benefits and other downstream properties of individual households that you specify. This notebook demonstrates how to use this function to simulate outcomes for specific households." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SingleHousehold(full_household={'people': {'person': {'age': {'2025': 30.0}, 'employment_income': {'2025': 30000.0}, 'employment_income_before_lsr': {'2025': 30000.0}, 'private_pension_income': {'2025': 0.0}, 'pension_income': {'2025': 0.0}, 'state_pension': {'2025': 0.0}, 'self_employment_income': {'2025': 0.0}, 'property_income': {'2025': 0.0}, 'savings_interest_income': {'2025': 0.0}, 'dividend_income': {'2025': 0.0}, 'sublet_income': {'2025': 0.0}, 'miscellaneous_income': {'2025': 0.0}, 'private_transfer_income': {'2025': 0.0}, 'lump_sum_income': {'2025': 0.0}, 'maintenance_income': {'2025': 0.0}, 'other_investment_income': {'2025': 0.0}, 'dla_sc_category': {'2025': 'NONE'}, 'dla_m_category': {'2025': 'NONE'}, 'pip_m_category': {'2025': 'NONE'}, 'pip_dl_category': {'2025': 'NONE'}, 'receives_carers_allowance': {'2025': False}, 'childcare_expenses': {'2025': 0.0}, 'employer_pension_contributions': {'2025': 0.0}, 'employee_pension_contributions': {'2025': 0.0}, 'personal_pension_contributions': {'2025': 0.0}, 'maintenance_expenses': {'2025': 0.0}, 'bi_individual_phaseout': {'2025': 0.0}, 'bi_household_phaseout': {'2025': 0.0}, 'bi_phaseout': {'2025': 0.0}, 'basic_income': {'2025': 0.0}, 'bi_maximum': {'2025': 0.0}, 'attends_private_school': {'2025': False}, 'employer_cost': {'2025': 32884.2}, 'baseline_employer_cost': {'2025': 32884.2}, 'adjusted_employer_cost': {'2025': 32884.2}, 'employer_ni_response_consumer_incidence': {'2025': 0.0}, 'employer_ni_response_capital_incidence': {'2025': 0.0}, 'employer_ni_fixed_employer_cost_change': {'2025': 0.0}, 'marginal_tax_rate': {'2025': 0.27999997}, 'cliff_evaluated': {'2025': True}, 'cliff_gap': {'2025': 0.0}, 'is_on_cliff': {'2025': False}, 'person_id': {'2025': 0.0}, 'people': {'2025': 1.0}, 'raw_person_weight': {'2025': 1.0}, 'person_weight': {'2025': 1.0}, 'adult_index': {'2025': 1.0}, 'birth_year': {'2025': 1995.0}, 'over_16': {'2025': True}, 'is_adult': {'2025': True}, 'is_child': {'2025': False}, 'child_index': {'2025': -1.0}, 'is_eldest_child': {'2025': True}, 'is_benunit_eldest_child': {'2025': False}, 'marital_status': {'2025': 'SINGLE'}, 'current_education': {'2025': 'NOT_IN_EDUCATION'}, 'highest_education': {'2025': 'UPPER_SECONDARY'}, 'in_FE': {'2025': False}, 'in_HE': {'2025': False}, 'gender': {'2025': 'MALE'}, 'is_male': {'2025': True}, 'is_female': {'2025': False}, 'is_household_head': {'2025': True}, 'is_benunit_head': {'2025': True}, 'in_social_housing': {'2025': False}, 'is_WA_adult': {'2025': True}, 'is_young_child': {'2025': False}, 'age_under_18': {'2025': False}, 'age_18_64': {'2025': True}, 'age_over_64': {'2025': False}, 'is_older_child': {'2025': False}, 'is_higher_earner': {'2025': True}, 'person_benunit_id': {'2025': 0.0}, 'person_household_id': {'2025': 0.0}, 'role': {'2025': ''}, 'person_benunit_role': {'2025': ''}, 'person_household_role': {'2025': ''}, 'is_disabled_for_benefits': {'2025': False}, 'is_enhanced_disabled_for_benefits': {'2025': False}, 'is_severely_disabled_for_benefits': {'2025': False}, 'person_state_id': {'2025': 0.0}, 'person_state_role': {'2025': ''}, 'is_blind': {'2025': False}, 'is_carer_for_benefits': {'2025': False}, 'personal_rent': {'2025': 0.0}, 'weekly_childcare_expenses': {'2025': 0.0}, 'earned_income': {'2025': 30000.0}, 'market_income': {'2025': 30000.0}, 'hours_worked': {'2025': 0.0}, 'in_work': {'2025': True}, 'weekly_hours': {'2025': 0.0}, 'employment_status': {'2025': 'UNEMPLOYED'}, 'capital_income': {'2025': 0.0}, 'base_net_income': {'2025': 0.0}, 'is_apprentice': {'2025': False}, 'minimum_wage_category': {'2025': 'OVER_24'}, 'minimum_wage': {'2025': 9.5}, 'income_decile': {'2025': 10.0}, 'household_statutory_maternity_pay': {'2025': 0.0}, 'household_statutory_paternity_pay': {'2025': 0.0}, 'household_statutory_sick_pay': {'2025': 0.0}, 'capital_gains': {'2025': 0.0}, 'is_QYP': {'2025': False}, 'is_child_or_QYP': {'2025': False}, 'employment_benefits': {'2025': 0.0}, 'relative_income_change': {'2025': 0.0}, 'relative_wage_change': {'2025': 0.0}, 'income_elasticity_lsr': {'2025': 0.0}, 'substitution_elasticity_lsr': {'2025': 0.0}, 'employment_income_behavioral_response': {'2025': 0.0}, 'income_support_reported': {'2025': 0.0}, 'attendance_allowance': {'2025': 0.0}, 'attendance_allowance_reported': {'2025': 0.0}, 'aa_category': {'2025': 'NONE'}, 'esa_income_reported': {'2025': 0.0}, 'iidb': {'2025': 0.0}, 'iidb_reported': {'2025': 0.0}, 'jsa_contrib': {'2025': 0.0}, 'jsa_contrib_reported': {'2025': 0.0}, 'maternity_allowance_reported': {'2025': 0.0}, 'maternity_allowance': {'2025': 0.0}, 'ssmg_reported': {'2025': 0.0}, 'ssmg': {'2025': 0.0}, 'council_tax_benefit_reported': {'2025': 0.0}, 'working_tax_credit_reported': {'2025': 0.0}, 'child_tax_credit_reported': {'2025': 0.0}, 'is_CTC_child_limit_exempt': {'2025': True}, 'is_child_for_CTC': {'2025': False}, 'jsa_income_reported': {'2025': 0.0}, 'bsp': {'2025': 0.0}, 'bsp_reported': {'2025': 0.0}, 'incapacity_benefit': {'2025': 0.0}, 'incapacity_benefit_reported': {'2025': 0.0}, 'sda': {'2025': 0.0}, 'sda_reported': {'2025': 0.0}, 'carers_allowance': {'2025': 0.0}, 'care_hours': {'2025': 0.0}, 'carers_allowance_reported': {'2025': 0.0}, 'armed_forces_independence_payment': {'2025': 0.0}, 'esa_contrib': {'2025': 0.0}, 'esa_contrib_reported': {'2025': 0.0}, 'esa': {'2025': 0.0}, 'afcs': {'2025': 0.0}, 'afcs_reported': {'2025': 0.0}, 'student_loans': {'2025': 0.0}, 'adult_ema': {'2025': 0.0}, 'child_ema': {'2025': 0.0}, 'access_fund': {'2025': 0.0}, 'education_grants': {'2025': 0.0}, 'student_payments': {'2025': 0.0}, 'state_pension_age': {'2025': 66.0}, 'is_SP_age': {'2025': False}, 'state_pension_type': {'2025': 'NONE'}, 'basic_state_pension': {'2025': 0.0}, 'additional_state_pension': {'2025': 0.0}, 'new_state_pension': {'2025': 0.0}, 'state_pension_reported': {'2025': 0.0}, 'winter_fuel_allowance_reported': {'2025': 0.0}, 'dla_m_reported': {'2025': 0.0}, 'dla_m': {'2025': 0.0}, 'dla_sc_reported': {'2025': 0.0}, 'dla_sc': {'2025': 0.0}, 'dla_sc_middle_plus': {'2025': False}, 'receives_highest_dla_sc': {'2025': False}, 'dla': {'2025': 0.0}, 'housing_benefit_reported': {'2025': 0.0}, 'household_benefits_individual_non_dep_deduction': {'2025': 6476.6}, 'housing_benefit_individual_non_dep_deduction_eligible': {'2025': True}, 'universal_credit_reported': {'2025': 0.0}, 'uc_is_child_born_before_child_limit': {'2025': False}, 'uc_individual_child_element': {'2025': 0.0}, 'uc_individual_disabled_child_element': {'2025': 0.0}, 'uc_individual_severely_disabled_child_element': {'2025': 0.0}, 'uc_is_in_startup_period': {'2025': False}, 'uc_minimum_income_floor': {'2025': 17290.0}, 'uc_mif_applies': {'2025': False}, 'uc_mif_capped_earned_income': {'2025': 30000.0}, 'uc_limited_capability_for_WRA': {'2025': False}, 'uc_individual_non_dep_deduction_eligible': {'2025': True}, 'uc_individual_non_dep_deduction': {'2025': 1125.3458}, 'uc_non_dep_deduction_exempt': {'2025': False}, 'pip_m_reported': {'2025': 0.0}, 'pip_m': {'2025': 0.0}, 'pip_dl_reported': {'2025': 0.0}, 'pip_dl': {'2025': 0.0}, 'receives_enhanced_pip_dl': {'2025': False}, 'pip': {'2025': 0.0}, 'pension_credit_reported': {'2025': 0.0}, 'tax': {'2025': 4880.4033}, 'tax_reported': {'2025': 0.0}, 'tax_modelling': {'2025': 4880.4033}, 'child_benefit_reported': {'2025': 0.0}, 'child_benefit_respective_amount': {'2025': 0.0}, 'relative_capital_gains_mtr_change': {'2025': 0.0}, 'capital_gains_elasticity': {'2025': 0.0}, 'capital_gains_behavioural_response': {'2025': 0.0}, 'capital_gains_before_response': {'2025': 0.0}, 'adult_index_cg': {'2025': 1.0}, 'marginal_tax_rate_on_capital_gains': {'2025': 0.0}, 'capital_gains_tax': {'2025': 0.0}, 'ni_employee': {'2025': 1394.4033}, 'national_insurance': {'2025': 1394.4033}, 'ni_employer': {'2025': 2884.2}, 'ni_self_employed': {'2025': 0.0}, 'total_national_insurance': {'2025': 4278.6035}, 'ni_class_4_maximum': {'2025': 917.73663}, 'ni_class_4': {'2025': 0.0}, 'ni_class_4_main': {'2025': 0.0}, 'ni_class_3': {'2025': 0.0}, 'ni_class_2': {'2025': 0.0}, 'ni_class_1_employee_primary': {'2025': 1394.4033}, 'ni_class_1_income': {'2025': 30000.0}, 'ni_class_1_employee': {'2025': 1394.4033}, 'ni_class_1_employee_additional': {'2025': 0.0}, 'ni_liable': {'2025': True}, 'ni_class_1_employer': {'2025': 2884.2}, 'other_tax_credits': {'2025': 0.0}, 'earned_income_tax': {'2025': 3486.0}, 'total_income': {'2025': 30000.0}, 'income_tax': {'2025': 3486.0}, 'taxed_income': {'2025': 17430.0}, 'adjusted_net_income': {'2025': 30000.0}, 'total_pension_income': {'2025': 0.0}, 'social_security_income': {'2025': 0.0}, 'income_tax_pre_charges': {'2025': 3486.0}, 'personal_allowance': {'2025': 12570.0}, 'blind_persons_allowance': {'2025': 0.0}, 'married_couples_allowance': {'2025': 0.0}, 'married_couples_allowance_deduction': {'2025': 0.0}, 'capped_mcad': {'2025': 0.0}, 'pension_annual_allowance': {'2025': 40000.0}, 'trading_allowance': {'2025': 1000.0}, 'trading_allowance_deduction': {'2025': 0.0}, 'property_allowance': {'2025': 1000.0}, 'property_allowance_deduction': {'2025': 0.0}, 'savings_allowance': {'2025': 1000.0}, 'dividend_allowance': {'2025': 500.0}, 'gift_aid': {'2025': 0.0}, 'covenanted_payments': {'2025': 0.0}, 'charitable_investment_gifts': {'2025': 0.0}, 'other_deductions': {'2025': 0.0}, 'allowances': {'2025': 12570.0}, 'unused_personal_allowance': {'2025': 0.0}, 'meets_marriage_allowance_income_conditions': {'2025': True}, 'partners_unused_personal_allowance': {'2025': 0.0}, 'marriage_allowance': {'2025': 0.0}, 'received_allowances': {'2025': 12570.0}, 'received_allowances_savings_income': {'2025': 0.0}, 'received_allowances_dividend_income': {'2025': 0.0}, 'received_allowances_earned_income': {'2025': 12570.0}, 'savings_income_tax': {'2025': 0.0}, 'dividend_income_tax': {'2025': 0.0}, 'loss_relief': {'2025': 0.0}, 'capital_allowances': {'2025': 0.0}, 'deficiency_relief': {'2025': 0.0}, 'employment_deductions': {'2025': 0.0}, 'employment_expenses': {'2025': 0.0}, 'CB_HITC': {'2025': 0.0}, 'higher_rate_earned_income': {'2025': 0.0}, 'add_rate_earned_income': {'2025': 0.0}, 'earned_taxable_income': {'2025': 17430.0}, 'basic_rate_earned_income': {'2025': 17430.0}, 'taxable_pension_income': {'2025': 0.0}, 'taxable_miscellaneous_income': {'2025': 0.0}, 'taxed_dividend_income': {'2025': 0.0}, 'taxable_dividend_income': {'2025': 0.0}, 'taxable_social_security_income': {'2025': 0.0}, 'taxable_employment_income': {'2025': 30000.0}, 'trading_loss': {'2025': 0.0}, 'taxable_self_employment_income': {'2025': 0.0}, 'taxable_property_income': {'2025': 0.0}, 'individual_savings_account_interest_income': {'2025': 0.0}, 'taxable_savings_interest_income': {'2025': 0.0}, 'tax_free_savings_income': {'2025': 0.0}, 'higher_rate_earned_income_tax': {'2025': 0.0}, 'add_rate_earned_income_tax': {'2025': 0.0}, 'tax_band': {'2025': 'BASIC'}, 'basic_rate_earned_income_tax': {'2025': 3486.0}, 'basic_rate_savings_income_pre_starter': {'2025': 0.0}, 'taxed_savings_income': {'2025': 0.0}, 'higher_rate_savings_income': {'2025': 0.0}, 'savings_starter_rate_income': {'2025': 0.0}, 'add_rate_savings_income': {'2025': 0.0}, 'basic_rate_savings_income': {'2025': 0.0}, 'personal_pension_contributions_tax': {'2025': 0.0}, 'pension_contributions_relief': {'2025': 0.0}, 'pension_contributions': {'2025': 0.0}, 'statutory_maternity_pay': {'2025': 0.0}, 'statutory_sick_pay': {'2025': 0.0}, 'pays_scottish_income_tax': {'2025': False}}}})" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine import Simulation\n", + "\n", + "sim = Simulation({\n", + " \"scope\": \"household\", # Required for this\n", + " \"country\": \"uk\", # or \"us\"\n", + " \"time_period\": 2025,\n", + " \"data\": { # Required for this\n", + " \"people\": {\n", + " \"person\": {\n", + " \"age\": {\n", + " \"2025\": 30,\n", + " },\n", + " \"employment_income\": {\n", + " \"2025\": 30_000,\n", + " },\n", + " }\n", + " }\n", + " }\n", + "})\n", + "\n", + "sim.calculate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Output schema\n", + "\n", + "`calculate_single_household` or `calculate` (when `scope=household` and `reform=None`) return the following schema." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'description': 'Statistics for a single household scenario.',\n", + " 'properties': {'full_household': {'additionalProperties': {'anyOf': [{'additionalProperties': {'additionalProperties': {'additionalProperties': {'anyOf': [{'type': 'number'},\n", + " {'type': 'string'},\n", + " {'type': 'boolean'},\n", + " {'items': {}, 'type': 'array'},\n", + " {'type': 'null'}]},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " 'type': 'object'},\n", + " {'items': {'items': {'additionalProperties': {'anyOf': [{'type': 'string'},\n", + " {'type': 'integer'}]},\n", + " 'type': 'object'},\n", + " 'type': 'array'},\n", + " 'type': 'array'}]},\n", + " 'title': 'Full Household',\n", + " 'type': 'object'}},\n", + " 'required': ['full_household'],\n", + " 'title': 'SingleHousehold',\n", + " 'type': 'object'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from policyengine.outputs.household.single.calculate_single_household import SingleHousehold\n", + "\n", + "SingleHousehold.model_json_schema()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/reference/create_charts.ipynb b/docs/reference/create_charts.ipynb new file mode 100644 index 00000000..16c0c188 --- /dev/null +++ b/docs/reference/create_charts.ipynb @@ -0,0 +1,7175 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create charts for an economic comparison\n", + "\n", + "This package also comes with utilities that allow you to create charts from the economy comparison operation. In this notebook, we'll walk through them." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# First, set up the simulation\n", + "\n", + "from policyengine import Simulation\n", + "from policyengine.outputs.macro.comparison.charts import *\n", + "\n", + "sim = Simulation({\n", + " \"country\": \"uk\",\n", + " \"scope\": \"macro\",\n", + " \"reform\": {\n", + " \"gov.hmrc.income_tax.allowances.personal_allowance.amount\": 10_000,\n", + " },\n", + " \"title\": \"Lowering the personal allowance to £10,000\" # Required for charts\n", + "})\n", + "\n", + "from policyengine.utils.charts import add_fonts\n", + "\n", + "add_fonts() # Load the right font (Roboto Serif) in this notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Budget\n", + "\n", + "The budget chart shows high-level budget changes under the reform." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "decreasing": { + "marker": { + "color": "#616161" + } + }, + "increasing": { + "marker": { + "color": "#2C6496" + } + }, + "measure": [ + "relative", + "relative", + "total" + ], + "text": [ + "£24.2bn", + "£0.7bn", + "£23.5bn" + ], + "textposition": "inside", + "totals": { + "marker": { + "color": "#2C6496" + } + }, + "type": "waterfall", + "x": [ + "Tax revenues", + "Government spending", + "Public sector net worth" + ], + "y": [ + 24.18759785404004, + 0.7363357242798462, + 23.45126212976019 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would raise £23.5bn" + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "title": { + "text": "" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "title": { + "text": "Budgetary impact (£bn)" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_budget_comparison_chart(sim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is also the budget by program chart, which splits out the budgetary impact by program." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "decreasing": { + "marker": { + "color": "#616161" + } + }, + "increasing": { + "marker": { + "color": "#2C6496" + } + }, + "measure": [ + "relative", + "relative", + "relative", + "relative", + "total" + ], + "text": [ + "£24.2bn", + "-£0.4bn", + "-£0.2bn", + "-£1.0bn", + "£23.0bn" + ], + "textposition": "inside", + "totals": { + "marker": { + "color": "#2C6496" + } + }, + "type": "waterfall", + "x": [ + "Income Tax", + "Universal Credit", + "Pension Credit", + "Other", + "Combined" + ], + "y": [ + 24.2, + -0.4, + -0.2, + -1, + 23 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would raise £23bn" + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "title": { + "text": "" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "title": { + "text": "Budgetary impact (bn)" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_budget_program_comparison_chart(sim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Decile\n", + "\n", + "The decile chart shows the impact of the reform on each decile of the income distribution. You can specify whether this is over income deciles, or wealth deciles, in the UK." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": [ + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161" + ] + }, + "text": [ + "-1.1%", + "-1.5%", + "-1.7%", + "-1.8%", + "-1.5%", + "-1.9%", + "-2.0%", + "-1.9%", + "-1.8%", + "-0.8%" + ], + "type": "bar", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "y": [ + -0.010774457133013601, + -0.01452619007920295, + -0.017437944033923014, + -0.018396321126487758, + -0.015306613953115554, + -0.019266000449108846, + -0.019665841659677847, + -0.018543594207703178, + -0.018167225868890278, + -0.007966273529744838 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would decrease the net income of
households by 1.6% " + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "tickvals": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "title": { + "text": "Income decile" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "tickformat": ".0%", + "ticksuffix": "", + "title": { + "text": "Average change to net income (%)" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_decile_chart(sim, decile_variable=\"income\", relative=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Winners and losers\n", + "\n", + "The winners and losers chart shows in each decile (and overall) the share of people who come out ahead or behind under the reform. Again, you can specify whether the deciles are income or wealth in the UK." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": [ + "#2C6496", + "#D8E6F3", + "#F2F2F2", + "#BDBDBD", + "#616161" + ] + }, + "name": "All deciles", + "orientation": "h", + "showlegend": false, + "text": [ + "0.0%", + "0.1%", + "13.1%", + "74.3%", + "12.5%" + ], + "type": "bar", + "x": [ + 0, + 0.0012506888662903927, + 0.13111063617035676, + 0.7427831391111167, + 0.12485553585223622 + ], + "xaxis": "x", + "y": [ + "All", + "All", + "All", + "All", + "All" + ], + "yaxis": "y" + }, + { + "customdata": [ + "Gain more than 5%, 1: 0.0%", + "Gain more than 5%, 2: 0.0%", + "Gain more than 5%, 3: 0.0%", + "Gain more than 5%, 4: 0.0%", + "Gain more than 5%, 5: 0.0%", + "Gain more than 5%, 6: 0.0%", + "Gain more than 5%, 7: 0.0%", + "Gain more than 5%, 8: 0.0%", + "Gain more than 5%, 9: 0.0%", + "Gain more than 5%, 10: 0.0%", + "Gain less than 5%, 1: 0.0%", + "Gain less than 5%, 2: 0.8%", + "Gain less than 5%, 3: 0.4%", + "Gain less than 5%, 4: 0.0%", + "Gain less than 5%, 5: 0.0%", + "Gain less than 5%, 6: 0.0%", + "Gain less than 5%, 7: 0.0%", + "Gain less than 5%, 8: 0.0%", + "Gain less than 5%, 9: 0.0%", + "Gain less than 5%, 10: 0.0%", + "No change, 1: 62.5%", + "No change, 2: 27.6%", + "No change, 3: 17.2%", + "No change, 4: 10.3%", + "No change, 5: 2.6%", + "No change, 6: 2.9%", + "No change, 7: 1.0%", + "No change, 8: 0.8%", + "No change, 9: 1.5%", + "No change, 10: 9.0%", + "Lose less than 5%, 1: 20.3%", + "Lose less than 5%, 2: 54.3%", + "Lose less than 5%, 3: 45.3%", + "Lose less than 5%, 4: 74.6%", + "Lose less than 5%, 5: 95.7%", + "Lose less than 5%, 6: 78.5%", + "Lose less than 5%, 7: 80.9%", + "Lose less than 5%, 8: 94.4%", + "Lose less than 5%, 9: 97.6%", + "Lose less than 5%, 10: 91.0%", + "Lose more than 5%, 1: 17.1%", + "Lose more than 5%, 2: 17.2%", + "Lose more than 5%, 3: 37.0%", + "Lose more than 5%, 4: 15.1%", + "Lose more than 5%, 5: 1.7%", + "Lose more than 5%, 6: 18.6%", + "Lose more than 5%, 7: 18.1%", + "Lose more than 5%, 8: 4.8%", + "Lose more than 5%, 9: 1.0%", + "Lose more than 5%, 10: 0.0%" + ], + "hovertemplate": "%{customdata}", + "marker": { + "color": [ + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#D8E6F3", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#F2F2F2", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#BDBDBD", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161" + ] + }, + "name": "Deciles", + "orientation": "h", + "text": [ + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.8%", + "0.4%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "0.0%", + "62.5%", + "27.6%", + "17.2%", + "10.3%", + "2.6%", + "2.9%", + "1.0%", + "0.8%", + "1.5%", + "9.0%", + "20.3%", + "54.3%", + "45.3%", + "74.6%", + "95.7%", + "78.5%", + "80.9%", + "94.4%", + "97.6%", + "91.0%", + "17.1%", + "17.2%", + "37.0%", + "15.1%", + "1.7%", + "18.6%", + "18.1%", + "4.8%", + "1.0%", + "0.0%" + ], + "textposition": "inside", + "type": "bar", + "x": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.00003002075376702071, + 0.008309730310565712, + 0.0042514917572317205, + 0, + 0, + 0, + 5.104037721866914e-7, + 1.224587452954663e-7, + 0, + 0, + 0.6251904617648583, + 0.2761051112600827, + 0.17241658338662263, + 0.10326230200712576, + 0.02634261147112231, + 0.029121268727080388, + 0.009779479442778611, + 0.007915780728303014, + 0.014550917092224268, + 0.09022786691788508, + 0.20347253259186693, + 0.5434876317349786, + 0.4532449619985432, + 0.7461001383808286, + 0.9570849978504702, + 0.7850737490397103, + 0.8087431337210494, + 0.9444749389980199, + 0.9758083400649616, + 0.9097721330821149, + 0.17130698488950774, + 0.17209752669437295, + 0.37008696285760245, + 0.15063755961204564, + 0.01657239067840755, + 0.18580498223320932, + 0.1814768764323998, + 0.047609157814931725, + 0.009640742842814045, + 0 + ], + "xaxis": "x2", + "y": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "yaxis": "y2" + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "barmode": "stack", + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "grid": { + "columns": 1, + "rows": 2 + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would raise the net income of 0.1% of
people " + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "anchor": "y", + "fixedrange": true, + "gridcolor": "#F4F4F4", + "matches": "x2", + "showgrid": false, + "showticklabels": false, + "tickformat": ".0%", + "ticksuffix": "", + "title": { + "text": "" + }, + "zerolinecolor": "#F4F4F4" + }, + "xaxis2": { + "anchor": "y2", + "fixedrange": true, + "tickformat": ".0%", + "title": { + "text": "Population share" + } + }, + "yaxis": { + "domain": [ + 0.91, + 1 + ], + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "tickvals": [ + "All" + ], + "title": { + "text": "" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0, + 0.85 + ], + "tickvals": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "title": { + "text": "Population share" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_winners_losers_chart(sim, decile_variable=\"income\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Poverty\n", + "\n", + "The poverty chart shows the impact of the reform on various poverty rates, split out by demographic groups you can specify. You can show the change to poverty rate by age group, gender or racial group (US-only), and you can choose between regular or deep poverty." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": [ + "#2C6496", + "#2C6496", + "#2C6496", + "#2C6496" + ] + }, + "text": [ + "33,440", + "52,656", + "23,791", + "109,889" + ], + "type": "bar", + "x": [ + "child", + "working_age", + "senior", + "all" + ], + "y": [ + 33440.125, + 52656.5, + 23791.21875, + 109889 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would raise the poverty rate by 1.9%" + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "ticktext": [ + "Child", + "Working-age", + "Senior", + "All" + ], + "tickvals": [ + "child", + "working_age", + "senior", + "all" + ], + "title": { + "text": "Group" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "tickformat": ",.0f", + "ticksuffix": "", + "title": { + "text": "Poverty rate change" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_poverty_chart(\n", + " sim,\n", + " age_group=None, # Specify None to show all age groups\n", + " gender=\"all\", # The rest are filters\n", + " racial_group=\"all\",\n", + " rate_relative=False, # Compare how many people are in poverty rather than the rate\n", + " change_relative=False, # Compare the absolute headcount rather than % change\n", + " poverty_rate=\"regular\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inequality\n", + "\n", + "The inequality chart shows the impact of the reform on various inequality measures: the Gini coefficient, the share of income held by the top 10% of households (by income) and the top 1% share." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": [ + "#616161", + "#616161", + "#616161" + ] + }, + "text": [ + "0.2%", + "0.6%", + "1.4%" + ], + "type": "bar", + "x": [ + "Gini index", + "Top 10% share", + "Top 1% share" + ], + "y": [ + 0.002379218659187675, + 0.006010878001505188, + 0.014167378755875062 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would raise inequality" + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "title": { + "text": "" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "tickformat": ".0%", + "ticksuffix": "", + "title": { + "text": "Change (%)" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "create_inequality_chart(sim, relative=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Labor supply\n", + "\n", + "The labor supply chart shows the impact of the reform on labor supply if labor supply response assumptions have been set in the `reform`, split out by groups you can specify. You can show the change to labor supply by decile, the mechanism (or elasticity- e.g. filtering to only substitution effect-powered responses), and also by the unit (hours or earnings, though only earnings in the UK)." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "marker": { + "color": [ + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#616161", + "#2C6496", + "#616161" + ] + }, + "text": [ + "-1.3%", + "-0.1%", + "-0.7%", + "-0.2%", + "-0.1%", + "-0.4%", + "-0.5%", + "-0.5%", + "-0.1%", + "0.4%", + "-0.1%" + ], + "type": "bar", + "x": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + "all" + ], + "y": [ + -0.013388361268997362, + -0.0009001679620899952, + -0.006940002445757689, + -0.002096522479093097, + -0.000590021861392062, + -0.003602100638872149, + -0.005081699001099658, + -0.004559364671289845, + -0.001499923178195422, + 0.0038960671090264246, + -0.0007300784012860403 + ] + } + ], + "layout": { + "annotations": [ + { + "showarrow": false, + "text": "Source: PolicyEngine UK tax-benefit microsimulation model (version 2.18.0)", + "x": 0, + "xanchor": "left", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "font": { + "color": "black", + "family": "Roboto Serif" + }, + "height": 600, + "images": [ + { + "sizex": 0.15, + "sizey": 0.15, + "source": "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png", + "x": 1.1, + "xanchor": "right", + "xref": "paper", + "y": -0.2, + "yanchor": "bottom", + "yref": "paper" + } + ], + "margin": { + "b": 120, + "l": 120, + "r": 120, + "t": 120 + }, + "modebar": { + "activecolor": "#F4F4F4", + "bgcolor": "#F4F4F4", + "color": "#F4F4F4" + }, + "paper_bgcolor": "#F4F4F4", + "plot_bgcolor": "#F4F4F4", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Lowering the personal allowance to £10,000 would lower labor supply by 0.1%" + }, + "uniformtext": { + "minsize": 12, + "mode": "hide" + }, + "width": 800, + "xaxis": { + "gridcolor": "#F4F4F4", + "ticksuffix": "", + "ticktext": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "tickvals": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + "all" + ], + "title": { + "text": "Group" + }, + "zerolinecolor": "#F4F4F4" + }, + "yaxis": { + "gridcolor": "#F4F4F4", + "tickformat": ".0%", + "ticksuffix": "", + "title": { + "text": "Labor supply change (£bn)" + }, + "zerolinecolor": "#616161" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "sim = Simulation({\n", + " \"country\": \"uk\",\n", + " \"scope\": \"macro\",\n", + " \"reform\": {\n", + " \"gov.hmrc.income_tax.allowances.personal_allowance.amount\": 10_000,\n", + " \"gov.simulation.labor_supply_responses.substitution_elasticity\": 0.2,\n", + " },\n", + " \"title\": \"Lowering the personal allowance to £10,000\" # Required for charts\n", + "})\n", + "\n", + "create_labor_supply_chart(\n", + " sim,\n", + " decile=None,\n", + " elasticity=\"all\",\n", + " unit=\"earnings\",\n", + " change_relative=True,\n", + " change_average=False,\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/reference/simulation.ipynb b/docs/reference/simulation.ipynb index ee3c846a..99d2e5ee 100644 --- a/docs/reference/simulation.ipynb +++ b/docs/reference/simulation.ipynb @@ -4,9 +4,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Simulation\n", + "# Simulation interface\n", "\n", - "The `Simulation` class is the core interface of this package. You can initialise it by passing in a dictionary that matches the `SimulationOptions` schema, and then use its `calculate` methods to ask it questions." + "The `Simulation` class is the core interface of this package. You can initialise it by passing in a dictionary that matches the `SimulationOptions` schema, and then use its `calculate` methods to ask it questions.\n", + "\n", + "Some of the options are straightforward and some are more complex. The straightforward ones are:\n", + "\n", + "* `country`: `uk` or `us`.\n", + "* `scope`: `macro` (simulating over large data to represent e.g. a country) or `household` (simulating over specific households you describe).\n", + "* `time_period`: the year to simulate.\n", + "\n", + "The next important features are:\n", + "* `reform`: the policy to use in the reform scenario if we are comparing against a different scenario.\n", + "* `baseline`: the policy to use in the baseline scenario if we are comparing against a different baseline scenario.\n", + "* `data`: either a household (if `scope` is `household`) or a large dataset name (if `scope` is `macro`)." ] }, { @@ -42,6 +53,61 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "## Providing `baseline` and `reform` policies\n", + "\n", + "The `baseline` and `reform` policies are dictionaries that represent the policy to simulate. You don't have to provide a reform policy (if you don't, the simulation will just simulate the baseline policy). You also don't have to provide a baseline policy (if you don't, the simulation will just compare your reform scenario against current law).\n", + "\n", + "If you do, they should each follow this syntax:\n", + "\n", + "```json\n", + "{\n", + " \"gov.hmrc.income_tax.rate\": { // Parameter address, in the country model's `parameters/` folder\n", + " \"2025\": 0.2 // Value to set the parameter to in the year 2025\n", + " }\n", + "}\n", + "```\n", + "\n", + "You can also use this shorthand to set parameters for all years:\n", + "\n", + "```json\n", + "{\n", + " \"gov.hmrc.income_tax.rate\": 0.2\n", + "}\n", + "```\n", + "\n", + "## Providing `data`\n", + "\n", + "If you set `scope` to `macro`, you should provide either:\n", + "\n", + "* A Hugging Face `.h5` dataset address in this format: `\"hf://policyengine/policyengine-us-data/cps_2023.h5\"` (`hf://owner/dataset-name/path.h5`).\n", + "* An instance of `policyengine_core.data.Dataset` (advanced).\n", + "\n", + "See `policyengine.constants` for the available datasets.\n", + "\n", + "If you set `scope` to `household`, you should provide a dictionary that represents a household. This should look like:\n", + "\n", + "```json\n", + "{\n", + " \"people\": { // Entity group\n", + " \"person\": { // Entity name\n", + " \"age\": { // Variable (in the country model's `variables/` folder)\n", + " \"2025\": 30, // Time period and value\n", + " }\n", + " }\n", + " },\n", + " \"households\": {\n", + " \"household\": {\n", + " \"members\": [\"person\"], // Group entities need a `members` field\n", + " \"region\": {\n", + " \"2025\": \"LONDON\",\n", + " }\n", + " }\n", + " }\n", + "}\n", + "```\n", + "\n", + "See the country model's repository for more information on what entity types are available.\n", + "\n", "## Module documentation\n", "\n", "```{eval-rst}\n", diff --git a/policyengine/outputs/household/comparison/calculate_household_comparison.py b/policyengine/outputs/household/comparison/calculate_household_comparison.py index adf81963..48c28f0c 100644 --- a/policyengine/outputs/household/comparison/calculate_household_comparison.py +++ b/policyengine/outputs/household/comparison/calculate_household_comparison.py @@ -8,22 +8,23 @@ from pydantic import BaseModel from policyengine.utils.calculations import get_change from policyengine_core.simulations import Simulation as CountrySimulation +from policyengine.outputs.household.single.calculate_single_household import ( + SingleHousehold, + fill_and_calculate, + FullHouseholdSpecification, +) from typing import Literal, List class HouseholdComparison(BaseModel): - household_net_income: float - """The net income of the household.""" + full_household_baseline: FullHouseholdSpecification + """The full completion of the household under the baseline scenario.""" + full_household_reform: FullHouseholdSpecification + """The full completion of the household under the reform scenario.""" -def calculate_net_income( - baseline: CountrySimulation, - reform: CountrySimulation, -) -> float: - return ( - reform.calculate("household_net_income").sum() - - baseline.calculate("household_net_income").sum() - ) + change: FullHouseholdSpecification + """The change in the household from the baseline to the reform scenario.""" def calculate_household_comparison( @@ -33,11 +34,21 @@ def calculate_household_comparison( if not simulation.is_comparison: raise ValueError("Simulation must be a comparison simulation.") - baseline = simulation.baseline_simulation - reform = simulation.reform_simulation - - net_income = calculate_net_income(baseline, reform) + baseline_household = fill_and_calculate( + simulation.options.data, simulation.baseline_simulation + ) + reform_household = fill_and_calculate( + simulation.options.data, simulation.reform_simulation + ) + change = get_change( + baseline_household, + reform_household, + relative=False, + skip_mismatch=True, + ) return HouseholdComparison( - household_net_income=net_income, + full_household_baseline=baseline_household, + full_household_reform=reform_household, + change=change, ) diff --git a/policyengine/outputs/household/single/calculate_single_household.py b/policyengine/outputs/household/single/calculate_single_household.py index 26631794..858a0d6c 100644 --- a/policyengine/outputs/household/single/calculate_single_household.py +++ b/policyengine/outputs/household/single/calculate_single_household.py @@ -7,18 +7,30 @@ from pydantic import BaseModel from policyengine_core.simulations import Simulation as CountrySimulation -from typing import List +from typing import List, Dict +from datetime import date +from policyengine_core.variables import Variable +from policyengine_core.entities import Entity +from policyengine_core.model_api import YEAR, MONTH, ETERNITY, Enum +import dpath.util +import math +import json +Value = float | str | bool | list | None +Axes = List[List[Dict[str, str | int]]] +TimePeriodValues = Dict[str, Value] +EntityValues = Dict[str, TimePeriodValues] +EntityGroupValues = Dict[str, EntityValues] +FullHouseholdSpecification = Dict[ + str, EntityGroupValues | Axes +] # {people: {person: {variable: {time_period: value}}}} -class SingleHousehold(BaseModel): - household_net_income: float - """The net income of the household.""" +class SingleHousehold(BaseModel): + """Statistics for a single household scenario.""" -def calculate_net_income( - simulation: CountrySimulation, -) -> float: - return simulation.calculate("household_net_income").sum() + full_household: FullHouseholdSpecification + """Full variable calculations for the household.""" def calculate_single_household( @@ -30,8 +42,163 @@ def calculate_single_household( "This function is for single economy simulations only." ) - net_income = calculate_net_income(simulation.baseline_simulation) - return SingleHousehold( - household_net_income=net_income, + full_household=fill_and_calculate( + simulation.options.data, simulation.baseline_simulation + ) + ) + + +def fill_and_calculate( + household: FullHouseholdSpecification, simulation: CountrySimulation +): + """Fill in missing variables and calculate all variables for a household""" + # Copy the household to avoid modifying the original + household = json.loads(json.dumps(household)) + household = add_yearly_variables(household, simulation) + household = calculate_all_variables(household, simulation) + household.pop("axes", None) + return household + + +def get_requested_computations( + household: FullHouseholdSpecification, +) -> List[tuple[str, str, str, str]]: + requested_computations = dpath.util.search( + {k: v for k, v in household.items() if k != "axes"}, + "*/*/*/*", + # afilter=lambda t: t is None, + yielded=True, + ) + requested_computation_data = [] + + for computation in requested_computations: + path = computation[0] + entity_plural, entity_id, variable_name, period = path.split("/") + requested_computation_data.append( + (entity_plural, entity_id, variable_name, period) + ) + + return requested_computation_data + + +def calculate_all_variables( + household: FullHouseholdSpecification, simulation: CountrySimulation +) -> FullHouseholdSpecification: + requested_computations = get_requested_computations(household) + + for ( + entity_plural, + entity_id, + variable_name, + period, + ) in requested_computations: + variable = simulation.tax_benefit_system.get_variable(variable_name) + result = simulation.calculate(variable_name, period) + population = simulation.get_population(entity_plural) + + if "axes" in household: + count_entities = len(household[entity_plural]) + entity_index = 0 + for _entity_id in household[entity_plural].keys(): + if _entity_id == entity_id: + break + entity_index += 1 + try: + result = result.astype(float) + except: + pass + result = ( + result.reshape((-1, count_entities)).T[entity_index].tolist() + ) + # If the result contains infinities, throw an error + if any( + [ + not isinstance(value, str) and math.isinf(value) + for value in result + ] + ): + raise ValueError("Infinite value") + else: + household[entity_plural][entity_id][variable_name][ + period + ] = result + else: + entity_index = population.get_index(entity_id) + if variable.value_type == Enum: + entity_result = result.decode()[entity_index].name + elif variable.value_type == float: + entity_result = float(str(result[entity_index])) + # Convert infinities to JSON infinities + if entity_result == float("inf"): + entity_result = "Infinity" + elif entity_result == float("-inf"): + entity_result = "-Infinity" + elif variable.value_type == str: + entity_result = str(result[entity_index]) + else: + entity_result = result.tolist()[entity_index] + + household[entity_plural][entity_id][variable_name][ + period + ] = entity_result + + return household + + +def get_household_year(household: FullHouseholdSpecification) -> str: + """Given a household dict, get the household's year + + Args: + household (dict): The household itself + """ + + # Set household_year based on current year + household_year = date.today().year + + # Determine if "age" variable present within household and return list of values at it + household_age_list = list( + household.get("people", {}).get("you", {}).get("age", {}).keys() ) + # If it is, overwrite household_year with the value present + if len(household_age_list) > 0: + household_year = household_age_list[0] + + return str(household_year) + + +def add_yearly_variables( + household: FullHouseholdSpecification, simulation: CountrySimulation +) -> FullHouseholdSpecification: + """ + Add yearly variables to a household dict before enqueueing calculation + """ + + variables: Dict[str, Variable] = simulation.tax_benefit_system.variables + entities: Dict[str, Entity] = ( + simulation.tax_benefit_system.entities_by_singular() + ) + household_year = get_household_year(household) + + for variable in variables: + if variables[variable].definition_period in (YEAR, MONTH, ETERNITY): + entity_plural = entities[variables[variable].entity.key].plural + if entity_plural in household: + possible_entities = household[entity_plural].keys() + for entity in possible_entities: + if ( + not variables[variable].name + in household[entity_plural][entity] + ): + if variables[variable].is_input_variable(): + value = variables[variable].default_value + if isinstance(value, Enum): + value = value.name + household[entity_plural][entity][ + variables[variable].name + ] = {household_year: value} + else: + household[entity_plural][entity][ + variables[variable].name + ] = {household_year: None} + return household diff --git a/policyengine/outputs/macro/comparison/calculate_economy_comparison.py b/policyengine/outputs/macro/comparison/calculate_economy_comparison.py index d2ddde59..f9d04fd6 100644 --- a/policyengine/outputs/macro/comparison/calculate_economy_comparison.py +++ b/policyengine/outputs/macro/comparison/calculate_economy_comparison.py @@ -39,15 +39,31 @@ class InequalityComparison(BaseModel): relative_change: InequalitySummary +class Headlines(BaseModel): + budgetary_impact: float + """The change in the (federal) government budget balance.""" + poverty_impact: float + """The relative change in the regular poverty rate.""" + winner_share: float + """The share of people that are better off in the reform scenario.""" + + class PovertyRateMetricComparison(BaseModel): age_group: Literal["child", "working_age", "senior", "all"] """The age group of the population.""" + gender: Literal["male", "female", "all"] + """The gender of the population.""" racial_group: Literal["white", "black", "hispanic", "other", "all"] """The racial group of the population.""" relative: bool """Whether the poverty rate is relative to the total population, or a headcount.""" poverty_rate: Literal[ - "uk_hbai_bhc", "uk_hbai_bhc_half", "us_spm", "us_spm_half" + "regular", + "deep", + "uk_hbai_bhc", + "uk_hbai_bhc_half", + "us_spm", + "us_spm_half", ] """The poverty rate definition being calculated.""" baseline: float @@ -61,6 +77,8 @@ class PovertyRateMetricComparison(BaseModel): class EconomyComparison(BaseModel): + headlines: Headlines + """Headline statistics for the comparison.""" fiscal: FiscalComparison """Government budgets and other top-level fiscal statistics.""" inequality: InequalityComparison @@ -118,7 +136,7 @@ def calculate_economy_comparison( baseline_poverty_metrics = calculate_poverty(baseline, options) reform_poverty_metrics = calculate_poverty(reform, options) - poverty_metrics = [] + poverty_metrics: List[PovertyRateMetricComparison] = [] for baseline_metric, reform_metric in zip( baseline_poverty_metrics, reform_poverty_metrics ): @@ -130,6 +148,7 @@ def calculate_economy_comparison( poverty_metrics.append( PovertyRateMetricComparison( age_group=baseline_metric.age_group, + gender=baseline_metric.gender, racial_group=baseline_metric.racial_group, relative=baseline_metric.relative, poverty_rate=baseline_metric.poverty_rate, @@ -144,7 +163,25 @@ def calculate_economy_comparison( baseline, reform, options ) + # Headlines + budgetary_impact = fiscal_comparison.change.federal_balance + poverty_impact = next( + filter( + lambda metric: metric.age_group == "all" + and metric.racial_group == "all" + and metric.poverty_rate == "regular", + poverty_metrics, + ) + ).relative_change + winner_share = decile_impacts.income.winners_and_losers.all.gain_share + headlines = Headlines( + budgetary_impact=budgetary_impact, + poverty_impact=poverty_impact, + winner_share=winner_share, + ) + return EconomyComparison( + headlines=headlines, fiscal=fiscal_comparison, inequality=inequality_comparison, distributional=decile_impacts, diff --git a/policyengine/outputs/macro/comparison/charts/__init__.py b/policyengine/outputs/macro/comparison/charts/__init__.py new file mode 100644 index 00000000..2089605e --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/__init__.py @@ -0,0 +1,8 @@ +from .budget import create_budget_comparison_chart +from .budget_by_program import create_budget_program_comparison_chart +from .decile import create_decile_chart +from .winners_losers import create_winners_losers_chart +from .poverty import create_poverty_chart +from .inequality import create_inequality_chart +from .labor_supply import create_labor_supply_chart +from .create_all_charts import create_all_charts diff --git a/policyengine/outputs/macro/comparison/charts/budget.py b/policyengine/outputs/macro/comparison/charts/budget.py new file mode 100644 index 00000000..7a8d8b38 --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/budget.py @@ -0,0 +1,91 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * + + +def create_budget_comparison_chart( + simulation: "Simulation", +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + if simulation.options.country == "uk": + x_values = [ + "Tax revenues", + "Government spending", + "Public sector net worth", + ] + y_values = [ + economy.fiscal.change.federal_tax, + economy.fiscal.change.government_spending, + economy.fiscal.change.federal_balance, + ] + else: + x_values = [ + "Federal tax revenues", + "State tax revenues", + "Federal government spending", + ] + y_values = [ + economy.fiscal.change.federal_tax, + economy.fiscal.change.state_tax, + economy.fiscal.change.government_spending, + ] + + y_values = [value / 1e9 for value in y_values] + + net_change = round(economy.fiscal.change.federal_balance / 1e9, 1) + + if net_change > 0: + description = f"raise ${net_change}bn" + elif net_change < 0: + description = f"cost ${-net_change}bn" + else: + description = "have no effect on government finances" + + chart = go.Figure( + data=[ + go.Waterfall( + x=x_values, + y=y_values, + measure=["relative"] * (len(x_values) - 1) + ["total"], + textposition="inside", + text=[f"${value:.1f}bn" for value in y_values], + increasing=dict( + marker=dict( + color=BLUE, + ) + ), + decreasing=dict( + marker=dict( + color=DARK_GRAY, + ) + ), + totals=dict( + marker=dict( + color=BLUE if net_change > 0 else DARK_GRAY, + ) + ), + ), + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title="Budgetary impact ($bn)", + uniformtext=dict( + mode="hide", + minsize=12, + ), + ) + + return format_fig( + chart, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/budget_by_program.py b/policyengine/outputs/macro/comparison/charts/budget_by_program.py new file mode 100644 index 00000000..27eb23de --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/budget_by_program.py @@ -0,0 +1,97 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * + + +def create_budget_program_comparison_chart( + simulation: "Simulation", +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + if not simulation.options.country == "uk": + raise ValueError("This chart is only available for the UK.") + + economy = simulation.calculate_economy_comparison() + + change_programs = economy.fiscal.change.tax_benefit_programs + + change_programs = { + program: change_programs[program] + for program in change_programs + if round(change_programs[program] / 1e9, 1) != 0 + } + + labels = [ + simulation.baseline_simulation.tax_benefit_system.variables.get( + program + ).label + for program in change_programs + ] + + x_values = labels + y_values = [ + round(change_programs[program] / 1e9, 1) for program in change_programs + ] + + total_from_programs = round(sum(y_values)) + total_overall = round(economy.fiscal.change.federal_balance / 1e9) + + if total_from_programs != total_overall: + x_values.append("Other") + y_values.append(total_overall - total_from_programs) + + x_values.append("Combined") + y_values.append(total_overall) + + if total_overall > 0: + description = f"raise ${total_overall}bn" + elif total_overall < 0: + description = f"cost ${-total_overall}bn" + else: + description = "have no effect on government finances" + + chart = go.Figure( + data=[ + go.Waterfall( + x=x_values, + y=y_values, + measure=["relative"] * (len(x_values) - 1) + ["total"], + textposition="inside", + text=[f"${value:.1f}bn" for value in y_values], + increasing=dict( + marker=dict( + color=BLUE, + ) + ), + decreasing=dict( + marker=dict( + color=DARK_GRAY, + ) + ), + totals=dict( + marker=dict( + color=BLUE if total_overall > 0 else DARK_GRAY, + ) + ), + ), + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title="Budgetary impact (bn)", + uniformtext=dict( + mode="hide", + minsize=12, + ), + ) + + return format_fig( + chart, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/create_all_charts.py b/policyengine/outputs/macro/comparison/charts/create_all_charts.py new file mode 100644 index 00000000..eb6b2e3a --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/create_all_charts.py @@ -0,0 +1,65 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * +from .budget import create_budget_comparison_chart +from .budget_by_program import create_budget_program_comparison_chart +from .decile import create_decile_chart +from .winners_losers import create_winners_losers_chart +from .poverty import create_poverty_chart +from .inequality import create_inequality_chart +from .labor_supply import create_labor_supply_chart +from typing import Any + + +class MacroCharts(BaseModel): + budget: Any + budget_programs: Any + decile_income_relative: Any + decile_income_average: Any + decile_wealth_relative: Any + decile_wealth_average: Any + winners_and_losers_income_decile: Any + winners_and_losers_wealth_decile: Any + + +def create_all_charts( + simulation: "Simulation", +) -> MacroCharts: + """Create all charts.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + if not simulation.options.scope == "macro": + raise ValueError( + "This function is only available for macro simulations." + ) + + return MacroCharts( + budget=create_budget_comparison_chart(simulation).to_dict(), + budget_programs=create_budget_program_comparison_chart( + simulation + ).to_dict(), + decile_income_relative=create_decile_chart( + simulation, "income", True + ).to_dict(), + decile_income_average=create_decile_chart( + simulation, "income", False + ).to_dict(), + decile_wealth_relative=create_decile_chart( + simulation, "wealth", True + ).to_dict(), + decile_wealth_average=create_decile_chart( + simulation, "wealth", True + ).to_dict(), + winners_and_losers_income_decile=create_winners_losers_chart( + simulation, "income" + ).to_dict(), + winners_and_losers_wealth_decile=create_winners_losers_chart( + simulation, "wealth" + ).to_dict(), + ) diff --git a/policyengine/outputs/macro/comparison/charts/decile.py b/policyengine/outputs/macro/comparison/charts/decile.py new file mode 100644 index 00000000..d17c5bf2 --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/decile.py @@ -0,0 +1,90 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * +from typing import Literal + + +def create_decile_chart( + simulation: "Simulation", + decile_variable: Literal["income", "wealth"], + relative: bool, +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + if decile_variable == "income": + data = economy.distributional.income.income_change + else: + data = economy.distributional.wealth.income_change + + if relative: + data = data.relative + else: + data = data.average + + avg_change = sum(data.values()) / len(data) + + if relative: + text = [f"{value:.1%}" for value in data.values()] + avg_change = round(avg_change, 3) + else: + text = [f"${value:,.0f}" for value in data.values()] + avg_change = round(avg_change) + + avg_change_str = ( + f"${abs(avg_change):,.0f}" + if not relative + else f"{abs(avg_change):.1%}" + ) + + if avg_change > 0: + description = ( + f"increase the net income of households by {avg_change_str}" + ) + elif avg_change < 0: + description = ( + f"decrease the net income of households by {avg_change_str}" + ) + else: + description = "have no effect on household net income" + + chart = go.Figure( + data=[ + go.Bar( + x=list(data.keys()), + y=list(data.values()), + text=text, + marker=dict( + color=[ + BLUE if value > 0 else DARK_GRAY + for value in data.values() + ] + ), + ) + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title=f"Average change to net income ({'%' if relative else '$'})", + yaxis_tickformat="$,.0f" if not relative else ".0%", + xaxis_title=( + "Income decile" if decile_variable == "income" else "Wealth decile" + ), + uniformtext=dict( + mode="hide", + minsize=12, + ), + xaxis_tickvals=list(data.keys()), + ) + + return format_fig( + chart, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/inequality.py b/policyengine/outputs/macro/comparison/charts/inequality.py new file mode 100644 index 00000000..5fa00d39 --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/inequality.py @@ -0,0 +1,78 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * + + +def create_inequality_chart( + simulation: "Simulation", + relative: bool, +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + x_values = [ + "Gini index", + "Top 10% share", + "Top 1% share", + ] + + if relative: + data = economy.inequality.relative_change + else: + data = economy.inequality.change + + y_values = [ + data.gini, + data.top_10_share, + data.top_1_share, + ] + + if all(value < 0 for value in y_values): + description = f"lower inequality" + elif all(value > 0 for value in y_values): + description = f"raise inequality" + else: + description = "have an ambiguous effect on inequality" + + if not relative: + y_values = [value * 100 for value in y_values] + + chart = go.Figure( + data=[ + go.Bar( + x=x_values, + y=y_values, + text=[ + f"{value:.1%}" if relative else f"{value:.1f}pp" + for value in y_values + ], + marker=dict( + color=[ + BLUE if value < 0 else DARK_GRAY for value in y_values + ] + ), + ), + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title="Change" + (" (%)" if relative else ""), + yaxis_ticksuffix="pp" if not relative else "", + yaxis_tickformat=".0%" if relative else ".1f", + uniformtext=dict( + mode="hide", + minsize=12, + ), + ) + + return format_fig( + chart, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/labor_supply.py b/policyengine/outputs/macro/comparison/charts/labor_supply.py new file mode 100644 index 00000000..c3946e60 --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/labor_supply.py @@ -0,0 +1,126 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + from policyengine.outputs.macro.comparison.calculate_economy_comparison import ( + LaborSupplyMetricImpact, + ) + +from pydantic import BaseModel +from policyengine.utils.charts import * +from typing import Literal + + +def create_labor_supply_chart( + simulation: "Simulation", + decile: Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "all"] | None, + elasticity: Literal["income", "substitution", "all"] | None, + unit: Literal["earnings", "hours"] | None, + change_relative: bool = True, + change_average: bool = False, +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + def lsr_filter(comparison: "LaborSupplyMetricImpact"): + if decile is not None: + if comparison.decile != decile: + return False + if elasticity is not None: + if comparison.elasticity != elasticity: + return False + if unit is not None: + if comparison.unit != unit: + return False + return True + + overall_lsr_impact = list( + filter( + lambda comparison: comparison.decile == "all" + and comparison.elasticity == "all" + and comparison.unit == "earnings", + economy.labor_supply, + ) + )[0].relative_change + + overall_lsr_impact = round(overall_lsr_impact, 3) + + if overall_lsr_impact > 0: + description = f"raise labor supply by {overall_lsr_impact:.1%}" + elif overall_lsr_impact < 0: + description = f"lower labor supply by {-overall_lsr_impact:.1%}" + else: + description = "have no effect on labor supply" + + lsr_impacts = list( + filter( + lsr_filter, + economy.labor_supply, + ) + ) + + if decile is None: + x_values = [lsr.decile for lsr in lsr_impacts] + x_titles = list(range(1, 11)) + elif elasticity is None: + x_values = [lsr.elasticity for lsr in lsr_impacts] + x_titles = ["Income", "Substitution", "All"] + elif unit is None: + x_values = [lsr.unit for lsr in lsr_impacts] + x_titles = ["Earnings", "Hours"] + + if change_relative: + y_values = [lsr.relative_change for lsr in lsr_impacts] + elif change_average: + y_values = [lsr.average_change for lsr in lsr_impacts] + else: + y_values = [lsr.change / 1e9 for lsr in lsr_impacts] + + colors = [BLUE if value > 0 else DARK_GRAY for value in y_values] + text = [ + ( + f"{value:.1%}" + if change_relative + else ( + f"{value:,.1%}" + if change_relative + else ( + f"${value:.1f}bn" + if not change_average + else f"${value:,.0f}" + ) + ) + ) + for value in y_values + ] + + fig = go.Figure( + data=[ + go.Bar( + x=x_values, + y=y_values, + marker=dict(color=colors), + text=text, + ) + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title="Labor supply change" + + (" ($bn)" if not change_average else ""), + yaxis_tickformat=(".0%" if change_relative else ",.0f"), + yaxis_ticksuffix=( + " ($bn)" if not change_average and not change_relative else "" + ), + xaxis_title="Group", + xaxis_tickvals=x_values, + xaxis_ticktext=x_titles, + ) + + return format_fig( + fig, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/poverty.py b/policyengine/outputs/macro/comparison/charts/poverty.py new file mode 100644 index 00000000..271071fb --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/poverty.py @@ -0,0 +1,139 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + from policyengine.outputs.macro.comparison.calculate_economy_comparison import ( + PovertyRateMetricComparison, + ) + +from pydantic import BaseModel +from policyengine.utils.charts import * +from typing import Literal + + +def create_poverty_chart( + simulation: "Simulation", + age_group: str, + gender: str, + racial_group: str, + poverty_rate: str, + rate_relative: bool, + change_relative: bool = True, +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + def poverty_filter(comparison: "PovertyRateMetricComparison"): + if age_group is not None: + if comparison.age_group != age_group: + return False + if racial_group is not None: + if comparison.racial_group != racial_group: + return False + if gender is not None: + if comparison.gender != gender: + return False + if poverty_rate is not None: + if comparison.poverty_rate != poverty_rate: + return False + if rate_relative is not None: + if comparison.relative != rate_relative: + return False + return True + + poverty_rates = list( + filter( + poverty_filter, + economy.poverty, + ) + ) + + if len(poverty_rates) == 0: + raise ValueError("No data found for the selected filters.") + + overall_poverty_rate = list( + filter( + lambda comparison: comparison.age_group == "all" + and comparison.racial_group == "all" + and comparison.gender == "all" + and comparison.poverty_rate == (poverty_rate or "regular"), + economy.poverty, + ) + )[0].relative_change + + overall_poverty_rate = round(overall_poverty_rate, 3) + + if overall_poverty_rate > 0: + description = f"raise the {'deep ' if poverty_rate == 'deep' else ''}poverty rate by {overall_poverty_rate:.1%}" + elif overall_poverty_rate < 0: + description = f"lower the {'deep ' if poverty_rate == 'deep' else ''}poverty rate by {-overall_poverty_rate:.1%}" + else: + description = "have no effect on the poverty rate" + + if age_group is None: + x_values = [poverty.age_group for poverty in poverty_rates] + x_titles = ["Child", "Working-age", "Senior", "All"] + elif gender is None: + x_values = [poverty.gender for poverty in poverty_rates] + x_titles = ["Male", "Female", "All"] + elif racial_group is None: + x_values = [poverty.racial_group for poverty in poverty_rates] + x_titles = ["White", "Black", "Hispanic", "Other", "All"] + elif poverty_rate is None: + x_values = [poverty.poverty_rate for poverty in poverty_rates] + x_titles = ["Regular", "Deep", "All"] + elif rate_relative is None: + x_values = [poverty.relative for poverty in poverty_rates] + x_titles = ["Relative", "Headcount", "All"] + + if change_relative: + y_values = [poverty.relative_change for poverty in poverty_rates] + elif not rate_relative: + y_values = [poverty.change for poverty in poverty_rates] + else: + y_values = [poverty.change * 100 for poverty in poverty_rates] + + colors = [BLUE if value > 0 else DARK_GRAY for value in y_values] + text = [ + ( + f"{value:.1%}" + if change_relative + else (f"{value:,.0f}" if not rate_relative else f"{value:.1f}pp") + ) + for value in y_values + ] + + fig = go.Figure( + data=[ + go.Bar( + x=x_values, + y=y_values, + marker=dict(color=colors), + text=text, + ) + ] + ).update_layout( + title=f"{simulation.options.title} would {description}", + yaxis_title="Poverty rate change" + + (" (%)" if rate_relative and not change_relative else ""), + yaxis_tickformat=( + ".0%" + if change_relative + else (",.0f" if not rate_relative else ".1f") + ), + yaxis_ticksuffix=( + "pp" if (rate_relative and not change_relative) else "" + ), + xaxis_title="Group", + xaxis_tickvals=x_values, + xaxis_ticktext=x_titles, + ) + + return format_fig( + fig, country=simulation.options.country, add_zero_line=True + ) diff --git a/policyengine/outputs/macro/comparison/charts/winners_losers.py b/policyengine/outputs/macro/comparison/charts/winners_losers.py new file mode 100644 index 00000000..9d17d495 --- /dev/null +++ b/policyengine/outputs/macro/comparison/charts/winners_losers.py @@ -0,0 +1,149 @@ +import plotly.express as px +import plotly.graph_objects as go +import typing + +if typing.TYPE_CHECKING: + from policyengine import Simulation + +from pydantic import BaseModel +from policyengine.utils.charts import * +from typing import Literal, Dict + + +COLOR_MAP = { + "Gain more than 5%": BLUE, + "Gain less than 5%": BLUE_95, + "No change": LIGHT_GRAY, + "Lose less than 5%": MEDIUM_LIGHT_GRAY, + "Lose more than 5%": DARK_GRAY, +} + +FORMATTED_KEYS = { + "gain_more_than_5_percent_share": "Gain more than 5%", + "gain_less_than_5_percent_share": "Gain less than 5%", + "no_change_share": "No change", + "lose_less_than_5_percent_share": "Lose less than 5%", + "lose_more_than_5_percent_share": "Lose more than 5%", +} + + +def create_winners_losers_chart( + simulation: "Simulation", + decile_variable: Literal["income", "wealth"], +) -> go.Figure: + """Create a budget comparison chart.""" + if not simulation.is_comparison: + raise ValueError("Simulation must be a comparison simulation.") + + economy = simulation.calculate_economy_comparison() + + if decile_variable == "income": + data = economy.distributional.income.winners_and_losers + else: + data = economy.distributional.wealth.winners_and_losers + + all_decile_data = {} + for key in FORMATTED_KEYS.keys(): + all_decile_data[FORMATTED_KEYS[key]] = data.all.model_dump()[key] + + all_decile_chart = go.Bar( + x=list(all_decile_data.values()), + y=["All"] * len(all_decile_data), + name="All deciles", + orientation="h", + yaxis="y", + xaxis="x", + showlegend=False, + text=[f"{value:.1%}" for value in all_decile_data.values()], + marker=dict(color=[COLOR_MAP[key] for key in all_decile_data.keys()]), + ) + + x_values = [] + y_values = [] + color_values = [] + text = [] + hover_text = [] + for outcome_type in FORMATTED_KEYS.keys(): + for decile in range(1, 11): + value = data.deciles[decile].model_dump()[outcome_type] + x_values.append(value) + y_values.append(decile) + color_values.append(COLOR_MAP[FORMATTED_KEYS[outcome_type]]) + text.append(f"{value:.1%}") + hover_text.append( + f"{FORMATTED_KEYS[outcome_type]}, {decile}: {value:.1%}" + ) + + decile_chart = go.Bar( + x=x_values, + y=y_values, + name="Deciles", + orientation="h", + yaxis="y2", + xaxis="x2", + text=text, + textposition="inside", + marker=dict( + color=color_values, + ), + customdata=hover_text, + hovertemplate="%{customdata}", + # Need to sort out showlegend, currently fiddly. + ) + + fig = go.Figure( + data=[ + all_decile_chart, + decile_chart, + ] + ) + + winner_share = round( + economy.distributional.income.winners_and_losers.all.gain_share, 3 + ) + + if winner_share > 0: + description = f"raise the net income of {winner_share:.1%} of people" + elif winner_share < 0: + description = ( + f"decrease the net income of {-winner_share:.1%} of people" + ) + else: + description = "have no effect on household net income" + + fig.update_layout( + barmode="stack", + grid=dict( + rows=2, + columns=1, + ), + yaxis=dict( + title="", + tickvals=["All"], + domain=[0.91, 1], + ), + xaxis=dict( + title="", + tickformat=".0%", + anchor="y", + matches="x2", + showgrid=False, + showticklabels=False, + fixedrange=True, + ), + xaxis2=dict( + title="Population share", + tickformat=".0%", + anchor="y2", + fixedrange=True, + ), + yaxis2=dict( + title="Population share", + tickvals=list(range(1, 11)), + anchor="x2", + domain=[0, 0.85], + ), + title=f"{simulation.options.title} would {description}", + ) + + return format_fig(fig, country=simulation.options.country) diff --git a/policyengine/outputs/macro/comparison/decile.py b/policyengine/outputs/macro/comparison/decile.py index 61dc7381..a7041e7c 100644 --- a/policyengine/outputs/macro/comparison/decile.py +++ b/policyengine/outputs/macro/comparison/decile.py @@ -125,11 +125,11 @@ def calculate_income_specific_decile_winners_losers( BOUNDS = [ (-np.inf, -0.05), - (-0.05, 0), + (-0.05, -1e-3), (-np.inf, -1e-3), (-1e-3, 1e-3), (1e-3, np.inf), - (0, 0.05), + (1e-3, 0.05), (0.05, np.inf), ] LABELS = [ diff --git a/policyengine/outputs/macro/comparison/labor_supply.py b/policyengine/outputs/macro/comparison/labor_supply.py index 6f1b8126..fd8269e6 100644 --- a/policyengine/outputs/macro/comparison/labor_supply.py +++ b/policyengine/outputs/macro/comparison/labor_supply.py @@ -25,6 +25,8 @@ class LaborSupplyMetricImpact(BaseModel): """The change in the labor supply metric value.""" relative_change: float """The relative change in the labor supply metric value.""" + average_change: float + """The average change in the labor supply metric value (per household).""" def calculate_labor_supply_impact( @@ -53,6 +55,8 @@ def calculate_labor_supply_impact( ) ) + return lsr_metrics + def calculate_specific_lsr_metric( baseline: Microsimulation, @@ -82,19 +86,25 @@ def calculate_specific_lsr_metric( else: variable = "weekly_hours_worked" - baseline_values = baseline.calculate(baseline_variable) - reform_values = reformed.calculate(baseline_variable) + reformed.calculate( - variable - ) + baseline_values = baseline.calculate(baseline_variable, map_to="household") + reform_values = reformed.calculate( + baseline_variable, map_to="household" + ) + reformed.calculate(variable, map_to="household") if decile == "all": in_decile = np.ones_like(baseline_values, dtype=bool) else: - in_decile = reformed.calculate("household_income_decile") == decile + in_decile = ( + reformed.calculate("household_income_decile").values == decile + ) baseline_total = (baseline_values * in_decile).sum() reform_total = (reform_values * in_decile).sum() + households = ( + in_decile * baseline.calculate("household_weight").values + ).sum() change = reform_total - baseline_total + average_change = change / households relative_change = change / baseline_total return LaborSupplyMetricImpact( @@ -104,6 +114,7 @@ def calculate_specific_lsr_metric( baseline=baseline_total, reform=reform_total, change=change, + average_change=average_change, relative_change=relative_change, ) diff --git a/policyengine/outputs/macro/single/budget.py b/policyengine/outputs/macro/single/budget.py index c349c364..d5fbdb1a 100644 --- a/policyengine/outputs/macro/single/budget.py +++ b/policyengine/outputs/macro/single/budget.py @@ -35,10 +35,12 @@ class FiscalSummary(BaseModel): """The total tax revenue collected by the government.""" federal_tax: float """The total tax revenue collected by the federal (or national) government.""" + federal_balance: float + """Federal taxes subtract spending.""" state_tax: float """The total tax revenue collected by the state government.""" government_spending: float - """The total spending by the government on modeled programs.""" + """The total spending by the (federal) government on modeled programs.""" tax_benefit_programs: dict[str, float] """The total revenue change to the government from each tax-benefit program.""" household_net_income: float @@ -73,6 +75,7 @@ def calculate_government_balance( return FiscalSummary( tax_revenue=total_tax, federal_tax=national_tax, + federal_balance=national_tax - total_spending, state_tax=total_state_tax, government_spending=total_spending, tax_benefit_programs=tb_programs, diff --git a/policyengine/outputs/macro/single/poverty.py b/policyengine/outputs/macro/single/poverty.py index 91aa8639..f0f2c93c 100644 --- a/policyengine/outputs/macro/single/poverty.py +++ b/policyengine/outputs/macro/single/poverty.py @@ -15,10 +15,17 @@ class PovertyRateMetric(BaseModel): """The age group of the population.""" racial_group: Literal["white", "black", "hispanic", "other", "all"] """The racial group of the population.""" + gender: Literal["male", "female", "all"] + """The gender of the population.""" relative: bool """Whether the poverty rate is relative to the total population, or a headcount.""" poverty_rate: Literal[ - "uk_hbai_bhc", "uk_hbai_bhc_half", "us_spm", "us_spm_half" + "regular", + "deep", + "uk_hbai_bhc", + "uk_hbai_bhc_half", + "us_spm", + "us_spm_half", ] """The poverty rate definition being calculated.""" value: float @@ -41,6 +48,15 @@ def calculate_poverty( poverty_metrics = [] age = simulation.calculate("age") + if options.country == "uk": + gender = simulation.calculate("gender") + else: + gender = simulation.calculate("is_male").map( + { + True: "MALE", + False: "FEMALE", + } + ) person_weight = simulation.calculate("person_weight").values if options.country == "us": racial_groups = ["white", "black", "hispanic", "other", "all"] @@ -49,56 +65,57 @@ def calculate_poverty( for age_group in ["child", "working_age", "senior", "all"]: lower_age, upper_age = AGE_BOUNDS[age_group] in_age_group = (age >= lower_age) & (age < upper_age) - for racial_group in racial_groups: - if racial_group != "all": - in_racial_group = simulation.calculate("race") == racial_group - else: - in_racial_group = np.ones_like(age, dtype=bool) - for relative in [True, False]: - for poverty_rate in [ - "uk_hbai_bhc", - "uk_hbai_bhc_half", - "us_spm", - "us_spm_half", - ]: - if not poverty_rate.startswith(options.country): - continue + for gender_group in ["male", "female", "all"]: + in_gender = (gender_group == "all") | ( + gender == gender_group.upper() + ) + for racial_group in racial_groups: + if racial_group != "all": + in_racial_group = ( + simulation.calculate("race") == racial_group + ) + else: + in_racial_group = np.ones_like(age, dtype=bool) + for relative in [True, False]: + for poverty_rate in ["regular", "deep"]: + if poverty_rate in ( + "regular", + "uk_hbai_bhc", + "us_spm", + ): + in_poverty = simulation.calculate( + "in_poverty", map_to="person" + ) + elif poverty_rate in ( + "deep", + "uk_hbai_bhc_half", + "us_spm_half", + ): + in_poverty = simulation.calculate( + "in_deep_poverty", map_to="person" + ) - if poverty_rate == "uk_hbai_bhc": - in_poverty = simulation.calculate( - "in_poverty", map_to="person" - ) - elif poverty_rate == "uk_hbai_bhc_half": - in_poverty = simulation.calculate( - "in_deep_poverty", map_to="person" - ) - elif poverty_rate == "us_spm": - in_poverty = simulation.calculate( - "in_poverty", map_to="person" + in_group = np.array( + in_age_group & in_racial_group & in_gender ) - elif poverty_rate == "us_spm_half": - in_poverty = simulation.calculate( - "in_deep_poverty", map_to="person" - ) - - in_group = np.array(in_age_group & in_racial_group) - total_in_group = (in_group * person_weight).sum() - total_in_group_in_poverty = ( - in_group * in_poverty * person_weight - ).sum() - if relative: - result = total_in_group_in_poverty / total_in_group - else: - result = total_in_group_in_poverty + total_in_group = (in_group * person_weight).sum() + total_in_group_in_poverty = ( + in_group * in_poverty * person_weight + ).sum() + if relative: + result = total_in_group_in_poverty / total_in_group + else: + result = total_in_group_in_poverty - poverty_metrics.append( - PovertyRateMetric( - age_group=age_group, - racial_group=racial_group, - relative=relative, - poverty_rate=poverty_rate, - value=result, + poverty_metrics.append( + PovertyRateMetric( + age_group=age_group, + gender=gender_group, + racial_group=racial_group, + relative=relative, + poverty_rate=poverty_rate, + value=result, + ) ) - ) return poverty_metrics diff --git a/policyengine/simulation.py b/policyengine/simulation.py index 09036e7b..f62a9011 100644 --- a/policyengine/simulation.py +++ b/policyengine/simulation.py @@ -42,10 +42,17 @@ HouseholdComparison, calculate_household_comparison, ) +from .outputs.macro.comparison.charts.create_all_charts import ( + create_all_charts, + MacroCharts, +) +from typing import Any, Tuple CountryType = Literal["uk", "us"] ScopeType = Literal["household", "macro"] -DataType = str | dict | None # Needs stricter typing +DataType = ( + str | dict | Any | None +) # Needs stricter typing. Any==policyengine_core.data.Dataset, but pydantic refuses for some reason. TimePeriodType = int ReformType = ( ParametricReform | SimulationAdjustment | Type[StructuralReform] | None @@ -70,6 +77,10 @@ class SimulationOptions(BaseModel): None, description="How many, if a subsample, households to randomly simulate.", ) + title: str | None = Field( + "[Analysis title]", + description="The title of the analysis (for charts). If not provided, a default title will be generated.", + ) class Simulation: @@ -342,3 +353,7 @@ def calculate_single_household(self) -> SingleHousehold: def calculate_household_comparison(self) -> HouseholdComparison: """Calculate comparison statistics between two household scenarios.""" return calculate_household_comparison(self) + + def create_all_charts(self) -> MacroCharts: + """Create all macro charts for the simulation.""" + return create_all_charts(self) diff --git a/policyengine/utils/calculations.py b/policyengine/utils/calculations.py index b6c24e7e..0a9aa709 100644 --- a/policyengine/utils/calculations.py +++ b/policyengine/utils/calculations.py @@ -1,5 +1,6 @@ from typing import Dict from pydantic import BaseModel +import numpy as np Output = Dict[str, float | None] @@ -8,6 +9,7 @@ def get_change( x: Output | Dict[str, Output], y: Output | Dict[str, Output], relative: bool, + skip_mismatch: bool = False, ) -> Output | Dict[str, Output]: """Take two objects of nested str-float relations and create a similarly-structured object with the differences.""" if isinstance(x, BaseModel): @@ -21,12 +23,28 @@ def get_change( for key in x: if isinstance(x[key], dict): result[key] = get_change(x[key], y[key], relative=relative) + elif isinstance(x[key], list): + try: + result[key] = list(np.array(y[key]) - np.array(x[key])) + except: + result[key] = None elif x[key] is None and y[key] is None: result[key] = None elif x[key] is None: - raise ValueError(f"Key {key} is None in x but not in y") + if skip_mismatch: + result[key] = None + else: + raise ValueError(f"Key {key} is None in x but not in y") elif y[key] is None: - raise ValueError(f"Key {key} is None in y but not in x") + if skip_mismatch: + result[key] = None + else: + raise ValueError(f"Key {key} is None in y but not in x") + elif isinstance(x[key], str) or isinstance(y[key], str): + if x[key] == y[key]: + result[key] = 0 + else: + result[key] = f"{x[key]} -> {y[key]}" elif not relative: result[key] = y[key] - x[key] else: diff --git a/policyengine/utils/charts.py b/policyengine/utils/charts.py index bf3a665b..9f624c47 100644 --- a/policyengine/utils/charts.py +++ b/policyengine/utils/charts.py @@ -21,6 +21,7 @@ def add_fonts(): BLUE_PRIMARY = BLUE = "#2C6496" BLUE_PRESSED = "#17354F" BLUE_98 = "#F7FAFD" +BLUE_95 = "#D8E6F3" TEAL_LIGHT = "#D7F4F2" TEAL_ACCENT = "#39C6C0" TEAL_PRESSED = "#227773" @@ -29,6 +30,7 @@ def add_fonts(): GRAY = "#808080" LIGHT_GRAY = "#F2F2F2" MEDIUM_DARK_GRAY = "#D2D2D2" +MEDIUM_LIGHT_GRAY = "#BDBDBD" WHITE = "#FFFFFF" TEAL_98 = "#F7FDFC" BLACK = "#000000" @@ -118,10 +120,71 @@ def format_fig( margin_t=120, margin_l=120, margin_r=120, + uniformtext=dict( + mode="hide", + minsize=12, + ), + ) + + # Auto-format currency + + if country == "uk": + currency = "£" + else: + currency = "$" + + fig.update_layout( + title=correct_text_currency(fig.layout.title.text or "", currency), + yaxis_title=correct_text_currency( + fig.layout.yaxis.title.text or "", currency + ), + yaxis_ticksuffix=correct_text_currency( + fig.layout.yaxis.ticksuffix or "", currency + ), + xaxis_title=correct_text_currency( + fig.layout.xaxis.title.text or "", currency + ), + xaxis_ticksuffix=correct_text_currency( + fig.layout.xaxis.ticksuffix or "", currency + ), ) + + fig.update_layout( + title=wrap_text(fig.layout.title.text or ""), + ) + + for trace in fig.data: + if trace.text is not None: + trace.text = [ + correct_text_currency(t, currency) for t in trace.text + ] + return fig +def wrap_text(text: str, max_length: int = 80) -> str: + """Wrap text to a maximum length, respecting spaces.""" + if len(text) <= max_length: + return text + + split_text = text.split(" ") + wrapped_text = "" + line_length = 0 + for word in split_text: + if line_length + len(word) > max_length: + wrapped_text += "
" + line_length = 0 + wrapped_text += word + " " + line_length += len(word) + 1 + + return wrapped_text + + +def correct_text_currency(text: str, currency: str) -> str: + """Correct text to match the currency symbol.""" + return text.replace("$", currency).replace(f"{currency}-", f"-{currency}") + + def cardinal(n: int) -> int: """Convert an integer to a cardinal string.""" ending_number = n % 10