diff --git a/src/posts/articles/childcare_expansion.ipynb b/src/posts/articles/childcare_expansion.ipynb
new file mode 100644
index 000000000..f1f60a7a7
--- /dev/null
+++ b/src/posts/articles/childcare_expansion.ipynb
@@ -0,0 +1,1621 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3c508aa1",
+ "metadata": {},
+ "source": [
+ "## Introduction\n",
+ "\n",
+ "In March 2023, Chancellor Jeremy Hunt [announced](https://assets.publishing.service.gov.uk/media/66221ba8252f0d71cf757d2b/Spring_budget_2023_childcare_expansion_costing_note_information.pdf) an extension of funded childcare hours in England, extending the 30-hours free childcare (the extended childcare entitlement) to children between nine months and four years old (previously, the lower age limit was three years). In this report, we use PolicyEngine to model the fiscal and household impacts of this reform.\n",
+ "\n",
+ "## Current policy\n",
+ "\n",
+ "Under the previous policy, free childcare hours were available to the following groups:\n",
+ "\n",
+ "- All three and four-year-olds were entitled to 15 hours of free childcare per week (the universal entitlement)\n",
+ "- Three and four-year-olds in families where all parents earn the equivalent of 16 hours at the National Minimum Wage were entitled to an additional 15 hours (the extended entitlement)\n",
+ "- Two-year-olds from households claiming specific benefits were eligible for 15 hours of free childcare (the targeted entitlement)\n",
+ "\n",
+ "The free entitlement applied for 38 weeks per year (during term time). Parents can choose to spread their hours over more weeks, which reduces the weekly entitlement proportionally. The eligibility threshold for the additional 15 hours includes an income cap, with households where any parent earns over £100,000 not qualifying.\n",
+ "\n",
+ "This policy includes several parameters in the PolicyEngine model, including:\n",
+ "- Age thresholds for entitlement (currently set at 1 year for certain provisions)\n",
+ "- Hour allocations for different age brackets\n",
+ "- Income eligibility criteria\n",
+ "\n",
+ "## Reform\n",
+ "\n",
+ "The reform extended the extended childcare entitlement in three phases:\n",
+ "\n",
+ "- **April 2024**: The age eligibility condition is reduced from 3-4 years to 2-4 years. Children aged 2-3 years are entitled to 15 hours of free childcare per week rather than 30 hours.\n",
+ "- **September 2024**: This two-year old age limit is lowered to 9 months. Children aged 9 months to 3 years are entitled to 15 hours of free childcare per week.\n",
+ "- **September 2025**: Children aged 9 months to 4 years are entitled to 30 hours of free childcare per week.\n",
+ "\n",
+ "The eligibility criteria for \"working parents\" remains the same as the current 30-hour offer for three and four-year-olds: parents must earn the equivalent of 16 hours at the National Minimum Wage, and no parent can earn more than £100,000.\n",
+ "\n",
+ "Our PolicyEngine model implements this reform by:\n",
+ "1. Reducing the age threshold for childcare entitlement from 1 year to 9 months (0.75 years)\n",
+ "2. Increasing the funded hours for different age groups according to the implementation timeline\n",
+ "3. Maintaining the same income eligibility criteria\n",
+ "\n",
+ "## Household impacts\n",
+ "\n",
+ "Different household compositions experience varying impacts from the childcare extension. Here are examples based on our model:\n",
+ "\n",
+ "**Single parent, one child aged 1, earning £25,000 per year**\n",
+ "- Pre-reform: No entitlement to free childcare\n",
+ "- Post-reform (full implementation): 30 hours free childcare weekly\n",
+ "\n",
+ "**Couple, two children aged 10 months and 2 years, combined income of £60,000**\n",
+ "- Pre-reform: No entitlement to free childcare\n",
+ "- Post-reform (full implementation): 30 hours free childcare weekly for both children\n",
+ "\n",
+ "The reform affects households differently based on family composition, income levels, and childcare usage patterns. Families with incomes over £100,000 are not eligible for the extended entitlement.\n",
+ "\n",
+ "## Economic impacts\n",
+ "\n",
+ "Our analysis shows that the childcare hours extension will reduce government revenue by the following amounts:\n",
+ "\n",
+ "| Revenue impact (£bn) | 2024/25 | 2025/26 | 2026/27 | 2027/28 | 2028/29 | 2029/30 |\n",
+ "|:---------------------|-----:|-----:|-----:|-----:|-----:|-----:|\n",
+ "| PolicyEngine | -1.3 | -3.9 | -4.3 | -4.4 | -4.6 | -4.7 |\n",
+ "| HM Treasury | -1.7 | -3.3 | -4.1 | -4.1 | - | - |\n",
+ "\n",
+ "## Conclusion\n",
+ "\n",
+ "We estimate that the UK's extended childcare entitlement will reduce government revenue by £4.7 billion in 2029/30, and will increase the net income of households with children who meet the eligibility criteria. The greatest income changes accrue to families with multiple young children who use the full entitlement.\n",
+ "\n",
+ "Use PolicyEngine to view the full results or calculate the effect on your household.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "id": "6081c8a8",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using Hugging Face for download.\n"
+ ]
+ }
+ ],
+ "source": [
+ "baseline = {\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].threshold\": {\n",
+ " \"2024\": 1,\n",
+ " \"2025\": 1,\n",
+ " \"2026\": 1,\n",
+ " \"2027\": 1,\n",
+ " \"2028\": 1,\n",
+ " \"2029\": 1,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].amount\": {\n",
+ " \"2024\": 0,\n",
+ " \"2025\": 0,\n",
+ " \"2026\": 0,\n",
+ " \"2027\": 0,\n",
+ " \"2028\": 0,\n",
+ " \"2029\": 0,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[2].amount\": {\n",
+ " \"2024\": 0,\n",
+ " \"2025\": 0,\n",
+ " \"2026\": 0,\n",
+ " \"2027\": 0,\n",
+ " \"2028\": 0,\n",
+ " \"2029\": 0,\n",
+ " },\n",
+ "}\n",
+ "reform = {\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].threshold\": {\n",
+ " \"2024\": 0.75,\n",
+ " \"2025\": 0.75,\n",
+ " \"2026\": 0.75,\n",
+ " \"2027\": 0.75,\n",
+ " \"2028\": 0.75,\n",
+ " \"2029\": 0.75,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[0].amount\": {\n",
+ " \"2024\": (0 + 15) / 2,\n",
+ " \"2025\": (15 + 30) / 2,\n",
+ " \"2026\": 30,\n",
+ " \"2027\": 30,\n",
+ " \"2028\": 30,\n",
+ " \"2029\": 30,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[2].amount\": {\n",
+ " \"2024\": 15,\n",
+ " \"2025\": (15 + 30) / 2,\n",
+ " \"2026\": 300,\n",
+ " \"2027\": 30,\n",
+ " \"2028\": 30,\n",
+ " \"2029\": 30,\n",
+ " },\n",
+ "}\n",
+ "\n",
+ "from policyengine import Simulation\n",
+ "\n",
+ "sim = Simulation(\n",
+ " country=\"uk\",\n",
+ " scope=\"macro\",\n",
+ " baseline=baseline,\n",
+ " reform=reform,\n",
+ ")\n",
+ "baseline = sim.baseline_simulation\n",
+ "reformed = sim.reform_simulation\n",
+ "\n",
+ "costs_per_year = []\n",
+ "for year in range(2024, 2030):\n",
+ " baseline_spending = baseline.calculate(\"gov_spending\", year).sum()/1e9\n",
+ " reform_spending = reformed.calculate(\"gov_spending\", year).sum()/1e9\n",
+ " change = reform_spending - baseline_spending\n",
+ " costs_per_year.append(change)\n",
+ "\n",
+ "from policyengine.utils.charts import *"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 93,
+ "id": "ec88c629",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using Hugging Face for download.\n",
+ "Using Hugging Face for download.\n"
+ ]
+ }
+ ],
+ "source": [
+ "comparison = sim.calculate_economy_comparison()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 104,
+ "id": "8abf8b8e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.plotly.v1+json": {
+ "config": {
+ "plotlyServerURL": "https://plot.ly"
+ },
+ "data": [
+ {
+ "alignmentgroup": "True",
+ "hovertemplate": "x=%{x}
y=%{y}",
+ "legendgroup": "",
+ "marker": {
+ "color": "#2C6496",
+ "pattern": {
+ "shape": ""
+ }
+ },
+ "name": "",
+ "offsetgroup": "",
+ "orientation": "v",
+ "showlegend": false,
+ "textposition": "auto",
+ "type": "bar",
+ "x": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10
+ ],
+ "xaxis": "x",
+ "y": [
+ 1.9131494308534902,
+ 6.239646055929712,
+ 15.485073323752633,
+ 36.751220383192205,
+ 52.97933780821839,
+ 125.62123368838385,
+ 142.75104755347152,
+ 581.2588969544767,
+ 369.2912487516033,
+ 99.47409752032834
+ ],
+ "yaxis": "y"
+ }
+ ],
+ "layout": {
+ "annotations": [
+ {
+ "showarrow": false,
+ "text": "Source: PolicyEngine UK tax-benefit microsimulation model",
+ "x": 0,
+ "xanchor": "left",
+ "xref": "paper",
+ "y": -0.2,
+ "yanchor": "bottom",
+ "yref": "paper"
+ }
+ ],
+ "barmode": "relative",
+ "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"
+ }
+ ],
+ "legend": {
+ "tracegroupgap": 0
+ },
+ "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": "Impact of the 2023 childcare expansion by income decile"
+ },
+ "uniformtext": {
+ "minsize": 12,
+ "mode": "hide"
+ },
+ "width": 800,
+ "xaxis": {
+ "anchor": "y",
+ "domain": [
+ 0,
+ 1
+ ],
+ "gridcolor": "#F4F4F4",
+ "ticksuffix": "",
+ "title": {
+ "text": "x"
+ },
+ "zerolinecolor": "#F4F4F4"
+ },
+ "yaxis": {
+ "anchor": "x",
+ "domain": [
+ 0,
+ 1
+ ],
+ "gridcolor": "#F4F4F4",
+ "ticksuffix": "",
+ "title": {
+ "text": "y"
+ },
+ "zerolinecolor": "#F4F4F4"
+ }
+ }
+ }
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig = px.bar(\n",
+ " x=comparison.decile.average.keys(),\n",
+ " y=comparison.decile.average.values(),\n",
+ " color_discrete_sequence=[BLUE]\n",
+ ")\n",
+ "\n",
+ "format_fig(fig).update_layout(\n",
+ " title=\"Impact of the 2023 childcare expansion by income decile\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "id": "f73c0e5a",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "| | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 |\n",
+ "|:---------------------|-------:|-------:|-------:|-------:|-------:|-------:|\n",
+ "| Revenue impact (£bn) | -1.3 | -3.9 | -4.3 | -4.4 | -4.6 | -4.7 |\n"
+ ]
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "df = pd.DataFrame({\n",
+ " \"Year\": [str(year) for year in range(2024, 2030)],\n",
+ " \"Revenue impact (£bn)\": costs_per_year,\n",
+ "})\n",
+ "df[\"Revenue impact (£bn)\"] = df[\"Revenue impact (£bn)\"].round(1)\n",
+ "df[\"Revenue impact (£bn)\"] *= -1\n",
+ "\n",
+ "print(df.set_index(\"Year\").T.to_markdown(index=True))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "da87044a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "baseline_df = baseline.calculate_dataframe([\"age\", \"household_net_income\", \"household_id\", \"extended_childcare_entitlement\"], 2029)\n",
+ "reformed_df = reformed.calculate_dataframe([\"age\", \"household_net_income\", \"household_id\", \"extended_childcare_entitlement\"], 2029)\n",
+ "baseline_df = baseline_df.rename(columns={col: f\"baseline_{col}\" for col in baseline_df.columns})\n",
+ "reformed_df = reformed_df.rename(columns={col: f\"reformed_{col}\" for col in reformed_df.columns})\n",
+ "\n",
+ "df = pd.concat([baseline_df, reformed_df], axis=1)\n",
+ "df[\"change\"] = df[\"reformed_household_net_income\"] - df[\"baseline_household_net_income\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "id": "018112bb",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " baseline_age | \n",
+ " baseline_household_net_income | \n",
+ " baseline_household_id | \n",
+ " baseline_extended_childcare_entitlement | \n",
+ " reformed_age | \n",
+ " reformed_household_net_income | \n",
+ " reformed_household_id | \n",
+ " reformed_extended_childcare_entitlement | \n",
+ " change | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 20701 | \n",
+ " 29.0 | \n",
+ " 55654.0 | \n",
+ " 10974300 | \n",
+ " 0.0 | \n",
+ " 29.0 | \n",
+ " 57326.0 | \n",
+ " 10974300 | \n",
+ " 1672.24939 | \n",
+ " 1672.0 | \n",
+ "
\n",
+ " \n",
+ " | 20702 | \n",
+ " 33.0 | \n",
+ " 55654.0 | \n",
+ " 10974300 | \n",
+ " 0.0 | \n",
+ " 33.0 | \n",
+ " 57326.0 | \n",
+ " 10974300 | \n",
+ " 1672.24939 | \n",
+ " 1672.0 | \n",
+ "
\n",
+ " \n",
+ " | 20703 | \n",
+ " 0.0 | \n",
+ " 55654.0 | \n",
+ " 10974300 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 57326.0 | \n",
+ " 10974300 | \n",
+ " 1672.24939 | \n",
+ " 1672.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " baseline_age baseline_household_net_income baseline_household_id \\\n",
+ "20701 29.0 55654.0 10974300 \n",
+ "20702 33.0 55654.0 10974300 \n",
+ "20703 0.0 55654.0 10974300 \n",
+ "\n",
+ " baseline_extended_childcare_entitlement reformed_age \\\n",
+ "20701 0.0 29.0 \n",
+ "20702 0.0 33.0 \n",
+ "20703 0.0 0.0 \n",
+ "\n",
+ " reformed_household_net_income reformed_household_id \\\n",
+ "20701 57326.0 10974300 \n",
+ "20702 57326.0 10974300 \n",
+ "20703 57326.0 10974300 \n",
+ "\n",
+ " reformed_extended_childcare_entitlement change \n",
+ "20701 1672.24939 1672.0 \n",
+ "20702 1672.24939 1672.0 \n",
+ "20703 1672.24939 1672.0 "
+ ]
+ },
+ "execution_count": 68,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df[df.baseline_household_id.isin(df[df.change.between(1, 2000)].sample(1).baseline_household_id.values)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "id": "c973cd91",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " baseline_age | \n",
+ " baseline_household_net_income | \n",
+ " baseline_household_id | \n",
+ " baseline_extended_childcare_entitlement | \n",
+ " reformed_age | \n",
+ " reformed_household_net_income | \n",
+ " reformed_household_id | \n",
+ " reformed_extended_childcare_entitlement | \n",
+ " change | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 153404 | \n",
+ " 37.0 | \n",
+ " 114136.0 | \n",
+ " 34674100 | \n",
+ " 0.0 | \n",
+ " 37.0 | \n",
+ " 117263.0 | \n",
+ " 34674100 | \n",
+ " 3127.197266 | \n",
+ " 3127.0 | \n",
+ "
\n",
+ " \n",
+ " | 153405 | \n",
+ " 38.0 | \n",
+ " 114136.0 | \n",
+ " 34674100 | \n",
+ " 0.0 | \n",
+ " 38.0 | \n",
+ " 117263.0 | \n",
+ " 34674100 | \n",
+ " 3127.197266 | \n",
+ " 3127.0 | \n",
+ "
\n",
+ " \n",
+ " | 153406 | \n",
+ " 1.0 | \n",
+ " 114136.0 | \n",
+ " 34674100 | \n",
+ " 0.0 | \n",
+ " 1.0 | \n",
+ " 117263.0 | \n",
+ " 34674100 | \n",
+ " 3127.197266 | \n",
+ " 3127.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " baseline_age baseline_household_net_income baseline_household_id \\\n",
+ "153404 37.0 114136.0 34674100 \n",
+ "153405 38.0 114136.0 34674100 \n",
+ "153406 1.0 114136.0 34674100 \n",
+ "\n",
+ " baseline_extended_childcare_entitlement reformed_age \\\n",
+ "153404 0.0 37.0 \n",
+ "153405 0.0 38.0 \n",
+ "153406 0.0 1.0 \n",
+ "\n",
+ " reformed_household_net_income reformed_household_id \\\n",
+ "153404 117263.0 34674100 \n",
+ "153405 117263.0 34674100 \n",
+ "153406 117263.0 34674100 \n",
+ "\n",
+ " reformed_extended_childcare_entitlement change \n",
+ "153404 3127.197266 3127.0 \n",
+ "153405 3127.197266 3127.0 \n",
+ "153406 3127.197266 3127.0 "
+ ]
+ },
+ "execution_count": 71,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df[df.baseline_household_id.isin(df[df.change.between(2001, 8000)].sample(1).baseline_household_id.values)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "id": "c890f5de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "baseline = {\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].threshold\": {\n",
+ " \"2024\": 1,\n",
+ " \"2025\": 1,\n",
+ " \"2026\": 1,\n",
+ " \"2027\": 1,\n",
+ " \"2028\": 1,\n",
+ " \"2029\": 1,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].amount\": {\n",
+ " \"2024\": 0,\n",
+ " \"2025\": 0,\n",
+ " \"2026\": 0,\n",
+ " \"2027\": 0,\n",
+ " \"2028\": 0,\n",
+ " \"2029\": 0,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[2].amount\": {\n",
+ " \"2024\": 0,\n",
+ " \"2025\": 0,\n",
+ " \"2026\": 0,\n",
+ " \"2027\": 0,\n",
+ " \"2028\": 0,\n",
+ " \"2029\": 0,\n",
+ " },\n",
+ "}\n",
+ "reform = {\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[1].threshold\": {\n",
+ " \"2024\": 0.75,\n",
+ " \"2025\": 0.75,\n",
+ " \"2026\": 0.75,\n",
+ " \"2027\": 0.75,\n",
+ " \"2028\": 0.75,\n",
+ " \"2029\": 0.75,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[0].amount\": {\n",
+ " \"2024\": (0 + 15) / 2,\n",
+ " \"2025\": (15 + 30) / 2,\n",
+ " \"2026\": 30,\n",
+ " \"2027\": 30,\n",
+ " \"2028\": 30,\n",
+ " \"2029\": 30,\n",
+ " },\n",
+ " \"gov.dfe.extended_childcare_entitlement.hours[2].amount\": {\n",
+ " \"2024\": 15,\n",
+ " \"2025\": (15 + 30) / 2,\n",
+ " \"2026\": 300,\n",
+ " \"2027\": 30,\n",
+ " \"2028\": 30,\n",
+ " \"2029\": 30,\n",
+ " },\n",
+ "}\n",
+ "\n",
+ "def get_array(\n",
+ " year: int,\n",
+ " child_age: int,\n",
+ " is_reform: bool,\n",
+ "):\n",
+ " household = Simulation(\n",
+ " country=\"uk\",\n",
+ " scope=\"household\",\n",
+ " baseline=reform if is_reform else baseline,\n",
+ " data={\n",
+ " \"households\": {\n",
+ " \"household\": {\n",
+ " \"members\": [\"parent\", \"child\"]\n",
+ " }\n",
+ " },\n",
+ " \"people\": {\n",
+ " \"parent\": {\n",
+ " \"age\": 30,\n",
+ " },\n",
+ " \"child\": {\n",
+ " \"age\": child_age,\n",
+ " }\n",
+ " },\n",
+ " \"axes\": [[{\n",
+ " \"name\": \"employment_income\",\n",
+ " \"min\": 0,\n",
+ " \"max\": 150_000,\n",
+ " \"count\": 151,\n",
+ " }]]\n",
+ " }\n",
+ " )\n",
+ "\n",
+ " return household.baseline_simulation.calculate(\"household_net_income\", year)\n",
+ " \n",
+ "\n",
+ "household = Simulation(\n",
+ " country=\"uk\",\n",
+ " scope=\"household\",\n",
+ " baseline=baseline,\n",
+ " reform=reform,\n",
+ " data={\n",
+ " \"households\": {\n",
+ " \"household\": {\n",
+ " \"members\": [\"parent\", \"child\"]\n",
+ " }\n",
+ " },\n",
+ " \"people\": {\n",
+ " \"parent\": {\n",
+ " \"age\": 30,\n",
+ " },\n",
+ " \"child\": {\n",
+ " \"age\": 2,\n",
+ " }\n",
+ " },\n",
+ " \"axes\": [[{\n",
+ " \"name\": \"employment_income\",\n",
+ " \"min\": 0,\n",
+ " \"max\": 150_000,\n",
+ " \"count\": 151,\n",
+ " }]]\n",
+ " }\n",
+ ")\n",
+ "\n",
+ "market_income = household.baseline_simulation.calculate(\"household_market_income\", 2029)\n",
+ "\n",
+ "baseline_values = []\n",
+ "child_age_values = []\n",
+ "year_values = []\n",
+ "hnet_values = []\n",
+ "market_values = []\n",
+ "\n",
+ "for is_baseline in [True]:\n",
+ " for child_age in [0.75, 1, 2]:\n",
+ " for year in range(2024, 2030):\n",
+ " array_r = get_array(year, child_age, True)\n",
+ " array_b = get_array(year, child_age, False)\n",
+ " for i in range(len(array_r)):\n",
+ " baseline_values.append(is_baseline)\n",
+ " child_age_values.append(child_age)\n",
+ " year_values.append(year)\n",
+ " hnet_values.append(array_r[i] - array_b[i])\n",
+ " market_values.append(market_income[i])\n",
+ "\n",
+ "df = pd.DataFrame({\n",
+ " \"Baseline\": baseline_values,\n",
+ " \"Child age\": child_age_values,\n",
+ " \"Year\": year_values,\n",
+ " \"Household net income\": hnet_values,\n",
+ " \"Market income\": market_values,\n",
+ "})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "fa004652",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'px' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m px\u001b[38;5;241m.\u001b[39mline(\n\u001b[1;32m 2\u001b[0m df[df\u001b[38;5;241m.\u001b[39mYear \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m2029\u001b[39m],\n\u001b[1;32m 3\u001b[0m x\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMarket income\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 4\u001b[0m y\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHousehold net income\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 5\u001b[0m color\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mChild age\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 6\u001b[0m )\n",
+ "\u001b[0;31mNameError\u001b[0m: name 'px' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "px.line(\n",
+ " df[df.Year == 2029],\n",
+ " x=\"Market income\",\n",
+ " y=\"Household net income\",\n",
+ " color=\"Child age\",\n",
+ ")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "base",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/src/posts/posts.json b/src/posts/posts.json
index f854f3646..b575205fa 100644
--- a/src/posts/posts.json
+++ b/src/posts/posts.json
@@ -1252,5 +1252,14 @@
"description": "Utah’s latest individual income tax changes will lower state revenues by $96 million and raise net income for 62% of residents in 2025.",
"filename": "utah-income-tax-changes.ipynb",
"image": "utah-income-tax-changes.jpg"
+ },
+ {
+ "title": "Expansion of free childcare hours.",
+ "description": "PolicyEngine estimates the impacts of the 2023 expansion to the extended childcare entitlement.",
+ "date": "2025-05-17 00:00:00",
+ "tags": ["uk", "policy", "featured"],
+ "authors": ["nikhil-woodruff"],
+ "filename": "childcare_expansion.ipynb",
+ "image": "uk-tax-post.jpg"
}
]