Claude
Skills
Sign in
Back

policyengine-analysis

Included with Lifetime
$97 forever

Common analysis patterns for PolicyEngine research repositories (CRFB, newsletters, dashboards, impact studies). For population-level estimates (cost, poverty, distributional impacts), use the policyengine-microsimulation skill instead.

General

What this skill does


# PolicyEngine analysis

Patterns for creating policy impact analyses, dashboards, and research using PolicyEngine.

**For population-level estimates** (budgetary cost, poverty impact, distributional analysis), use the **policyengine-microsimulation** skill instead. This skill covers analysis repo patterns, visualization, and household-level calculations.

See `MICROSIMULATION_REFORM_GUIDE.md` for UK-specific microsimulation patterns.

## For Users

### What are Analysis Repositories?

Analysis repositories produce the research you see on PolicyEngine:

**Blog posts:**
- "How Montana's tax cuts affect poverty"
- "Harris EITC proposal costs and impacts"
- "UK Budget 2024 analysis"

**Dashboards:**
- State tax comparisons
- Policy proposal scorecards
- Interactive calculators (GiveCalc, SALT calculator)

**Research reports:**
- Distributional analyses for organizations
- Policy briefs for legislators
- Impact assessments

### How Analysis Works

1. **Define policy reform** using PolicyEngine parameters
2. **Create household examples** showing specific impacts
3. **Run population simulations** for aggregate effects
4. **Calculate distributional impacts** (who wins, who loses)
5. **Create visualizations** (charts, tables)
6. **Write report** following policyengine-writing-skill style
7. **Publish** to blog or share with stakeholders

### Reading PolicyEngine Analysis

**Key sections in typical analysis:**

**The proposal:**
- What policy changes
- Specific parameter values

**Household impacts:**
- 3-5 example households
- Dollar amounts for each
- Charts showing impact across income range

**Statewide/national impacts:**
- Total cost or revenue
- Winners and losers by income decile
- Poverty and inequality effects

**See policyengine-writing-skill for writing conventions.**

## For Analysts

### When to Use This Skill

- Creating policy impact analyses
- Building interactive dashboards with Next.js + Recharts
- Writing analysis notebooks
- Calculating distributional impacts
- Comparing policy proposals
- Creating visualizations for research
- Publishing policy research

### Example Analysis Repositories

- `crfb-tob-impacts` - Policy impact analyses
- `newsletters` - Data-driven newsletters
- `2024-election-dashboard` - Policy comparison dashboards
- `marginal-child` - Specialized policy analyses
- `givecalc` - Charitable giving calculator

## Repository Structure

Standard analysis repository structure:

```
analysis-repo/
├── analysis.ipynb           # Main Jupyter notebook
├── requirements.txt         # Python dependencies
├── README.md               # Documentation
├── data/                   # Data files (if needed)
└── outputs/                # Generated charts, tables
```

## Common Analysis Patterns

### Pattern 1: Impact Analysis Across Income Distribution

```python
import pandas as pd
import numpy as np
from policyengine_us import Simulation

# Define reform
reform = {
    "gov.irs.credits.ctc.amount.base[0].amount": {
        "2026-01-01.2100-12-31": 5000
    }
}

# Analyze across income distribution
incomes = np.linspace(0, 200000, 101)
results = []

for income in incomes:
    # Baseline
    situation = create_situation(income=income)
    sim_baseline = Simulation(situation=situation)
    tax_baseline = sim_baseline.calculate("income_tax", 2026)[0]

    # Reform
    sim_reform = Simulation(situation=situation, reform=reform)
    tax_reform = sim_reform.calculate("income_tax", 2026)[0]

    results.append({
        "income": income,
        "tax_baseline": tax_baseline,
        "tax_reform": tax_reform,
        "tax_change": tax_reform - tax_baseline
    })

df = pd.DataFrame(results)
```

### Pattern 2: Household-Level Case Studies

