Esempio n. 1
0
def headline_metrics(baseline: Microsimulation,
                     reformed: Microsimulation) -> dict:
    """Compute headline society-wide metrics.

    :param baseline: Baseline simulation.
    :type baseline: Microsimulation
    :param reformed: Reform simulation.
    :type reformed: Microsimulation
    :return: Dictionary with net_cost, poverty_change, winner_share,
        loser_share, and gini_change.
    :rtype: dict
    """
    new_income = reformed.calc("equiv_household_net_income", map_to="person")
    old_income = baseline.calc("equiv_household_net_income", map_to="person")
    gain = new_income - old_income
    net_cost = (reformed.calc("net_income").sum() -
                baseline.calc("net_income").sum())
    poverty_change = pct_change(
        baseline.calc("in_poverty_bhc", map_to="person").mean(),
        reformed.calc("in_poverty_bhc", map_to="person").mean(),
    )
    winner_share = (gain > 1).mean()
    loser_share = (gain < -1).mean()
    gini_change = pct_change(old_income.gini(), new_income.gini())
    return dict(
        net_cost=gbp(net_cost),
        net_cost_numeric=(net_cost),
        poverty_change=float(poverty_change),
        winner_share=float(winner_share),
        loser_share=float(loser_share),
        gini_change=float(gini_change),
    )
def compute_reform():
    params = request.json
    reform = Microsimulation(create_reform(params))
    new_income = reform.calc("equiv_household_net_income", map_to="person")
    old_income = baseline.calc("equiv_household_net_income", map_to="person")
    gain = new_income - old_income
    net_cost = reform.calc("net_income").sum() - baseline.calc("net_income").sum()
    decile_plot = px.bar(gain.groupby(old_income.percentile_rank()).mean()).update_layout(
        title="Income effect by percentile",
        xaxis_title="Equivalised disposable income percentile",
        yaxis_title="Average income effect",
        yaxis_tickprefix="£",
        width=800,
        height=600,
        template="plotly_white",
        showlegend=False
    ).to_json()
    top_1_pct_share_effect = gain[old_income.percentile_rank() == 100].mean()
    top_10_pct_share_effect = gain[old_income.decile_rank() == 10].mean()
    median_effect = new_income.median() - old_income.median()
    return {"net_cost": gbp(net_cost), "decile_plot": json.loads(decile_plot), "1pct": top_1_pct_share_effect, "10pct": top_10_pct_share_effect, "median": median_effect}
def hover_label(component: str, amount: float, is_pop: bool) -> str:
    """Create a label for an individual point in a waterfall hovercard.

    :param component: Name of the component, e.g. "Tax revenues".
    :type component: str
    :param amount: Name of the component, e.g. "Tax revenues".
    :type amount: float
    :param is_pop: Whether the component is population- vs. household-level.
    :type is_pop: bool
    :return: Label for hovercard.
    :rtype: str
    """
    # Reset household net income label to match the headline.
    if component == "Your net income":
        component = "Your annual net income"
    # Net impact bars should match the title.
    res = component
    # Flip the amount for labeling population benefits and household taxes.
    if component in ["Benefit outlays", "Your taxes"]:
        amount *= -1
    # Round population estimates, not individual.
    abs_amount = round(abs(amount))
    abs_amount_display = gbp(abs_amount) if is_pop else f"£{abs_amount:,}"
    # Branch logic, starting with no change.
    # More special handling of the net impact to match the title.
    if amount == 0:
        if component == "Net impact":
            return "Reform has no budgetary impact"
        return res + " would not change"
    if amount > 0:
        if component == "Net impact":  # Population.
            return "Reform produces " + abs_amount_display + " net surplus"
        return res + " would rise by " + abs_amount_display
    if amount < 0:
        if component == "Net impact":  # Population.
            return "Reform produces " + abs_amount_display + " net cost"
        return res + " would fall by " + abs_amount_display
Esempio n. 4
0
def test_rounding():
    from rdbl import gbp

    assert gbp(231e9) == "£231bn"