diff --git a/docs/_toc.yml b/docs/_toc.yml
index e060ef57..65fd941b 100644
--- a/docs/_toc.yml
+++ b/docs/_toc.yml
@@ -7,7 +7,6 @@ parts:
- file: basic/calculate_household_comparison
- file: basic/calculate_single_economy
- file: basic/calculate_economy_comparison
- - file: basic/create_charts
- caption: Reference
chapters:
- file: reference/parameters_us
diff --git a/docs/basic/calculate_economy_comparison.ipynb b/docs/basic/calculate_economy_comparison.ipynb
index c9d08f0b..09f9f931 100644
--- a/docs/basic/calculate_economy_comparison.ipynb
+++ b/docs/basic/calculate_economy_comparison.ipynb
@@ -11,26 +11,16 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
- "name": "stdout",
+ "name": "stderr",
"output_type": "stream",
"text": [
- "WARNING: Gini calculation failed. Setting to 0.4.\n",
- "WARNING: Gini calculation failed. Setting to 0.4.\n"
+ "/Users/nikhilwoodruff/policyengine/policyengine.py/.venv/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+ " from .autonotebook import tqdm as notebook_tqdm\n"
]
- },
- {
- "data": {
- "text/plain": [
- "EconomyComparison(headlines=Headlines(budgetary_impact=12057201822.641846, winner_share=3.096710278402974e-05), fiscal=FiscalComparison(baseline=FiscalSummary(tax_revenue=3013608593152.1895, federal_tax=2583108898331.884, federal_balance=1160152745100.683, state_tax=430499694820.3057, government_spending=1422956153231.2007, tax_benefit_programs={}, household_net_income=12826524419636.805), reform=FiscalSummary(tax_revenue=3013602235736.6367, federal_tax=2583108898330.5815, federal_balance=1172209946923.325, state_tax=430493337406.05536, government_spending=1410898951407.2566, tax_benefit_programs={}, household_net_income=12814482607439.363), change=FiscalSummary(tax_revenue=-6357415.552734375, federal_tax=-1.30224609375, federal_balance=12057201822.641846, state_tax=-6357414.250366211, government_spending=-12057201823.944092, tax_benefit_programs={}, household_net_income=-12041812197.441406), relative_change=FiscalSummary(tax_revenue=-2.1095690950644036e-06, federal_tax=-5.041390607228997e-13, federal_balance=0.01039277101533339, state_tax=-1.476752324532971e-05, government_spending=-0.008473347401861264, tax_benefit_programs={}, household_net_income=-0.0009388211337286318)), inequality=InequalityComparison(baseline=InequalitySummary(gini=0.4, top_10_share=0.3056184716000026, top_1_share=0.07133480442157591), reform=InequalitySummary(gini=0.4, top_10_share=0.30585587458075175, top_1_share=0.0713913687702228), change=InequalitySummary(gini=0.0, top_10_share=0.00023740298074914623, top_1_share=5.65643486468842e-05), relative_change=InequalitySummary(gini=0.0, top_10_share=0.000776795262100068, top_1_share=0.0007929418059745287)), distributional=DecileImpacts(income=IncomeMeasureSpecificDecileImpacts(income_change=IncomeMeasureSpecificDecileIncomeChange(relative={1: -0.003725182447367451, 2: -0.004777925629293106, 3: -0.004427406664007123, 4: -0.003033546615233723, 5: -0.0012295913621786522, 6: -0.0003957445652524665, 7: -9.39759257002033e-05, 8: -3.0593991125471323e-05, 9: -1.4266187310034442e-05, 10: -1.1781514896665692e-05}, average={1: -63.89275812122564, 2: -174.0337390913802, 3: -224.9955222412714, 4: -193.3288209208671, 5: -96.35100483351104, 6: -37.64443533520402, 7: -10.856160889113756, 8: -4.3236716100441095, 9: -2.6063802446197073, 10: -3.9748627643461294}), winners_and_losers=IncomeMeasureSpecificDecileWinnersLosers(deciles={1: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0657153256192896, lose_less_than_5_percent_share=0.05318331952206108, lose_share=0.11889864514135068, no_change_share=0.8807898379100747, gain_share=0.00031151694857464756, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.00031151694857464756), 2: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.15194453295736532, lose_less_than_5_percent_share=0.07711620163220688, lose_share=0.22906073458957218, no_change_share=0.7709392654104278, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 3: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.17114447859504486, lose_less_than_5_percent_share=0.059347324242194015, lose_share=0.23049180283723886, no_change_share=0.7695081971627611, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 4: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.12989846703096578, lose_less_than_5_percent_share=0.04485983299864166, lose_share=0.17475830002960743, no_change_share=0.8252416999703925, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 5: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.051068199514449644, lose_less_than_5_percent_share=0.024111392231720524, lose_share=0.07517959174617017, no_change_share=0.9248204082538298, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 6: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.015369267341425434, lose_less_than_5_percent_share=0.018481961006501027, lose_share=0.03385122834792646, no_change_share=0.9661487716520736, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 7: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0029113126526266477, lose_less_than_5_percent_share=0.00904746763596632, lose_share=0.011958780288592966, no_change_share=0.988041219711407, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 8: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0005094937950111613, lose_less_than_5_percent_share=0.0031321041000860993, lose_share=0.0036415978950972605, no_change_share=0.9963584021049028, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 9: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.00029487893089546547, lose_less_than_5_percent_share=0.0035164203584642836, lose_share=0.003811299289359749, no_change_share=0.9961887007106403, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0), 10: IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.0002281227488112428, lose_less_than_5_percent_share=0.003779501887019752, lose_share=0.004007624635830995, no_change_share=0.9867296828146133, gain_share=0.0, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=0.0)}, all=IncomeMeasureSpecificDecileWinnersLosersGroupOutcomes(lose_more_than_5_percent_share=0.05886871339782029, lose_less_than_5_percent_share=0.02962594712536097, lose_share=0.08849466052318125, no_change_share=0.9105479297614693, gain_share=3.096710278402974e-05, gain_less_than_5_percent_share=0.0, gain_more_than_5_percent_share=3.096710278402974e-05))), wealth=None))"
- ]
- },
- "execution_count": 1,
- "metadata": {},
- "output_type": "execute_result"
}
],
"source": [
@@ -61,7 +51,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
@@ -255,7 +245,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "base",
+ "display_name": ".venv",
"language": "python",
"name": "python3"
},
@@ -269,7 +259,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.9"
+ "version": "3.11.11"
}
},
"nbformat": 4,
diff --git a/docs/basic/calculate_single_economy.ipynb b/docs/basic/calculate_single_economy.ipynb
index 6e330de3..2a7de6e1 100644
--- a/docs/basic/calculate_single_economy.ipynb
+++ b/docs/basic/calculate_single_economy.ipynb
@@ -34,7 +34,7 @@
" time_period=2025,\n",
")\n",
"\n",
- "sim.calculate_single_economy()"
+ "result = sim.calculate_single_economy()"
]
},
{
diff --git a/docs/basic/create_charts.ipynb b/docs/basic/create_charts.ipynb
deleted file mode 100644
index c2a8d65a..00000000
--- a/docs/basic/create_charts.ipynb
+++ /dev/null
@@ -1,5191 +0,0 @@
-{
- "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": null,
- "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": [
- "## 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)"
- ]
- }
- ],
- "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/policyengine/__init__.py b/policyengine/__init__.py
index 26fe276e..4bb8a90c 100644
--- a/policyengine/__init__.py
+++ b/policyengine/__init__.py
@@ -1,3 +1,3 @@
from .simulation import Simulation, SimulationOptions
-__version__ = "0.1.1"
\ No newline at end of file
+__version__ = "0.1.1"
diff --git a/policyengine/outputs/macro/comparison/calculate_economy_comparison.py b/policyengine/outputs/macro/comparison/calculate_economy_comparison.py
index 41398eee..4cb4ecda 100644
--- a/policyengine/outputs/macro/comparison/calculate_economy_comparison.py
+++ b/policyengine/outputs/macro/comparison/calculate_economy_comparison.py
@@ -1,110 +1,847 @@
"""Calculate comparison statistics between two economic scenarios."""
-import typing
-
+from microdf import MicroSeries
+import numpy as np
+from policyengine_core.tools.hugging_face import download_huggingface_dataset
+import pandas as pd
+import h5py
+from pydantic import BaseModel
from policyengine import Simulation
+from policyengine.outputs.macro.single.calculate_single_economy import (
+ SingleEconomy,
+)
+from typing import List, Dict
-from pydantic import BaseModel
-from policyengine.utils.calculations import get_change
-from policyengine.outputs.macro.single import (
- _calculate_government_balance,
- FiscalSummary,
- _calculate_inequality,
- InequalitySummary,
-)
+class BudgetaryImpact(BaseModel):
+ budgetary_impact: float
+ tax_revenue_impact: float
+ state_tax_revenue_impact: float
+ benefit_spending_impact: float
+ households: float
+ baseline_net_income: float
-from .decile import calculate_decile_impacts, DecileImpacts
-from typing import Literal, List
+def budgetary_impact(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> BudgetaryImpact:
+ tax_revenue_impact = reform.total_tax - baseline.total_tax
+ state_tax_revenue_impact = (
+ reform.total_state_tax - baseline.total_state_tax
+ )
+ benefit_spending_impact = reform.total_benefits - baseline.total_benefits
+ budgetary_impact = tax_revenue_impact - benefit_spending_impact
+ return BudgetaryImpact(
+ budgetary_impact=budgetary_impact,
+ tax_revenue_impact=tax_revenue_impact,
+ state_tax_revenue_impact=state_tax_revenue_impact,
+ benefit_spending_impact=benefit_spending_impact,
+ households=sum(baseline.household_weight),
+ baseline_net_income=baseline.total_net_income,
+ )
-class FiscalComparison(BaseModel):
- baseline: FiscalSummary
- reform: FiscalSummary
- change: FiscalSummary
- relative_change: FiscalSummary
+DecileValues = Dict[int, float]
-class InequalityComparison(BaseModel):
- baseline: InequalitySummary
- reform: InequalitySummary
- change: InequalitySummary
- relative_change: InequalitySummary
+class HoursResponse(BaseModel):
+ baseline: float
+ reform: float
+ change: float
+ income_effect: float
+ substitution_effect: float
-class Headlines(BaseModel):
- budgetary_impact: float
- """The change in the (federal) government budget balance."""
- winner_share: float
- """The share of people that are better off in the reform scenario."""
+class LaborSupplyResponse(BaseModel):
+ substitution_lsr: float
+ income_lsr: float
+ relative_lsr: dict
+ total_change: float
+ revenue_change: float
+ decile: Dict[str, Dict[str, DecileValues]]
+ hours: HoursResponse
-class EconomyComparison(BaseModel):
- headlines: Headlines
- """Headline statistics for the comparison."""
- fiscal: FiscalComparison
- """Government budgets and other top-level fiscal statistics."""
- inequality: InequalityComparison
- """Inequality statistics for the household sector."""
- distributional: DecileImpacts
- """Distributional impacts of the reform."""
+def labor_supply_response(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> LaborSupplyResponse:
+ substitution_lsr = reform.substitution_lsr - baseline.substitution_lsr
+ income_lsr = reform.income_lsr - baseline.income_lsr
+ total_change = substitution_lsr + income_lsr
+ revenue_change = (
+ reform.budgetary_impact_lsr - baseline.budgetary_impact_lsr
+ )
+ substitution_lsr_hh = np.array(reform.substitution_lsr_hh) - np.array(
+ baseline.substitution_lsr_hh
+ )
+ income_lsr_hh = np.array(reform.income_lsr_hh) - np.array(
+ baseline.income_lsr_hh
+ )
+ decile = np.array(baseline.household_income_decile)
+ household_weight = baseline.household_weight
-def calculate_economy_comparison(
- simulation: Simulation,
-) -> EconomyComparison:
- """Calculate comparison statistics between two economic scenarios."""
- if not simulation.is_comparison:
- raise ValueError("Simulation must be a comparison simulation.")
+ total_lsr_hh = substitution_lsr_hh + income_lsr_hh
- baseline = simulation.baseline_simulation
- reform = simulation.reform_simulation
- options = simulation.options
+ emp_income = MicroSeries(
+ baseline.employment_income_hh, weights=household_weight
+ )
+ self_emp_income = MicroSeries(
+ baseline.self_employment_income_hh, weights=household_weight
+ )
+ earnings = emp_income + self_emp_income
+ original_earnings = earnings - total_lsr_hh
+ substitution_lsr_hh = MicroSeries(
+ substitution_lsr_hh, weights=household_weight
+ )
+ income_lsr_hh = MicroSeries(income_lsr_hh, weights=household_weight)
- baseline_balance = _calculate_government_balance(baseline, options)
- reform_balance = _calculate_government_balance(reform, options)
- balance_change = get_change(
- baseline_balance, reform_balance, relative=False
+ decile_avg = dict(
+ income=income_lsr_hh.groupby(decile).mean().to_dict(),
+ substitution=substitution_lsr_hh.groupby(decile).mean().to_dict(),
)
- balance_rel_change = get_change(
- baseline_balance, reform_balance, relative=True
+ decile_rel = dict(
+ income=(
+ income_lsr_hh.groupby(decile).sum()
+ / original_earnings.groupby(decile).sum()
+ ).to_dict(),
+ substitution=(
+ substitution_lsr_hh.groupby(decile).sum()
+ / original_earnings.groupby(decile).sum()
+ ).to_dict(),
)
- fiscal_comparison = FiscalComparison(
- baseline=baseline_balance,
- reform=reform_balance,
- change=balance_change,
- relative_change=balance_rel_change,
+
+ relative_lsr = dict(
+ income=(income_lsr_hh.sum() / original_earnings.sum()),
+ substitution=(substitution_lsr_hh.sum() / original_earnings.sum()),
)
- baseline_inequality = _calculate_inequality(baseline)
- reform_inequality = _calculate_inequality(reform)
- inequality_change = get_change(
- baseline_inequality, reform_inequality, relative=False
+ decile_rel["income"] = {
+ int(k): v for k, v in decile_rel["income"].items() if k > 0
+ }
+ decile_rel["substitution"] = {
+ int(k): v for k, v in decile_rel["substitution"].items() if k > 0
+ }
+
+ hours = dict(
+ baseline=baseline.weekly_hours,
+ reform=reform.weekly_hours,
+ change=reform.weekly_hours - baseline.weekly_hours,
+ income_effect=reform.weekly_hours_income_effect
+ - baseline.weekly_hours_income_effect,
+ substitution_effect=reform.weekly_hours_substitution_effect
+ - baseline.weekly_hours_substitution_effect,
)
- inequality_rel_change = get_change(
- baseline_inequality, reform_inequality, relative=True
+
+ return LaborSupplyResponse(
+ substitution_lsr=substitution_lsr,
+ income_lsr=income_lsr,
+ relative_lsr=relative_lsr,
+ total_change=total_change,
+ revenue_change=revenue_change,
+ decile=dict(
+ average=decile_avg,
+ relative=decile_rel,
+ ),
+ hours=hours,
)
- inequality_comparison = InequalityComparison(
- baseline=baseline_inequality,
- reform=reform_inequality,
- change=inequality_change,
- relative_change=inequality_rel_change,
+
+
+class ProgramSpecificImpact(BaseModel):
+ baseline: float
+ reform: float
+ difference: float
+
+
+DetailedBudgetaryImpact = Dict[str, ProgramSpecificImpact] | None
+
+
+def detailed_budgetary_impact(
+ baseline: SingleEconomy, reform: SingleEconomy, country_id: str
+) -> DetailedBudgetaryImpact:
+ result = {}
+ if country_id == "uk":
+ for program in baseline.programs:
+ # baseline[programs][program] = total budgetary impact of program
+ result[program] = dict(
+ baseline=baseline.programs[program],
+ reform=reform.programs[program],
+ difference=reform.programs[program]
+ - baseline.programs[program],
+ )
+ return result
+
+
+class DecileImpact(BaseModel):
+ relative: DecileValues
+ average: DecileValues
+
+
+def decile_impact(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> DecileImpact:
+ """
+ Compare the impact of a reform on the deciles of the population.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on the deciles of the population.
+ """
+ baseline_income = MicroSeries(
+ baseline.household_net_income, weights=baseline.household_weight
+ )
+ reform_income = MicroSeries(
+ reform.household_net_income, weights=baseline_income.weights
)
- decile_impacts = calculate_decile_impacts(baseline, reform, options)
+ # Filter out negative decile values
+ decile = MicroSeries(baseline.household_income_decile)
+ baseline_income_filtered = baseline_income[decile >= 0]
+ reform_income_filtered = reform_income[decile >= 0]
- # Headlines
- budgetary_impact = fiscal_comparison.change.federal_balance
- winner_share = decile_impacts.income.winners_and_losers.all.gain_share
- headlines = Headlines(
- budgetary_impact=budgetary_impact,
- winner_share=winner_share,
+ income_change = reform_income_filtered - baseline_income_filtered
+ rel_income_change_by_decile = (
+ income_change.groupby(decile).sum()
+ / baseline_income_filtered.groupby(decile).sum()
)
- return EconomyComparison(
- headlines=headlines,
- fiscal=fiscal_comparison,
- inequality=inequality_comparison,
- distributional=decile_impacts,
+ avg_income_change_by_decile = (
+ income_change.groupby(decile).sum()
+ / baseline_income_filtered.groupby(decile).count()
+ )
+ rel_decile_dict = rel_income_change_by_decile.to_dict()
+ avg_decile_dict = avg_income_change_by_decile.to_dict()
+ return DecileImpact(
+ relative={int(k): v for k, v in rel_decile_dict.items()},
+ average={int(k): v for k, v in avg_decile_dict.items()},
+ )
+
+
+class WealthDecileImpactWithValues(BaseModel):
+ relative: DecileValues
+ average: DecileValues
+
+
+WealthDecileImpact = WealthDecileImpactWithValues | None
+
+
+def wealth_decile_impact(
+ baseline: SingleEconomy, reform: SingleEconomy, country_id: str
+) -> WealthDecileImpact:
+ """
+ Compare the impact of a reform on the deciles of the population.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on the deciles of the population.
+ """
+ if country_id != "uk":
+ return None
+ baseline_income = MicroSeries(
+ baseline.household_net_income, weights=baseline.household_weight
+ )
+ reform_income = MicroSeries(
+ reform.household_net_income, weights=baseline_income.weights
+ )
+
+ # Filter out negative decile values
+ decile = MicroSeries(baseline.household_wealth_decile)
+ baseline_income_filtered = baseline_income[decile >= 0]
+ reform_income_filtered = reform_income[decile >= 0]
+
+ income_change = reform_income_filtered - baseline_income_filtered
+ rel_income_change_by_decile = (
+ income_change.groupby(decile).sum()
+ / baseline_income_filtered.groupby(decile).sum()
+ )
+ avg_income_change_by_decile = (
+ income_change.groupby(decile).sum()
+ / baseline_income_filtered.groupby(decile).count()
+ )
+ rel_decile_dict = rel_income_change_by_decile.to_dict()
+ avg_decile_dict = avg_income_change_by_decile.to_dict()
+ return WealthDecileImpactWithValues(
+ relative={int(k): v for k, v in rel_decile_dict.items()},
+ average={int(k): v for k, v in avg_decile_dict.items()},
+ )
+
+
+class BaselineReformValues(BaseModel):
+ baseline: float
+ reform: float
+
+
+class InequalityImpact(BaseModel):
+ gini: BaselineReformValues
+ top_10_pct_share: BaselineReformValues
+ top_1_pct_share: BaselineReformValues
+
+
+def inequality_impact(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> InequalityImpact:
+ """
+ Compare the impact of a reform on inequality.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on inequality.
+ """
+
+ values = dict(
+ gini=dict(
+ baseline=baseline.gini,
+ reform=reform.gini,
+ ),
+ top_10_pct_share=dict(
+ baseline=baseline.top_10_percent_share,
+ reform=reform.top_10_percent_share,
+ ),
+ top_1_pct_share=dict(
+ baseline=baseline.top_1_percent_share,
+ reform=reform.top_1_percent_share,
+ ),
+ )
+
+ return InequalityImpact(**values)
+
+
+class AgeGroupBaselineReformValues(BaseModel):
+ child: BaselineReformValues
+ adult: BaselineReformValues
+ senior: BaselineReformValues
+ all: BaselineReformValues
+
+
+class PovertyImpact(BaseModel):
+ poverty: AgeGroupBaselineReformValues
+ deep_poverty: AgeGroupBaselineReformValues
+
+
+def poverty_impact(baseline: SingleEconomy, reform: SingleEconomy) -> dict:
+ """
+ Compare the impact of a reform on poverty.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on poverty.
+ """
+ baseline_poverty = MicroSeries(
+ baseline.person_in_poverty, weights=baseline.person_weight
+ )
+ baseline_deep_poverty = MicroSeries(
+ baseline.person_in_deep_poverty, weights=baseline.person_weight
+ )
+ reform_poverty = MicroSeries(
+ reform.person_in_poverty, weights=baseline_poverty.weights
+ )
+ reform_deep_poverty = MicroSeries(
+ reform.person_in_deep_poverty, weights=baseline_poverty.weights
+ )
+ age = MicroSeries(baseline.age)
+
+ poverty = dict(
+ child=dict(
+ baseline=float(baseline_poverty[age < 18].mean()),
+ reform=float(reform_poverty[age < 18].mean()),
+ ),
+ adult=dict(
+ baseline=float(baseline_poverty[(age >= 18) & (age < 65)].mean()),
+ reform=float(reform_poverty[(age >= 18) & (age < 65)].mean()),
+ ),
+ senior=dict(
+ baseline=float(baseline_poverty[age >= 65].mean()),
+ reform=float(reform_poverty[age >= 65].mean()),
+ ),
+ all=dict(
+ baseline=float(baseline_poverty.mean()),
+ reform=float(reform_poverty.mean()),
+ ),
+ )
+
+ deep_poverty = dict(
+ child=dict(
+ baseline=float(baseline_deep_poverty[age < 18].mean()),
+ reform=float(reform_deep_poverty[age < 18].mean()),
+ ),
+ adult=dict(
+ baseline=float(
+ baseline_deep_poverty[(age >= 18) & (age < 65)].mean()
+ ),
+ reform=float(reform_deep_poverty[(age >= 18) & (age < 65)].mean()),
+ ),
+ senior=dict(
+ baseline=float(baseline_deep_poverty[age >= 65].mean()),
+ reform=float(reform_deep_poverty[age >= 65].mean()),
+ ),
+ all=dict(
+ baseline=float(baseline_deep_poverty.mean()),
+ reform=float(reform_deep_poverty.mean()),
+ ),
+ )
+
+ return PovertyImpact(
+ poverty=poverty,
+ deep_poverty=deep_poverty,
+ )
+
+
+class IntraDecileImpact(BaseModel):
+ deciles: Dict[str, List[float]]
+ all: Dict[str, float]
+
+
+def intra_decile_impact(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> IntraDecileImpact:
+ baseline_income = MicroSeries(
+ baseline.household_net_income, weights=baseline.household_weight
+ )
+ reform_income = MicroSeries(
+ reform.household_net_income, weights=baseline_income.weights
+ )
+ people = MicroSeries(
+ baseline.household_count_people, weights=baseline_income.weights
)
+ decile = MicroSeries(baseline.household_income_decile).values
+ absolute_change = (reform_income - baseline_income).values
+ capped_baseline_income = np.maximum(baseline_income.values, 1)
+ capped_reform_income = (
+ np.maximum(reform_income.values, 1) + absolute_change
+ )
+ income_change = (
+ capped_reform_income - capped_baseline_income
+ ) / capped_baseline_income
+
+ # Within each decile, calculate the percentage of people who:
+ # 1. Gained more than 5% of their income
+ # 2. Gained between 0% and 5% of their income
+ # 3. Had no change in income
+ # 3. Lost between 0% and 5% of their income
+ # 4. Lost more than 5% of their income
+
+ outcome_groups = {}
+ all_outcomes = {}
+ BOUNDS = [-np.inf, -0.05, -1e-3, 1e-3, 0.05, np.inf]
+ LABELS = [
+ "Lose more than 5%",
+ "Lose less than 5%",
+ "No change",
+ "Gain less than 5%",
+ "Gain more than 5%",
+ ]
+ for lower, upper, label in zip(BOUNDS[:-1], BOUNDS[1:], LABELS):
+ outcome_groups[label] = []
+ for i in range(1, 11):
+
+ in_decile: bool = decile == i
+ in_group: bool = (income_change > lower) & (income_change <= upper)
+ in_both: bool = in_decile & in_group
+
+ people_in_both: np.float64 = people[in_both].sum()
+ people_in_decile: np.float64 = people[in_decile].sum()
+
+ # np.float64 does not raise ZeroDivisionError, instead returns NaN
+ if people_in_decile == 0 and people_in_both == 0:
+ people_in_proportion: float = 0.0
+ else:
+ people_in_proportion: float = float(
+ people_in_both / people_in_decile
+ )
+
+ outcome_groups[label].append(people_in_proportion)
+
+ all_outcomes[label] = sum(outcome_groups[label]) / 10
+ return IntraDecileImpact(deciles=outcome_groups, all=all_outcomes)
+
+
+class IntraWealthDecileImpactWithValues(BaseModel):
+ deciles: Dict[str, List[float]]
+ all: Dict[str, float]
+
+
+IntraWealthDecileImpact = IntraWealthDecileImpactWithValues | None
+
+
+def intra_wealth_decile_impact(
+ baseline: SingleEconomy, reform: SingleEconomy, country_id: str
+) -> IntraWealthDecileImpact:
+ if country_id != "uk":
+ return None
+ baseline_income = MicroSeries(
+ baseline.household_net_income, weights=baseline.household_weight
+ )
+ reform_income = MicroSeries(
+ reform.household_net_income, weights=baseline_income.weights
+ )
+ people = MicroSeries(
+ baseline.household_count_people, weights=baseline_income.weights
+ )
+ decile = MicroSeries(baseline.household_wealth_decile).values
+ absolute_change = (reform_income - baseline_income).values
+ capped_baseline_income = np.maximum(baseline_income.values, 1)
+ capped_reform_income = (
+ np.maximum(reform_income.values, 1) + absolute_change
+ )
+ income_change = (
+ capped_reform_income - capped_baseline_income
+ ) / capped_baseline_income
+
+ # Within each decile, calculate the percentage of people who:
+ # 1. Gained more than 5% of their income
+ # 2. Gained between 0% and 5% of their income
+ # 3. Had no change in income
+ # 3. Lost between 0% and 5% of their income
+ # 4. Lost more than 5% of their income
+
+ outcome_groups = {}
+ all_outcomes = {}
+ BOUNDS = [-np.inf, -0.05, -1e-3, 1e-3, 0.05, np.inf]
+ LABELS = [
+ "Lose more than 5%",
+ "Lose less than 5%",
+ "No change",
+ "Gain less than 5%",
+ "Gain more than 5%",
+ ]
+ for lower, upper, label in zip(BOUNDS[:-1], BOUNDS[1:], LABELS):
+ outcome_groups[label] = []
+ for i in range(1, 11):
+
+ in_decile: bool = decile == i
+ in_group: bool = (income_change > lower) & (income_change <= upper)
+ in_both: bool = in_decile & in_group
+
+ people_in_both: np.float64 = people[in_both].sum()
+ people_in_decile: np.float64 = people[in_decile].sum()
+
+ # np.float64 does not raise ZeroDivisionError, instead returns NaN
+ if people_in_decile == 0 and people_in_both == 0:
+ people_in_proportion = 0
+ else:
+ people_in_proportion: float = float(
+ people_in_both / people_in_decile
+ )
+
+ outcome_groups[label].append(people_in_proportion)
+
+ all_outcomes[label] = sum(outcome_groups[label]) / 10
+ return IntraWealthDecileImpactWithValues(
+ deciles=outcome_groups, all=all_outcomes
+ )
+
+
+class GenderBaselineReformValues(BaseModel):
+ male: BaselineReformValues
+ female: BaselineReformValues
+
+
+class PovertyGenderBreakdown(BaseModel):
+ poverty: GenderBaselineReformValues
+ deep_poverty: GenderBaselineReformValues
+
+
+def poverty_gender_breakdown(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> PovertyGenderBreakdown:
+ """
+ Compare the impact of a reform on poverty.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on poverty.
+ """
+ if baseline.is_male is None:
+ return {}
+ baseline_poverty = MicroSeries(
+ baseline.person_in_poverty, weights=baseline.person_weight
+ )
+ baseline_deep_poverty = MicroSeries(
+ baseline.person_in_deep_poverty, weights=baseline.person_weight
+ )
+ reform_poverty = MicroSeries(
+ reform.person_in_poverty, weights=baseline_poverty.weights
+ )
+ reform_deep_poverty = MicroSeries(
+ reform.person_in_deep_poverty, weights=baseline_poverty.weights
+ )
+ is_male = MicroSeries(baseline.is_male)
+
+ poverty = dict(
+ male=dict(
+ baseline=float(baseline_poverty[is_male].mean()),
+ reform=float(reform_poverty[is_male].mean()),
+ ),
+ female=dict(
+ baseline=float(baseline_poverty[~is_male].mean()),
+ reform=float(reform_poverty[~is_male].mean()),
+ ),
+ )
+
+ deep_poverty = dict(
+ male=dict(
+ baseline=float(baseline_deep_poverty[is_male].mean()),
+ reform=float(reform_deep_poverty[is_male].mean()),
+ ),
+ female=dict(
+ baseline=float(baseline_deep_poverty[~is_male].mean()),
+ reform=float(reform_deep_poverty[~is_male].mean()),
+ ),
+ )
+
+ return PovertyGenderBreakdown(
+ poverty=poverty,
+ deep_poverty=deep_poverty,
+ )
+
+
+class RacialBaselineReformValues(BaseModel):
+ white: BaselineReformValues
+ black: BaselineReformValues
+ hispanic: BaselineReformValues
+ other: BaselineReformValues
+
+
+class PovertyRacialBreakdownWithValues(BaseModel):
+ poverty: RacialBaselineReformValues
+
+
+PovertyRacialBreakdown = PovertyRacialBreakdownWithValues | None
+
+
+def poverty_racial_breakdown(
+ baseline: SingleEconomy, reform: SingleEconomy
+) -> PovertyRacialBreakdown:
+ """
+ Compare the impact of a reform on poverty.
+
+ Args:
+ baseline (dict): The baseline economy.
+ reform (dict): The reform economy.
+
+ Returns:
+ dict: The impact of the reform on poverty.
+ """
+ if baseline.race is None:
+ return None
+ baseline_poverty = MicroSeries(
+ baseline.person_in_poverty, weights=baseline.person_weight
+ )
+ reform_poverty = MicroSeries(
+ reform.person_in_poverty, weights=baseline_poverty.weights
+ )
+ race = MicroSeries(
+ baseline.race
+ ) # Can be WHITE, BLACK, HISPANIC, or OTHER.
+
+ poverty = dict(
+ white=dict(
+ baseline=float(baseline_poverty[race == "WHITE"].mean()),
+ reform=float(reform_poverty[race == "WHITE"].mean()),
+ ),
+ black=dict(
+ baseline=float(baseline_poverty[race == "BLACK"].mean()),
+ reform=float(reform_poverty[race == "BLACK"].mean()),
+ ),
+ hispanic=dict(
+ baseline=float(baseline_poverty[race == "HISPANIC"].mean()),
+ reform=float(reform_poverty[race == "HISPANIC"].mean()),
+ ),
+ other=dict(
+ baseline=float(baseline_poverty[race == "OTHER"].mean()),
+ reform=float(reform_poverty[race == "OTHER"].mean()),
+ ),
+ )
+
+ return PovertyRacialBreakdownWithValues(
+ poverty=poverty,
+ )
+
+
+class UKConstituencyBreakdownByConstituency(BaseModel):
+ average_household_income_change: float
+ relative_household_income_change: float
+ x: int
+ y: int
+
+
+class UKConstituencyBreakdownWithValues(BaseModel):
+ by_constituency: dict[str, UKConstituencyBreakdownByConstituency]
+ outcomes_by_region: dict[str, dict[str, int]]
+
+
+UKConstituencyBreakdown = UKConstituencyBreakdownWithValues | None
+
+
+def uk_constituency_breakdown(
+ baseline: SingleEconomy, reform: SingleEconomy, country_id: str
+) -> UKConstituencyBreakdown:
+ if country_id != "uk":
+ return None
+
+ output = {
+ "by_constituency": {},
+ "outcomes_by_region": {},
+ }
+ for region in ["uk", "england", "scotland", "wales", "northern_ireland"]:
+ output["outcomes_by_region"][region] = {
+ "Gain more than 5%": 0,
+ "Gain less than 5%": 0,
+ "No change": 0,
+ "Lose less than 5%": 0,
+ "Lose more than 5%": 0,
+ }
+ baseline_hnet = baseline.household_net_income
+ reform_hnet = reform.household_net_income
+
+ constituency_weights_path = download_huggingface_dataset(
+ repo="policyengine/policyengine-uk-data",
+ repo_filename="parliamentary_constituency_weights.h5",
+ )
+ with h5py.File(constituency_weights_path, "r") as f:
+ weights = f["2025"][
+ ...
+ ] # {2025: array(650, 100180) where cell i, j is the weight of household record i in constituency j}
+
+ constituency_names_path = download_huggingface_dataset(
+ repo="policyengine/policyengine-uk-data",
+ repo_filename="constituencies_2024.csv",
+ )
+ constituency_names = pd.read_csv(
+ constituency_names_path
+ ) # columns code (constituency code), name (constituency name), x, y (geographic position)
+
+ for i in range(len(constituency_names)):
+ name: str = constituency_names.iloc[i]["name"]
+ code: str = constituency_names.iloc[i]["code"]
+ weight: np.ndarray = weights[i]
+ baseline_income = MicroSeries(baseline_hnet, weights=weight)
+ reform_income = MicroSeries(reform_hnet, weights=weight)
+ average_household_income_change: float = (
+ reform_income.sum() - baseline_income.sum()
+ ) / baseline_income.count()
+ percent_household_income_change: float = (
+ reform_income.sum() / baseline_income.sum() - 1
+ )
+ output["by_constituency"][name] = {
+ "average_household_income_change": average_household_income_change,
+ "relative_household_income_change": percent_household_income_change,
+ "x": int(constituency_names.iloc[i]["x"]), # Geographic positions
+ "y": int(constituency_names.iloc[i]["y"]),
+ }
+
+ regions = ["uk"]
+ if "E" in code:
+ regions.append("england")
+ elif "S" in code:
+ regions.append("scotland")
+ elif "W" in code:
+ regions.append("wales")
+ elif "N" in code:
+ regions.append("northern_ireland")
+
+ if percent_household_income_change > 0.05:
+ bucket = "Gain more than 5%"
+ elif percent_household_income_change > 1e-3:
+ bucket = "Gain less than 5%"
+ elif percent_household_income_change > -1e-3:
+ bucket = "No change"
+ elif percent_household_income_change > -0.05:
+ bucket = "Lose less than 5%"
+ else:
+ bucket = "Lose more than 5%"
+
+ for region_ in regions:
+ output["outcomes_by_region"][region_][bucket] += 1
+
+ return UKConstituencyBreakdownWithValues(**output)
+
+
+class EconomyComparison(BaseModel):
+ budget: BudgetaryImpact
+ detailed_budget: DetailedBudgetaryImpact
+ decile: DecileImpact
+ inequality: InequalityImpact
+ poverty: PovertyImpact
+ poverty_by_gender: PovertyGenderBreakdown
+ poverty_by_race: PovertyRacialBreakdown
+ intra_decile: IntraDecileImpact
+ wealth_decile: WealthDecileImpact
+ intra_wealth_decile: IntraWealthDecileImpact
+ labor_supply_response: LaborSupplyResponse
+ constituency_impact: UKConstituencyBreakdown
+
+
+def calculate_economy_comparison(
+ simulation: Simulation,
+) -> EconomyComparison:
+ """Calculate comparison statistics between two economic scenarios."""
+ if not simulation.is_comparison:
+ raise ValueError("Simulation must be a comparison simulation.")
+
+ baseline: SingleEconomy = simulation.calculate_single_economy(reform=False)
+ reform: SingleEconomy = simulation.calculate_single_economy(reform=True)
+ options = simulation.options
+ country_id = options.country
+ if baseline.type == "general":
+ budgetary_impact_data = budgetary_impact(baseline, reform)
+ detailed_budgetary_impact_data = detailed_budgetary_impact(
+ baseline, reform, country_id
+ )
+ decile_impact_data = decile_impact(baseline, reform)
+ inequality_impact_data = inequality_impact(baseline, reform)
+ poverty_impact_data = poverty_impact(baseline, reform)
+ poverty_by_gender_data = poverty_gender_breakdown(baseline, reform)
+ poverty_by_race_data = poverty_racial_breakdown(baseline, reform)
+ intra_decile_impact_data = intra_decile_impact(baseline, reform)
+ labor_supply_response_data = labor_supply_response(baseline, reform)
+ constituency_impact_data: UKConstituencyBreakdown = (
+ uk_constituency_breakdown(baseline, reform, country_id)
+ )
+ wealth_decile_impact_data = wealth_decile_impact(
+ baseline, reform, country_id
+ )
+ intra_wealth_decile_impact_data = intra_wealth_decile_impact(
+ baseline, reform, country_id
+ )
+
+ return EconomyComparison(
+ budget=budgetary_impact_data,
+ detailed_budget=detailed_budgetary_impact_data,
+ decile=decile_impact_data,
+ inequality=inequality_impact_data,
+ poverty=poverty_impact_data,
+ poverty_by_gender=poverty_by_gender_data,
+ poverty_by_race=poverty_by_race_data,
+ intra_decile=intra_decile_impact_data,
+ wealth_decile=wealth_decile_impact_data,
+ intra_wealth_decile=intra_wealth_decile_impact_data,
+ labor_supply_response=labor_supply_response_data,
+ constituency_impact=constituency_impact_data,
+ )
+ elif baseline.type == "cliff":
+ return dict(
+ baseline=dict(
+ cliff_gap=baseline.cliff_gap,
+ cliff_share=baseline.cliff_share,
+ ),
+ reform=dict(
+ cliff_gap=reform.cliff_gap,
+ cliff_share=reform.cliff_share,
+ ),
+ )
diff --git a/policyengine/outputs/macro/comparison/charts/__init__.py b/policyengine/outputs/macro/comparison/charts/__init__.py
deleted file mode 100644
index 9db0bf9c..00000000
--- a/policyengine/outputs/macro/comparison/charts/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-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 .inequality import create_inequality_chart
diff --git a/policyengine/outputs/macro/comparison/charts/budget.py b/policyengine/outputs/macro/comparison/charts/budget.py
deleted file mode 100644
index f7e453fd..00000000
--- a/policyengine/outputs/macro/comparison/charts/budget.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import plotly.express as px
-import plotly.graph_objects as go
-import typing
-
-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
deleted file mode 100644
index 382cdfcf..00000000
--- a/policyengine/outputs/macro/comparison/charts/budget_by_program.py
+++ /dev/null
@@ -1,96 +0,0 @@
-import plotly.express as px
-import plotly.graph_objects as go
-import typing
-
-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/decile.py b/policyengine/outputs/macro/comparison/charts/decile.py
deleted file mode 100644
index bd2c69e7..00000000
--- a/policyengine/outputs/macro/comparison/charts/decile.py
+++ /dev/null
@@ -1,89 +0,0 @@
-import plotly.express as px
-import plotly.graph_objects as go
-import typing
-
-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
deleted file mode 100644
index e0db5c29..00000000
--- a/policyengine/outputs/macro/comparison/charts/inequality.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import plotly.express as px
-import plotly.graph_objects as go
-import typing
-
-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/winners_losers.py b/policyengine/outputs/macro/comparison/charts/winners_losers.py
deleted file mode 100644
index db21e18d..00000000
--- a/policyengine/outputs/macro/comparison/charts/winners_losers.py
+++ /dev/null
@@ -1,148 +0,0 @@
-import plotly.express as px
-import plotly.graph_objects as go
-import typing
-
-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/single/calculate_single_economy.py b/policyengine/outputs/macro/single/calculate_single_economy.py
index 206fd489..7a21133a 100644
--- a/policyengine/outputs/macro/single/calculate_single_economy.py
+++ b/policyengine/outputs/macro/single/calculate_single_economy.py
@@ -5,35 +5,416 @@
from policyengine import Simulation
from pydantic import BaseModel
-
-from .budget import FiscalSummary, _calculate_government_balance
-from .inequality import InequalitySummary, _calculate_inequality
from typing import List
+from policyengine_core.simulations import Microsimulation
+from typing import Dict
+from dataclasses import dataclass
+
class SingleEconomy(BaseModel):
- fiscal: FiscalSummary
- """Government budgets and other top-level fiscal statistics."""
- inequality: InequalitySummary
- """Inequality statistics for the household sector."""
+ total_net_income: float
+ employment_income_hh: List[float]
+ self_employment_income_hh: List[float]
+ total_tax: float
+ total_state_tax: float
+ total_benefits: float
+ household_net_income: List[float]
+ equiv_household_net_income: List[float]
+ household_income_decile: List[int]
+ household_market_income: List[float]
+ household_wealth_decile: List[int] | None
+ household_wealth: List[float] | None
+ in_poverty: List[bool]
+ person_in_poverty: List[bool]
+ person_in_deep_poverty: List[bool]
+ poverty_gap: float
+ deep_poverty_gap: float
+ person_weight: List[float]
+ household_weight: List[float]
+ household_count_people: List[int]
+ gini: float
+ top_10_percent_share: float
+ top_1_percent_share: float
+ is_male: List[bool]
+ race: List[str] | None
+ age: List[int]
+ substitution_lsr: float
+ income_lsr: float
+ budgetary_impact_lsr: float
+ income_lsr_hh: List[float]
+ substitution_lsr_hh: List[float]
+ weekly_hours: float | None
+ weekly_hours_income_effect: float | None
+ weekly_hours_substitution_effect: float | None
+ type: str
+ programs: Dict[str, float] | None
-def calculate_single_economy(
- simulation: Simulation,
-) -> SingleEconomy:
- """Calculate economy statistics for a single economic scenario."""
- options = simulation.options
- if simulation.is_comparison:
- raise ValueError(
- "This function is for single economy simulations only."
+@dataclass
+class UKProgram:
+ name: str
+ is_positive: bool
+
+
+class UKPrograms:
+ PROGRAMS = [
+ UKProgram("income_tax", True),
+ UKProgram("national_insurance", True),
+ UKProgram("vat", True),
+ UKProgram("council_tax", True),
+ UKProgram("fuel_duty", True),
+ UKProgram("tax_credits", False),
+ UKProgram("universal_credit", False),
+ UKProgram("child_benefit", False),
+ UKProgram("state_pension", False),
+ UKProgram("pension_credit", False),
+ UKProgram("ni_employer", True),
+ ]
+
+
+class GeneralEconomyTask:
+ def __init__(self, simulation: Microsimulation, country_id: str):
+ self.simulation = simulation
+ self.country_id = country_id
+ self.household_count_people = self.simulation.calculate(
+ "household_count_people"
+ )
+
+ def calculate_tax_and_spending(self):
+ if self.country_id == "uk":
+ total_tax = self.simulation.calculate("gov_tax").sum()
+ total_spending = self.simulation.calculate("gov_spending").sum()
+ else:
+ total_tax = self.simulation.calculate("household_tax").sum()
+ total_spending = self.simulation.calculate(
+ "household_benefits"
+ ).sum()
+ return total_tax, total_spending
+
+ def calculate_inequality_metrics(self):
+ personal_hh_equiv_income = self._get_weighted_household_income()
+
+ try:
+ gini = personal_hh_equiv_income.gini()
+ except Exception as e:
+ print(
+ "WARNING: Gini index calculations resulted in an error: returning no change, but this is inaccurate."
+ )
+ print("Error: ", e)
+ gini = 0.4
+
+ in_top_10_pct = personal_hh_equiv_income.decile_rank() == 10
+ in_top_1_pct = personal_hh_equiv_income.percentile_rank() == 100
+
+ personal_hh_equiv_income.weights /= self.household_count_people
+
+ top_10_share = (
+ personal_hh_equiv_income[in_top_10_pct].sum()
+ / personal_hh_equiv_income.sum()
+ )
+ top_1_share = (
+ personal_hh_equiv_income[in_top_1_pct].sum()
+ / personal_hh_equiv_income.sum()
+ )
+
+ return gini, top_10_share, top_1_share
+
+ def _get_weighted_household_income(self):
+ income = self.simulation.calculate("equiv_household_net_income")
+ income[income < 0] = 0
+ income.weights *= self.household_count_people
+ return income
+
+ def calculate_income_breakdown_metrics(self):
+ total_net_income = self.simulation.calculate(
+ "household_net_income"
+ ).sum()
+ employment_income_hh = (
+ self.simulation.calculate("employment_income", map_to="household")
+ .astype(float)
+ .tolist()
+ )
+ self_employment_income_hh = (
+ self.simulation.calculate(
+ "self_employment_income", map_to="household"
+ )
+ .astype(float)
+ .tolist()
+ )
+
+ return (
+ total_net_income,
+ employment_income_hh,
+ self_employment_income_hh,
+ )
+
+ def calculate_household_income_metrics(self):
+ household_net_income = (
+ self.simulation.calculate("household_net_income")
+ .astype(float)
+ .tolist()
+ )
+ equiv_household_net_income = (
+ self.simulation.calculate("equiv_household_net_income")
+ .astype(float)
+ .tolist()
+ )
+ household_income_decile = (
+ self.simulation.calculate("household_income_decile")
+ .astype(int)
+ .tolist()
+ )
+ household_market_income = (
+ self.simulation.calculate("household_market_income")
+ .astype(float)
+ .tolist()
+ )
+
+ return (
+ household_net_income,
+ equiv_household_net_income,
+ household_income_decile,
+ household_market_income,
+ )
+
+ def calculate_wealth_metrics(self):
+ try:
+ wealth = self.simulation.calculate("total_wealth")
+ wealth.weights *= self.household_count_people
+ wealth_decile = (
+ wealth.decile_rank().clip(1, 10).astype(int).tolist()
+ )
+ wealth = wealth.astype(float).tolist()
+ except Exception as e:
+ wealth = None
+ wealth_decile = None
+ return wealth, wealth_decile
+
+ def calculate_demographic_metrics(self):
+ try:
+ is_male = (
+ self.simulation.calculate("is_male").astype(bool).tolist()
+ )
+ except Exception:
+ is_male = None
+
+ try:
+ race = self.simulation.calculate("race").astype(str).tolist()
+ except Exception:
+ race = None
+
+ age = self.simulation.calculate("age").astype(int).tolist()
+
+ return is_male, race, age
+
+ def calculate_poverty_metrics(self):
+ in_poverty = (
+ self.simulation.calculate("in_poverty").astype(bool).tolist()
+ )
+ person_in_poverty = (
+ self.simulation.calculate("in_poverty", map_to="person")
+ .astype(bool)
+ .tolist()
+ )
+ person_in_deep_poverty = (
+ self.simulation.calculate("in_deep_poverty", map_to="person")
+ .astype(bool)
+ .tolist()
+ )
+ poverty_gap = self.simulation.calculate("poverty_gap").sum()
+ deep_poverty_gap = self.simulation.calculate("deep_poverty_gap").sum()
+ return (
+ in_poverty,
+ person_in_poverty,
+ person_in_deep_poverty,
+ poverty_gap,
+ deep_poverty_gap,
+ )
+
+ def calculate_weights(self):
+ person_weight = (
+ self.simulation.calculate("person_weight").astype(float).tolist()
+ )
+ household_weight = (
+ self.simulation.calculate("household_weight")
+ .astype(float)
+ .tolist()
+ )
+
+ return person_weight, household_weight
+
+ def calculate_labor_supply_responses(self):
+ result = {
+ "substitution_lsr": 0,
+ "income_lsr": 0,
+ "budgetary_impact_lsr": 0,
+ "income_lsr_hh": (self.household_count_people * 0)
+ .astype(float)
+ .tolist(),
+ "substitution_lsr_hh": (self.household_count_people * 0)
+ .astype(float)
+ .tolist(),
+ }
+
+ if not self._has_behavioral_response():
+ return result
+
+ result.update(
+ {
+ "substitution_lsr": self.simulation.calculate(
+ "substitution_elasticity_lsr"
+ ).sum(),
+ "income_lsr": self.simulation.calculate(
+ "income_elasticity_lsr"
+ ).sum(),
+ "income_lsr_hh": self.simulation.calculate(
+ "income_elasticity_lsr", map_to="household"
+ )
+ .astype(float)
+ .tolist(),
+ "substitution_lsr_hh": self.simulation.calculate(
+ "substitution_elasticity_lsr", map_to="household"
+ )
+ .astype(float)
+ .tolist(),
+ }
)
- fiscal = _calculate_government_balance(
- simulation.baseline_simulation, options
+ return result
+
+ def _has_behavioral_response(self) -> bool:
+ return (
+ "employment_income_behavioral_response"
+ in self.simulation.tax_benefit_system.variables
+ and any(
+ self.simulation.calculate(
+ "employment_income_behavioral_response"
+ )
+ != 0
+ )
+ )
+
+ def calculate_lsr_working_hours(self):
+ if self.country_id != "us":
+ return {
+ "weekly_hours": 0,
+ "weekly_hours_income_effect": 0,
+ "weekly_hours_substitution_effect": 0,
+ }
+
+ return {
+ "weekly_hours": self.simulation.calculate(
+ "weekly_hours_worked"
+ ).sum(),
+ "weekly_hours_income_effect": self.simulation.calculate(
+ "weekly_hours_worked_behavioural_response_income_elasticity"
+ ).sum(),
+ "weekly_hours_substitution_effect": self.simulation.calculate(
+ "weekly_hours_worked_behavioural_response_substitution_elasticity"
+ ).sum(),
+ }
+
+ def calculate_uk_programs(self) -> Dict[str, float]:
+ if self.country_id != "uk":
+ return {}
+
+ return {
+ program.name: self.simulation.calculate(
+ program.name, map_to="household"
+ ).sum()
+ * (1 if program.is_positive else -1)
+ for program in UKPrograms.PROGRAMS
+ }
+
+
+def calculate_single_economy(
+ simulation: Simulation, reform: bool = False
+) -> Dict:
+ task_manager = GeneralEconomyTask(
+ (
+ simulation.baseline_simulation
+ if not reform
+ else simulation.reform_simulation
+ ),
+ simulation.options.country,
+ )
+ country_id = simulation.options.country
+
+ total_tax, total_spending = task_manager.calculate_tax_and_spending()
+ gini, top_10_share, top_1_share = (
+ task_manager.calculate_inequality_metrics()
+ )
+ wealth, wealth_decile = task_manager.calculate_wealth_metrics()
+ is_male, race, age = task_manager.calculate_demographic_metrics()
+ labor_supply_responses = task_manager.calculate_labor_supply_responses()
+ lsr_working_hours = task_manager.calculate_lsr_working_hours()
+ (
+ in_poverty,
+ person_in_poverty,
+ person_in_deep_poverty,
+ poverty_gap,
+ deep_poverty_gap,
+ ) = task_manager.calculate_poverty_metrics()
+ total_net_income, employment_income_hh, self_employment_income_hh = (
+ task_manager.calculate_income_breakdown_metrics()
)
- inequality = _calculate_inequality(simulation.baseline_simulation)
+ (
+ household_net_income,
+ equiv_household_net_income,
+ household_income_decile,
+ household_market_income,
+ ) = task_manager.calculate_household_income_metrics()
+ person_weight, household_weight = task_manager.calculate_weights()
+
+ if country_id == "uk":
+ uk_programs = task_manager.calculate_uk_programs()
+ else:
+ uk_programs = None
+
+ total_state_tax = 0
+
+ if country_id == "us":
+ try:
+ total_state_tax = simulation.calculate(
+ "household_state_income_tax"
+ ).sum()
+ except:
+ total_state_tax = 0
return SingleEconomy(
- fiscal=fiscal,
- inequality=inequality,
+ **{
+ "total_net_income": total_net_income,
+ "employment_income_hh": employment_income_hh,
+ "self_employment_income_hh": self_employment_income_hh,
+ "total_tax": total_tax,
+ "total_state_tax": total_state_tax,
+ "total_benefits": total_spending,
+ "household_net_income": household_net_income,
+ "equiv_household_net_income": equiv_household_net_income,
+ "household_income_decile": household_income_decile,
+ "household_market_income": household_market_income,
+ "household_wealth_decile": wealth_decile,
+ "household_wealth": wealth,
+ "in_poverty": in_poverty,
+ "person_in_poverty": person_in_poverty,
+ "person_in_deep_poverty": person_in_deep_poverty,
+ "poverty_gap": poverty_gap,
+ "deep_poverty_gap": deep_poverty_gap,
+ "person_weight": person_weight,
+ "household_weight": household_weight,
+ "household_count_people": task_manager.household_count_people.astype(
+ int
+ ).tolist(),
+ "gini": float(gini),
+ "top_10_percent_share": float(top_10_share),
+ "top_1_percent_share": float(top_1_share),
+ "is_male": is_male,
+ "race": race,
+ "age": age,
+ **labor_supply_responses,
+ **lsr_working_hours,
+ "type": "general",
+ "programs": uk_programs,
+ }
)
diff --git a/policyengine/simulation.py b/policyengine/simulation.py
index bfadd921..abec5e2b 100644
--- a/policyengine/simulation.py
+++ b/policyengine/simulation.py
@@ -7,7 +7,7 @@
from policyengine_core.simulations import (
Microsimulation as CountryMicrosimulation,
)
-from .utils.reforms import ParametricReform, SimulationAdjustment
+from .utils.reforms import ParametricReform
from policyengine_core.reforms import Reform as StructuralReform
from policyengine_core.data import Dataset
from .utils.huggingface import download
@@ -33,9 +33,7 @@
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
-)
+ReformType = ParametricReform | Type[StructuralReform] | None
RegionType = str | None
SubsampleType = int | None
@@ -172,12 +170,6 @@ def _initialise_simulation(
if isinstance(reform, ParametricReform):
reform = reform.model_dump()
- simulation_editing_reform = None
-
- if isinstance(reform, SimulationAdjustment):
- simulation_editing_reform = reform.root
- reform = None
-
simulation: CountrySimulation = _simulation_type(
dataset=data if macro else None,
situation=data if not macro else None,
@@ -199,9 +191,6 @@ def _initialise_simulation(
if subsample is not None:
simulation = simulation.subsample(subsample)
- if simulation_editing_reform is not None:
- simulation_editing_reform(simulation)
-
return simulation
def _apply_region_to_simulation(
diff --git a/policyengine/utils/reforms.py b/policyengine/utils/reforms.py
index ab8225bb..6d681f57 100644
--- a/policyengine/utils/reforms.py
+++ b/policyengine/utils/reforms.py
@@ -11,9 +11,3 @@ class ParametricReform(RootModel):
"""A reform that just changes parameter values."""
root: Dict[str, Dict | float | bool]
-
-
-class SimulationAdjustment(RootModel):
- """A reform that changes the simulation in some way."""
-
- root: object # Python callable function that takes a Simulation object and returns nothing. Not JSON serialisable. Needs fixing.
diff --git a/pyproject.toml b/pyproject.toml
index 82c45fc6..c9d75b71 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,7 +15,7 @@ requires-python = ">=3.6"
dependencies = [
"policyengine_core>=3.10",
"policyengine-uk",
- "policyengine-us",
+ "policyengine-us>=1.213.1",
"microdf_python",
"getpass4",
"pydantic",