Pensioner income sources#

The chart below (Figure 12 from the 2022 HBAI publication) shows the distribution of income for each decile for pensioner households. We can reproduce this figure from PolicyEngine using the code below.

from policyengine_uk import Microsimulation
import pandas as pd

sim = Microsimulation()

is_pensioner_household = (
    sim.calculate("is_SP_age", map_to="household") > 0
) * (sim.calculate("is_child", map_to="household") == 0)
household_benefits = sim.calculate("household_benefits")
household_pensions = sim.calculate("pension_income", map_to="household")
household_investment_income = sim.calculate(
    "capital_income", map_to="household"
)
household_earnings = sim.calculate(
    "employment_income", map_to="household"
) + sim.calculate("self_employment_income", map_to="household")
total_income = sim.calculate("household_market_income") + household_benefits

equivalised_income = sim.calculate("equiv_household_net_income")[
    is_pensioner_household
]
household_count_people = sim.calculate("people", map_to="household")[
    is_pensioner_household
]
equivalised_income.weights *= household_count_people.values
household_income_decile = equivalised_income.decile_rank()

income_source_decodes = {
    "Earnings": household_earnings,
    "Pensions": household_pensions,
    "Investment": household_investment_income,
    "State support": household_benefits,
}

deciles = []
values = []
income_sources = []

for decile in range(1, 11):
    in_decile = household_income_decile == decile
    cumulative_income = 0
    for income_source in income_source_decodes:
        deciles.append(decile)
        income_sources.append(income_source)
        income_source_values = income_source_decodes[income_source]
        values.append(
            income_source_values[is_pensioner_household][in_decile].sum()
            / total_income[is_pensioner_household][in_decile].sum()
        )
        cumulative_income += income_source_values[is_pensioner_household][
            in_decile
        ].sum()
    # Add 'other income'
    deciles.append(decile)
    income_sources.append("Other")
    values.append(
        1
        - cumulative_income
        / total_income[is_pensioner_household][in_decile].sum()
    )

df = pd.DataFrame(
    {
        "Decile": deciles,
        "Income source": income_sources,
        "Value": values,
    }
)

# Order by state support, other income, pensions, investment, earnings
df["Income source"] = pd.Categorical(
    df["Income source"],
    ["State support", "Other", "Pensions", "Investment", "Earnings"],
)
df = df.sort_values(["Decile", "Income source"], ascending=[True, False])

import plotly.express as px
from policyengine_core.charts import format_fig

fig = px.bar(
    df,
    x="Decile",
    y="Value",
    color="Income source",
).update_layout(
    height=600,
    width=800,
    # No bar gap
    bargap=0,
    yaxis=dict(
        tickformat=".0%",
        title="Percentage of income",
        tickvals=[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
    ),
    xaxis=dict(
        title="Income decile",
        tickvals=list(range(1, 11)),
    ),
)

fig = format_fig(fig).update_layout(
    title="Sources of income for pensioner households",
)
fig