```python
# Define representative households
households = {
    "Single, No Children": {
        "income": 40000,
        "num_children": 0,
        "married": False
    },
    "Single Parent, 2 Children": {
        "income": 50000,
        "num_children": 2,
        "married": False
    },
    "Married, 2 Children": {
        "income": 100000,
        "num_children": 2,
        "married": True
    }
}

# Calculate impacts for each
case_studies = {}
for name, params in households.items():
    situation = create_family(**params)

    sim_baseline = Simulation(situation=situation)
    sim_reform = Simulation(situation=situation, reform=reform)

    case_studies[name] = {
        "baseline_tax": sim_baseline.calculate("income_tax", 2026)[0],
        "reform_tax": sim_reform.calculate("income_tax", 2026)[0],
        "ctc_baseline": sim_baseline.calculate("ctc", 2026)[0],
        "ctc_reform": sim_reform.calculate("ctc", 2026)[0]
    }

case_df = pd.DataFrame(case_studies).T
```

### Pattern 3: State-by-State Comparison

```python
states = ["CA", "NY", "TX", "FL", "PA", "OH", "IL", "MI"]

state_results = []
for state in states:
    situation = create_situation(income=75000, state=state)

    sim_baseline = Simulation(situation=situation)
    sim_reform = Simulation(situation=situation, reform=reform)

    state_results.append({
        "state": state,
        "baseline_net_income": sim_baseline.calculate("household_net_income", 2026)[0],
        "reform_net_income": sim_reform.calculate("household_net_income", 2026)[0],
        "change": (sim_reform.calculate("household_net_income", 2026)[0] -
                  sim_baseline.calculate("household_net_income", 2026)[0])
    })

state_df = pd.DataFrame(state_results)
```

### Pattern 4: Marginal Analysis (Winners/Losers)

```python
import plotly.graph_objects as go

# Calculate across income range
situation_with_axes = {
    # ... setup ...
    "axes": [[{
        "name": "employment_income",
        "count": 1001,
        "min": 0,
        "max": 200000,
        "period": 2026
    }]]
}

sim_baseline = Simulation(situation=situation_with_axes)
sim_reform = Simulation(situation=situation_with_axes, reform=reform)

incomes = sim_baseline.calculate("employment_income", 2026)
baseline_net = sim_baseline.calculate("household_net_income", 2026)
reform_net = sim_reform.calculate("household_net_income", 2026)

gains = reform_net - baseline_net

# Identify winners and losers
winners = gains > 0
losers = gains < 0
neutral = gains == 0

print(f"Winners: {winners.sum() / len(gains) * 100:.1f}%")
print(f"Losers: {losers.sum() / len(gains) * 100:.1f}%")
print(f"Neutral: {neutral.sum() / len(gains) * 100:.1f}%")
```

## Visualization Patterns

### Standard Plotly Configuration

```python
import plotly.graph_objects as go

# PolicyEngine brand colors — see policyengine-design-skill for canonical values.
# Python charts can't use CSS vars, so reference the design token hex values:
TEAL = "#319795"       # --pe-color-primary-500
BLUE = "#026AA2"       # --pe-color-blue-700
DARK_GRAY = "#5A5A5A"  # --pe-color-text-secondary

def create_pe_layout(title, xaxis_title, yaxis_title):
    """Create standard PolicyEngine chart layout."""
    return go.Layout(
        title=title,
        xaxis_title=xaxis_title,
        yaxis_title=yaxis_title,
        font=dict(family="Inter", size=14),
        plot_bgcolor="white",
        hovermode="x unified",
        xaxis=dict(
            showgrid=True,
            gridcolor="lightgray",
            zeroline=True
        ),
        yaxis=dict(
            showgrid=True,
            gridcolor="lightgray",
            zeroline=True
        )
    )

# Use in charts
fig = go.Figure(layout=create_pe_layout(
    "Tax Impact by Income",
    "Income",
    "Tax Change"
))
fig.add_trace(go.Scatter(x=incomes, y=tax_change, line=dict(color=TEAL)))
```

### Common Chart Types

**1. Line Chart (Impact by Income)**
```python
fig = go.Figure()
fig.add_trace(go.Scatter(
    x=df.income,
    y=df.tax_change,
    mode='lines',
    name='Tax Change',
    line=dict(color=TEAL, width=3)
))
fig.update_layout(
    title="Tax Impact by Income Level",
    xaxis_title="Income",
    yaxis_title="Tax Change ($)",
    xaxis_tickformat="$,.0f",
    yaxis_tickformat="$,.0f"
)
```

**

Related in General